diff --git a/.gitignore b/.gitignore index 39a0d76c16..15d874097c 100644 --- a/.gitignore +++ b/.gitignore @@ -78,6 +78,7 @@ Mage.Tests/Mage.log Mage.Tests/watchdog.log # Mage +*.log Mage/target # Mage.Updater @@ -91,6 +92,7 @@ Mage.Verify/AllCards.json.zip Mage.Verify/AllSets.json.zip Mage.Verify/AllCards.json Mage.Verify/AllSets.json +Mage.Verify/db releases Utils/author.txt diff --git a/.travis.yml b/.travis.yml index a5d7bdc1f5..7862dd752a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,3 +3,10 @@ dist: trusty language: java before_install: - echo "MAVEN_OPTS='-Xmx2g'" > ~/.mavenrc +# addons: +# sonarcloud: +# organization: "magefree" +# token: +# secure: SONAR_TOKEN +# script: +# - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar diff --git a/Mage.Client/manifest.mf b/Mage.Client/manifest.mf deleted file mode 100644 index 3ccfa98e1d..0000000000 --- a/Mage.Client/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build -SplashScreen-Image: splash.jpg diff --git a/Mage.Client/pom.xml b/Mage.Client/pom.xml index 7a5a733b2c..77780930ce 100644 --- a/Mage.Client/pom.xml +++ b/Mage.Client/pom.xml @@ -6,10 +6,9 @@ org.mage mage-root - 1.4.31 + 1.4.35 - org.mage mage-client jar Mage Client @@ -52,12 +51,11 @@ com.mortennobel java-image-scaling - 0.8.5 + 0.8.6 - com.google.collections - google-collections - 1.0 + com.google.guava + guava org.swinglabs @@ -67,12 +65,12 @@ org.jetlang jetlang - 0.2.9 + 0.2.23 com.amazonaws aws-java-sdk-s3 - 1.11.286 + 1.11.498 com.jgoodies @@ -109,13 +107,13 @@ org.jsoup jsoup - 1.5.2 + 1.11.3 truevfs-profile-base net.java.truevfs jar - 0.10.8 + 0.11.1 truevfs-access-swing @@ -130,7 +128,7 @@ com.googlecode.soundlibs mp3spi - 1.9.5-1 + 1.9.5.4 javazoom @@ -155,14 +153,14 @@ org.apache.xmlgraphics batik-transcoder - 1.7 + 1.11 - - org.ocpsoft.prettytime - prettytime - 3.2.7.Final - + + org.ocpsoft.prettytime + prettytime + 4.0.2.Final + @@ -194,11 +192,13 @@ maven-jar-plugin - ${manifest.file} true mage.client.MageFrame + + splash.jpg + diff --git a/Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Séance Combo.dck b/Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Seance Combo.dck similarity index 96% rename from Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Séance Combo.dck rename to Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Seance Combo.dck index 6cb6e9d096..a11ea95c63 100644 --- a/Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Séance Combo.dck +++ b/Mage.Client/release/sample-decks/2013/Standard/DailyMTG Reconstructed - Sliving the good Life/Douglas Scheinberg's Seance Combo.dck @@ -1,22 +1,22 @@ -NAME:Douglas Scheinberg's Sance Combo -1 [AVR:42] Alchemist's Apprentice -4 [RTR:1] Angel of Serenity -1 [ISD:68] Mirror-Mad Phantasm -2 [ISD:248] Sulfur Falls -4 [RTR:249] Transguild Promenade -3 [RTR:247] Steam Vents -1 [AVR:1] Angel of Glory's Rise -4 [ISD:122] Unburial Rites -4 [RTR:201] Supreme Verdict -1 [ISD:55] Forbidden Alchemy -1 [ISD:61] Laboratory Maniac -3 [ISD:238] Clifftop Retreat -3 [ISD:43] Armored Skaab -2 [GTC:245] Sacred Foundry -4 [M13:69] Sphinx of Uthuun -3 [M13:225] Glacial Fortress -4 [RTR:172] Izzet Charm -2 [AVR:229] Slayers' Stronghold -2 [AVR:226] Cavern of Souls -4 [DKA:87] Faithless Looting -4 [RTR:241] Hallowed Fountain +NAME:Douglas Scheinberg's Sance Combo +1 [AVR:42] Alchemist's Apprentice +4 [RTR:1] Angel of Serenity +1 [ISD:68] Mirror-Mad Phantasm +2 [ISD:248] Sulfur Falls +4 [RTR:249] Transguild Promenade +3 [RTR:247] Steam Vents +1 [AVR:1] Angel of Glory's Rise +4 [ISD:122] Unburial Rites +4 [RTR:201] Supreme Verdict +1 [ISD:55] Forbidden Alchemy +1 [ISD:61] Laboratory Maniac +3 [ISD:238] Clifftop Retreat +3 [ISD:43] Armored Skaab +2 [GTC:245] Sacred Foundry +4 [M13:69] Sphinx of Uthuun +3 [M13:225] Glacial Fortress +4 [RTR:172] Izzet Charm +2 [AVR:229] Slayers' Stronghold +2 [AVR:226] Cavern of Souls +4 [DKA:87] Faithless Looting +4 [RTR:241] Hallowed Fountain diff --git a/Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramírez's Reanimator.dck b/Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramirez's Reanimator.dck similarity index 96% rename from Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramírez's Reanimator.dck rename to Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramirez's Reanimator.dck index db9096fb72..c8bf400e7d 100644 --- a/Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramírez's Reanimator.dck +++ b/Mage.Client/release/sample-decks/2013/Standard/GP Guadalajara (May 26)/Emmanuel Ramirez's Reanimator.dck @@ -1,31 +1,31 @@ -NAME:Emmanuel Ramrez's Reanimator -4 [ISD:170] Avacyn's Pilgrim -2 [ISD:249] Woodland Cemetery -3 [M13:159] Acidic Slime -3 [ISD:196] Mulch -1 [ISD:239] Gavony Township -3 [ISD:15] Fiend Hunter -3 [RTR:1] Angel of Serenity -2 [AVR:226] Cavern of Souls -4 [AVR:32] Restoration Angel -2 [ISD:242] Isolated Chapel -4 [RTR:248] Temple Garden -4 [RTR:243] Overgrown Tomb -3 [M13:160] Arbor Elf -4 [M13:193] Thragtusk -2 [DGM:103] Sin Collector -4 [RTR:165] Grisly Salvage -3 [M13:229] Sunpetal Grove -3 [RTR:270] Forest -2 [GTC:242] Godless Shrine -4 [ISD:122] Unburial Rites -SB: 1 [RTR:148] Centaur Healer -SB: 2 [DKA:17] Ray of Revelation -SB: 1 [M13:159] Acidic Slime -SB: 2 [ISD:181] Garruk Relentless -SB: 2 [RTR:141] Abrupt Decay -SB: 1 [ISD:15] Fiend Hunter -SB: 2 [RTR:213] Deathrite Shaman -SB: 1 [DGM:103] Sin Collector -SB: 2 [RTR:178] Loxodon Smiter -SB: 1 [ISD:115] Sever the Bloodline +NAME:Emmanuel Ramrez's Reanimator +4 [ISD:170] Avacyn's Pilgrim +2 [ISD:249] Woodland Cemetery +3 [M13:159] Acidic Slime +3 [ISD:196] Mulch +1 [ISD:239] Gavony Township +3 [ISD:15] Fiend Hunter +3 [RTR:1] Angel of Serenity +2 [AVR:226] Cavern of Souls +4 [AVR:32] Restoration Angel +2 [ISD:242] Isolated Chapel +4 [RTR:248] Temple Garden +4 [RTR:243] Overgrown Tomb +3 [M13:160] Arbor Elf +4 [M13:193] Thragtusk +2 [DGM:103] Sin Collector +4 [RTR:165] Grisly Salvage +3 [M13:229] Sunpetal Grove +3 [RTR:270] Forest +2 [GTC:242] Godless Shrine +4 [ISD:122] Unburial Rites +SB: 1 [RTR:148] Centaur Healer +SB: 2 [DKA:17] Ray of Revelation +SB: 1 [M13:159] Acidic Slime +SB: 2 [ISD:181] Garruk Relentless +SB: 2 [RTR:141] Abrupt Decay +SB: 1 [ISD:15] Fiend Hunter +SB: 2 [RTR:213] Deathrite Shaman +SB: 1 [DGM:103] Sin Collector +SB: 2 [RTR:178] Loxodon Smiter +SB: 1 [ISD:115] Sever the Bloodline diff --git a/Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frédéric Mercier's Esper Control.dck b/Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frederic Mercier's Esper Control.dck similarity index 96% rename from Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frédéric Mercier's Esper Control.dck rename to Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frederic Mercier's Esper Control.dck index 40acc0590e..70622a3155 100644 --- a/Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frédéric Mercier's Esper Control.dck +++ b/Mage.Client/release/sample-decks/2013/Standard/GP Quebec City/Frederic Mercier's Esper Control.dck @@ -1,33 +1,33 @@ -NAME:Frdric Mercier's Esper Control -2 [M13:26] Planar Cleansing -1 [RTR:250] Plains -4 [M13:225] Glacial Fortress -2 [GTC:63] Devour Flesh -4 [ISD:83] Think Twice -4 [RTR:145] Azorius Charm -2 [ISD:78] Snapcaster Mage -2 [GTC:249] Watery Grave -1 [RTR:82] Ultimate Price -1 [RTR:156] Dramatic Rescue -2 [GPT:157] Godless Shrine -3 [AVR:32] Restoration Angel -4 [M13:43] Augur of Bolas -4 [ISD:242] Isolated Chapel -4 [RTR:201] Supreme Verdict -2 [MIR:61] Dissipate -1 [RTR:256] Island -1 [RTR:255] Island -4 [ISD:245] Nephalia Drownyard -4 [RTR:241] Hallowed Fountain -4 [M13:223] Drowned Catacomb -4 [RTR:200] Sphinx's Revelation -SB: 1 [WWK:26] Dispel -SB: 3 [AVR:104] Gloom Surgeon -SB: 2 [M11:96] Duress -SB: 2 [ISD:236] Witchbane Orb -SB: 1 [RTR:18] Rest in Peace -SB: 1 [RTR:36] Dispel -SB: 1 [SOK:158] Pithing Needle -SB: 1 [RTR:47] Psychic Spiral -SB: 2 [M13:56] Jace, Memory Adept -SB: 1 [M12:69] Negate +NAME:Frdric Mercier's Esper Control +2 [M13:26] Planar Cleansing +1 [RTR:250] Plains +4 [M13:225] Glacial Fortress +2 [GTC:63] Devour Flesh +4 [ISD:83] Think Twice +4 [RTR:145] Azorius Charm +2 [ISD:78] Snapcaster Mage +2 [GTC:249] Watery Grave +1 [RTR:82] Ultimate Price +1 [RTR:156] Dramatic Rescue +2 [GPT:157] Godless Shrine +3 [AVR:32] Restoration Angel +4 [M13:43] Augur of Bolas +4 [ISD:242] Isolated Chapel +4 [RTR:201] Supreme Verdict +2 [MIR:61] Dissipate +1 [RTR:256] Island +1 [RTR:255] Island +4 [ISD:245] Nephalia Drownyard +4 [RTR:241] Hallowed Fountain +4 [M13:223] Drowned Catacomb +4 [RTR:200] Sphinx's Revelation +SB: 1 [WWK:26] Dispel +SB: 3 [AVR:104] Gloom Surgeon +SB: 2 [M11:96] Duress +SB: 2 [ISD:236] Witchbane Orb +SB: 1 [RTR:18] Rest in Peace +SB: 1 [RTR:36] Dispel +SB: 1 [SOK:158] Pithing Needle +SB: 1 [RTR:47] Psychic Spiral +SB: 2 [M13:56] Jace, Memory Adept +SB: 1 [M12:69] Negate diff --git a/Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jérémy Dezani's Jund Midrange.dck b/Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jeremy Dezani's Jund Midrange.dck similarity index 96% rename from Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jérémy Dezani's Jund Midrange.dck rename to Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jeremy Dezani's Jund Midrange.dck index 3a4b62e014..e5e32ee185 100644 --- a/Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jérémy Dezani's Jund Midrange.dck +++ b/Mage.Client/release/sample-decks/2013/Standard/GP Verona/Jeremy Dezani's Jund Midrange.dck @@ -1,36 +1,36 @@ -NAME:Jrmy Dezani's Jund Midrange -4 [M13:170] Farseek -3 [AVR:129] Bonfire of the Damned -1 [DKA:76] Tragic Slip -4 [ISD:249] Woodland Cemetery -2 [RTR:141] Abrupt Decay -3 [ISD:105] Liliana of the Veil -3 [M13:222] Dragonskull Summit -1 [RTR:82] Ultimate Price -2 [ISD:243] Kessig Wolf Run -1 [M13:217] Staff of Nin -1 [M13:101] Murder -4 [GTC:247] Stomping Ground -3 [ISD:215] Olivia Voldaren -2 [M13:174] Garruk, Primal Hunter -2 [RTR:188] Rakdos's Return -4 [DKA:140] Huntmaster of the Fells -4 [RTR:243] Overgrown Tomb -2 [M13:160] Arbor Elf -4 [M13:193] Thragtusk -4 [RTR:238] Blood Crypt -2 [M13:228] Rootbound Crag -1 [RTR:101] Mizzium Mortars -1 [RTR:157] Dreadbore -2 [RTR:270] Forest -SB: 1 [RTR:188] Rakdos's Return -SB: 1 [AVR:129] Bonfire of the Damned -SB: 1 [DKA:76] Tragic Slip -SB: 2 [M13:159] Acidic Slime -SB: 1 [RTR:141] Abrupt Decay -SB: 1 [DKA:149] Grafdigger's Cage -SB: 2 [M13:90] Duress -SB: 1 [M13:219] Tormod's Crypt -SB: 3 [RTR:197] Slaughter Games -SB: 1 [RTR:101] Mizzium Mortars -SB: 1 [AVR:149] Pillar of Flame +NAME:Jrmy Dezani's Jund Midrange +4 [M13:170] Farseek +3 [AVR:129] Bonfire of the Damned +1 [DKA:76] Tragic Slip +4 [ISD:249] Woodland Cemetery +2 [RTR:141] Abrupt Decay +3 [ISD:105] Liliana of the Veil +3 [M13:222] Dragonskull Summit +1 [RTR:82] Ultimate Price +2 [ISD:243] Kessig Wolf Run +1 [M13:217] Staff of Nin +1 [M13:101] Murder +4 [GTC:247] Stomping Ground +3 [ISD:215] Olivia Voldaren +2 [M13:174] Garruk, Primal Hunter +2 [RTR:188] Rakdos's Return +4 [DKA:140] Huntmaster of the Fells +4 [RTR:243] Overgrown Tomb +2 [M13:160] Arbor Elf +4 [M13:193] Thragtusk +4 [RTR:238] Blood Crypt +2 [M13:228] Rootbound Crag +1 [RTR:101] Mizzium Mortars +1 [RTR:157] Dreadbore +2 [RTR:270] Forest +SB: 1 [RTR:188] Rakdos's Return +SB: 1 [AVR:129] Bonfire of the Damned +SB: 1 [DKA:76] Tragic Slip +SB: 2 [M13:159] Acidic Slime +SB: 1 [RTR:141] Abrupt Decay +SB: 1 [DKA:149] Grafdigger's Cage +SB: 2 [M13:90] Duress +SB: 1 [M13:219] Tormod's Crypt +SB: 3 [RTR:197] Slaughter Games +SB: 1 [RTR:101] Mizzium Mortars +SB: 1 [AVR:149] Pillar of Flame diff --git a/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schönegger's Miracles.dck b/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schonegger's Miracles.dck similarity index 96% rename from Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schönegger's Miracles.dck rename to Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schonegger's Miracles.dck index 1959f8d1e6..791dfa7183 100644 --- a/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schönegger's Miracles.dck +++ b/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Philipp Schonegger's Miracles.dck @@ -1,32 +1,32 @@ -NAME:Philipp Schnegger's Miracles -4 [C13:341] Island -4 [CHK:268] Sensei's Divining Top -4 [ONS:316] Flooded Strand -2 [AVR:20] Entreat the Angels -3 [WWK:31] Jace, the Mind Sculptor -3 [ISD:78] Snapcaster Mage -4 [ALL:42] Force of Will -2 [ZEN:211] Arid Mesa -2 [M12:73] Ponder -1 [MMA:70] Vendilion Clique -4 [CMD:40] Brainstorm -1 [LEG:248] Karakas -2 [7ED:67] Counterspell -3 [CSP:31] Counterbalance -4 [AVR:38] Terminus -4 [ZEN:223] Scalding Tarn -2 [ZEN:67] Spell Pierce -2 [C13:337] Plains -2 [3ED:306] Volcanic Island -3 [3ED:304] Tundra -4 [DDF:22] Swords to Plowshares -SB: 1 [5ED:262] Pyroblast -SB: 1 [AVR:20] Entreat the Angels -SB: 3 [CMD:46] Flusterstorm -SB: 2 [4ED:236] Red Elemental Blast -SB: 1 [TSB:6] Disenchant -SB: 2 [MMA:204] Engineered Explosives -SB: 1 [7ED:67] Counterspell -SB: 1 [RTR:201] Supreme Verdict -SB: 1 [MMA:70] Vendilion Clique -SB: 2 [RTR:18] Rest in Peace +NAME:Philipp Schnegger's Miracles +4 [C13:341] Island +4 [CHK:268] Sensei's Divining Top +4 [ONS:316] Flooded Strand +2 [AVR:20] Entreat the Angels +3 [WWK:31] Jace, the Mind Sculptor +3 [ISD:78] Snapcaster Mage +4 [ALL:42] Force of Will +2 [ZEN:211] Arid Mesa +2 [M12:73] Ponder +1 [MMA:70] Vendilion Clique +4 [CMD:40] Brainstorm +1 [LEG:248] Karakas +2 [7ED:67] Counterspell +3 [CSP:31] Counterbalance +4 [AVR:38] Terminus +4 [ZEN:223] Scalding Tarn +2 [ZEN:67] Spell Pierce +2 [C13:337] Plains +2 [3ED:306] Volcanic Island +3 [3ED:304] Tundra +4 [DDF:22] Swords to Plowshares +SB: 1 [5ED:262] Pyroblast +SB: 1 [AVR:20] Entreat the Angels +SB: 3 [CMD:46] Flusterstorm +SB: 2 [4ED:236] Red Elemental Blast +SB: 1 [TSB:6] Disenchant +SB: 2 [MMA:204] Engineered Explosives +SB: 1 [7ED:67] Counterspell +SB: 1 [RTR:201] Supreme Verdict +SB: 1 [MMA:70] Vendilion Clique +SB: 2 [RTR:18] Rest in Peace diff --git a/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Böttcher's Deathblade.dck b/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Bottcher's Deathblade.dck similarity index 96% rename from Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Böttcher's Deathblade.dck rename to Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Bottcher's Deathblade.dck index eeb9e9c781..668d8ad15d 100644 --- a/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Böttcher's Deathblade.dck +++ b/Mage.Client/release/sample-decks/2014/Legacy/GP Paris/Stefan Bottcher's Deathblade.dck @@ -1,42 +1,42 @@ -NAME:Stefan Bttcher's Deathblade -1 [WWK:134] Creeping Tar Pit -4 [RTR:213] Deathrite Shaman -1 [AVR:20] Entreat the Angels -2 [C13:63] True-Name Nemesis -2 [WWK:31] Jace, the Mind Sculptor -3 [ISD:78] Snapcaster Mage -3 [MMA:75] Dark Confidant -1 [MMA:70] Vendilion Clique -1 [NPH:130] Batterskull -1 [ARB:85] Zealous Persecution -4 [CMD:40] Brainstorm -2 [THS:107] Thoughtseize -1 [MMA:204] Engineered Explosives -1 [BOK:163] Umezawa's Jitte -1 [3ED:298] Scrubland -1 [C13:337] Plains -3 [3ED:305] Underground Sea -3 [3ED:304] Tundra -4 [DDF:22] Swords to Plowshares -1 [3ED:303] Tropical Island -1 [C13:341] Island -3 [ONS:316] Flooded Strand -1 [C13:345] Swamp -1 [ZEN:219] Marsh Flats -2 [TMP:340] Wasteland -1 [LEG:248] Karakas -1 [MMA:219] Academy Ruins -1 [7ED:67] Counterspell -3 [ONS:321] Polluted Delta -3 [ZEN:67] Spell Pierce -3 [WWK:20] Stoneforge Mystic -SB: 1 [ISD:105] Liliana of the Veil -SB: 1 [RTR:155] Detention Sphere -SB: 3 [ALL:42] Force of Will -SB: 1 [RTR:201] Supreme Verdict -SB: 3 [M11:21] Leyline of Sanctity -SB: 1 [MBS:138] Sword of Feast and Famine -SB: 2 [NPH:74] Surgical Extraction -SB: 1 [THS:65] Swan Song -SB: 1 [MMA:213] Relic of Progenitus -SB: 1 [NMS:111] Reverent Silence +NAME:Stefan Bttcher's Deathblade +1 [WWK:134] Creeping Tar Pit +4 [RTR:213] Deathrite Shaman +1 [AVR:20] Entreat the Angels +2 [C13:63] True-Name Nemesis +2 [WWK:31] Jace, the Mind Sculptor +3 [ISD:78] Snapcaster Mage +3 [MMA:75] Dark Confidant +1 [MMA:70] Vendilion Clique +1 [NPH:130] Batterskull +1 [ARB:85] Zealous Persecution +4 [CMD:40] Brainstorm +2 [THS:107] Thoughtseize +1 [MMA:204] Engineered Explosives +1 [BOK:163] Umezawa's Jitte +1 [3ED:298] Scrubland +1 [C13:337] Plains +3 [3ED:305] Underground Sea +3 [3ED:304] Tundra +4 [DDF:22] Swords to Plowshares +1 [3ED:303] Tropical Island +1 [C13:341] Island +3 [ONS:316] Flooded Strand +1 [C13:345] Swamp +1 [ZEN:219] Marsh Flats +2 [TMP:340] Wasteland +1 [LEG:248] Karakas +1 [MMA:219] Academy Ruins +1 [7ED:67] Counterspell +3 [ONS:321] Polluted Delta +3 [ZEN:67] Spell Pierce +3 [WWK:20] Stoneforge Mystic +SB: 1 [ISD:105] Liliana of the Veil +SB: 1 [RTR:155] Detention Sphere +SB: 3 [ALL:42] Force of Will +SB: 1 [RTR:201] Supreme Verdict +SB: 3 [M11:21] Leyline of Sanctity +SB: 1 [MBS:138] Sword of Feast and Famine +SB: 2 [NPH:74] Surgical Extraction +SB: 1 [THS:65] Swan Song +SB: 1 [MMA:213] Relic of Progenitus +SB: 1 [NMS:111] Reverent Silence diff --git a/Mage.Client/serverlist.txt b/Mage.Client/serverlist.txt deleted file mode 100644 index caecdb8ac0..0000000000 --- a/Mage.Client/serverlist.txt +++ /dev/null @@ -1,6 +0,0 @@ -XMage.de 1 (Europe/Germany) fast :xmage.de:17171 -old xmage.de (Europe/Germany) :185.3.232.200:17171 -XMage Players MTG:xmageplayersmtg.ddns.net:17171 -XMage.tahiti :xmage.tahiti.one:443 -Seedds Server (Asia) :115.29.203.80:17171 -localhost -> connect to your local server (must be started):localhost:17171 diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.form b/Mage.Client/src/main/java/mage/client/MageFrame.form index 189853af51..1c0968259a 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.form +++ b/Mage.Client/src/main/java/mage/client/MageFrame.form @@ -1,6 +1,24 @@
+ + + + + + + + + + + + + + + + + + @@ -26,7 +44,7 @@ - + @@ -85,7 +103,6 @@ - @@ -101,7 +118,6 @@ - @@ -118,7 +134,6 @@ - @@ -131,11 +146,10 @@ - + - @@ -152,7 +166,6 @@ - @@ -169,7 +182,6 @@ - @@ -186,7 +198,6 @@ - @@ -200,10 +211,9 @@ - + - @@ -211,6 +221,22 @@ + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/MageFrame.java b/Mage.Client/src/main/java/mage/client/MageFrame.java index 3437772294..b94c7459f3 100644 --- a/Mage.Client/src/main/java/mage/client/MageFrame.java +++ b/Mage.Client/src/main/java/mage/client/MageFrame.java @@ -1,24 +1,11 @@ - package mage.client; -import java.awt.*; -import java.awt.event.*; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.net.SocketException; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.prefs.Preferences; -import javax.imageio.ImageIO; -import javax.swing.*; -import javax.swing.event.PopupMenuEvent; -import javax.swing.event.PopupMenuListener; import mage.cards.action.ActionCallback; import mage.cards.decks.Deck; import mage.cards.repository.CardRepository; +import mage.cards.repository.CardScanner; +import mage.cards.repository.ExpansionRepository; +import mage.cards.repository.RepositoryUtil; import mage.client.cards.BigCard; import mage.client.chat.ChatPanelBasic; import mage.client.components.*; @@ -47,6 +34,7 @@ import mage.client.util.stats.UpdateMemUsageTask; import mage.components.ImagePanel; import mage.components.ImagePanelStyle; import mage.constants.PlayerAction; +import mage.game.draft.RateCard; import mage.interfaces.MageClient; import mage.interfaces.callback.CallbackClient; import mage.interfaces.callback.ClientCallback; @@ -63,12 +51,28 @@ import net.java.truevfs.access.TConfig; import net.java.truevfs.kernel.spec.FsAccessOption; import org.apache.log4j.Logger; import org.mage.card.arcane.ManaSymbols; -import org.mage.plugins.card.images.DownloadPictures; +import org.mage.plugins.card.images.DownloadPicturesService; import org.mage.plugins.card.info.CardInfoPaneImpl; import org.mage.plugins.card.utils.impl.ImageManagerImpl; +import javax.imageio.ImageIO; +import javax.swing.*; +import javax.swing.event.PopupMenuEvent; +import javax.swing.event.PopupMenuListener; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketException; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.prefs.Preferences; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class MageFrame extends javax.swing.JFrame implements MageClient { @@ -83,17 +87,19 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private static final String PASSWORD_ARG = "-pw"; private static final String SERVER_ARG = "-server"; private static final String PORT_ARG = "-port"; + private static final String DEBUG_ARG = "-debug"; private static final String NOT_CONNECTED_TEXT = ""; private static MageFrame instance; private final ConnectDialog connectDialog; + private WhatsNewDialog whatsNewDialog; // can be null private final ErrorDialog errorDialog; private static CallbackClient callbackClient; private static final Preferences PREFS = Preferences.userNodeForPackage(MageFrame.class); private JLabel title; private Rectangle titleRectangle; - private static final MageVersion VERSION = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion VERSION = new MageVersion(MageFrame.class); private Connection currentConnection; private static MagePane activeFrame; private static boolean liteMode = false; @@ -105,6 +111,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private static String startPassword = ""; private static String startServer = "localhost"; private static int startPort = -1; + private static boolean debugMode = false; private static final Map CHATS = new HashMap<>(); private static final Map GAMES = new HashMap<>(); @@ -136,7 +143,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { public static boolean isGray() { return grayMode; } - + public static boolean isSkipSmallSymbolGenerationForExisting() { return skipSmallSymbolGenerationForExisting; } @@ -212,6 +219,18 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { LOGGER.fatal(null, ex); } + // DATA PREPARE + RepositoryUtil.bootstrapLocalDb(); + // re-create database on empty (e.g. after new build cleaned db on startup) + if (RepositoryUtil.CARD_DB_RECREATE_BY_CLIENT_SIDE && RepositoryUtil.isDatabaseEmpty()) { + LOGGER.info("DB: creating cards database"); + CardScanner.scan(); + LOGGER.info("Done."); + } + + if (RateCard.PRELOAD_CARD_RATINGS_ON_STARTUP) { + RateCard.bootstrapCardsAndRatings(); + } ManaSymbols.loadImages(); Plugins.instance.loadPlugins(); @@ -227,6 +246,14 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { SessionHandler.startSession(this); callbackClient = new CallbackClientImpl(this); connectDialog = new ConnectDialog(); + try { + whatsNewDialog = new WhatsNewDialog(); + } catch (NoClassDefFoundError e) { + // JavaFX is not supported on old MacOS with OpenJDK + // https://bugs.openjdk.java.net/browse/JDK-8202132 + LOGGER.error("JavaFX is not supported by your system. What's new page will be disabled.", e); + whatsNewDialog = null; + } desktopPane.add(connectDialog, JLayeredPane.MODAL_LAYER); errorDialog = new ErrorDialog(); errorDialog.setLocation(100, 100); @@ -281,7 +308,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (Plugins.instance.isCounterPluginLoaded()) { int i = Plugins.instance.getGamesPlayed(); - JLabel label = new JLabel(" Games played: " + String.valueOf(i)); + JLabel label = new JLabel(" Games played: " + i); desktopPane.add(label, JLayeredPane.DEFAULT_LAYER + 1); label.setVisible(true); label.setForeground(Color.white); @@ -313,6 +340,11 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { SystemUtil.toggleMacOSFullScreenMode(this); } } + + // run what's new checks (loading in background) + SwingUtilities.invokeLater(() -> { + showWhatsNewDialog(false); + }); } private void setWindowTitle() { @@ -321,61 +353,76 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { + ((SessionHandler.getSession() != null && SessionHandler.isConnected()) ? SessionHandler.getVersionInfo() : NOT_CONNECTED_TEXT)); } + private void updateTooltipContainerSizes() { + JPanel cardPreviewContainer; + BigCard bigCard; + JPanel cardPreviewContainerRotated; + BigCard bigCardRotated; + try { + cardPreviewContainer = (JPanel) UI.getComponent(MageComponents.CARD_PREVIEW_CONTAINER); + bigCard = (BigCard) UI.getComponent(MageComponents.CARD_PREVIEW_PANE); + cardPreviewContainerRotated = (JPanel) UI.getComponent(MageComponents.CARD_PREVIEW_CONTAINER_ROTATED); + bigCardRotated = (BigCard) UI.getComponent(MageComponents.CARD_PREVIEW_PANE_ROTATED); + } catch (InterruptedException e) { + LOGGER.fatal("Can't update tooltip panel sizes"); + Thread.currentThread().interrupt(); + return; + } + + int height = GUISizeHelper.enlargedImageHeight; + int width = (int) ((float) height * (float) 0.64); + bigCard.setSize(width, height); + cardPreviewContainer.setBounds(0, 0, width + 80, height + 30); + bigCardRotated.setSize(height, width + 30); + cardPreviewContainerRotated.setBounds(0, 0, height + 80, width + 100 + 30); + } + private void addTooltipContainer() { - final JEditorPane cardInfoPane = (JEditorPane) Plugins.instance.getCardInfoPane(); + JEditorPane cardInfoPane = (JEditorPane) Plugins.instance.getCardInfoPane(); if (cardInfoPane == null) { + LOGGER.fatal("Can't find card tooltip plugin"); return; } cardInfoPane.setLocation(40, 40); cardInfoPane.setBackground(new Color(0, 0, 0, 0)); + UI.addComponent(MageComponents.CARD_INFO_PANE, cardInfoPane); MageRoundPane popupContainer = new MageRoundPane(); popupContainer.setLayout(null); - popupContainer.add(cardInfoPane); popupContainer.setVisible(false); - desktopPane.add(popupContainer, JLayeredPane.POPUP_LAYER); - - UI.addComponent(MageComponents.CARD_INFO_PANE, cardInfoPane); UI.addComponent(MageComponents.POPUP_CONTAINER, popupContainer); - // preview panel normal + + JPanel cardPreviewContainer = new JPanel(); cardPreviewContainer.setOpaque(false); cardPreviewContainer.setLayout(null); - BigCard bigCard = new BigCard(); - int height = GUISizeHelper.enlargedImageHeight; - int width = (int) ((float) height * (float) 0.64); - bigCard.setSize(width, height); - bigCard.setLocation(40, 40); - bigCard.setBackground(new Color(0, 0, 0, 0)); - - cardPreviewContainer.add(bigCard); cardPreviewContainer.setVisible(false); - cardPreviewContainer.setBounds(0, 0, width + 80, height + 30); - - UI.addComponent(MageComponents.CARD_PREVIEW_PANE, bigCard); + desktopPane.add(cardPreviewContainer, JLayeredPane.POPUP_LAYER); UI.addComponent(MageComponents.CARD_PREVIEW_CONTAINER, cardPreviewContainer); - desktopPane.add(cardPreviewContainer, JLayeredPane.POPUP_LAYER); + BigCard bigCard = new BigCard(); + bigCard.setLocation(40, 40); + bigCard.setBackground(new Color(0, 0, 0, 0)); + cardPreviewContainer.add(bigCard); + UI.addComponent(MageComponents.CARD_PREVIEW_PANE, bigCard); - // preview panel rotated JPanel cardPreviewContainerRotated = new JPanel(); cardPreviewContainerRotated.setOpaque(false); cardPreviewContainerRotated.setLayout(null); - bigCard = new BigCard(true); - bigCard.setSize(height, width + 30); - bigCard.setLocation(40, 40); - bigCard.setBackground(new Color(0, 0, 0, 0)); - cardPreviewContainerRotated.add(bigCard); cardPreviewContainerRotated.setVisible(false); - cardPreviewContainerRotated.setBounds(0, 0, height + 80, width + 100 + 30); - - UI.addComponent(MageComponents.CARD_PREVIEW_PANE_ROTATED, bigCard); + desktopPane.add(cardPreviewContainerRotated, JLayeredPane.POPUP_LAYER); UI.addComponent(MageComponents.CARD_PREVIEW_CONTAINER_ROTATED, cardPreviewContainerRotated); - desktopPane.add(cardPreviewContainerRotated, JLayeredPane.POPUP_LAYER); + BigCard bigCardRotated = new BigCard(true); + bigCardRotated.setLocation(40, 40); + bigCardRotated.setBackground(new Color(0, 0, 0, 0)); + cardPreviewContainerRotated.add(bigCardRotated); + UI.addComponent(MageComponents.CARD_PREVIEW_PANE_ROTATED, bigCardRotated); + + updateTooltipContainerSizes(); } private void setGUISizeTooltipContainer() { @@ -547,8 +594,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { container.repaint(); } } catch (InterruptedException e) { - + LOGGER.fatal("MageFrame error", e); + Thread.currentThread().interrupt(); } + // Nothing to do if (activeFrame == frame) { return; @@ -717,6 +766,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { boolean autoConnectParamValue = startUser != null || Boolean.parseBoolean(PREFS.get("autoConnect", "false")); boolean status = false; if (autoConnectParamValue) { + LOGGER.info("Auto-connecting to " + MagePreferences.getServerAddress()); status = performConnect(false); } return status; @@ -724,10 +774,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private boolean performConnect(boolean reconnect) { if (currentConnection == null || !reconnect) { - String server = MagePreferences.getServerAddress(); - int port = MagePreferences.getServerPort(); - String userName = MagePreferences.getUserName(server); - String password = MagePreferences.getPassword(server); + String server = MagePreferences.getLastServerAddress(); + int port = MagePreferences.getLastServerPort(); + String userName = MagePreferences.getLastServerUser(); + String password = MagePreferences.getLastServerPassword(); String proxyServer = PREFS.get("proxyAddress", ""); int proxyPort = Integer.parseInt(PREFS.get("proxyPort", "0")); ProxyType proxyType = ProxyType.valueByText(PREFS.get("proxyType", "None")); @@ -739,6 +789,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { currentConnection.setPassword(password); currentConnection.setHost(server); currentConnection.setPort(port); + // force to redownload db on updates + boolean redownloadDatabase = (ExpansionRepository.instance.getSetByCode("GRN") == null || CardRepository.instance.findCard("Island") == null); + currentConnection.setForceDBComparison(redownloadDatabase); String allMAC = ""; try { allMAC = Connection.getMAC(); @@ -760,7 +813,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { prepareAndShowTablesPane(); return true; } else { - showMessage("Unable to connect to server"); + showMessage("Unable connect to server: " + SessionHandler.getLastConnectError()); } } finally { setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); @@ -781,6 +834,8 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { // //GEN-BEGIN:initComponents private void initComponents() { + popupDebug = new javax.swing.JPopupMenu(); + menuDebugTestModalDialog = new javax.swing.JMenuItem(); desktopPane = new MageJDesktop(); mageToolbar = new javax.swing.JToolBar(); btnPreferences = new javax.swing.JButton(); @@ -799,8 +854,18 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { jSeparatorImages = new javax.swing.JToolBar.Separator(); btnAbout = new javax.swing.JButton(); jSeparator7 = new javax.swing.JToolBar.Separator(); + btnDebug = new javax.swing.JButton(); + separatorDebug = new javax.swing.JToolBar.Separator(); jMemUsageLabel = new javax.swing.JLabel(); + menuDebugTestModalDialog.setText("Test Modal Dialogs"); + menuDebugTestModalDialog.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuDebugTestModalDialogActionPerformed(evt); + } + }); + popupDebug.add(menuDebugTestModalDialog); + setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE); setMinimumSize(new java.awt.Dimension(1024, 768)); @@ -818,7 +883,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnPreferences.setToolTipText("By changing the settings in the preferences window you can adjust the look and behaviour of xmage."); btnPreferences.setFocusable(false); btnPreferences.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnPreferences.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnPreferences.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnPreferencesActionPerformed(evt); @@ -831,7 +895,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnConnect.setToolTipText("Connect to or disconnect from a XMage server."); btnConnect.setFocusable(false); btnConnect.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnConnect.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnConnect.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnConnectActionPerformed(evt); @@ -845,7 +908,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnDeckEditor.setToolTipText("Start the deck editor to create or modify decks."); btnDeckEditor.setFocusable(false); btnDeckEditor.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnDeckEditor.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnDeckEditor.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnDeckEditorActionPerformed(evt); @@ -855,11 +917,10 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(jSeparator2); btnCollectionViewer.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/collection.png"))); // NOI18N - btnCollectionViewer.setText("Viewer"); + btnCollectionViewer.setText("Card Viewer"); btnCollectionViewer.setToolTipText("Card viewer to show the cards of sets. "); btnCollectionViewer.setFocusable(false); btnCollectionViewer.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnCollectionViewer.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnCollectionViewer.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnCollectionViewerActionPerformed(evt); @@ -873,7 +934,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnSendFeedback.setToolTipText("Send some feedback to the developers."); btnSendFeedback.setFocusable(false); btnSendFeedback.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnSendFeedback.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnSendFeedback.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnSendFeedbackActionPerformed(evt); @@ -887,7 +947,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnSymbols.setToolTipText("Load the mana and other card symbols from the internet.
\nOtherwise you only see the replacement sequence like {U} for blue mana symbol.
\nYou need to do that only once."); btnSymbols.setFocusable(false); btnSymbols.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnSymbols.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnSymbols.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnSymbolsActionPerformed(evt); @@ -901,7 +960,6 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnImages.setToolTipText("Load card images from external sources."); btnImages.setFocusable(false); btnImages.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnImages.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnImages.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnImagesActionPerformed(evt); @@ -912,10 +970,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { btnAbout.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/about.png"))); // NOI18N btnAbout.setText("About"); - btnAbout.setToolTipText("Some information about the developers."); + btnAbout.setToolTipText("About app"); btnAbout.setFocusable(false); btnAbout.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT); - btnAbout.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); btnAbout.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnAboutActionPerformed(evt); @@ -924,6 +981,19 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { mageToolbar.add(btnAbout); mageToolbar.add(jSeparator7); + btnDebug.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/connect.png"))); // NOI18N + btnDebug.setText("Debug"); + btnDebug.setToolTipText("Show debug tools"); + btnDebug.setFocusable(false); + btnDebug.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnDebug.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnDebugMouseClicked(evt); + } + }); + mageToolbar.add(btnDebug); + mageToolbar.add(separatorDebug); + jMemUsageLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); jMemUsageLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/menu/memory.png"))); // NOI18N jMemUsageLabel.setText("100% Free mem"); @@ -934,16 +1004,16 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 769, Short.MAX_VALUE) - .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 838, Short.MAX_VALUE) + .addComponent(mageToolbar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(mageToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(2, 2, 2) - .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(mageToolbar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(2, 2, 2) + .addComponent(desktopPane, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE)) ); pack(); @@ -1009,8 +1079,17 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { downloadImages(); }//GEN-LAST:event_btnImagesActionPerformed + private void menuDebugTestModalDialogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuDebugTestModalDialogActionPerformed + final TestModalDialog dialog = new TestModalDialog(); + dialog.showDialog(); + }//GEN-LAST:event_menuDebugTestModalDialogActionPerformed + + private void btnDebugMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnDebugMouseClicked + popupDebug.show(evt.getComponent(), 0, evt.getComponent().getHeight()); + }//GEN-LAST:event_btnDebugMouseClicked + public void downloadImages() { - DownloadPictures.startDownload(); + DownloadPicturesService.startDownload(); } public void exitApp() { @@ -1160,7 +1239,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { /** * @param args the command line arguments */ - public static void main(final String args[]) { + public static void main(final String[] args) { // Workaround for #451 System.setProperty("java.util.Arrays.useLegacyMergeSort", "true"); LOGGER.info("Starting MAGE client version " + VERSION); @@ -1168,7 +1247,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { startTime = System.currentTimeMillis(); Thread.setDefaultUncaughtExceptionHandler((t, e) -> LOGGER.fatal(null, e)); - + SwingUtilities.invokeLater(() -> { for (int i = 0; i < args.length; i++) { String arg = args[i]; @@ -1184,22 +1263,25 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { if (arg.startsWith(SKIP_DONE_SYMBOLS)) { skipSmallSymbolGenerationForExisting = true; } - if (arg.startsWith(USER_ARG)){ - startUser = args[i+1]; + if (arg.startsWith(USER_ARG)) { + startUser = args[i + 1]; i++; } - if (arg.startsWith(PASSWORD_ARG)){ - startPassword = args[i+1]; + if (arg.startsWith(PASSWORD_ARG)) { + startPassword = args[i + 1]; i++; } - if (arg.startsWith(SERVER_ARG)){ - startServer = args[i+1]; + if (arg.startsWith(SERVER_ARG)) { + startServer = args[i + 1]; i++; } - if (arg.startsWith(PORT_ARG)){ - startPort = Integer.valueOf(args[i+1]); + if (arg.startsWith(PORT_ARG)) { + startPort = Integer.valueOf(args[i + 1]); i++; } + if (arg.startsWith(DEBUG_ARG)) { + debugMode = true; + } } if (!liteMode) { final SplashScreen splash = SplashScreen.getSplashScreen(); @@ -1212,14 +1294,18 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } } instance = new MageFrame(); - - if( startUser != null){ + + // debug menu + instance.separatorDebug.setVisible(debugMode); + instance.btnDebug.setVisible(debugMode); + + if (startUser != null) { instance.currentConnection = new Connection(); instance.currentConnection.setUsername(startUser); instance.currentConnection.setHost(startServer); - if (startPort > 0){ + if (startPort > 0) { instance.currentConnection.setPort(startPort); - }else { + } else { instance.currentConnection.setPort(MagePreferences.getServerPortWithDefault(Config.port)); } PreferencesDialog.setProxyInformation(instance.currentConnection); @@ -1234,6 +1320,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private javax.swing.JButton btnAbout; private javax.swing.JButton btnCollectionViewer; private javax.swing.JButton btnConnect; + private javax.swing.JButton btnDebug; private javax.swing.JButton btnDeckEditor; private javax.swing.JButton btnImages; private javax.swing.JButton btnPreferences; @@ -1250,6 +1337,9 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { private javax.swing.JToolBar.Separator jSeparatorImages; private javax.swing.JToolBar.Separator jSeparatorSymbols; private javax.swing.JToolBar mageToolbar; + private javax.swing.JMenuItem menuDebugTestModalDialog; + private javax.swing.JPopupMenu popupDebug; + private javax.swing.JToolBar.Separator separatorDebug; // End of variables declaration//GEN-END:variables private static final long serialVersionUID = -9104885239063142218L; @@ -1329,28 +1419,30 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } @Override - public void disconnected(final boolean errorCall) { + public void disconnected(final boolean askToReconnect) { if (SwingUtilities.isEventDispatchThread()) { // Returns true if the current thread is an AWT event dispatching thread. - LOGGER.info("DISCONNECTED (Event Dispatch Thread)"); + // REMOTE task, e.g. connecting + LOGGER.info("Disconnected from remote task"); setConnectButtonText(NOT_CONNECTED_TEXT); disableButtons(); hideGames(); hideTables(); } else { - LOGGER.info("DISCONNECTED (NO Event Dispatch Thread)"); + // USER mode, e.g. user plays and got disconnect + LOGGER.info("Disconnected from user mode"); SwingUtilities.invokeLater(() -> { - setConnectButtonText(NOT_CONNECTED_TEXT); - disableButtons(); - hideGames(); - hideTables(); - SessionHandler.disconnect(false); - if (errorCall) { - UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect?"); - message.setButton1("No", null); - message.setButton2("Yes", PlayerAction.CLIENT_RECONNECT); - showUserRequestDialog(message); - } - } + SessionHandler.disconnect(false); // user already disconnected, can't do any online actions like quite chat + setConnectButtonText(NOT_CONNECTED_TEXT); + disableButtons(); + hideGames(); + hideTables(); + if (askToReconnect) { + UserRequestMessage message = new UserRequestMessage("Connection lost", "The connection to server was lost. Reconnect to " + MagePreferences.getLastServerAddress() + "?"); + message.setButton1("No", null); + message.setButton2("Yes", PlayerAction.CLIENT_RECONNECT); + showUserRequestDialog(message); + } + } ); } } @@ -1380,7 +1472,7 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { Plugins.instance.downloadSymbols(); break; case CLIENT_DOWNLOAD_CARD_IMAGES: - DownloadPictures.startDownload(); + DownloadPicturesService.startDownload(); break; case CLIENT_DISCONNECT: if (SessionHandler.isConnected()) { @@ -1509,7 +1601,13 @@ public class MageFrame extends javax.swing.JFrame implements MageClient { } balloonTip.setFont(GUISizeHelper.balloonTooltipFont); - addTooltipContainer(); + updateTooltipContainerSizes(); + } + + public void showWhatsNewDialog(boolean forceToShowPage) { + if (whatsNewDialog != null) { + whatsNewDialog.checkUpdatesAndShow(forceToShowPage); + } } } diff --git a/Mage.Client/src/main/java/mage/client/MagePane.java b/Mage.Client/src/main/java/mage/client/MagePane.java index 209dbbb6de..819ee17bf6 100644 --- a/Mage.Client/src/main/java/mage/client/MagePane.java +++ b/Mage.Client/src/main/java/mage/client/MagePane.java @@ -1,76 +1,78 @@ /* - * MagePane.java - * - * Created on 15-Dec-2009, 9:34:25 PM - */ -package mage.client; + * MagePane.java + * + * Created on 15-Dec-2009, 9:34:25 PM + */ + package mage.client; -import java.awt.AWTEvent; -import java.awt.KeyboardFocusManager; + import java.awt.*; -/** - * - * @author BetaSteward_at_googlemail.com - */ -public abstract class MagePane extends javax.swing.JLayeredPane { + /** + * @author BetaSteward_at_googlemail.com + */ + public abstract class MagePane extends javax.swing.JLayeredPane { - private String title = "no title set"; + private String title = "no title set"; - /** - * Creates new form MagePane - */ - public MagePane() { - initComponents(); - } + /** + * Creates new form MagePane + */ + public MagePane() { + initComponents(); + } - public void changeGUISize() { + public void changeGUISize() { - } + } - public void setTitle(String title) { - this.title = title; - } + public void setTitle(String title) { + this.title = title; + } - public String getTitle() { - return title; - } + public String getTitle() { + return title; + } - public void hideFrame() { - MageFrame.deactivate(this); - } + public void hideFrame() { + MageFrame.deactivate(this); + } - public void removeFrame() { - KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); - MageFrame.deactivate(this); - MageFrame.getDesktop().remove(this); - } + public void removeFrame() { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner(); + MageFrame.deactivate(this); + MageFrame.getDesktop().remove(this); + } - public void activated() { + public void activated() { - } + } - public void deactivated() { + public void deactivated() { - } + } - public void handleEvent(AWTEvent event) { - } + public void handleEvent(AWTEvent event) { + } - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { + public Container getContentPane() { + return this; + } - setBorder(null); + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { - }// //GEN-END:initComponents + setBorder(null); - // Variables declaration - do not modify//GEN-BEGIN:variables - // End of variables declaration//GEN-END:variables -} + }// //GEN-END:initComponents + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + } diff --git a/Mage.Client/src/main/java/mage/client/SessionHandler.java b/Mage.Client/src/main/java/mage/client/SessionHandler.java index 8524b125da..9a975275de 100644 --- a/Mage.Client/src/main/java/mage/client/SessionHandler.java +++ b/Mage.Client/src/main/java/mage/client/SessionHandler.java @@ -1,6 +1,5 @@ package mage.client; -import java.util.*; import mage.cards.decks.DeckCardLists; import mage.client.chat.LocalCommands; import mage.client.dialog.PreferencesDialog; @@ -15,20 +14,30 @@ import mage.remote.MageRemoteException; import mage.remote.Session; import mage.remote.SessionImpl; import mage.view.*; +import org.apache.log4j.Logger; + +import java.util.*; /** * Created by IGOUDT on 15-9-2016. */ public final class SessionHandler { + + private static final Logger logger = Logger.getLogger(SessionHandler.class); + private static Session session; + private static String lastConnectError = ""; + + private SessionHandler(){ + } public static void startSession(MageFrame mageFrame) { session = new SessionImpl(mageFrame); session.setJsonLogActive("true".equals(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_GAME_LOG_AUTO_SAVE, "true"))); } - + public static void ping() { session.ping(); } @@ -46,7 +55,17 @@ public final class SessionHandler { } public static boolean connect(Connection connection) { - return session.connect(connection); + lastConnectError = ""; + if (session.connect(connection)) { + return true; + } else { + lastConnectError = session.getLastError(); + return false; + } + } + + public static String getLastConnectError() { + return lastConnectError; } public static boolean stopConnecting() { @@ -169,7 +188,7 @@ public final class SessionHandler { try { return session.getTournament(tournamentId); } catch (MageRemoteException e) { - e.printStackTrace(); + logger.info(e); return null; } @@ -263,7 +282,7 @@ public final class SessionHandler { try { return session.getRoomUsers(roomId); } catch (MageRemoteException e) { - e.printStackTrace(); + logger.info(e); return Collections.emptyList(); } } @@ -272,8 +291,8 @@ public final class SessionHandler { try { return session.getFinishedMatches(roomId); } catch (MageRemoteException e) { - e.printStackTrace(); - return new ArrayList<>(); + logger.info(e); + return Collections.emptyList(); } } @@ -289,8 +308,8 @@ public final class SessionHandler { try { return session.getTables(roomId); } catch (MageRemoteException e) { - e.printStackTrace(); - return new ArrayList<>(); + logger.info(e); + return Collections.emptyList(); } } diff --git a/Mage.Client/src/main/java/mage/client/cards/Card.java b/Mage.Client/src/main/java/mage/client/cards/Card.java index 73b862e3e1..9cd5b3bc87 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Card.java +++ b/Mage.Client/src/main/java/mage/client/cards/Card.java @@ -77,7 +77,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis this.gameId = gameId; this.card = card; this.bigCard = bigCard; - small = new BufferedImage(Config.dimensions.frameWidth, Config.dimensions.frameHeight, BufferedImage.TYPE_INT_RGB); + small = new BufferedImage(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight(), BufferedImage.TYPE_INT_RGB); backgroundName = getBackgroundName(); background = ImageHelper.getBackground(card, backgroundName); @@ -129,7 +129,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis gSmall.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); gSmall.setColor(Color.BLACK); - gSmall.drawImage(ImageHelper.scaleImage(image, Config.dimensions.frameWidth, Config.dimensions.frameHeight), 0, 0, this); + gSmall.drawImage(ImageHelper.scaleImage(image, Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()), 0, 0, this); gImage.setFont(new Font("Arial", Font.PLAIN, NAME_FONT_MAX_SIZE)); gImage.drawString(card.getName()+"TEST", CONTENT_MAX_XOFFSET, NAME_MAX_YOFFSET); @@ -145,16 +145,16 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis gImage.dispose(); - gSmall.setFont(new Font("Arial", Font.PLAIN, Config.dimensions.nameFontSize)); - gSmall.drawString(card.getName()+"TEST2", Config.dimensions.contentXOffset, Config.dimensions.nameYOffset); + gSmall.setFont(new Font("Arial", Font.PLAIN, Config.dimensions.getNameFontSize())); + gSmall.drawString(card.getName()+"TEST2", Config.dimensions.getContentXOffset(), Config.dimensions.getNameYOffset()); if (card.isCreature()) { - gSmall.drawString(card.getPower() + "/-/" + card.getToughness(), Config.dimensions.powBoxTextLeft, Config.dimensions.powBoxTextTop); + gSmall.drawString(card.getPower() + "/-/" + card.getToughness(), Config.dimensions.getPowBoxTextLeft(), Config.dimensions.getPowBoxTextTop()); } else if (card.isPlanesWalker()) { - gSmall.drawString(card.getLoyalty(), Config.dimensions.powBoxTextLeft, Config.dimensions.powBoxTextTop); + gSmall.drawString(card.getLoyalty(), Config.dimensions.getPowBoxTextLeft(), Config.dimensions.getPowBoxTextTop()); } if (!card.getCardTypes().isEmpty()) { - gSmall.drawString(cardType, Config.dimensions.contentXOffset, Config.dimensions.typeYOffset); + gSmall.drawString(cardType, Config.dimensions.getContentXOffset(), Config.dimensions.getTypeYOffset()); } drawText(); @@ -287,7 +287,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis setMinimumSize(getPreferredSize()); setOpaque(false); - setPreferredSize(new Dimension(dimension.frameWidth, dimension.frameHeight)); + setPreferredSize(new Dimension(dimension.getFrameWidth(), dimension.getFrameHeight())); setLayout(null); jScrollPane1.setBorder(null); @@ -304,7 +304,7 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis add(jScrollPane1); jScrollPane1.setBounds(20, 110, 130, 100); - jScrollPane1.setBounds(new Rectangle(dimension.contentXOffset, dimension.textYOffset, dimension.textWidth, dimension.textHeight)); + jScrollPane1.setBounds(new Rectangle(dimension.getContentXOffset(), dimension.getTextYOffset(), dimension.getTextWidth(), dimension.getTextHeight())); }//
//GEN-END:initComponents @Override @@ -355,11 +355,11 @@ public class Card extends MagePermanent implements MouseMotionListener, MouseLis tooltipPopup.hide(); } PopupFactory factory = PopupFactory.getSharedInstance(); - tooltipPopup = factory.getPopup(this, tooltipText, (int) this.getLocationOnScreen().getX() + Config.dimensions.frameWidth, (int) this.getLocationOnScreen().getY() + 40); + tooltipPopup = factory.getPopup(this, tooltipText, (int) this.getLocationOnScreen().getX() + Config.dimensions.getFrameWidth(), (int) this.getLocationOnScreen().getY() + 40); tooltipPopup.show(); //hack to get tooltipPopup to resize to fit text tooltipPopup.hide(); - tooltipPopup = factory.getPopup(this, tooltipText, (int) this.getLocationOnScreen().getX() + Config.dimensions.frameWidth, (int) this.getLocationOnScreen().getY() + 40); + tooltipPopup = factory.getPopup(this, tooltipText, (int) this.getLocationOnScreen().getX() + Config.dimensions.getFrameWidth(), (int) this.getLocationOnScreen().getY() + 40); tooltipPopup.show(); tooltipShowing = true; diff --git a/Mage.Client/src/main/java/mage/client/cards/CardArea.java b/Mage.Client/src/main/java/mage/client/cards/CardArea.java index cb51c75543..c98be7e7b0 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardArea.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardArea.java @@ -1,4 +1,3 @@ - package mage.client.cards; import mage.cards.MageCard; @@ -71,6 +70,14 @@ public class CardArea extends JPanel implements MouseListener { this.verticalCardOffset = verticalCardOffset; } + private void fixDialogSize() { + // fix panel size (must include scrolls) + Dimension newSize = new Dimension(cardArea.getPreferredSize()); + newSize.width += 20; + newSize.height += 20; + this.setPreferredSize(newSize); + } + public void loadCards(CardsView showCards, BigCard bigCard, UUID gameId) { this.reloaded = true; cardArea.removeAll(); @@ -85,6 +92,8 @@ public class CardArea extends JPanel implements MouseListener { this.revalidate(); this.repaint(); + + fixDialogSize(); } public void loadCardsNarrow(CardsView showCards, BigCard bigCard, UUID gameId) { @@ -98,6 +107,8 @@ public class CardArea extends JPanel implements MouseListener { this.revalidate(); this.repaint(); + + fixDialogSize(); } private void loadCardsFew(CardsView showCards, BigCard bigCard, UUID gameId) { @@ -106,7 +117,7 @@ public class CardArea extends JPanel implements MouseListener { addCard(card, bigCard, gameId, rectangle); rectangle.translate(cardDimension.width, 0); } - cardArea.setPreferredSize(new Dimension(cardDimension.width * showCards.size(), cardDimension.height)); + cardArea.setPreferredSize(new Dimension(cardDimension.width * showCards.size(), cardDimension.height + verticalCardOffset)); } private void addCard(CardView card, BigCard bigCard, UUID gameId, Rectangle rectangle) { @@ -221,7 +232,7 @@ public class CardArea extends JPanel implements MouseListener { if (e.isAltDown()) { cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.ALT_DOUBLE_CLICK); } else { - cardEventSource.fireEvent(((MageCard) obj).getOriginal(),ClientEventType.DOUBLE_CLICK); + cardEventSource.fireEvent(((MageCard) obj).getOriginal(), ClientEventType.DOUBLE_CLICK); } } } diff --git a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java index f4c6a75976..4a094c6655 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardGrid.java @@ -14,7 +14,7 @@ import mage.client.util.ClientEventType; import mage.client.util.Event; import mage.client.util.GUISizeHelper; import mage.client.util.Listener; -import mage.utils.CardUtil; +import mage.utils.CardColorUtil; import mage.view.CardView; import mage.view.CardsView; import org.mage.card.arcane.CardPanel; @@ -172,8 +172,8 @@ public class CardGrid extends javax.swing.JLayeredPane implements MouseListener, } break; case COLOR_IDENTITY: - if (CardUtil.getColorIdentitySortValue(cardImg.getOriginal().getManaCost(), cardImg.getOriginal().getColor(), cardImg.getOriginal().getRules()) - != CardUtil.getColorIdentitySortValue(lastCard.getOriginal().getManaCost(), lastCard.getOriginal().getColor(), lastCard.getOriginal().getRules())) { + if (CardColorUtil.getColorIdentitySortValue(cardImg.getOriginal().getManaCost(), cardImg.getOriginal().getColor(), cardImg.getOriginal().getRules()) + != CardColorUtil.getColorIdentitySortValue(lastCard.getOriginal().getManaCost(), lastCard.getOriginal().getColor(), lastCard.getOriginal().getRules())) { curColumn++; curRow = 0; } @@ -404,8 +404,8 @@ class CardColorDetailedIdentity implements Comparator { @Override public int compare(MageCard o1, MageCard o2) { - int val = CardUtil.getColorIdentitySortValue(o1.getOriginal().getManaCost(), o1.getOriginal().getColor(), o1.getOriginal().getRules()) - - CardUtil.getColorIdentitySortValue(o2.getOriginal().getManaCost(), o2.getOriginal().getColor(), o2.getOriginal().getRules()); + int val = CardColorUtil.getColorIdentitySortValue(o1.getOriginal().getManaCost(), o1.getOriginal().getColor(), o1.getOriginal().getRules()) + - CardColorUtil.getColorIdentitySortValue(o2.getOriginal().getManaCost(), o2.getOriginal().getColor(), o2.getOriginal().getRules()); if (val == 0) { return o1.getOriginal().getName().compareTo(o2.getOriginal().getName()); } else { diff --git a/Mage.Client/src/main/java/mage/client/cards/Cards.java b/Mage.Client/src/main/java/mage/client/cards/Cards.java index 6b0d64a5ba..32fa2a2060 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Cards.java +++ b/Mage.Client/src/main/java/mage/client/cards/Cards.java @@ -1,349 +1,339 @@ /* - * Cards.java - * - * Created on Dec 18, 2009, 10:40:12 AM - */ -package mage.client.cards; + * Cards.java + * + * Created on Dec 18, 2009, 10:40:12 AM + */ + package mage.client.cards; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; -import javax.swing.border.Border; -import javax.swing.border.EmptyBorder; -import mage.cards.MageCard; -import mage.client.plugins.impl.Plugins; -import mage.client.util.CardsViewUtil; -import mage.client.util.Config; -import mage.client.util.GUISizeHelper; -import mage.view.CardView; -import mage.view.CardsView; -import mage.view.PermanentView; -import mage.view.SimpleCardsView; -import mage.view.StackAbilityView; -import org.apache.log4j.Logger; -import org.mage.card.arcane.CardPanel; + import mage.cards.MageCard; + import mage.client.plugins.impl.Plugins; + import mage.client.util.CardsViewUtil; + import mage.client.util.Config; + import mage.client.util.GUISizeHelper; + import mage.view.*; + import org.apache.log4j.Logger; + import org.mage.card.arcane.CardPanel; -/** - * - * @author BetaSteward_at_googlemail.com - */ -public class Cards extends javax.swing.JPanel { + import javax.swing.border.Border; + import javax.swing.border.EmptyBorder; + import java.awt.*; + import java.util.*; + import java.util.Map.Entry; - private static final Logger LOGGER = Logger.getLogger(Cards.class); - private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0); + /** + * @author BetaSteward_at_googlemail.com + */ + public class Cards extends javax.swing.JPanel { - private final Map cards = new LinkedHashMap<>(); - private boolean dontDisplayTapped = false; - private static final int GAP_X = 5; // needed for marking cards with coloured fram (e.g. on hand) - private String zone; + private static final Logger LOGGER = Logger.getLogger(Cards.class); + private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0); - private int minOffsetY = 0; + private final Map cards = new LinkedHashMap<>(); + private boolean dontDisplayTapped = false; + private static final int GAP_X = 5; // needed for marking cards with coloured fram (e.g. on hand) + private String zone; - /** - * Defines whether component should be visible whenever there is no objects - * within. True by default. - */ - private boolean isVisibleIfEmpty = true; + private int minOffsetY = 0; - private Dimension cardDimension; + /** + * Defines whether component should be visible whenever there is no objects + * within. True by default. + */ + private boolean isVisibleIfEmpty = true; - /** - * Creates new form Cards - */ - public Cards() { - this(false); - } + private Dimension cardDimension; - public Cards(boolean skipAddingScrollPane) { - initComponents(skipAddingScrollPane); - setOpaque(false); - //cardArea.setOpaque(false); - setBackgroundColor(new Color(0, 0, 0, 100)); - if (!skipAddingScrollPane) { - jScrollPane1.setOpaque(false); - jScrollPane1.getViewport().setOpaque(false); - jScrollPane1.setBorder(EMPTY_BORDER); - } - if (Plugins.instance.isCardPluginLoaded()) { - cardArea.setLayout(null); - } - cardArea.setBorder(EMPTY_BORDER); - setGUISize(); - } + /** + * Creates new form Cards + */ + public Cards() { + this(false); + } - public void cleanUp() { - } + public Cards(boolean skipAddingScrollPane) { + initComponents(skipAddingScrollPane); + setOpaque(false); + //cardArea.setOpaque(false); + setBackgroundColor(new Color(0, 0, 0, 100)); + if (!skipAddingScrollPane) { + jScrollPane1.setOpaque(false); + jScrollPane1.getViewport().setOpaque(false); + jScrollPane1.setBorder(EMPTY_BORDER); + } + if (Plugins.instance.isCardPluginLoaded()) { + cardArea.setLayout(null); + } + cardArea.setBorder(EMPTY_BORDER); + setGUISize(); + } - public void changeGUISize() { - setGUISize(); - for (MageCard mageCard : cards.values()) { - mageCard.setCardBounds(0, 0, getCardDimension().width, getCardDimension().height); - mageCard.updateArtImage(); - mageCard.doLayout(); - } - layoutCards(); - sizeCards(cardDimension); - } + public void cleanUp() { + } - private void setGUISize() { - if (jScrollPane1 != null) { - jScrollPane1.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0)); - jScrollPane1.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize)); - } - } + public void changeGUISize() { + setGUISize(); + for (MageCard mageCard : cards.values()) { + mageCard.setCardBounds(0, 0, getCardDimension().width, getCardDimension().height); + mageCard.updateArtImage(); + mageCard.doLayout(); + } + layoutCards(); + sizeCards(getCardDimension()); + } - /** - * Sets components background color - * - * @param color - */ - public void setBackgroundColor(Color color) { - setBackground(color); - cardArea.setOpaque(true); - cardArea.setBackground(color); - } + private void setGUISize() { + if (jScrollPane1 != null) { + jScrollPane1.getVerticalScrollBar().setPreferredSize(new Dimension(GUISizeHelper.scrollBarSize, 0)); + jScrollPane1.getHorizontalScrollBar().setPreferredSize(new Dimension(0, GUISizeHelper.scrollBarSize)); + } + } - public void setVisibleIfEmpty(boolean isVisibleIfEmpty) { - this.isVisibleIfEmpty = isVisibleIfEmpty; - } + /** + * Sets components background color + * + * @param color + */ + public void setBackgroundColor(Color color) { + setBackground(color); + cardArea.setOpaque(true); + cardArea.setBackground(color); + } - @Override - public void setBorder(Border border) { - super.setBorder(border); - if (jScrollPane1 != null) { - jScrollPane1.setViewportBorder(border); - jScrollPane1.setBorder(border); - } - } + public void setVisibleIfEmpty(boolean isVisibleIfEmpty) { + this.isVisibleIfEmpty = isVisibleIfEmpty; + } - public boolean loadCards(SimpleCardsView cardsView, BigCard bigCard, UUID gameId) { - return loadCards(CardsViewUtil.convertSimple(cardsView), bigCard, gameId, true); - } + @Override + public void setBorder(Border border) { + super.setBorder(border); + if (jScrollPane1 != null) { + jScrollPane1.setViewportBorder(border); + jScrollPane1.setBorder(border); + } + } - public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId, boolean revertOrder) { - boolean changed = false; + public boolean loadCards(SimpleCardsView cardsView, BigCard bigCard, UUID gameId) { + return loadCards(CardsViewUtil.convertSimple(cardsView), bigCard, gameId, true); + } - // remove objects no longer on the stack from display - for (Iterator> i = cards.entrySet().iterator(); i.hasNext();) { - Entry entry = i.next(); - if (!cardsView.containsKey(entry.getKey())) { - removeCard(entry.getKey()); - i.remove(); - changed = true; - } - } + public boolean loadCards(CardsView cardsView, BigCard bigCard, UUID gameId, boolean revertOrder) { + boolean changed = false; - // Workaround for bug leaving display of objects on the stack (issue #213 https://github.com/magefree/mage/issues/213) - if (cardsView.isEmpty() && countCards() > 0) { - // problem happens with transformable cards - LOGGER.fatal("Card object on the cards panel was not removed"); - for (Component comp : cardArea.getComponents()) { - if (comp instanceof Card) { - Card card = (Card) comp; - LOGGER.fatal("Card name:" + card.getName() + " type:" + card.getType(null)); - } else if (comp instanceof MageCard) { - MageCard mageCard = (MageCard) comp; - LOGGER.fatal("MageCard name:" + mageCard.getName() + " toolTiptext:" + mageCard.getToolTipText()); - } else { - LOGGER.fatal("Unknown object:" + comp.getName() + " className:" + comp.getClass().getName()); - } - cardArea.remove(comp); - } - } + // remove objects no longer on the stack from display + for (Iterator> i = cards.entrySet().iterator(); i.hasNext(); ) { + Entry entry = i.next(); + if (!cardsView.containsKey(entry.getKey())) { + removeCard(entry.getKey()); + i.remove(); + changed = true; + } + } - java.util.List orderedList = new ArrayList<>(); - if (revertOrder) { - // order objects for display - for (CardView card : cardsView.values()) { - orderedList.add(0, card); - } - } else { - orderedList.addAll(cardsView.values()); - } + // Workaround for bug leaving display of objects on the stack (issue #213 https://github.com/magefree/mage/issues/213) + if (cardsView.isEmpty() && countCards() > 0) { + // problem happens with transformable cards + LOGGER.fatal("Card object on the cards panel was not removed"); + for (Component comp : cardArea.getComponents()) { + if (comp instanceof Card) { + Card card = (Card) comp; + LOGGER.fatal("Card name:" + card.getName() + " type:" + card.getType(null)); + } else if (comp instanceof MageCard) { + MageCard mageCard = (MageCard) comp; + LOGGER.fatal("MageCard name:" + mageCard.getName() + " toolTiptext:" + mageCard.getToolTipText()); + } else { + LOGGER.fatal("Unknown object:" + comp.getName() + " className:" + comp.getClass().getName()); + } + cardArea.remove(comp); + } + } - // add objects to the panel - for (CardView card : orderedList) { - if (dontDisplayTapped) { - if (card instanceof PermanentView) { - ((PermanentView) card).overrideTapped(false); - } - } - if (card instanceof StackAbilityView) { - CardView tmp = ((StackAbilityView) card).getSourceCard(); - tmp.overrideRules(card.getRules()); - tmp.setIsAbility(true); - tmp.overrideTargets(card.getTargets()); - tmp.overrideId(card.getId()); - tmp.setAbilityType(card.getAbilityType()); - card = tmp; - } else { - card.setAbilityType(null); - } - if (!cards.containsKey(card.getId())) { - addCard(card, bigCard, gameId); - changed = true; - } - cards.get(card.getId()).update(card); - } + java.util.List orderedList = new ArrayList<>(); + if (revertOrder) { + // order objects for display + for (CardView card : cardsView.values()) { + orderedList.add(0, card); + } + } else { + orderedList.addAll(cardsView.values()); + } - if (changed) { - layoutCards(); - } + // add objects to the panel + for (CardView card : orderedList) { + if (dontDisplayTapped) { + if (card instanceof PermanentView) { + ((PermanentView) card).overrideTapped(false); + } + } + if (card instanceof StackAbilityView) { + CardView tmp = ((StackAbilityView) card).getSourceCard(); + tmp.overrideRules(card.getRules()); + tmp.setIsAbility(true); + tmp.overrideTargets(card.getTargets()); + tmp.overrideId(card.getId()); + tmp.setAbilityType(card.getAbilityType()); + card = tmp; + } else { + card.setAbilityType(null); + } + if (!cards.containsKey(card.getId())) { + addCard(card, bigCard, gameId); + changed = true; + } + cards.get(card.getId()).update(card); + } - if (!isVisibleIfEmpty) { - cardArea.setVisible(!cards.isEmpty()); - } + if (changed) { + layoutCards(); + } - sizeCards(getCardDimension()); - this.revalidate(); - this.repaint(); + if (!isVisibleIfEmpty) { + cardArea.setVisible(!cards.isEmpty()); + } - return changed; - } + sizeCards(getCardDimension()); + this.revalidate(); + this.repaint(); - public void sizeCards(Dimension cardDimension) { - cardArea.setPreferredSize(new Dimension((int) ((cards.size()) * (cardDimension.getWidth() + GAP_X)) + 20, (int) (cardDimension.getHeight()) + 20)); - cardArea.revalidate(); - cardArea.repaint(); - } + return changed; + } - public int getNumberOfCards() { - return cards.size(); - } + public void sizeCards(Dimension cardDimension) { + cardArea.setPreferredSize(new Dimension((int) ((cards.size()) * (cardDimension.getWidth() + GAP_X)) + 20, (int) (cardDimension.getHeight()) + 20)); + cardArea.revalidate(); + cardArea.repaint(); + } - private Dimension getCardDimension() { - if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); - } - return cardDimension; - } + public int getNumberOfCards() { + return cards.size(); + } - public void setCardDimension(Dimension dimension) { - this.cardDimension = dimension; - for (Component component : cardArea.getComponents()) { - if (component instanceof CardPanel) { - component.setBounds(0, 0, dimension.width, dimension.height); - } - } - layoutCards(); - } + private Dimension getCardDimension() { + if (cardDimension == null) { + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); + } + return cardDimension; + } - private void addCard(CardView card, BigCard bigCard, UUID gameId) { - MageCard mageCard = Plugins.instance.getMageCard(card, bigCard, getCardDimension(), gameId, true, true); - if (zone != null) { - mageCard.setZone(zone); - } - cards.put(card.getId(), mageCard); - cardArea.add(mageCard); - definePosition(mageCard); - mageCard.setCardAreaRef(cardArea); - } + public void setCardDimension(Dimension dimension) { + this.cardDimension = dimension; + for (Component component : cardArea.getComponents()) { + if (component instanceof CardPanel) { + component.setBounds(0, 0, dimension.width, dimension.height); + } + } + layoutCards(); + } - private void definePosition(MageCard card) { - int dx = 0; - for (Component comp : cardArea.getComponents()) { - if (!comp.equals(card)) { - dx = Math.max(dx, (int) comp.getLocation().getX()); - } - } - dx += ((CardPanel) card).getCardWidth() + GAP_X; - card.setLocation(dx, (int) card.getLocation().getY()); - } + private void addCard(CardView card, BigCard bigCard, UUID gameId) { + MageCard mageCard = Plugins.instance.getMageCard(card, bigCard, getCardDimension(), gameId, true, true); + if (zone != null) { + mageCard.setZone(zone); + } + cards.put(card.getId(), mageCard); + cardArea.add(mageCard); + definePosition(mageCard); + mageCard.setCardAreaRef(cardArea); + } - private void removeCard(UUID cardId) { - for (Component comp : cardArea.getComponents()) { - if (comp instanceof Card) { - if (((Card) comp).getCardId().equals(cardId)) { - cardArea.remove(comp); - } - } else if (comp instanceof MageCard) { - if (((MageCard) comp).getOriginal().getId().equals(cardId)) { - cardArea.remove(comp); - } - } - } - } + private void definePosition(MageCard card) { + int dx = 0; + for (Component comp : cardArea.getComponents()) { + if (!comp.equals(card)) { + dx = Math.max(dx, (int) comp.getLocation().getX()); + } + } + dx += ((CardPanel) card).getCardWidth() + GAP_X; + card.setLocation(dx, (int) card.getLocation().getY()); + } - private int countCards() { - return cardArea.getComponentCount(); - } + private void removeCard(UUID cardId) { + for (Component comp : cardArea.getComponents()) { + if (comp instanceof Card) { + if (((Card) comp).getCardId().equals(cardId)) { + cardArea.remove(comp); + } + } else if (comp instanceof MageCard) { + if (((MageCard) comp).getOriginal().getId().equals(cardId)) { + cardArea.remove(comp); + } + } + } + } - /** - * This method is called from within the constructor to initialize the form. - * WARNING: Do NOT modify this code. The content of this method is always - * regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents(boolean skipAddingScrollPane) { - setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0, 0))); - setLayout(new java.awt.BorderLayout()); + private int countCards() { + return cardArea.getComponentCount(); + } - cardArea = new javax.swing.JPanel(); - cardArea.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0)); + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents(boolean skipAddingScrollPane) { + setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0, 0))); + setLayout(new java.awt.BorderLayout()); - if (skipAddingScrollPane) { - add(cardArea, java.awt.BorderLayout.CENTER); - } else{ - jScrollPane1 = new javax.swing.JScrollPane(); - jScrollPane1.setViewportView(cardArea); - jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); - add(jScrollPane1, java.awt.BorderLayout.CENTER); - } - }// //GEN-END:initComponents + cardArea = new javax.swing.JPanel(); + cardArea.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT, 0, 0)); - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JPanel cardArea; - private javax.swing.JScrollPane jScrollPane1; - // End of variables declaration//GEN-END:variables + if (skipAddingScrollPane) { + add(cardArea, java.awt.BorderLayout.CENTER); + } else { + jScrollPane1 = new javax.swing.JScrollPane(); + jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); + jScrollPane1.setViewportView(cardArea); + add(jScrollPane1, java.awt.BorderLayout.CENTER); + } + }// //GEN-END:initComponents - public void setDontDisplayTapped(boolean dontDisplayTapped) { - this.dontDisplayTapped = dontDisplayTapped; - } + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JPanel cardArea; + private javax.swing.JScrollPane jScrollPane1; + // End of variables declaration//GEN-END:variables - public void setHScrollSpeed(int unitIncrement) { - if (jScrollPane1 != null) { - jScrollPane1.getHorizontalScrollBar().setUnitIncrement(unitIncrement); - } - } + public void setDontDisplayTapped(boolean dontDisplayTapped) { + this.dontDisplayTapped = dontDisplayTapped; + } - public void setVScrollSpeed(int unitIncrement) { - if (jScrollPane1 != null) { - jScrollPane1.getVerticalScrollBar().setUnitIncrement(unitIncrement); - } - } + public void setHScrollSpeed(int unitIncrement) { + if (jScrollPane1 != null) { + jScrollPane1.getHorizontalScrollBar().setUnitIncrement(unitIncrement); + } + } - private void layoutCards() { - java.util.List cardsToLayout = new ArrayList<>(); - // get all the card panels - for (Component component : cardArea.getComponents()) { - if (component instanceof CardPanel) { - cardsToLayout.add((CardPanel) component); - } - } - // sort the cards - cardsToLayout.sort((cp1, cp2) -> Integer.valueOf(cp1.getLocation().x).compareTo(cp2.getLocation().x)); - // relocate the cards - int dx = 0; - for (Component component : cardsToLayout) { - component.setLocation(dx, Math.max(component.getLocation().y, minOffsetY)); - dx += ((CardPanel) component).getCardWidth() + GAP_X; - } - } + public void setVScrollSpeed(int unitIncrement) { + if (jScrollPane1 != null) { + jScrollPane1.getVerticalScrollBar().setUnitIncrement(unitIncrement); + } + } - public void setZone(String zone) { - this.zone = zone; - } + private void layoutCards() { + java.util.List cardsToLayout = new ArrayList<>(); + // get all the card panels + for (Component component : cardArea.getComponents()) { + if (component instanceof CardPanel) { + cardsToLayout.add((CardPanel) component); + } + } + // sort the cards + cardsToLayout.sort((cp1, cp2) -> Integer.valueOf(cp1.getLocation().x).compareTo(cp2.getLocation().x)); + // relocate the cards + int dx = 0; + for (Component component : cardsToLayout) { + component.setLocation(dx, Math.max(component.getLocation().y, minOffsetY)); + dx += ((CardPanel) component).getCardWidth() + GAP_X; + } + } - public void setMinOffsetY(int minOffsetY) { - this.minOffsetY = minOffsetY; - } -} + public void setZone(String zone) { + this.zone = zone; + } + + public void setMinOffsetY(int minOffsetY) { + this.minOffsetY = minOffsetY; + } + } diff --git a/Mage.Client/src/main/java/mage/client/cards/CardsList.java b/Mage.Client/src/main/java/mage/client/cards/CardsList.java index 31b5b2b688..857a8cf286 100644 --- a/Mage.Client/src/main/java/mage/client/cards/CardsList.java +++ b/Mage.Client/src/main/java/mage/client/cards/CardsList.java @@ -77,6 +77,12 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar for (MouseListener ml : cardArea.getMouseListeners()) { cardArea.removeMouseListener(ml); } + for (Component comp : cardArea.getComponents()) { + if (comp instanceof CardPanel) { + ((CardPanel) comp).cleanUp(); + } + } + cardArea.removeAll(); } if (mainTable != null) { for (MouseListener ml : mainTable.getMouseListeners()) { @@ -86,13 +92,8 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar if (currentView != null) { currentView.clearCardEventListeners(); } - for (Component comp : cardArea.getComponents()) { - if (comp instanceof CardPanel) { - ((CardPanel) comp).cleanUp(); - } - } + mageCards.clear(); - cardArea.removeAll(); this.bigCard = null; } @@ -270,12 +271,14 @@ public class CardsList extends javax.swing.JPanel implements MouseListener, ICar mageCards = new LinkedHashMap<>(); //Find card view - for (UUID uuid : cards.keySet()) { + for (Map.Entry view : cards.entrySet()) { + UUID uuid = view.getKey(); + CardView cardView = view.getValue(); if (oldMageCards.containsKey(uuid)) { mageCards.put(uuid, oldMageCards.get(uuid)); oldMageCards.remove(uuid); } else { - mageCards.put(uuid, addCard(cards.get(uuid), bigCard, gameId)); + mageCards.put(uuid, addCard(cardView, bigCard, gameId)); } } //Remove unused cards diff --git a/Mage.Client/src/main/java/mage/client/cards/DraftGrid.java b/Mage.Client/src/main/java/mage/client/cards/DraftGrid.java index e76221493d..18c9980eb8 100644 --- a/Mage.Client/src/main/java/mage/client/cards/DraftGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/DraftGrid.java @@ -84,7 +84,7 @@ public class DraftGrid extends javax.swing.JPanel implements MouseListener { for (int i = 1; i < maxRows; i++) { scale = (double) (this.getHeight()/i) / Constants.FRAME_MAX_HEIGHT; cardDimension = new CardDimensions(scale); - maxCards = this.getWidth() / (cardDimension.frameWidth + offsetX); + maxCards = this.getWidth() / (cardDimension.getFrameWidth() + offsetX); if ((maxCards * i) >= booster.size()) { numColumns = booster.size() / i; if (booster.size() % i > 0) { @@ -95,8 +95,8 @@ public class DraftGrid extends javax.swing.JPanel implements MouseListener { } if (cardDimension != null) { - Rectangle rectangle = new Rectangle(cardDimension.frameWidth, cardDimension.frameHeight); - Dimension dimension = new Dimension(cardDimension.frameWidth, cardDimension.frameHeight); + Rectangle rectangle = new Rectangle(cardDimension.getFrameWidth(), cardDimension.getFrameHeight()); + Dimension dimension = new Dimension(cardDimension.getFrameWidth(), cardDimension.getFrameHeight()); List sortedCards = new ArrayList<>(booster.values()); sortedCards.sort(new CardViewRarityComparator()); @@ -105,7 +105,7 @@ public class DraftGrid extends javax.swing.JPanel implements MouseListener { cardImg.addMouseListener(this); add(cardImg); cardImg.update(card); - rectangle.setLocation(curColumn * (cardDimension.frameWidth + offsetX) + offsetX, curRow * (rectangle.height + offsetY) + offsetY); + rectangle.setLocation(curColumn * (cardDimension.getFrameWidth() + offsetX) + offsetX, curRow * (rectangle.height + offsetY) + offsetY); cardImg.setBounds(rectangle); cardImg.setCardBounds(rectangle.x, rectangle.y, rectangle.width, rectangle.height); diff --git a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java index 7ca2057605..12ca7ef2f7 100644 --- a/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java +++ b/Mage.Client/src/main/java/mage/client/cards/DragCardGrid.java @@ -1,5 +1,16 @@ package mage.client.cards; +import java.awt.*; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.*; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import javax.swing.*; import mage.cards.Card; import mage.cards.MageCard; import mage.cards.decks.DeckCardInfo; @@ -20,34 +31,17 @@ import mage.view.CardsView; import org.apache.log4j.Logger; import org.mage.card.arcane.CardRenderer; -import javax.swing.*; -import java.awt.*; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Collectors; - /** * Created by StravantUser on 2016-09-20. */ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarget { - private final static Logger LOGGER = Logger.getLogger(DragCardGrid.class); + private static final Logger LOGGER = Logger.getLogger(DragCardGrid.class); private Constants.DeckEditorMode mode; @Override public Collection dragCardList() { - ArrayList selectedCards = new ArrayList<>(); - for (CardView card : allCards) { - if (card.isSelected()) { - selectedCards.add(card); - } - } - return selectedCards; + return allCards.stream().filter(CardView::isSelected).collect(Collectors.toCollection(ArrayList::new)); } @Override @@ -63,8 +57,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Don't remove the cards, no target } else { // Remove dragged cards - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (int i = 0; i < stack.size(); ++i) { CardView card = stack.get(i); if (card.isSelected()) { @@ -161,7 +155,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } // Get the appropirate stack - ArrayList stack; + List stack; if (rowIndex < cardGrid.size() && col < cardGrid.get(0).size()) { stack = cardGrid.get(rowIndex).get(col); } else { @@ -201,8 +195,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // If we're dragging onto ourself, erase the old cards (just null them out, we will // compact the grid removing the null gaps / empty rows & cols later) if (source == this) { - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (int i = 0; i < stack.size(); ++i) { if (cards.contains(stack.get(i))) { stack.set(i, null); @@ -242,7 +236,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Add a new row if needed if (rowIndex >= cardGrid.size()) { - ArrayList> newRow = new ArrayList<>(); + List> newRow = new ArrayList<>(); if (!cardGrid.isEmpty()) { for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { newRow.add(new ArrayList<>()); @@ -287,7 +281,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Add a new row if needed if (rowIndex >= cardGrid.size()) { - ArrayList> newRow = new ArrayList<>(); + List> newRow = new ArrayList<>(); if (!cardGrid.isEmpty()) { for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { newRow.add(new ArrayList<>()); @@ -305,7 +299,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } // Get the appropirate stack - ArrayList stack = cardGrid.get(rowIndex).get(col); + List stack = cardGrid.get(rowIndex).get(col); // Figure out position in the stack based on the offsetIntoRow int stackInsertIndex = (offsetIntoStack + cardTopHeight / 2) / cardTopHeight; @@ -376,8 +370,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } public void removeSelection() { - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (int i = 0; i < stack.size(); ++i) { CardView card = stack.get(i); if (card.isSelected()) { @@ -395,11 +389,11 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg public DeckCardLayout getCardLayout() { // 2D Array to put entries into - java.util.List>> info = new ArrayList<>(); - for (ArrayList> gridRow : cardGrid) { - java.util.List> row = new ArrayList<>(); + List>> info = new ArrayList<>(); + for (List> gridRow : cardGrid) { + List> row = new ArrayList<>(); info.add(row); - for (ArrayList stack : gridRow) { + for (List stack : gridRow) { row.add(stack.stream() .map(card -> new DeckCardInfo(card.getName(), card.getCardNumber(), card.getExpansionSetCode())) .collect(Collectors.toList())); @@ -545,12 +539,12 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg public static final int COUNT_LABEL_HEIGHT = 20; public static final int GRID_PADDING = 10; - private final static ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png")); - private final static ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png")); + private static final ImageIcon INSERT_ROW_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_row.png")); + private static final ImageIcon INSERT_COL_ICON = new ImageIcon(DragCardGrid.class.getClassLoader().getResource("editor_insert_col.png")); // All of the current card views private final Map cardViews = new LinkedHashMap<>(); - private final ArrayList allCards = new ArrayList<>(); + private final List allCards = new ArrayList<>(); // Card listeners private final CardEventSource eventSource = new CardEventSource(); @@ -579,8 +573,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg final JSlider cardSizeSlider; final JLabel cardSizeSliderLabel; - final Map sortButtons = new HashMap<>(); - final HashMap selectByTypeButtons = new HashMap<>(); + final Map sortButtons = new EnumMap<>(Sort.class); + final Map selectByTypeButtons = new EnumMap<>(CardType.class); final JLabel deckNameAndCountLabel; final JLabel landCountLabel; @@ -612,11 +606,11 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // The outermost array contains multiple rows of stacks of cards // The next inner array represents a row of stacks of cards // The innermost array represents a single vertical stack of cards - private ArrayList>> cardGrid; - private ArrayList maxStackSize = new ArrayList<>(); - private final ArrayList> stackCountLabels = new ArrayList<>(); + private List>> cardGrid; + private List maxStackSize = new ArrayList<>(); + private final List> stackCountLabels = new ArrayList<>(); private Sort cardSort = Sort.CMC; - private final ArrayList selectByTypeSelected = new ArrayList<>(); + private final List selectByTypeSelected = new ArrayList<>(); private boolean separateCreatures = true; public enum Role { @@ -640,7 +634,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg public boolean separateCreatures; public int cardSize; - private final static Pattern parser = Pattern.compile("\\(([^,]*),([^,]*),([^)]*)\\)"); + private static final Pattern parser = Pattern.compile("\\(([^,]*),([^,]*),([^)]*)\\)"); public static Settings parse(String str) { Matcher m = parser.matcher(str); @@ -811,7 +805,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg insertArrow = new JLabel(); insertArrow.setSize(20, 20); insertArrow.setVisible(false); - cardContent.add(insertArrow, new Integer(1000)); + cardContent.add(insertArrow, 1000); // Selection panel selectionPanel = new SelectionBox(); @@ -918,7 +912,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg ButtonGroup selectByTypeModeGroup = new ButtonGroup(); for (final CardType cardType : CardType.values()) { - if (cardType == cardType.CONSPIRACY) { + if (cardType == CardType.CONSPIRACY) { multiplesButton = new JToggleButton("Multiples"); selectByTypeButtons.put(cardType, multiplesButton); selectByTypeMode.add(multiplesButton); @@ -1046,8 +1040,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg * Deselect all cards in this DragCardGrid */ public void deselectAll() { - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { if (card.isSelected()) { card.setSelected(false); @@ -1167,9 +1161,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } else { stackEndIndex = (y2 - curY) / cardTopHeight; } - ArrayList> gridRow = cardGrid.get(rowIndex); + List> gridRow = cardGrid.get(rowIndex); for (int col = 0; col < gridRow.size(); ++col) { - ArrayList stack = gridRow.get(col); + List stack = gridRow.get(col); int stackBottomBegin = curY + cardTopHeight * (stack.size()); int stackBottomEnd = curY + cardTopHeight * (stack.size() - 1) + cardHeight; for (int i = 0; i < stack.size(); ++i) { @@ -1202,8 +1196,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Resort the existing cards based on the current sort public void resort() { // First null out the grid and trim it down - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { stack.clear(); } } @@ -1244,8 +1238,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg if (cardType == CardType.CONSPIRACY) { HashMap cardNames = new HashMap<>(); - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { if (cardNames.get(card.getName()) == null) { cardNames.put(card.getName(), card); @@ -1263,10 +1257,10 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg continue; } - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { - boolean s = card.isSelected() | card.getCardTypes().contains(cardType); + boolean s = card.isSelected() || card.getCardTypes().contains(cardType); card.setSelected(s); cardViews.get(card.getId()).update(card); } @@ -1277,13 +1271,13 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } if (useText) { - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { boolean s = card.isSelected(); // Name if (!s) { - s |= card.getName().toLowerCase(Locale.ENGLISH).contains(searchStr); + s = card.getName().toLowerCase(Locale.ENGLISH).contains(searchStr); } // Sub & Super Types if (!s) { @@ -1355,21 +1349,13 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg qtys.put("wastes", 0); manaCounts = new HashMap<>(); - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { // Type line - String t = ""; - for (CardType type : card.getCardTypes()) { - t += ' ' + type.toString(); - } - // Sub & Super Types - for (SuperType type : card.getSuperTypes()) { - t += ' ' + type.toString().toLowerCase(Locale.ENGLISH); - } - for (SubType str : card.getSubTypes()) { - t += " " + str.toString().toLowerCase(Locale.ENGLISH); - } + String t = card.getCardTypes().stream().map(CardType::toString).collect(Collectors.joining(" ")); + t += card.getSuperTypes().stream().map(st -> st.toString().toLowerCase(Locale.ENGLISH)).collect(Collectors.joining(" ")); + t += card.getSubTypes().stream().map(st -> st.toString().toLowerCase(Locale.ENGLISH)).collect(Collectors.joining(" ")); for (String qty : qtys.keySet()) { int value = qtys.get(qty); @@ -1408,13 +1394,13 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg while (regexMatcher.find()) { String val = regexMatcher.group(1); int colorless_val = Integer.parseInt(val); - + int total_c_pip = 0; - if (pips.get("#c}") != null) { + if (pips.get("#c}") != null) { total_c_pip = pips.get("#c}"); } pips.put("#c}", colorless_val + total_c_pip); - + int cmc_pip_value = 0; if (pips_at_cmcs.get(cmc + "##c}") != null) { cmc_pip_value = pips_at_cmcs.get(cmc + "##c}"); @@ -1495,7 +1481,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } public void blingDeck() { - if (!(this.mode == Constants.DeckEditorMode.FREE_BUILDING)) { + if (this.mode != Constants.DeckEditorMode.FREE_BUILDING) { return; } @@ -1504,8 +1490,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg return; } - HashMap pimpedSets = new HashMap<>(); - HashMap pimpedCards = new HashMap<>(); + Map pimpedSets = new HashMap<>(); + Map pimpedCards = new HashMap<>(); pimpedSets.put("CP", 1); pimpedSets.put("JR", 1); pimpedSets.put("MPS", 1); @@ -1530,8 +1516,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg String[] sets = pimpedSets.keySet().toArray(new String[pimpedSets.keySet().size()]); Boolean didModify = false; - for (ArrayList> gridRow : cardGrid) { - for (ArrayList stack : gridRow) { + for (List> gridRow : cardGrid) { + for (List stack : gridRow) { for (CardView card : stack) { if (card.getSuperTypes().contains(SuperType.BASIC)) { continue; @@ -1581,9 +1567,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Remove all of the cards not in the cardsView boolean didModify = false; // Until contested for (int i = 0; i < cardGrid.size(); ++i) { - ArrayList> gridRow = cardGrid.get(i); + List> gridRow = cardGrid.get(i); for (int j = 0; j < gridRow.size(); ++j) { - ArrayList stack = gridRow.get(j); + List stack = gridRow.get(j); for (int k = 0; k < stack.size(); ++k) { CardView card = stack.get(k); if (!cardsView.containsKey(card.getId())) { @@ -1627,21 +1613,21 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg loadSettings(Settings.parse(layout.getSettings())); // Traverse the cards once and track them so we can pick ones to insert into the grid - Map>> trackedCards = new HashMap<>(); + Map>> trackedCards = new HashMap<>(); for (CardView newCard : cardsView.values()) { if (!cardViews.containsKey(newCard.getId())) { // Add the new card addCardView(newCard, false); // Add the new card to tracking - Map> forSetCode; + Map> forSetCode; if (trackedCards.containsKey(newCard.getExpansionSetCode())) { forSetCode = trackedCards.get(newCard.getExpansionSetCode()); } else { forSetCode = new HashMap<>(); trackedCards.put(newCard.getExpansionSetCode(), forSetCode); } - ArrayList list; + List list; if (forSetCode.containsKey(newCard.getCardNumber())) { list = forSetCode.get(newCard.getCardNumber()); } else { @@ -1655,16 +1641,16 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Now go through the layout and use it to build the cardGrid cardGrid = new ArrayList<>(); maxStackSize = new ArrayList<>(); - for (java.util.List> row : layout.getCards()) { - ArrayList> gridRow = new ArrayList<>(); + for (List> row : layout.getCards()) { + List> gridRow = new ArrayList<>(); int thisMaxStackSize = 0; cardGrid.add(gridRow); - for (java.util.List stack : row) { + for (List stack : row) { ArrayList gridStack = new ArrayList<>(); gridRow.add(gridStack); for (DeckCardInfo info : stack) { if (trackedCards.containsKey(info.getSetCode()) && trackedCards.get(info.getSetCode()).containsKey(info.getCardNum())) { - ArrayList candidates + List candidates = trackedCards.get(info.getSetCode()).get(info.getCardNum()); if (!candidates.isEmpty()) { gridStack.add(candidates.remove(0)); @@ -1679,8 +1665,8 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Check that there aren't any "orphans" not referenced in the layout. There should // never be any under normal operation, but as a failsafe in case the user screwed with // the file in an invalid way, sort them into the grid so that they aren't just left hanging. - for (Map> tracked : trackedCards.values()) { - for (ArrayList orphans : tracked.values()) { + for (Map> tracked : trackedCards.values()) { + for (List orphans : tracked.values()) { for (CardView orphan : orphans) { LOGGER.info("Orphan when setting with layout: "); sortIntoGrid(orphan); @@ -1734,7 +1720,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg AbstractButton button = selectByTypeButtons.get(cardType); String text = cardType.toString(); int numCards = getCount(cardType); - if (cardType == cardType.CONSPIRACY) { + if (cardType == CardType.CONSPIRACY) { continue; } @@ -1909,7 +1895,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg maxStackSize.add(0, 0); } // What row to add it to? - ArrayList> targetRow; + List> targetRow; if (separateCreatures && !newCard.isCreature()) { // Ensure row 2 exists if (cardGrid.size() < 2) { @@ -1930,7 +1916,7 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg for (int currentColumn = 0; currentColumn < cardGrid.get(0).size(); ++currentColumn) { // Find an item from this column CardView cardInColumn = null; - for (ArrayList> gridRow : cardGrid) { + for (List> gridRow : cardGrid) { for (CardView card : gridRow.get(currentColumn)) { cardInColumn = card; break; @@ -1975,9 +1961,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg private void trimGrid() { // Compact stacks and rows for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { - ArrayList> gridRow = cardGrid.get(rowIndex); + List> gridRow = cardGrid.get(rowIndex); int rowMaxStackSize = 0; - for (ArrayList stack : gridRow) { + for (List stack : gridRow) { // Clear out nulls in the stack for (int i = 0; i < stack.size(); ++i) { if (stack.get(i) == null) { @@ -2001,15 +1987,15 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg if (!cardGrid.isEmpty()) { for (int colIndex = 0; colIndex < cardGrid.get(0).size(); ++colIndex) { boolean hasContent = false; // Until contested - for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { - if (!cardGrid.get(rowIndex).get(colIndex).isEmpty()) { + for (List> aCardGrid : cardGrid) { + if (!aCardGrid.get(colIndex).isEmpty()) { hasContent = true; break; } } if (!hasContent) { - for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { - cardGrid.get(rowIndex).remove(colIndex); + for (List> aCardGrid : cardGrid) { + aCardGrid.remove(colIndex); } --colIndex; } @@ -2018,13 +2004,13 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg // Clean up extra column header count labels while (stackCountLabels.size() > cardGrid.size()) { - ArrayList labels = stackCountLabels.remove(cardGrid.size()); + List labels = stackCountLabels.remove(cardGrid.size()); for (JLabel label : labels) { cardContent.remove(label); } } int colCount = cardGrid.isEmpty() ? 0 : cardGrid.get(0).size(); - for (ArrayList labels : stackCountLabels) { + for (List labels : stackCountLabels) { while (labels.size() > colCount) { cardContent.remove(labels.remove(colCount)); } @@ -2032,6 +2018,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg } private int getCardWidth() { + if (GUISizeHelper.editorCardDimension == null) { + return 200; + } return (int) (GUISizeHelper.editorCardDimension.width * cardSizeMod); } @@ -2054,9 +2043,9 @@ public class DragCardGrid extends JPanel implements DragCardSource, DragCardTarg int maxWidth = 0; for (int rowIndex = 0; rowIndex < cardGrid.size(); ++rowIndex) { int rowMaxStackSize = 0; - ArrayList> gridRow = cardGrid.get(rowIndex); + List> gridRow = cardGrid.get(rowIndex); for (int colIndex = 0; colIndex < gridRow.size(); ++colIndex) { - ArrayList stack = gridRow.get(colIndex); + List stack = gridRow.get(colIndex); // Stack count label if (stackCountLabels.size() <= rowIndex) { diff --git a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java index cf33d0e1e7..ce438c8fa9 100644 --- a/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java +++ b/Mage.Client/src/main/java/mage/client/cards/ManaPieChart.java @@ -5,11 +5,13 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; +import java.io.Serializable; import java.util.ArrayList; +import java.util.List; import javax.swing.JComponent; -class Slice { +class Slice implements Serializable { double value; Color color; @@ -22,7 +24,7 @@ class Slice { public class ManaPieChart extends JComponent { - ArrayList slices = new ArrayList(); + private List slices = new ArrayList<>(); ManaPieChart() { } diff --git a/Mage.Client/src/main/java/mage/client/cards/Permanent.java b/Mage.Client/src/main/java/mage/client/cards/Permanent.java index 8524632827..cde8528da7 100644 --- a/Mage.Client/src/main/java/mage/client/cards/Permanent.java +++ b/Mage.Client/src/main/java/mage/client/cards/Permanent.java @@ -49,7 +49,7 @@ public class Permanent extends Card { super(permanent, bigCard, dimensions, gameId); this.setSize(this.getPreferredSize()); this.permanent = permanent; - tappedImage = new BufferedImage(Config.dimensions.frameHeight, Config.dimensions.frameWidth, BufferedImage.TYPE_INT_RGB); + tappedImage = new BufferedImage(Config.dimensions.getFrameHeight(), Config.dimensions.getFrameWidth(), BufferedImage.TYPE_INT_RGB); } public UUID getPermanentId() { @@ -173,10 +173,10 @@ public class Permanent extends Card { g2.setColor(Color.BLACK); } if (permanent.isTapped()) { - g2.drawRect(0, 0, Config.dimensions.frameHeight - 1, Config.dimensions.frameWidth - 1); + g2.drawRect(0, 0, Config.dimensions.getFrameHeight() - 1, Config.dimensions.getFrameWidth() - 1); } else { - g2.drawRect(0, 0, Config.dimensions.frameWidth - 1, Config.dimensions.frameHeight - 1); + g2.drawRect(0, 0, Config.dimensions.getFrameWidth() - 1, Config.dimensions.getFrameHeight() - 1); } } @@ -185,7 +185,7 @@ public class Permanent extends Card { Graphics2D g = (Graphics2D) tappedImage.getGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - g.drawImage(TransformedImageCache.getRotatedResizedImage(small, dimension.frameWidth, dimension.frameHeight, Math.toRadians(90.0)), 0, 0, this); + g.drawImage(TransformedImageCache.getRotatedResizedImage(small, dimension.getFrameWidth(), dimension.getFrameHeight(), Math.toRadians(90.0)), 0, 0, this); g.dispose(); } @@ -206,10 +206,10 @@ public class Permanent extends Card { @Override public Dimension getPreferredSize() { if (permanent != null && permanent.isTapped()) { - return new Dimension(Config.dimensions.frameHeight, Config.dimensions.frameWidth); + return new Dimension(Config.dimensions.getFrameHeight(), Config.dimensions.getFrameWidth()); } else { - return new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); + return new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); } } @@ -229,7 +229,7 @@ public class Permanent extends Card { tooltipPopup.hide(); } PopupFactory factory = PopupFactory.getSharedInstance(); - int x = (int) this.getLocationOnScreen().getX() + (permanent.isTapped()?Config.dimensions.frameHeight:Config.dimensions.frameWidth); + int x = (int) this.getLocationOnScreen().getX() + (permanent.isTapped()? Config.dimensions.getFrameHeight() : Config.dimensions.getFrameWidth()); int y = (int) this.getLocationOnScreen().getY() + 40; tooltipPopup = factory.getPopup(this, tooltipText, x, y); tooltipPopup.show(); diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.form b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.form index 80e38b5831..adf961e87e 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.form +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.form @@ -47,6 +47,7 @@ + diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java index 97392d0e58..2b351fa28c 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelBasic.java @@ -224,7 +224,6 @@ public class ChatPanelBasic extends javax.swing.JPanel { StringBuilder text = new StringBuilder(); if (time != null) { text.append(getColoredText(TIMESTAMP_COLOR, timeFormatter.format(time) + ": ")); - //this.txtConversation.append(TIMESTAMP_COLOR, time + " "); } String userColor; String textColor; @@ -239,11 +238,7 @@ public class ChatPanelBasic extends javax.swing.JPanel { userColor = USER_INFO_COLOR; break; default: - if (parentChatRef != null) { - userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; - } else { - userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; - } + userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; textColor = MESSAGE_COLOR; userSeparator = ": "; } @@ -366,6 +361,7 @@ public class ChatPanelBasic extends javax.swing.JPanel { jScrollPaneTxt.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); jScrollPaneTxt.setPreferredSize(new java.awt.Dimension(32767, 32767)); + txtConversation.setEditable(false); txtConversation.setBorder(javax.swing.BorderFactory.createEmptyBorder(1, 1, 1, 1)); txtConversation.setFont(new java.awt.Font("Arial", 0, 14)); // NOI18N txtConversation.setFocusCycleRoot(false); diff --git a/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java b/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java index 56be922608..5fe65747f0 100644 --- a/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java +++ b/Mage.Client/src/main/java/mage/client/chat/ChatPanelSeparated.java @@ -55,11 +55,7 @@ public class ChatPanelSeparated extends ChatPanelBasic { userColor = USER_INFO_COLOR; break; default: - if (parentChatRef != null) { - userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; - } else { - userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; - } + userColor = SessionHandler.getUserName().equals(username) ? MY_COLOR : OPPONENT_COLOR; textColor = MESSAGE_COLOR; userSeparator = ": "; } diff --git a/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java b/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java index 92731f941c..2fd0878f8f 100644 --- a/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java +++ b/Mage.Client/src/main/java/mage/client/chat/LocalCommands.java @@ -14,6 +14,9 @@ import java.util.UUID; public final class LocalCommands { + + private LocalCommands(){} + /** * Handler for commands that do not require server interaction, i.e settings etc * @param chatId diff --git a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java index be63bbacbe..1849b44d15 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyBindButton.java @@ -1,118 +1,176 @@ package mage.client.components; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPopupMenu; import mage.client.dialog.PreferencesDialog; +import javax.swing.*; +import java.awt.event.*; + /** - * - * @author Campbell Suter + * @author Campbell Suter , JayDi85 */ public class KeyBindButton extends JButton implements ActionListener { - private final PreferencesDialog preferences; - private final String key; - private PopupItem item; - private JPopupMenu menu; - private int keyCode; - private String text; + private final PreferencesDialog preferences; + private final String key; + private PopupItem item; + private JPopupMenu menu; + private int keyCode; + private int modifierCode; + private String text; - /** - * For the IDE only, do not use! - */ - public KeyBindButton() { - this(null, null); - } + /** + * For the IDE only, do not use! + */ + public KeyBindButton() { + this(null, null); + } - public KeyBindButton(PreferencesDialog preferences, String key) { - this.preferences = preferences; - this.key = key; - addActionListener(this); - fixText(); - } + public KeyBindButton(PreferencesDialog preferences, String key) { + this.preferences = preferences; + this.key = key; + addActionListener(this); + fixText(); + } - private JPopupMenu getMenu() { - menu = new JPopupMenu(); - menu.add(item = new PopupItem()); - return menu; - } + private JPopupMenu createPopupMenu() { + menu = new JPopupMenu(); + menu.add(item = new PopupItem()); + return menu; + } - private void applyNewKeycode(int code) { - preferences.getKeybindButtons().stream() - .filter(b -> b != KeyBindButton.this) - .filter(b -> { - return b.keyCode == code; + private void applyNewKeycode(int code, int modifier) { + // clear used keys + preferences.getKeybindButtons().stream() + .filter(b -> b != KeyBindButton.this) + .filter(b -> { + return b.keyCode == code && b.modifierCode == modifier; }) - .forEach(b -> b.setKeyCode(0)); + .forEach(b -> { + b.setKeyCode(0); + b.setModifierCode(0); + }); - setKeyCode(code); - menu.setVisible(false); - } + // set new + setKeyCode(code); + setModifierCode(modifier); + menu.setVisible(false); + } - private void fixText() { - if (keyCode == 0) { - text = ""; - } else { - text = KeyEvent.getKeyText(keyCode); - } - repaint(); - } + private void fixText() { + if (keyCode == 0) { + text = ""; + } else { + String codeStr = KeyEvent.getKeyText(keyCode); + String modStr = KeyEvent.getKeyModifiersText(modifierCode); + text = (modStr.isEmpty() ? "" : modStr + " + ") + codeStr; + } + repaint(); + } - public void setKeyCode(int keyCode) { - this.keyCode = keyCode; - switch (keyCode) { - case KeyEvent.VK_ESCAPE: - case KeyEvent.VK_SPACE: - keyCode = 0; - } - fixText(); - setSize(getPreferredSize()); - } + public void setKeyCode(int keyCode) { + this.keyCode = keyCode; + switch (keyCode) { + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + this.keyCode = 0; + } + fixText(); + //setSize(getPreferredSize()); + } - public int getKeyCode() { - return keyCode; - } + public int getKeyCode() { + return keyCode; + } - @Override - public String getText() { - return text; - } + public void setModifierCode(int modifierCode) { + this.modifierCode = modifierCode; - public String getKey() { - return key; - } + // only single modifier allowed + if (!(modifierCode == InputEvent.ALT_MASK + || modifierCode == InputEvent.CTRL_MASK + || modifierCode == InputEvent.SHIFT_MASK)) { + this.modifierCode = 0; + } + fixText(); + //setSize(getPreferredSize()); + } - @Override - public void actionPerformed(ActionEvent e) { - getMenu().show(this, 0, 0); - item.requestFocusInWindow(); - } + public int getModifierCode() { + return modifierCode; + } - private class PopupItem extends JLabel implements KeyListener { + @Override + public String getText() { + return text; + } - public PopupItem() { - super("Press a key"); - addKeyListener(this); - setFocusable(true); - } + public String getKey() { + return key; + } - @Override - public void keyTyped(KeyEvent e) { - } + @Override + public void actionPerformed(ActionEvent e) { + JPopupMenu m = createPopupMenu(); + m.setPopupSize(this.getWidth(), this.getHeight()); + m.show(this, 0, 0); + item.requestFocusInWindow(); + } - @Override - public void keyPressed(KeyEvent e) { - applyNewKeycode(e.getKeyCode()); - } + private class PopupItem extends JLabel implements KeyListener { - @Override - public void keyReleased(KeyEvent e) { - } + public PopupItem() { + super("Press a key"); + addKeyListener(this); + setFocusable(true); + } - } + @Override + public void keyTyped(KeyEvent e) { + } + + @Override + public void keyPressed(KeyEvent e) { + + // cancel on ESC + if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { + menu.setVisible(false); + return; + } + + // clear on SPACE + if (e.getKeyCode() == KeyEvent.VK_SPACE) { + setKeyCode(0); + setModifierCode(0); + menu.setVisible(false); + return; + } + + // ignore multiple mod keys + switch (e.getModifiers()) { + case KeyEvent.CTRL_MASK: + case KeyEvent.SHIFT_MASK: + case KeyEvent.ALT_MASK: + case 0: + break; + default: + return; + } + + // skip single mod keys without chars + switch (e.getKeyCode()) { + case KeyEvent.VK_CONTROL: + case KeyEvent.VK_SHIFT: + case KeyEvent.VK_ALT: + return; + } + + // all done, can save + applyNewKeycode(e.getKeyCode(), e.getModifiers()); + } + + @Override + public void keyReleased(KeyEvent e) { + } + + } } diff --git a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java index c1f806cd71..c58ae3cad2 100644 --- a/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java +++ b/Mage.Client/src/main/java/mage/client/components/KeyboundButton.java @@ -15,6 +15,8 @@ public class KeyboundButton extends JButton { private final String text; private static final Font keyFont = new Font(Font.SANS_SERIF, Font.BOLD, 13); + private boolean tinting = false; + public KeyboundButton(String key) { text = PreferencesDialog.getCachedKeyText(key); } @@ -25,7 +27,11 @@ public class KeyboundButton extends JButton { Graphics sg = g.create(); try { ui.update(sg, this); - sg.setColor(Color.white); + if (tinting) { + sg.setColor(new Color(0, 0, 0, 32)); + sg.fillRoundRect(2, 2, getWidth() - 4 , getHeight() - 4, 6, 6); + } + sg.setColor(tinting ? Color.lightGray : Color.white); sg.setFont(keyFont); int textWidth = sg.getFontMetrics(keyFont).stringWidth(text); @@ -37,4 +43,10 @@ public class KeyboundButton extends JButton { } } } + + public void setTint(boolean tinting) { + this.tinting = tinting; + repaint(); + } + } diff --git a/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java b/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java index 8c5052ce6d..ca74f6196f 100644 --- a/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java +++ b/Mage.Client/src/main/java/mage/client/components/MageJDesktop.java @@ -22,15 +22,9 @@ public class MageJDesktop extends JDesktopPane { public void updateUI() { if ("Nimbus".equals(UIManager.getLookAndFeel().getName())) { UIDefaults map = new UIDefaults(); - Painter painter = new Painter() { - - final Color color = null; - - @Override - public void paint(Graphics2D g, Object c, int w, int h) { - g.setColor(color == null ? UIManager.getDefaults().getColor("desktop") : color); - g.fillRect(0,0,w,h); - } + Painter painter = (g, c, w, h) -> { + g.setColor( UIManager.getDefaults().getColor("desktop") ); + g.fillRect(0,0,w,h); }; map.put("DesktopPane[Enabled].backgroundPainter", painter); putClientProperty("Nimbus.Overrides", map); diff --git a/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java b/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java index 39e968074d..b5957413e7 100644 --- a/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java +++ b/Mage.Client/src/main/java/mage/client/components/MageRoundPane.java @@ -1,20 +1,21 @@ package mage.client.components; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; +import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Map; import java.util.Objects; -import javax.swing.JPanel; -import mage.client.util.ImageCaches; + +import javax.swing.*; + import org.jdesktop.swingx.graphics.GraphicsUtilities; import org.jdesktop.swingx.graphics.ShadowRenderer; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +import mage.client.util.ImageCaches; +import mage.client.util.SoftValuesLoadingCache; + /** * Mage round pane with transparency. Used for tooltips. * @@ -26,17 +27,15 @@ public class MageRoundPane extends JPanel { private int Y_OFFSET = 30; private final Color defaultBackgroundColor = new Color(141, 130, 112, 200); // color of the frame of the popup window private Color backgroundColor = defaultBackgroundColor; - private static final int alpha = 0; - private static final Map SHADOW_IMAGE_CACHE; - private static final Map IMAGE_CACHE; + private static final SoftValuesLoadingCache SHADOW_IMAGE_CACHE; + private static final SoftValuesLoadingCache IMAGE_CACHE; static { - SHADOW_IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function) key -> createShadowImage(key))); - - IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function) key -> createImage(key))); + SHADOW_IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createShadowImage)); + IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(MageRoundPane::createImage)); } - private final static class ShadowKey { + private static final class ShadowKey { final int width; final int height; @@ -76,7 +75,7 @@ public class MageRoundPane extends JPanel { } } - private final static class Key { + private static final class Key { final int width; final int height; @@ -136,7 +135,7 @@ public class MageRoundPane extends JPanel { @Override protected void paintComponent(Graphics g) { - g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null); + g.drawImage(IMAGE_CACHE.getOrThrow(new Key(getWidth(), getHeight(), X_OFFSET, Y_OFFSET, backgroundColor)), 0, 0, null); } private static BufferedImage createImage(Key key) { @@ -150,7 +149,7 @@ public class MageRoundPane extends JPanel { Graphics2D g2 = image.createGraphics(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); - BufferedImage shadow = SHADOW_IMAGE_CACHE.get(new ShadowKey(w, h)); + BufferedImage shadow = SHADOW_IMAGE_CACHE.getOrThrow(new ShadowKey(w, h)); { int xOffset = (shadow.getWidth() - w) / 2; @@ -163,8 +162,8 @@ public class MageRoundPane extends JPanel { /** * Add white translucent substrate */ - /*if (alpha != 0) { - g2.setColor(new Color(255, 255, 255, alpha)); + /*if (ALPHA != 0) { + g2.setColor(new Color(255, 255, 255, ALPHA)); g2.fillRoundRect(x, y, w, h, arc, arc); }*/ g2.setColor(key.backgroundColor); diff --git a/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java index 98881758db..90eff9c8ec 100644 --- a/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java +++ b/Mage.Client/src/main/java/mage/client/components/ability/AbilityPicker.java @@ -1,9 +1,8 @@ package mage.client.components.ability; import mage.client.SessionHandler; +import mage.client.dialog.MageDialog; import mage.client.util.ImageHelper; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.remote.Session; import mage.view.AbilityPickerView; import org.apache.log4j.Logger; @@ -17,8 +16,8 @@ import org.mage.card.arcane.UI; import javax.swing.*; import java.awt.*; import java.awt.event.*; -import java.util.*; import java.util.List; +import java.util.*; /** * Dialog for choosing abilities. @@ -112,10 +111,7 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener { this.selected = false; // back to false - waiting for selection setVisible(true); - Point centered = SettingsManager.instance.getComponentPosition(DIALOG_WIDTH, DIALOG_HEIGHT); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); - + MageDialog.makeWindowCentered(this, DIALOG_WIDTH, DIALOG_HEIGHT); //startModal(); } @@ -188,28 +184,28 @@ public class AbilityPicker extends JXPanel implements MouseWheelListener { GroupLayout.TRAILING, layout.createSequentialGroup().addContainerGap().add( layout.createParallelGroup(GroupLayout.TRAILING).add(GroupLayout.LEADING, jScrollPane2, GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE).add(GroupLayout.LEADING, - layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( - GroupLayout.LEADING, - layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) - ) - .addPreferredGap(LayoutStyle.RELATED) - .add( - layout.createParallelGroup(GroupLayout.TRAILING) - .add( - GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); + layout.createSequentialGroup().add(jLabel1).addPreferredGap(LayoutStyle.RELATED, 175, Short.MAX_VALUE).add(1, 1, 1)).add( + GroupLayout.LEADING, + layout.createSequentialGroup().add(layout.createParallelGroup(GroupLayout.LEADING) + ) + .addPreferredGap(LayoutStyle.RELATED) + .add( + layout.createParallelGroup(GroupLayout.TRAILING) + .add( + GroupLayout.LEADING, layout.createParallelGroup(GroupLayout.LEADING))))).add(10, 10, 10))); layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.LEADING).add( layout.createSequentialGroup().add( layout.createParallelGroup(GroupLayout.LEADING).add( - layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) - .add(5, 5, 5) - .add( - layout.createParallelGroup(GroupLayout.BASELINE) - ) - ).add(layout.createSequentialGroup().add(8, 8, 8))) - .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( - layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( - LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); + layout.createSequentialGroup().add(jLabel1, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE) + .add(5, 5, 5) + .add( + layout.createParallelGroup(GroupLayout.BASELINE) + ) + ).add(layout.createSequentialGroup().add(8, 8, 8))) + .addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add( + layout.createParallelGroup(GroupLayout.BASELINE)).addPreferredGap(LayoutStyle.RELATED).add(layout.createParallelGroup(GroupLayout.LEADING)).addPreferredGap( + LayoutStyle.RELATED).add(jScrollPane2, GroupLayout.PREFERRED_SIZE, 180, GroupLayout.PREFERRED_SIZE).addContainerGap(23, Short.MAX_VALUE))); } @Override diff --git a/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java b/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java index d87f2c7057..9a2f806913 100644 --- a/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java +++ b/Mage.Client/src/main/java/mage/client/components/ability/BackgroundPainter.java @@ -16,7 +16,7 @@ public class BackgroundPainter extends AbstractPainter { private final Color bgColor = Color.black; - static final float bgalpha = 0.6f; + static final float BACKGROUND_ALPHA = 0.6f; public BackgroundPainter() { super(); @@ -25,7 +25,7 @@ public class BackgroundPainter extends AbstractPainter { @Override protected void doPaint(Graphics2D g2, Object o, int i, int i1) { - float alpha = bgalpha; + float alpha = BACKGROUND_ALPHA; Component c = (Component)o; Composite composite = g2.getComposite(); if (composite instanceof AlphaComposite) { diff --git a/Mage.Client/src/main/java/mage/client/components/ext/MessageDialogType.java b/Mage.Client/src/main/java/mage/client/components/ext/MessageDialogType.java new file mode 100644 index 0000000000..535355a85a --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/components/ext/MessageDialogType.java @@ -0,0 +1,8 @@ +package mage.client.components.ext; + +public enum MessageDialogType { + INFO, + WARNING, + ERROR, + FLASH_INFO +} diff --git a/Mage.Client/src/main/java/mage/client/components/ext/MessageDlg.java b/Mage.Client/src/main/java/mage/client/components/ext/MessageDlg.java deleted file mode 100644 index a09b8ca796..0000000000 --- a/Mage.Client/src/main/java/mage/client/components/ext/MessageDlg.java +++ /dev/null @@ -1,13 +0,0 @@ -package mage.client.components.ext; - -/** - * @author mw, noxx - */ -public class MessageDlg { - - MessageDlg() {} - - public enum Types { - Info, Warning, Error, FlashInfo - } -} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogContainer.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogContainer.java index 39845bae64..81048c967c 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogContainer.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogContainer.java @@ -1,6 +1,6 @@ package mage.client.components.ext.dlg; -import mage.client.components.ext.MessageDlg; +import mage.client.components.ext.MessageDialogType; import mage.client.components.ext.dlg.impl.ChoiceDialog; import mage.client.components.ext.dlg.impl.StackDialog; @@ -37,146 +37,99 @@ public class DialogContainer extends JPanel { setLayout(null); drawContainer = true; - if (dialogType == DialogManager.MTGDialogs.MessageDialog) { - //backgroundColor = new Color(0, 255, 255, 60); - if (params.type == MessageDlg.Types.Warning) { - backgroundColor = new Color(255, 0, 0, 90); - } else { - backgroundColor = new Color(0, 0, 0, 90); + switch (dialogType) { + case MESSAGE: + //backgroundColor = new Color(0, 255, 255, 60); + if (params.type == MessageDialogType.WARNING) { + backgroundColor = new Color(255, 0, 0, 90); + } else { + backgroundColor = new Color(0, 0, 0, 90); + } + alpha = 0; + //MessageDlg dlg = new MessageDlg(params); + //add(dlg); + //dlg.setLocation(X_OFFSET + 10, Y_OFFSET); + //dlg.updateSize(params.rect.width, params.rect.height); + break; + case STACK: { + //backgroundColor = new Color(0, 255, 255, 60); + backgroundColor = new Color(0, 0, 0, 50); + alpha = 0; + StackDialog dlg = new StackDialog(params); + add(dlg); + dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); + //int width = Math.min(params.rect.width - 80, 600); + int width = params.rect.width; + int height = params.rect.height - 80; + dlg.updateSize(width, height); + break; } - alpha = 0; - //MessageDlg dlg = new MessageDlg(params); - //add(dlg); - //dlg.setLocation(X_OFFSET + 10, Y_OFFSET); - //dlg.updateSize(params.rect.width, params.rect.height); - } else if (dialogType == DialogManager.MTGDialogs.StackDialog) { - //backgroundColor = new Color(0, 255, 255, 60); - backgroundColor = new Color(0, 0, 0, 50); - alpha = 0; - StackDialog dlg = new StackDialog(params); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - //int width = Math.min(params.rect.width - 80, 600); - int width = params.rect.width; - int height = params.rect.height - 80; - dlg.updateSize(width, height); - } /* - else if (dialogType == DialogManager.MTGDialogs.CombatDialog) { + else if (dialogType == DialogManager.MTGDialogs.COMBAT) { backgroundColor = new Color(0, 0, 0, 60); alpha = 0; - CombatDialog dlg = new CombatDialog(params); + COMBAT dlg = new COMBAT(params); add(dlg); dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - }*/ else if (dialogType == DialogManager.MTGDialogs.ChoiceDialog) { + }*/ + case CHOICE: { - //backgroundColor = new Color(200, 200, 172, 120); - //backgroundColor = new Color(180, 150, 200, 120); - //backgroundColor = new Color(0, 255, 0, 60); + //backgroundColor = new Color(200, 200, 172, 120); + //backgroundColor = new Color(180, 150, 200, 120); + //backgroundColor = new Color(0, 255, 0, 60); - //backgroundColor = new Color(139, 46, 173, 20); - backgroundColor = new Color(0, 0, 0, 110); - //backgroundColor = new Color(139, 46, 173, 0); + //backgroundColor = new Color(139, 46, 173, 20); + backgroundColor = new Color(0, 0, 0, 110); + //backgroundColor = new Color(139, 46, 173, 0); - alpha = 0; - ChoiceDialog dlg = new ChoiceDialog(params, "Choose"); - add(dlg); - //GameManager.getManager().setCurrentChoiceDlg(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); + alpha = 0; + ChoiceDialog dlg = new ChoiceDialog(params, "Choose"); + add(dlg); + //GameManager.getManager().setCurrentChoiceDlg(dlg); + dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); + dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - } else if (dialogType == DialogManager.MTGDialogs.GraveDialog) { - - backgroundColor = new Color(0, 0, 0, 110); - - alpha = 0; - ChoiceDialog dlg = new ChoiceDialog(params, "Graveyard"); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - } else if (dialogType == DialogManager.MTGDialogs.ExileDialog) { - - backgroundColor = new Color(250, 250, 250, 50); - - alpha = 0; - ChoiceDialog dlg = new ChoiceDialog(params, "Exile"); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - } else if (dialogType == DialogManager.MTGDialogs.EmblemsDialog) { - - backgroundColor = new Color(0, 0, 50, 110); - - alpha = 0; - ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commander, Emblems and Planes)"); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - } /*else if (dialogType == DialogManager.MTGDialogs.GraveDialog) { - backgroundColor = new Color(20, 20, 20, 120); - alpha = 0; - GraveDialog dlg = new GraveDialog(params); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - } else if (dialogType == DialogManager.MTGDialogs.RevealDialog) { - backgroundColor = new Color(90, 135, 190, 80); - alpha = 0; - RevealDialog dlg = new RevealDialog(params); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - } else if (dialogType == DialogManager.MTGDialogs.AssignDamageDialog) { - backgroundColor = new Color(255, 255, 255, 130); - alpha = 0; - AssignDamageDialog dlg = new AssignDamageDialog(params); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - } else if (dialogType == DialogManager.MTGDialogs.ManaChoiceDialog) { - backgroundColor = new Color(0, 255, 255, 60); - alpha = 20; - ManaChoiceDialog dlg = new ManaChoiceDialog(params); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); - dlg.updateSize(params.rect.width - 80, params.rect.height - 80); - - //isGradient = true; - gradient = ImageManager.getGradientImage(); - if (gradient != null) { - b = ImageToBufferedImage.toBufferedImage(gradient); - b = Transparency.makeImageTranslucent(b, 0.35); - Rectangle2D tr = new Rectangle2D.Double(0, 0, params.rect.width, params.rect.height); - //gradient = gradient.getScaledInstance(w, h, Image.SCALE_SMOOTH); - tp = new TexturePaint(b, tr); + break; + } + case GRAVEYARD: { + + backgroundColor = new Color(0, 0, 0, 110); + + alpha = 0; + ChoiceDialog dlg = new ChoiceDialog(params, "Graveyard"); + add(dlg); + dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); + dlg.updateSize(params.rect.width - 80, params.rect.height - 80); + + break; + } + case EXILE: { + + backgroundColor = new Color(250, 250, 250, 50); + + alpha = 0; + ChoiceDialog dlg = new ChoiceDialog(params, "Exile"); + add(dlg); + dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); + dlg.updateSize(params.rect.width - 80, params.rect.height - 80); + + break; + } + case EMBLEMS: { + + backgroundColor = new Color(0, 0, 50, 110); + + alpha = 0; + ChoiceDialog dlg = new ChoiceDialog(params, "Command Zone (Commander, Emblems and Planes)"); + add(dlg); + dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); + dlg.updateSize(params.rect.width - 80, params.rect.height - 80); + + break; } - } else if (dialogType == DialogManager.MTGDialogs.ChooseDeckDialog) { - MWDeckPanel deckPanel = new MWDeckPanel(params.getDeckList(), params.isAI); - deckPanel.setVisible(true); - deckPanel.setBounds(0,0,480,320); - add(deckPanel); - drawContainer = false; - } else if (dialogType == DialogManager.MTGDialogs.ChooseCommonDialog) { - MWChoosePanel choosePanel = new MWChoosePanel(params.getObjectList(), params.getTitle()); - choosePanel.setVisible(true); - choosePanel.setBounds(0,0,440,240); - add(choosePanel); - drawContainer = false; - } else if (dialogType == DialogManager.MTGDialogs.AboutDialog) { - backgroundColor = new Color(255, 255, 255, 120); - alpha = 0; - AboutDialog dlg = new AboutDialog(); - add(dlg); - dlg.setLocation(X_OFFSET + 10, Y_OFFSET + 10); } - */ } public void cleanUp() { diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java index 329ff3ec0e..6b1e3a82c0 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DialogManager.java @@ -20,7 +20,7 @@ import java.util.UUID; public class DialogManager extends JComponent implements MouseListener, MouseMotionListener { - private final static Map dialogManagers = new HashMap<>(); + private static final Map dialogManagers = new HashMap<>(); public static DialogManager getManager(UUID gameId) { if (!dialogManagers.containsKey(gameId)) { @@ -39,8 +39,8 @@ public class DialogManager extends JComponent implements MouseListener, } public enum MTGDialogs { - none, AboutDialog, MessageDialog, StackDialog, AssignDamageDialog, ManaChoiceDialog, ChoiceDialog, EmblemsDialog, GraveDialog, DialogContainer, CombatDialog, - ChooseDeckDialog, ChooseCommonDialog, RevealDialog, ExileDialog + NONE, ABOUT, MESSAGE, STACK, ASSIGN_DAMAGE, MANA_CHOICE, CHOICE, EMBLEMS, GRAVEYARD, DialogContainer, COMBAT, + CHOOSE_DECK, CHOOSE_COMMON, REVEAL, EXILE } /** @@ -58,7 +58,7 @@ public class DialogManager extends JComponent implements MouseListener, } } - private MTGDialogs currentDialog = MTGDialogs.none; + private MTGDialogs currentDialog = MTGDialogs.NONE; private DialogContainer dialogContainer = null; @@ -133,7 +133,7 @@ public class DialogManager extends JComponent implements MouseListener, params.gameId = gameId; params.feedbackPanel = feedbackPanel; params.setCards(cards); - dialogContainer = new DialogContainer(MTGDialogs.StackDialog, params); + dialogContainer = new DialogContainer(MTGDialogs.STACK, params); dialogContainer.setVisible(true); add(dialogContainer); @@ -163,7 +163,7 @@ public class DialogManager extends JComponent implements MouseListener, params.gameId = gameId; //params.feedbackPanel = feedbackPanel; params.setCards(cards); - dialogContainer = new DialogContainer(MTGDialogs.GraveDialog, params); + dialogContainer = new DialogContainer(MTGDialogs.GRAVEYARD, params); dialogContainer.setVisible(true); add(dialogContainer); @@ -192,7 +192,7 @@ public class DialogManager extends JComponent implements MouseListener, params.bigCard = bigCard; params.gameId = gameId; params.setCards(cards); - dialogContainer = new DialogContainer(MTGDialogs.ExileDialog, params); + dialogContainer = new DialogContainer(MTGDialogs.EXILE, params); dialogContainer.setVisible(true); add(dialogContainer); @@ -222,7 +222,7 @@ public class DialogManager extends JComponent implements MouseListener, params.gameId = gameId; //params.feedbackPanel = feedbackPanel; params.setCards(cards); - dialogContainer = new DialogContainer(MTGDialogs.EmblemsDialog, params); + dialogContainer = new DialogContainer(MTGDialogs.EMBLEMS, params); dialogContainer.setVisible(true); add(dialogContainer); @@ -248,7 +248,7 @@ public class DialogManager extends JComponent implements MouseListener, removeAll(); } - this.currentDialog = MTGDialogs.none; + this.currentDialog = MTGDialogs.NONE; setVisible(false); @@ -312,6 +312,7 @@ public class DialogManager extends JComponent implements MouseListener, @Override public void mouseExited(MouseEvent e) { + } @Override @@ -360,7 +361,7 @@ public class DialogManager extends JComponent implements MouseListener, public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); // System.out.println("outx:"+notches); -// if (currentDialog != null && currentDialog.equals(MTGDialogs.ChooseCommonDialog)) { +// if (currentDialog != null && currentDialog.equals(MTGDialogs.CHOOSE_COMMON)) { // System.out.println("out:"+1); // } } diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DlgParams.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DlgParams.java index 0eeac96eb3..51dc575b29 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/DlgParams.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/DlgParams.java @@ -1,13 +1,14 @@ package mage.client.components.ext.dlg; import mage.client.cards.BigCard; -import mage.client.components.ext.MessageDlg; +import mage.client.components.ext.MessageDialogType; import mage.client.game.FeedbackPanel; import mage.view.CardsView; import java.awt.*; import java.util.ArrayList; import java.util.HashSet; +import java.util.Set; import java.util.UUID; /** @@ -18,7 +19,7 @@ import java.util.UUID; public class DlgParams { public Rectangle rect; - public MessageDlg.Types type; + public MessageDialogType type; public BigCard bigCard; public FeedbackPanel feedbackPanel; public UUID gameId; @@ -26,19 +27,19 @@ public class DlgParams { private int playerID; private CardsView cards; - private ArrayList stringList; + private java.util.List stringList; //private ArrayList deckList; - private ArrayList objectList; + private java.util.List objectList; private String title; private int opponentID; - boolean isOptional = false; - boolean isChooseAbility = false; - boolean isCancelStopsPlaying = true; + private boolean isOptional = false; + private boolean isChooseAbility = false; + private boolean isCancelStopsPlaying = true; - boolean isAI = false; + private boolean isAI = false; - public HashSet manaChoices = new HashSet<>(); + private Set manaChoices = new HashSet<>(); public int getPlayerID() { return playerID; @@ -74,11 +75,11 @@ public class DlgParams { this.message = message; } - public HashSet getManaChoices() { + public Set getManaChoices() { return manaChoices; } - public void setManaChoices(HashSet manaChoices) { + public void setManaChoices(Set manaChoices) { this.manaChoices = manaChoices; } @@ -98,7 +99,7 @@ public class DlgParams { this.isChooseAbility = isChooseAbility; } - public ArrayList getStringList() { + public java.util.List getStringList() { return stringList; } @@ -114,7 +115,7 @@ public class DlgParams { this.deckList = deckList; }*/ - public ArrayList getObjectList() { + public java.util.List getObjectList() { return objectList; } diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/IDialogPanel.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/IDialogPanel.java index 5720341ee9..9d9863c77b 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/IDialogPanel.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/IDialogPanel.java @@ -10,7 +10,7 @@ import java.awt.*; /** * @author mw, noxx */ -abstract public class IDialogPanel extends JXPanel { +public abstract class IDialogPanel extends JXPanel { private DlgParams params; private Dimension cardDimension; @@ -71,7 +71,7 @@ abstract public class IDialogPanel extends JXPanel { protected Dimension getCardDimension() { if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); } return cardDimension; } diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/ChoiceDialog.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/ChoiceDialog.java index 938a99483a..13594995e7 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/ChoiceDialog.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/ChoiceDialog.java @@ -50,11 +50,12 @@ public class ChoiceDialog extends IDialogPanel { private boolean isCancelStopsPlaying = true; private final DlgParams params; - + private final String title; /** * This is the default constructor + * * @param params * @param title */ @@ -130,18 +131,18 @@ public class ChoiceDialog extends IDialogPanel { return; } - ArrayList toRemove = new ArrayList<>(); + java.util.List toRemove = new ArrayList<>(); for (int i = getComponentCount() - 1; i > 0; i--) { Component o = getComponent(i); if (o instanceof MageCard) { toRemove.add(o); } } - for (int i = 0; i < toRemove.size(); i++) { - remove(toRemove.get(i)); + for (Component aToRemove : toRemove) { + remove(aToRemove); } - ArrayList cardList = new ArrayList<>(cards.values()); + java.util.List cardList = new ArrayList<>(cards.values()); int width = SettingsManager.instance.getCardSize().width; int height = SettingsManager.instance.getCardSize().height; @@ -163,7 +164,7 @@ public class ChoiceDialog extends IDialogPanel { CardView card = cardList.get(i); MageCard cardImg = Plugins.instance.getMageCard(card, bigCard, getCardDimension(), gameId, true, true); - cardImg.setLocation(dx, dy + j*(height + 30)); + cardImg.setLocation(dx, dy + j * (height + 30)); add(cardImg); dx += (width + 20); @@ -237,11 +238,8 @@ public class ChoiceDialog extends IDialogPanel { int h = getDlgParams().rect.height - 90; jButtonNextPage.setBounds(new Rectangle(w / 2 + 45, h - 50, 60, 60)); - if (maxPages > 1) { - jButtonNextPage.setVisible(true); - } else { - jButtonNextPage.setVisible(false); - } + jButtonNextPage.setVisible(maxPages > 1); + jButtonNextPage.setObserver(new Command() { private static final long serialVersionUID = -3174360416099554104L; diff --git a/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/StackDialog.java b/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/StackDialog.java index df8cbd65ec..8645e5f3de 100644 --- a/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/StackDialog.java +++ b/Mage.Client/src/main/java/mage/client/components/ext/dlg/impl/StackDialog.java @@ -85,11 +85,6 @@ public class StackDialog extends IDialogPanel { jTitle.setFont(new Font("Dialog", Font.BOLD, 14)); jTitle.setText("Current stack: "); - /*jTitle2 = new CustomLabel(); - jTitle2.setBounds(new Rectangle(5, 5 + SettingsManager.getInstance().getCardSize().height + 30, 129, 20)); - jTitle2.setFont(new Font("Dialog", Font.BOLD, 14)); - jTitle2.setText("Spell targets:");*/ - this.setLayout(null); jLayeredPane.setLayout(null); diff --git a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java index 43810b3e3e..4bd3166cbe 100644 --- a/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java +++ b/Mage.Client/src/main/java/mage/client/components/tray/MageTray.java @@ -78,7 +78,6 @@ public enum MageTray { tray.add(trayIcon); } catch (AWTException e) { log.error("TrayIcon could not be added: ", e); - return; } } catch (Exception e) { diff --git a/Mage.Client/src/main/java/mage/client/constants/Constants.java b/Mage.Client/src/main/java/mage/client/constants/Constants.java index 3b1ba14dd6..54d74f3699 100644 --- a/Mage.Client/src/main/java/mage/client/constants/Constants.java +++ b/Mage.Client/src/main/java/mage/client/constants/Constants.java @@ -94,7 +94,6 @@ public final class Constants { public interface IO { String DEFAULT_IMAGES_DIR = "plugins" + File.separator + "images" + File.separator; - String IMAGE_PROPERTIES_FILE = "image.url.properties"; } public enum DeckEditorMode { diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java index 88c94f1711..ab7e7b0774 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGenerator.java @@ -1,4 +1,3 @@ - package mage.client.deck.generator; import java.util.ArrayList; @@ -7,6 +6,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; + import mage.cards.Card; import mage.cards.decks.Deck; import mage.cards.repository.CardCriteria; @@ -123,9 +123,9 @@ public final class DeckGenerator { * non-creatures, lands (including non-basic). Fixes the deck, adjusting for * size and color of the cards retrieved. * - * @param deckSize how big the deck is to generate. + * @param deckSize how big the deck is to generate. * @param allowedColors which colors are allowed in the deck. - * @param setsToUse which sets to use to retrieve cards for this deck. + * @param setsToUse which sets to use to retrieve cards for this deck. * @return the final deck to use. */ private static Deck generateDeck(int deckSize, List allowedColors, List setsToUse) { @@ -180,9 +180,9 @@ public final class DeckGenerator { * non-creatures are retrieved separately to ensure the deck contains a * reasonable mix of both. * - * @param criteria the criteria to search for in the database. + * @param criteria the criteria to search for in the database. * @param spellCount the number of spells that match the criteria needed in - * the deck. + * the deck. */ private static void generateSpells(CardCriteria criteria, int spellCount) { List cardPool = CardRepository.instance.findCards(criteria); @@ -233,7 +233,7 @@ public final class DeckGenerator { * in this deck. Usually the lands will be well balanced relative to the * color of cards. * - * @param criteria the criteria of the lands to search for in the database. + * @param criteria the criteria of the lands to search for in the database. * @param landsCount the amount of lands required for this deck. * @param basicLands information about the basic lands from the sets used. */ @@ -310,10 +310,10 @@ public final class DeckGenerator { * filled. * * @param landsNeeded how many remaining lands are needed. - * @param percentage the percentage needed for each color in the final deck. - * @param count how many of each color can be produced by non-basic lands. - * @param basicLands list of information about basic lands from the - * database. + * @param percentage the percentage needed for each color in the final deck. + * @param count how many of each color can be produced by non-basic lands. + * @param basicLands list of information about basic lands from the + * database. */ private static void addBasicLands(int landsNeeded, Map percentage, Map count, Map> basicLands) { @@ -360,15 +360,14 @@ public final class DeckGenerator { /** * Return a random basic land of the chosen color. * - * @param color the color the basic land should produce. + * @param color the color the basic land should produce. * @param basicLands list of information about basic lands from the - * database. + * database. * @return a single basic land that produces the color needed. */ private static Card getBasicLand(ColoredManaSymbol color, Map> basicLands) { String landName = DeckGeneratorPool.getBasicLandName(color.toString()); List basicLandsInfo = basicLands.get(landName); - return basicLandsInfo.get(RandomUtil.nextInt(basicLandsInfo.size() - 1)).getMockCard().copy(); + return basicLandsInfo.get(RandomUtil.nextInt(basicLandsInfo.size())).getMockCard().copy(); } - } diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorCMC.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorCMC.java index 16202fa4ff..7ed336c88e 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorCMC.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorCMC.java @@ -1,66 +1,59 @@ package mage.client.deck.generator; -import java.util.ArrayList; +import com.google.common.collect.ImmutableList; + +import java.util.List; public enum DeckGeneratorCMC { - Low( - new ArrayList() {{ - add(new CMC(0, 2, 0.60f)); - add(new CMC(3, 4, 0.30f)); - add(new CMC(5, 6, 0.10f)); - }}, - new ArrayList() {{ - add(new CMC(0, 2, 0.65f)); - add(new CMC(3, 4, 0.30f)); - add(new CMC(5, 5, 0.05f)); - }}), - Default( - new ArrayList() {{ - add(new CMC(0, 2, 0.20f)); - add(new CMC(3, 5, 0.50f)); - add(new CMC(6, 7, 0.25f)); - add(new CMC(8, 100, 0.05f)); - }}, - new ArrayList() {{ - add(new CMC(0, 2, 0.30f)); - add(new CMC(3, 4, 0.45f)); - add(new CMC(5, 6, 0.20f)); - add(new CMC(7, 100, 0.05f)); - }}), - High( - new ArrayList() {{ - add(new CMC(0, 2, 0.05f)); - add(new CMC(3, 5, 0.35f)); - add(new CMC(6, 7, 0.40f)); - add(new CMC(8, 100, 0.15f)); - }}, - new ArrayList() {{ - add(new CMC(0, 2, 0.10f)); - add(new CMC(3, 4, 0.30f)); - add(new CMC(5, 6, 0.45f)); - add(new CMC(7, 100, 0.15f)); - }}); + Low(ImmutableList.builder() + .add(new CMC(0, 2, 0.60f)) + .add(new CMC(3, 4, 0.30f)) + .add(new CMC(5, 6, 0.10f)).build(), + ImmutableList.builder() + .add(new CMC(0, 2, 0.65f)) + .add(new CMC(3, 4, 0.30f)) + .add(new CMC(5, 5, 0.05f)).build()), + Default(ImmutableList.builder() + .add(new CMC(0, 2, 0.20f)) + .add(new CMC(3, 5, 0.50f)) + .add(new CMC(6, 7, 0.25f)) + .add(new CMC(8, 100, 0.05f)).build(), + ImmutableList.builder() + .add(new CMC(0, 2, 0.30f)) + .add(new CMC(3, 4, 0.45f)) + .add(new CMC(5, 6, 0.20f)) + .add(new CMC(7, 100, 0.05f)).build()), - private final ArrayList poolCMCs60; - private final ArrayList poolCMCs40; + High(ImmutableList.builder(). + add(new CMC(0, 2, 0.05f)) + .add(new CMC(3, 5, 0.35f)) + .add(new CMC(6, 7, 0.40f)) + .add(new CMC(8, 100, 0.15f)).build(), + ImmutableList.builder(). + add(new CMC(0, 2, 0.10f)) + .add(new CMC(3, 4, 0.30f)) + .add(new CMC(5, 6, 0.45f)) + .add(new CMC(7, 100, 0.15f)).build()); - DeckGeneratorCMC(ArrayList CMCs60, ArrayList CMCs40) { + private final List poolCMCs60; + private final List poolCMCs40; + + DeckGeneratorCMC(List CMCs60, List CMCs40) { this.poolCMCs60 = CMCs60; this.poolCMCs40 = CMCs40; } - public ArrayList get40CardPoolCMC() { + public List get40CardPoolCMC() { return this.poolCMCs40; } - public ArrayList get60CardPoolCMC() { + public List get60CardPoolCMC() { return this.poolCMCs60; } - static class CMC - { + static class CMC { public final int min; public final int max; public final float percentage; @@ -68,12 +61,12 @@ public enum DeckGeneratorCMC { /** * Constructs a CMC range given a minimum and maximum, and the percentage of cards that are in this range. - * @param min the minimum CMC a card in this range can be. - * @param max the maximum CMC a card in this range can be. + * + * @param min the minimum CMC a card in this range can be. + * @param max the maximum CMC a card in this range can be. * @param percentage the percentage of cards in the range (min, max) */ - CMC(int min, int max, float percentage) - { + CMC(int min, int max, float percentage) { this.min = min; this.max = max; this.percentage = percentage; @@ -81,19 +74,19 @@ public enum DeckGeneratorCMC { /** * Sets the amount of cards needed in this CMC range. + * * @param amount the number of cards needed. */ - public void setAmount(int amount) - { + public void setAmount(int amount) { this.amount = amount; } /** * Gets the number of cards needed in this CMC range. + * * @return the number of cards needed in this CMC range. */ - public int getAmount() - { + public int getAmount() { return this.amount; } } diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java index a16607fa29..11778ac269 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorDialog.java @@ -1,17 +1,5 @@ - package mage.client.deck.generator; -import java.awt.*; -import java.awt.event.ActionListener; -import java.awt.event.ItemListener; -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.Date; -import javax.swing.*; -import javax.swing.border.CompoundBorder; -import javax.swing.border.EmptyBorder; -import javax.swing.border.EtchedBorder; -import mage.cards.Sets; import mage.cards.decks.Deck; import mage.client.MageFrame; import mage.client.dialog.PreferencesDialog; @@ -19,8 +7,20 @@ import mage.client.util.gui.ColorsChooser; import mage.client.util.gui.FastSearchUtil; import mage.client.util.sets.ConstructedFormats; +import javax.swing.*; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.border.EtchedBorder; +import java.awt.*; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +import static mage.cards.decks.DeckFormats.XMAGE; + /** - * * @author Simown */ public class DeckGeneratorDialog { @@ -328,7 +328,7 @@ public class DeckGeneratorDialog { tmp.getParentFile().mkdirs(); tmp.createNewFile(); deck.setName(deckName); - Sets.saveDeck(tmp.getAbsolutePath(), deck.getDeckCardLists()); + XMAGE.getExporter().writeDeck(tmp.getAbsolutePath(), deck.getDeckCardLists()); cleanUp(); return tmp.getAbsolutePath(); } catch (Exception e) { diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java index c58ae335d5..cf77d9d09e 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/DeckGeneratorPool.java @@ -136,7 +136,7 @@ public class DeckGeneratorPool int cardCount = getCardCount((card.getName())); // No need to check if the land is valid for the colors chosen // They are all filtered before searching for lands to include in the deck. - return (cardCount < 4); + return (cardCount < (isSingleton ? 1 : 4)); } diff --git a/Mage.Client/src/main/java/mage/client/deck/generator/RatioAdjustingSliderPanel.java b/Mage.Client/src/main/java/mage/client/deck/generator/RatioAdjustingSliderPanel.java index 21036d93c7..b01bef149b 100644 --- a/Mage.Client/src/main/java/mage/client/deck/generator/RatioAdjustingSliderPanel.java +++ b/Mage.Client/src/main/java/mage/client/deck/generator/RatioAdjustingSliderPanel.java @@ -143,7 +143,7 @@ public class RatioAdjustingSliderPanel extends JPanel { private static JLabel createChangingPercentageLabel(final JSlider slider) { - final JLabel label = new JLabel(" " + String.valueOf(slider.getValue()) + '%'); + final JLabel label = new JLabel(" " + slider.getValue() + '%'); slider.addChangeListener(e -> { String value = String.valueOf(slider.getValue()); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java index 413b087ebd..1385d61686 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/CardSelector.java @@ -1,35 +1,21 @@ - - - /* +/* * CardSelector.java * * Created on Feb 18, 2010, 2:49:03 PM */ package mage.client.deckeditor; -import java.awt.*; -import java.awt.event.*; -import java.util.*; -import java.util.Map.Entry; -import javax.swing.*; -import javax.swing.table.DefaultTableCellRenderer; import mage.MageObject; import mage.ObjectColor; import mage.cards.Card; import mage.cards.ExpansionSet; import mage.cards.Sets; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; +import mage.cards.repository.*; import mage.client.MageFrame; import mage.client.cards.*; import mage.client.constants.Constants.SortBy; import mage.client.deckeditor.table.TableModel; import mage.client.dialog.CheckBoxList; -import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_NAMES; -import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_RULES; -import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_TYPES; -import static mage.client.dialog.PreferencesDialog.KEY_DECK_EDITOR_SEARCH_UNIQUE; import mage.client.util.GUISizeHelper; import mage.client.util.gui.FastSearchUtil; import mage.client.util.sets.ConstructedFormats; @@ -43,12 +29,21 @@ import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.mageobject.ColorlessPredicate; import mage.filter.predicate.other.CardTextPredicate; import mage.filter.predicate.other.ExpansionSetPredicate; +import mage.game.events.Listener; import mage.view.CardView; import mage.view.CardsView; import org.mage.card.arcane.ManaSymbolsCellRenderer; +import javax.swing.*; +import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.util.Map.Entry; + +import static mage.client.dialog.PreferencesDialog.*; + /** - * * @author BetaSteward_at_googlemail.com, nantuko */ public class CardSelector extends javax.swing.JPanel implements ComponentListener, DragCardTarget { @@ -58,6 +53,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene private boolean limited = false; private final SortSetting sortSetting; private static final Map pdAllowed = new HashMap<>(); + private static Listener setsDbListener = null; private final String TEST_MULTI_SET = "Multiple Sets selected"; @@ -76,15 +72,12 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene currentView = mainModel; // by default we use List View listCodeSelected = new CheckBoxList(); - // remove the all option - boolean is_removeFinish = false; String[] setCodes = ConstructedFormats.getTypes(); java.util.List result = new ArrayList<>(); - for (int i = 0; (i < setCodes.length) && (!is_removeFinish); i++) { - String item = setCodes[i]; - if (!item.equals(ConstructedFormats.ALL)) { + for (String item : setCodes) { + if (!item.equals(ConstructedFormats.ALL_SETS)) { result.add(item); } } @@ -165,7 +158,6 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene /** * Free all references - * */ public void cleanUp() { this.cardGrid.clear(); @@ -255,7 +247,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene predicates.add(new ColorPredicate(ObjectColor.WHITE)); } if (this.tbColorless.isSelected()) { - predicates.add(new ColorlessPredicate()); + predicates.add(ColorlessPredicate.instance); } filter.add(Predicates.or(predicates)); @@ -365,9 +357,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene for (int itemIndex : choiseValue) { java.util.List listReceived = ConstructedFormats.getSetsByFormat(x.getElementAt(itemIndex).toString()); - listReceived.stream().filter((item) -> (setCodes.contains(item) == false)).forEachOrdered((item) -> { - setCodes.add(item); - }); + listReceived.stream().filter(item -> !setCodes.contains(item)).forEachOrdered(setCodes::add); } criteria.setCodes(setCodes.toArray(new String[0])); } @@ -505,6 +495,11 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene } } + private void reloadSetsCombobox() { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(ConstructedFormats.getTypes()); + cbExpansionSet.setModel(model); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -575,8 +570,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbRed.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/color_red_off.png"))); // NOI18N tbRed.setSelected(true); - tbRed.setToolTipText("Red
" - + tbColor.getToolTipText()); + tbRed.setToolTipText("Red
" + + tbColor.getToolTipText()); tbRed.setActionCommand("Red"); tbRed.setFocusable(false); tbRed.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -666,7 +661,7 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbColor.add(tbColorless); tbColor.add(jSeparator1); - cbExpansionSet.setModel(new DefaultComboBoxModel<>(ConstructedFormats.getTypes())); + reloadSetsCombobox(); cbExpansionSet.setMaximumSize(new java.awt.Dimension(250, 25)); cbExpansionSet.setMinimumSize(new java.awt.Dimension(250, 25)); cbExpansionSet.setName("cbExpansionSet"); // NOI18N @@ -676,6 +671,17 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene cbExpansionSetActionPerformed(evt); } }); + // auto-update sets list on changes + setsDbListener = new Listener() { + @Override + public void event(RepositoryEvent event) { + if (event.getEventType().equals(RepositoryEvent.RepositoryEventType.DB_UPDATED)) { + reloadSetsCombobox(); + // TODO: auto-refresh cards list + } + } + }; + ExpansionRepository.instance.subscribe(setsDbListener); tbColor.add(cbExpansionSet); btnExpansionSearch.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_32.png"))); // NOI18N @@ -735,8 +741,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbLand.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_land.png"))); // NOI18N tbLand.setSelected(true); - tbLand.setToolTipText("Land
" - + tbTypes.getToolTipText()); + tbLand.setToolTipText("Land
" + + tbTypes.getToolTipText()); tbLand.setActionCommand("Lands"); tbLand.setFocusable(false); tbLand.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -750,8 +756,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbCreatures.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_creatures.png"))); // NOI18N tbCreatures.setSelected(true); - tbCreatures.setToolTipText("Creatures
" - + tbTypes.getToolTipText()); + tbCreatures.setToolTipText("Creatures
" + + tbTypes.getToolTipText()); tbCreatures.setActionCommand("Creatures"); tbCreatures.setFocusable(false); tbCreatures.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -765,8 +771,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbArifiacts.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_artifact.png"))); // NOI18N tbArifiacts.setSelected(true); - tbArifiacts.setToolTipText("Artifacts
" - + tbTypes.getToolTipText()); + tbArifiacts.setToolTipText("Artifacts
" + + tbTypes.getToolTipText()); tbArifiacts.setActionCommand("Artifacts"); tbArifiacts.setFocusable(false); tbArifiacts.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -780,8 +786,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbSorceries.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_sorcery.png"))); // NOI18N tbSorceries.setSelected(true); - tbSorceries.setToolTipText("Sorceries
" - + tbTypes.getToolTipText()); + tbSorceries.setToolTipText("Sorceries
" + + tbTypes.getToolTipText()); tbSorceries.setActionCommand("Soceries"); tbSorceries.setFocusable(false); tbSorceries.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -795,8 +801,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbInstants.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_instant.png"))); // NOI18N tbInstants.setSelected(true); - tbInstants.setToolTipText("Instants
" - + tbTypes.getToolTipText()); + tbInstants.setToolTipText("Instants
" + + tbTypes.getToolTipText()); tbInstants.setActionCommand("Instants"); tbInstants.setFocusable(false); tbInstants.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -810,8 +816,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbEnchantments.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_enchantment.png"))); // NOI18N tbEnchantments.setSelected(true); - tbEnchantments.setToolTipText("Enchantments
" - + tbTypes.getToolTipText()); + tbEnchantments.setToolTipText("Enchantments
" + + tbTypes.getToolTipText()); tbEnchantments.setActionCommand("Enchantments"); tbEnchantments.setFocusable(false); tbEnchantments.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -825,8 +831,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbPlaneswalkers.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_planeswalker.png"))); // NOI18N tbPlaneswalkers.setSelected(true); - tbPlaneswalkers.setToolTipText("Planeswalker
" - + tbTypes.getToolTipText()); + tbPlaneswalkers.setToolTipText("Planeswalker
" + + tbTypes.getToolTipText()); tbPlaneswalkers.setActionCommand("Planeswalkers"); tbPlaneswalkers.setFocusable(false); tbPlaneswalkers.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -907,8 +913,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbCommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_common_20.png"))); // NOI18N tbCommon.setSelected(true); - tbCommon.setToolTipText("Common
" - + tbRarities.getToolTipText()); + tbCommon.setToolTipText("Common
" + + tbRarities.getToolTipText()); tbCommon.setActionCommand("Common"); tbCommon.setFocusable(false); tbCommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -922,8 +928,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbUncommon.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_uncommon_20.png"))); // NOI18N tbUncommon.setSelected(true); - tbUncommon.setToolTipText("Uncommon
" - + tbRarities.getToolTipText()); + tbUncommon.setToolTipText("Uncommon
" + + tbRarities.getToolTipText()); tbUncommon.setActionCommand("Uncommon"); tbUncommon.setFocusable(false); tbUncommon.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -937,8 +943,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbRare.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_rare_20.png"))); // NOI18N tbRare.setSelected(true); - tbRare.setToolTipText("Rare
" - + tbRarities.getToolTipText()); + tbRare.setToolTipText("Rare
" + + tbRarities.getToolTipText()); tbRare.setActionCommand("Rare"); tbRare.setFocusable(false); tbRare.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -952,8 +958,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbMythic.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_mythic_20.png"))); // NOI18N tbMythic.setSelected(true); - tbMythic.setToolTipText("Mythic
" - + tbRarities.getToolTipText()); + tbMythic.setToolTipText("Mythic
" + + tbRarities.getToolTipText()); tbMythic.setActionCommand("Mythic"); tbMythic.setFocusable(false); tbMythic.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -967,8 +973,8 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene tbSpecial.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/rarity_special_20.png"))); // NOI18N tbSpecial.setSelected(true); - tbSpecial.setToolTipText("Special
" - + tbRarities.getToolTipText()); + tbSpecial.setToolTipText("Special
" + + tbRarities.getToolTipText()); tbSpecial.setActionCommand("Special"); tbSpecial.setFocusable(false); tbSpecial.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); @@ -1121,59 +1127,59 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene javax.swing.GroupLayout cardSelectorBottomPanelLayout = new javax.swing.GroupLayout(cardSelectorBottomPanel); cardSelectorBottomPanel.setLayout(cardSelectorBottomPanelLayout); cardSelectorBottomPanelLayout.setHorizontalGroup( - cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(jButtonAddToMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(2, 2, 2) - .addComponent(jButtonRemoveFromMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(1, 1, 1) - .addComponent(jButtonAddToSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(2, 2, 2) - .addComponent(jButtonRemoveFromSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jTextFieldSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButtonSearch) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jButtonClean) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkNames, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(5, 5, 5) - .addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(5, 5, 5) - .addComponent(cardCountLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cardCount, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(jButtonAddToMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(2, 2, 2) + .addComponent(jButtonRemoveFromMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(1, 1, 1) + .addComponent(jButtonAddToSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(2, 2, 2) + .addComponent(jButtonRemoveFromSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jTextFieldSearch, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButtonSearch) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jButtonClean) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkNames, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkRules, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(5, 5, 5) + .addComponent(chkUnique, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(5, 5, 5) + .addComponent(cardCountLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cardCount, javax.swing.GroupLayout.PREFERRED_SIZE, 48, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); cardSelectorBottomPanelLayout.setVerticalGroup( - cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() - .addGap(4, 4, 4) - .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(chkTypes, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkRules, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkUnique, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkNames, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() - .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jButtonRemoveFromMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jButtonAddToSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jButtonRemoveFromSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jTextFieldSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(jButtonSearch) - .addComponent(jButtonClean) - .addComponent(cardCount) - .addComponent(jButtonAddToMain, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cardCountLabel))) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() + .addGap(4, 4, 4) + .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(chkTypes, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkRules, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkUnique, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkNames, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(cardSelectorBottomPanelLayout.createSequentialGroup() + .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jButtonRemoveFromMain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButtonAddToSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButtonRemoveFromSideboard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(cardSelectorBottomPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jTextFieldSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jButtonSearch) + .addComponent(jButtonClean) + .addComponent(cardCount) + .addComponent(jButtonAddToMain, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cardCountLabel))) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); cardCountLabel.getAccessibleContext().setAccessibleName("cardCountLabel"); @@ -1182,22 +1188,22 @@ public class CardSelector extends javax.swing.JPanel implements ComponentListene javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tbColor, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(tbTypes, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE) - .addComponent(cardSelectorScrollPane) - .addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(tbColor, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(tbTypes, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE) + .addComponent(cardSelectorScrollPane) + .addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1057, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(tbColor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(tbTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(cardSelectorScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE) - .addGap(0, 0, 0) - .addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(tbColor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(tbTypes, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(cardSelectorScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 237, Short.MAX_VALUE) + .addGap(0, 0, 0) + .addComponent(cardSelectorBottomPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE)) ); }// //GEN-END:initComponents diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckArea.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckArea.java index a0b9c92f5f..d087803205 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckArea.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckArea.java @@ -55,7 +55,7 @@ public class DeckArea extends javax.swing.JPanel { public int dividerLocationLimited; public int dividerLocationNormal; - private final static Pattern parser = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|([^|]*)"); + private static final Pattern parser = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|([^|]*)"); public static Settings parse(String s) { Matcher m = parser.matcher(s); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form index 6f2e689765..7428599da1 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.form @@ -1,8 +1,8 @@ - + - + @@ -14,22 +14,35 @@ + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java index 477c1cff45..f3b65eb154 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPane.java @@ -1,24 +1,17 @@ - - - /* - * DeckEditorPane.java - * - * Created on Dec 17, 2009, 9:21:42 AM - */ package mage.client.deckeditor; -import java.awt.Component; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; -import javax.swing.JComponent; import mage.cards.decks.Deck; import mage.client.MagePane; import mage.client.constants.Constants.DeckEditorMode; import mage.client.plugins.impl.Plugins; +import javax.swing.*; +import java.awt.*; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class DeckEditorPane extends MagePane { @@ -79,17 +72,10 @@ public class DeckEditorPane extends MagePane { private void initComponents() { deckEditorPanel1 = new mage.client.deckeditor.DeckEditorPanel(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 10), new java.awt.Dimension(0, 32767)); - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); - this.setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(deckEditorPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 885, Short.MAX_VALUE) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(deckEditorPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE) - ); + getContentPane().add(deckEditorPanel1, java.awt.BorderLayout.CENTER); + getContentPane().add(filler1, java.awt.BorderLayout.NORTH); }// //GEN-END:initComponents private void initComponents(Component container) { @@ -98,14 +84,13 @@ public class DeckEditorPane extends MagePane { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(container, javax.swing.GroupLayout.DEFAULT_SIZE, 885, Short.MAX_VALUE) + .addComponent(container, javax.swing.GroupLayout.DEFAULT_SIZE, 885, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(container, javax.swing.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE) + .addComponent(container, javax.swing.GroupLayout.DEFAULT_SIZE, 626, Short.MAX_VALUE) ); - } public DeckEditorPanel getPanel() { @@ -114,6 +99,7 @@ public class DeckEditorPane extends MagePane { // Variables declaration - do not modify//GEN-BEGIN:variables private mage.client.deckeditor.DeckEditorPanel deckEditorPanel1; + private javax.swing.Box.Filler filler1; // End of variables declaration//GEN-END:variables } diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.form index 5065dfbe63..78ffbeab4d 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.form +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.form @@ -1,6 +1,6 @@ -
+ @@ -17,21 +17,21 @@ - - - + + + - - + + - + @@ -49,171 +49,427 @@ - + - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java index 971e45679b..05ccb0f917 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckEditorPanel.java @@ -1,12 +1,8 @@ - package mage.client.deckeditor; import mage.cards.Card; -import mage.cards.Sets; -import mage.cards.decks.Deck; -import mage.cards.decks.DeckCardLists; +import mage.cards.decks.*; import mage.cards.decks.importer.DeckImporter; -import mage.cards.decks.importer.DeckImporterUtil; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.client.MageFrame; @@ -25,57 +21,63 @@ import mage.client.util.audio.AudioManager; import mage.components.CardInfoPane; import mage.game.GameException; import mage.remote.Session; +import mage.util.DeckUtil; import mage.view.CardView; import mage.view.SimpleCardView; import org.apache.log4j.Logger; import javax.swing.*; -import javax.swing.Timer; import javax.swing.filechooser.FileFilter; import java.awt.*; -import java.awt.event.*; +import java.awt.dnd.DropTarget; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.HierarchyEvent; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.util.*; import java.util.List; +import java.util.*; import java.util.concurrent.*; +import static mage.cards.decks.DeckFormats.XMAGE; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class DeckEditorPanel extends javax.swing.JPanel { private static final Logger logger = Logger.getLogger(DeckEditorPanel.class); private final JFileChooser fcSelectDeck; private final JFileChooser fcImportDeck; + private final JFileChooser fcExportDeck; private Deck deck = new Deck(); private final Map temporaryCards = new HashMap<>(); // Cards dragged out of one part of the view into another private boolean isShowCardInfo = false; private UUID tableId; private DeckEditorMode mode; private int timeout; - private Timer countdown; + private javax.swing.Timer countdown; private UpdateDeckTask updateDeckTask; private int timeToSubmit = -1; + private final String LAST_DECK_FOLDER = "lastDeckFolder"; - /** - * Creates new form DeckEditorPanel - */ public DeckEditorPanel() { initComponents(); + fcSelectDeck = new JFileChooser(); fcSelectDeck.setAcceptAllFileFilterUsed(false); - fcSelectDeck.addChoosableFileFilter(new DeckFilter()); + fcSelectDeck.addChoosableFileFilter(new DeckFileFilter("dck", "XMage's deck files (*.dck)")); fcImportDeck = new JFileChooser(); fcImportDeck.setAcceptAllFileFilterUsed(false); fcImportDeck.addChoosableFileFilter(new ImportFilter()); + fcExportDeck = new JFileChooser(); + fcExportDeck.setAcceptAllFileFilterUsed(false); deckArea.setOpaque(false); - jPanel1.setOpaque(false); - jSplitPane1.setOpaque(false); + panelLeft.setOpaque(false); + panelRight.setOpaque(false); restoreDividerLocationsAndDeckAreaSettings(); - countdown = new Timer(1000, + countdown = new javax.swing.Timer(1000, e -> { if (--timeout > 0) { setTimeout(timeout); @@ -123,7 +125,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { } private void saveDividerLocationsAndDeckAreaSettings() { - PreferencesDialog.saveValue(PreferencesDialog.KEY_EDITOR_HORIZONTAL_DIVIDER_LOCATION, Integer.toString(jSplitPane1.getDividerLocation())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_EDITOR_HORIZONTAL_DIVIDER_LOCATION, Integer.toString(panelRight.getDividerLocation())); PreferencesDialog.saveValue(PreferencesDialog.KEY_EDITOR_DECKAREA_SETTINGS, this.deckArea.saveSettings().toString()); } @@ -131,7 +133,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { // Load horizontal split position setting String dividerLocation = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_EDITOR_HORIZONTAL_DIVIDER_LOCATION, ""); if (!dividerLocation.isEmpty()) { - jSplitPane1.setDividerLocation(Integer.parseInt(dividerLocation)); + panelRight.setDividerLocation(Integer.parseInt(dividerLocation)); } // Load deck area settings @@ -157,7 +159,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { case LIMITED_BUILDING: this.btnAddLand.setVisible(true); this.txtTimeRemaining.setVisible(true); - // Fall through to sideboarding + // Fall through to sideboarding case SIDEBOARDING: this.btnSubmit.setVisible(true); this.btnSubmitTimer.setVisible(true); @@ -209,7 +211,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { this.btnGenDeck.setVisible(false); this.btnImport.setVisible(false); this.btnLoad.setVisible(false); - this.btnNew.setVisible(false); + this.btnNew.setVisible(false); this.btnSubmit.setVisible(false); this.btnSubmitTimer.setVisible(false); this.cardSelector.loadCards(this.bigCard); @@ -244,32 +246,31 @@ public class DeckEditorPanel extends javax.swing.JPanel { private void init() { //this.cardSelector.setVisible(true); - this.jPanel1.setVisible(true); + this.panelLeft.setVisible(true); for (ICardGrid component : this.cardSelector.getCardGridComponents()) { component.clearCardEventListeners(); - component.addCardEventListener( - (Listener) event -> { - switch (event.getEventType()) { - case DOUBLE_CLICK: - moveSelectorCardToDeck(event); - break; - case ALT_DOUBLE_CLICK: - if (mode == DeckEditorMode.FREE_BUILDING) { - moveSelectorCardToSideboard(event); - } else { - // because in match mode selector is used as sideboard the card goes to deck also for shift click - moveSelectorCardToDeck(event); - } - break; - case REMOVE_MAIN: - DeckEditorPanel.this.deckArea.getDeckList().removeSelection(); - break; - case REMOVE_SIDEBOARD: - DeckEditorPanel.this.deckArea.getSideboardList().removeSelection(); - break; + component.addCardEventListener((Listener) event -> { + switch (event.getEventType()) { + case DOUBLE_CLICK: + moveSelectorCardToDeck(event); + break; + case ALT_DOUBLE_CLICK: + if (mode == DeckEditorMode.FREE_BUILDING) { + moveSelectorCardToSideboard(event); + } else { + // because in match mode selector is used as sideboard the card goes to deck also for shift click + moveSelectorCardToDeck(event); } - refreshDeck(); - }); + break; + case REMOVE_MAIN: + DeckEditorPanel.this.deckArea.getDeckList().removeSelection(); + break; + case REMOVE_SIDEBOARD: + DeckEditorPanel.this.deckArea.getSideboardList().removeSelection(); + break; + } + refreshDeck(); + }); } this.deckArea.clearDeckEventListeners(); this.deckArea.addDeckEventListener( @@ -446,7 +447,25 @@ public class DeckEditorPanel extends javax.swing.JPanel { } } }); - refreshDeck(); + refreshDeck(true); + + if (mode == DeckEditorMode.FREE_BUILDING) { + setDropTarget(new DropTarget(this, new DnDDeckTargetListener() { + + @Override + protected boolean handleFilesDrop(boolean move, List files) { + loadDeck(files.get(0).getAbsolutePath()); + return true; + } + + @Override + protected boolean handlePlainTextDrop(boolean move, String text) { + String tmpFile = DeckUtil.writeTextToTempFile(text); + loadDeck(tmpFile); + return true; + } + })); + } this.setVisible(true); this.repaint(); @@ -456,7 +475,7 @@ public class DeckEditorPanel extends javax.swing.JPanel { CardView cardView = (CardView) event.getSource(); int numberToSet = event.getNumber(); int cardsFound = 0; - List toDelete = new ArrayList<>(); + java.util.List toDelete = new ArrayList<>(); for (Card card : cards) { if (card.getName().equals(cardView.getName()) && Objects.equals(card.getCardNumber(), cardView.getCardNumber()) @@ -575,9 +594,9 @@ public class DeckEditorPanel extends javax.swing.JPanel { text = Integer.toString(minute) + ':'; } if (second < 10) { - text = text + '0' + Integer.toString(second); + text = text + '0' + second; } else { - text = text + Integer.toString(second); + text = text + second; } this.txtTimeRemaining.setText(text); if (s == 60) { @@ -590,33 +609,225 @@ public class DeckEditorPanel extends javax.swing.JPanel { } } + private void importChoose(java.awt.event.ActionEvent evt) { + + Object[] options = {"From file", "From clipboard (new deck)", "From clipboard (append cards)"}; + + int n = JOptionPane.showOptionDialog(MageFrame.getDesktop(), + "Where would you like to import from?", + "Deck import", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0] + ); + + switch (n) { + case 0: + importFromFile(evt); + break; + case 1: + importFromClipboard(evt); + break; + case 2: + importFromClipboardWithAppend(evt); + break; + default: + break; + } + } + + private void importFromFile(java.awt.event.ActionEvent evt) { + String lastFolder = MageFrame.getPreferences().get("lastImportFolder", ""); + if (!lastFolder.isEmpty()) { + fcImportDeck.setCurrentDirectory(new File(lastFolder)); + } + int ret = fcImportDeck.showOpenDialog(this); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = fcImportDeck.getSelectedFile(); + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + DeckImporter importer = DeckImporter.getDeckImporter(file.getPath()); + + if (importer != null) { + StringBuilder errorMessages = new StringBuilder(); + Deck newDeck = null; + + newDeck = Deck.load(importer.importDeck(file.getPath(), errorMessages)); + processAndShowImportErrors(errorMessages); + + if (newDeck != null) { + deck = newDeck; + refreshDeck(); + } + + // save last deck import folder + try { + MageFrame.getPreferences().put("lastImportFolder", file.getCanonicalPath()); + } catch (IOException ex) { + logger.error("Error on save last used import folder: " + ex.getMessage()); + } + + } else { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Unknown deck format", "Error importing deck", JOptionPane.ERROR_MESSAGE); + } + } catch (Exception ex) { + logger.fatal(ex); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + fcImportDeck.setSelectedFile(null); + } + + private void importFromClipboard(ActionEvent evt) { + final DeckImportClipboardDialog dialog = new DeckImportClipboardDialog(); + dialog.showDialog(); + + if (!dialog.getTmpPath().isEmpty()) { + loadDeck(dialog.getTmpPath()); + } + } + + private void importFromClipboardWithAppend(ActionEvent evt) { + final DeckImportClipboardDialog dialog = new DeckImportClipboardDialog(); + dialog.showDialog(); + + if (!dialog.getTmpPath().isEmpty()) { + Deck deckToAppend = null; + StringBuilder errorMessages = new StringBuilder(); + + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + deckToAppend = Deck.load(DeckImporter.importDeckFromFile(dialog.getTmpPath(), errorMessages), true, true); + processAndShowImportErrors(errorMessages); + + if (deckToAppend != null) { + deck = Deck.append(deckToAppend, deck); + refreshDeck(); + } + } catch (GameException e1) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + } + + private void exportChoose(java.awt.event.ActionEvent evt) { + + Object[] options = {"To file", "To clipboard"}; + + int n = JOptionPane.showOptionDialog(MageFrame.getDesktop(), + "Where would you like to export?", + "Deck export", + JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[0] + ); + + switch (n) { + case 0: + exportToFile(evt); + break; + case 1: + exportToClipboard(evt); + break; + default: + break; + } + } + + private void exportToFile(java.awt.event.ActionEvent evt) { + // all available export formats + fcExportDeck.resetChoosableFileFilters(); + for (FileFilter filter : DeckFormats.getFileFilters()) { + fcExportDeck.addChoosableFileFilter(filter); + } + + String lastFolder = MageFrame.getPreferences().get("lastExportFolder", ""); + if (!lastFolder.isEmpty()) { + fcExportDeck.setCurrentDirectory(new File(lastFolder)); + } + int ret = fcExportDeck.showSaveDialog(this); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = fcExportDeck.getSelectedFile(); + + // default ext for file + String needFileName = file.getAbsolutePath(); + String needFileExt = DeckFormats.getDefaultFileExtForFilter(fcExportDeck.getFileFilter()); + if (!needFileExt.isEmpty() && !needFileName.toLowerCase(Locale.ENGLISH).endsWith("." + needFileExt)) { + needFileName += "." + needFileExt; + } + + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + DeckFormats.writeDeck(needFileName, deck.getDeckCardLists()); + + try { + MageFrame.getPreferences().put("lastExportFolder", file.getCanonicalPath()); + } catch (IOException ex) { + logger.error("Error on save last used export folder: " + ex.getMessage()); + } + } catch (Exception ex) { + logger.fatal(ex); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + fcExportDeck.setSelectedFile(null); + } + + private void exportToClipboard(java.awt.event.ActionEvent evt) { + final DeckExportClipboardDialog dialog = new DeckExportClipboardDialog(); + dialog.showDialog(deck); + } + + private void processAndShowImportErrors(StringBuilder errorMessages) { + // show up errors list + if (errorMessages.length() > 0) { + String mes = "Found problems with deck: \n\n" + errorMessages.toString(); + JOptionPane.showMessageDialog(MageFrame.getDesktop(), mes.substring(0, Math.min(1000, mes.length())), "Errors while loading deck", JOptionPane.WARNING_MESSAGE); + } + } + + private boolean loadDeck(String file) { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + StringBuilder errorMessages = new StringBuilder(); + Deck newDeck = Deck.load(DeckImporter.importDeckFromFile(file, errorMessages), true, true); + processAndShowImportErrors(errorMessages); + + if (newDeck != null) { + deck = newDeck; + refreshDeck(); + return true; + } + + } catch (GameException e1) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + return false; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents private void initComponents() { - jSplitPane1 = new javax.swing.JSplitPane(); + panelRight = new javax.swing.JSplitPane(); cardSelector = new mage.client.deckeditor.CardSelector(); deckArea = new mage.client.deckeditor.DeckArea(); - jPanel1 = new javax.swing.JPanel(); - bigCard = new mage.client.cards.BigCard(); - txtDeckName = new javax.swing.JTextField(); - lblDeckName = new javax.swing.JLabel(); - btnSave = new javax.swing.JButton(); - btnLoad = new javax.swing.JButton(); - btnNew = new javax.swing.JButton(); - btnExit = new javax.swing.JButton(); - btnImport = new javax.swing.JButton(); - btnSubmit = new javax.swing.JButton(); - btnSubmitTimer = new javax.swing.JButton(); - btnAddLand = new javax.swing.JButton(); - btnGenDeck = new javax.swing.JButton(); - txtTimeRemaining = new javax.swing.JTextField(); - - jSplitPane1.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); - jSplitPane1.setResizeWeight(0.5); - jSplitPane1.setTopComponent(cardSelector); - jSplitPane1.setBottomComponent(deckArea); - - bigCard.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); - + panelLeft = new javax.swing.JPanel(); cardInfoPane = Plugins.instance.getCardInfoPane(); if (cardInfoPane != null && System.getProperty("testCardInfo") != null) { cardInfoPane.setPreferredSize(new Dimension(170, 150)); @@ -626,289 +837,348 @@ public class DeckEditorPanel extends javax.swing.JPanel { cardInfoPane = new JLabel(); cardInfoPane.setVisible(false); } + bigCard = new mage.client.cards.BigCard(); + panelDeck = new javax.swing.JPanel(); + panelDeckName = new javax.swing.JPanel(); + lblDeckName = new javax.swing.JLabel(); + txtDeckName = new javax.swing.JTextField(); + panelDeckCreate = new javax.swing.JPanel(); + btnNew = new javax.swing.JButton(); + btnGenDeck = new javax.swing.JButton(); + panelDeckLoad = new javax.swing.JPanel(); + btnLoad = new javax.swing.JButton(); + btnImport = new javax.swing.JButton(); + panelDeckSave = new javax.swing.JPanel(); + btnSave = new javax.swing.JButton(); + btnExport = new javax.swing.JButton(); + panelDeckDraft = new javax.swing.JPanel(); + btnSubmit = new javax.swing.JButton(); + btnSubmitTimer = new javax.swing.JButton(); + panelDeckLands = new javax.swing.JPanel(); + btnAddLand = new javax.swing.JButton(); + panelDeckExit = new javax.swing.JPanel(); + btnExit = new javax.swing.JButton(); + txtTimeRemaining = new javax.swing.JTextField(); + panelRight.setOrientation(javax.swing.JSplitPane.VERTICAL_SPLIT); + panelRight.setResizeWeight(0.5); + panelRight.setTopComponent(cardSelector); + panelRight.setBottomComponent(deckArea); + + panelDeck.setOpaque(false); + panelDeck.setLayout(new javax.swing.BoxLayout(panelDeck, javax.swing.BoxLayout.Y_AXIS)); + + panelDeckName.setOpaque(false); + + lblDeckName.setForeground(new java.awt.Color(255, 255, 255)); lblDeckName.setLabelFor(txtDeckName); lblDeckName.setText("Deck Name:"); - btnSave.setText("Save"); - btnSave.addActionListener(evt -> btnSaveActionPerformed(evt)); + javax.swing.GroupLayout panelDeckNameLayout = new javax.swing.GroupLayout(panelDeckName); + panelDeckName.setLayout(panelDeckNameLayout); + panelDeckNameLayout.setHorizontalGroup( + panelDeckNameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckNameLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblDeckName) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE) + .addContainerGap()) + ); + panelDeckNameLayout.setVerticalGroup( + panelDeckNameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckNameLayout.createSequentialGroup() + .addGroup(panelDeckNameLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblDeckName)) + .addGap(0, 0, 0)) + ); - btnLoad.setText("Load"); - btnLoad.addActionListener(evt -> btnLoadActionPerformed(evt)); + panelDeck.add(panelDeckName); - btnNew.setText("New"); - btnNew.addActionListener(evt -> btnNewActionPerformed(evt)); + panelDeckCreate.setOpaque(false); - btnExit.setText("Exit"); - btnExit.addActionListener(evt -> btnExitActionPerformed(evt)); - - btnImport.setText("Import"); - btnImport.setName("btnImport"); // NOI18N - btnImport.addActionListener(evt -> { - Object[] options = {"File", "Clipboard", "Append from Clipboard"}; - - int n = JOptionPane.showOptionDialog(MageFrame.getDesktop(), - "Where would you like to import from?", - "Deck import", - JOptionPane.YES_NO_CANCEL_OPTION, - JOptionPane.QUESTION_MESSAGE, - null, - options, - options[0] - ); - - logger.info(n); - - switch (n) { - case 0: - btnImportActionPerformed(evt); - break; - case 1: - btnImportFromClipboardActionPerformed(evt); - break; - case 2: - btnImportFromClipboardActionWAppendPerformed(evt); - break; + btnNew.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/state_active.png"))); // NOI18N + btnNew.setText("NEW"); + btnNew.setIconTextGap(2); + btnNew.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNewActionPerformed(evt); } }); - btnSubmit.setText("Submit"); - btnSubmitTimer.setToolTipText("Submit your deck now!"); + btnGenDeck.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/card_panel.png"))); // NOI18N + btnGenDeck.setText("Random"); + btnGenDeck.setIconTextGap(1); + btnGenDeck.setName("btnGenDeck"); // NOI18N + btnGenDeck.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnGenDeckActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelDeckCreateLayout = new javax.swing.GroupLayout(panelDeckCreate); + panelDeckCreate.setLayout(panelDeckCreateLayout); + panelDeckCreateLayout.setHorizontalGroup( + panelDeckCreateLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckCreateLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnNew, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnGenDeck, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(40, Short.MAX_VALUE)) + ); + panelDeckCreateLayout.setVerticalGroup( + panelDeckCreateLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckCreateLayout.createSequentialGroup() + .addGap(5, 5, 5) + .addGroup(panelDeckCreateLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnGenDeck, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE) + .addComponent(btnNew, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE))) + ); + + panelDeck.add(panelDeckCreate); + + panelDeckLoad.setOpaque(false); + + btnLoad.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N + btnLoad.setText("LOAD"); + btnLoad.setIconTextGap(2); + btnLoad.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnLoadActionPerformed(evt); + } + }); + + btnImport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/deck_in.png"))); // NOI18N + btnImport.setText("Import"); + btnImport.setIconTextGap(2); + btnImport.setName("btnImport"); // NOI18N + btnImport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnImportActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelDeckLoadLayout = new javax.swing.GroupLayout(panelDeckLoad); + panelDeckLoad.setLayout(panelDeckLoadLayout); + panelDeckLoadLayout.setHorizontalGroup( + panelDeckLoadLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckLoadLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnImport, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(40, Short.MAX_VALUE)) + ); + panelDeckLoadLayout.setVerticalGroup( + panelDeckLoadLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckLoadLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelDeckLoadLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(btnImport, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE))) + ); + + panelDeck.add(panelDeckLoad); + + panelDeckSave.setOpaque(false); + + btnSave.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/sideboard_out.png"))); // NOI18N + btnSave.setText("SAVE"); + btnSave.setIconTextGap(2); + btnSave.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSaveActionPerformed(evt); + } + }); + + btnExport.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/deck_out.png"))); // NOI18N + btnExport.setText("Export"); + btnExport.setIconTextGap(2); + btnExport.setName("btnImport"); // NOI18N + btnExport.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnExportActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelDeckSaveLayout = new javax.swing.GroupLayout(panelDeckSave); + panelDeckSave.setLayout(panelDeckSaveLayout); + panelDeckSaveLayout.setHorizontalGroup( + panelDeckSaveLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckSaveLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnSave, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnExport, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(40, Short.MAX_VALUE)) + ); + panelDeckSaveLayout.setVerticalGroup( + panelDeckSaveLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckSaveLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelDeckSaveLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(btnSave, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE) + .addComponent(btnExport, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE))) + ); + + panelDeck.add(panelDeckSave); + + panelDeckDraft.setOpaque(false); + + btnSubmit.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/state_finished.png"))); // NOI18N + btnSubmit.setText("SUBMIT"); + btnSubmit.setIconTextGap(2); btnSubmit.setName("btnSubmit"); // NOI18N - btnSubmit.addActionListener(evt -> btnSubmitActionPerformed(evt)); + btnSubmit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSubmitActionPerformed(evt); + } + }); - btnSubmitTimer.setText("Submit (60s)"); - btnSubmitTimer.setToolTipText("Submit your deck in one minute!"); - btnSubmitTimer.setName("btnSubmitTimer"); - btnSubmitTimer.addActionListener(evt -> btnSubmitTimerActionPerformed(evt)); + btnSubmitTimer.setFont(new java.awt.Font("Tahoma", 0, 9)); // NOI18N + btnSubmitTimer.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/state_finished.png"))); // NOI18N + btnSubmitTimer.setText("Submit
in 1 min"); + btnSubmitTimer.setIconTextGap(2); + btnSubmitTimer.setName("btnSubmitTimer"); // NOI18N + btnSubmitTimer.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnSubmitTimerActionPerformed(evt); + } + }); - btnAddLand.setText("Add Land"); + javax.swing.GroupLayout panelDeckDraftLayout = new javax.swing.GroupLayout(panelDeckDraft); + panelDeckDraft.setLayout(panelDeckDraftLayout); + panelDeckDraftLayout.setHorizontalGroup( + panelDeckDraftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckDraftLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnSubmit, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSubmitTimer, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(40, Short.MAX_VALUE)) + ); + panelDeckDraftLayout.setVerticalGroup( + panelDeckDraftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckDraftLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelDeckDraftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckDraftLayout.createSequentialGroup() + .addComponent(btnSubmit, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addComponent(btnSubmitTimer, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addGap(0, 0, 0)) + ); + + panelDeck.add(panelDeckDraft); + + panelDeckLands.setOpaque(false); + + btnAddLand.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/type_land.png"))); // NOI18N + btnAddLand.setText("Lands"); + btnAddLand.setIconTextGap(2); btnAddLand.setName("btnAddLand"); // NOI18N - btnAddLand.addActionListener(evt -> btnAddLandActionPerformed(evt)); + btnAddLand.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnAddLandActionPerformed(evt); + } + }); - btnGenDeck.setText("Generate"); - btnGenDeck.setName("btnGenDeck"); - btnGenDeck.addActionListener(evt -> btnGenDeckActionPerformed(evt)); + javax.swing.GroupLayout panelDeckLandsLayout = new javax.swing.GroupLayout(panelDeckLands); + panelDeckLands.setLayout(panelDeckLandsLayout); + panelDeckLandsLayout.setHorizontalGroup( + panelDeckLandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckLandsLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnAddLand, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(146, Short.MAX_VALUE)) + ); + panelDeckLandsLayout.setVerticalGroup( + panelDeckLandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckLandsLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnAddLand, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); - txtTimeRemaining.setEditable(false); - txtTimeRemaining.setForeground(java.awt.Color.red); - txtTimeRemaining.setHorizontalAlignment(javax.swing.JTextField.CENTER); - txtTimeRemaining.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.RAISED)); + panelDeck.add(panelDeckLands); - javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); - jPanel1.setLayout(jPanel1Layout); - jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - /*.addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(jLayeredPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 256, Short.MAX_VALUE))*/ - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(lblDeckName) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtDeckName, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)) - .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + panelDeckExit.setOpaque(false); + + btnExit.setText("Exit"); + btnExit.setIconTextGap(2); + btnExit.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnExitActionPerformed(evt); + } + }); + + txtTimeRemaining.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + txtTimeRemainingActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelDeckExitLayout = new javax.swing.GroupLayout(panelDeckExit); + panelDeckExit.setLayout(panelDeckExitLayout); + panelDeckExitLayout.setHorizontalGroup( + panelDeckExitLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelDeckExitLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtTimeRemaining, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(40, Short.MAX_VALUE)) + ); + panelDeckExitLayout.setVerticalGroup( + panelDeckExitLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelDeckExitLayout.createSequentialGroup() + .addGap(0, 11, Short.MAX_VALUE) + .addGroup(panelDeckExitLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnExit, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtTimeRemaining, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + + panelDeck.add(panelDeckExit); + + javax.swing.GroupLayout panelLeftLayout = new javax.swing.GroupLayout(panelLeft); + panelLeft.setLayout(panelLeftLayout); + panelLeftLayout.setHorizontalGroup( + panelLeftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelLeftLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelLeftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelDeck, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(bigCard, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + ); + panelLeftLayout.setVerticalGroup( + panelLeftLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelLeftLayout.createSequentialGroup() + .addComponent(panelDeck, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(btnSave) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnLoad) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnNew) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnExit)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(btnImport) - .addContainerGap() - .addComponent(btnGenDeck) - .addContainerGap() - .addComponent(btnAddLand) - .addContainerGap() - .addComponent(btnSubmit) - .addContainerGap() - .addComponent(btnSubmitTimer)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(txtTimeRemaining)) - ) - .addContainerGap())); - jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtDeckName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblDeckName)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnSave) - .addComponent(btnLoad) - .addComponent(btnNew) - .addComponent(btnExit)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnImport) - .addComponent(btnGenDeck) - .addComponent(btnAddLand) - .addComponent(btnSubmit) - .addComponent(btnSubmitTimer)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtTimeRemaining)) - //.addComponent(jLayeredPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, isShowCardInfo ? 30 : 159, Short.MAX_VALUE) - .addComponent(cardInfoPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 104, Short.MAX_VALUE) - .addComponent(bigCard, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))); + .addContainerGap()) + ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 261, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 604, Short.MAX_VALUE))); + .addGroup(layout.createSequentialGroup() + .addComponent(panelLeft, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(panelRight, javax.swing.GroupLayout.DEFAULT_SIZE, 890, Short.MAX_VALUE)) + ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jSplitPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 615, Short.MAX_VALUE)); - } - - private void processAndShowImportErrors(StringBuilder errorMessages){ - // show up errors list - if (errorMessages.length() > 0){ - String mes = "Founded problems with deck: \n\n" + errorMessages.toString(); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), mes.substring(0, Math.min(1000, mes.length())), "Errors while loading deck", JOptionPane.WARNING_MESSAGE); - } - } - - /** - * @param evt ActionEvent - */ - private void btnImportFromClipboardActionPerformed(ActionEvent evt) { - final DeckImportFromClipboardDialog dialog = new DeckImportFromClipboardDialog(); - dialog.pack(); - dialog.setVisible(true); - - dialog.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - Deck newDeck = null; - StringBuilder errorMessages = new StringBuilder(); - - MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - try { - newDeck = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true); - processAndShowImportErrors(errorMessages); - - if (newDeck != null) { - deck = newDeck; - refreshDeck(); - } - - } catch (GameException e1) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); - }finally { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } - }); - } - - /** - * @param evt ActionEvent - */ - private void btnImportFromClipboardActionWAppendPerformed(ActionEvent evt) { - final DeckImportFromClipboardDialog dialog = new DeckImportFromClipboardDialog(); - dialog.pack(); - dialog.setVisible(true); - - dialog.addWindowListener(new WindowAdapter() { - @Override - public void windowClosed(WindowEvent e) { - Deck deckToAppend = null; - StringBuilder errorMessages = new StringBuilder(); - - MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - try { - deckToAppend = Deck.load(DeckImporterUtil.importDeck(dialog.getTmpPath(), errorMessages), true, true); - processAndShowImportErrors(errorMessages); - - if (deckToAppend != null) { - deck = Deck.append(deckToAppend, deck); - refreshDeck(); - } - } catch (GameException e1) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); - }finally { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } - }); - } - - private void btnLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLoadActionPerformed - //fcSelectDeck.setCurrentDirectory(new File()); - String lastFolder = MageFrame.getPreferences().get("lastDeckFolder", ""); - if (!lastFolder.isEmpty()) { - fcSelectDeck.setCurrentDirectory(new File(lastFolder)); - } - int ret = fcSelectDeck.showOpenDialog(this); - if (ret == JFileChooser.APPROVE_OPTION) { - File file = fcSelectDeck.getSelectedFile(); - { - /** - * Work around a JFileChooser bug on Windows 7-10 with JRT 7+ In - * the case where the user selects the exact same file as was - * previously selected without touching anything else in the - * dialog, getSelectedFile() will erroneously return null due to - * some combination of our settings. - * - * We manually sub in the last selected file in this case. - */ - if (file == null) { - if (!lastFolder.isEmpty()) { - file = new File(lastFolder); - } - } - } - - MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - try { - Deck newDeck = null; - StringBuilder errorMessages = new StringBuilder(); - - newDeck = Deck.load(DeckImporterUtil.importDeck(file.getPath(), errorMessages), true, true); - processAndShowImportErrors(errorMessages); - - if (newDeck != null) { - deck = newDeck; - refreshDeck(true); - } - - // save last deck history - try { - MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); - } catch (IOException ex) { - logger.error("Error on save last load deck folder: " + ex.getMessage()); - } - - } catch (GameException ex) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); - } finally { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - } - fcSelectDeck.setSelectedFile(null); - }//GEN-LAST:event_btnLoadActionPerformed + .addComponent(panelLeft, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelRight, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 808, Short.MAX_VALUE) + ); + }//
//GEN-END:initComponents private void btnSaveActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSaveActionPerformed - String lastFolder = MageFrame.getPreferences().get("lastDeckFolder", ""); + String lastFolder = MageFrame.getPreferences().get(LAST_DECK_FOLDER, ""); if (!lastFolder.isEmpty()) { fcSelectDeck.setCurrentDirectory(new File(lastFolder)); } @@ -941,20 +1211,75 @@ public class DeckEditorPanel extends javax.swing.JPanel { DeckCardLists cardLists = deck.getDeckCardLists(); cardLists.setCardLayout(deckArea.getCardLayout()); cardLists.setSideboardLayout(deckArea.getSideboardLayout()); - Sets.saveDeck(fileName, cardLists); - } catch (FileNotFoundException ex) { + XMAGE.getExporter().writeDeck(fileName, cardLists); + } catch (IOException ex) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage() + "\nTry ensuring that the selected directory is writable.", "Error saving deck", JOptionPane.ERROR_MESSAGE); } finally { MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } try { - MageFrame.getPreferences().put("lastDeckFolder", file.getCanonicalPath()); + MageFrame.getPreferences().put(LAST_DECK_FOLDER, file.getCanonicalPath()); } catch (IOException ex) { ex.printStackTrace(); } } }//GEN-LAST:event_btnSaveActionPerformed + private void btnLoadActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnLoadActionPerformed + //fcSelectDeck.setCurrentDirectory(new File()); + String lastFolder = MageFrame.getPreferences().get(LAST_DECK_FOLDER, ""); + if (!lastFolder.isEmpty()) { + fcSelectDeck.setCurrentDirectory(new File(lastFolder)); + } + int ret = fcSelectDeck.showOpenDialog(this); + if (ret == JFileChooser.APPROVE_OPTION) { + File file = fcSelectDeck.getSelectedFile(); + { + /** + * Work around a JFileChooser bug on Windows 7-10 with JRT 7+ In + * the case where the user selects the exact same file as was + * previously selected without touching anything else in the + * dialog, getSelectedFile() will erroneously return null due to + * some combination of our settings. + * + * We manually sub in the last selected file in this case. + */ + if (file == null) { + if (!lastFolder.isEmpty()) { + file = new File(lastFolder); + } + } + } + + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + Deck newDeck = null; + StringBuilder errorMessages = new StringBuilder(); + + newDeck = Deck.load(DeckImporter.importDeckFromFile(file.getPath(), errorMessages), true, true); + processAndShowImportErrors(errorMessages); + + if (newDeck != null) { + deck = newDeck; + refreshDeck(true); + } + + // save last deck history + try { + MageFrame.getPreferences().put(LAST_DECK_FOLDER, file.getCanonicalPath()); + } catch (IOException ex) { + logger.error("Error on save last load deck folder: " + ex.getMessage()); + } + + } catch (GameException ex) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } + } + fcSelectDeck.setSelectedFile(null); + }//GEN-LAST:event_btnLoadActionPerformed + private void btnNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewActionPerformed if (mode == DeckEditorMode.SIDEBOARDING || mode == DeckEditorMode.LIMITED_BUILDING) { for (Card card : deck.getCards()) { @@ -972,48 +1297,26 @@ public class DeckEditorPanel extends javax.swing.JPanel { removeDeckEditor(); }//GEN-LAST:event_btnExitActionPerformed - private void btnImportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnImportActionPerformed - String lastFolder = MageFrame.getPreferences().get("lastImportFolder", ""); - if (!lastFolder.isEmpty()) { - fcImportDeck.setCurrentDirectory(new File(lastFolder)); - } - int ret = fcImportDeck.showOpenDialog(this); - if (ret == JFileChooser.APPROVE_OPTION) { - File file = fcImportDeck.getSelectedFile(); + private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed + AddLandDialog addLand = new AddLandDialog(); + addLand.showDialog(deck, mode); + refreshDeck(); + }//GEN-LAST:event_btnAddLandActionPerformed + + private void btnGenDeckActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGenDeckActionPerformed + try { MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - try { - DeckImporter importer = DeckImporterUtil.getDeckImporter(file.getPath()); - - if (importer != null) { - StringBuilder errorMessages = new StringBuilder(); - Deck newDeck = null; - - newDeck = Deck.load(importer.importDeck(file.getPath(), errorMessages)); - processAndShowImportErrors(errorMessages); - - if (newDeck != null) { - deck = newDeck; - refreshDeck(); - } - - // save last deck import folder - try { - MageFrame.getPreferences().put("lastImportFolder", file.getCanonicalPath()); - } catch (IOException ex) { - logger.error("Error on save last used import folder: " + ex.getMessage()); - } - - } else { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Unknown deck format", "Error importing deck", JOptionPane.ERROR_MESSAGE); - } - } catch (Exception ex) { - logger.fatal(ex); - } finally { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } + String path = DeckGenerator.generateDeck(); + deck = Deck.load(DeckImporter.importDeckFromFile(path), true, true); + } catch (GameException ex) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading generated deck", JOptionPane.ERROR_MESSAGE); + } catch (DeckGeneratorException ex) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Generator error", JOptionPane.ERROR_MESSAGE); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); } - fcImportDeck.setSelectedFile(null); - }//GEN-LAST:event_btnImportActionPerformed + refreshDeck(); + }//GEN-LAST:event_btnGenDeckActionPerformed private void btnSubmitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnSubmitActionPerformed if (updateDeckTask != null) { @@ -1043,73 +1346,53 @@ public class DeckEditorPanel extends javax.swing.JPanel { }, 60, TimeUnit.SECONDS); }//GEN-LAST:event_btnSubmitTimerActionPerformed - private void btnAddLandActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddLandActionPerformed - AddLandDialog addLand = new AddLandDialog(); - addLand.showDialog(deck, mode); - refreshDeck(); - }//GEN-LAST:event_btnAddLandActionPerformed + private void txtTimeRemainingActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_txtTimeRemainingActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_txtTimeRemainingActionPerformed + + private void btnImportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnImportActionPerformed + importChoose(evt); + }//GEN-LAST:event_btnImportActionPerformed + + private void btnExportActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnExportActionPerformed + exportChoose(evt); + }//GEN-LAST:event_btnExportActionPerformed - private void btnGenDeckActionPerformed(ActionEvent evt) { - try { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); - String path = DeckGenerator.generateDeck(); - deck = Deck.load(DeckImporterUtil.importDeck(path), true, true); - } catch (GameException ex) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Error loading generated deck", JOptionPane.ERROR_MESSAGE); - } catch (DeckGeneratorException ex) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), ex.getMessage(), "Generator error", JOptionPane.ERROR_MESSAGE); - } finally { - MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); - } - refreshDeck(); - } // Variables declaration - do not modify//GEN-BEGIN:variables private mage.client.cards.BigCard bigCard; + private javax.swing.JButton btnAddLand; private javax.swing.JButton btnExit; + private javax.swing.JButton btnExport; + private javax.swing.JButton btnGenDeck; private javax.swing.JButton btnImport; private javax.swing.JButton btnLoad; private javax.swing.JButton btnNew; private javax.swing.JButton btnSave; - private mage.client.deckeditor.CardSelector cardSelector; - private mage.client.deckeditor.DeckArea deckArea; - private javax.swing.JPanel jPanel1; - private javax.swing.JSplitPane jSplitPane1; - private javax.swing.JLabel lblDeckName; - private javax.swing.JTextField txtDeckName; private javax.swing.JButton btnSubmit; private javax.swing.JButton btnSubmitTimer; - private javax.swing.JButton btnAddLand; - private javax.swing.JButton btnGenDeck; private JComponent cardInfoPane; + /* + private org.mage.plugins.card.info.CardInfoPaneImpl cardInfoPane; + */ + private mage.client.deckeditor.CardSelector cardSelector; + private mage.client.deckeditor.DeckArea deckArea; + private javax.swing.JLabel lblDeckName; + private javax.swing.JPanel panelDeck; + private javax.swing.JPanel panelDeckCreate; + private javax.swing.JPanel panelDeckDraft; + private javax.swing.JPanel panelDeckExit; + private javax.swing.JPanel panelDeckLands; + private javax.swing.JPanel panelDeckLoad; + private javax.swing.JPanel panelDeckName; + private javax.swing.JPanel panelDeckSave; + private javax.swing.JPanel panelLeft; + private javax.swing.JSplitPane panelRight; + private javax.swing.JTextField txtDeckName; private javax.swing.JTextField txtTimeRemaining; // End of variables declaration//GEN-END:variables } -class DeckFilter extends FileFilter { - - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - - String ext = null; - String s = f.getName(); - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH); - } - return (ext == null) ? false : ext.equals("dck"); - } - - @Override - public String getDescription() { - return "Deck Files"; - } -} - class ImportFilter extends FileFilter { @Override @@ -1126,16 +1409,20 @@ class ImportFilter extends FileFilter { ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH); } if (ext != null) { - if (ext.toLowerCase(Locale.ENGLISH).equals("dec") || ext.toLowerCase(Locale.ENGLISH).equals("mwdeck") || ext.toLowerCase(Locale.ENGLISH).equals("txt") || ext.toLowerCase(Locale.ENGLISH).equals("dek")) { - return true; - } + return ext.equalsIgnoreCase("dec") + || ext.equalsIgnoreCase("mwdeck") + || ext.equalsIgnoreCase("txt") + || ext.equalsIgnoreCase("dek") + || ext.equalsIgnoreCase("cod") + || ext.equalsIgnoreCase("o8d") + || ext.equalsIgnoreCase("draft"); } return false; } @Override public String getDescription() { - return "*.dec | *.mwDeck | *.txt | *.dek"; + return "All formats (*.dec; *.mwDeck; *.txt; *.dek; *.cod; *.o8d; *.draft)"; } } @@ -1170,4 +1457,4 @@ class UpdateDeckTask extends SwingWorker { } catch (CancellationException ex) { } } -} +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.form new file mode 100644 index 0000000000..08b2a175b5 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.form @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.java new file mode 100644 index 0000000000..52c7ffb03c --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckExportClipboardDialog.java @@ -0,0 +1,236 @@ +package mage.client.deckeditor; + +import mage.cards.decks.Deck; +import mage.cards.decks.DeckFormats; +import mage.cards.decks.exporter.DeckExporter; +import mage.client.MageFrame; +import mage.client.dialog.MageDialog; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.event.KeyEvent; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; + +/** + * @author JayDi85 + */ +public class DeckExportClipboardDialog extends MageDialog { + + private Deck deck; + private ArrayList formats = new ArrayList<>(); + + public DeckExportClipboardDialog() { + initComponents(); + } + + public void showDialog(Deck deck) { + this.deck = deck; + + // formats combobox + formats.clear(); + comboFormats.removeAllItems(); + for (DeckFormats df : DeckFormats.values()) { + formats.add(df); + comboFormats.addItem(df.getExporter().getDescription()); + } + if (comboFormats.getItemCount() > 0) { + comboFormats.setSelectedIndex(0); + } + + onRefreshData(); + + this.setModal(true); + this.setResizable(true); + getRootPane().setDefaultButton(buttonOK); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + this.setVisible(true); + } + + private void setClipboardStringData(String text) { + try { + StringSelection data = new StringSelection(text); + Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data, data); + } catch (HeadlessException e) { + //e.printStackTrace(); + } + } + + private void onOK() { + onCopyToClipboard(); + this.removeDialog(); + } + + private void onCancel() { + this.removeDialog(); + } + + private void onRefreshData() { + int formatIndex = comboFormats.getSelectedIndex(); + if (formatIndex < 0 || formatIndex >= formats.size()) { + return; + } + + DeckExporter exporter = formats.get(formatIndex).getExporter(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + exporter.writeDeck(baos, deck.getDeckCardLists()); + editData.setText(baos.toString()); + editData.setCaretPosition(0); + } + + private void onCopyToClipboard() { + setClipboardStringData(editData.getText()); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panelData = new javax.swing.JScrollPane(); + editData = new javax.swing.JEditorPane(); + labelData = new javax.swing.JLabel(); + panelCommands = new javax.swing.JPanel(); + buttonOK = new javax.swing.JButton(); + buttonCancel = new javax.swing.JButton(); + buttonCopy = new javax.swing.JButton(); + comboFormats = new javax.swing.JComboBox<>(); + + setTitle("Export to clipboard"); + setMinimumSize(new java.awt.Dimension(400, 400)); + + panelData.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + panelData.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + panelData.setViewportView(editData); + + labelData.setText("Choose deck format:"); + + buttonOK.setText("Copy"); + buttonOK.setToolTipText("Import deck from current text"); + buttonOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonOKActionPerformed(evt); + } + }); + + buttonCancel.setText("Close"); + buttonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCancelActionPerformed(evt); + } + }); + + buttonCopy.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/copy_24.png"))); // NOI18N + buttonCopy.setToolTipText("Copy current text to clipboard"); + buttonCopy.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCopyActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); + panelCommands.setLayout(panelCommandsLayout); + panelCommandsLayout.setHorizontalGroup( + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelCommandsLayout.createSequentialGroup() + .addComponent(buttonCopy, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + panelCommandsLayout.setVerticalGroup( + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(buttonCopy, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + + comboFormats.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + comboFormats.addItemListener(new java.awt.event.ItemListener() { + public void itemStateChanged(java.awt.event.ItemEvent evt) { + comboFormatsItemStateChanged(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelCommands, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelData, javax.swing.GroupLayout.DEFAULT_SIZE, 364, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(labelData) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(comboFormats, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(8, 8, 8) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(labelData) + .addComponent(comboFormats, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(10, 10, 10) + .addComponent(panelData, javax.swing.GroupLayout.DEFAULT_SIZE, 520, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed + onCancel(); + }//GEN-LAST:event_buttonCancelActionPerformed + + private void buttonOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOKActionPerformed + onOK(); + }//GEN-LAST:event_buttonOKActionPerformed + + private void buttonCopyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCopyActionPerformed + onCopyToClipboard(); + }//GEN-LAST:event_buttonCopyActionPerformed + + private void comboFormatsItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_comboFormatsItemStateChanged + onRefreshData(); + }//GEN-LAST:event_comboFormatsItemStateChanged + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonCopy; + private javax.swing.JButton buttonOK; + private javax.swing.JComboBox comboFormats; + private javax.swing.JEditorPane editData; + private javax.swing.JLabel labelData; + private javax.swing.JPanel panelCommands; + private javax.swing.JScrollPane panelData; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.form new file mode 100644 index 0000000000..bb988c1694 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.form @@ -0,0 +1,141 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.java new file mode 100644 index 0000000000..5b7af3b3f6 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportClipboardDialog.java @@ -0,0 +1,210 @@ +package mage.client.deckeditor; + +import mage.client.MageFrame; +import mage.client.dialog.MageDialog; +import mage.util.DeckUtil; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.util.Optional; + +/** + * @author JayDi85 + */ +public class DeckImportClipboardDialog extends MageDialog { + + private static final String FORMAT_TEXT = + "// Example:\n" + + "//1 Library of Congress\n" + + "//1 Cryptic Gateway\n" + + "//1 Azami, Lady of Scrolls\n" + + "// NB: This is slow as, and will lock your screen :)\n" + + "\n" + + "// Your current clipboard:\n" + + "\n"; + + private String tmpPath; + + public DeckImportClipboardDialog() { + initComponents(); + } + + public void showDialog() { + this.tmpPath = ""; + onRefreshClipboard(); + + this.setModal(true); + this.setResizable(true); + getRootPane().setDefaultButton(buttonOK); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + this.setVisible(true); + } + + private Optional getClipboardStringData() { + try { + return Optional.of((String) Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor)); + } catch (HeadlessException | UnsupportedFlavorException | IOException e) { + //e.printStackTrace(); + } + return Optional.empty(); + } + + private void onOK() { + tmpPath = DeckUtil.writeTextToTempFile(editData.getText()); + this.removeDialog(); + } + + private void onCancel() { + this.removeDialog(); + } + + private void onRefreshClipboard() { + editData.setText(FORMAT_TEXT + getClipboardStringData().orElse("")); + editData.setCaretPosition(FORMAT_TEXT.length()); + } + + public String getTmpPath() { + return tmpPath; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panelData = new javax.swing.JScrollPane(); + editData = new javax.swing.JEditorPane(); + labelData = new javax.swing.JLabel(); + panelCommands = new javax.swing.JPanel(); + buttonOK = new javax.swing.JButton(); + buttonCancel = new javax.swing.JButton(); + buttonPaste = new javax.swing.JButton(); + + setTitle("Import from clipboard"); + setMinimumSize(new java.awt.Dimension(400, 400)); + + panelData.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); + panelData.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + panelData.setViewportView(editData); + + labelData.setLabelFor(editData); + labelData.setText("Deck in text format to import:"); + + buttonOK.setText("Import"); + buttonOK.setToolTipText("Import deck from current text"); + buttonOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonOKActionPerformed(evt); + } + }); + + buttonCancel.setText("Close"); + buttonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCancelActionPerformed(evt); + } + }); + + buttonPaste.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/paste_24.png"))); // NOI18N + buttonPaste.setToolTipText("Paste text from clipboard"); + buttonPaste.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPasteActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); + panelCommands.setLayout(panelCommandsLayout); + panelCommandsLayout.setHorizontalGroup( + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelCommandsLayout.createSequentialGroup() + .addComponent(buttonPaste, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 128, Short.MAX_VALUE) + .addComponent(buttonOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + ); + panelCommandsLayout.setVerticalGroup( + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(buttonPaste, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) + ); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(panelData, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(labelData) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(labelData) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelData, javax.swing.GroupLayout.DEFAULT_SIZE, 440, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed + onCancel(); + }//GEN-LAST:event_buttonCancelActionPerformed + + private void buttonOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonOKActionPerformed + onOK(); + }//GEN-LAST:event_buttonOKActionPerformed + + private void buttonPasteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPasteActionPerformed + onRefreshClipboard(); + }//GEN-LAST:event_buttonPasteActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonOK; + private javax.swing.JButton buttonPaste; + private javax.swing.JEditorPane editData; + private javax.swing.JLabel labelData; + private javax.swing.JPanel panelCommands; + private javax.swing.JScrollPane panelData; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.form b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.form deleted file mode 100644 index a1bceb019a..0000000000 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.form +++ /dev/null @@ -1,79 +0,0 @@ - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java b/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java deleted file mode 100644 index eef1987dfa..0000000000 --- a/Mage.Client/src/main/java/mage/client/deckeditor/DeckImportFromClipboardDialog.java +++ /dev/null @@ -1,157 +0,0 @@ -package mage.client.deckeditor; - -import mage.util.StreamUtils; - -import java.awt.*; -import java.awt.event.*; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import javax.swing.*; - -public class DeckImportFromClipboardDialog extends JDialog { - - private JPanel contentPane; - private JButton buttonOK; - private JButton buttonCancel; - private JEditorPane txtDeckList; - - private String tmpPath; - - public DeckImportFromClipboardDialog() { - initComponents(); - setContentPane(contentPane); - setModal(true); - getRootPane().setDefaultButton(buttonOK); - - buttonOK.addActionListener(e -> onOK()); - buttonCancel.addActionListener(e -> onCancel()); - - setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); - addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - onCancel(); - } - }); - - // Close on "ESC" - contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - } - - private void onOK() { - BufferedWriter bw = null; - try { - File temp = File.createTempFile("cbimportdeck", ".txt"); - bw = new BufferedWriter(new FileWriter(temp)); - bw.write(txtDeckList.getText()); - tmpPath = temp.getPath(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - StreamUtils.closeQuietly(bw); - } - - dispose(); - } - - private void onCancel() { - dispose(); - } - - public String getTmpPath() { - return tmpPath; - } - - private void initComponents() { - contentPane = new JPanel(); - JPanel panel1 = new JPanel(); - JPanel panel2 = new JPanel(); - buttonOK = new JButton(); - buttonCancel = new JButton(); - JPanel panel3 = new JPanel(); - txtDeckList = new JEditorPane(); - - { - contentPane.setMinimumSize(new Dimension(540, 450)); - - contentPane.setBorder(new javax.swing.border.CompoundBorder( - new javax.swing.border.TitledBorder(new javax.swing.border.EmptyBorder(0, 0, 0, 0), - "Import from Clipboard", javax.swing.border.TitledBorder.CENTER, - javax.swing.border.TitledBorder.TOP, new java.awt.Font("Dialog", java.awt.Font.PLAIN, 12), - java.awt.Color.BLACK), contentPane.getBorder())); - - contentPane.addPropertyChangeListener(e -> { - if ("border".equals(e.getPropertyName())) { - throw new RuntimeException(); - } - }); - - contentPane.addPropertyChangeListener(e -> { - if ("border".equals(e.getPropertyName())) { - throw new RuntimeException(); - } - }); - - contentPane.setLayout(new GridBagLayout()); - ((GridBagLayout) contentPane.getLayout()).columnWidths = new int[]{0, 0}; - ((GridBagLayout) contentPane.getLayout()).rowHeights = new int[]{0, 0, 0}; - ((GridBagLayout) contentPane.getLayout()).columnWeights = new double[]{0.01, 1.0E-4}; - ((GridBagLayout) contentPane.getLayout()).rowWeights = new double[]{0.01, 0.0, 1.0E-4}; - - { - panel1.setLayout(new GridBagLayout()); - ((GridBagLayout) panel1.getLayout()).columnWidths = new int[]{0, 0, 0}; - ((GridBagLayout) panel1.getLayout()).rowHeights = new int[]{0, 0}; - ((GridBagLayout) panel1.getLayout()).columnWeights = new double[]{0.0, 0.01, 1.0E-4}; - ((GridBagLayout) panel1.getLayout()).rowWeights = new double[]{0.01, 1.0E-4}; - - { - panel2.setLayout(new GridBagLayout()); - ((GridBagLayout) panel2.getLayout()).columnWidths = new int[]{0, 4, 0, 0}; - ((GridBagLayout) panel2.getLayout()).rowHeights = new int[]{0, 0}; - ((GridBagLayout) panel2.getLayout()).columnWeights = new double[]{0.01, 0.0, 0.01, 1.0E-4}; - ((GridBagLayout) panel2.getLayout()).rowWeights = new double[]{0.0, 1.0E-4}; - - //---- buttonOK ---- - buttonOK.setText("Import"); - panel2.add(buttonOK, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 0), 0, 0)); - - //---- buttonCancel ---- - buttonCancel.setText("Cancel"); - panel2.add(buttonCancel, new GridBagConstraints(2, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, - new Insets(0, 0, 0, 0), 0, 0)); - } - panel1.add(panel2, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 0), 0, 0)); - } - contentPane.add(panel1, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 0), 0, 0)); - - { - panel3.setLayout(new GridBagLayout()); - ((GridBagLayout) panel3.getLayout()).columnWidths = new int[]{0, 0}; - ((GridBagLayout) panel3.getLayout()).rowHeights = new int[]{0, 0}; - ((GridBagLayout) panel3.getLayout()).columnWeights = new double[]{0.0, 1.0E-4}; - ((GridBagLayout) panel3.getLayout()).rowWeights = new double[]{1.0, 1.0E-4}; - - txtDeckList.setMinimumSize(new Dimension(250, 400)); - txtDeckList.setPreferredSize(new Dimension(550, 400)); - txtDeckList.setText("// Example:\n//1 Library of Congress\n//1 Cryptic Gateway\n//1 Azami, Lady of Scrolls\n// NB: This is slow as, and will lock your screen :)"); - JScrollPane txtScrollableDeckList = new JScrollPane(txtDeckList); - panel3.add(txtScrollableDeckList, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(0, 0, 0, 0), 0, 0)); - } - contentPane.add(panel3, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, - new Insets(0, 0, 5, 0), 0, 0)); - } - } -} diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingBase.java b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingBase.java index 59eafa9004..9df3a75a17 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingBase.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingBase.java @@ -10,7 +10,7 @@ import mage.client.dialog.PreferencesDialog; public class SortSettingBase extends SortSetting { - private final static SortSettingBase instance = new SortSettingBase(); + private static final SortSettingBase instance = new SortSettingBase(); public static SortSettingBase getInstance() { return instance; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDeck.java b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDeck.java index 17b5956cc0..f520d106f4 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDeck.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDeck.java @@ -10,7 +10,7 @@ import mage.client.dialog.PreferencesDialog; public class SortSettingDeck extends SortSetting { - private final static SortSettingDeck instance = new SortSettingDeck(); + private static final SortSettingDeck instance = new SortSettingDeck(); public static SortSettingDeck getInstance() { return instance; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDraft.java b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDraft.java index 3545eaa77c..26b4d3cc48 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDraft.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/SortSettingDraft.java @@ -10,7 +10,7 @@ import mage.client.dialog.PreferencesDialog; */ public class SortSettingDraft extends SortSetting { - private final static SortSettingDraft instance = new SortSettingDraft(); + private static final SortSettingDraft instance = new SortSettingDraft(); public static SortSettingDraft getInstance() { return instance; diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java index 91f2841a3f..999ec7c066 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/CollectionViewerPanel.java @@ -1,27 +1,19 @@ - package mage.client.deckeditor.collection.viewer; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.GridBagLayout; -import javax.swing.Box; -import javax.swing.BoxLayout; -import javax.swing.JButton; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JLabel; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; +import mage.cards.repository.ExpansionRepository; +import mage.cards.repository.RepositoryEvent; import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.dialog.PreferencesDialog; import mage.client.plugins.impl.Plugins; import mage.client.util.gui.FastSearchUtil; import mage.client.util.sets.ConstructedFormats; +import mage.game.events.Listener; import org.apache.log4j.Logger; +import javax.swing.*; +import java.awt.*; + /** * Pane with big card and mage book. * @@ -33,6 +25,7 @@ public final class CollectionViewerPanel extends JPanel { protected static final String LAYOYT_CONFIG_KEY = "collectionViewerLayoutConfig"; private static final String FORMAT_CONFIG_KEY = "collectionViewerFormat"; + private static Listener setsDbListener = null; public CollectionViewerPanel() { initComponents(); @@ -49,6 +42,12 @@ public final class CollectionViewerPanel extends JPanel { this.bigCard = null; } + private void reloadFormatCombobox() { + DefaultComboBoxModel model = new DefaultComboBoxModel<>(ConstructedFormats.getTypes()); + formats.setModel(model); + formats.setSelectedItem(ConstructedFormats.getDefault()); + } + public void initComponents() { buttonsPanel = new javax.swing.JPanel(); buttonsPanel.setOpaque(false); @@ -74,8 +73,27 @@ public final class CollectionViewerPanel extends JPanel { setPanel.setAlignmentX(Component.LEFT_ALIGNMENT); buttonsPanel.add(setPanel); // combo set - formats = new JComboBox<>(ConstructedFormats.getTypes()); - formats.setSelectedItem(ConstructedFormats.getDefault()); + formats = new JComboBox<>(); + reloadFormatCombobox(); + // auto-update sets list on changes + setsDbListener = new Listener() { + @Override + public void event(RepositoryEvent event) { + if (event.getEventType().equals(RepositoryEvent.RepositoryEventType.DB_UPDATED)) { + reloadFormatCombobox(); + } + } + }; + ExpansionRepository.instance.subscribe(setsDbListener); + // update cards on format combobox changes + formats.addActionListener(e -> { + if (mageBook != null) { + String format = (String) formats.getSelectedItem(); + MageFrame.getPreferences().put(CollectionViewerPanel.FORMAT_CONFIG_KEY, format); + mageBook.updateDispayedSets(format); + } + }); + formats.setAlignmentX(0.0F); formats.setMinimumSize(new Dimension(50, 25)); formats.setPreferredSize(new Dimension(50, 25)); @@ -104,12 +122,12 @@ public final class CollectionViewerPanel extends JPanel { small3x3 = new JRadioButton("3x3"); small3x3.setForeground(Color.white); - boolean selected3x3 = MageFrame.getPreferences().get(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3x3).equals(MageBook.LAYOUT_3x3); + boolean selected3x3 = MageFrame.getPreferences().get(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3X3).equals(MageBook.LAYOUT_3X3); small3x3.setSelected(selected3x3); small3x3.addActionListener(e -> { big4x4.setSelected(false); - mageBook.updateSize(MageBook.LAYOUT_3x3); - MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3x3); + mageBook.updateSize(MageBook.LAYOUT_3X3); + MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3X3); }); buttonsPanel.add(small3x3); @@ -118,8 +136,8 @@ public final class CollectionViewerPanel extends JPanel { big4x4.setSelected(!selected3x3); big4x4.addActionListener(e -> { small3x3.setSelected(false); - mageBook.updateSize(MageBook.LAYOUT_4x4); - MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_4x4); + mageBook.updateSize(MageBook.LAYOUT_4X4); + MageFrame.getPreferences().put(LAYOYT_CONFIG_KEY, MageBook.LAYOUT_4X4); }); buttonsPanel.add(big4x4); @@ -155,14 +173,6 @@ public final class CollectionViewerPanel extends JPanel { cardsOrTokens.addActionListener(e -> mageBook.cardsOrTokens(cardsOrTokens.isSelected())); buttonsPanel.add(cardsOrTokens); - formats.addActionListener(e -> { - if (mageBook != null) { - String format = (String) formats.getSelectedItem(); - MageFrame.getPreferences().put(CollectionViewerPanel.FORMAT_CONFIG_KEY, format); - mageBook.updateDispayedSets(format); - } - }); - buttonsPanel.add(Box.createVerticalGlue()); bigCard.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java index fd53051191..80b4c18fbf 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/collection/viewer/MageBook.java @@ -1,20 +1,5 @@ - package mage.client.deckeditor.collection.viewer; -import java.awt.*; -import java.awt.image.BufferedImage; -import java.io.FileNotFoundException; -import java.io.InputStream; -import static java.lang.Math.min; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import javax.imageio.ImageIO; -import javax.swing.*; import mage.cards.*; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; @@ -24,14 +9,16 @@ import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.components.HoverButton; import mage.client.plugins.impl.Plugins; -import mage.client.util.*; +import mage.client.util.Config; +import mage.client.util.ImageHelper; +import mage.client.util.NaturalOrderCardNumberComparator; import mage.client.util.audio.AudioManager; import mage.client.util.sets.ConstructedFormats; import mage.components.ImagePanel; import mage.components.ImagePanelStyle; -import mage.constants.Rarity; import mage.game.command.Emblem; import mage.game.command.Plane; +import mage.game.draft.RateCard; import mage.game.permanent.PermanentToken; import mage.game.permanent.token.Token; import mage.view.CardView; @@ -41,7 +28,20 @@ import mage.view.PlaneView; import org.apache.log4j.Logger; import org.mage.card.arcane.ManaSymbols; import org.mage.plugins.card.images.CardDownloadData; -import static org.mage.plugins.card.images.DownloadPictures.getTokenCardUrls; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.*; + +import static java.lang.Math.min; +import static org.mage.plugins.card.images.DownloadPicturesService.getTokenCardUrls; /** * Mage book with cards and page flipping. @@ -52,15 +52,15 @@ public class MageBook extends JComponent { private static final long serialVersionUID = 1L; - public static final String LAYOUT_3x3 = "small"; + public static final String LAYOUT_3X3 = "small"; - public static final String LAYOUT_4x4 = "big"; + public static final String LAYOUT_4X4 = "big"; public MageBook(BigCard bigCard) { super(); this.bigCard = bigCard; this.setsToDisplay = ConstructedFormats.getSetsByFormat(ConstructedFormats.getDefault()); - boolean selected3x3 = MageFrame.getPreferences().get(CollectionViewerPanel.LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3x3).equals(MageBook.LAYOUT_3x3); + boolean selected3x3 = MageFrame.getPreferences().get(CollectionViewerPanel.LAYOYT_CONFIG_KEY, MageBook.LAYOUT_3X3).equals(MageBook.LAYOUT_3X3); this.conf = selected3x3 ? new _3x3Configuration() : new _4x4Configuration(); initComponents(); } @@ -250,7 +250,7 @@ public class MageBook extends JComponent { // calculate the x offset of the second (right) page int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH) - - (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; + - (cardDimensions.getFrameWidth() + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; rectangle.setLocation(second_page_x, OFFSET_Y); for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) { @@ -265,7 +265,7 @@ public class MageBook extends JComponent { public int showTokens() { jLayeredPane.removeAll(); List tokens = getTokens(currentPage, currentSet); - if (tokens != null && tokens.size() > 0) { + if (tokens != null && !tokens.isEmpty()) { int size = tokens.size(); Rectangle rectangle = new Rectangle(); rectangle.translate(OFFSET_X, OFFSET_Y); @@ -277,7 +277,7 @@ public class MageBook extends JComponent { // calculate the x offset of the second (right) page int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH) - - (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; + - (cardDimensions.getFrameWidth() + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; rectangle.setLocation(second_page_x, OFFSET_Y); for (int i = conf.CARDS_PER_PAGE / 2; i < min(conf.CARDS_PER_PAGE, size); i++) { @@ -295,37 +295,45 @@ public class MageBook extends JComponent { public int showEmblems(int numTokens) { List emblems = getEmblems(currentPage, currentSet, numTokens); int numEmblems = 0; - if (emblems != null && emblems.size() > 0) { + if (emblems != null && !emblems.isEmpty()) { int size = emblems.size(); numEmblems = size; Rectangle rectangle = new Rectangle(); rectangle.translate(OFFSET_X, OFFSET_Y); // calculate the x offset of the second (right) page int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH) - - (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; + - (cardDimensions.getFrameWidth() + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; // Already have numTokens tokens presented. Appending the emblems to the end of these. numTokens = numTokens % conf.CARDS_PER_PAGE; if (numTokens < conf.CARDS_PER_PAGE / 2) { + // page 1 with tokens for (int z = 0; z < numTokens && z < conf.CARDS_PER_PAGE / 2; z++) { rectangle = CardPosition.translatePosition(z, rectangle, conf); } } else { + // page 2 with tokens rectangle.setLocation(second_page_x, OFFSET_Y); for (int z = 0; z < numTokens - conf.CARDS_PER_PAGE / 2; z++) { rectangle = CardPosition.translatePosition(z, rectangle, conf); } } + // page 1 with emblems after tokens int lastI = 0; + boolean needContinueFromPage1 = false; for (int i = 0; i < size && i + numTokens < conf.CARDS_PER_PAGE / 2; i++) { Emblem emblem = emblems.get(i); addEmblem(emblem, bigCard, null, rectangle); rectangle = CardPosition.translatePosition(i + numTokens, rectangle, conf); lastI++; + needContinueFromPage1 = true; } - rectangle.setLocation(second_page_x, OFFSET_Y); + // page 2 with emblems after tokens + if (needContinueFromPage1) { + rectangle.setLocation(second_page_x, OFFSET_Y); + } if (size + numTokens > conf.CARDS_PER_PAGE / 2) { for (int i = lastI; i < size && i + numTokens < conf.CARDS_PER_PAGE; i++) { Emblem emblem = emblems.get(i); @@ -350,29 +358,37 @@ public class MageBook extends JComponent { rectangle.translate(OFFSET_X, OFFSET_Y); int second_page_x = (conf.WIDTH - 2 * LEFT_RIGHT_PAGES_WIDTH) - - (cardDimensions.frameWidth + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; + - (cardDimensions.getFrameWidth() + CardPosition.GAP_X) * conf.CARD_COLUMNS + CardPosition.GAP_X - OFFSET_X; numTokensEmblems = numTokensEmblems % conf.CARDS_PER_PAGE; if (numTokensEmblems < conf.CARDS_PER_PAGE / 2) { + // page 1 with tokens/emblems for (int z = 0; z < numTokensEmblems && z < conf.CARDS_PER_PAGE / 2; z++) { rectangle = CardPosition.translatePosition(z, rectangle, conf); } } else { + // page 2 with tokens/emblems rectangle.setLocation(second_page_x, OFFSET_Y); for (int z = 0; z < numTokensEmblems - conf.CARDS_PER_PAGE / 2; z++) { rectangle = CardPosition.translatePosition(z, rectangle, conf); } } + // page 1 with planes after tokens/emblems int lastI = 0; + boolean needContinueFromPage1 = false; for (int i = 0; i < size && i + numTokensEmblems < conf.CARDS_PER_PAGE / 2; i++) { Plane plane = planes.get(i); addPlane(plane, bigCard, null, rectangle); rectangle = CardPosition.translatePosition(i + numTokensEmblems, rectangle, conf); lastI++; + needContinueFromPage1 = true; } - rectangle.setLocation(second_page_x, OFFSET_Y); + // page 2 with planes after tokens/emblems + if (needContinueFromPage1) { + rectangle.setLocation(second_page_x, OFFSET_Y); + } if (size + numTokensEmblems > conf.CARDS_PER_PAGE / 2) { for (int i = lastI; i < size && i + numTokensEmblems < conf.CARDS_PER_PAGE; i++) { Plane plane = planes.get(i); @@ -388,30 +404,44 @@ public class MageBook extends JComponent { private void addCard(CardView card, BigCard bigCard, UUID gameId, Rectangle rectangle) { if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); } final MageCard cardImg = Plugins.instance.getMageCard(card, bigCard, cardDimension, gameId, true, true); cardImg.setBounds(rectangle); jLayeredPane.add(cardImg, JLayeredPane.DEFAULT_LAYER, 10); cardImg.update(card); - cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight); + cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.getFrameWidth(), cardDimensions.getFrameHeight()); cardImg.setCardCaptionTopOffset(8); // card caption below real card caption to see full name even with mana icons // card number label JLabel cardNumber = new JLabel(); int dy = -5; // image panel have empty space in bottom (bug?), need to move label up - cardNumber.setBounds(rectangle.x, rectangle.y + cardImg.getHeight() + dy, cardDimensions.frameWidth, 20); + cardNumber.setBounds(rectangle.x, rectangle.y + cardImg.getHeight() + dy, cardDimensions.getFrameWidth(), 20); cardNumber.setHorizontalAlignment(SwingConstants.CENTER); //cardNumber.setBorder(BorderFactory.createLineBorder(new Color(180, 50, 150), 3, true)); cardNumber.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD)); cardNumber.setText(card.getCardNumber()); jLayeredPane.add(cardNumber); + + // draft rating label ( + JLabel draftRating = new JLabel(); + dy = -5 * 2 + cardNumber.getHeight(); // under card number + draftRating.setBounds(rectangle.x, rectangle.y + cardImg.getHeight() + dy, cardDimensions.getFrameWidth(), 20); + draftRating.setHorizontalAlignment(SwingConstants.CENTER); + //draftRating.setBorder(BorderFactory.createLineBorder(new Color(0, 0, 150), 3, true)); + draftRating.setFont(jLayeredPane.getFont().deriveFont(jLayeredPane.getFont().getStyle() | Font.BOLD)); + if (card.getOriginalCard() != null) { + draftRating.setText("draft rating: " + RateCard.rateCard(card.getOriginalCard(), null)); + } else { + draftRating.setText(""); + } + jLayeredPane.add(draftRating); } private void addToken(Token token, BigCard bigCard, UUID gameId, Rectangle rectangle) { if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); } PermanentToken newToken = new PermanentToken(token, null, token.getOriginalExpansionSetCode(), null); newToken.removeSummoningSickness(); @@ -421,7 +451,7 @@ public class MageBook extends JComponent { cardImg.setBounds(rectangle); jLayeredPane.add(cardImg, JLayeredPane.DEFAULT_LAYER, 10); cardImg.update(theToken); - cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.frameWidth, cardDimensions.frameHeight); + cardImg.setCardBounds(rectangle.x, rectangle.y, cardDimensions.getFrameWidth(), cardDimensions.getFrameHeight()); } private void addEmblem(Emblem emblem, BigCard bigCard, UUID gameId, Rectangle rectangle) { @@ -602,13 +632,13 @@ public class MageBook extends JComponent { } } } - + int totalTokens = getTotalNumTokens(set); int start = 0; if (!(page * conf.CARDS_PER_PAGE <= totalTokens && (page + 1) * conf.CARDS_PER_PAGE >= totalTokens)) { start = page * conf.CARDS_PER_PAGE - totalTokens; } - + int end = emblems.size(); if ((page + 1) * conf.CARDS_PER_PAGE < totalTokens + emblems.size()) { end = (page + 1) * conf.CARDS_PER_PAGE - totalTokens; @@ -659,7 +689,7 @@ public class MageBook extends JComponent { } } } - + int totalTokens = getTotalNumTokens(set); int totalTokensEmblems = totalTokens + getTotalNumEmblems(set); int start = 0; @@ -667,7 +697,7 @@ public class MageBook extends JComponent { start = page * conf.CARDS_PER_PAGE - totalTokensEmblems; pageRight.setVisible(true); } - + int end = planes.size(); if ((page + 1) * conf.CARDS_PER_PAGE < totalTokensEmblems + planes.size()) { end = (page + 1) * conf.CARDS_PER_PAGE - totalTokensEmblems; @@ -797,10 +827,10 @@ public class MageBook extends JComponent { public void updateSize(String size) { switch (size) { - case LAYOUT_3x3: + case LAYOUT_3X3: this.conf = new _3x3Configuration(); break; - case LAYOUT_4x4: + case LAYOUT_4X4: this.conf = new _4x4Configuration(); break; default: @@ -825,8 +855,8 @@ public class MageBook extends JComponent { public static Rectangle translatePosition(int index, Rectangle r, Configuration conf) { Rectangle rect = new Rectangle(r); - rect.translate((cardDimensions.frameWidth + GAP_X) * conf.dx[index], - (cardDimensions.frameHeight + GAP_Y) * conf.dy[index]); + rect.translate((cardDimensions.getFrameWidth() + GAP_X) * conf.dx[index], + (cardDimensions.getFrameHeight() + GAP_Y) * conf.dy[index]); return rect; } diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java b/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java index 11a8a9d24b..3c52cabeb4 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/table/MageCardComparator.java @@ -26,10 +26,12 @@ */ package mage.client.deckeditor.table; -import java.util.Comparator; - import mage.cards.MageCard; +import mage.game.draft.RateCard; import mage.view.CardView; +import org.apache.log4j.Logger; + +import java.util.Comparator; /** * {@link MageCard} comparator. Used to sort cards in Deck Editor Table View @@ -39,6 +41,8 @@ import mage.view.CardView; */ public class MageCardComparator implements Comparator { + private static final Logger logger = Logger.getLogger(MageCardComparator.class); + private final int column; private final boolean ascending; @@ -49,14 +53,12 @@ public class MageCardComparator implements Comparator { @Override public int compare(CardView a, CardView b) { - Comparable aCom = null; - Comparable bCom = null; + Comparable aCom = 1; + Comparable bCom = 1; switch (column) { // #skip case 0: - aCom = 1; - bCom = 1; break; // Name case 1: @@ -107,6 +109,10 @@ public class MageCardComparator implements Comparator { aCom = Integer.parseInt(a.getCardNumber().replaceAll("[\\D]", "")); bCom = Integer.parseInt(b.getCardNumber().replaceAll("[\\D]", "")); break; + case 9: + aCom = RateCard.rateCard(a.getOriginalCard(), null); + bCom = RateCard.rateCard(b.getOriginalCard(), null); + break; default: break; } diff --git a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java index 20e6513c1d..ee8f160a7e 100644 --- a/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java +++ b/Mage.Client/src/main/java/mage/client/deckeditor/table/TableModel.java @@ -1,4 +1,3 @@ - package mage.client.deckeditor.table; import mage.client.MageFrame; @@ -13,6 +12,7 @@ import mage.client.util.Event; import mage.client.util.Listener; import mage.client.util.gui.GuiDisplayUtil; import mage.constants.EnlargeMode; +import mage.game.draft.RateCard; import mage.view.CardView; import mage.view.CardsView; import org.apache.log4j.Logger; @@ -25,8 +25,8 @@ import javax.swing.table.TableColumnModel; import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; -import java.util.*; import java.util.List; +import java.util.*; import java.util.Map.Entry; /** @@ -51,8 +51,9 @@ public class TableModel extends AbstractTableModel implements ICardGrid { private boolean displayNoCopies = false; private UpdateCountsCallback updateCountsCallback; - private final String column[] = {"Qty", "Name", "Cost", "Color", "Type", "Stats", "Rarity", "Set", "#"}; + private final String[] column = {"Qty", "Name", "Cost", "Color", "Type", "Stats", "Rarity", "Set", "Card number", "Draft Rating"}; public final int COLUMN_INDEX_COST = 2; + public final int COLUMN_INDEX_RATING = 9; private SortSetting sortSetting; private int recentSortedColumn; @@ -239,6 +240,8 @@ public class TableModel extends AbstractTableModel implements ICardGrid { return c.getExpansionSetCode(); case 8: return c.getCardNumber(); + case 9: + return RateCard.rateCard(c.getOriginalCard(), null); default: return "error"; } @@ -246,8 +249,8 @@ public class TableModel extends AbstractTableModel implements ICardGrid { private void addCard(CardView card, BigCard bigCard, UUID gameId) { if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, - Config.dimensions.frameHeight); + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), + Config.dimensions.getFrameHeight()); } cards.put(card.getId(), card); diff --git a/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.form b/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.form index f9036d14f4..3055978fc8 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.form @@ -27,14 +27,23 @@ - - - - + + + + - - + + + + + + + + + + + @@ -54,8 +63,11 @@ - - + + + + + @@ -64,7 +76,7 @@ - + @@ -95,5 +107,13 @@ + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.java index a311aefc20..c9b8c1165c 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AboutDialog.java @@ -1,26 +1,18 @@ - - package mage.client.dialog; +import mage.client.MageFrame; import mage.utils.MageVersion; -/* - * AboutDialog.java - * - * Created on Mar 10, 2010, 8:19:41 AM - */ - +import javax.swing.*; +import java.awt.event.KeyEvent; /** - * - * @author BetaSteward_at_googlemail.com + * @author JayDi85 */ public class AboutDialog extends MageDialog { - /** Creates new form AboutDialog */ public AboutDialog() { - this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); initComponents(); this.modal = false; } @@ -28,10 +20,28 @@ public class AboutDialog extends MageDialog { public void showDialog(MageVersion version) { this.lblVersion.setText(version.toString()); this.setLocation(100, 100); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + this.setVisible(true); } - /** This method is called from within the constructor to + private void onCancel() { + this.hideDialog(); + } + + /** + * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. @@ -46,12 +56,17 @@ public class AboutDialog extends MageDialog { jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); jLabel4 = new javax.swing.JLabel(); + btnWhatsNew = new javax.swing.JButton(); setMaximizable(true); setTitle("About XMage"); - btnOk.setText("OK"); - btnOk.addActionListener(this::btnOkActionPerformed); + btnOk.setText("Close"); + btnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOkActionPerformed(evt); + } + }); jLabel1.setText("XMage client"); @@ -59,53 +74,74 @@ public class AboutDialog extends MageDialog { jLabel2.setText("Courtesy: BetaSteward@googlemail.com. Site: http://XMage.de/"); - jLabel3.setText("Devs: BetaSteward, Noxx, Eugen.Rivniy, North, LevelX2, Jeff, Plopman, dustinconrad, emerald000,"); - jLabel4.setText("fireshoes, lunaskyrise, mnapoleon, jgod, LoneFox, drmDev, spjspj, TheElk801, L_J, JayDi85."); + jLabel3.setText("Devs: BetaSteward, Noxx, Eugen.Rivniy, North, LevelX2, Jeff, Plopman, dustinconrad, emerald000.,"); + + jLabel4.setText("fireshoes, lunaskyrise, mnapoleon, jgod, LoneFox."); + + btnWhatsNew.setText("What's new"); + btnWhatsNew.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnWhatsNewActionPerformed(evt); + } + }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblVersion)) - .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(btnOk) - .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(btnWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblVersion)) + .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING)) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(jLabel1) - .addComponent(lblVersion)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel2) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel4) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 71, Short.MAX_VALUE) - .addComponent(btnOk) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(lblVersion)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 21, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel4) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 68, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); pack(); }// //GEN-END:initComponents private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed - this.removeDialog(); + onCancel(); }//GEN-LAST:event_btnOkActionPerformed + private void btnWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnWhatsNewActionPerformed + MageFrame.getInstance().showWhatsNewDialog(true); + }//GEN-LAST:event_btnWhatsNewActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnOk; + private javax.swing.JButton btnWhatsNew; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form index 53405d95e3..6dc731f950 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.form @@ -51,9 +51,9 @@ - + - + @@ -103,10 +103,12 @@ - - - + + + + + @@ -150,8 +152,8 @@ - - + + @@ -161,7 +163,7 @@ - + @@ -304,20 +306,20 @@ - + - + - + - + @@ -366,7 +368,7 @@
- + diff --git a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java index 1abb59a590..e3c067ca5d 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/AddLandDialog.java @@ -1,23 +1,10 @@ - package mage.client.dialog; -import java.awt.image.BufferedImage; -import java.util.List; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import javax.swing.DefaultComboBoxModel; -import javax.swing.ImageIcon; -import javax.swing.JLayeredPane; import mage.Mana; import mage.cards.Card; import mage.cards.FrameStyle; import mage.cards.decks.Deck; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.cards.repository.ExpansionInfo; -import mage.cards.repository.ExpansionRepository; +import mage.cards.repository.*; import mage.client.MageFrame; import mage.client.constants.Constants.DeckEditorMode; import mage.client.util.gui.FastSearchUtil; @@ -26,8 +13,15 @@ import mage.util.RandomUtil; import org.apache.log4j.Logger; import org.mage.card.arcane.ManaSymbols; +import javax.swing.*; +import java.awt.event.KeyEvent; +import java.awt.image.BufferedImage; +import java.util.List; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + /** - * * @author BetaSteward_at_googlemail.com */ public class AddLandDialog extends MageDialog { @@ -38,9 +32,6 @@ public class AddLandDialog extends MageDialog { private static final int DEFAULT_SEALED_DECK_CARD_NUMBER = 40; - /** - * Creates new form AddLandDialog - */ public AddLandDialog() { initComponents(); this.setModal(true); @@ -100,12 +91,6 @@ public class AddLandDialog extends MageDialog { } - // windows settings - if (this.isModal()) { - MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - } else { - MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); - } spnDeckSize.setValue(DEFAULT_SEALED_DECK_CARD_NUMBER); BufferedImage image = ManaSymbols.getSizedManaSymbol("G", 15); if (image != null) { @@ -128,6 +113,20 @@ public class AddLandDialog extends MageDialog { lblSwampIcon.setIcon(new ImageIcon(image)); } + getRootPane().setDefaultButton(btnOK); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + this.setVisible(true); } @@ -178,6 +177,27 @@ public class AddLandDialog extends MageDialog { } } + private void onCancel() { + this.removeDialog(); + } + + private void onOK() { + int nForest = ((Number) spnForest.getValue()).intValue(); + int nIsland = ((Number) spnIsland.getValue()).intValue(); + int nMountain = ((Number) spnMountain.getValue()).intValue(); + int nPlains = ((Number) spnPlains.getValue()).intValue(); + int nSwamp = ((Number) spnSwamp.getValue()).intValue(); + boolean useFullArt = ckbFullArtLands.isSelected(); + + addLands("Forest", nForest, useFullArt); + addLands("Island", nIsland, useFullArt); + addLands("Mountain", nMountain, useFullArt); + addLands("Plains", nPlains, useFullArt); + addLands("Swamp", nSwamp, useFullArt); + + this.removeDialog(); + } + /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -208,7 +228,7 @@ public class AddLandDialog extends MageDialog { lblDeckSize = new javax.swing.JLabel(); spnDeckSize = new javax.swing.JSpinner(); btnAutoAdd = new javax.swing.JButton(); - btnAdd = new javax.swing.JButton(); + btnOK = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); panelSet = new javax.swing.JPanel(); cbLandSet = new javax.swing.JComboBox(); @@ -221,7 +241,7 @@ public class AddLandDialog extends MageDialog { setTitle("Add Land"); - lblLandSet.setText("Set:"); + lblLandSet.setText("From set:"); lblForest.setText("Forest:"); @@ -268,7 +288,7 @@ public class AddLandDialog extends MageDialog { spnDeckSize.setModel(new javax.swing.SpinnerNumberModel(0, 0, null, 1)); - btnAutoAdd.setText("Suggest"); + btnAutoAdd.setText("Suggest lands"); btnAutoAdd.setToolTipText("Propose related to the mana costs of the cards in the deck
\nthe number of lands to add to get to the set deck size."); btnAutoAdd.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -276,11 +296,11 @@ public class AddLandDialog extends MageDialog { } }); - btnAdd.setText("Add"); - btnAdd.setToolTipText("Add the selected number of basic lands to the deck."); - btnAdd.addActionListener(new java.awt.event.ActionListener() { + btnOK.setText("Add lands"); + btnOK.setToolTipText("Add the selected number of basic lands to the deck."); + btnOK.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - btnAddActionPerformed(evt); + btnOKActionPerformed(evt); } }); @@ -293,7 +313,7 @@ public class AddLandDialog extends MageDialog { panelSet.setLayout(new javax.swing.BoxLayout(panelSet, javax.swing.BoxLayout.LINE_AXIS)); - cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + cbLandSet.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); cbLandSet.setMinimumSize(new java.awt.Dimension(20, 20)); panelSet.add(cbLandSet); @@ -308,132 +328,121 @@ public class AddLandDialog extends MageDialog { }); panelSet.add(btnSetFastSearch); - ckbFullArtLands.setText("Only use full art lands"); + ckbFullArtLands.setText("Only full art lands"); ckbFullArtLands.setToolTipText("For example, lands from ZEN/UST/HOU"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblMountain) - .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING)) - .addComponent(lblDeckSize)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(btnAdd) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel) - .addContainerGap()) - .addComponent(ckbFullArtLands) - .addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblForestIcon, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(btnAutoAdd))) - .addGroup(layout.createSequentialGroup() - .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(36, 36, 36)))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblMountain) + .addComponent(lblForest, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblLandSet, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblIsland, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblPains, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblSwamp, javax.swing.GroupLayout.Alignment.TRAILING)) + .addComponent(lblDeckSize)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addComponent(ckbFullArtLands) + .addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 219, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(layout.createSequentialGroup() + .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblForestIcon, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(btnAutoAdd))) + .addGroup(layout.createSequentialGroup() + .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(36, 36, 36)))) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblLandSet) - .addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblForest) - .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblForestIcon, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblIsland) - .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblMountain) - .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPains) - .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblSwamp) - .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(ckbFullArtLands) - .addGap(2, 2, 2) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnAutoAdd) - .addComponent(lblDeckSize) - .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnAdd) - .addComponent(btnCancel)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblLandSet) + .addComponent(panelSet, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblForestIcon, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblForest) + .addComponent(spnForest, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblIsland) + .addComponent(spnIsland, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblIslandIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblMountain) + .addComponent(spnMountain, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblMountainIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPains) + .addComponent(spnPlains, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblPlainsIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblSwamp) + .addComponent(spnSwamp, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(lblSwampIcon, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(ckbFullArtLands) + .addGap(2, 2, 2) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnAutoAdd) + .addComponent(lblDeckSize) + .addComponent(spnDeckSize, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); pack(); }// //GEN-END:initComponents private void btnCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCancelActionPerformed - this.removeDialog(); + onCancel(); }//GEN-LAST:event_btnCancelActionPerformed - private void btnAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAddActionPerformed - int nForest = ((Number) spnForest.getValue()).intValue(); - int nIsland = ((Number) spnIsland.getValue()).intValue(); - int nMountain = ((Number) spnMountain.getValue()).intValue(); - int nPlains = ((Number) spnPlains.getValue()).intValue(); - int nSwamp = ((Number) spnSwamp.getValue()).intValue(); - boolean useFullArt = ckbFullArtLands.isSelected(); - - addLands("Forest", nForest, useFullArt); - addLands("Island", nIsland, useFullArt); - addLands("Mountain", nMountain, useFullArt); - addLands("Plains", nPlains, useFullArt); - addLands("Swamp", nSwamp, useFullArt); - this.removeDialog(); - }//GEN-LAST:event_btnAddActionPerformed + private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed + onOK(); + }//GEN-LAST:event_btnOKActionPerformed private void btnAutoAddActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnAutoAddActionPerformed autoAddLands(); @@ -484,9 +493,9 @@ public class AddLandDialog extends MageDialog { } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton btnAdd; private javax.swing.JButton btnAutoAdd; private javax.swing.JButton btnCancel; + private javax.swing.JButton btnOK; private javax.swing.JButton btnSetFastSearch; private javax.swing.JComboBox cbLandSet; private javax.swing.JCheckBox ckbFullArtLands; diff --git a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.form b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.form index 9ee542fdf2..75d0c306ec 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.form @@ -5,7 +5,7 @@ - + @@ -21,31 +21,20 @@ +
- - - - - - - - - - - - - - - - - - + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java index 461db10be1..904624e640 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/CardInfoWindowDialog.java @@ -1,23 +1,5 @@ - - - /* - * CardInfoWindowDialog.java - * - * Created on Feb 1, 2010, 3:00:35 PM - */ package mage.client.dialog; -import java.awt.Dimension; -import java.awt.Point; -import java.beans.PropertyVetoException; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; -import javax.swing.ImageIcon; -import javax.swing.SwingUtilities; -import javax.swing.event.InternalFrameAdapter; -import javax.swing.event.InternalFrameEvent; - import mage.client.cards.BigCard; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; @@ -31,8 +13,17 @@ import mage.view.SimpleCardsView; import org.apache.log4j.Logger; import org.mage.plugins.card.utils.impl.ImageManagerImpl; +import javax.swing.*; +import javax.swing.event.InternalFrameAdapter; +import javax.swing.event.InternalFrameEvent; +import java.awt.*; +import java.beans.PropertyVetoException; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class CardInfoWindowDialog extends MageDialog { @@ -151,6 +142,7 @@ public class CardInfoWindowDialog extends MageDialog { return; } } + super.show(); if (positioned) { // check if in frame rectangle showAndPositionWindow(); @@ -201,23 +193,10 @@ public class CardInfoWindowDialog extends MageDialog { setIconifiable(true); setResizable(true); - setPreferredSize(new Dimension((int) Math.round(GUISizeHelper.otherZonesCardDimension.width * 1.3), - (int) Math.round(GUISizeHelper.otherZonesCardDimension.height * 1.2))); - - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); - getContentPane().setLayout(layout); - layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(cards, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(0, 0, 0)) - ); - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(cards, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(0, 0, 0)) - ); + setPreferredSize(new Dimension((int) Math.round(GUISizeHelper.otherZonesCardDimension.width * 1.4), + (int) Math.round(GUISizeHelper.otherZonesCardDimension.height * 1.4))); + getContentPane().setLayout(new java.awt.BorderLayout()); + getContentPane().add(cards, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form index 5b74e76cbf..1481b6aeb8 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.form @@ -3,9 +3,6 @@
- - - @@ -26,30 +23,21 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + - + + + + + + @@ -57,84 +45,77 @@ - + - - + + + + - - - - - - - - - - - - - - - - - - - - - + + + + - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + + + + + + + + + + + + + + + + + + + + + + + + - + - - - + + + + + + @@ -152,49 +133,27 @@ + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - + + @@ -205,10 +164,11 @@ + - + @@ -289,86 +249,23 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + + + + - - + + @@ -420,5 +317,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java index 120c35e2c0..1007492696 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ConnectDialog.java @@ -1,45 +1,10 @@ -/* - * ConnectDialog.java - * - * Created on 20-Jan-2010, 9:37:07 PM - */ package mage.client.dialog; -import java.awt.Cursor; -import java.awt.event.ActionListener; -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.InputStreamReader; -import java.io.Writer; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.URL; -import java.net.UnknownHostException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import javax.swing.DefaultComboBoxModel; -import javax.swing.JLayeredPane; -import javax.swing.JOptionPane; -import javax.swing.SwingWorker; +import mage.cards.repository.RepositoryUtil; import mage.choices.Choice; import mage.choices.ChoiceImpl; import mage.client.MageFrame; -import static mage.client.dialog.PreferencesDialog.KEY_CONNECTION_URL_SERVER_LIST; -import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_AUTO_CONNECT; -import static mage.client.dialog.PreferencesDialog.KEY_CONNECT_FLAG; +import mage.client.SessionHandler; import mage.client.preference.MagePreferences; import mage.client.util.Config; import mage.client.util.gui.countryBox.CountryItemEditor; @@ -48,6 +13,20 @@ import mage.remote.Connection; import mage.utils.StreamUtils; import org.apache.log4j.Logger; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionListener; +import java.io.*; +import java.net.*; +import java.util.List; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +import static mage.client.dialog.PreferencesDialog.*; + /** * @author BetaSteward_at_googlemail.com */ @@ -107,8 +86,11 @@ public class ConnectDialog extends MageDialog { MagePreferences.setServerAddress(serverAddress); MagePreferences.setServerPort(Integer.parseInt(txtPort.getText().trim())); MagePreferences.setUserName(serverAddress, txtUserName.getText().trim()); - MagePreferences.setPassword(serverAddress, txtPassword.getText().trim()); + MagePreferences.setPassword(serverAddress, String.valueOf(txtPassword.getPassword()).trim()); MageFrame.getPreferences().put(KEY_CONNECT_AUTO_CONNECT, Boolean.toString(chkAutoConnect.isSelected())); + + // last settings for reconnect + MagePreferences.saveLastServer(); } /** @@ -121,10 +103,6 @@ public class ConnectDialog extends MageDialog { private void initComponents() { lblServer = new javax.swing.JLabel(); - txtServer = new javax.swing.JTextField(); - btnFind = new javax.swing.JButton(); - lblPort = new javax.swing.JLabel(); - txtPort = new javax.swing.JTextField(); lblUserName = new javax.swing.JLabel(); txtUserName = new javax.swing.JTextField(); lblPassword = new javax.swing.JLabel(); @@ -138,47 +116,43 @@ public class ConnectDialog extends MageDialog { lblStatus = new javax.swing.JLabel(); btnRegister = new javax.swing.JButton(); btnForgotPassword = new javax.swing.JButton(); - btnFind1 = new javax.swing.JButton(); - btnFind2 = new javax.swing.JButton(); - btnFind3 = new javax.swing.JButton(); lblFastConnect = new javax.swing.JLabel(); panelFlag = new javax.swing.JPanel(); cbFlag = new mage.client.util.gui.countryBox.CountryComboBox(); filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(4, 0), new java.awt.Dimension(5, 32767)); btnFlagSearch = new javax.swing.JButton(); + panelFast = new javax.swing.JPanel(); + btnFindMain = new javax.swing.JButton(); + btnFindLocal = new javax.swing.JButton(); + btnFindBeta = new javax.swing.JButton(); + btnFindUs = new javax.swing.JButton(); + btnFindOther = new javax.swing.JButton(); + panelServer = new javax.swing.JPanel(); + txtServer = new javax.swing.JTextField(); + txtPort = new javax.swing.JTextField(); + lblPort = new javax.swing.JLabel(); + btnCheckStatus = new javax.swing.JButton(); + filler2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 50), new java.awt.Dimension(0, 50), new java.awt.Dimension(32767, 50)); + btnWhatsNew = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); setTitle("Connect to server"); - setNormalBounds(new java.awt.Rectangle(100, 100, 410, 307)); + lblServer.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblServer.setLabelFor(txtServer); - lblServer.setText("Server:"); - - btnFind.setText("Find..."); - btnFind.setToolTipText("Shows the list of public servers"); - btnFind.setName("findServerBtn"); // NOI18N - btnFind.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - findPublicServerActionPerformed(evt); - } - }); - - lblPort.setLabelFor(txtPort); - lblPort.setText("Port:"); - - txtPort.addKeyListener(new java.awt.event.KeyAdapter() { - public void keyTyped(java.awt.event.KeyEvent evt) { - ConnectDialog.this.keyTyped(evt); - } - }); + lblServer.setText("Server name:"); + lblUserName.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblUserName.setLabelFor(txtUserName); - lblUserName.setText("User name:"); + lblUserName.setText("Username:"); + lblPassword.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblPassword.setLabelFor(txtPassword); lblPassword.setText("Password:"); + lblFlag.setHorizontalAlignment(javax.swing.SwingConstants.RIGHT); lblFlag.setLabelFor(txtUserName); - lblFlag.setText("User flag:"); + lblFlag.setText("User's flag:"); chkAutoConnect.setText("Automatically connect to this server next time"); chkAutoConnect.setToolTipText("If active this connect dialog will not be shown if you choose to connect.
\nInstead XMage tries to connect to the last server you were connected to."); @@ -239,55 +213,12 @@ public class ConnectDialog extends MageDialog { } }); - btnFind1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/de.png"))); // NOI18N - btnFind1.setText("X"); - btnFind1.setToolTipText("Connect to xmage.de (Europe, most popular)"); - btnFind1.setActionCommand("connectXmageDe"); - btnFind1.setAlignmentY(0.0F); - btnFind1.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnFind1.setMaximumSize(new java.awt.Dimension(42, 23)); - btnFind1.setMinimumSize(new java.awt.Dimension(42, 23)); - btnFind1.setName("connectXmageDeBtn"); // NOI18N - btnFind1.setPreferredSize(new java.awt.Dimension(23, 23)); - btnFind1.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - connectXmageDe(evt); - } - }); - - btnFind2.setText("L"); - btnFind2.setToolTipText("Connect to localhost (local server)"); - btnFind2.setActionCommand("connectLocalhost"); - btnFind2.setAlignmentY(0.0F); - btnFind2.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - btnFind2.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnFind2.setName("connectLocalhostBtn"); // NOI18N - btnFind2.setPreferredSize(new java.awt.Dimension(23, 23)); - btnFind2.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - connectLocalhost(evt); - } - }); - - btnFind3.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N - btnFind3.setText("W"); - btnFind3.setToolTipText("Connect to vaporservermtg.com (USA)"); - btnFind3.setActionCommand("connectXmageus"); - btnFind3.setAlignmentY(0.0F); - btnFind3.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnFind3.setName("connectXmageusBtn"); // NOI18N - btnFind3.setPreferredSize(new java.awt.Dimension(23, 23)); - btnFind3.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - connectXmageus(evt); - } - }); - - lblFastConnect.setLabelFor(btnFind1); - lblFastConnect.setText("Fast connect to:"); + lblFastConnect.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); + lblFastConnect.setLabelFor(btnFindMain); + lblFastConnect.setText("Connect to:"); lblFastConnect.setName(""); // NOI18N - panelFlag.setPreferredSize(new java.awt.Dimension(189, 30)); + panelFlag.setMinimumSize(new java.awt.Dimension(50, 33)); panelFlag.setLayout(new javax.swing.BoxLayout(panelFlag, javax.swing.BoxLayout.LINE_AXIS)); cbFlag.setEditable(true); @@ -309,109 +240,250 @@ public class ConnectDialog extends MageDialog { }); panelFlag.add(btnFlagSearch); + btnFindMain.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/de.png"))); // NOI18N + btnFindMain.setText("X"); + btnFindMain.setToolTipText("Connect to xmage.de (Europe, most popular, registration needs)"); + btnFindMain.setActionCommand("connectXmageDe"); + btnFindMain.setAlignmentY(0.0F); + btnFindMain.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnFindMain.setMaximumSize(new java.awt.Dimension(42, 23)); + btnFindMain.setMinimumSize(new java.awt.Dimension(42, 23)); + btnFindMain.setName("connectXmageDeBtn"); // NOI18N + btnFindMain.setPreferredSize(new java.awt.Dimension(23, 23)); + btnFindMain.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + connectXmageDe(evt); + } + }); + + btnFindLocal.setText("LOCAL, AI"); + btnFindLocal.setToolTipText("Connect to localhost, AI enabled (run local server from launcher)"); + btnFindLocal.setActionCommand("connectLocalhost"); + btnFindLocal.setAlignmentY(0.0F); + btnFindLocal.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFindLocal.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnFindLocal.setName("connectLocalhostBtn"); // NOI18N + btnFindLocal.setPreferredSize(new java.awt.Dimension(23, 23)); + btnFindLocal.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + connectLocalhost(evt); + } + }); + + btnFindBeta.setText("BETA, AI"); + btnFindBeta.setToolTipText("Connect to BETA server, AI enabled (use any username without registration)"); + btnFindBeta.setAlignmentY(0.0F); + btnFindBeta.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFindBeta.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnFindBeta.setPreferredSize(new java.awt.Dimension(23, 23)); + btnFindBeta.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFindBetaconnectLocalhost(evt); + } + }); + + btnFindUs.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/us.png"))); // NOI18N + btnFindUs.setText("P"); + btnFindUs.setToolTipText("Connect to mtg.powersofwar.com (USA, use any username without registration)"); + btnFindUs.setActionCommand("connectXmageus"); + btnFindUs.setAlignmentY(0.0F); + btnFindUs.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnFindUs.setName("connectXmageusBtn"); // NOI18N + btnFindUs.setPreferredSize(new java.awt.Dimension(23, 23)); + btnFindUs.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + connectXmageus(evt); + } + }); + + btnFindOther.setText("Other servers..."); + btnFindOther.setToolTipText("Choose server from full servers list"); + btnFindOther.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFindOther.setName("findServerBtn"); // NOI18N + btnFindOther.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + findPublicServerActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelFastLayout = new javax.swing.GroupLayout(panelFast); + panelFast.setLayout(panelFastLayout); + panelFastLayout.setHorizontalGroup( + panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelFastLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 90, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnFindOther, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + panelFastLayout.setVerticalGroup( + panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelFastLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelFastLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnFindMain, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindLocal, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindUs, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindBeta, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnFindOther, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, 0)) + ); + + txtPort.addKeyListener(new java.awt.event.KeyAdapter() { + public void keyTyped(java.awt.event.KeyEvent evt) { + ConnectDialog.this.keyTyped(evt); + } + }); + + lblPort.setLabelFor(txtPort); + lblPort.setText("Port:"); + + btnCheckStatus.setIcon(new javax.swing.ImageIcon(getClass().getResource("/flags/world.png"))); // NOI18N + btnCheckStatus.setText("Check online status"); + btnCheckStatus.setToolTipText("Go to servers online statuses page"); + btnCheckStatus.setAlignmentY(0.0F); + btnCheckStatus.setMargin(new java.awt.Insets(2, 2, 2, 2)); + btnCheckStatus.setPreferredSize(new java.awt.Dimension(23, 23)); + btnCheckStatus.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCheckStatusActionPerformed(evt); + } + }); + + javax.swing.GroupLayout panelServerLayout = new javax.swing.GroupLayout(panelServer); + panelServer.setLayout(panelServerLayout); + panelServerLayout.setHorizontalGroup( + panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelServerLayout.createSequentialGroup() + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 212, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPort) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, 205, Short.MAX_VALUE) + .addGap(0, 0, 0)) + ); + panelServerLayout.setVerticalGroup( + panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelServerLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addGroup(panelServerLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPort) + .addComponent(btnCheckStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + ); + + btnWhatsNew.setText("Show what's new"); + btnWhatsNew.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnWhatsNewActionPerformed(evt); + } + }); + + jLabel1.setText("(use empty password for servers without registration)"); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(29, 29, 29) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblPort) - .addComponent(lblServer))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(lblFlag))) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblUserName) - .addComponent(lblPassword, javax.swing.GroupLayout.Alignment.TRAILING)))) - .addGap(0, 0, 0) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(jProxySettingsButton) - .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelFlag, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(txtServer, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtUserName, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtPassword, javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 71, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 11, Short.MAX_VALUE) - .addComponent(lblFastConnect) + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblUserName, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblStatus, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkForceUpdateDB, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(chkAutoConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(txtUserName) + .addComponent(panelFlag, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelServer, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(jProxySettingsButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnWhatsNew) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addComponent(txtPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel1))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFind1, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnFind2, javax.swing.GroupLayout.PREFERRED_SIZE, 40, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(0, 0, 0) - .addComponent(btnFind))) - .addContainerGap()) + .addComponent(filler2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblServer) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFind)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPort) - .addComponent(btnFind1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFind2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnFind3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblFastConnect)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblUserName)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPassword)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(chkAutoConnect) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(chkForceUpdateDB) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jProxySettingsButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(23, 23, 23)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelFast, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblFastConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblServer, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPassword) + .addComponent(jLabel1)) + .addComponent(lblPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addComponent(filler2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblFlag, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(chkAutoConnect) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkForceUpdateDB) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jProxySettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnWhatsNew, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(btnRegister, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnForgotPassword, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(btnConnect, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnCancel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(23, 23, 23)) ); + lblFastConnect.getAccessibleContext().setAccessibleName("Fast connect to:"); + pack(); }// //GEN-END:initComponents @@ -448,16 +520,15 @@ public class ConnectDialog extends MageDialog { char[] input = new char[0]; try { - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); connection = new Connection(); connection.setHost(this.txtServer.getText().trim()); connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); connection.setUsername(this.txtUserName.getText().trim()); - connection.setPassword(this.txtPassword.getText().trim()); - connection.setForceDBComparison(this.chkForceUpdateDB.isSelected()); + connection.setPassword(String.valueOf(this.txtPassword.getPassword()).trim()); + connection.setForceDBComparison(this.chkForceUpdateDB.isSelected() || RepositoryUtil.isDatabaseEmpty()); String allMAC = ""; try { - allMAC = connection.getMAC(); + allMAC = Connection.getMAC(); } catch (SocketException ex) { } connection.setUserIdStr(System.getProperty("user.name") + ":" + System.getProperty("os.name") + ":" + MagePreferences.getUserNames() + ":" + allMAC); @@ -476,17 +547,25 @@ public class ConnectDialog extends MageDialog { }//GEN-LAST:event_btnConnectActionPerformed + private void setConnectButtonsState(boolean enable) { + btnConnect.setEnabled(enable); + btnRegister.setEnabled(enable); + btnForgotPassword.setEnabled(enable); + } + private class ConnectTask extends SwingWorker { private boolean result = false; + private String lastConnectError = ""; private static final int CONNECTION_TIMEOUT_MS = 2100; @Override protected Boolean doInBackground() throws Exception { lblStatus.setText("Connecting..."); - btnConnect.setEnabled(false); + setConnectButtonsState(false); result = MageFrame.connect(connection); + lastConnectError = SessionHandler.getLastConnectError(); return result; } @@ -494,26 +573,25 @@ public class ConnectDialog extends MageDialog { protected void done() { try { get(CONNECTION_TIMEOUT_MS, TimeUnit.MILLISECONDS); - setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); if (result) { lblStatus.setText(""); connected(); MageFrame.getInstance().prepareAndShowTablesPane(); } else { - lblStatus.setText("Could not connect"); + lblStatus.setText("Could not connect: " + lastConnectError); } } catch (InterruptedException ex) { logger.fatal("Update Players Task error", ex); } catch (ExecutionException ex) { logger.fatal("Update Players Task error", ex); } catch (CancellationException ex) { - logger.info("Connect was canceled"); + logger.info("Connect: canceled"); lblStatus.setText("Connect was canceled"); } catch (TimeoutException ex) { logger.fatal("Connection timeout: ", ex); } finally { MageFrame.stopConnecting(); - btnConnect.setEnabled(true); + setConnectButtonsState(true); } } } @@ -673,8 +751,7 @@ public class ConnectDialog extends MageDialog { this.txtPort.setText("17171"); // Update userName and password according to the chosen server. this.txtUserName.setText(MagePreferences.getUserName(serverAddress)); - this.txtPassword.setText(MagePreferences.getPassword(serverAddress)); - + this.txtPassword.setText(MagePreferences.getPassword(serverAddress)); // TODO add your handling code here: }//GEN-LAST:event_btnFind1findPublicServerActionPerformed private void connectLocalhost(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFind2findPublicServerActionPerformed @@ -688,7 +765,16 @@ public class ConnectDialog extends MageDialog { }//GEN-LAST:event_btnFind2findPublicServerActionPerformed private void connectXmageus(java.awt.event.ActionEvent evt) { - String serverAddress = "vapormtgserver.com"; + String serverAddress = "mtg.powersofwar.com"; + this.txtServer.setText(serverAddress); + this.txtPort.setText("17171"); + // Update userName and password according to the chosen server. + this.txtUserName.setText(MagePreferences.getUserName(serverAddress)); + this.txtPassword.setText(MagePreferences.getPassword(serverAddress)); + } + + private void connectBeta(java.awt.event.ActionEvent evt) { + String serverAddress = "xmage.today"; this.txtServer.setText(serverAddress); this.txtPort.setText("17171"); // Update userName and password according to the chosen server. @@ -700,6 +786,24 @@ public class ConnectDialog extends MageDialog { doFastFlagSearch(); }//GEN-LAST:event_btnFlagSearchActionPerformed + private void btnFindBetaconnectLocalhost(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFindBetaconnectLocalhost + connectBeta(evt); + }//GEN-LAST:event_btnFindBetaconnectLocalhost + + private void btnCheckStatusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCheckStatusActionPerformed + if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { + try { + Desktop.getDesktop().browse(new URI("http://xmageservers.online/")); + } catch (Exception e) { + // + } + } + }//GEN-LAST:event_btnCheckStatusActionPerformed + + private void btnWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnWhatsNewActionPerformed + MageFrame.getInstance().showWhatsNewDialog(true); + }//GEN-LAST:event_btnWhatsNewActionPerformed + private void doFastFlagSearch() { Choice choice = new ChoiceImpl(false); @@ -745,18 +849,23 @@ public class ConnectDialog extends MageDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; + private javax.swing.JButton btnCheckStatus; private javax.swing.JButton btnConnect; - private javax.swing.JButton btnFind; - private javax.swing.JButton btnFind1; - private javax.swing.JButton btnFind2; - private javax.swing.JButton btnFind3; + private javax.swing.JButton btnFindBeta; + private javax.swing.JButton btnFindLocal; + private javax.swing.JButton btnFindMain; + private javax.swing.JButton btnFindOther; + private javax.swing.JButton btnFindUs; private javax.swing.JButton btnFlagSearch; private javax.swing.JButton btnForgotPassword; private javax.swing.JButton btnRegister; + private javax.swing.JButton btnWhatsNew; private mage.client.util.gui.countryBox.CountryComboBox cbFlag; private javax.swing.JCheckBox chkAutoConnect; private javax.swing.JCheckBox chkForceUpdateDB; private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler filler2; + private javax.swing.JLabel jLabel1; private javax.swing.JButton jProxySettingsButton; private javax.swing.JLabel lblFastConnect; private javax.swing.JLabel lblFlag; @@ -765,7 +874,9 @@ public class ConnectDialog extends MageDialog { private javax.swing.JLabel lblServer; private javax.swing.JLabel lblStatus; private javax.swing.JLabel lblUserName; + private javax.swing.JPanel panelFast; private javax.swing.JPanel panelFlag; + private javax.swing.JPanel panelServer; private javax.swing.JPasswordField txtPassword; private javax.swing.JTextField txtPort; private javax.swing.JTextField txtServer; diff --git a/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form new file mode 100644 index 0000000000..2ab6699220 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.form @@ -0,0 +1,560 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java new file mode 100644 index 0000000000..f6877c8eff --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/DownloadImagesDialog.java @@ -0,0 +1,470 @@ +package mage.client.dialog; + +import mage.client.MageFrame; +import mage.client.util.gui.FastSearchUtil; +import mage.client.util.gui.MageDialogState; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.HashMap; +import java.util.Map; + +/** + * @author JayDi85 + */ +public class DownloadImagesDialog extends MageDialog { + + public static final int RET_CANCEL = 0; + public static final int RET_OK = 1; + + private Dimension sizeModeMessageOnly; + private Dimension sizeModeMessageAndControls; + private Map actionsControlStates = new HashMap<>(); + + + /** + * Creates new form DownloadImagesDialog + */ + public DownloadImagesDialog() { + initComponents(); + this.setModal(true); + + // fix for panelInfo (it's resets aligmentX after netbeans designer opened) + panelInfo.setAlignmentX(CENTER_ALIGNMENT); + + // save default sizes + // + this.sizeModeMessageAndControls = new Dimension(580, 330); // dialog -> properties -> designer size + // + this.sizeModeMessageOnly = new Dimension(this.sizeModeMessageAndControls.getSize()); + sizeModeMessageOnly.height = 25 * 4; + sizeModeMessageOnly.width = sizeModeMessageOnly.width / 2; + + // Close the dialog when Esc is pressed + String cancelName = "cancel"; + InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); + ActionMap actionMap = getRootPane().getActionMap(); + actionMap.put(cancelName, new AbstractAction() { + public void actionPerformed(ActionEvent e) { + doClose(RET_CANCEL); + } + }); + } + + public void setWindowSize(int width, int heigth) { + this.setSize(new Dimension(width, heigth)); + } + + public void showDialog() { + showDialog(null); + } + + public void showDialog(MageDialogState mageDialogState) { + + // window settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + if (mageDialogState != null) mageDialogState.setStateToDialog(this); + else this.makeWindowCentered(); + + showDownloadControls(false); // call to change window size + + this.setVisible(true); + } + + public void setGlobalInfo(String info) { + this.labelGlobal.setText(info); + } + + public void setCurrentInfo(String info) { + this.labelInfo.setText(info); + } + + public JComboBox getSourcesCombo() { + return this.comboSource; + } + + public JComboBox getLaunguagesCombo() { + return this.comboLanguage; + } + + public JComboBox getSetsCombo() { + return this.comboSets; + } + + public JButton getStartButton() { + return this.buttonOK; + } + + public JButton getCancelButton() { + return this.buttonCancel; + } + + public JButton getStopButton() { + return this.buttonStop; + } + + public JProgressBar getProgressBar() { + return this.progress; + } + + public JCheckBox getRedownloadCheckbox() { + return this.checkboxRedownload; + } + + public void showLanguagesSupport(boolean haveSupport) { + labelLanguage.setEnabled(haveSupport); + comboLanguage.setEnabled(haveSupport); + } + + private void enableActionControl(boolean enable, Component comp) { + if (enable) { + // restore last enable state + comp.setEnabled(actionsControlStates.getOrDefault(comp, true)); + } else { + // save enable state and disable it + actionsControlStates.putIfAbsent(comp, comp.isEnabled()); + comp.setEnabled(false); + } + } + + public void enableActionControls(boolean enable) { + // restrict user actions while downloading/processing (all buttons, comboboxes and edits) + enableActionControl(enable, tabsList); + enableActionControl(enable, comboSource); + enableActionControl(enable, comboSets); + enableActionControl(enable, buttonSearchSet); + enableActionControl(enable, comboLanguage); + enableActionControl(enable, checkboxRedownload); + } + + private void setTabTitle(int tabIndex, String title, String iconResourceName) { + // tab caption with left sided icon + // https://stackoverflow.com/questions/1782224/jtabbedpane-icon-on-left-side-of-tabs + JLabel lbl = new JLabel(title); + Icon icon = new ImageIcon(getClass().getResource(iconResourceName)); + lbl.setIcon(icon); + lbl.setIconTextGap(5); + lbl.setHorizontalTextPosition(SwingConstants.RIGHT); + tabsList.setTabComponentAt(tabIndex, lbl); + } + + public void showDownloadControls(boolean needToShow) { + // 2 modes: + // - only message; + // - message + download controls and buttons + this.panelGlobal.setVisible(true); + this.buttonStop.setVisible(!needToShow); // stop button only for loading mode + this.tabsList.setVisible(needToShow); + this.panelCommands.setVisible(needToShow); + + // auto-size form + if (needToShow) { + this.setWindowSize(this.sizeModeMessageAndControls.width, this.sizeModeMessageAndControls.height); + } else { + this.setWindowSize(this.sizeModeMessageOnly.width, this.sizeModeMessageOnly.height); + } + this.makeWindowCentered(); + //this.setLocationRelativeTo(null); // center screen //FIX + + // icons on tabs left side + setTabTitle(0, "Standard download", "/buttons/card_panel.png"); + setTabTitle(1, "Custom download", "/buttons/list_panel.png"); + + // TODO: add manual mode as tab + this.tabsList.getTabComponentAt(1).setEnabled(false); + this.tabsList.setEnabledAt(1, false); + } + + /** + * @return the return status of this dialog - one of RET_OK or RET_CANCEL + */ + public int getReturnStatus() { + return returnStatus; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + panelGlobal = new javax.swing.JPanel(); + fillerGlobal1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + labelGlobal = new javax.swing.JLabel(); + buttonStop = new javax.swing.JButton(); + fillerglobal2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + tabsList = new javax.swing.JTabbedPane(); + tabMain = new javax.swing.JPanel(); + panelInfo = new javax.swing.JPanel(); + fillerInfo1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + labelInfo = new javax.swing.JLabel(); + fillerInfo2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 5), new java.awt.Dimension(32767, 5)); + panelSource = new javax.swing.JPanel(); + panelSourceLeft = new javax.swing.JPanel(); + labelSource = new javax.swing.JLabel(); + comboSource = new javax.swing.JComboBox<>(); + panelSourceRight = new javax.swing.JPanel(); + labelLanguage = new javax.swing.JLabel(); + comboLanguage = new javax.swing.JComboBox<>(); + panelMode = new javax.swing.JPanel(); + panelModeInner = new javax.swing.JPanel(); + labelMode = new javax.swing.JLabel(); + panelModeSelect = new javax.swing.JPanel(); + comboSets = new javax.swing.JComboBox<>(); + fillerMode1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + buttonSearchSet = new javax.swing.JButton(); + panelRedownload = new javax.swing.JPanel(); + checkboxRedownload = new javax.swing.JCheckBox(); + filler1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 5), new java.awt.Dimension(0, 3), new java.awt.Dimension(32767, 5)); + fillerMain1 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 10), new java.awt.Dimension(0, 10), new java.awt.Dimension(32767, 10)); + panelProgress = new javax.swing.JPanel(); + fillerProgress1 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + progress = new javax.swing.JProgressBar(); + fillerProgress2 = new javax.swing.Box.Filler(new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 0), new java.awt.Dimension(5, 32767)); + fillerMain2 = new javax.swing.Box.Filler(new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(32767, 32767)); + tabCustom = new javax.swing.JPanel(); + panelCommands = new javax.swing.JPanel(); + buttonOK = new javax.swing.JButton(); + buttonCancel = new javax.swing.JButton(); + + setTitle("Downloading images"); + setPreferredSize(new java.awt.Dimension(600, 400)); + getContentPane().setLayout(new java.awt.BorderLayout()); + + panelGlobal.setLayout(new javax.swing.BoxLayout(panelGlobal, javax.swing.BoxLayout.Y_AXIS)); + panelGlobal.add(fillerGlobal1); + + labelGlobal.setText("Initializing image download..."); + labelGlobal.setAlignmentX(0.5F); + panelGlobal.add(labelGlobal); + + buttonStop.setText("Cancel"); + buttonStop.setAlignmentX(0.5F); + buttonStop.setPreferredSize(new java.awt.Dimension(65, 30)); + buttonStop.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonStopActionPerformed(evt); + } + }); + panelGlobal.add(buttonStop); + panelGlobal.add(fillerglobal2); + + getContentPane().add(panelGlobal, java.awt.BorderLayout.NORTH); + + tabsList.setTabLayoutPolicy(javax.swing.JTabbedPane.SCROLL_TAB_LAYOUT); + + tabMain.setLayout(new javax.swing.BoxLayout(tabMain, javax.swing.BoxLayout.Y_AXIS)); + + panelInfo.setLayout(new javax.swing.BoxLayout(panelInfo, javax.swing.BoxLayout.Y_AXIS)); + panelInfo.add(fillerInfo1); + + labelInfo.setText("Missing stats: 12345 card images / 789 token images"); + labelInfo.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 7, 0, 0)); + panelInfo.add(labelInfo); + panelInfo.add(fillerInfo2); + + tabMain.add(panelInfo); + + panelSource.setMaximumSize(new java.awt.Dimension(65536, 55)); + panelSource.setMinimumSize(new java.awt.Dimension(352, 55)); + panelSource.setPreferredSize(new java.awt.Dimension(593, 55)); + panelSource.setLayout(new javax.swing.BoxLayout(panelSource, javax.swing.BoxLayout.X_AXIS)); + + panelSourceLeft.setMinimumSize(new java.awt.Dimension(430, 30)); + panelSourceLeft.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + + labelSource.setText("Images source to download:"); + panelSourceLeft.add(labelSource); + + comboSource.setMaximumRowCount(15); + comboSource.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + comboSource.setMinimumSize(new java.awt.Dimension(300, 20)); + comboSource.setPreferredSize(new java.awt.Dimension(400, 25)); + panelSourceLeft.add(comboSource); + + panelSource.add(panelSourceLeft); + + panelSourceRight.setAlignmentX(0.0F); + panelSourceRight.setMaximumSize(new java.awt.Dimension(130, 32767)); + panelSourceRight.setMinimumSize(new java.awt.Dimension(130, 30)); + panelSourceRight.setPreferredSize(new java.awt.Dimension(130, 100)); + panelSourceRight.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEADING)); + + labelLanguage.setText("Language:"); + panelSourceRight.add(labelLanguage); + + comboLanguage.setMaximumRowCount(15); + comboLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + comboLanguage.setPreferredSize(new java.awt.Dimension(90, 25)); + panelSourceRight.add(comboLanguage); + + panelSource.add(panelSourceRight); + + tabMain.add(panelSource); + + panelMode.setMaximumSize(new java.awt.Dimension(32869, 55)); + panelMode.setMinimumSize(new java.awt.Dimension(322, 55)); + panelMode.setPreferredSize(new java.awt.Dimension(100, 55)); + panelMode.setLayout(new javax.swing.BoxLayout(panelMode, javax.swing.BoxLayout.LINE_AXIS)); + + panelModeInner.setMinimumSize(new java.awt.Dimension(430, 43)); + panelModeInner.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); + + labelMode.setText("Sets to download:"); + labelMode.setAlignmentY(0.0F); + panelModeInner.add(labelMode); + + panelModeSelect.setLayout(new javax.swing.BoxLayout(panelModeSelect, javax.swing.BoxLayout.X_AXIS)); + + comboSets.setMaximumRowCount(15); + comboSets.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); + comboSets.setPreferredSize(new java.awt.Dimension(373, 25)); + panelModeSelect.add(comboSets); + panelModeSelect.add(fillerMode1); + + buttonSearchSet.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/search_24.png"))); // NOI18N + buttonSearchSet.setToolTipText("Fast search your flag"); + buttonSearchSet.setAlignmentX(1.0F); + buttonSearchSet.setPreferredSize(new java.awt.Dimension(25, 25)); + buttonSearchSet.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonSearchSetActionPerformed(evt); + } + }); + panelModeSelect.add(buttonSearchSet); + + panelModeInner.add(panelModeSelect); + + panelMode.add(panelModeInner); + + panelRedownload.setAlignmentX(0.0F); + panelRedownload.setMaximumSize(new java.awt.Dimension(130, 32767)); + panelRedownload.setMinimumSize(new java.awt.Dimension(130, 30)); + panelRedownload.setPreferredSize(new java.awt.Dimension(130, 100)); + panelRedownload.setLayout(new java.awt.BorderLayout()); + + checkboxRedownload.setText("Re-download selected images"); + checkboxRedownload.setVerticalAlignment(javax.swing.SwingConstants.BOTTOM); + panelRedownload.add(checkboxRedownload, java.awt.BorderLayout.CENTER); + panelRedownload.add(filler1, java.awt.BorderLayout.PAGE_END); + + panelMode.add(panelRedownload); + + tabMain.add(panelMode); + tabMain.add(fillerMain1); + + panelProgress.setMaximumSize(new java.awt.Dimension(32777, 30)); + panelProgress.setMinimumSize(new java.awt.Dimension(20, 30)); + panelProgress.setPreferredSize(new java.awt.Dimension(564, 30)); + panelProgress.setLayout(new javax.swing.BoxLayout(panelProgress, javax.swing.BoxLayout.X_AXIS)); + panelProgress.add(fillerProgress1); + + progress.setValue(75); + progress.setMaximumSize(new java.awt.Dimension(32767, 25)); + progress.setString("123 of 12313 (120 cards/546 tokens) image downloads finished! Please wait! [123 Mb]"); + progress.setStringPainted(true); + panelProgress.add(progress); + panelProgress.add(fillerProgress2); + + tabMain.add(panelProgress); + tabMain.add(fillerMain2); + + tabsList.addTab("Standard download", new javax.swing.ImageIcon(getClass().getResource("/buttons/card_panel.png")), tabMain); // NOI18N + + tabCustom.setLayout(new javax.swing.BoxLayout(tabCustom, javax.swing.BoxLayout.Y_AXIS)); + tabsList.addTab("Custom download", new javax.swing.ImageIcon(getClass().getResource("/buttons/list_panel.png")), tabCustom); // NOI18N + + getContentPane().add(tabsList, java.awt.BorderLayout.CENTER); + + panelCommands.setAlignmentX(0.0F); + panelCommands.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.TRAILING)); + + buttonOK.setText("Start download"); + buttonOK.setPreferredSize(new java.awt.Dimension(120, 30)); + panelCommands.add(buttonOK); + getRootPane().setDefaultButton(buttonOK); + + buttonCancel.setText("Cancel"); + buttonCancel.setPreferredSize(new java.awt.Dimension(80, 30)); + panelCommands.add(buttonCancel); + + getContentPane().add(panelCommands, java.awt.BorderLayout.SOUTH); + + pack(); + }// //GEN-END:initComponents + + /** + * Closes the dialog + */ + private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + doClose(RET_CANCEL); + }//GEN-LAST:event_closeDialog + + private void buttonSearchSetActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonSearchSetActionPerformed + FastSearchUtil.showFastSearchForStringComboBox(comboSets, FastSearchUtil.DEFAULT_EXPANSION_SEARCH_MESSAGE, 400, 500); + }//GEN-LAST:event_buttonSearchSetActionPerformed + + private void buttonStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonStopActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_buttonStopActionPerformed + + private void doClose(int retStatus) { + returnStatus = retStatus; + setVisible(false); + dispose(); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonOK; + private javax.swing.JButton buttonSearchSet; + private javax.swing.JButton buttonStop; + private javax.swing.JCheckBox checkboxRedownload; + private javax.swing.JComboBox comboLanguage; + private javax.swing.JComboBox comboSets; + private javax.swing.JComboBox comboSource; + private javax.swing.Box.Filler filler1; + private javax.swing.Box.Filler fillerGlobal1; + private javax.swing.Box.Filler fillerInfo1; + private javax.swing.Box.Filler fillerInfo2; + private javax.swing.Box.Filler fillerMain1; + private javax.swing.Box.Filler fillerMain2; + private javax.swing.Box.Filler fillerMode1; + private javax.swing.Box.Filler fillerProgress1; + private javax.swing.Box.Filler fillerProgress2; + private javax.swing.Box.Filler fillerglobal2; + private javax.swing.JLabel labelGlobal; + private javax.swing.JLabel labelInfo; + private javax.swing.JLabel labelLanguage; + private javax.swing.JLabel labelMode; + private javax.swing.JLabel labelSource; + private javax.swing.JPanel panelCommands; + private javax.swing.JPanel panelGlobal; + private javax.swing.JPanel panelInfo; + private javax.swing.JPanel panelMode; + private javax.swing.JPanel panelModeInner; + private javax.swing.JPanel panelModeSelect; + private javax.swing.JPanel panelProgress; + private javax.swing.JPanel panelRedownload; + private javax.swing.JPanel panelSource; + private javax.swing.JPanel panelSourceLeft; + private javax.swing.JPanel panelSourceRight; + private javax.swing.JProgressBar progress; + private javax.swing.JPanel tabCustom; + private javax.swing.JPanel tabMain; + private javax.swing.JTabbedPane tabsList; + // End of variables declaration//GEN-END:variables + + private int returnStatus = RET_CANCEL; +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java index a16a7bbccd..5d4e19e764 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/JoinTableDialog.java @@ -1,7 +1,7 @@ package mage.client.dialog; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.players.PlayerType; @@ -119,9 +119,9 @@ public class JoinTableDialog extends MageDialog { try { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD_JOIN, txtPassword.getText()); if (isTournament) { - joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText()); + joined = session.joinTournamentTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText()); } else { - joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText()); + joined = session.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), this.txtPassword.getText()); } } catch (Exception ex) { diff --git a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java index 513f4ede22..5abf39fff2 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/MageDialog.java @@ -1,32 +1,20 @@ - - - /* - * MageDialog.java - * - * Created on 15-Dec-2009, 10:28:27 PM - */ package mage.client.dialog; -import java.awt.AWTEvent; -import java.awt.ActiveEvent; -import java.awt.Component; -import java.awt.EventQueue; -import java.awt.KeyboardFocusManager; -import java.awt.MenuComponent; -import java.awt.TrayIcon; +import mage.client.MageFrame; +import mage.client.util.SettingsManager; +import mage.client.util.gui.GuiDisplayUtil; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; import java.awt.event.InvocationEvent; import java.awt.event.MouseEvent; import java.beans.PropertyVetoException; import java.lang.reflect.InvocationTargetException; import java.util.logging.Level; -import javax.swing.*; - -import mage.client.MageFrame; -import org.apache.log4j.Logger; /** - * - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class MageDialog extends javax.swing.JInternalFrame { @@ -45,6 +33,34 @@ public class MageDialog extends javax.swing.JInternalFrame { } + public static boolean isModalDialogActivated() { + for (JInternalFrame frame : MageFrame.getDesktop().getAllFrames()) { + if (frame instanceof MageDialog) { + MageDialog md = (MageDialog) frame; + if (md.isVisible() && md.isModal()) { + return true; + } + } + } + return false; + } + + public static void printFramesOrder(String name) { + ///* + JInternalFrame[] frames = MageFrame.getDesktop().getAllFrames(); + System.out.println("--- " + name + " ---"); + int order = 0; + for (JInternalFrame frame : frames) { + order++; + int zorder = -1; + if (frame.getParent() != null) { + zorder = frame.getParent().getComponentZOrder(frame); + } + System.out.println(order + ". " + frame.getClass() + " (" + frame.getTitle() + ") : layer = " + frame.getLayer() + ", zorder = " + zorder); + } + //*/ + } + @Override public void show() { super.show(); @@ -57,17 +73,6 @@ public class MageDialog extends javax.swing.JInternalFrame { // - JLayeredPane.MODAL_LAYER: all modal dialogs (user required actions - select cards in game, new game window, error windows) // - JLayeredPane.POPUP_LAYER: hints and other top level graphics // - JLayeredPane.DRAG_LAYER: top most layer for critical actions and user controls - /* - JInternalFrame[] frames = MageFrame.getDesktop().getAllFrames(); - System.out.println("---"); - for(JInternalFrame frame: frames){ - int zorder = -1; - if (frame.getParent() != null){ - frame.getParent().getComponentZOrder(frame); - } - System.out.println(frame.getClass() + " (" + frame.getTitle() + ") : layer = " + frame.getLayer() + ", zorder = " + zorder); - } - */ if (modal) { this.setClosable(false); @@ -75,7 +80,7 @@ public class MageDialog extends javax.swing.JInternalFrame { this.toFront(); - if (modal){ + if (modal) { startModal(); } } @@ -83,9 +88,16 @@ public class MageDialog extends javax.swing.JInternalFrame { @Override public void setVisible(boolean value) { super.setVisible(value); + if (value) { this.toFront(); + try { + this.setSelected(true); + } catch (PropertyVetoException e) { + // + } } + if (modal) { this.setClosable(false); if (value) { @@ -97,6 +109,7 @@ public class MageDialog extends javax.swing.JInternalFrame { SwingUtilities.invokeAndWait(() -> stopModal()); } catch (InterruptedException ex) { LOGGER.fatal("MageDialog error", ex); + Thread.currentThread().interrupt(); } catch (InvocationTargetException ex) { LOGGER.fatal("MageDialog error", ex); } @@ -105,6 +118,7 @@ public class MageDialog extends javax.swing.JInternalFrame { } private synchronized void startModal() { + // modal loop -- all mouse events must be ignored by other windows try { if (SwingUtilities.isEventDispatchThread()) { EventQueue theQueue = getToolkit().getSystemEventQueue(); @@ -115,18 +129,47 @@ public class MageDialog extends javax.swing.JInternalFrame { // https://github.com/magefree/mage/issues/584 - Let's hope this will fix the Linux window problem if (event.getSource() != null && event.getSource() instanceof TrayIcon && !(event instanceof InvocationEvent)) { - return; + dispatch = false; + //return; // JayDi85: users can move mouse over try icon to disable modal mode (it's a bug but can be used in the future) } + + // ignore mouse events outside from panel, only drag and move allowed -- as example: + // combobox's popup will be selectable outside + // cards and button hints will be works + Component popupComponent = null; + MouseEvent popupEvent = null; if (event instanceof MouseEvent && event.getSource() instanceof Component) { MouseEvent e = (MouseEvent) event; MouseEvent m = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, this); - if (!this.contains(m.getPoint()) && e.getID() != MouseEvent.MOUSE_DRAGGED) { - dispatch = false; + + // disable all outer events (except some actions) + if (!this.contains(m.getPoint())) { + boolean allowedEvent = false; + + // need any mouse move (for hints) + if (e.getID() == MouseEvent.MOUSE_DRAGGED || e.getID() == MouseEvent.MOUSE_MOVED) { + allowedEvent = true; + } + + // need popup clicks and mouse wheel (for out of bound actions) + if (!allowedEvent) { + popupComponent = SwingUtilities.getDeepestComponentAt(e.getComponent(), e.getX(), e.getY()); // show root component (popups creates at root) + if (popupComponent != null && (popupComponent.getClass().getName().contains("BasicComboPopup") + || popupComponent.getClass().getName().contains("JMenuItem"))) { + popupEvent = SwingUtilities.convertMouseEvent((Component) e.getSource(), e, popupComponent); + allowedEvent = true; + } + } + + dispatch = allowedEvent; } } if (dispatch) { - if (event instanceof ActiveEvent) { + if (popupEvent != null) { + // process outer popup events, it's must be FIRST check + popupComponent.dispatchEvent(popupEvent); + } else if (event instanceof ActiveEvent) { ((ActiveEvent) event).dispatch(); } else if (source instanceof Component) { ((Component) source).dispatchEvent(event); @@ -142,9 +185,10 @@ public class MageDialog extends javax.swing.JInternalFrame { wait(); } } - } catch (InterruptedException ignored) { + } catch (InterruptedException e) { + LOGGER.fatal("MageDialog error", e); + Thread.currentThread().interrupt(); } - } private synchronized void stopModal() { @@ -174,14 +218,21 @@ public class MageDialog extends javax.swing.JInternalFrame { java.util.logging.Logger.getLogger(MageDialog.class.getName()).log(Level.SEVERE, "setClosed(false) failed", ex); } MageFrame.getDesktop().remove(this); + } + public void makeWindowCentered() { + makeWindowCentered(this, this.getWidth(), this.getHeight()); + } + + public static void makeWindowCentered(Component component, int width, int height) { + Point centered = SettingsManager.instance.getComponentPosition(width, height); + component.setLocation(centered.x, centered.y); + GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, component); } /** * Used to set a tooltip text on icon and titel bar * - * used in {@link ExileZoneDialog} and {@link ShowCardsDialog} - * * @param text */ public void setTitelBarToolTip(final String text) { @@ -209,12 +260,12 @@ public class MageDialog extends javax.swing.JInternalFrame { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 394, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 394, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 274, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGap(0, 274, Short.MAX_VALUE) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form index b712fbe518..9cd42978e4 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.form @@ -1,6 +1,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -25,104 +98,123 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -131,66 +223,80 @@ - - - - - - - - - - + + + + + + + + + + + + + - + + + + - - - - - - - - - - - - - + + + + + - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - - - + + - + @@ -199,21 +305,24 @@ - - + + - - + + + + + - + - + @@ -233,17 +342,13 @@ - + - - - - @@ -271,12 +376,15 @@ - + + + + @@ -289,11 +397,10 @@ - + - @@ -301,7 +408,7 @@ - + @@ -314,7 +421,7 @@ - + @@ -330,7 +437,7 @@ - + @@ -346,7 +453,8 @@ - + + @@ -362,14 +470,11 @@ - + - - - @@ -404,7 +509,7 @@ - + @@ -427,10 +532,76 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java index 0e3121f61d..f433f0c0cb 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTableDialog.java @@ -1,13 +1,6 @@ - package mage.client.dialog; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import javax.swing.*; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.components.MageComponents; @@ -20,13 +13,21 @@ import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.constants.SkillLevel; import mage.game.match.MatchOptions; +import mage.game.mulligan.MulliganType; import mage.players.PlayerType; import mage.view.GameTypeView; import mage.view.TableView; import org.apache.log4j.Logger; +import javax.swing.*; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class NewTableDialog extends MageDialog { @@ -51,6 +52,7 @@ public class NewTableDialog extends MageDialog { this.spnNumWins.setModel(new SpinnerNumberModel(1, 1, 5, 1)); this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1)); this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5)); + this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); this.spnEdhPowerLevel.setModel(new SpinnerNumberModel(100, 0, 100, 5)); MageFrame.getUI().addButton(MageComponents.NEW_TABLE_OK_BUTTON, btnOK); } @@ -64,6 +66,16 @@ public class NewTableDialog extends MageDialog { // //GEN-BEGIN:initComponents private void initComponents() { + popupSaveSettings = new javax.swing.JPopupMenu(); + menuSaveSettings1 = new javax.swing.JMenuItem(); + menuSaveSettings2 = new javax.swing.JMenuItem(); + popupLoadSettings = new javax.swing.JPopupMenu(); + menuLoadSettingsLast = new javax.swing.JMenuItem(); + separator1 = new javax.swing.JPopupMenu.Separator(); + menuLoadSettings1 = new javax.swing.JMenuItem(); + menuLoadSettings2 = new javax.swing.JMenuItem(); + separator2 = new javax.swing.JPopupMenu.Separator(); + menuLoadSettingsDefault = new javax.swing.JMenuItem(); lblName = new javax.swing.JLabel(); txtName = new javax.swing.JTextField(); lblPassword = new javax.swing.JLabel(); @@ -75,10 +87,9 @@ public class NewTableDialog extends MageDialog { lblGameType = new javax.swing.JLabel(); cbGameType = new javax.swing.JComboBox(); chkRollbackTurnsAllowed = new javax.swing.JCheckBox(); + lblFreeMulligans = new javax.swing.JLabel(); chkSpectatorsAllowed = new javax.swing.JCheckBox(); chkPlaneChase = new javax.swing.JCheckBox(); - chkRated = new javax.swing.JCheckBox(); - lblFreeMulligans = new javax.swing.JLabel(); spnFreeMulligans = new javax.swing.JSpinner(); lblNumPlayers = new javax.swing.JLabel(); spnNumPlayers = new javax.swing.JSpinner(); @@ -98,72 +109,136 @@ public class NewTableDialog extends MageDialog { pnlOtherPlayers = new javax.swing.JPanel(); jSeparator1 = new javax.swing.JSeparator(); btnOK = new javax.swing.JButton(); - btnPreviousConfiguration1 = new javax.swing.JButton(); - btnPreviousConfiguration2 = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); lblQuitRatio = new javax.swing.JLabel(); - lblEdhPowerLevel = new javax.swing.JLabel(); spnQuitRatio = new javax.swing.JSpinner(); + lblEdhPowerLevel = new javax.swing.JLabel(); spnEdhPowerLevel = new javax.swing.JSpinner(); + cbMulligan = new javax.swing.JComboBox<>(); + lblMullgian = new javax.swing.JLabel(); + lblMinimumRating = new javax.swing.JLabel(); + spnMinimumRating = new javax.swing.JSpinner(); + chkRated = new javax.swing.JCheckBox(); + btnSettingsLoad = new javax.swing.JButton(); + btnSettingsSave = new javax.swing.JButton(); + lblSettings = new javax.swing.JLabel(); + + menuSaveSettings1.setText("Save to config 1"); + menuSaveSettings1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuSaveSettings1ActionPerformed(evt); + } + }); + popupSaveSettings.add(menuSaveSettings1); + + menuSaveSettings2.setText("Save to config 2"); + menuSaveSettings2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuSaveSettings2ActionPerformed(evt); + } + }); + popupSaveSettings.add(menuSaveSettings2); + + menuLoadSettingsLast.setText("Load from last time"); + menuLoadSettingsLast.setToolTipText(""); + menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettingsLastActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettingsLast); + popupLoadSettings.add(separator1); + + menuLoadSettings1.setText("Load from config 1"); + menuLoadSettings1.setToolTipText(""); + menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettings1ActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettings1); + + menuLoadSettings2.setText("Load from config 2"); + menuLoadSettings2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettings2ActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettings2); + popupLoadSettings.add(separator2); + + menuLoadSettingsDefault.setText("Load default settings"); + menuLoadSettingsDefault.setToolTipText(""); + menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettingsDefaultActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettingsDefault); setTitle("New Table"); lblName.setLabelFor(txtName); lblName.setText("Name:"); - lblPassword.setLabelFor(txtName); + lblPassword.setLabelFor(txtPassword); lblPassword.setText("Password:"); lbDeckType.setText("Deck Type:"); lbTimeLimit.setText("Time Limit:"); - lbTimeLimit.setToolTipText("The active time a player may use to finish the match. If their time runs out, the player looses the current game."); + lbTimeLimit.setToolTipText("The active time a player may use to finish the match. If his or her time runs out, the player looses the current game."); lblGameType.setText("Game Type:"); - cbGameType.addActionListener(evt -> cbGameTypeActionPerformed(evt)); + cbGameType.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbGameTypeActionPerformed(evt); + } + }); - chkRollbackTurnsAllowed.setText("Allow rollbacks"); + chkRollbackTurnsAllowed.setText("Rollbacks"); chkRollbackTurnsAllowed.setToolTipText("Allow to rollback to the start of previous turns
\nif all players agree.\n"); - chkSpectatorsAllowed.setText("Allow Spectators"); - chkSpectatorsAllowed.setToolTipText("Allow spectators to watch.\n"); - - chkPlaneChase.setText("Use PlaneChase"); - chkPlaneChase.setToolTipText("Use planechase variant (suitable for all game types).\n"); - - chkRated.setText("Rated"); - chkRated.setToolTipText("Indicates if matches will be rated."); - + lblFreeMulligans.setLabelFor(spnFreeMulligans); lblFreeMulligans.setText("Free Mulligans:"); lblFreeMulligans.setToolTipText("The number of mulligans a player can use without decreasing the number of drawn cards."); - lblNumPlayers.setLabelFor(spnNumPlayers); - lblNumPlayers.setText("Players"); + chkSpectatorsAllowed.setText("Spectators allowed"); + chkSpectatorsAllowed.setToolTipText("Allow spectators to view your game."); - spnNumPlayers.addChangeListener(evt -> numPlayersChanged(evt)); + chkPlaneChase.setText("PlaneChase"); + chkPlaneChase.setToolTipText("Use the PlaneChase variant for your game."); + + lblNumPlayers.setLabelFor(spnNumPlayers); + lblNumPlayers.setText("Players:"); + + spnNumPlayers.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + numPlayersChanged(evt); + } + }); lblRange.setLabelFor(cbRange); - lblRange.setText("Range of Influence"); + lblRange.setText("Range of Influence:"); cbRange.setToolTipText("An option for multiplayer games.\nA player's range of influence is the maximum distance from that player, measured in player seats,
\nthat the player can affect. Players within that many seats of the player are within that player's range
\nof influence. Objects controlled by players within a player's range of influence are also within that
\nplayer's range of influence. Range of influence covers spells, abilities, effects, damage dealing, attacking,\nmaking choices, and winning the game."); lblAttack.setLabelFor(cbAttackOption); - lblAttack.setText("Attack Option"); + lblAttack.setText("Attack Option:"); cbAttackOption.setToolTipText("An option for multiplayer games that defines
\nwhich opponents can be attacked from a player."); lblSkillLevel.setLabelFor(cbAttackOption); - lblSkillLevel.setText("Skill Level"); + lblSkillLevel.setText("Skill Level:"); + lblSkillLevel.setToolTipText(""); cbSkillLevel.setToolTipText("This option can be used to make it easier to find matches
\nwith opponents of the appropriate skill level."); lblNumWins.setLabelFor(spnNumWins); - lblNumWins.setText("Wins"); + lblNumWins.setText("Wins:"); lblNumWins.setToolTipText("How many games has a player to win to win the match."); - spnNumWins.addChangeListener(evt -> spnNumWinsnumPlayersChanged(evt)); - jLabel1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N jLabel1.setText("Player 1 (You)"); @@ -172,24 +247,54 @@ public class NewTableDialog extends MageDialog { pnlOtherPlayers.setLayout(new java.awt.GridLayout(0, 1)); - btnOK.setText("OK"); - btnOK.addActionListener(evt -> btnOKActionPerformed(evt)); - - btnPreviousConfiguration1.setText("M1"); - btnPreviousConfiguration1.setToolTipText("Load saved Match configuration #1"); - btnPreviousConfiguration1.addActionListener(evt -> btnPreviousConfigurationActionPerformed(evt, 1)); - btnPreviousConfiguration2.setText("M2"); - btnPreviousConfiguration2.setToolTipText("Load saved Match configuration #2"); - btnPreviousConfiguration2.addActionListener(evt -> btnPreviousConfigurationActionPerformed(evt, 2)); + btnOK.setText("Create"); + btnOK.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOKActionPerformed(evt); + } + }); btnCancel.setText("Cancel"); - btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt)); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); lblQuitRatio.setText("Allowed quit %"); - lblEdhPowerLevel.setText("EDH power level"); - spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table"); - spnEdhPowerLevel.setToolTipText("Players with decks with a higher power level can't join this table"); + lblEdhPowerLevel.setText("EDH power level:"); + + cbMulligan.setToolTipText("Selections the type of mulligan for games."); + + lblMullgian.setLabelFor(cbMulligan); + lblMullgian.setText("Mulligan type:"); + lblMullgian.setToolTipText("What style of mulligan?"); + + lblMinimumRating.setLabelFor(spnMinimumRating); + lblMinimumRating.setText("Minimum rating:"); + lblMinimumRating.setToolTipText("Players with rating less than this value can't join this table"); + + chkRated.setText("Rated game"); + chkRated.setToolTipText("Indicates if matche will be rated"); + + btnSettingsLoad.setText("Load..."); + btnSettingsLoad.setToolTipText("Load settings"); + btnSettingsLoad.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnSettingsLoadMouseClicked(evt); + } + }); + + btnSettingsSave.setText("Save..."); + btnSettingsSave.setToolTipText("Save settings"); + btnSettingsSave.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnSettingsSaveMouseClicked(evt); + } + }); + + lblSettings.setText("Settings"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); @@ -198,144 +303,166 @@ public class NewTableDialog extends MageDialog { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblName) - .addComponent(lbDeckType) - .addComponent(lblGameType)) - .addGap(6, 6, 6) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createSequentialGroup() - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, 270, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(chkRollbackTurnsAllowed) - .addGap(13, 13, 13) - .addComponent(lblFreeMulligans) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(13, 13, 13) - .addComponent(chkSpectatorsAllowed) - .addGap(13, 13, 13) - .addComponent(chkPlaneChase)) - .addGroup(layout.createSequentialGroup() - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbTimeLimit) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPassword) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 125, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnPreviousConfiguration1, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnPreviousConfiguration2, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, 332, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(chkRated) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(lblQuitRatio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblEdhPowerLevel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(btnOK) + .addComponent(lblSettings) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel)) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblNumPlayers) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(btnSettingsLoad) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblRange) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(btnSettingsSave) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(lblAttack) - .addGap(116, 116, 116) - .addComponent(lblSkillLevel)) - .addGroup(layout.createSequentialGroup() - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 148, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(18, 18, 18) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblNumWins) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(jSeparator2) - .addComponent(player1Panel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(player1Panel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 863, Short.MAX_VALUE) .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING)) + .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblName) + .addComponent(lbDeckType) + .addComponent(lblGameType)) + .addGap(6, 6, 6) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 178, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbTimeLimit) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 109, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkSpectatorsAllowed)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(cbDeckType, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(cbGameType, 0, 270, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(chkRollbackTurnsAllowed) + .addGroup(layout.createSequentialGroup() + .addComponent(chkRated) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblMinimumRating) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblQuitRatio) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEdhPowerLevel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE)))))) + .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblNumPlayers) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblRange) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(8, 8, 8) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblAttack)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 102, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSkillLevel)) + .addGap(4, 4, 4) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblNumWins)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblMullgian) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 149, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 72, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(chkPlaneChase)) + .addComponent(lblFreeMulligans)))) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 660, Short.MAX_VALUE) + .addComponent(jSeparator3, javax.swing.GroupLayout.DEFAULT_SIZE, 863, Short.MAX_VALUE) .addContainerGap())) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblName) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnPreviousConfiguration1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnPreviousConfiguration2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPassword) - .addComponent(lbTimeLimit) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtName) + .addComponent(lblName)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbTimeLimit) + .addComponent(lbTimeLimit) + .addComponent(lblPassword) + .addComponent(txtPassword) + .addComponent(chkSpectatorsAllowed))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lbDeckType) .addComponent(lblQuitRatio) - .addComponent(chkRated) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblEdhPowerLevel) - .addComponent(chkRated) - .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(spnEdhPowerLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chkRated)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblFreeMulligans) - .addComponent(chkRollbackTurnsAllowed) - .addComponent(chkSpectatorsAllowed) - .addComponent(chkPlaneChase)) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblGameType))) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblGameType) + .addComponent(chkRollbackTurnsAllowed)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(lblRange) + .addGap(0, 0, 0) + .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) .addComponent(lblNumPlayers) .addGap(0, 0, 0) .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblSkillLevel) - .addComponent(lblNumWins) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblRange) - .addComponent(lblAttack))) + .addGroup(layout.createSequentialGroup() + .addComponent(lblAttack) + .addGap(0, 0, 0) + .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblSkillLevel) + .addGap(0, 0, 0) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblNumWins) + .addGap(0, 0, 0) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblMullgian) + .addGap(0, 0, 0) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblFreeMulligans) .addGap(0, 0, 0) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbRange, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbAttackOption, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(chkPlaneChase)))) + .addGap(14, 14, 14) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel1) @@ -344,21 +471,26 @@ public class NewTableDialog extends MageDialog { .addGap(16, 16, 16) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 105, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 94, Short.MAX_VALUE) + .addGap(9, 9, 9) .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnCancel) - .addComponent(btnOK)) - .addGap(0, 0, 0)) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnOK, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSettings)) + .addContainerGap()) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(201, 201, 201) .addComponent(jSeparator3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(167, Short.MAX_VALUE))) + .addContainerGap(180, Short.MAX_VALUE))) ); + lblMullgian.getAccessibleContext().setAccessibleName("Mullgian"); + pack(); }//
//GEN-END:initComponents @@ -369,39 +501,19 @@ public class NewTableDialog extends MageDialog { }//GEN-LAST:event_btnCancelActionPerformed private void btnPreviousConfigurationActionPerformed(java.awt.event.ActionEvent evt, int i) {//GEN-FIRST:event_btnPreviousConfigurationActionPerformed - currentSettingVersion = i; - setGameSettingsFromPrefs(currentSettingVersion); }//GEN-LAST:event_btnPreviousConfigurationActionPerformed private void btnOKActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOKActionPerformed - GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); - MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName(), false, 2); - options.getPlayerTypes().add(PlayerType.HUMAN); - for (TablePlayerPanel player : players) { - options.getPlayerTypes().add(player.getPlayerType()); - } - options.setDeckType((String) this.cbDeckType.getSelectedItem()); - options.setLimited(false); - options.setMatchTimeLimit((MatchTimeLimit) this.cbTimeLimit.getSelectedItem()); - options.setAttackOption((MultiplayerAttackOption) this.cbAttackOption.getSelectedItem()); - options.setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem()); - options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem()); - options.setWinsNeeded((Integer) this.spnNumWins.getValue()); - options.setRollbackTurnsAllowed(chkRollbackTurnsAllowed.isSelected()); - options.setSpectatorsAllowed(chkSpectatorsAllowed.isSelected()); - options.setPlaneChase(chkPlaneChase.isSelected()); - options.setRated(chkRated.isSelected()); - options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); - options.setPassword(this.txtPassword.getText()); - options.setQuitRatio((Integer) this.spnQuitRatio.getValue()); - options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue()); - String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); - options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); + + MatchOptions options = getMatchOptions(); if (!checkMatchOptions(options)) { return; } - saveGameSettingsToPrefs(options, this.player1Panel.getDeckFile()); + // save last used + onSaveSettings(0, options, this.player1Panel.getDeckFile()); + + // run table = SessionHandler.createTable(roomId, options); if (table == null) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error creating table.", "Error", JOptionPane.ERROR_MESSAGE); @@ -413,7 +525,7 @@ public class NewTableDialog extends MageDialog { table.getTableId(), this.player1Panel.getPlayerName(), PlayerType.HUMAN, 1, - DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()), + DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()), this.txtPassword.getText())) { for (TablePlayerPanel player : players) { if (player.getPlayerType() != PlayerType.HUMAN) { @@ -449,9 +561,68 @@ public class NewTableDialog extends MageDialog { createPlayers(numPlayers); }//GEN-LAST:event_numPlayersChanged - private void spnNumWinsnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnNumWinsnumPlayersChanged - // TODO add your handling code here: - }//GEN-LAST:event_spnNumWinsnumPlayersChanged + private void btnSettingsSaveMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnSettingsSaveMouseClicked + popupSaveSettings.show(evt.getComponent(), evt.getX(), evt.getY()); + }//GEN-LAST:event_btnSettingsSaveMouseClicked + + private void btnSettingsLoadMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnSettingsLoadMouseClicked + popupLoadSettings.show(evt.getComponent(), evt.getX(), evt.getY()); + }//GEN-LAST:event_btnSettingsLoadMouseClicked + + private void menuSaveSettings2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveSettings2ActionPerformed + onSaveSettings(2); + }//GEN-LAST:event_menuSaveSettings2ActionPerformed + + private void menuSaveSettings1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveSettings1ActionPerformed + onSaveSettings(1); + }//GEN-LAST:event_menuSaveSettings1ActionPerformed + + private void menuLoadSettingsLastActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettingsLastActionPerformed + onLoadSettings(0); + }//GEN-LAST:event_menuLoadSettingsLastActionPerformed + + private void menuLoadSettings1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettings1ActionPerformed + onLoadSettings(1); + }//GEN-LAST:event_menuLoadSettings1ActionPerformed + + private void menuLoadSettings2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettings2ActionPerformed + onLoadSettings(2); + }//GEN-LAST:event_menuLoadSettings2ActionPerformed + + private void menuLoadSettingsDefaultActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettingsDefaultActionPerformed + onLoadSettings(-1); + }//GEN-LAST:event_menuLoadSettingsDefaultActionPerformed + + private MatchOptions getMatchOptions() { + // current settings + GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); + MatchOptions options = new MatchOptions(this.txtName.getText(), gameType.getName(), false, 2); + options.getPlayerTypes().add(PlayerType.HUMAN); + for (TablePlayerPanel player : players) { + options.getPlayerTypes().add(player.getPlayerType()); + } + options.setDeckType((String) this.cbDeckType.getSelectedItem()); + options.setLimited(false); + options.setMatchTimeLimit((MatchTimeLimit) this.cbTimeLimit.getSelectedItem()); + options.setAttackOption((MultiplayerAttackOption) this.cbAttackOption.getSelectedItem()); + options.setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem()); + options.setRange((RangeOfInfluence) this.cbRange.getSelectedItem()); + options.setWinsNeeded((Integer) this.spnNumWins.getValue()); + options.setRollbackTurnsAllowed(chkRollbackTurnsAllowed.isSelected()); + options.setSpectatorsAllowed(chkSpectatorsAllowed.isSelected()); + options.setPlaneChase(chkPlaneChase.isSelected()); + options.setRated(chkRated.isSelected()); + options.setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); + options.setPassword(this.txtPassword.getText()); + options.setQuitRatio((Integer) this.spnQuitRatio.getValue()); + options.setMinimumRating((Integer) this.spnMinimumRating.getValue()); + options.setEdhPowerLevel((Integer) this.spnEdhPowerLevel.getValue()); + options.setMullgianType((MulliganType) this.cbMulligan.getSelectedItem()); + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); + + return options; + } /** * Checks about not valid game option combinations and shows an error @@ -460,10 +631,14 @@ public class NewTableDialog extends MageDialog { * @return */ private boolean checkMatchOptions(MatchOptions options) { + + // deck => game switch (options.getDeckType()) { case "Variant Magic - Commander": case "Variant Magic - Duel Commander": case "Variant Magic - MTGO 1v1 Commander": + case "Variant Magic - Freeform Commander": + case "Variant Magic - Penny Dreadful Commander": if (!options.getGameType().startsWith("Commander")) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE); return false; @@ -489,12 +664,16 @@ public class NewTableDialog extends MageDialog { } break; } + + // game => deck switch (options.getGameType()) { case "Commander Two Player Duel": case "Commander Free For All": if (!options.getDeckType().equals("Variant Magic - Commander") && !options.getDeckType().equals("Variant Magic - Duel Commander") - && !options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander")) { + && !options.getDeckType().equals("Variant Magic - MTGO 1v1 Commander") + && !options.getDeckType().equals("Variant Magic - Freeform Commander") + && !options.getDeckType().equals("Variant Magic - Penny Dreadful Commander")) { JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Deck type Commander needs also a Commander game type", "Error", JOptionPane.ERROR_MESSAGE); return false; } @@ -567,8 +746,7 @@ public class NewTableDialog extends MageDialog { private void handleError(Exception ex) { logger.fatal("Error loading deck", ex); - //JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error loading deck.", "Error", JOptionPane.ERROR_MESSAGE); - MageFrame.getInstance().showErrorDialog("Error loading deck.", ex.getMessage()); + MageFrame.getInstance().showErrorDialog("Error loading deck", ex.getMessage()); } public void showDialog(UUID roomId) { @@ -583,6 +761,7 @@ public class NewTableDialog extends MageDialog { cbRange.setModel(new DefaultComboBoxModel(RangeOfInfluence.values())); cbAttackOption.setModel(new DefaultComboBoxModel(MultiplayerAttackOption.values())); cbSkillLevel.setModel(new DefaultComboBoxModel(SkillLevel.values())); + cbMulligan.setModel(new DefaultComboBoxModel(MulliganType.values())); // Update the existing player panels (neccessary if server was changes = new session) int i = 2; for (TablePlayerPanel tablePlayerPanel : players) { @@ -592,8 +771,10 @@ public class NewTableDialog extends MageDialog { setGameOptions(); this.setLocation(150, 100); } - currentSettingVersion = 0; - setGameSettingsFromPrefs(currentSettingVersion); + + // auto-load last settings + onLoadSettings(0); + this.setVisible(true); } @@ -615,27 +796,24 @@ public class NewTableDialog extends MageDialog { } } - /** - * set the table settings from java prefs - */ - int currentSettingVersion = 0; + private void onLoadSettings(int version) { - private void setGameSettingsFromPrefs(int version) { - currentSettingVersion = version; String versionStr = ""; - switch (currentSettingVersion) { + switch (version) { + case -1: + versionStr = "-1"; // default (empty) + break; case 1: versionStr = "1"; - btnPreviousConfiguration1.requestFocus(); break; case 2: versionStr = "2"; - btnPreviousConfiguration2.requestFocus(); break; default: - btnPreviousConfiguration2.getParent().requestFocus(); + versionStr = ""; break; } + txtName.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NAME + versionStr, "Game")); txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD + versionStr, "")); @@ -671,6 +849,7 @@ public class NewTableDialog extends MageDialog { this.chkPlaneChase.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_PLANECHASE + versionStr, "No").equals("Yes")); this.chkRated.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RATED + versionStr, "No").equals("Yes")); this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, "0"))); + this.cbMulligan.setSelectedItem(MulliganType.valueByName(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE + versionStr, MulliganType.GAME_DEFAULT.toString()))); int range = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, "1")); for (RangeOfInfluence roi : RangeOfInfluence.values()) { @@ -686,7 +865,7 @@ public class NewTableDialog extends MageDialog { break; } } - String skillLevelDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_SKILL_LEVEL, "Casual"); + String skillLevelDefault = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_SKILL_LEVEL + versionStr, "Casual"); for (SkillLevel skillLevel : SkillLevel.values()) { if (skillLevel.toString().equals(skillLevelDefault)) { this.cbSkillLevel.setSelectedItem(skillLevel); @@ -694,24 +873,31 @@ public class NewTableDialog extends MageDialog { } } - this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO, "100"))); - this.spnEdhPowerLevel.setValue(0); + this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, "100"))); + this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, "0"))); + this.spnEdhPowerLevel.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TABLE_EDH_POWER_LEVEL + versionStr, "0"))); } - /** - * Save the settings to java prefs to reload it next time the dialog will be - * created - * - * @param options - * @param deckFile - */ - private void saveGameSettingsToPrefs(MatchOptions options, String deckFile) { + private void onSaveSettings(int version) { + MatchOptions options = getMatchOptions(); + onSaveSettings(version, options, this.player1Panel.getDeckFile()); + } + + private void onSaveSettings(int version, MatchOptions options, String deckFile) { + String versionStr = ""; - if (currentSettingVersion == 1) { - versionStr = "1"; - } else if (currentSettingVersion == 2) { - versionStr = "2"; + switch (version) { + case 1: + versionStr = "1"; + break; + case 2: + versionStr = "2"; + break; + default: + versionStr = ""; + break; } + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_NAME + versionStr, options.getName()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PASSWORD + versionStr, options.getPassword()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_DECK_TYPE + versionStr, options.getDeckType()); @@ -721,6 +907,7 @@ public class NewTableDialog extends MageDialog { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_ROLLBACK_TURNS_ALLOWED + versionStr, options.isRollbackTurnsAllowed() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_RATED + versionStr, options.isRated() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(options.getFreeMulligans())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_MULLIGAN_TYPE + versionStr, options.getMulliganType().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_DECK_FILE + versionStr, deckFile); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_NUMBER_PLAYERS + versionStr, spnNumPlayers.getValue().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_RANGE + versionStr, Integer.toString(options.getRange().getRange())); @@ -729,6 +916,9 @@ public class NewTableDialog extends MageDialog { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_SPECTATORS_ALLOWED + versionStr, options.isSpectatorsAllowed() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_PLANECHASE + versionStr, options.isPlaneChase() ? "Yes" : "No"); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_QUIT_RATIO + versionStr, Integer.toString(options.getQuitRatio())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_MINIMUM_RATING + versionStr, Integer.toString(options.getMinimumRating())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_EDH_POWER_LEVEL + versionStr, Integer.toString(options.getEdhPowerLevel())); + StringBuilder playerTypesString = new StringBuilder(); for (Object player : players) { if (playerTypesString.length() > 0) { @@ -743,18 +933,19 @@ public class NewTableDialog extends MageDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; private javax.swing.JButton btnOK; - private javax.swing.JButton btnPreviousConfiguration1; - private javax.swing.JButton btnPreviousConfiguration2; + private javax.swing.JButton btnSettingsLoad; + private javax.swing.JButton btnSettingsSave; private javax.swing.JComboBox cbAttackOption; private javax.swing.JComboBox cbDeckType; private javax.swing.JComboBox cbGameType; + private javax.swing.JComboBox cbMulligan; private javax.swing.JComboBox cbRange; private javax.swing.JComboBox cbSkillLevel; private javax.swing.JComboBox cbTimeLimit; - private javax.swing.JCheckBox chkRollbackTurnsAllowed; - private javax.swing.JCheckBox chkSpectatorsAllowed; private javax.swing.JCheckBox chkPlaneChase; private javax.swing.JCheckBox chkRated; + private javax.swing.JCheckBox chkRollbackTurnsAllowed; + private javax.swing.JCheckBox chkSpectatorsAllowed; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JSeparator jSeparator1; @@ -763,23 +954,37 @@ public class NewTableDialog extends MageDialog { private javax.swing.JLabel lbDeckType; private javax.swing.JLabel lbTimeLimit; private javax.swing.JLabel lblAttack; + private javax.swing.JLabel lblEdhPowerLevel; private javax.swing.JLabel lblFreeMulligans; private javax.swing.JLabel lblGameType; + private javax.swing.JLabel lblMinimumRating; + private javax.swing.JLabel lblMullgian; private javax.swing.JLabel lblName; private javax.swing.JLabel lblNumPlayers; private javax.swing.JLabel lblNumWins; private javax.swing.JLabel lblPassword; private javax.swing.JLabel lblQuitRatio; - private javax.swing.JLabel lblEdhPowerLevel; private javax.swing.JLabel lblRange; + private javax.swing.JLabel lblSettings; private javax.swing.JLabel lblSkillLevel; + private javax.swing.JMenuItem menuLoadSettings1; + private javax.swing.JMenuItem menuLoadSettings2; + private javax.swing.JMenuItem menuLoadSettingsDefault; + private javax.swing.JMenuItem menuLoadSettingsLast; + private javax.swing.JMenuItem menuSaveSettings1; + private javax.swing.JMenuItem menuSaveSettings2; private mage.client.table.NewPlayerPanel player1Panel; private javax.swing.JPanel pnlOtherPlayers; + private javax.swing.JPopupMenu popupLoadSettings; + private javax.swing.JPopupMenu popupSaveSettings; + private javax.swing.JPopupMenu.Separator separator1; + private javax.swing.JPopupMenu.Separator separator2; + private javax.swing.JSpinner spnEdhPowerLevel; private javax.swing.JSpinner spnFreeMulligans; + private javax.swing.JSpinner spnMinimumRating; private javax.swing.JSpinner spnNumPlayers; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; - private javax.swing.JSpinner spnEdhPowerLevel; private javax.swing.JTextField txtName; private javax.swing.JTextField txtPassword; // End of variables declaration//GEN-END:variables diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form index 349e6bf771..391bb71c50 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.form @@ -1,6 +1,79 @@
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -29,8 +102,16 @@ - - + + + + + + + + + + @@ -53,77 +134,96 @@ - - - - - - - + + + + + + + + + + + + + - - - + + + + + + + + - - - - - + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -135,7 +235,7 @@ - + @@ -143,22 +243,30 @@ - - + - - - - - - - - + + + + + + + + + + + + + + + + + @@ -166,42 +274,54 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - + - - - - + + - + - + @@ -210,17 +330,21 @@ - - - - - - + + + + + + + + + + @@ -312,6 +436,9 @@ + + + @@ -390,8 +517,16 @@ - - + + + + + + + + + + @@ -402,7 +537,7 @@ - + @@ -459,11 +594,10 @@ - + - @@ -479,7 +613,7 @@ - + @@ -505,7 +639,7 @@ - + @@ -527,25 +661,9 @@ - + - - - - - - - - - - - - - - - - - + @@ -575,7 +693,7 @@ - + @@ -583,5 +701,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java index f5f2961f51..ffc4c952ed 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/NewTournamentDialog.java @@ -1,29 +1,14 @@ - - - /* - * NewTournamentDialog.java - * - * Created on Jan 28, 2011, 12:15:56 PM - */ package mage.client.dialog; -import java.awt.*; -import java.io.File; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.UUID; -import javax.swing.*; -import javax.swing.filechooser.FileFilter; import mage.cards.decks.Deck; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.DeckFileFilter; +import mage.cards.decks.importer.DeckImporter; import mage.cards.repository.ExpansionInfo; import mage.cards.repository.ExpansionRepository; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.table.TournamentPlayerPanel; +import mage.client.util.IgnoreList; import mage.client.util.gui.FastSearchUtil; import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; @@ -32,6 +17,7 @@ import mage.constants.SkillLevel; import mage.game.GameException; import mage.game.draft.DraftOptions; import mage.game.draft.DraftOptions.TimingOption; +import mage.game.mulligan.MulliganType; import mage.game.tournament.LimitedOptions; import mage.game.tournament.TournamentOptions; import mage.players.PlayerType; @@ -40,8 +26,15 @@ import mage.view.TableView; import mage.view.TournamentTypeView; import org.apache.log4j.Logger; +import javax.swing.*; +import java.awt.*; +import java.io.File; +import java.util.List; +import java.util.*; +import java.util.stream.Collectors; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class NewTournamentDialog extends MageDialog { @@ -62,18 +55,17 @@ public class NewTournamentDialog extends MageDialog { private String cubeFromDeckFilename = ""; private boolean automaticChange = false; - /** - * Creates new form NewTournamentDialog - */ public NewTournamentDialog() { initComponents(); lastSessionId = ""; txtName.setText("Tournament"); this.spnNumWins.setModel(new SpinnerNumberModel(2, 1, 5, 1)); this.spnFreeMulligans.setModel(new SpinnerNumberModel(0, 0, 5, 1)); + this.cbMulligan.setModel(new DefaultComboBoxModel(MulliganType.values())); this.spnConstructTime.setModel(new SpinnerNumberModel(10, CONSTRUCTION_TIME_MIN, CONSTRUCTION_TIME_MAX, 2)); this.spnNumRounds.setModel(new SpinnerNumberModel(2, 2, 10, 1)); this.spnQuitRatio.setModel(new SpinnerNumberModel(100, 0, 100, 5)); + this.spnMinimumRating.setModel(new SpinnerNumberModel(0, 0, 3000, 10)); } public void showDialog(UUID roomId) { @@ -101,8 +93,9 @@ public class NewTournamentDialog extends MageDialog { this.setModal(true); this.setLocation(150, 100); } - currentSettingVersion = 0; - setTournamentSettingsFromPrefs(currentSettingVersion); + + onLoadSettings(0); + this.setVisible(true); } @@ -116,6 +109,16 @@ public class NewTournamentDialog extends MageDialog { private void initComponents() { bindingGroup = new org.jdesktop.beansbinding.BindingGroup(); + popupSaveSettings = new javax.swing.JPopupMenu(); + menuSaveSettings1 = new javax.swing.JMenuItem(); + menuSaveSettings2 = new javax.swing.JMenuItem(); + popupLoadSettings = new javax.swing.JPopupMenu(); + menuLoadSettingsLast = new javax.swing.JMenuItem(); + separator1 = new javax.swing.JPopupMenu.Separator(); + menuLoadSettings1 = new javax.swing.JMenuItem(); + menuLoadSettings2 = new javax.swing.JMenuItem(); + separator2 = new javax.swing.JPopupMenu.Separator(); + menuLoadSettingsDefault = new javax.swing.JMenuItem(); lblName = new javax.swing.JLabel(); txtName = new javax.swing.JTextField(); lbTimeLimit = new javax.swing.JLabel(); @@ -141,8 +144,8 @@ public class NewTournamentDialog extends MageDialog { lblPacks = new javax.swing.JLabel(); pnlPacks = new javax.swing.JPanel(); lblNbrPlayers = new javax.swing.JLabel(); - spnNumPlayers = new javax.swing.JSpinner(); lblNbrSeats = new javax.swing.JLabel(); + spnNumPlayers = new javax.swing.JSpinner(); spnNumSeats = new javax.swing.JSpinner(); pnlDraftOptions = new javax.swing.JPanel(); jLabel6 = new javax.swing.JLabel(); @@ -152,24 +155,82 @@ public class NewTournamentDialog extends MageDialog { lblPlayer1 = new javax.swing.JLabel(); lblConstructionTime = new javax.swing.JLabel(); chkRollbackTurnsAllowed = new javax.swing.JCheckBox(); - chkRated = new javax.swing.JCheckBox(); spnConstructTime = new javax.swing.JSpinner(); player1Panel = new mage.client.table.NewPlayerPanel(); pnlPlayers = new javax.swing.JPanel(); pnlOtherPlayers = new javax.swing.JPanel(); - btnSavedConfiguration1 = new javax.swing.JButton(); - btnSavedConfiguration2 = new javax.swing.JButton(); btnOk = new javax.swing.JButton(); btnCancel = new javax.swing.JButton(); pnlRandomPacks = new javax.swing.JPanel(); lblQuitRatio = new javax.swing.JLabel(); spnQuitRatio = new javax.swing.JSpinner(); + lblMinimumRating = new javax.swing.JLabel(); + spnMinimumRating = new javax.swing.JSpinner(); + chkRated = new javax.swing.JCheckBox(); + lblMullgian = new javax.swing.JLabel(); + cbMulligan = new javax.swing.JComboBox<>(); + btnSettingsSave = new javax.swing.JButton(); + btnSettingsLoad = new javax.swing.JButton(); + lblSettings = new javax.swing.JLabel(); + + menuSaveSettings1.setText("Save to config 1"); + menuSaveSettings1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuSaveSettings1ActionPerformed(evt); + } + }); + popupSaveSettings.add(menuSaveSettings1); + + menuSaveSettings2.setText("Save to config 2"); + menuSaveSettings2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuSaveSettings2ActionPerformed(evt); + } + }); + popupSaveSettings.add(menuSaveSettings2); + + menuLoadSettingsLast.setText("Load from last time"); + menuLoadSettingsLast.setToolTipText(""); + menuLoadSettingsLast.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettingsLastActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettingsLast); + popupLoadSettings.add(separator1); + + menuLoadSettings1.setText("Load from config 1"); + menuLoadSettings1.setToolTipText(""); + menuLoadSettings1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettings1ActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettings1); + + menuLoadSettings2.setText("Load from config 2"); + menuLoadSettings2.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettings2ActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettings2); + popupLoadSettings.add(separator2); + + menuLoadSettingsDefault.setText("Load default settings"); + menuLoadSettingsDefault.setToolTipText(""); + menuLoadSettingsDefault.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + menuLoadSettingsDefaultActionPerformed(evt); + } + }); + popupLoadSettings.add(menuLoadSettingsDefault); setTitle("New Tournament"); lblName.setText("Name:"); - lbTimeLimit.setText("Time:"); + lbTimeLimit.setText("Time Limit:"); lbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "); org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, cbTimeLimit, org.jdesktop.beansbinding.ObjectProperty.create(), lbTimeLimit, org.jdesktop.beansbinding.BeanProperty.create("labelFor")); @@ -177,7 +238,7 @@ public class NewTournamentDialog extends MageDialog { cbTimeLimit.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "); - lbSkillLevel.setText("Skill:"); + lbSkillLevel.setText("Skill Level:"); lbSkillLevel.setToolTipText("The time a player has for the whole match. If a player runs out of time during a game, he loses the complete match. "); cbSkillLevel.setToolTipText("This option can be used to make it easier to find matches
\nwith opponents of the appropriate skill level."); @@ -190,7 +251,11 @@ public class NewTournamentDialog extends MageDialog { lblTournamentType.setText("Tournament Type:"); cbTournamentType.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); - cbTournamentType.addActionListener(evt -> cbTournamentTypeActionPerformed(evt)); + cbTournamentType.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbTournamentTypeActionPerformed(evt); + } + }); lbDeckType.setText("Deck Type:"); lbDeckType.setFocusable(false); @@ -198,8 +263,13 @@ public class NewTournamentDialog extends MageDialog { lblGameType.setText("Game Type:"); lblGameType.setFocusable(false); - cbGameType.addActionListener(evt -> cbGameTypeActionPerformed(evt)); + cbGameType.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbGameTypeActionPerformed(evt); + } + }); + lblFreeMulligans.setLabelFor(spnFreeMulligans); lblFreeMulligans.setText("Free Mulligans:"); spnFreeMulligans.setToolTipText("Players can take this number of free mulligans (their hand size will not be reduced)."); @@ -207,18 +277,30 @@ public class NewTournamentDialog extends MageDialog { lblNumWins.setText("Wins:"); spnNumWins.setToolTipText("To win a match a player has to win this number of games."); - spnNumWins.addChangeListener(evt -> spnNumWinsnumPlayersChanged(evt)); + spnNumWins.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnNumWinsnumPlayersChanged(evt); + } + }); lblDraftCube.setText("Draft Cube:"); cbDraftCube.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); - cbDraftCube.addActionListener(evt -> cbDraftCubeActionPerformed(evt)); + cbDraftCube.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbDraftCubeActionPerformed(evt); + } + }); lblNumRounds.setText("Number of Swiss Rounds:"); lblNumRounds.setToolTipText("The number of rounds the swiss tournament has in total.
\nThe tournaments ends after that number of rounds or
\nif there are less than two players left in the tournament."); spnNumRounds.setToolTipText("The number of rounds the swiss tournament has in total.
\nThe tournaments ends after that number of rounds or
\nif there are less than two players left in the tournament."); - spnNumRounds.addChangeListener(evt -> spnNumRoundsnumPlayersChanged(evt)); + spnNumRounds.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnNumRoundsnumPlayersChanged(evt); + } + }); lblPacks.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N lblPacks.setText("Packs"); @@ -228,16 +310,28 @@ public class NewTournamentDialog extends MageDialog { lblNbrPlayers.setText("Players:"); - spnNumPlayers.addChangeListener(evt -> spnNumPlayersStateChanged(evt)); - lblNbrSeats.setText("Seats:"); - spnNumSeats.addChangeListener(evt -> spnNumSeatsStateChanged(evt)); + spnNumPlayers.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnNumPlayersStateChanged(evt); + } + }); + + spnNumSeats.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnNumSeatsStateChanged(evt); + } + }); jLabel6.setText("Timing:"); cbDraftTiming.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); - cbDraftTiming.addActionListener(evt -> cbDraftTimingActionPerformed(evt)); + cbDraftTiming.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbDraftTimingActionPerformed(evt); + } + }); javax.swing.GroupLayout pnlDraftOptionsLayout = new javax.swing.GroupLayout(pnlDraftOptions); pnlDraftOptions.setLayout(pnlDraftOptionsLayout); @@ -262,23 +356,21 @@ public class NewTournamentDialog extends MageDialog { cbAllowSpectators.setText("Allow spectators"); cbAllowSpectators.setToolTipText("Allow other players to watch the games of this table."); - cbPlaneChase.setText("Use Plane Chase"); - cbPlaneChase.setToolTipText("Use Plane Chase variant for the tournament."); + cbPlaneChase.setText("PlaneChase"); + cbPlaneChase.setToolTipText("Use Plane Chase for the tournament."); lblPlayer1.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N lblPlayer1.setText("Player 1 (You)"); lblConstructionTime.setText("Construction Time (Minutes):"); - chkRollbackTurnsAllowed.setText("Allow rollbacks"); + chkRollbackTurnsAllowed.setText("Rollbacks"); chkRollbackTurnsAllowed.setToolTipText("Allow to rollback to the start of previous turns
if all players agree. "); - chkRated.setText("Rated"); - chkRated.setToolTipText("Indicates if matches will be rated."); - spnConstructTime.setToolTipText("The time players have to build their deck."); player1Panel.setPreferredSize(new java.awt.Dimension(400, 44)); + pnlOtherPlayers.setBorder(javax.swing.BorderFactory.createEtchedBorder()); pnlOtherPlayers.setLayout(new java.awt.GridLayout(0, 1, 2, 0)); @@ -290,34 +382,65 @@ public class NewTournamentDialog extends MageDialog { ); pnlPlayersLayout.setVerticalGroup( pnlPlayersLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnlOtherPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 5, Short.MAX_VALUE) ); - btnSavedConfiguration1.setText("T1"); - btnSavedConfiguration1.setToolTipText("Load saved tournament configuration #1"); - btnSavedConfiguration1.addActionListener(evt -> btnSavedConfigurationActionPerformed(evt, 1)); - btnSavedConfiguration1.setVisible(true); - - btnSavedConfiguration2.setText("T2"); - btnSavedConfiguration2.setToolTipText("Load saved tournament configuration #2"); - btnSavedConfiguration2.addActionListener(evt -> btnSavedConfigurationActionPerformed(evt, 2)); - btnSavedConfiguration2.setVisible(true); - - btnOk.setText("OK"); - btnOk.addActionListener(evt -> btnOkActionPerformed(evt)); + btnOk.setText("Create"); + btnOk.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnOkActionPerformed(evt); + } + }); btnCancel.setText("Cancel"); - btnCancel.addActionListener(evt -> btnCancelActionPerformed(evt)); + btnCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnCancelActionPerformed(evt); + } + }); pnlRandomPacks.setBorder(javax.swing.BorderFactory.createEtchedBorder()); pnlRandomPacks.setToolTipText(""); pnlRandomPacks.setLayout(new javax.swing.BoxLayout(pnlRandomPacks, javax.swing.BoxLayout.Y_AXIS)); - lblQuitRatio.setText("Allowed quit %:"); + lblQuitRatio.setText("Allowed quit %"); - spnQuitRatio.setToolTipText("Players with quit % more than this value can't join this table"); - spnNumSeats.setToolTipText("The number of seats for each duel. If more than 2, will set number of wins to 1"); - spnNumPlayers.setToolTipText("The total number of players who will draft"); + spnQuitRatio.setToolTipText(""); + + lblMinimumRating.setText("Minimum rating:"); + lblMinimumRating.setToolTipText("Players with rating less than this value can't join this table"); + + spnMinimumRating.addChangeListener(new javax.swing.event.ChangeListener() { + public void stateChanged(javax.swing.event.ChangeEvent evt) { + spnMinimumRatingnumPlayersChanged(evt); + } + }); + + chkRated.setText("Rated game"); + chkRated.setToolTipText("Indicates if matches will be rated"); + + lblMullgian.setText("Mulligan type:"); + lblMullgian.setToolTipText("What style of mulligan?"); + + cbMulligan.setToolTipText("Selections the type of mulligan for games."); + + btnSettingsSave.setText("Save..."); + btnSettingsSave.setToolTipText("Save settings"); + btnSettingsSave.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnSettingsSaveMouseClicked(evt); + } + }); + + btnSettingsLoad.setText("Load..."); + btnSettingsLoad.setToolTipText("Load settings"); + btnSettingsLoad.addMouseListener(new java.awt.event.MouseAdapter() { + public void mouseClicked(java.awt.event.MouseEvent evt) { + btnSettingsLoadMouseClicked(evt); + } + }); + + lblSettings.setText("Settings"); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); @@ -333,8 +456,8 @@ public class NewTournamentDialog extends MageDialog { .addGroup(layout.createSequentialGroup() .addComponent(lblNbrPlayers) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() .addComponent(lblNbrSeats) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(spnNumSeats, javax.swing.GroupLayout.PREFERRED_SIZE, 46, javax.swing.GroupLayout.PREFERRED_SIZE)) @@ -355,67 +478,80 @@ public class NewTournamentDialog extends MageDialog { .addComponent(spnConstructTime, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(chkRollbackTurnsAllowed)) - .addGroup(layout.createSequentialGroup() - .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbAllowSpectators) - .addComponent(cbPlaneChase) - ))) + .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(95, 95, 95)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(lblSettings) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsLoad) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnSettingsSave) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(btnOk) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblDraftCube) + .addComponent(lblTournamentType) + .addComponent(lbDeckType) + .addComponent(lblGameType)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() + .addComponent(chkRated) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblMinimumRating) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblNumWins) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblMullgian) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, 151, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblFreeMulligans, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(spnFreeMulligans)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbPlaneChase)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblDraftCube) - .addComponent(lblTournamentType) - .addComponent(lbDeckType) - .addComponent(lblGameType)) + .addComponent(lblQuitRatio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() - .addGap(28, 28, 28) - .addComponent(lblNumWins) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblQuitRatio) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, 60, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(chkRated)) - .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, 290, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGroup(layout.createSequentialGroup() - .addComponent(lblName) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbTimeLimit) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(spnQuitRatio)) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addComponent(lbSkillLevel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPassword) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSavedConfiguration1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnSavedConfiguration2)) - .addGroup(layout.createSequentialGroup() - .addComponent(lblFreeMulligans) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addGap(45, 45, 45)) + .addGroup(layout.createSequentialGroup() + .addComponent(lblName) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, 224, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lbTimeLimit) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, 101, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPassword) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 56, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cbAllowSpectators) + .addGap(0, 0, Short.MAX_VALUE)) .addComponent(player1Panel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnlRandomPacks, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) @@ -423,7 +559,7 @@ public class NewTournamentDialog extends MageDialog { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(4, 4, 4) + .addGap(3, 3, 3) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblName) @@ -431,35 +567,47 @@ public class NewTournamentDialog extends MageDialog { .addComponent(cbTimeLimit, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblPassword) .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnSavedConfiguration1) - .addComponent(btnSavedConfiguration2) - .addComponent(lbSkillLevel) - .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblFreeMulligans) - .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblNumWins) - .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblQuitRatio) - .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(chkRated)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblQuitRatio) + .addComponent(spnQuitRatio, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblNumWins) + .addComponent(spnNumWins, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(chkRated) + .addComponent(lblMinimumRating) + .addComponent(spnMinimumRating, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbTournamentType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblTournamentType)) + .addComponent(lblTournamentType) + .addComponent(lbSkillLevel) + .addComponent(cbSkillLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cbDraftCube, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblDraftCube)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lbDeckType)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblGameType) - .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbDeckType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lbDeckType)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblGameType) + .addComponent(cbGameType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblMullgian) + .addComponent(lblFreeMulligans)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cbMulligan, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(spnFreeMulligans, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(cbPlaneChase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblPacks) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -467,19 +615,19 @@ public class NewTournamentDialog extends MageDialog { .addGroup(layout.createSequentialGroup() .addComponent(pnlPacks, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(pnlRandomPacks, javax.swing.GroupLayout.DEFAULT_SIZE, 10, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cbAllowSpectators, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(cbPlaneChase, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(spnNumRounds, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(lblNumRounds)) .addComponent(lblNbrPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(spnNumPlayers) + .addComponent(spnNumPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE) + .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(lblNbrSeats, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(spnNumSeats) - .addComponent(pnlDraftOptions, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(spnNumSeats)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(lblPlayer1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) @@ -491,9 +639,14 @@ public class NewTournamentDialog extends MageDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(pnlPlayers, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnOk) - .addComponent(btnCancel)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnSettingsLoad, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnSettingsSave, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblSettings)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOk, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap()) ); @@ -503,108 +656,27 @@ public class NewTournamentDialog extends MageDialog { }// //GEN-END:initComponents private void cbTournamentTypeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbTournamentTypeActionPerformed - setTournamentOptions((Integer) this.spnNumPlayers.getValue()); + prepareTourneyView((Integer) this.spnNumPlayers.getValue()); }//GEN-LAST:event_cbTournamentTypeActionPerformed - private void btnSavedConfigurationActionPerformed(java.awt.event.ActionEvent evt, int setting) {//GEN-FIRST:event_btnSavedConfigurationActionPerformed - currentSettingVersion = setting; - setTournamentSettingsFromPrefs(currentSettingVersion); - }//GEN-LAST:event_btnSavedConfigurationActionPerformed - private void btnOkActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnOkActionPerformed + + // get settings + TournamentOptions tOptions = getTournamentOptions(); + + // CHECKS TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); - int numSeats = (Integer) this.spnNumSeats.getValue(); - TournamentOptions tOptions = new TournamentOptions(this.txtName.getText(), "", numSeats); - tOptions.setTournamentType(tournamentType.getName()); - tOptions.setPassword(txtPassword.getText()); - tOptions.getPlayerTypes().add(PlayerType.HUMAN); - tOptions.setWatchingAllowed(cbAllowSpectators.isSelected()); - tOptions.setPlaneChase(cbPlaneChase.isSelected()); - tOptions.setQuitRatio((Integer) spnQuitRatio.getValue()); - for (TournamentPlayerPanel player : players) { - tOptions.getPlayerTypes().add((PlayerType) player.getPlayerType().getSelectedItem()); - } - if (!tournamentType.isElimination()) { - tOptions.setNumberRounds((Integer) spnNumRounds.getValue()); - } - if (tournamentType.isDraft()) { - DraftOptions options = new DraftOptions(); - options.setDraftType(""); - options.setTiming((TimingOption) this.cbDraftTiming.getSelectedItem()); - tOptions.setLimitedOptions(options); - } - if (tOptions.getLimitedOptions() == null) { - tOptions.setLimitedOptions(new LimitedOptions()); - } - if (tournamentType.isLimited()) { - tOptions.getLimitedOptions().setConstructionTime((Integer) this.spnConstructTime.getValue() * 60); - tOptions.getLimitedOptions().setIsRandom(tournamentType.isRandom()); - if (tournamentType.isCubeBooster()) { - tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString()); - if (!(cubeFromDeckFilename.isEmpty())) { - Deck cubeFromDeck = new Deck(); - try { - cubeFromDeck = Deck.load(DeckImporterUtil.importDeck(cubeFromDeckFilename), true, true); - } catch (GameException e1) { - JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); - } - if (cubeFromDeck != null) { - cubeFromDeck.clearLayouts(); - tOptions.getLimitedOptions().setCubeFromDeck(cubeFromDeck); - } - } - } else if (tournamentType.isRandom() || tournamentType.isRichMan()) { - this.isRandom = tournamentType.isRandom(); - this.isRichMan = tournamentType.isRichMan(); - tOptions.getLimitedOptions().getSetCodes().clear(); - ArrayList selected = randomPackSelector.getSelectedPacks(); - int maxPacks = 3 * (players.size() + 1); - if (tournamentType.isRichMan()) { - maxPacks = 36; - } - if (selected.size() > maxPacks) { - StringBuilder infoString = new StringBuilder("More sets were selected than needed. "); - infoString.append(maxPacks); - infoString.append(" sets will be randomly chosen."); - JOptionPane.showMessageDialog(MageFrame.getDesktop(), infoString, "Information", JOptionPane.INFORMATION_MESSAGE); - Collections.shuffle(selected); - tOptions.getLimitedOptions().getSetCodes().addAll(selected.subList(0, maxPacks)); - } else { - tOptions.getLimitedOptions().getSetCodes().addAll(selected); - } - } else { - for (JPanel panel : packPanels) { - JComboBox combo = findComboInComponent(panel); - if (combo != null) { - tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode()); - } else { - logger.error("Can't find combo component in " + panel.toString()); - } - } + if (tournamentType.isRandom() || tournamentType.isRichMan()) { + if (tOptions.getLimitedOptions().getSetCodes().isEmpty()) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Warning, you must select packs for the pool", "Warning", JOptionPane.WARNING_MESSAGE); + return; } - tOptions.getMatchOptions().setDeckType("Limited"); - tOptions.getMatchOptions().setGameType("Two Player Duel"); - tOptions.getMatchOptions().setLimited(true); - } else { - tOptions.getLimitedOptions().setConstructionTime(0); - tOptions.getLimitedOptions().setNumberBoosters(0); - tOptions.getLimitedOptions().setDraftCube(null); - tOptions.getLimitedOptions().setDraftCubeName(""); - tOptions.getMatchOptions().setDeckType((String) this.cbDeckType.getSelectedItem()); - tOptions.getMatchOptions().setGameType(((GameTypeView) this.cbGameType.getSelectedItem()).getName()); - tOptions.getMatchOptions().setLimited(false); } - tOptions.getMatchOptions().setMatchTimeLimit((MatchTimeLimit) this.cbTimeLimit.getSelectedItem()); - tOptions.getMatchOptions().setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem()); - tOptions.getMatchOptions().setWinsNeeded((Integer) this.spnNumWins.getValue()); - tOptions.getMatchOptions().setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); - tOptions.getMatchOptions().setAttackOption(MultiplayerAttackOption.LEFT); - tOptions.getMatchOptions().setRange(RangeOfInfluence.ALL); - tOptions.getMatchOptions().setRollbackTurnsAllowed(this.chkRollbackTurnsAllowed.isSelected()); - tOptions.getMatchOptions().setRated(this.chkRated.isSelected()); - saveTournamentSettingsToPrefs(tOptions); + // save last settings + onSaveSettings(0, tOptions); + // run table = SessionHandler.createTournamentTable(roomId, tOptions); if (table == null) { // message must be send by server! @@ -615,11 +687,11 @@ public class NewTournamentDialog extends MageDialog { table.getTableId(), this.player1Panel.getPlayerName(), PlayerType.HUMAN, 1, - DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()), + DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()), tOptions.getPassword())) { for (TournamentPlayerPanel player : players) { if (player.getPlayerType().getSelectedItem() != PlayerType.HUMAN) { - if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporterUtil.importDeck(this.player1Panel.getDeckFile()))) { + if (!player.joinTournamentTable(roomId, table.getTableId(), DeckImporter.importDeckFromFile(this.player1Panel.getDeckFile()))) { // error message must be send by sever SessionHandler.removeTable(roomId, table.getTableId()); table = null; @@ -693,7 +765,7 @@ public class NewTournamentDialog extends MageDialog { if (fcSelectDeck == null) { fcSelectDeck = new JFileChooser(); fcSelectDeck.setAcceptAllFileFilterUsed(false); - fcSelectDeck.addChoosableFileFilter(new DeckFilter()); + fcSelectDeck.addChoosableFileFilter(new DeckFileFilter("dck", "XMage's deck files (*.dck)")); } String lastFolder = MageFrame.getPreferences().get("lastDeckFolder", ""); if (!lastFolder.isEmpty()) { @@ -726,6 +798,42 @@ public class NewTournamentDialog extends MageDialog { setGameOptions(); }//GEN-LAST:event_cbGameTypeActionPerformed + private void spnMinimumRatingnumPlayersChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_spnMinimumRatingnumPlayersChanged + // TODO add your handling code here: + }//GEN-LAST:event_spnMinimumRatingnumPlayersChanged + + private void menuSaveSettings1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveSettings1ActionPerformed + onSaveSettings(1); + }//GEN-LAST:event_menuSaveSettings1ActionPerformed + + private void menuSaveSettings2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuSaveSettings2ActionPerformed + onSaveSettings(2); + }//GEN-LAST:event_menuSaveSettings2ActionPerformed + + private void menuLoadSettingsLastActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettingsLastActionPerformed + onLoadSettings(0); + }//GEN-LAST:event_menuLoadSettingsLastActionPerformed + + private void menuLoadSettings1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettings1ActionPerformed + onLoadSettings(1); + }//GEN-LAST:event_menuLoadSettings1ActionPerformed + + private void menuLoadSettings2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettings2ActionPerformed + onLoadSettings(2); + }//GEN-LAST:event_menuLoadSettings2ActionPerformed + + private void menuLoadSettingsDefaultActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_menuLoadSettingsDefaultActionPerformed + onLoadSettings(-1); + }//GEN-LAST:event_menuLoadSettingsDefaultActionPerformed + + private void btnSettingsSaveMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnSettingsSaveMouseClicked + popupSaveSettings.show(evt.getComponent(), evt.getX(), evt.getY()); + }//GEN-LAST:event_btnSettingsSaveMouseClicked + + private void btnSettingsLoadMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_btnSettingsLoadMouseClicked + popupLoadSettings.show(evt.getComponent(), evt.getX(), evt.getY()); + }//GEN-LAST:event_btnSettingsLoadMouseClicked + private void setGameOptions() { GameTypeView gameType = (GameTypeView) cbGameType.getSelectedItem(); // int oldValue = (Integer) this.spnNumPlayers.getValue(); @@ -739,19 +847,25 @@ public class NewTournamentDialog extends MageDialog { createPlayers((Integer) spnNumPlayers.getValue() - 1); } - private void setTournamentOptions(int numPlayers) { + private void prepareTourneyView(int numPlayers) { TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); activatePanelElements(tournamentType); + // players if (numPlayers < tournamentType.getMinPlayers() || numPlayers > tournamentType.getMaxPlayers()) { numPlayers = tournamentType.getMinPlayers(); - createPlayers(numPlayers - 1); + createPlayers(numPlayers - 1); // ? } this.spnNumPlayers.setModel(new SpinnerNumberModel(numPlayers, tournamentType.getMinPlayers(), tournamentType.getMaxPlayers(), 1)); this.spnNumPlayers.setEnabled(tournamentType.getMinPlayers() != tournamentType.getMaxPlayers()); createPlayers((Integer) spnNumPlayers.getValue() - 1); this.spnNumSeats.setModel(new SpinnerNumberModel(2, 2, tournamentType.getMaxPlayers(), 1)); + // packs + preparePacksView(tournamentType); + } + + private void preparePacksView(TournamentTypeView tournamentType) { if (tournamentType.isLimited()) { this.isRandom = tournamentType.isRandom(); this.isRichMan = tournamentType.isRichMan(); @@ -761,7 +875,6 @@ public class NewTournamentDialog extends MageDialog { createPacks(tournamentType.getNumBoosters()); } } - } private void setNumberOfSwissRoundsMin(int numPlayers) { @@ -823,6 +936,43 @@ public class NewTournamentDialog extends MageDialog { } } + private String prepareVersionStr(int version, boolean saveMode) { + // version: 0, 1, 2... to save/load + // version: -1 to reset (load from empty record) + switch (version) { + case -1: + return saveMode ? "" : "-1"; // can't save to -1 version + case 1: + return "1"; + case 2: + return "2"; + default: + return ""; + } + } + + private void loadRandomPacks(int version) { + String versionStr = prepareVersionStr(version, false); + ArrayList packList; + String packNames; + String randomPrefs = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT + versionStr, ""); + if (!randomPrefs.isEmpty()) { + packList = new ArrayList<>(Arrays.asList(randomPrefs.split(";"))); + packNames = randomPrefs; + } else { + ExpansionInfo[] allExpansions = ExpansionRepository.instance.getWithBoostersSortedByReleaseDate(); + packList = Arrays.stream(allExpansions).map(ExpansionInfo::getCode).collect(Collectors.toCollection(ArrayList::new)); + packNames = Arrays.stream(allExpansions).map(ExpansionInfo::getCode).collect(Collectors.joining(";")); + } + randomPackSelector.setSelectedPacks(packList); + txtRandomPacks.setText(packNames); + + // workaround to apply field's auto-size + this.pack(); + this.revalidate(); + this.repaint(); + } + private void createRandomPacks() { if (pnlRandomPacks.getComponentCount() == 0) { if (randomPackSelector == null) { @@ -832,20 +982,9 @@ public class NewTournamentDialog extends MageDialog { txtRandomPacks = new JTextArea(); txtRandomPacks.setEnabled(false); txtRandomPacks.setLineWrap(true); - String randomPrefs = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT, ""); - if (!randomPrefs.isEmpty()) { - txtRandomPacks.setText(randomPrefs); - ArrayList theList = new ArrayList<>(Arrays.asList(randomPrefs.split(";"))); - randomPackSelector.setSelectedPacks(theList); - } else { - ExpansionInfo[] allExpansions = ExpansionRepository.instance.getWithBoostersSortedByReleaseDate(); - StringBuilder packList = new StringBuilder(); - for (ExpansionInfo exp : allExpansions) { - packList.append(exp.getCode()); - packList.append(';'); - } - txtRandomPacks.setText(packList.toString()); - } + + loadRandomPacks(-1); // load default packs + txtRandomPacks.setAlignmentX(Component.LEFT_ALIGNMENT); pnlRandomPacks.add(txtRandomPacks); JButton btnSelectRandomPacks = new JButton(); @@ -855,6 +994,7 @@ public class NewTournamentDialog extends MageDialog { btnSelectRandomPacks.addActionListener(evt -> showRandomPackSelectorDialog()); pnlRandomPacks.add(btnSelectRandomPacks); } + txtRandomPacks.setText(txtRandomPacks.getText()); // workaround to apply field's auto-size this.pack(); this.revalidate(); this.repaint(); @@ -863,12 +1003,7 @@ public class NewTournamentDialog extends MageDialog { private void showRandomPackSelectorDialog() { randomPackSelector.setType(isRandom, isRichMan); randomPackSelector.showDialog(); - StringBuilder packList = new StringBuilder(); - for (String str : randomPackSelector.getSelectedPacks()) { - packList.append(str); - packList.append(';'); - } - this.txtRandomPacks.setText(packList.toString()); + this.txtRandomPacks.setText(String.join(";", randomPackSelector.getSelectedPacks())); this.pack(); this.revalidate(); this.repaint(); @@ -891,7 +1026,6 @@ public class NewTournamentDialog extends MageDialog { packPanels.add(setPanel); // for later access // combo set JComboBox pack = new JComboBox(); - pack = new JComboBox(); pack.setModel(new DefaultComboBoxModel(ExpansionRepository.instance.getWithBoostersSortedByReleaseDate())); pack.addActionListener(evt -> packActionPerformed(evt)); pack.setAlignmentX(0.0F); @@ -947,7 +1081,7 @@ public class NewTournamentDialog extends MageDialog { int startIndex = 0; for (int i = 0; i < packPanels.size(); i++) { JComboBox pack = findComboInComponent(packPanels.get(i)); - if (pack.equals(curentCombo)) { + if (pack != null && pack.equals(curentCombo)) { startIndex = i + 1; break; } @@ -956,7 +1090,9 @@ public class NewTournamentDialog extends MageDialog { // change all from start index for (int i = startIndex; i < packPanels.size(); i++) { JComboBox pack = findComboInComponent(packPanels.get(i)); - pack.setSelectedIndex(newValue); + if (pack != null) { + pack.setSelectedIndex(newValue); + } } } @@ -1012,23 +1148,139 @@ public class NewTournamentDialog extends MageDialog { automaticChange = false; } - /** - * set the tournament settings from java prefs - */ - int currentSettingVersion = 0; + private void loadBoosterPacks(String packString) { + if (!packString.isEmpty()) { + String[] packsArray = packString.substring(1, packString.length() - 1).split(","); + int packNumber = 0; + for (String pack : packsArray) { + packNumber++; + if (this.packPanels.size() >= packNumber - 1) { + JPanel panel = packPanels.get(packNumber - 1); + JComboBox comboBox = findComboInComponent(panel); - private void setTournamentSettingsFromPrefs(int version) { - currentSettingVersion = version; - String versionStr = ""; - if (currentSettingVersion == 1) { - versionStr = "1"; - btnSavedConfiguration1.requestFocus(); - } else if (currentSettingVersion == 2) { - versionStr = "2"; - btnSavedConfiguration2.requestFocus(); - } else { - btnSavedConfiguration2.getParent().requestFocus(); + if (comboBox != null) { + ComboBoxModel model = comboBox.getModel(); + int size = model.getSize(); + for (int i = 0; i < size; i++) { + ExpansionInfo element = (ExpansionInfo) model.getElementAt(i); + if (element.getCode().equals(pack.trim())) { + comboBox.setSelectedIndex(i); + break; + } + } + } else { + logger.error("Can't find combo component in " + panel.toString()); + } + } + + } } + } + + private TournamentOptions getTournamentOptions() { + TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); + int numSeats = (Integer) this.spnNumSeats.getValue(); + TournamentOptions tOptions = new TournamentOptions(this.txtName.getText(), "", numSeats); + tOptions.setTournamentType(tournamentType.getName()); + tOptions.setPassword(txtPassword.getText()); + tOptions.getPlayerTypes().add(PlayerType.HUMAN); + tOptions.setWatchingAllowed(cbAllowSpectators.isSelected()); + tOptions.setPlaneChase(cbPlaneChase.isSelected()); + tOptions.setQuitRatio((Integer) spnQuitRatio.getValue()); + tOptions.setMinimumRating((Integer) spnMinimumRating.getValue()); + for (TournamentPlayerPanel player : players) { + tOptions.getPlayerTypes().add((PlayerType) player.getPlayerType().getSelectedItem()); + } + if (!tournamentType.isElimination()) { + tOptions.setNumberRounds((Integer) spnNumRounds.getValue()); + } + if (tournamentType.isDraft()) { + DraftOptions options = new DraftOptions(); + options.setDraftType(""); + options.setTiming((TimingOption) this.cbDraftTiming.getSelectedItem()); + tOptions.setLimitedOptions(options); + } + if (tOptions.getLimitedOptions() == null) { + tOptions.setLimitedOptions(new LimitedOptions()); + } + if (tournamentType.isLimited()) { + tOptions.getLimitedOptions().setConstructionTime((Integer) this.spnConstructTime.getValue() * 60); + tOptions.getLimitedOptions().setIsRandom(tournamentType.isRandom()); + tOptions.getLimitedOptions().setIsRichMan(tournamentType.isRichMan()); + if (tournamentType.isCubeBooster()) { + tOptions.getLimitedOptions().setDraftCubeName(this.cbDraftCube.getSelectedItem().toString()); + if (!(cubeFromDeckFilename.isEmpty())) { + Deck cubeFromDeck = new Deck(); + try { + cubeFromDeck = Deck.load(DeckImporter.importDeckFromFile(cubeFromDeckFilename), true, true); + } catch (GameException e1) { + JOptionPane.showMessageDialog(MageFrame.getDesktop(), e1.getMessage(), "Error loading deck", JOptionPane.ERROR_MESSAGE); + } + if (cubeFromDeck != null) { + cubeFromDeck.clearLayouts(); + tOptions.getLimitedOptions().setCubeFromDeck(cubeFromDeck); + } + } + } else if (tournamentType.isRandom() || tournamentType.isRichMan()) { + this.isRandom = tournamentType.isRandom(); + this.isRichMan = tournamentType.isRichMan(); + tOptions.getLimitedOptions().getSetCodes().clear(); + ArrayList selected = randomPackSelector.getSelectedPacks(); + Collections.shuffle(selected); + int maxPacks = 3 * (players.size() + 1); + if (tournamentType.isRichMan()) { + maxPacks = 36; + } + if (selected.size() > maxPacks) { + StringBuilder infoString = new StringBuilder("More sets were selected than needed. "); + infoString.append(maxPacks); + infoString.append(" sets will be randomly chosen."); + JOptionPane.showMessageDialog(MageFrame.getDesktop(), infoString, "Information", JOptionPane.INFORMATION_MESSAGE); + tOptions.getLimitedOptions().getSetCodes().addAll(selected.subList(0, maxPacks)); + } else { + tOptions.getLimitedOptions().getSetCodes().addAll(selected); + } + } else { + for (JPanel panel : packPanels) { + JComboBox combo = findComboInComponent(panel); + if (combo != null) { + tOptions.getLimitedOptions().getSetCodes().add(((ExpansionInfo) combo.getSelectedItem()).getCode()); + } else { + logger.error("Can't find combo component in " + panel.toString()); + } + } + } + tOptions.getMatchOptions().setDeckType("Limited"); + tOptions.getMatchOptions().setGameType("Two Player Duel"); + tOptions.getMatchOptions().setLimited(true); + } else { + tOptions.getLimitedOptions().setConstructionTime(0); + tOptions.getLimitedOptions().setNumberBoosters(0); + tOptions.getLimitedOptions().setDraftCube(null); + tOptions.getLimitedOptions().setDraftCubeName(""); + tOptions.getMatchOptions().setDeckType((String) this.cbDeckType.getSelectedItem()); + tOptions.getMatchOptions().setGameType(((GameTypeView) this.cbGameType.getSelectedItem()).getName()); + tOptions.getMatchOptions().setLimited(false); + } + + String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); + tOptions.getMatchOptions().setBannedUsers(IgnoreList.ignoreList(serverAddress)); + + tOptions.getMatchOptions().setMatchTimeLimit((MatchTimeLimit) this.cbTimeLimit.getSelectedItem()); + tOptions.getMatchOptions().setSkillLevel((SkillLevel) this.cbSkillLevel.getSelectedItem()); + tOptions.getMatchOptions().setWinsNeeded((Integer) this.spnNumWins.getValue()); + tOptions.getMatchOptions().setFreeMulligans((Integer) this.spnFreeMulligans.getValue()); + tOptions.getMatchOptions().setMullgianType((MulliganType) this.cbMulligan.getSelectedItem()); + tOptions.getMatchOptions().setAttackOption(MultiplayerAttackOption.LEFT); + tOptions.getMatchOptions().setRange(RangeOfInfluence.ALL); + tOptions.getMatchOptions().setRollbackTurnsAllowed(this.chkRollbackTurnsAllowed.isSelected()); + tOptions.getMatchOptions().setRated(this.chkRated.isSelected()); + + return tOptions; + } + + private void onLoadSettings(int version) { + String versionStr = prepareVersionStr(version, false); int numPlayers; txtName.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NAME + versionStr, "Tournament")); txtPassword.setText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PASSWORD + versionStr, "")); @@ -1059,23 +1311,22 @@ public class NewTournamentDialog extends MageDialog { } } this.spnFreeMulligans.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, "0"))); + this.cbMulligan.setSelectedItem(MulliganType.valueByName(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MULLIGUN_TYPE + versionStr, MulliganType.GAME_DEFAULT.toString()))); this.spnNumWins.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, "2"))); this.spnQuitRatio.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, "100"))); + this.spnMinimumRating.setValue(Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, "0"))); TournamentTypeView tournamentType = (TournamentTypeView) cbTournamentType.getSelectedItem(); activatePanelElements(tournamentType); if (tournamentType.isLimited()) { - if (!tournamentType.isDraft()) { - numPlayers = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PLAYERS_SEALED + versionStr, "2")); - setTournamentOptions(numPlayers); - loadBoosterPacks(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_SEALED + versionStr, "")); - } - if (tournamentType.isDraft()) { numPlayers = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PLAYERS_DRAFT + versionStr, "4")); - setTournamentOptions(numPlayers); - if (!(tournamentType.isRandom() || tournamentType.isRichMan())) { + prepareTourneyView(numPlayers); + + if (tournamentType.isRandom() || tournamentType.isRichMan()) { + loadRandomPacks(version); + } else { loadBoosterPacks(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_DRAFT + versionStr, "")); } @@ -1086,6 +1337,10 @@ public class NewTournamentDialog extends MageDialog { break; } } + } else { + numPlayers = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PLAYERS_SEALED + versionStr, "2")); + prepareTourneyView(numPlayers); + loadBoosterPacks(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_SEALED + versionStr, "")); } } this.cbAllowSpectators.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_ALLOW_SPECTATORS + versionStr, "Yes").equals("Yes")); @@ -1094,48 +1349,13 @@ public class NewTournamentDialog extends MageDialog { this.chkRated.setSelected(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEW_TOURNAMENT_RATED + versionStr, "No").equals("Yes")); } - private void loadBoosterPacks(String packString) { - if (!packString.isEmpty()) { - String[] packsArray = packString.substring(1, packString.length() - 1).split(","); - int packNumber = 0; - for (String pack : packsArray) { - packNumber++; - if (this.packPanels.size() >= packNumber - 1) { - JPanel panel = packPanels.get(packNumber - 1); - JComboBox comboBox = findComboInComponent(panel); - - if (comboBox != null) { - ComboBoxModel model = comboBox.getModel(); - int size = model.getSize(); - for (int i = 0; i < size; i++) { - ExpansionInfo element = (ExpansionInfo) model.getElementAt(i); - if (element.getCode().equals(pack.trim())) { - comboBox.setSelectedIndex(i); - break; - } - } - } else { - logger.error("Can't find combo component in " + panel.toString()); - } - } - - } - } + private void onSaveSettings(int version) { + TournamentOptions tOptions = getTournamentOptions(); + onSaveSettings(version, tOptions); } - /** - * Save the settings to java prefs to reload it next time the dialog will be - * created - * - * @param tOptions Tournament options - */ - private void saveTournamentSettingsToPrefs(TournamentOptions tOptions) { - String versionStr = ""; - if (currentSettingVersion == 1) { - versionStr = "1"; - } else if (currentSettingVersion == 2) { - versionStr = "2"; - } + private void onSaveSettings(int version, TournamentOptions tOptions) { + String versionStr = prepareVersionStr(version, true); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NAME + versionStr, tOptions.getName()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PASSWORD + versionStr, tOptions.getPassword()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_TIME_LIMIT + versionStr, Integer.toString(tOptions.getMatchOptions().getPriorityTime())); @@ -1144,8 +1364,10 @@ public class NewTournamentDialog extends MageDialog { } PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_TYPE + versionStr, tOptions.getTournamentType()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS + versionStr, Integer.toString(tOptions.getMatchOptions().getFreeMulligans())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MULLIGUN_TYPE + versionStr, tOptions.getMatchOptions().getMulliganType().toString()); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_NUMBER_OF_WINS + versionStr, Integer.toString(tOptions.getMatchOptions().getWinsNeeded())); PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_QUIT_RATIO + versionStr, Integer.toString(tOptions.getQuitRatio())); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_MINIMUM_RATING + versionStr, Integer.toString(tOptions.getMinimumRating())); if (tOptions.getTournamentType().startsWith("Sealed")) { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_SEALED + versionStr, tOptions.getLimitedOptions().getSetCodes().toString()); @@ -1163,15 +1385,8 @@ public class NewTournamentDialog extends MageDialog { if (deckFile != null && !deckFile.isEmpty()) { PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TABLE_DECK_FILE + versionStr, deckFile); } - - if (tOptions.getLimitedOptions().getIsRandom()) { - // save random boosters to prefs - StringBuilder packlist = new StringBuilder(); - for (String pack : this.randomPackSelector.getSelectedPacks()) { - packlist.append(pack); - packlist.append(';'); - } - PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT + versionStr, packlist.toString()); + if (tOptions.getLimitedOptions().getIsRandom() || tOptions.getLimitedOptions().getIsRichMan()) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_PACKS_RANDOM_DRAFT + versionStr, String.join(";", this.randomPackSelector.getSelectedPacks())); } } PreferencesDialog.saveValue(PreferencesDialog.KEY_NEW_TOURNAMENT_ALLOW_SPECTATORS + versionStr, (tOptions.isWatchingAllowed() ? "Yes" : "No")); @@ -1187,19 +1402,20 @@ public class NewTournamentDialog extends MageDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton btnCancel; private javax.swing.JButton btnOk; - private javax.swing.JButton btnSavedConfiguration1; - private javax.swing.JButton btnSavedConfiguration2; + private javax.swing.JButton btnSettingsLoad; + private javax.swing.JButton btnSettingsSave; private javax.swing.JCheckBox cbAllowSpectators; - private javax.swing.JCheckBox cbPlaneChase; private javax.swing.JComboBox cbDeckType; private javax.swing.JComboBox cbDraftCube; private javax.swing.JComboBox cbDraftTiming; private javax.swing.JComboBox cbGameType; + private javax.swing.JComboBox cbMulligan; + private javax.swing.JCheckBox cbPlaneChase; private javax.swing.JComboBox cbSkillLevel; private javax.swing.JComboBox cbTimeLimit; private javax.swing.JComboBox cbTournamentType; - private javax.swing.JCheckBox chkRollbackTurnsAllowed; private javax.swing.JCheckBox chkRated; + private javax.swing.JCheckBox chkRollbackTurnsAllowed; private javax.swing.JLabel jLabel6; private javax.swing.JLabel lbDeckType; private javax.swing.JLabel lbSkillLevel; @@ -1208,6 +1424,8 @@ public class NewTournamentDialog extends MageDialog { private javax.swing.JLabel lblDraftCube; private javax.swing.JLabel lblFreeMulligans; private javax.swing.JLabel lblGameType; + private javax.swing.JLabel lblMinimumRating; + private javax.swing.JLabel lblMullgian; private javax.swing.JLabel lblName; private javax.swing.JLabel lblNbrPlayers; private javax.swing.JLabel lblNbrSeats; @@ -1217,18 +1435,30 @@ public class NewTournamentDialog extends MageDialog { private javax.swing.JLabel lblPassword; private javax.swing.JLabel lblPlayer1; private javax.swing.JLabel lblQuitRatio; + private javax.swing.JLabel lblSettings; private javax.swing.JLabel lblTournamentType; + private javax.swing.JMenuItem menuLoadSettings1; + private javax.swing.JMenuItem menuLoadSettings2; + private javax.swing.JMenuItem menuLoadSettingsDefault; + private javax.swing.JMenuItem menuLoadSettingsLast; + private javax.swing.JMenuItem menuSaveSettings1; + private javax.swing.JMenuItem menuSaveSettings2; private mage.client.table.NewPlayerPanel player1Panel; private javax.swing.JPanel pnlDraftOptions; private javax.swing.JPanel pnlOtherPlayers; private javax.swing.JPanel pnlPacks; private javax.swing.JPanel pnlPlayers; private javax.swing.JPanel pnlRandomPacks; + private javax.swing.JPopupMenu popupLoadSettings; + private javax.swing.JPopupMenu popupSaveSettings; + private javax.swing.JPopupMenu.Separator separator1; + private javax.swing.JPopupMenu.Separator separator2; private javax.swing.JSpinner spnConstructTime; private javax.swing.JSpinner spnFreeMulligans; + private javax.swing.JSpinner spnMinimumRating; private javax.swing.JSpinner spnNumPlayers; - private javax.swing.JSpinner spnNumSeats; private javax.swing.JSpinner spnNumRounds; + private javax.swing.JSpinner spnNumSeats; private javax.swing.JSpinner spnNumWins; private javax.swing.JSpinner spnQuitRatio; private javax.swing.JTextField txtName; @@ -1236,28 +1466,4 @@ public class NewTournamentDialog extends MageDialog { private org.jdesktop.beansbinding.BindingGroup bindingGroup; // End of variables declaration//GEN-END:variables -} - -class DeckFilter extends FileFilter { - - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - - String ext = null; - String s = f.getName(); - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH); - } - return (ext == null) ? false : ext.equals("dck"); - } - - @Override - public String getDescription() { - return "Deck Files"; - } -} +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java index a9d86c2044..1806ed8492 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickCheckBoxDialog.java @@ -1,37 +1,17 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.dialog; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; -import javax.swing.KeyStroke; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import mage.choices.Choice; import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.MageDialogState; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + /** - * * @author JayDi85 * @author Salco */ @@ -42,28 +22,29 @@ public class PickCheckBoxDialog extends MageDialog { ArrayList allItems = new ArrayList<>(); DefaultListModel dataModel = new DefaultListModel(); CheckBoxList.CheckBoxListModel m_dataModel; - + CheckBoxList tList; - + final private static String HTML_TEMPLATE = "
%s
"; - private void setFocus(CheckBoxList obj){ - + private void setFocus(CheckBoxList obj) { + if (!(obj instanceof java.awt.Component)) { throw new IllegalArgumentException("Must be a java.awt.Component!"); } - this.scrollList.setViewportView((java.awt.Component)obj); - } - private javax.swing.JList get_a_Jlist_from_ScrollListView(){ - return ((javax.swing.JList)this.scrollList.getViewport().getView()); + this.scrollList.setViewportView(obj); } - private void restoreData(Object dataFrom){ + private javax.swing.JList get_a_Jlist_from_ScrollListView() { + return ((javax.swing.JList) this.scrollList.getViewport().getView()); + } + + private void restoreData(Object dataFrom) { this.allItems.forEach((item) -> { - ((CheckBoxList.CheckBoxListModel)dataFrom).addElement(item.getObjectValue()); + ((CheckBoxList.CheckBoxListModel) dataFrom).addElement(item.getObjectValue()); }); } - + public void showDialog(Choice choice) { showDialog(choice, null, null, null); } @@ -75,47 +56,45 @@ public class PickCheckBoxDialog extends MageDialog { public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) { showDialog(choice, objectId, mageDialogState, null); } - + public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) { this.choice = choice; KeyValueItem tempKeyValue; int indexInTList; - + setLabelText(this.labelMessage, choice.getMessage()); setLabelText(this.labelSubMessage, choice.getSubMessage()); - + btCancel.setEnabled(!choice.isRequired()); - + // 2 modes: string or key-values // sore data in allItems for inremental filtering // http://logicbig.com/tutorials/core-java-tutorial/swing/list-filter/ this.allItems.clear(); - if (choice.isKeyChoice()){ - for (Map.Entry entry: choice.getKeyChoices().entrySet()) { - if(tList != null){ + if (choice.isKeyChoice()) { + for (Map.Entry entry : choice.getKeyChoices().entrySet()) { + if (tList != null) { indexInTList = m_dataModel.indexOf(entry.getKey()); - tempKeyValue=new KeyValueItem(entry.getKey(), entry.getValue(),(CheckBoxList.CheckBoxListItem) this.tList.getModel().getElementAt(indexInTList)); - } - else{ - tempKeyValue=new KeyValueItem(entry.getKey(), entry.getValue()); + tempKeyValue = new KeyValueItem(entry.getKey(), entry.getValue(), (CheckBoxList.CheckBoxListItem) this.tList.getModel().getElementAt(indexInTList)); + } else { + tempKeyValue = new KeyValueItem(entry.getKey(), entry.getValue()); } this.allItems.add(tempKeyValue); } } else { - for (String value: choice.getChoices()){ - if(tList != null){ + for (String value : choice.getChoices()) { + if (tList != null) { indexInTList = m_dataModel.indexOf(value); - tempKeyValue=new KeyValueItem(value, value,(CheckBoxList.CheckBoxListItem) tList.getModel().getElementAt(indexInTList)); - } - else{ - tempKeyValue=new KeyValueItem(value, value); + tempKeyValue = new KeyValueItem(value, value, (CheckBoxList.CheckBoxListItem) tList.getModel().getElementAt(indexInTList)); + } else { + tempKeyValue = new KeyValueItem(value, value); } this.allItems.add(tempKeyValue); } } // sorting - if(choice.isSortEnabled()){ + if (choice.isSortEnabled()) { Collections.sort(this.allItems, new Comparator() { @Override public int compare(KeyValueItem o1, KeyValueItem o2) { @@ -125,38 +104,37 @@ public class PickCheckBoxDialog extends MageDialog { } }); } - + // search - if(choice.isSearchEnabled()) - { + if (choice.isSearchEnabled()) { panelSearch.setVisible(true); this.editSearch.setText(choice.getSearchText()); - }else{ + } else { panelSearch.setVisible(false); this.editSearch.setText(""); } - + // listeners for inremental filtering editSearch.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void insertUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void removeUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void removeUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void changedUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void changedUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } }); - + // listeners for select up and down without edit focus lost editSearch.addKeyListener(new KeyListener() { @Override @@ -165,10 +143,10 @@ public class PickCheckBoxDialog extends MageDialog { } @Override - public void keyPressed(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_UP){ + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_UP) { doPrevSelect(); - }else if(e.getKeyCode() == KeyEvent.VK_DOWN){ + } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { doNextSelect(); } } @@ -178,19 +156,19 @@ public class PickCheckBoxDialog extends MageDialog { //System.out.println("released"); } }); - + // listeners double click choose listChoices.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if(e.getClickCount() == 2){ + if (e.getClickCount() == 2) { doChoose(); } } }); - + // listeners for ESC close - if(!choice.isRequired()){ + if (!choice.isRequired()) { String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -201,107 +179,104 @@ public class PickCheckBoxDialog extends MageDialog { } }); } - + // window settings - if (this.isModal()){ + MageFrame.getDesktop().remove(this); + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } - if (mageDialogState != null) { - mageDialogState.setStateToDialog(this); - - } else { - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); - } + if (mageDialogState != null) mageDialogState.setStateToDialog(this); + else this.makeWindowCentered(); // final load loadData(); // start selection - if((startSelectionValue != null)){ + if ((startSelectionValue != null)) { javax.swing.JList currentlistChoices;// = new javax.swing.JList(); - currentlistChoices=this.get_a_Jlist_from_ScrollListView(); + currentlistChoices = this.get_a_Jlist_from_ScrollListView(); /*currentlistChoices = this.listChoices;*/ int selectIndex = -1; - for(int i = 0; i < this.listChoices.getModel().getSize(); i++){ + for (int i = 0; i < this.listChoices.getModel().getSize(); i++) { //KeyValueItem listItem = (KeyValueItem)currentlistChoices.getModel().getElementAt(i); String elementOfList = currentlistChoices.getModel().getElementAt(i).toString(); - if (elementOfList.equals(startSelectionValue)){ + if (elementOfList.equals(startSelectionValue)) { selectIndex = i; break; } } - if(selectIndex >= 0){ - // currentlistChoices=this.get_a_Jlist_from_ScrollListView(); + if (selectIndex >= 0) { + // currentlistChoices=this.get_a_Jlist_from_ScrollListView(); /*currentlistChoices = this.listChoices;*/ - currentlistChoices.setSelectedIndex(selectIndex); - currentlistChoices.ensureIndexIsVisible(selectIndex); + currentlistChoices.setSelectedIndex(selectIndex); + currentlistChoices.ensureIndexIsVisible(selectIndex); } } this.setVisible(true); } - - public void setWindowSize(int width, int heigth){ + + public void setWindowSize(int width, int heigth) { this.setSize(new Dimension(width, heigth)); } - - private void loadData(){ + + private void loadData() { // load data to datamodel after filter or on startup - String filter = choice.getSearchText(); - if (filter == null){ filter = ""; } + String filter = choice.getSearchText(); + if (filter == null) { + filter = ""; + } filter = filter.toLowerCase(); - + this.dataModel.clear(); this.m_dataModel.clear(); - for(KeyValueItem item: this.allItems){ - if(!choice.isSearchEnabled() || item.Value.toLowerCase().contains(filter)){ + for (KeyValueItem item : this.allItems) { + if (!choice.isSearchEnabled() || item.Value.toLowerCase().contains(filter)) { this.dataModel.addElement(item); this.m_dataModel.addElement(item.getObjectValue()); } } } - - private void setLabelText(JLabel label, String text){ - if ((text != null) && !text.equals("")){ + + private void setLabelText(JLabel label, String text) { + if ((text != null) && !text.equals("")) { label.setText(String.format(HTML_TEMPLATE, text)); label.setVisible(true); - }else{ + } else { label.setText(""); label.setVisible(false); - } - } - - private void doNextSelect(){ - int newSel = this.listChoices.getSelectedIndex() + 1; - int maxSel = this.listChoices.getModel().getSize() - 1; - if(newSel <= maxSel){ - this.listChoices.setSelectedIndex(newSel); - this.listChoices.ensureIndexIsVisible(newSel); } } - - private void doPrevSelect(){ - int newSel = this.listChoices.getSelectedIndex() - 1; - if(newSel >= 0){ + + private void doNextSelect() { + int newSel = this.listChoices.getSelectedIndex() + 1; + int maxSel = this.listChoices.getModel().getSize() - 1; + if (newSel <= maxSel) { this.listChoices.setSelectedIndex(newSel); this.listChoices.ensureIndexIsVisible(newSel); } } - private void doChoose(){ - if((tList != null)||(setChoice())){ + private void doPrevSelect() { + int newSel = this.listChoices.getSelectedIndex() - 1; + if (newSel >= 0) { + this.listChoices.setSelectedIndex(newSel); + this.listChoices.ensureIndexIsVisible(newSel); + } + } + + private void doChoose() { + if ((tList != null) || (setChoice())) { this.m_dataModel.clear(); restoreData(this.m_dataModel); this.hideDialog(); } } - - private void doCancel(){ + + private void doCancel() { this.listChoices.clearSelection(); this.choice.clearChoice(); hideDialog(); @@ -309,91 +284,93 @@ public class PickCheckBoxDialog extends MageDialog { /** * Creates new form PickChoiceDialog - * @param list + * + * @param list */ public PickCheckBoxDialog(CheckBoxList list) { initComponents(); - tList=list; - + tList = list; + this.listChoices.setModel(dataModel); this.setModal(true); - if(tList != null) - { + if (tList != null) { this.listChoices.setVisible(false); - - m_dataModel= ( CheckBoxList.CheckBoxListModel )tList.getModel(); + + m_dataModel = (CheckBoxList.CheckBoxListModel) tList.getModel(); tList.setSelectionForeground(Color.BLUE); - - if(this.tList instanceof javax.swing.JList){ - setFocus(tList); - } - + + if (this.tList instanceof javax.swing.JList) { + setFocus(tList); + } + } } + /** * Creates new form PickChoiceDialog */ public PickCheckBoxDialog() { this(null); } - + public boolean setChoice() { - KeyValueItem item = (KeyValueItem)this.listChoices.getSelectedValue(); - + KeyValueItem item = (KeyValueItem) this.listChoices.getSelectedValue(); + // auto select one item (after incemental filtering) - if((item == null) && (this.listChoices.getModel().getSize() == 1)){ + if ((item == null) && (this.listChoices.getModel().getSize() == 1)) { this.listChoices.setSelectedIndex(0); - item = (KeyValueItem)this.listChoices.getSelectedValue(); + item = (KeyValueItem) this.listChoices.getSelectedValue(); } - - if(item != null){ - if(choice.isKeyChoice()){ + + if (item != null) { + if (choice.isKeyChoice()) { choice.setChoiceByKey(item.getKey()); - }else{ + } else { choice.setChoice(item.getKey()); } return true; - }else{ + } else { choice.clearChoice(); return false; } } - - class KeyValueItem - { + + class KeyValueItem { private final String Key; private final String Value; private final CheckBoxList.CheckBoxListItem objectValue; - - public KeyValueItem(String value) { - this(value,null,null); - } - public KeyValueItem(String value, String label) { - this(value,label,null); + + public KeyValueItem(String value) { + this(value, null, null); } - public KeyValueItem(String value, String label,CheckBoxList.CheckBoxListItem object) { + + public KeyValueItem(String value, String label) { + this(value, label, null); + } + + public KeyValueItem(String value, String label, CheckBoxList.CheckBoxListItem object) { this.Key = value; this.Value = label; - this.objectValue = object; + this.objectValue = object; } public String getKey() { return this.Key; - } + } public String getValue() { return this.Value; } - - public Object getObjectValue(){ - return (CheckBoxList.CheckBoxListItem)this.objectValue; + + public Object getObjectValue() { + return this.objectValue; } @Override public String toString() { return this.Value; - } + } } /** @@ -428,20 +405,20 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader); panelHeader.setLayout(panelHeaderLayout); panelHeaderLayout.setHorizontalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING)) - .addGap(0, 0, 0)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING)) + .addGap(0, 0, 0)) ); panelHeaderLayout.setVerticalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(labelMessage) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(labelSubMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(labelMessage) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(labelSubMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)) ); labelSearch.setText("Search:"); @@ -451,28 +428,34 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch); panelSearch.setLayout(panelSearchLayout); panelSearchLayout.setHorizontalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelSearch) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editSearch) - .addGap(0, 0, 0)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelSearch) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editSearch) + .addGap(0, 0, 0)) ); panelSearchLayout.setVerticalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(labelSearch) - .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(labelSearch) + .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3)) ); listChoices.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "item1", "item2", "item3" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } + String[] strings = {"item1", "item2", "item3"}; + + public int getSize() { + return strings.length; + } + + public Object getElementAt(int i) { + return strings[i]; + } }); scrollList.setViewportView(listChoices); @@ -501,25 +484,25 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btOK) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btOK) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 83, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btCancel) - .addComponent(btOK) - .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btCancel) + .addComponent(btOK) + .addComponent(btClear, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); getRootPane().setDefaultButton(btOK); @@ -528,28 +511,28 @@ public class PickCheckBoxDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 240, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java index 9a73c93a9b..572c206fdf 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickChoiceDialog.java @@ -1,36 +1,17 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.client.dialog; -import java.awt.Dimension; -import java.awt.Point; -import java.awt.event.ActionEvent; -import java.awt.event.KeyEvent; -import java.awt.event.KeyListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.*; -import javax.swing.AbstractAction; -import javax.swing.ActionMap; -import javax.swing.DefaultListModel; -import javax.swing.InputMap; -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JLayeredPane; -import javax.swing.KeyStroke; -import javax.swing.event.DocumentEvent; -import javax.swing.event.DocumentListener; import mage.choices.Choice; import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.client.util.gui.MageDialogState; +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.*; +import java.util.*; + /** - * * @author JayDi85 */ @@ -39,7 +20,7 @@ public class PickChoiceDialog extends MageDialog { Choice choice; ArrayList allItems = new ArrayList<>(); DefaultListModel dataModel = new DefaultListModel(); - + final private static String HTML_TEMPLATE = "
%s
"; public void showDialog(Choice choice) { @@ -53,31 +34,31 @@ public class PickChoiceDialog extends MageDialog { public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState) { showDialog(choice, objectId, mageDialogState, null); } - + public void showDialog(Choice choice, UUID objectId, MageDialogState mageDialogState, String startSelectionValue) { this.choice = choice; - + setLabelText(this.labelMessage, choice.getMessage()); setLabelText(this.labelSubMessage, choice.getSubMessage()); - + btCancel.setEnabled(!choice.isRequired()); - + // 2 modes: string or key-values // sore data in allItems for inremental filtering // http://logicbig.com/tutorials/core-java-tutorial/swing/list-filter/ this.allItems.clear(); - if (choice.isKeyChoice()){ - for (Map.Entry entry: choice.getKeyChoices().entrySet()) { - this.allItems.add(new KeyValueItem(entry.getKey(), entry.getValue())); + if (choice.isKeyChoice()) { + for (Map.Entry entry : choice.getKeyChoices().entrySet()) { + this.allItems.add(new KeyValueItem(entry.getKey(), entry.getValue())); } } else { - for (String value: choice.getChoices()){ - this.allItems.add(new KeyValueItem(value, value)); + for (String value : choice.getChoices()) { + this.allItems.add(new KeyValueItem(value, value)); } } // sorting - if(choice.isSortEnabled()){ + if (choice.isSortEnabled()) { Collections.sort(this.allItems, new Comparator() { @Override public int compare(KeyValueItem o1, KeyValueItem o2) { @@ -87,38 +68,37 @@ public class PickChoiceDialog extends MageDialog { } }); } - + // search - if(choice.isSearchEnabled()) - { + if (choice.isSearchEnabled()) { panelSearch.setVisible(true); this.editSearch.setText(choice.getSearchText()); - }else{ + } else { panelSearch.setVisible(false); this.editSearch.setText(""); } - + // listeners for inremental filtering editSearch.getDocument().addDocumentListener(new DocumentListener() { - @Override - public void insertUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void insertUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void removeUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void removeUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } - @Override - public void changedUpdate(DocumentEvent e) { - choice.setSearchText(editSearch.getText()); - loadData(); - } + @Override + public void changedUpdate(DocumentEvent e) { + choice.setSearchText(editSearch.getText()); + loadData(); + } }); - + // listeners for select up and down without edit focus lost editSearch.addKeyListener(new KeyListener() { @Override @@ -127,10 +107,10 @@ public class PickChoiceDialog extends MageDialog { } @Override - public void keyPressed(KeyEvent e) { - if(e.getKeyCode() == KeyEvent.VK_UP){ + public void keyPressed(KeyEvent e) { + if (e.getKeyCode() == KeyEvent.VK_UP) { doPrevSelect(); - }else if(e.getKeyCode() == KeyEvent.VK_DOWN){ + } else if (e.getKeyCode() == KeyEvent.VK_DOWN) { doNextSelect(); } } @@ -140,19 +120,19 @@ public class PickChoiceDialog extends MageDialog { //System.out.println("released"); } }); - + // listeners double click choose listChoices.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - if(e.getClickCount() == 2){ + if (e.getClickCount() == 2) { doChoose(); } } }); - + // listeners for ESC close - if(!choice.isRequired()){ + if (!choice.isRequired()) { String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -163,37 +143,32 @@ public class PickChoiceDialog extends MageDialog { } }); } - + // window settings - if (this.isModal()){ + MageFrame.getDesktop().remove(this); + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } - if (mageDialogState != null) { - mageDialogState.setStateToDialog(this); - - } else { - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); - } + if (mageDialogState != null) mageDialogState.setStateToDialog(this); + else this.makeWindowCentered(); // final load loadData(); // start selection - if((startSelectionValue != null)){ + if ((startSelectionValue != null)) { int selectIndex = -1; - for(int i = 0; i < this.listChoices.getModel().getSize(); i++){ - KeyValueItem listItem = (KeyValueItem)this.listChoices.getModel().getElementAt(i); - if (listItem.Key.equals(startSelectionValue)){ + for (int i = 0; i < this.listChoices.getModel().getSize(); i++) { + KeyValueItem listItem = (KeyValueItem) this.listChoices.getModel().getElementAt(i); + if (listItem.Key.equals(startSelectionValue)) { selectIndex = i; break; } } - if(selectIndex >= 0){ + if (selectIndex >= 0) { this.listChoices.setSelectedIndex(selectIndex); this.listChoices.ensureIndexIsVisible(selectIndex); } @@ -201,59 +176,61 @@ public class PickChoiceDialog extends MageDialog { this.setVisible(true); } - - public void setWindowSize(int width, int heigth){ - this.setSize(new Dimension(width, heigth)); + + public void setWindowSize(int width, int height) { + this.setSize(new Dimension(width, height)); } - - private void loadData(){ + + private void loadData() { // load data to datamodel after filter or on startup String filter = choice.getSearchText(); - if (filter == null){ filter = ""; } + if (filter == null) { + filter = ""; + } filter = filter.toLowerCase(Locale.ENGLISH); - + this.dataModel.clear(); - for(KeyValueItem item: this.allItems){ - if(!choice.isSearchEnabled() || item.Value.toLowerCase(Locale.ENGLISH).contains(filter)){ + for (KeyValueItem item : this.allItems) { + if (!choice.isSearchEnabled() || item.Value.toLowerCase(Locale.ENGLISH).contains(filter)) { this.dataModel.addElement(item); } } } - - private void setLabelText(JLabel label, String text){ - if ((text != null) && !text.equals("")){ + + private void setLabelText(JLabel label, String text) { + if ((text != null) && !text.equals("")) { label.setText(String.format(HTML_TEMPLATE, text)); label.setVisible(true); - }else{ + } else { label.setText(""); label.setVisible(false); - } - } - - private void doNextSelect(){ - int newSel = this.listChoices.getSelectedIndex() + 1; - int maxSel = this.listChoices.getModel().getSize() - 1; - if(newSel <= maxSel){ - this.listChoices.setSelectedIndex(newSel); - this.listChoices.ensureIndexIsVisible(newSel); } } - - private void doPrevSelect(){ - int newSel = this.listChoices.getSelectedIndex() - 1; - if(newSel >= 0){ + + private void doNextSelect() { + int newSel = this.listChoices.getSelectedIndex() + 1; + int maxSel = this.listChoices.getModel().getSize() - 1; + if (newSel <= maxSel) { this.listChoices.setSelectedIndex(newSel); this.listChoices.ensureIndexIsVisible(newSel); } } - private void doChoose(){ - if(setChoice()){ + private void doPrevSelect() { + int newSel = this.listChoices.getSelectedIndex() - 1; + if (newSel >= 0) { + this.listChoices.setSelectedIndex(newSel); + this.listChoices.ensureIndexIsVisible(newSel); + } + } + + private void doChoose() { + if (setChoice()) { this.hideDialog(); } } - - private void doCancel(){ + + private void doCancel() { this.listChoices.clearSelection(); this.choice.clearChoice(); hideDialog(); @@ -267,34 +244,33 @@ public class PickChoiceDialog extends MageDialog { this.listChoices.setModel(dataModel); this.setModal(true); } - + public boolean setChoice() { - KeyValueItem item = (KeyValueItem)this.listChoices.getSelectedValue(); - + KeyValueItem item = (KeyValueItem) this.listChoices.getSelectedValue(); + // auto select one item (after incemental filtering) - if((item == null) && (this.listChoices.getModel().getSize() == 1)){ + if ((item == null) && (this.listChoices.getModel().getSize() == 1)) { this.listChoices.setSelectedIndex(0); - item = (KeyValueItem)this.listChoices.getSelectedValue(); + item = (KeyValueItem) this.listChoices.getSelectedValue(); } - - if(item != null){ - if(choice.isKeyChoice()){ + + if (item != null) { + if (choice.isKeyChoice()) { choice.setChoiceByKey(item.getKey()); - }else{ + } else { choice.setChoice(item.getKey()); } return true; - }else{ + } else { choice.clearChoice(); return false; } } - - class KeyValueItem - { + + class KeyValueItem { private final String Key; private final String Value; - + public KeyValueItem(String value, String label) { this.Key = value; this.Value = label; @@ -311,7 +287,7 @@ public class PickChoiceDialog extends MageDialog { @Override public String toString() { return this.Value; - } + } } /** @@ -345,20 +321,20 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelHeaderLayout = new javax.swing.GroupLayout(panelHeader); panelHeader.setLayout(panelHeaderLayout); panelHeaderLayout.setHorizontalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE) - .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)) - .addGap(0, 0, 0)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGroup(panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(labelMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE) + .addComponent(labelSubMessage, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 210, Short.MAX_VALUE)) + .addGap(0, 0, 0)) ); panelHeaderLayout.setVerticalGroup( - panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelHeaderLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelMessage) - .addGap(0, 0, 0) - .addComponent(labelSubMessage)) + panelHeaderLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelHeaderLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelMessage) + .addGap(0, 0, 0) + .addComponent(labelSubMessage)) ); labelSearch.setText("Search:"); @@ -368,28 +344,34 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelSearchLayout = new javax.swing.GroupLayout(panelSearch); panelSearch.setLayout(panelSearchLayout); panelSearchLayout.setHorizontalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(0, 0, 0) - .addComponent(labelSearch) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(editSearch) - .addGap(0, 0, 0)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(0, 0, 0) + .addComponent(labelSearch) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editSearch) + .addGap(0, 0, 0)) ); panelSearchLayout.setVerticalGroup( - panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelSearchLayout.createSequentialGroup() - .addGap(3, 3, 3) - .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(labelSearch) - .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGap(3, 3, 3)) + panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelSearchLayout.createSequentialGroup() + .addGap(3, 3, 3) + .addGroup(panelSearchLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(labelSearch) + .addComponent(editSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3)) ); listChoices.setModel(new javax.swing.AbstractListModel() { - String[] strings = { "item1", "item2", "item3" }; - public int getSize() { return strings.length; } - public Object getElementAt(int i) { return strings[i]; } + String[] strings = {"item1", "item2", "item3"}; + + public int getSize() { + return strings.length; + } + + public Object getElementAt(int i) { + return strings[i]; + } }); scrollList.setViewportView(listChoices); @@ -410,25 +392,25 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btOK) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btOK) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); - panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {btCancel, btOK}); + panelCommandsLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, btCancel, btOK); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btCancel) - .addComponent(btOK)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btCancel) + .addComponent(btOK)) + .addContainerGap()) ); getRootPane().setDefaultButton(btOK); @@ -436,28 +418,28 @@ public class PickChoiceDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(scrollList, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(panelCommands, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelHeader, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(panelSearch, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelHeader, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelSearch, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(scrollList, javax.swing.GroupLayout.DEFAULT_SIZE, 246, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java index f24f80dc01..98c80bb755 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickNumberDialog.java @@ -1,31 +1,21 @@ - - -/* - * PickNumberDialog.java - * - * Created on Feb 25, 2010, 12:03:39 PM - */ - package mage.client.dialog; -import java.awt.Point; +import mage.client.MageFrame; + +import javax.swing.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; -import javax.swing.*; - -import mage.client.MageFrame; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class PickNumberDialog extends MageDialog { private boolean cancel; - /** Creates new form PickNumberDialog */ + /** + * Creates new form PickNumberDialog + */ public PickNumberDialog() { initComponents(); this.setModal(true); @@ -40,16 +30,18 @@ public class PickNumberDialog extends MageDialog { this.pack(); // window settings - if (this.isModal()){ + MageFrame.getDesktop().remove(this); + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } + this.getRootPane().setDefaultButton(this.btnOk); // restore default button after root panel change (no need actually) // enable spinner's enter key like text (one enter press instead two) // https://stackoverflow.com/questions/3873870/java-keylistener-not-firing-on-jspinner - ((JSpinner.DefaultEditor)this.spnAmount.getEditor()).getTextField().addKeyListener(new KeyListener(){ + ((JSpinner.DefaultEditor) this.spnAmount.getEditor()).getTextField().addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { @@ -68,23 +60,22 @@ public class PickNumberDialog extends MageDialog { }); - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); + this.makeWindowCentered(); // TODO: need to fix focus restore on second popup (it's not focues, test on Manamorphose) this.setVisible(true); } public int getAmount() { - return ((Number)spnAmount.getValue()).intValue(); + return ((Number) spnAmount.getValue()).intValue(); } public boolean isCancel() { return cancel; } - /** This method is called from within the constructor to + /** + * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. @@ -105,7 +96,7 @@ public class PickNumberDialog extends MageDialog { lblMessage.setEditable(false); lblMessage.setText("long text long text long text long text long text long text long text long text"); - lblMessage.setCursor(null ); + lblMessage.setCursor(null); lblMessage.setFocusable(false); lblMessage.setOpaque(false); jScrollPane1.setViewportView(lblMessage); @@ -129,22 +120,22 @@ public class PickNumberDialog extends MageDialog { javax.swing.GroupLayout panelCommandsLayout = new javax.swing.GroupLayout(panelCommands); panelCommands.setLayout(panelCommandsLayout); panelCommandsLayout.setHorizontalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnOk) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnOk) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap()) ); panelCommandsLayout.setVerticalGroup( - panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(panelCommandsLayout.createSequentialGroup() - .addContainerGap() - .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnOk) - .addComponent(btnCancel)) - .addContainerGap()) + panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(panelCommandsLayout.createSequentialGroup() + .addContainerGap() + .addGroup(panelCommandsLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnOk) + .addComponent(btnCancel)) + .addContainerGap()) ); getRootPane().setDefaultButton(btnOk); @@ -152,27 +143,27 @@ public class PickNumberDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE) - .addComponent(panelCommands, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE) + .addComponent(panelCommands, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 117, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(spnAmount, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(panelCommands, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java index 4bed9829d6..263f2694f7 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PickPileDialog.java @@ -1,23 +1,16 @@ - package mage.client.dialog; -import java.awt.BorderLayout; -import java.awt.Component; -import java.awt.Point; -import java.util.UUID; -import javax.swing.JButton; -import javax.swing.JLayeredPane; -import javax.swing.JPanel; import mage.client.MageFrame; import mage.client.cards.BigCard; import mage.client.cards.CardArea; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; import mage.view.CardsView; import org.mage.card.arcane.CardPanel; +import javax.swing.*; +import java.awt.*; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class PickPileDialog extends MageDialog { @@ -76,25 +69,20 @@ public class PickPileDialog extends MageDialog { this.pile1.loadCardsNarrow(pile1, bigCard, gameId); this.pile2.loadCardsNarrow(pile2, bigCard, gameId); - if (getParent() != MageFrame.getDesktop() /*|| this.isClosed*/) { - MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - } + this.setModal(true); pack(); - Point centered = SettingsManager.instance.getComponentPosition(getWidth(), getHeight()); - this.setLocation(centered.x, centered.y); - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, this); - - this.revalidate(); - this.repaint(); - this.setModal(true); - - // window settings - if (this.isModal()){ + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ + } else { MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); } + this.makeWindowCentered(); + + this.revalidate(); // TODO: remove? + this.repaint(); // TODO: remove? this.setVisible(true); } diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form index f122cdc1c4..f51d3fb355 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.form @@ -236,7 +236,7 @@ - + @@ -267,7 +267,7 @@ - + @@ -4071,7 +4071,7 @@
- +
@@ -4079,7 +4079,7 @@ - + @@ -4112,7 +4112,7 @@ - + @@ -4159,7 +4159,7 @@ - + @@ -4170,34 +4170,58 @@ - + - - + + - + - - + + + - + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -4206,8 +4230,8 @@ - - + + @@ -4302,7 +4326,7 @@ - + @@ -4351,7 +4375,7 @@
- +
@@ -4425,6 +4449,7 @@
+ @@ -4451,6 +4476,7 @@ + @@ -4467,7 +4493,7 @@ - + @@ -4608,7 +4634,7 @@ - + @@ -4646,7 +4672,7 @@ - + @@ -5776,7 +5802,7 @@ - + @@ -6009,11 +6035,8 @@ - - - - - + + @@ -6026,24 +6049,26 @@ + - - - - - - - - - - + + + + + + + + + + + - - + + @@ -6052,9 +6077,8 @@ - - - + + @@ -6104,10 +6128,16 @@ + + + + + + + + - - @@ -6116,37 +6146,37 @@ - + - + - + - + - + - + - + @@ -6215,7 +6245,7 @@ - + @@ -6228,12 +6258,12 @@ - + - + @@ -6247,7 +6277,7 @@ - + @@ -6258,6 +6288,19 @@ + + + + + + + + + + + + + diff --git a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java index 4d595a005a..c869f6e827 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/PreferencesDialog.java @@ -1,53 +1,13 @@ - - - /* - * PreferencesDialog.java - * - * Created on 26.06.2011, 16:35:40 - */ package mage.client.dialog; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.image.BufferedImage; -import java.io.File; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.prefs.BackingStoreException; -import java.util.prefs.Preferences; -import javax.swing.BorderFactory; -import javax.swing.DefaultComboBoxModel; -import javax.swing.ImageIcon; -import javax.swing.JCheckBox; -import javax.swing.JComboBox; -import javax.swing.JFileChooser; -import javax.swing.JLabel; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JSlider; -import javax.swing.JTextField; -import javax.swing.KeyStroke; -import javax.swing.border.Border; -import javax.swing.filechooser.FileFilter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.components.KeyBindButton; -import static mage.client.constants.Constants.BATTLEFIELD_FEEDBACK_COLORIZING_MODE_ENABLE_BY_MULTICOLOR; +import mage.client.util.CardLanguage; import mage.client.util.Config; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; import mage.client.util.gui.BufferedImageBuilder; -import static mage.constants.Constants.DEFAULT_AVATAR_ID; -import static mage.constants.Constants.MAX_AVATAR_ID; -import static mage.constants.Constants.MIN_AVATAR_ID; import mage.players.net.UserData; import mage.players.net.UserGroup; import mage.players.net.UserSkipPrioritySteps; @@ -57,10 +17,25 @@ import mage.remote.Session; import mage.view.UserRequestMessage; import org.apache.log4j.Logger; +import javax.swing.*; +import javax.swing.border.Border; +import javax.swing.filechooser.FileFilter; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.io.File; +import java.util.List; +import java.util.*; +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; + +import static mage.client.constants.Constants.BATTLEFIELD_FEEDBACK_COLORIZING_MODE_ENABLE_BY_MULTICOLOR; +import static mage.constants.Constants.*; + /** - * Preferences dialog. - * - * @author nantuko + * @author nantuko, JayDi85 */ public class PreferencesDialog extends javax.swing.JDialog { @@ -144,9 +119,11 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String END_OF_TURN_OTHERS = "endOfTurnOthers"; public static final String KEY_STOP_ATTACK = "stopDeclareAttacksStep"; - public static final String KEY_STOP_BLOCK = "stopDeclareBlockersStep"; + public static final String KEY_STOP_BLOCK_WITH_ANY = "stopDeclareBlockersStepWithAny"; + public static final String KEY_STOP_BLOCK_WITH_ZERO = "stopDeclareBlockersStepWithZero"; public static final String KEY_STOP_ALL_MAIN_PHASES = "stopOnAllMainPhases"; public static final String KEY_STOP_ALL_END_PHASES = "stopOnAllEndPhases"; + public static final String KEY_STOP_NEW_STACK_OBJECTS = "stopOnNewStackObjects"; public static final String KEY_PASS_PRIORITY_CAST = "passPriorityCast"; public static final String KEY_PASS_PRIORITY_ACTIVATION = "passPriorityActivation"; public static final String KEY_AUTO_ORDER_TRIGGER = "autoOrderTrigger"; @@ -215,6 +192,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TABLE_SPECTATORS_ALLOWED = "newTableSpectatorsAllowed"; public static final String KEY_NEW_TABLE_PLANECHASE = "newTablePlaneChase"; public static final String KEY_NEW_TABLE_NUMBER_OF_FREE_MULLIGANS = "newTableNumberOfFreeMulligans"; + public static final String KEY_NEW_TABLE_MULLIGAN_TYPE = "newTableMulliganType"; public static final String KEY_NEW_TABLE_DECK_FILE = "newTableDeckFile"; public static final String KEY_NEW_TABLE_RANGE = "newTableRange"; public static final String KEY_NEW_TABLE_ATTACK_OPTION = "newTableAttackOption"; @@ -222,7 +200,9 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TABLE_NUMBER_PLAYERS = "newTableNumberPlayers"; public static final String KEY_NEW_TABLE_PLAYER_TYPES = "newTablePlayerTypes"; public static final String KEY_NEW_TABLE_QUIT_RATIO = "newTableQuitRatio"; + public static final String KEY_NEW_TABLE_MINIMUM_RATING = "newTableMinimumRating"; public static final String KEY_NEW_TABLE_RATED = "newTableRated"; + public static final String KEY_NEW_TABLE_EDH_POWER_LEVEL = "newTableEdhPowerLevel"; // pref setting for new tournament dialog public static final String KEY_NEW_TOURNAMENT_NAME = "newTournamentName"; @@ -231,6 +211,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TOURNAMENT_CONSTR_TIME = "newTournamentConstructionTime"; public static final String KEY_NEW_TOURNAMENT_TYPE = "newTournamentType"; public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_FREE_MULLIGANS = "newTournamentNumberOfFreeMulligans"; + public static final String KEY_NEW_TOURNAMENT_MULLIGUN_TYPE = "newTournamentMulliganType"; public static final String KEY_NEW_TOURNAMENT_NUMBER_OF_WINS = "newTournamentNumberOfWins"; public static final String KEY_NEW_TOURNAMENT_PACKS_SEALED = "newTournamentPacksSealed"; public static final String KEY_NEW_TOURNAMENT_PACKS_DRAFT = "newTournamentPacksDraft"; @@ -243,6 +224,7 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_NEW_TOURNAMENT_ALLOW_ROLLBACKS = "newTournamentAllowRollbacks"; public static final String KEY_NEW_TOURNAMENT_DECK_FILE = "newTournamentDeckFile"; public static final String KEY_NEW_TOURNAMENT_QUIT_RATIO = "newTournamentQuitRatio"; + public static final String KEY_NEW_TOURNAMENT_MINIMUM_RATING = "newTournamentMinimumRating"; public static final String KEY_NEW_TOURNAMENT_RATED = "newTournamentRated"; // pref setting for deck generator @@ -289,8 +271,14 @@ public class PreferencesDialog extends javax.swing.JDialog { public static final String KEY_PROXY_PSWD = "proxyPassword"; public static final String KEY_CONNECTION_URL_SERVER_LIST = "connectionURLServerList"; + // news + public static final String KEY_NEWS_PAGE_LAST_VERSION = "newsPageLastVersion"; + public static final String KEY_NEWS_PAGE_COOKIES = "newsPageCookies"; + // controls + public static final String KEY_CONTROL_MODIFIER_POSTFIX = "_modifier"; public static final String KEY_CONTROL_TOGGLE_MACRO = "controlToggleMacro"; + public static final String KEY_CONTROL_SWITCH_CHAT = "controlSwitchChat"; public static final String KEY_CONTROL_CONFIRM = "controlConfirm"; public static final String KEY_CONTROL_CANCEL_SKIP = "controlCancelSkip"; public static final String KEY_CONTROL_NEXT_TURN = "controlNextTurn"; @@ -336,6 +324,10 @@ public class PreferencesDialog extends javax.swing.JDialog { fc_i.addChoosableFileFilter(new ImageFileFilter()); } + public static CardLanguage getPrefImagesLanguage() { + return CardLanguage.valueByCode(getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode())); + } + private static class ImageFileFilter extends FileFilter { @Override @@ -345,10 +337,8 @@ public class PreferencesDialog extends javax.swing.JDialog { return true; } if (filename != null) { - if (filename.endsWith(".jpg") || filename.endsWith(".jpeg") - || filename.endsWith(".png") || filename.endsWith(".bmp")) { - return true; - } + return filename.endsWith(".jpg") || filename.endsWith(".jpeg") + || filename.endsWith(".png") || filename.endsWith(".bmp"); } return false; } @@ -372,7 +362,7 @@ public class PreferencesDialog extends javax.swing.JDialog { cbProxyType.setModel(new DefaultComboBoxModel<>(Connection.ProxyType.values())); addAvatars(); - cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(new String[]{"en", "de", "fr", "it", "es", "pt", "jp", "cn", "ru", "tw", "ko"})); + cbPreferedImageLanguage.setModel(new DefaultComboBoxModel<>(CardLanguage.toList())); cbNumberOfDownloadThreads.setModel(new DefaultComboBoxModel<>(new String[]{"10", "9", "8", "7", "6", "5", "4", "3", "2", "1"})); } @@ -465,7 +455,9 @@ public class PreferencesDialog extends javax.swing.JDialog { checkBoxEndTurnOthers = new javax.swing.JCheckBox(); phases_stopSettings = new javax.swing.JPanel(); cbStopAttack = new javax.swing.JCheckBox(); - cbStopBlock = new javax.swing.JCheckBox(); + cbStopBlockWithAny = new javax.swing.JCheckBox(); + cbStopBlockWithZero = new javax.swing.JCheckBox(); + cbStopOnNewStackObjects = new javax.swing.JCheckBox(); cbStopOnAllMain = new javax.swing.JCheckBox(); cbStopOnAllEnd = new javax.swing.JCheckBox(); cbPassPriorityCast = new javax.swing.JCheckBox(); @@ -576,6 +568,8 @@ public class PreferencesDialog extends javax.swing.JDialog { bttnResetControls = new javax.swing.JButton(); labelToggleRecordMacro = new javax.swing.JLabel(); keyToggleRecordMacro = new KeyBindButton(this, KEY_CONTROL_TOGGLE_MACRO); + labelSwitchChat = new javax.swing.JLabel(); + keySwitchChat = new KeyBindButton(this, KEY_CONTROL_SWITCH_CHAT); saveButton = new javax.swing.JButton(); exitButton = new javax.swing.JButton(); @@ -616,24 +610,24 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout main_gamelogLayout = new org.jdesktop.layout.GroupLayout(main_gamelog); main_gamelog.setLayout(main_gamelogLayout); main_gamelogLayout.setHorizontalGroup( - main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_gamelogLayout.createSequentialGroup() - .addContainerGap() - .add(main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(cbDraftLogAutoSave) - .add(cbGameJsonLogAutoSave) - .add(cbGameLogAutoSave, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 505, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gamelogLayout.createSequentialGroup() + .addContainerGap() + .add(main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(cbDraftLogAutoSave) + .add(cbGameJsonLogAutoSave) + .add(cbGameLogAutoSave, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 505, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_gamelogLayout.setVerticalGroup( - main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_gamelogLayout.createSequentialGroup() - .add(cbGameLogAutoSave) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbDraftLogAutoSave) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbGameJsonLogAutoSave) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + main_gamelogLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gamelogLayout.createSequentialGroup() + .add(cbGameLogAutoSave) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbDraftLogAutoSave) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbGameJsonLogAutoSave) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_card.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card")); @@ -675,29 +669,29 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout main_cardLayout = new org.jdesktop.layout.GroupLayout(main_card); main_card.setLayout(main_cardLayout); main_cardLayout.setHorizontalGroup( - main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_cardLayout.createSequentialGroup() - .add(6, 6, 6) - .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .add(main_cardLayout.createSequentialGroup() - .add(showCardName) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(showFullImagePath))) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_cardLayout.createSequentialGroup() + .add(6, 6, 6) + .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(tooltipDelayLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .add(main_cardLayout.createSequentialGroup() + .add(showCardName) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(showFullImagePath))) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_cardLayout.setVerticalGroup( - main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_cardLayout.createSequentialGroup() - .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(showCardName) - .add(showFullImagePath)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tooltipDelayLabel) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_cardLayout.createSequentialGroup() + .add(main_cardLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(showCardName) + .add(showFullImagePath)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tooltipDelayLabel) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tooltipDelay, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_game.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Game")); @@ -784,48 +778,48 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout main_gameLayout = new org.jdesktop.layout.GroupLayout(main_game); main_game.setLayout(main_gameLayout); main_gameLayout.setHorizontalGroup( - main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_gameLayout.createSequentialGroup() - .addContainerGap() - .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_gameLayout.createSequentialGroup() - .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) - .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .add(0, 0, Short.MAX_VALUE)) - .add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gameLayout.createSequentialGroup() + .addContainerGap() + .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gameLayout.createSequentialGroup() + .add(main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(showPlayerNamesPermanently, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(nonLandPermanentsInOnePile, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbConfirmEmptyManaPool, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbAllowRequestToShowHandCards, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbShowStormCounter, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbAskMoveToGraveOrder, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(showAbilityPickerForced, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .add(0, 0, Short.MAX_VALUE)) + .add(displayLifeOnAvatar, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); main_gameLayout.setVerticalGroup( - main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_gameLayout.createSequentialGroup() - .add(nonLandPermanentsInOnePile) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(showPlayerNamesPermanently) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(displayLifeOnAvatar) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(showAbilityPickerForced) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbAllowRequestToShowHandCards) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbShowStormCounter) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbConfirmEmptyManaPool) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbAskMoveToGraveOrder)) + main_gameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_gameLayout.createSequentialGroup() + .add(nonLandPermanentsInOnePile) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(showPlayerNamesPermanently) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(displayLifeOnAvatar) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(showAbilityPickerForced) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbAllowRequestToShowHandCards) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbShowStormCounter) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbConfirmEmptyManaPool) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbAskMoveToGraveOrder)) ); nonLandPermanentsInOnePile.getAccessibleContext().setAccessibleName("nonLandPermanentsInOnePile"); main_battlefield.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Battlefield")); - cbBattlefieldFeedbackColorizingMode.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Disable colorizing", "Enable one color for all phases", "Enable multicolor for different phases" })); + cbBattlefieldFeedbackColorizingMode.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Disable colorizing", "Enable one color for all phases", "Enable multicolor for different phases"})); cbBattlefieldFeedbackColorizingMode.setToolTipText("Battlefield feedback panel colorizing on your turn (e.g. use green color if you must select card or answer to request)"); cbBattlefieldFeedbackColorizingMode.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -839,46 +833,46 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout main_battlefieldLayout = new org.jdesktop.layout.GroupLayout(main_battlefield); main_battlefield.setLayout(main_battlefieldLayout); main_battlefieldLayout.setHorizontalGroup( - main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_battlefieldLayout.createSequentialGroup() - .addContainerGap() - .add(lblBattlefieldFeedbackColorizingMode) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbBattlefieldFeedbackColorizingMode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 278, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_battlefieldLayout.createSequentialGroup() + .addContainerGap() + .add(lblBattlefieldFeedbackColorizingMode) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbBattlefieldFeedbackColorizingMode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 278, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_battlefieldLayout.setVerticalGroup( - main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(lblBattlefieldFeedbackColorizingMode) - .add(cbBattlefieldFeedbackColorizingMode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(main_battlefieldLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lblBattlefieldFeedbackColorizingMode) + .add(cbBattlefieldFeedbackColorizingMode, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) ); org.jdesktop.layout.GroupLayout tabMainLayout = new org.jdesktop.layout.GroupLayout(tabMain); tabMain.setLayout(tabMainLayout); tabMainLayout.setHorizontalGroup( - tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabMainLayout.createSequentialGroup() - .addContainerGap() - .add(tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(org.jdesktop.layout.GroupLayout.TRAILING, main_card, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(org.jdesktop.layout.GroupLayout.TRAILING, main_gamelog, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(main_game, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(org.jdesktop.layout.GroupLayout.TRAILING, main_battlefield, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabMainLayout.createSequentialGroup() + .addContainerGap() + .add(tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, main_card, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, main_gamelog, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(main_game, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, main_battlefield, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); tabMainLayout.setVerticalGroup( - tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabMainLayout.createSequentialGroup() - .addContainerGap() - .add(main_card, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + tabMainLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabMainLayout.createSequentialGroup() + .addContainerGap() + .add(main_card, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(main_game, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(main_gamelog, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(main_battlefield, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); main_card.getAccessibleContext().setAccessibleName("Game panel"); @@ -888,18 +882,18 @@ public class PreferencesDialog extends javax.swing.JDialog { tabGuiSize.setMaximumSize(new java.awt.Dimension(527, 423)); tabGuiSize.setMinimumSize(new java.awt.Dimension(527, 423)); java.awt.GridBagLayout tabGuiSizeLayout = new java.awt.GridBagLayout(); - tabGuiSizeLayout.columnWidths = new int[] {0}; - tabGuiSizeLayout.rowHeights = new int[] {0, 20, 0}; - tabGuiSizeLayout.columnWeights = new double[] {1.0}; - tabGuiSizeLayout.rowWeights = new double[] {1.0, 0.0, 1.0}; + tabGuiSizeLayout.columnWidths = new int[]{0}; + tabGuiSizeLayout.rowHeights = new int[]{0, 20, 0}; + tabGuiSizeLayout.columnWeights = new double[]{1.0}; + tabGuiSizeLayout.rowWeights = new double[]{1.0, 0.0, 1.0}; tabGuiSize.setLayout(tabGuiSizeLayout); guiSizeBasic.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Size basic elements")); guiSizeBasic.setMinimumSize(new java.awt.Dimension(600, 180)); guiSizeBasic.setPreferredSize(new java.awt.Dimension(600, 180)); java.awt.GridBagLayout guiSizeBasicLayout = new java.awt.GridBagLayout(); - guiSizeBasicLayout.columnWeights = new double[] {1.0, 1.0, 1.0}; - guiSizeBasicLayout.rowWeights = new double[] {1.0, 0.2, 1.0, 0.2}; + guiSizeBasicLayout.columnWeights = new double[]{1.0, 1.0, 1.0}; + guiSizeBasicLayout.rowWeights = new double[]{1.0, 0.2, 1.0, 0.2}; guiSizeBasic.setLayout(guiSizeBasicLayout); sliderFontSize.setMajorTickSpacing(5); @@ -1088,8 +1082,8 @@ public class PreferencesDialog extends javax.swing.JDialog { guiSizeGame.setMinimumSize(new java.awt.Dimension(600, 180)); guiSizeGame.setPreferredSize(new java.awt.Dimension(600, 180)); java.awt.GridBagLayout guiSizeGameLayout = new java.awt.GridBagLayout(); - guiSizeGameLayout.columnWeights = new double[] {1.0, 1.0, 1.0, 1.0}; - guiSizeGameLayout.rowWeights = new double[] {1.0, 0.2, 1.0, 0.2}; + guiSizeGameLayout.columnWeights = new double[]{1.0, 1.0, 1.0, 1.0}; + guiSizeGameLayout.rowWeights = new double[]{1.0, 0.2, 1.0, 0.2}; guiSizeGame.setLayout(guiSizeGameLayout); sliderCardSizeHand.setMajorTickSpacing(5); @@ -1310,7 +1304,7 @@ public class PreferencesDialog extends javax.swing.JDialog { tabsPanel.addTab("GUI Size", tabGuiSize); - jLabelHeadLine.setText("Choose phases your game will stop on if not skipped by a skip action (e.g. F6):"); + jLabelHeadLine.setText("Default stop steps if not skip buttons activated (e.g. F6):"); jLabelYourTurn.setText("Your turn"); @@ -1320,7 +1314,7 @@ public class PreferencesDialog extends javax.swing.JDialog { jLabelDraw.setText("Draw:"); - jLabelMain1.setText("Main:"); + jLabelMain1.setText("Main 1:"); jLabelBeforeCombat.setText("Before combat:"); @@ -1330,12 +1324,12 @@ public class PreferencesDialog extends javax.swing.JDialog { jLabelEndOfTurn.setText("End of turn:"); - phases_stopSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Stop settings")); - phases_stopSettings.setLayout(new java.awt.GridLayout(7, 1)); + phases_stopSettings.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "SKIP settings")); + phases_stopSettings.setLayout(new java.awt.GridLayout(9, 1)); cbStopAttack.setSelected(true); - cbStopAttack.setText("Stop on declare attackers step if you skip steps (F4/F5/F7) and attackers are available"); - cbStopAttack.setToolTipText("If you use F4, F5 or F7 to skip steps, you stop on declare attackers step if attackers are available. If this option is not activated, you also skip the declare attackers step with this actions. F9 does always skip the declare attackers step."); + cbStopAttack.setText("STOP skips on declare attackers if attackers are available"); + cbStopAttack.setToolTipText(""); cbStopAttack.setActionCommand(""); cbStopAttack.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -1344,18 +1338,40 @@ public class PreferencesDialog extends javax.swing.JDialog { }); phases_stopSettings.add(cbStopAttack); - cbStopBlock.setText("Stop on your declare blockers step also if no blockers available"); - cbStopBlock.setToolTipText("Also if you have no blockers to declare, the game stops at the declare blockers step."); - cbStopBlock.setActionCommand(""); - cbStopBlock.addActionListener(new java.awt.event.ActionListener() { + cbStopBlockWithAny.setSelected(true); + cbStopBlockWithAny.setText("STOP skips on declare blockers if ANY blockers are available"); + cbStopBlockWithAny.setToolTipText(""); + cbStopBlockWithAny.setActionCommand(""); + cbStopBlockWithAny.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - cbStopBlockActionPerformed(evt); + cbStopBlockWithAnyActionPerformed(evt); } }); - phases_stopSettings.add(cbStopBlock); + phases_stopSettings.add(cbStopBlockWithAny); - cbStopOnAllMain.setText("Skip with F7 to next main phase (if not activated skip always to your next main phase)"); - cbStopOnAllMain.setToolTipText("If activated F7 skips to next main phases (regardless of the active players)."); + cbStopBlockWithZero.setText("STOP skips on declare blockers if ZERO blockers are available"); + cbStopBlockWithZero.setToolTipText(""); + cbStopBlockWithZero.setActionCommand(""); + cbStopBlockWithZero.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbStopBlockWithZeroActionPerformed(evt); + } + }); + phases_stopSettings.add(cbStopBlockWithZero); + + cbStopOnNewStackObjects.setText("Skip to STACK resolved (F10): stop on new objects added (on) or stop until empty (off)"); + cbStopOnNewStackObjects.setToolTipText(""); + cbStopOnNewStackObjects.setActionCommand(""); + cbStopOnNewStackObjects.setPreferredSize(new java.awt.Dimension(300, 25)); + cbStopOnNewStackObjects.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cbStopOnNewStackObjectsActionPerformed(evt); + } + }); + phases_stopSettings.add(cbStopOnNewStackObjects); + + cbStopOnAllMain.setText("Skip to MAIN step (F7): stop on any main steps (on) or stop on your main step (off)"); + cbStopOnAllMain.setToolTipText(""); cbStopOnAllMain.setActionCommand(""); cbStopOnAllMain.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -1364,8 +1380,8 @@ public class PreferencesDialog extends javax.swing.JDialog { }); phases_stopSettings.add(cbStopOnAllMain); - cbStopOnAllEnd.setText("Skip with F5 to next end step (if not activated only to end steps of opponents)"); - cbStopOnAllEnd.setToolTipText("If activated - F5 skips to the next end step (regardless of the current player)"); + cbStopOnAllEnd.setText("Skip to END step (F5): stop on any end steps (on) or stop on opponents end step (off)"); + cbStopOnAllEnd.setToolTipText(""); cbStopOnAllEnd.setActionCommand(""); cbStopOnAllEnd.setPreferredSize(new java.awt.Dimension(300, 25)); cbStopOnAllEnd.addActionListener(new java.awt.event.ActionListener() { @@ -1411,120 +1427,120 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout tabPhasesLayout = new org.jdesktop.layout.GroupLayout(tabPhases); tabPhases.setLayout(tabPhasesLayout); tabPhasesLayout.setHorizontalGroup( - tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .add(20, 20, 20) + tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(jLabelUpkeep) - .add(jLabelBeforeCombat) - .add(jLabelEndofCombat) - .add(jLabelMain2) - .add(jLabelEndOfTurn)) - .add(77, 77, 77) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .add(2, 2, 2) - .add(jLabelYourTurn) - .add(32, 32, 32) - .add(jLabelOpponentsTurn)) - .add(tabPhasesLayout.createSequentialGroup() - .add(13, 13, 13) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(checkBoxDrawYou) - .add(checkBoxUpkeepYou) - .add(checkBoxMainYou) - .add(checkBoxBeforeCYou) - .add(checkBoxEndOfCYou) - .add(checkBoxMain2You) - .add(checkBoxEndTurnYou)) - .add(78, 78, 78) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(checkBoxUpkeepOthers) - .add(checkBoxBeforeCOthers) - .add(checkBoxMainOthers) - .add(checkBoxEndOfCOthers) - .add(checkBoxDrawOthers) - .add(checkBoxMain2Others) - .add(checkBoxEndTurnOthers))))) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(org.jdesktop.layout.GroupLayout.LEADING, jLabelMain1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(org.jdesktop.layout.GroupLayout.LEADING, jLabelDraw, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) - .add(tabPhasesLayout.createSequentialGroup() - .addContainerGap() - .add(jLabelHeadLine))) - .add(0, 0, Short.MAX_VALUE)) - .add(tabPhasesLayout.createSequentialGroup() - .addContainerGap() - .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap()) + .add(tabPhasesLayout.createSequentialGroup() + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() + .add(20, 20, 20) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jLabelUpkeep) + .add(jLabelBeforeCombat) + .add(jLabelEndofCombat) + .add(jLabelMain2) + .add(jLabelEndOfTurn)) + .add(77, 77, 77) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() + .add(2, 2, 2) + .add(jLabelYourTurn) + .add(32, 32, 32) + .add(jLabelOpponentsTurn)) + .add(tabPhasesLayout.createSequentialGroup() + .add(13, 13, 13) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(checkBoxDrawYou) + .add(checkBoxUpkeepYou) + .add(checkBoxMainYou) + .add(checkBoxBeforeCYou) + .add(checkBoxEndOfCYou) + .add(checkBoxMain2You) + .add(checkBoxEndTurnYou)) + .add(78, 78, 78) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(checkBoxUpkeepOthers) + .add(checkBoxBeforeCOthers) + .add(checkBoxMainOthers) + .add(checkBoxEndOfCOthers) + .add(checkBoxDrawOthers) + .add(checkBoxMain2Others) + .add(checkBoxEndTurnOthers))))) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(org.jdesktop.layout.GroupLayout.LEADING, jLabelMain1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.LEADING, jLabelDraw, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .add(tabPhasesLayout.createSequentialGroup() + .addContainerGap() + .add(jLabelHeadLine))) + .add(0, 0, Short.MAX_VALUE)) + .add(tabPhasesLayout.createSequentialGroup() + .addContainerGap() + .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) ); tabPhasesLayout.setVerticalGroup( - tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .addContainerGap() - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(tabPhasesLayout.createSequentialGroup() - .add(jLabelOpponentsTurn) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(checkBoxUpkeepOthers)) - .add(tabPhasesLayout.createSequentialGroup() - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(tabPhasesLayout.createSequentialGroup() - .add(jLabelHeadLine) - .add(20, 20, 20)) - .add(jLabelYourTurn)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(checkBoxUpkeepYou) - .add(jLabelUpkeep)))) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(jLabelDraw) - .add(checkBoxDrawYou) - .add(checkBoxDrawOthers)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(jLabelMain1) - .add(checkBoxMainYou) - .add(checkBoxMainOthers)) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabPhasesLayout.createSequentialGroup() - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabelBeforeCombat) - .add(org.jdesktop.layout.GroupLayout.TRAILING, checkBoxBeforeCYou))) - .add(tabPhasesLayout.createSequentialGroup() - .add(6, 6, 6) - .add(checkBoxBeforeCOthers))) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(jLabelEndofCombat) - .add(checkBoxEndOfCYou) - .add(checkBoxEndOfCOthers)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(jLabelMain2) - .add(checkBoxMain2You) - .add(checkBoxMain2Others)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(checkBoxEndTurnYou) - .add(jLabelEndOfTurn) - .add(checkBoxEndTurnOthers)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(170, Short.MAX_VALUE)) + tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() + .addContainerGap() + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(tabPhasesLayout.createSequentialGroup() + .add(jLabelOpponentsTurn) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(checkBoxUpkeepOthers)) + .add(tabPhasesLayout.createSequentialGroup() + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(tabPhasesLayout.createSequentialGroup() + .add(jLabelHeadLine) + .add(20, 20, 20)) + .add(jLabelYourTurn)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(checkBoxUpkeepYou) + .add(jLabelUpkeep)))) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(jLabelDraw) + .add(checkBoxDrawYou) + .add(checkBoxDrawOthers)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(jLabelMain1) + .add(checkBoxMainYou) + .add(checkBoxMainOthers)) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabPhasesLayout.createSequentialGroup() + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, jLabelBeforeCombat) + .add(org.jdesktop.layout.GroupLayout.TRAILING, checkBoxBeforeCYou))) + .add(tabPhasesLayout.createSequentialGroup() + .add(6, 6, 6) + .add(checkBoxBeforeCOthers))) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(jLabelEndofCombat) + .add(checkBoxEndOfCYou) + .add(checkBoxEndOfCOthers)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(jLabelMain2) + .add(checkBoxMain2You) + .add(checkBoxMain2Others)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabPhasesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(checkBoxEndTurnYou) + .add(jLabelEndOfTurn) + .add(checkBoxEndTurnOthers)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(phases_stopSettings, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(160, Short.MAX_VALUE)) ); tabsPanel.addTab("Phases & Priority", tabPhases); - panelCardImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card images:")); + panelCardImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card images")); cbUseDefaultImageFolder.setText("Use default location to save images"); cbUseDefaultImageFolder.addActionListener(new java.awt.event.ActionListener() { @@ -1556,73 +1572,75 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); - cbPreferedImageLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + cbPreferedImageLanguage.setMaximumRowCount(20); + cbPreferedImageLanguage.setModel(new javax.swing.DefaultComboBoxModel<>(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); labelPreferedImageLanguage.setText("Prefered image language:"); labelPreferedImageLanguage.setFocusable(false); labelNumberOfDownloadThreads.setText("Number of download threads:"); - cbNumberOfDownloadThreads.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Item 1", "Item 2", "Item 3", "Item 4" })); + cbNumberOfDownloadThreads.setMaximumRowCount(20); + cbNumberOfDownloadThreads.setModel(new javax.swing.DefaultComboBoxModel(new String[]{"Item 1", "Item 2", "Item 3", "Item 4"})); org.jdesktop.layout.GroupLayout panelCardImagesLayout = new org.jdesktop.layout.GroupLayout(panelCardImages); panelCardImages.setLayout(panelCardImagesLayout); panelCardImagesLayout.setHorizontalGroup( - panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelCardImagesLayout.createSequentialGroup() - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelCardImagesLayout.createSequentialGroup() - .addContainerGap() - .add(txtImageFolderPath) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(btnBrowseImageLocation)) - .add(panelCardImagesLayout.createSequentialGroup() - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(panelCardImagesLayout.createSequentialGroup() - .add(cbCheckForNewImages) - .add(147, 147, 147)) - .add(org.jdesktop.layout.GroupLayout.LEADING, panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(panelCardImagesLayout.createSequentialGroup() - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(org.jdesktop.layout.GroupLayout.LEADING, panelCardImagesLayout.createSequentialGroup() + panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelCardImagesLayout.createSequentialGroup() + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelCardImagesLayout.createSequentialGroup() .addContainerGap() - .add(labelPreferedImageLanguage)) - .add(org.jdesktop.layout.GroupLayout.LEADING, cbSaveToZipFiles)) - .add(20, 20, 20) - .add(cbPreferedImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(panelCardImagesLayout.createSequentialGroup() - .addContainerGap() - .add(labelNumberOfDownloadThreads) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) - .add(cbUseDefaultImageFolder)) - .add(0, 308, Short.MAX_VALUE))) - .addContainerGap()) + .add(txtImageFolderPath) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnBrowseImageLocation)) + .add(panelCardImagesLayout.createSequentialGroup() + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(panelCardImagesLayout.createSequentialGroup() + .add(cbCheckForNewImages) + .add(147, 147, 147)) + .add(org.jdesktop.layout.GroupLayout.LEADING, panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(panelCardImagesLayout.createSequentialGroup() + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(org.jdesktop.layout.GroupLayout.LEADING, panelCardImagesLayout.createSequentialGroup() + .addContainerGap() + .add(labelPreferedImageLanguage)) + .add(org.jdesktop.layout.GroupLayout.LEADING, cbSaveToZipFiles)) + .add(20, 20, 20) + .add(cbPreferedImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(panelCardImagesLayout.createSequentialGroup() + .addContainerGap() + .add(labelNumberOfDownloadThreads) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 153, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) + .add(cbUseDefaultImageFolder)) + .add(0, 391, Short.MAX_VALUE))) + .addContainerGap()) ); panelCardImagesLayout.setVerticalGroup( - panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelCardImagesLayout.createSequentialGroup() - .add(cbUseDefaultImageFolder) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtImageFolderPath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(btnBrowseImageLocation)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(cbCheckForNewImages) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbSaveToZipFiles) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelNumberOfDownloadThreads) - .add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(cbPreferedImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(labelPreferedImageLanguage))) + panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelCardImagesLayout.createSequentialGroup() + .add(cbUseDefaultImageFolder) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtImageFolderPath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnBrowseImageLocation)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(cbCheckForNewImages) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbSaveToZipFiles) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelNumberOfDownloadThreads) + .add(cbNumberOfDownloadThreads, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelCardImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(cbPreferedImageLanguage, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(labelPreferedImageLanguage))) ); - panelBackgroundImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Background images setting:")); + panelBackgroundImages.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Background images")); cbUseDefaultBackground.setText("Use default image"); cbUseDefaultBackground.addActionListener(new java.awt.event.ActionListener() { @@ -1678,57 +1696,57 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout panelBackgroundImagesLayout = new org.jdesktop.layout.GroupLayout(panelBackgroundImages); panelBackgroundImages.setLayout(panelBackgroundImagesLayout); panelBackgroundImagesLayout.setHorizontalGroup( - panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .add(19, 19, 19) - .add(jLabel14)) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .add(25, 25, 25) - .add(jLabel15))) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(txtBackgroundImagePath) - .add(txtBattlefieldImagePath)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(org.jdesktop.layout.GroupLayout.TRAILING, btnBrowseBackgroundImage) - .add(org.jdesktop.layout.GroupLayout.TRAILING, btnBrowseBattlefieldImage))) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(cbUseRandomBattleImage) - .add(cbUseDefaultBattleImage) - .add(cbUseDefaultBackground)) - .add(0, 0, Short.MAX_VALUE))) - .addContainerGap()) + panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .add(19, 19, 19) + .add(jLabel14)) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .add(25, 25, 25) + .add(jLabel15))) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(txtBackgroundImagePath) + .add(txtBattlefieldImagePath)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, btnBrowseBackgroundImage) + .add(org.jdesktop.layout.GroupLayout.TRAILING, btnBrowseBattlefieldImage))) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(cbUseRandomBattleImage) + .add(cbUseDefaultBattleImage) + .add(cbUseDefaultBackground)) + .add(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); panelBackgroundImagesLayout.setVerticalGroup( - panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelBackgroundImagesLayout.createSequentialGroup() - .addContainerGap() - .add(cbUseDefaultBackground) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtBackgroundImagePath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(btnBrowseBackgroundImage) - .add(jLabel14)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(cbUseDefaultBattleImage) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(cbUseRandomBattleImage) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtBattlefieldImagePath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(btnBrowseBattlefieldImage) - .add(jLabel15))) + panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelBackgroundImagesLayout.createSequentialGroup() + .addContainerGap() + .add(cbUseDefaultBackground) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtBackgroundImagePath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnBrowseBackgroundImage) + .add(jLabel14)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(cbUseDefaultBattleImage) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(cbUseRandomBattleImage) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(panelBackgroundImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtBattlefieldImagePath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnBrowseBattlefieldImage) + .add(jLabel15))) ); - jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card rendering:")); + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), "Card styles (restart xmage to apply new settings)")); - cbCardRenderImageFallback.setText("Fall back to plain image based rendering"); + cbCardRenderImageFallback.setText("Render mode: MTGO style (off) or IMAGE style (on)"); cbCardRenderImageFallback.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cbCardRenderImageFallbackActionPerformed(evt); @@ -1752,47 +1770,47 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel1Layout = new org.jdesktop.layout.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(jPanel1Layout.createSequentialGroup() - .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(cbCardRenderImageFallback) - .add(cbCardRenderShowReminderText) - .add(cbCardRenderHideSetSymbol)) - .add(0, 0, Short.MAX_VALUE)) + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(cbCardRenderImageFallback) + .add(cbCardRenderShowReminderText) + .add(cbCardRenderHideSetSymbol)) + .add(0, 0, Short.MAX_VALUE)) ); jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(jPanel1Layout.createSequentialGroup() - .add(cbCardRenderImageFallback) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbCardRenderShowReminderText) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(cbCardRenderHideSetSymbol) - .add(0, 0, Short.MAX_VALUE)) + jPanel1Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(jPanel1Layout.createSequentialGroup() + .add(cbCardRenderImageFallback) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbCardRenderShowReminderText) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(cbCardRenderHideSetSymbol) + .add(0, 0, Short.MAX_VALUE)) ); org.jdesktop.layout.GroupLayout tabImagesLayout = new org.jdesktop.layout.GroupLayout(tabImages); tabImages.setLayout(tabImagesLayout); tabImagesLayout.setHorizontalGroup( - tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabImagesLayout.createSequentialGroup() - .addContainerGap() - .add(tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(panelCardImages, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabImagesLayout.createSequentialGroup() + .addContainerGap() + .add(tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(panelCardImages, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); tabImagesLayout.setVerticalGroup( - tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabImagesLayout.createSequentialGroup() - .addContainerGap() - .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(133, Short.MAX_VALUE)) + tabImagesLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabImagesLayout.createSequentialGroup() + .addContainerGap() + .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelCardImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(panelBackgroundImages, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(133, Short.MAX_VALUE)) ); tabsPanel.addTab("Images", tabImages); @@ -1866,48 +1884,48 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout sounds_backgroundMusicLayout = new org.jdesktop.layout.GroupLayout(sounds_backgroundMusic); sounds_backgroundMusic.setLayout(sounds_backgroundMusicLayout); sounds_backgroundMusicLayout.setHorizontalGroup( - sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(sounds_backgroundMusicLayout.createSequentialGroup() - .addContainerGap() - .add(jLabel16) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(txtBattlefieldIBGMPath) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(btnBattlefieldBGMBrowse)) - .add(sounds_backgroundMusicLayout.createSequentialGroup() - .add(cbEnableBattlefieldBGM) - .add(0, 0, Short.MAX_VALUE)) + sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(sounds_backgroundMusicLayout.createSequentialGroup() + .addContainerGap() + .add(jLabel16) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtBattlefieldIBGMPath) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(btnBattlefieldBGMBrowse)) + .add(sounds_backgroundMusicLayout.createSequentialGroup() + .add(cbEnableBattlefieldBGM) + .add(0, 0, Short.MAX_VALUE)) ); sounds_backgroundMusicLayout.setVerticalGroup( - sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(sounds_backgroundMusicLayout.createSequentialGroup() - .add(cbEnableBattlefieldBGM) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtBattlefieldIBGMPath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(btnBattlefieldBGMBrowse) - .add(jLabel16))) + sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(sounds_backgroundMusicLayout.createSequentialGroup() + .add(cbEnableBattlefieldBGM) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(sounds_backgroundMusicLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtBattlefieldIBGMPath, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(btnBattlefieldBGMBrowse) + .add(jLabel16))) ); org.jdesktop.layout.GroupLayout tabSoundsLayout = new org.jdesktop.layout.GroupLayout(tabSounds); tabSounds.setLayout(tabSoundsLayout); tabSoundsLayout.setHorizontalGroup( - tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabSoundsLayout.createSequentialGroup() - .addContainerGap() - .add(tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(sounds_clips, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(org.jdesktop.layout.GroupLayout.TRAILING, sounds_backgroundMusic, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabSoundsLayout.createSequentialGroup() + .addContainerGap() + .add(tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(sounds_clips, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.TRAILING, sounds_backgroundMusic, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); tabSoundsLayout.setVerticalGroup( - tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabSoundsLayout.createSequentialGroup() - .addContainerGap() - .add(sounds_clips, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(sounds_backgroundMusic, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + tabSoundsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabSoundsLayout.createSequentialGroup() + .addContainerGap() + .add(sounds_clips, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(sounds_backgroundMusic, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); sounds_clips.getAccessibleContext().setAccessibleDescription(""); @@ -1931,12 +1949,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel10Layout = new org.jdesktop.layout.GroupLayout(jPanel10); jPanel10.setLayout(jPanel10Layout); jPanel10Layout.setHorizontalGroup( - jPanel10Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel10Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel10Layout.setVerticalGroup( - jPanel10Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel10Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel10); @@ -1949,12 +1967,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel11Layout = new org.jdesktop.layout.GroupLayout(jPanel11); jPanel11.setLayout(jPanel11Layout); jPanel11Layout.setHorizontalGroup( - jPanel11Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel11Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel11Layout.setVerticalGroup( - jPanel11Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel11Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel11); @@ -1967,12 +1985,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel12Layout = new org.jdesktop.layout.GroupLayout(jPanel12); jPanel12.setLayout(jPanel12Layout); jPanel12Layout.setHorizontalGroup( - jPanel12Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel12Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel12Layout.setVerticalGroup( - jPanel12Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel12Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel12); @@ -1985,12 +2003,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel13Layout = new org.jdesktop.layout.GroupLayout(jPanel13); jPanel13.setLayout(jPanel13Layout); jPanel13Layout.setHorizontalGroup( - jPanel13Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel13Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel13Layout.setVerticalGroup( - jPanel13Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel13Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel13); @@ -2003,12 +2021,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel14Layout = new org.jdesktop.layout.GroupLayout(jPanel14); jPanel14.setLayout(jPanel14Layout); jPanel14Layout.setHorizontalGroup( - jPanel14Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel14Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel14Layout.setVerticalGroup( - jPanel14Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel14Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel14); @@ -2021,12 +2039,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel15Layout = new org.jdesktop.layout.GroupLayout(jPanel15); jPanel15.setLayout(jPanel15Layout); jPanel15Layout.setHorizontalGroup( - jPanel15Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel15Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel15Layout.setVerticalGroup( - jPanel15Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel15Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel15); @@ -2039,12 +2057,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel16Layout = new org.jdesktop.layout.GroupLayout(jPanel16); jPanel16.setLayout(jPanel16Layout); jPanel16Layout.setHorizontalGroup( - jPanel16Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel16Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel16Layout.setVerticalGroup( - jPanel16Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel16Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel16); @@ -2057,12 +2075,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel17Layout = new org.jdesktop.layout.GroupLayout(jPanel17); jPanel17.setLayout(jPanel17Layout); jPanel17Layout.setHorizontalGroup( - jPanel17Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel17Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel17Layout.setVerticalGroup( - jPanel17Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel17Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel17); @@ -2075,12 +2093,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel18Layout = new org.jdesktop.layout.GroupLayout(jPanel18); jPanel18.setLayout(jPanel18Layout); jPanel18Layout.setHorizontalGroup( - jPanel18Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel18Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel18Layout.setVerticalGroup( - jPanel18Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel18Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel18); @@ -2093,12 +2111,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel19Layout = new org.jdesktop.layout.GroupLayout(jPanel19); jPanel19.setLayout(jPanel19Layout); jPanel19Layout.setHorizontalGroup( - jPanel19Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel19Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel19Layout.setVerticalGroup( - jPanel19Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel19Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel19); @@ -2111,12 +2129,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel20Layout = new org.jdesktop.layout.GroupLayout(jPanel20); jPanel20.setLayout(jPanel20Layout); jPanel20Layout.setHorizontalGroup( - jPanel20Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel20Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel20Layout.setVerticalGroup( - jPanel20Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel20Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel20); @@ -2129,12 +2147,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel21Layout = new org.jdesktop.layout.GroupLayout(jPanel21); jPanel21.setLayout(jPanel21Layout); jPanel21Layout.setHorizontalGroup( - jPanel21Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel21Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel21Layout.setVerticalGroup( - jPanel21Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel21Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel21); @@ -2147,12 +2165,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel22Layout = new org.jdesktop.layout.GroupLayout(jPanel22); jPanel22.setLayout(jPanel22Layout); jPanel22Layout.setHorizontalGroup( - jPanel22Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel22Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel22Layout.setVerticalGroup( - jPanel22Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel22Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel22); @@ -2165,12 +2183,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel23Layout = new org.jdesktop.layout.GroupLayout(jPanel23); jPanel23.setLayout(jPanel23Layout); jPanel23Layout.setHorizontalGroup( - jPanel23Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel23Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel23Layout.setVerticalGroup( - jPanel23Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel23Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel23); @@ -2183,12 +2201,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel24Layout = new org.jdesktop.layout.GroupLayout(jPanel24); jPanel24.setLayout(jPanel24Layout); jPanel24Layout.setHorizontalGroup( - jPanel24Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel24Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel24Layout.setVerticalGroup( - jPanel24Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel24Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel24); @@ -2201,12 +2219,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel25Layout = new org.jdesktop.layout.GroupLayout(jPanel25); jPanel25.setLayout(jPanel25Layout); jPanel25Layout.setHorizontalGroup( - jPanel25Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel25Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel25Layout.setVerticalGroup( - jPanel25Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel25Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel25); @@ -2219,12 +2237,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel26Layout = new org.jdesktop.layout.GroupLayout(jPanel26); jPanel26.setLayout(jPanel26Layout); jPanel26Layout.setHorizontalGroup( - jPanel26Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel26Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel26Layout.setVerticalGroup( - jPanel26Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel26Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel26); @@ -2237,12 +2255,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel27Layout = new org.jdesktop.layout.GroupLayout(jPanel27); jPanel27.setLayout(jPanel27Layout); jPanel27Layout.setHorizontalGroup( - jPanel27Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel27Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel27Layout.setVerticalGroup( - jPanel27Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel27Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel27); @@ -2255,12 +2273,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel28Layout = new org.jdesktop.layout.GroupLayout(jPanel28); jPanel28.setLayout(jPanel28Layout); jPanel28Layout.setHorizontalGroup( - jPanel28Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel28Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel28Layout.setVerticalGroup( - jPanel28Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel28Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel28); @@ -2273,12 +2291,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel29Layout = new org.jdesktop.layout.GroupLayout(jPanel29); jPanel29.setLayout(jPanel29Layout); jPanel29Layout.setHorizontalGroup( - jPanel29Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel29Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel29Layout.setVerticalGroup( - jPanel29Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel29Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel29); @@ -2291,12 +2309,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel30Layout = new org.jdesktop.layout.GroupLayout(jPanel30); jPanel30.setLayout(jPanel30Layout); jPanel30Layout.setHorizontalGroup( - jPanel30Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel30Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel30Layout.setVerticalGroup( - jPanel30Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel30Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel30); @@ -2309,12 +2327,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel31Layout = new org.jdesktop.layout.GroupLayout(jPanel31); jPanel31.setLayout(jPanel31Layout); jPanel31Layout.setHorizontalGroup( - jPanel31Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel31Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel31Layout.setVerticalGroup( - jPanel31Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel31Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel31); @@ -2327,12 +2345,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel32Layout = new org.jdesktop.layout.GroupLayout(jPanel32); jPanel32.setLayout(jPanel32Layout); jPanel32Layout.setHorizontalGroup( - jPanel32Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel32Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel32Layout.setVerticalGroup( - jPanel32Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel32Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel32); @@ -2344,12 +2362,12 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout jPanel33Layout = new org.jdesktop.layout.GroupLayout(jPanel33); jPanel33.setLayout(jPanel33Layout); jPanel33Layout.setHorizontalGroup( - jPanel33Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel33Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); jPanel33Layout.setVerticalGroup( - jPanel33Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(0, 0, Short.MAX_VALUE) + jPanel33Layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 0, Short.MAX_VALUE) ); avatarPanel.add(jPanel33); @@ -2359,16 +2377,16 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout tabAvatarsLayout = new org.jdesktop.layout.GroupLayout(tabAvatars); tabAvatars.setLayout(tabAvatarsLayout); tabAvatarsLayout.setHorizontalGroup( - tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabAvatarsLayout.createSequentialGroup() - .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 528, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(0, 0, Short.MAX_VALUE)) + tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabAvatarsLayout.createSequentialGroup() + .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 528, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(0, 0, Short.MAX_VALUE)) ); tabAvatarsLayout.setVerticalGroup( - tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabAvatarsLayout.createSequentialGroup() - .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 620, Short.MAX_VALUE) - .addContainerGap()) + tabAvatarsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabAvatarsLayout.createSequentialGroup() + .add(avatarPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 620, Short.MAX_VALUE) + .addContainerGap()) ); tabsPanel.addTab("Avatars", tabAvatars); @@ -2391,27 +2409,27 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout connection_serversLayout = new org.jdesktop.layout.GroupLayout(connection_servers); connection_servers.setLayout(connection_serversLayout); connection_serversLayout.setHorizontalGroup( - connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .addContainerGap() - .add(lblURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(txtURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 370, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(connection_serversLayout.createSequentialGroup() - .add(141, 141, 141) - .add(jLabel17))) - .addContainerGap(201, Short.MAX_VALUE)) + connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .addContainerGap() + .add(lblURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 96, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(txtURLServerList, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 370, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(connection_serversLayout.createSequentialGroup() + .add(141, 141, 141) + .add(jLabel17))) + .addContainerGap(251, Short.MAX_VALUE)) ); connection_serversLayout.setVerticalGroup( - connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(connection_serversLayout.createSequentialGroup() - .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) - .add(lblURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(txtURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(jLabel17)) + connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(connection_serversLayout.createSequentialGroup() + .add(connection_serversLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(lblURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(txtURLServerList, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 28, Short.MAX_VALUE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(jLabel17)) ); lblProxyType.setText("Proxy:"); @@ -2457,118 +2475,118 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout pnlProxyLayout = new org.jdesktop.layout.GroupLayout(pnlProxy); pnlProxy.setLayout(pnlProxyLayout); pnlProxyLayout.setHorizontalGroup( - pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(pnlProxyLayout.createSequentialGroup() - .addContainerGap() - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(pnlProxyLayout.createSequentialGroup() - .add(rememberPswd) - .add(47, 47, 47) - .add(jLabel11) - .add(34, 34, 34)) - .add(pnlProxyLayout.createSequentialGroup() - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(lblProxyPort) - .add(lblProxyPassword) - .add(lblProxyServer) - .add(lblProxyUserName)) - .add(19, 19, 19) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(txtProxyPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 58, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(org.jdesktop.layout.GroupLayout.LEADING, txtPasswordField) - .add(org.jdesktop.layout.GroupLayout.LEADING, txtProxyUserName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 148, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(txtProxyServer)) - .addContainerGap()))) + pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(pnlProxyLayout.createSequentialGroup() + .addContainerGap() + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(pnlProxyLayout.createSequentialGroup() + .add(rememberPswd) + .add(47, 47, 47) + .add(jLabel11) + .add(34, 34, 34)) + .add(pnlProxyLayout.createSequentialGroup() + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(lblProxyPort) + .add(lblProxyPassword) + .add(lblProxyServer) + .add(lblProxyUserName)) + .add(19, 19, 19) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(txtProxyPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 58, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) + .add(org.jdesktop.layout.GroupLayout.LEADING, txtPasswordField) + .add(org.jdesktop.layout.GroupLayout.LEADING, txtProxyUserName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 148, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(txtProxyServer)) + .addContainerGap()))) ); pnlProxyLayout.setVerticalGroup( - pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(pnlProxyLayout.createSequentialGroup() - .add(6, 6, 6) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtProxyServer, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(lblProxyServer)) - .add(8, 8, 8) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(lblProxyPort) - .add(txtProxyPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtProxyUserName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(lblProxyUserName)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(txtPasswordField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(lblProxyPassword)) - .add(18, 18, 18) - .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(rememberPswd) - .add(jLabel11)) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(pnlProxyLayout.createSequentialGroup() + .add(6, 6, 6) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtProxyServer, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(lblProxyServer)) + .add(8, 8, 8) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lblProxyPort) + .add(txtProxyPort, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtProxyUserName, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(lblProxyUserName)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(txtPasswordField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(lblProxyPassword)) + .add(18, 18, 18) + .add(pnlProxyLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(rememberPswd) + .add(jLabel11)) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); org.jdesktop.layout.GroupLayout pnlProxySettingsLayout = new org.jdesktop.layout.GroupLayout(pnlProxySettings); pnlProxySettings.setLayout(pnlProxySettingsLayout); pnlProxySettingsLayout.setHorizontalGroup( - pnlProxySettingsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(pnlProxySettingsLayout.createSequentialGroup() - .addContainerGap() - .add(pnlProxy, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + pnlProxySettingsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(pnlProxySettingsLayout.createSequentialGroup() + .addContainerGap() + .add(pnlProxy, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) ); pnlProxySettingsLayout.setVerticalGroup( - pnlProxySettingsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(pnlProxySettingsLayout.createSequentialGroup() - .add(pnlProxy, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + pnlProxySettingsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(pnlProxySettingsLayout.createSequentialGroup() + .add(pnlProxy, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) ); org.jdesktop.layout.GroupLayout tabConnectionLayout = new org.jdesktop.layout.GroupLayout(tabConnection); tabConnection.setLayout(tabConnectionLayout); tabConnectionLayout.setHorizontalGroup( - tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(org.jdesktop.layout.GroupLayout.TRAILING, tabConnectionLayout.createSequentialGroup() - .addContainerGap() - .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(pnlProxySettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(org.jdesktop.layout.GroupLayout.LEADING, tabConnectionLayout.createSequentialGroup() - .add(lblProxyType) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(cbProxyType, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 126, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, tabConnectionLayout.createSequentialGroup() + .addContainerGap() + .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(pnlProxySettings, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(org.jdesktop.layout.GroupLayout.LEADING, tabConnectionLayout.createSequentialGroup() + .add(lblProxyType) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(cbProxyType, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 126, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); tabConnectionLayout.setVerticalGroup( - tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabConnectionLayout.createSequentialGroup() - .addContainerGap() - .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(lblProxyType) - .add(cbProxyType, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .add(18, 18, 18) - .add(pnlProxySettings, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabConnectionLayout.createSequentialGroup() + .addContainerGap() + .add(connection_servers, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(tabConnectionLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(lblProxyType) + .add(cbProxyType, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .add(18, 18, 18) + .add(pnlProxySettings, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addContainerGap(org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pnlProxySettings.getAccessibleContext().setAccessibleDescription(""); tabsPanel.addTab("Connection", tabConnection); - labelNextTurn.setText("Next Turn"); + labelNextTurn.setText("Next Turn:"); - labelEndStep.setText("End Step"); + labelEndStep.setText("End Step:"); - labelMainStep.setText("Main Step"); + labelMainStep.setText("Main Step:"); - labelYourTurn.setText("Your Turn"); + labelYourTurn.setText("Your Turn:"); - lebelSkip.setText("Skip Stack"); + lebelSkip.setText("Skip Stack:"); - labelPriorEnd.setText("Prior End"); + labelPriorEnd.setText("Prior End:"); - labelCancel.setText("Cancel Skip"); + labelCancel.setText("Cancel Skip:"); keyCancelSkip.setText("keyBindButton1"); @@ -2586,13 +2604,13 @@ public class PreferencesDialog extends javax.swing.JDialog { keySkipStep.setText("keyBindButton1"); - labelSkipStep.setText("Skip Step"); + labelSkipStep.setText("Skip Step:"); keyConfirm.setText("keyBindButton1"); - labelConfirm.setText("Confirm"); + labelConfirm.setText("Confirm:"); - controlsDescriptionLabel.setText("Click on a button and press a key to change a keybind.
Space and ESC are not available, and will set the keybind to nothing.
If you are currently playing a game, the changes will not take effect until you start a new game."); + controlsDescriptionLabel.setText("Click on a button and press a KEY or a combination of CTRL/ALT/SHIF + KEY to change a keybind.\n
\nPress SPACE to clear binging.\n
\nPress ESC to cancel binding.\n
\nNew changes will be applied after new game start."); controlsDescriptionLabel.setVerticalAlignment(javax.swing.SwingConstants.TOP); bttnResetControls.setText("Reset to default"); @@ -2602,97 +2620,105 @@ public class PreferencesDialog extends javax.swing.JDialog { } }); - labelToggleRecordMacro.setText("Toggle Record Macro"); + labelToggleRecordMacro.setText("Record Macro (unsupported):"); keyToggleRecordMacro.setText("keyBindButton1"); + labelSwitchChat.setText("Go in/out to chat:"); + + keySwitchChat.setText("keyBindButton1"); + org.jdesktop.layout.GroupLayout tabControlsLayout = new org.jdesktop.layout.GroupLayout(tabControls); tabControls.setLayout(tabControlsLayout); tabControlsLayout.setHorizontalGroup( - tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabControlsLayout.createSequentialGroup() - .addContainerGap() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabControlsLayout.createSequentialGroup() - .add(bttnResetControls) - .add(0, 0, Short.MAX_VALUE)) - .add(tabControlsLayout.createSequentialGroup() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(labelCancel) - .add(labelNextTurn) - .add(labelEndStep) - .add(labelMainStep) - .add(labelYourTurn) - .add(lebelSkip) - .add(labelPriorEnd) - .add(labelSkipStep) - .add(labelConfirm) - .add(labelToggleRecordMacro)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(keyToggleRecordMacro, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 478, Short.MAX_VALUE))) - .addContainerGap()) + tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabControlsLayout.createSequentialGroup() + .addContainerGap() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(bttnResetControls, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(tabControlsLayout.createSequentialGroup() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(labelCancel) + .add(labelNextTurn) + .add(labelEndStep) + .add(labelMainStep) + .add(labelYourTurn) + .add(lebelSkip) + .add(labelPriorEnd) + .add(labelSkipStep) + .add(labelConfirm) + .add(labelToggleRecordMacro) + .add(labelSwitchChat)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keyToggleRecordMacro, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(keySwitchChat, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(controlsDescriptionLabel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 481, Short.MAX_VALUE) + .addContainerGap()) ); tabControlsLayout.setVerticalGroup( - tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(tabControlsLayout.createSequentialGroup() - .addContainerGap() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING, false) - .add(org.jdesktop.layout.GroupLayout.LEADING, controlsDescriptionLabel) - .add(org.jdesktop.layout.GroupLayout.LEADING, tabControlsLayout.createSequentialGroup() - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelConfirm) - .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelCancel) - .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelNextTurn) - .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelEndStep) - .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelSkipStep) - .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelMainStep) - .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelYourTurn) - .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(lebelSkip) - .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelPriorEnd) - .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(labelToggleRecordMacro) - .add(keyToggleRecordMacro, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) - .add(bttnResetControls) - .addContainerGap()) + tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(tabControlsLayout.createSequentialGroup() + .addContainerGap() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false) + .add(tabControlsLayout.createSequentialGroup() + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelConfirm) + .add(keyConfirm, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelCancel) + .add(keyCancelSkip, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelNextTurn) + .add(keyNextTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelEndStep) + .add(keyEndStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelSkipStep) + .add(keySkipStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelMainStep) + .add(keyMainStep, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelYourTurn) + .add(keyYourTurn, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(lebelSkip) + .add(keySkipStack, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelPriorEnd) + .add(keyPriorEnd, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelToggleRecordMacro) + .add(keyToggleRecordMacro, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(tabControlsLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(labelSwitchChat) + .add(keySwitchChat, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.UNRELATED) + .add(bttnResetControls)) + .add(controlsDescriptionLabel)) + .addContainerGap()) ); tabsPanel.addTab("Controls", tabControls); @@ -2722,27 +2748,27 @@ public class PreferencesDialog extends javax.swing.JDialog { org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) - .add(org.jdesktop.layout.GroupLayout.LEADING, tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(layout.createSequentialGroup() - .add(0, 0, Short.MAX_VALUE) - .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) - .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))) - .add(6, 6, 6)) + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) + .add(org.jdesktop.layout.GroupLayout.LEADING, tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(layout.createSequentialGroup() + .add(0, 0, Short.MAX_VALUE) + .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) + .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 100, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))) + .add(6, 6, 6)) ); layout.setVerticalGroup( - layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) - .add(layout.createSequentialGroup() - .add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) - .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) - .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) - .addContainerGap()) + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(layout.createSequentialGroup() + .add(tabsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) + .add(saveButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) + .add(exitButton, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) ); pack(); @@ -2854,9 +2880,11 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS); save(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "false", UPDATE_CACHE_POLICY); - save(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopBlockWithAny, KEY_STOP_BLOCK_WITH_ANY, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopBlockWithZero, KEY_STOP_BLOCK_WITH_ZERO, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false", UPDATE_CACHE_POLICY); + save(prefs, dialog.cbStopOnNewStackObjects, KEY_STOP_NEW_STACK_OBJECTS, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false", UPDATE_CACHE_POLICY); save(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "false", UPDATE_CACHE_POLICY); @@ -2909,6 +2937,7 @@ public class PreferencesDialog extends javax.swing.JDialog { save(prefs, dialog.keySkipStack); save(prefs, dialog.keyPriorEnd); save(prefs, dialog.keyToggleRecordMacro); + save(prefs, dialog.keySwitchChat); // Avatar if (selectedAvatarId < MIN_AVATAR_ID || selectedAvatarId > MAX_AVATAR_ID) { @@ -2919,7 +2948,6 @@ public class PreferencesDialog extends javax.swing.JDialog { try { SessionHandler.updatePreferencesForServer(getUserData()); - prefs.flush(); } catch (BackingStoreException ex) { logger.error("Error: couldn't save preferences", ex); @@ -3110,9 +3138,9 @@ public class PreferencesDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_cbStopAttackActionPerformed - private void cbStopBlockActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockActionPerformed + private void cbStopBlockWithAnyActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithAnyActionPerformed // TODO add your handling code here: - }//GEN-LAST:event_cbStopBlockActionPerformed + }//GEN-LAST:event_cbStopBlockWithAnyActionPerformed private void cbStopOnAllMainActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnAllMainActionPerformed // TODO add your handling code here: @@ -3203,7 +3231,9 @@ public class PreferencesDialog extends javax.swing.JDialog { getKeybindButtons().forEach((bttn) -> { String id = bttn.getKey(); int keyCode = getDefaultControlKey(id); + int modCode = getDefaultControlMofier(id); bttn.setKeyCode(keyCode); + bttn.setModifierCode(modCode); }); }//GEN-LAST:event_bttnResetControlsActionPerformed @@ -3225,6 +3255,14 @@ public class PreferencesDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_displayLifeOnAvatarActionPerformed + private void cbStopOnNewStackObjectsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopOnNewStackObjectsActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cbStopOnNewStackObjectsActionPerformed + + private void cbStopBlockWithZeroActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cbStopBlockWithZeroActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_cbStopBlockWithZeroActionPerformed + private void showProxySettings() { Connection.ProxyType proxyType = (Connection.ProxyType) cbProxyType.getSelectedItem(); switch (proxyType) { @@ -3275,7 +3313,7 @@ public class PreferencesDialog extends javax.swing.JDialog { /** * @param args the command line arguments */ - public static void main(String args[]) { + public static void main(String[] args) { int param = 0; if (args.length > 0) { String param1 = args[0]; @@ -3369,9 +3407,11 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.checkBoxEndTurnOthers, END_OF_TURN_OTHERS, "on", "on"); load(prefs, dialog.cbStopAttack, KEY_STOP_ATTACK, "true", "true"); - load(prefs, dialog.cbStopBlock, KEY_STOP_BLOCK, "true", "true"); + load(prefs, dialog.cbStopBlockWithAny, KEY_STOP_BLOCK_WITH_ANY, "true", "true"); + load(prefs, dialog.cbStopBlockWithZero, KEY_STOP_BLOCK_WITH_ZERO, "true", "false"); load(prefs, dialog.cbStopOnAllMain, KEY_STOP_ALL_MAIN_PHASES, "true", "false"); load(prefs, dialog.cbStopOnAllEnd, KEY_STOP_ALL_END_PHASES, "true", "false"); + load(prefs, dialog.cbStopOnNewStackObjects, KEY_STOP_NEW_STACK_OBJECTS, "true", "false"); load(prefs, dialog.cbPassPriorityCast, KEY_PASS_PRIORITY_CAST, "true", "false"); load(prefs, dialog.cbPassPriorityActivation, KEY_PASS_PRIORITY_ACTIVATION, "true", "false"); load(prefs, dialog.cbAutoOrderTrigger, KEY_AUTO_ORDER_TRIGGER, "true", "true"); @@ -3409,10 +3449,10 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.cbCheckForNewImages, KEY_CARD_IMAGES_CHECK, "true"); load(prefs, dialog.cbSaveToZipFiles, KEY_CARD_IMAGES_SAVE_TO_ZIP, "true"); dialog.cbNumberOfDownloadThreads.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_THREADS, "10")); - dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, "en")); + dialog.cbPreferedImageLanguage.setSelectedItem(MageFrame.getPreferences().get(KEY_CARD_IMAGES_PREF_LANGUAGE, CardLanguage.ENGLISH.getCode())); // rendering settings - load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true"); + load(prefs, dialog.cbCardRenderImageFallback, KEY_CARD_RENDERING_FALLBACK, "true", "false"); load(prefs, dialog.cbCardRenderHideSetSymbol, KEY_CARD_RENDERING_SET_SYMBOL, "true"); load(prefs, dialog.cbCardRenderShowReminderText, KEY_CARD_RENDERING_REMINDER_TEXT, "true"); @@ -3493,6 +3533,7 @@ public class PreferencesDialog extends javax.swing.JDialog { load(prefs, dialog.keySkipStack); load(prefs, dialog.keyPriorEnd); load(prefs, dialog.keyToggleRecordMacro); + load(prefs, dialog.keySwitchChat); } private static void loadSelectedAvatar(Preferences prefs) { @@ -3536,9 +3577,11 @@ public class PreferencesDialog extends javax.swing.JDialog { userSkipPrioritySteps.getOpponentTurn().setEndOfTurn(dialog.checkBoxEndTurnOthers.isSelected()); userSkipPrioritySteps.setStopOnDeclareAttackersDuringSkipActions(dialog.cbStopAttack.isSelected()); - userSkipPrioritySteps.setStopOnDeclareBlockerIfNoneAvailable(dialog.cbStopBlock.isSelected()); + userSkipPrioritySteps.setStopOnDeclareBlockersWithAnyPermanents(dialog.cbStopBlockWithAny.isSelected()); + userSkipPrioritySteps.setStopOnDeclareBlockersWithZeroPermanents(dialog.cbStopBlockWithZero.isSelected()); userSkipPrioritySteps.setStopOnAllEndPhases(dialog.cbStopOnAllEnd.isSelected()); userSkipPrioritySteps.setStopOnAllMainPhases(dialog.cbStopOnAllMain.isSelected()); + userSkipPrioritySteps.setStopOnStackNewObjects(dialog.cbStopOnNewStackObjects.isSelected()); return userSkipPrioritySteps; } @@ -3621,8 +3664,11 @@ public class PreferencesDialog extends javax.swing.JDialog { private static void load(Preferences prefs, KeyBindButton button) { String key = button.getKey(); - int prop = prefs.getInt(key, getDefaultControlKey(key)); - button.setKeyCode(prop); + + int code = prefs.getInt(key, getDefaultControlKey(key)); + int mod = prefs.getInt(key + KEY_CONTROL_MODIFIER_POSTFIX, getDefaultControlMofier(key)); + button.setKeyCode(code); + button.setModifierCode(mod); } private static void save(Preferences prefs, JCheckBox checkBox, String propName) { @@ -3664,9 +3710,15 @@ public class PreferencesDialog extends javax.swing.JDialog { private static void save(Preferences prefs, KeyBindButton button) { int code = button.getKeyCode(); + int mod = button.getModifierCode(); + String key = button.getKey(); + prefs.putInt(key, code); updateCache(key, Integer.toString(code)); + + prefs.putInt(key + KEY_CONTROL_MODIFIER_POSTFIX, mod); + updateCache(key + KEY_CONTROL_MODIFIER_POSTFIX, Integer.toString(mod)); } public void reset() { @@ -3699,6 +3751,13 @@ public class PreferencesDialog extends javax.swing.JDialog { } } + private static int getDefaultControlMofier(String key) { + switch (key) { + default: + return 0; + } + } + private static int getDefaultControlKey(String key) { switch (key) { case KEY_CONTROL_CONFIRM: @@ -3713,27 +3772,44 @@ public class PreferencesDialog extends javax.swing.JDialog { return KeyEvent.VK_F6; case KEY_CONTROL_MAIN_STEP: return KeyEvent.VK_F7; + case KEY_CONTROL_TOGGLE_MACRO: + return KeyEvent.VK_F8; case KEY_CONTROL_YOUR_TURN: return KeyEvent.VK_F9; case KEY_CONTROL_SKIP_STACK: return KeyEvent.VK_F10; case KEY_CONTROL_PRIOR_END: return KeyEvent.VK_F11; - case KEY_CONTROL_TOGGLE_MACRO: - return KeyEvent.VK_F8; + case KEY_CONTROL_SWITCH_CHAT: + return KeyEvent.VK_F12; default: return 0; } } + public static int getCurrentControlKey(String key) { + return getCachedValue(key, getDefaultControlKey(key)); + } + + public static int getCurrentControlModifier(String key) { + return getCachedValue(key + KEY_CONTROL_MODIFIER_POSTFIX, getDefaultControlMofier(key)); + } + public static KeyStroke getCachedKeystroke(String key) { int code = getCachedValue(key, getDefaultControlKey(key)); - return KeyStroke.getKeyStroke(code, 0); + int mod = getCachedValue(key + KEY_CONTROL_MODIFIER_POSTFIX, getDefaultControlMofier(key)); + + return KeyStroke.getKeyStroke(code, mod); } public static String getCachedKeyText(String key) { int code = getCachedValue(key, getDefaultControlKey(key)); - return KeyEvent.getKeyText(code); + String codeStr = KeyEvent.getKeyText(code); + + int mod = getCachedValue(key + KEY_CONTROL_MODIFIER_POSTFIX, getDefaultControlMofier(key)); + String modStr = KeyEvent.getKeyModifiersText(mod); + + return (modStr.isEmpty() ? "" : modStr + " + ") + codeStr; } private static void updateCache(String key, String value) { @@ -3794,7 +3870,7 @@ public class PreferencesDialog extends javax.swing.JDialog { } private void addAvatar(JPanel jPanel, final int id, boolean selected, boolean locked) { - String path = "/avatars/" + String.valueOf(id) + ".jpg"; + String path = "/avatars/" + id + ".jpg"; PANELS.put(id, jPanel); Image image = ImageHelper.getImageFromResources(path); @@ -3868,7 +3944,8 @@ public class PreferencesDialog extends javax.swing.JDialog { keySkipStack, keySkipStep, keyYourTurn, - keyToggleRecordMacro + keyToggleRecordMacro, + keySwitchChat ); } @@ -3905,9 +3982,11 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JCheckBox cbSaveToZipFiles; private javax.swing.JCheckBox cbShowStormCounter; private javax.swing.JCheckBox cbStopAttack; - private javax.swing.JCheckBox cbStopBlock; + private javax.swing.JCheckBox cbStopBlockWithAny; + private javax.swing.JCheckBox cbStopBlockWithZero; private javax.swing.JCheckBox cbStopOnAllEnd; private javax.swing.JCheckBox cbStopOnAllMain; + private javax.swing.JCheckBox cbStopOnNewStackObjects; private javax.swing.JCheckBox cbUseDefaultBackground; private javax.swing.JCheckBox cbUseDefaultBattleImage; private javax.swing.JCheckBox cbUseDefaultImageFolder; @@ -3982,6 +4061,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private mage.client.components.KeyBindButton keyPriorEnd; private mage.client.components.KeyBindButton keySkipStack; private mage.client.components.KeyBindButton keySkipStep; + private mage.client.components.KeyBindButton keySwitchChat; private mage.client.components.KeyBindButton keyToggleRecordMacro; private mage.client.components.KeyBindButton keyYourTurn; private javax.swing.JLabel labelCancel; @@ -4003,6 +4083,7 @@ public class PreferencesDialog extends javax.swing.JDialog { private javax.swing.JLabel labelPriorEnd; private javax.swing.JLabel labelSkipStep; private javax.swing.JLabel labelStackWidth; + private javax.swing.JLabel labelSwitchChat; private javax.swing.JLabel labelToggleRecordMacro; private javax.swing.JLabel labelTooltipSize; private javax.swing.JLabel labelYourTurn; diff --git a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java index da1b709bcf..ada52f2916 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/RandomPacksSelectorDialog.java @@ -25,7 +25,7 @@ public class RandomPacksSelectorDialog extends javax.swing.JDialog { private boolean isRandomDraft; private boolean isRichManDraft; private String title = ""; - public final static String randomDraftDescription = ("The selected packs will be randomly distributed to players. Each player may open different packs. Duplicates will be avoided."); + public static final String randomDraftDescription = ("The selected packs will be randomly distributed to players. Each player may open different packs. Duplicates will be avoided."); public RandomPacksSelectorDialog(boolean isRandomDraft, boolean isRichManDraft) { initComponents(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java index b226a1090c..bebc65749c 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/RegisterUserDialog.java @@ -1,16 +1,18 @@ package mage.client.dialog; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import javax.swing.SwingWorker; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.preference.MagePreferences; import mage.remote.Connection; import org.apache.log4j.Logger; +import javax.swing.*; +import java.util.Arrays; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + public class RegisterUserDialog extends MageDialog { private static final Logger logger = Logger.getLogger(ConnectDialog.class); @@ -106,73 +108,73 @@ public class RegisterUserDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblPasswordConfirmationReasoning) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblServer) - .addComponent(lblUserName) - .addComponent(lblPort) - .addComponent(lblPassword) - .addComponent(lblPasswordConfirmation) - .addComponent(lblEmail)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addComponent(lblEmailReasoning) - .addGroup(layout.createSequentialGroup() - .addComponent(btnRegister) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel))) - .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(22, Short.MAX_VALUE)) + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblPasswordConfirmationReasoning) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblServer) + .addComponent(lblUserName) + .addComponent(lblPort) + .addComponent(lblPassword) + .addComponent(lblPasswordConfirmation) + .addComponent(lblEmail)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(lblEmailReasoning) + .addGroup(layout.createSequentialGroup() + .addComponent(btnRegister) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel))) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(22, Short.MAX_VALUE)) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGap(9, 9, 9) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblServer) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPort) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblUserName) - .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPassword) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPasswordConfirmation)) - .addComponent(lblPasswordConfirmationReasoning) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblEmail) - .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblEmailReasoning) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnCancel) - .addComponent(btnRegister)) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(9, 9, 9) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblServer) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPort) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblUserName) + .addComponent(txtUserName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPassword) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPasswordConfirmation)) + .addComponent(lblPasswordConfirmationReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblEmail) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblEmailReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnCancel) + .addComponent(btnRegister)) + .addContainerGap()) ); pack(); @@ -187,7 +189,7 @@ public class RegisterUserDialog extends MageDialog { }//GEN-LAST:event_btnCancelActionPerformed private void btnRegisterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRegisterActionPerformed - if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) { + if (!Arrays.equals(this.txtPassword.getPassword(), this.txtPasswordConfirmation.getPassword())) { MageFrame.getInstance().showError("Passwords don't match."); return; } @@ -195,7 +197,7 @@ public class RegisterUserDialog extends MageDialog { connection.setHost(this.txtServer.getText().trim()); connection.setPort(Integer.valueOf(this.txtPort.getText().trim())); connection.setUsername(this.txtUserName.getText().trim()); - connection.setPassword(this.txtPassword.getText().trim()); + connection.setPassword(String.valueOf(this.txtPassword.getPassword()).trim()); connection.setEmail(this.txtEmail.getText().trim()); PreferencesDialog.setProxyInformation(connection); task = new ConnectTask(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java index 0b99f9a2c8..5e99e42127 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ResetPasswordDialog.java @@ -1,16 +1,18 @@ package mage.client.dialog; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; -import javax.swing.SwingWorker; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.preference.MagePreferences; import mage.remote.Connection; import org.apache.log4j.Logger; +import javax.swing.*; +import java.util.Arrays; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + public class ResetPasswordDialog extends MageDialog { private static final Logger logger = Logger.getLogger(ResetPasswordDialog.class); @@ -97,51 +99,51 @@ public class ResetPasswordDialog extends MageDialog { javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addComponent(jLabel6) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(jPanel2Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(lblAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblPasswordConfirmation, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtAuthToken) - .addComponent(txtPassword) - .addComponent(txtPasswordConfirmation))) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() - .addGap(0, 204, Short.MAX_VALUE) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblPasswordConfirmationReasoning, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(btnSubmitNewPassword, javax.swing.GroupLayout.Alignment.TRAILING)))) - .addContainerGap()) + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel6) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel2Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(lblAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, 74, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPassword, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblPasswordConfirmation, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtAuthToken) + .addComponent(txtPassword) + .addComponent(txtPasswordConfirmation))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel2Layout.createSequentialGroup() + .addGap(0, 204, Short.MAX_VALUE) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblPasswordConfirmationReasoning, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(btnSubmitNewPassword, javax.swing.GroupLayout.Alignment.TRAILING)))) + .addContainerGap()) ); jPanel2Layout.setVerticalGroup( - jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel2Layout.createSequentialGroup() - .addComponent(jLabel6) - .addGap(24, 24, 24) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblAuthToken) - .addComponent(txtAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPassword) - .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblPasswordConfirmation) - .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblPasswordConfirmationReasoning) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(btnSubmitNewPassword) - .addContainerGap(9, Short.MAX_VALUE)) + jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel2Layout.createSequentialGroup() + .addComponent(jLabel6) + .addGap(24, 24, 24) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblAuthToken) + .addComponent(txtAuthToken, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPassword) + .addComponent(txtPassword, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblPasswordConfirmation) + .addComponent(txtPasswordConfirmation, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblPasswordConfirmationReasoning) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(btnSubmitNewPassword) + .addContainerGap(9, Short.MAX_VALUE)) ); jPanel1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); @@ -158,33 +160,33 @@ public class ResetPasswordDialog extends MageDialog { javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel5) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(lblEmail) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(txtEmail)) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(btnGetAuthToken))) - .addContainerGap()) + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(lblEmail) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(txtEmail)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(btnGetAuthToken))) + .addContainerGap()) ); jPanel1Layout.setVerticalGroup( - jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(jLabel5) - .addGap(24, 24, 24) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblEmail) - .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnGetAuthToken) - .addContainerGap()) + jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jLabel5) + .addGap(24, 24, 24) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblEmail) + .addComponent(txtEmail, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnGetAuthToken) + .addContainerGap()) ); btnCancel.setText("Cancel"); @@ -199,46 +201,46 @@ public class ResetPasswordDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(btnCancel)) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblServer) - .addComponent(lblPort)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtServer) - .addComponent(txtPort)))) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(btnCancel)) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(lblStatus, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblServer) + .addComponent(lblPort)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtServer) + .addComponent(txtPort)))) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblServer) - .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblPort)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnCancel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblServer) + .addComponent(txtServer, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtPort, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblPort)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(lblStatus, javax.swing.GroupLayout.PREFERRED_SIZE, 28, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnCancel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pack(); @@ -269,11 +271,11 @@ public class ResetPasswordDialog extends MageDialog { MageFrame.getInstance().showError("Please enter an auth token."); return; } - if (this.txtPassword.getText().isEmpty()) { + if (String.valueOf(this.txtPassword.getPassword()).trim().isEmpty()) { MageFrame.getInstance().showError("Please enter a new password."); return; } - if (!this.txtPassword.getText().equals(this.txtPasswordConfirmation.getText())) { + if (!Arrays.equals(this.txtPassword.getPassword(), this.txtPasswordConfirmation.getPassword())) { MageFrame.getInstance().showError("Passwords don't match."); return; } @@ -284,7 +286,7 @@ public class ResetPasswordDialog extends MageDialog { PreferencesDialog.setProxyInformation(connection); connection.setEmail(this.txtEmail.getText().trim()); connection.setAuthToken(this.txtAuthToken.getText().trim()); - connection.setPassword(this.txtPassword.getText().trim()); + connection.setPassword(String.valueOf(this.txtPassword.getPassword()).trim()); resetPasswordTask = new ResetPasswordTask(); resetPasswordTask.execute(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java index fb524cee04..3bcebfbc88 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/ShowCardsDialog.java @@ -1,138 +1,137 @@ /* - * ShowCardsDialog.java - * - * Created on 3-Feb-2010, 8:59:11 PM - */ -package mage.client.dialog; + * ShowCardsDialog.java + * + * Created on 3-Feb-2010, 8:59:11 PM + */ + package mage.client.dialog; -import java.awt.Component; -import java.awt.Point; -import java.io.Serializable; -import java.util.Map; -import java.util.UUID; -import javax.swing.JLayeredPane; -import javax.swing.JPopupMenu; -import javax.swing.SwingUtilities; -import mage.client.MageFrame; -import mage.client.cards.BigCard; -import mage.client.cards.CardArea; -import mage.client.util.Event; -import mage.client.util.Listener; -import mage.client.util.SettingsManager; -import mage.client.util.gui.GuiDisplayUtil; -import mage.game.events.PlayerQueryEvent.QueryType; -import mage.view.CardsView; -import org.mage.card.arcane.CardPanel; + import mage.client.MageFrame; + import mage.client.cards.BigCard; + import mage.client.cards.CardArea; + import mage.client.util.Event; + import mage.client.util.Listener; + import mage.client.util.SettingsManager; + import mage.client.util.gui.GuiDisplayUtil; + import mage.game.events.PlayerQueryEvent.QueryType; + import mage.view.CardsView; + import org.mage.card.arcane.CardPanel; -/** - * @author BetaSteward_at_googlemail.com - */ -public class ShowCardsDialog extends MageDialog { + import javax.swing.*; + import java.awt.*; + import java.io.Serializable; + import java.util.Map; + import java.util.UUID; - // remember if this dialog was already auto positioned, so don't do it after the first time - private boolean positioned; + /** + * @author BetaSteward_at_googlemail.com + */ + public class ShowCardsDialog extends MageDialog { - /** - * Creates new form ShowCardsDialog - */ - public ShowCardsDialog() { - this.positioned = false; + // remember if this dialog was already auto positioned, so don't do it after the first time + private boolean positioned; - this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); - initComponents(); + /** + * Creates new form ShowCardsDialog + */ + public ShowCardsDialog() { + this.positioned = false; - this.setModal(false); + this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); + initComponents(); - } + this.setModal(false); - public void cleanUp() { - cardArea.cleanUp(); - for (Component comp : cardArea.getComponents()) { - if (comp instanceof CardPanel) { - ((CardPanel) comp).cleanUp(); - cardArea.remove(comp); - } - } - } + } - @Override - public void changeGUISize() { - setGUISize(); - cardArea.changeGUISize(); - } + public void cleanUp() { + cardArea.cleanUp(); + for (Component comp : cardArea.getComponents()) { + if (comp instanceof CardPanel) { + ((CardPanel) comp).cleanUp(); + cardArea.remove(comp); + } + } + } - private void setGUISize() { + @Override + public void changeGUISize() { + setGUISize(); + cardArea.changeGUISize(); + } - } + private void setGUISize() { - public void loadCards(String name, CardsView showCards, BigCard bigCard, - UUID gameId, boolean modal, Map options, - JPopupMenu popupMenu, Listener eventListener) { - this.title = name; - this.setTitelBarToolTip(name); - cardArea.clearCardEventListeners(); - cardArea.loadCards(showCards, bigCard, gameId); - if (options != null) { - if (options.containsKey("chosen")) { - java.util.List chosenCards = (java.util.List) options.get("chosen"); - cardArea.selectCards(chosenCards); - } - if (options.containsKey("choosable")) { - java.util.List choosableCards = (java.util.List) options.get("choosable"); - cardArea.markCards(choosableCards); - } - if (options.containsKey("queryType") && options.get("queryType") == QueryType.PICK_ABILITY) { - cardArea.setPopupMenu(popupMenu); - } - } - if (popupMenu != null) { - this.cardArea.setPopupMenu(popupMenu); - } - if (eventListener != null) { - this.cardArea.addCardEventListener(eventListener); - } + } - pack(); + public void loadCards(String name, CardsView showCards, BigCard bigCard, + UUID gameId, boolean modal, Map options, + JPopupMenu popupMenu, Listener eventListener) { + this.title = name; + this.setTitelBarToolTip(name); + cardArea.clearCardEventListeners(); + cardArea.loadCards(showCards, bigCard, gameId); + if (options != null) { + if (options.containsKey("chosen")) { + java.util.List chosenCards = (java.util.List) options.get("chosen"); + cardArea.selectCards(chosenCards); + } + if (options.containsKey("choosable")) { + java.util.List choosableCards = (java.util.List) options.get("choosable"); + cardArea.markCards(choosableCards); + } + if (options.containsKey("queryType") && options.get("queryType") == QueryType.PICK_ABILITY) { + cardArea.setPopupMenu(popupMenu); + } + } + if (popupMenu != null) { + this.cardArea.setPopupMenu(popupMenu); + } + if (eventListener != null) { + this.cardArea.addCardEventListener(eventListener); + } - this.revalidate(); - this.repaint(); - this.setModal(modal); + pack(); - // window settings - if (this.isModal()){ - MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); - }else{ - MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); - } + this.revalidate(); + this.repaint(); + this.setModal(modal); - SwingUtilities.invokeLater(() -> { - if (!positioned) { - int width = ShowCardsDialog.this.getWidth(); - int height = ShowCardsDialog.this.getHeight(); - if (width > 0 && height > 0) { - Point centered = SettingsManager.instance.getComponentPosition(width, height); - ShowCardsDialog.this.setLocation(centered.x, centered.y); - positioned = true; - GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, ShowCardsDialog.this); - } - } - ShowCardsDialog.this.setVisible(true); - }); - } + // window settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } - private void initComponents() { + SwingUtilities.invokeLater(() -> { + if (!positioned) { + int width = ShowCardsDialog.this.getWidth(); + int height = ShowCardsDialog.this.getHeight(); + if (width > 0 && height > 0) { + Point centered = SettingsManager.instance.getComponentPosition(width, height); + ShowCardsDialog.this.setLocation(centered.x, centered.y); + positioned = true; + GuiDisplayUtil.keepComponentInsideScreen(centered.x, centered.y, ShowCardsDialog.this); + } + } + ShowCardsDialog.this.setVisible(true); + }); + } - cardArea = new CardArea(); + private void initComponents() { - setClosable(true); - setResizable(true); - getContentPane().setLayout(new java.awt.BorderLayout()); - getContentPane().add(cardArea, java.awt.BorderLayout.CENTER); - setGUISize(); - pack(); - } + cardArea = new CardArea(); - private CardArea cardArea; -} + setClosable(true); + setResizable(true); + getContentPane().setLayout(new java.awt.BorderLayout()); + getContentPane().add(cardArea, java.awt.BorderLayout.CENTER); + setGUISize(); + pack(); + } + + private CardArea cardArea; + } diff --git a/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.form b/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.form new file mode 100644 index 0000000000..ee033ae8af --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.form @@ -0,0 +1,194 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.java new file mode 100644 index 0000000000..fd2e785cbe --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/TestModalDialog.java @@ -0,0 +1,345 @@ +package mage.client.dialog; + +import mage.client.MageFrame; +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.event.KeyEvent; + +/** + * @author JayDi85 + */ +public class TestModalDialog extends MageDialog { + + private static final Logger logger = Logger.getLogger(TestModalDialog.class); + + private final TestModalSampleDialog constModalDialog1; + private final TestModalSampleDialog constModalDialog2; + private final TestModalSampleDialog constModalDialog3; + + private final TestModalSampleDialog constNonModalDialog1; + private final TestModalSampleDialog constNonModalDialog2; + private final TestModalSampleDialog constNonModalDialog3; + + public TestModalDialog() { + initComponents(); + + constModalDialog1 = new TestModalSampleDialog("const modal dialog 1", true, true, -50, -50); + constModalDialog2 = new TestModalSampleDialog("const modal dialog 2", true, true, -100, -100); + constModalDialog3 = new TestModalSampleDialog("const modal dialog 3", true, true, -150, -150); + + constNonModalDialog1 = new TestModalSampleDialog("const non modal dialog 1", false, true, -50, -50); + constNonModalDialog2 = new TestModalSampleDialog("const non modal dialog 2", false, true, -100, -100); + constNonModalDialog3 = new TestModalSampleDialog("const non modal dialog 3", false, true, -150, -150); + } + + public void showDialog() { + this.setModal(false); + getRootPane().setDefaultButton(buttonCancel); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + this.setVisible(true); + } + + private void onCancel() { + this.removeDialog(); + } + + private void showLater(TestModalSampleDialog dialog) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + logger.info(dialog.getTitle()); + dialog.showDialog(); + } + }); + } + + private void showConstModalDialogs(boolean isReverse) { + if (isReverse) { + showLater(constModalDialog3); + showLater(constModalDialog2); + showLater(constModalDialog1); + } else { + showLater(constModalDialog1); + showLater(constModalDialog2); + showLater(constModalDialog3); + } + } + + private void showConstNonModalDialogs(boolean isReverse) { + if (isReverse) { + showLater(constNonModalDialog3); + showLater(constNonModalDialog2); + showLater(constNonModalDialog1); + } else { + showLater(constNonModalDialog1); + showLater(constNonModalDialog2); + showLater(constNonModalDialog3); + } + } + + private void showDynModalDialogs(boolean isReverse) { + TestModalSampleDialog dynDialog1 = new TestModalSampleDialog("dyn modal dialog 1", true, false, -50, -50); + TestModalSampleDialog dynDialog2 = new TestModalSampleDialog("dyn modal dialog 2", true, false, -100, -100); + TestModalSampleDialog dynDialog3 = new TestModalSampleDialog("dyn modal dialog 3", true, false, -150, -150); + + if (isReverse) { + showLater(dynDialog3); + showLater(dynDialog2); + showLater(dynDialog1); + } else { + showLater(dynDialog1); + showLater(dynDialog2); + showLater(dynDialog3); + } + } + + private void showDynNonModalDialogs(boolean isReverse) { + TestModalSampleDialog dynDialog1 = new TestModalSampleDialog("dyn non modal dialog 1", false, false, -50, -50); + TestModalSampleDialog dynDialog2 = new TestModalSampleDialog("dyn non modal dialog 2", false, false, -100, -100); + TestModalSampleDialog dynDialog3 = new TestModalSampleDialog("dyn non modal dialog 3", false, false, -150, -150); + + if (isReverse) { + showLater(dynDialog3); + showLater(dynDialog2); + showLater(dynDialog1); + } else { + showLater(dynDialog1); + showLater(dynDialog2); + showLater(dynDialog3); + } + } + + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonCancel = new javax.swing.JButton(); + jLabel1 = new javax.swing.JLabel(); + buttonShowConstModal123 = new javax.swing.JButton(); + buttonShowConstModal321 = new javax.swing.JButton(); + buttonShowDynModal123 = new javax.swing.JButton(); + buttonShowDynModal321 = new javax.swing.JButton(); + jLabel2 = new javax.swing.JLabel(); + buttonShowConstNonModal123 = new javax.swing.JButton(); + buttonShowConstNonModal321 = new javax.swing.JButton(); + buttonShowDynNonModal321 = new javax.swing.JButton(); + buttonShowDynNonModal123 = new javax.swing.JButton(); + buttonPrintFramesList = new javax.swing.JButton(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + buttonCancel.setText("Close"); + buttonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCancelActionPerformed(evt); + } + }); + + jLabel1.setText("Test modal dialog system:"); + + buttonShowConstModal123.setText("const modal 123"); + buttonShowConstModal123.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowConstModal123ActionPerformed(evt); + } + }); + + buttonShowConstModal321.setText("const modal 321"); + buttonShowConstModal321.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowConstModal321ActionPerformed(evt); + } + }); + + buttonShowDynModal123.setText("dyn modal 123"); + buttonShowDynModal123.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowDynModal123ActionPerformed(evt); + } + }); + + buttonShowDynModal321.setText("dyn modal 321"); + buttonShowDynModal321.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowDynModal321ActionPerformed(evt); + } + }); + + jLabel2.setText("Test mon modal dialog system:"); + + buttonShowConstNonModal123.setText("const non modal 123"); + buttonShowConstNonModal123.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowConstNonModal123ActionPerformed(evt); + } + }); + + buttonShowConstNonModal321.setText("const non modal 321"); + buttonShowConstNonModal321.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowConstNonModal321ActionPerformed(evt); + } + }); + + buttonShowDynNonModal321.setText("dyn non modal 321"); + buttonShowDynNonModal321.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowDynNonModal321ActionPerformed(evt); + } + }); + + buttonShowDynNonModal123.setText("dyn non modal 123"); + buttonShowDynNonModal123.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonShowDynNonModal123ActionPerformed(evt); + } + }); + + buttonPrintFramesList.setText("print frames list"); + buttonPrintFramesList.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonPrintFramesListActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel1) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonShowConstModal123) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonShowConstModal321)) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonShowDynModal123) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonShowDynModal321)) + .addComponent(jLabel2) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonShowConstNonModal123) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonShowConstNonModal321)) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonShowDynNonModal123) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonShowDynNonModal321)) + .addComponent(buttonPrintFramesList)) + .addGap(0, 44, Short.MAX_VALUE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonShowConstModal123) + .addComponent(buttonShowConstModal321)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonShowDynModal123) + .addComponent(buttonShowDynModal321)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonShowConstNonModal123) + .addComponent(buttonShowConstNonModal321)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonShowDynNonModal123) + .addComponent(buttonShowDynNonModal321)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(buttonPrintFramesList) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 129, Short.MAX_VALUE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed + onCancel(); + }//GEN-LAST:event_buttonCancelActionPerformed + + private void buttonShowConstModal123ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowConstModal123ActionPerformed + showConstModalDialogs(false); + }//GEN-LAST:event_buttonShowConstModal123ActionPerformed + + private void buttonShowConstModal321ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowConstModal321ActionPerformed + showConstModalDialogs(true); + }//GEN-LAST:event_buttonShowConstModal321ActionPerformed + + private void buttonShowDynModal123ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowDynModal123ActionPerformed + showDynModalDialogs(false); + }//GEN-LAST:event_buttonShowDynModal123ActionPerformed + + private void buttonShowDynModal321ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowDynModal321ActionPerformed + showDynModalDialogs(true); + }//GEN-LAST:event_buttonShowDynModal321ActionPerformed + + private void buttonShowConstNonModal123ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowConstNonModal123ActionPerformed + showConstNonModalDialogs(false); + }//GEN-LAST:event_buttonShowConstNonModal123ActionPerformed + + private void buttonShowConstNonModal321ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowConstNonModal321ActionPerformed + showConstNonModalDialogs(true); + }//GEN-LAST:event_buttonShowConstNonModal321ActionPerformed + + private void buttonShowDynNonModal321ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowDynNonModal321ActionPerformed + showDynNonModalDialogs(true); + }//GEN-LAST:event_buttonShowDynNonModal321ActionPerformed + + private void buttonShowDynNonModal123ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonShowDynNonModal123ActionPerformed + showDynNonModalDialogs(false); + }//GEN-LAST:event_buttonShowDynNonModal123ActionPerformed + + private void buttonPrintFramesListActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonPrintFramesListActionPerformed + MageDialog.printFramesOrder("print"); + }//GEN-LAST:event_buttonPrintFramesListActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonPrintFramesList; + private javax.swing.JButton buttonShowConstModal123; + private javax.swing.JButton buttonShowConstModal321; + private javax.swing.JButton buttonShowConstNonModal123; + private javax.swing.JButton buttonShowConstNonModal321; + private javax.swing.JButton buttonShowDynModal123; + private javax.swing.JButton buttonShowDynModal321; + private javax.swing.JButton buttonShowDynNonModal123; + private javax.swing.JButton buttonShowDynNonModal321; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.form b/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.form new file mode 100644 index 0000000000..263652f535 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.form @@ -0,0 +1,65 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.java b/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.java new file mode 100644 index 0000000000..19575ad9a0 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/TestModalSampleDialog.java @@ -0,0 +1,119 @@ +package mage.client.dialog; + +import mage.client.MageFrame; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + +/** + * @author JayDi85 + */ +public class TestModalSampleDialog extends MageDialog { + + private final boolean useModal; + private final boolean useHideDialog; + private final int offsetX; + private final int offsetY; + + public TestModalSampleDialog(String name, boolean useModal, boolean useHideDialog, int offsetX, int offsetY) { + initComponents(); + + this.useModal = useModal; + this.useHideDialog = useHideDialog; + this.offsetX = offsetX; + this.offsetY = offsetY; + + labelInfo.setText(name); + this.setTitle(name); + } + + public void showDialog() { + this.setModal(useModal); + getRootPane().setDefaultButton(buttonCancel); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + Point p = this.getLocation(); + p.x = p.x + offsetX; + p.y = p.y + offsetY; + this.setLocation(p); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + this.setVisible(true); + } + + private void onCancel() { + if (useHideDialog) { + this.hideDialog(); + } else { + this.removeDialog(); + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonCancel = new javax.swing.JButton(); + labelInfo = new javax.swing.JLabel(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + buttonCancel.setText("Close"); + buttonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCancelActionPerformed(evt); + } + }); + + labelInfo.setText("Sample dialog"); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(290, Short.MAX_VALUE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(labelInfo) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addComponent(labelInfo) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 234, Short.MAX_VALUE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed + onCancel(); + }//GEN-LAST:event_buttonCancelActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JLabel labelInfo; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java index c9c9394a83..368e6b3422 100644 --- a/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java +++ b/Mage.Client/src/main/java/mage/client/dialog/UserRequestDialog.java @@ -1,22 +1,15 @@ - - /* - * ErrorDialog.java - * - * Created on Dec 23, 2009, 11:01:32 AM - */ package mage.client.dialog; -import java.awt.Dimension; -import java.awt.Font; -import javax.swing.JComponent; -import javax.swing.plaf.basic.BasicInternalFrameUI; import mage.client.MageFrame; import mage.client.util.GUISizeHelper; import mage.constants.PlayerAction; import mage.view.UserRequestMessage; +import javax.swing.*; +import javax.swing.plaf.basic.BasicInternalFrameUI; +import java.awt.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class UserRequestDialog extends MageDialog { @@ -34,7 +27,7 @@ public class UserRequestDialog extends MageDialog { private void setGUISize() { Font font = GUISizeHelper.gameRequestsFont; lblText.setFont(font); - lblText.setMaximumSize(new Dimension(300 + font.getSize() * 15, 20 + font.getSize() * 5)); + lblText.setMaximumSize(new Dimension(300 + font.getSize() * 15, 200 + font.getSize() * 5)); lblText.setMinimumSize(new Dimension(300 + font.getSize() * 15, 20 + font.getSize() * 5)); lblText.setPreferredSize(new Dimension(300 + font.getSize() * 15, 20 + font.getSize() * 5)); btn1.setFont(font); @@ -58,7 +51,7 @@ public class UserRequestDialog extends MageDialog { public void showDialog(UserRequestMessage userRequestMessage) { this.userRequestMessage = userRequestMessage; - this.setTitle(userRequestMessage.getTitel()); + this.setTitle(userRequestMessage.getTitle()); String text = "

" + userRequestMessage.getMessage() + "

"; this.lblText.setText(text); if (userRequestMessage.getButton1Text() != null) { @@ -128,30 +121,30 @@ public class UserRequestDialog extends MageDialog { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(btn3, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btn2, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btn1, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE))) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(btn3, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btn2, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btn1, javax.swing.GroupLayout.PREFERRED_SIZE, 1, Short.MAX_VALUE))) + .addContainerGap()) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btn1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btn2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btn3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(12, 12, 12)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(lblText, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btn1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btn2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btn3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(12, 12, 12)) ); pack(); diff --git a/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.form b/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.form new file mode 100644 index 0000000000..af26b1a540 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.form @@ -0,0 +1,73 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.java b/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.java new file mode 100644 index 0000000000..761024b843 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/dialog/WhatsNewDialog.java @@ -0,0 +1,434 @@ +package mage.client.dialog; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.concurrent.Worker; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Scene; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import mage.client.MageFrame; +import mage.utils.MageVersion; +import org.apache.log4j.Logger; +import org.w3c.dom.events.EventListener; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Type; +import java.net.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +/** + * @author JayDi85 + */ +public class WhatsNewDialog extends MageDialog { + + private static final Logger logger = Logger.getLogger(WhatsNewDialog.class); + private static final MageVersion clientVersion = new MageVersion(WhatsNewDialog.class); + + // cookies tester: http://www.html-kit.com/tools/cookietester/ + private static final String WHATS_NEW_PAGE = "https://jaydi85.github.io/xmage-web-news/news.html"; + private static final String WHATS_NEW_VERSION_PAGE = "https://jaydi85.github.io/xmage-web-news/news_version.html"; // increment version=123 to auto-shown for all users + private static final int WHATS_NEW_LOAD_TIMEOUT_SECS = 20; // timeout for page loading + + private final JFXPanel fxPanel; + private WebView webView; + private WebEngine engine; + private boolean isPageReady = false; + + private final SwingWorker backgroundWorker = new SwingWorker() { + @Override + public Void doInBackground() { + try { + int maxWait = WHATS_NEW_LOAD_TIMEOUT_SECS; + int currentWait = 0; + while (!isPageReady) { + Thread.sleep(1000); + currentWait++; + if (currentWait > maxWait) { + logger.error("Can't load news page: " + WHATS_NEW_PAGE); + break; + } + } + } catch (InterruptedException e) { + logger.error("Checking news was interrupted", e); + Thread.currentThread().interrupt(); + } + return null; + } + + @Override + public void done() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (isPageReady) { + showDialog(); + } + } + }); + } + }; + + private final SwingWorker backgroundUpdatesWorker = new SwingWorker() { + + private String newVersion = ""; + + @Override + public Void doInBackground() { + try { + // download version + URLConnection connection = new URL(WHATS_NEW_VERSION_PAGE).openConnection(); + connection.setRequestProperty("user-agent", "xmage"); + InputStream download = connection.getInputStream(); + Scanner s = new Scanner(download).useDelimiter("\\A"); + String result = s.hasNext() ? s.next() : ""; + + // check version (default: always have new version) + if (result.startsWith("version=")) { + newVersion = result.substring("version=".length()); + } + } catch (MalformedURLException e) { + logger.error("Checking updates got wrong url " + WHATS_NEW_VERSION_PAGE, e); + } catch (IOException e) { + logger.error("Checking updates got error", e); + } + return null; + } + + @Override + public void done() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + String oldVersion = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEWS_PAGE_LAST_VERSION, "1"); + + boolean isHaveUpdates = newVersion.isEmpty() || !newVersion.equals(oldVersion); + if (isHaveUpdates) { + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEWS_PAGE_LAST_VERSION, newVersion); + loadURL(WHATS_NEW_PAGE); + backgroundWorker.execute(); + } + } + }); + } + }; + + public WhatsNewDialog() { + initComponents(); + this.setDefaultCloseOperation(HIDE_ON_CLOSE); + + fxPanel = new JFXPanel(); + panelData.add(fxPanel); + webView = null; + engine = null; + + createWebView(); + } + + public void checkUpdatesAndShow(boolean forceToShowPage) { + // lazy loading in background + // shows it on page ready or by force + + isPageReady = false; + if (forceToShowPage) { + // direct open + loadURL(WHATS_NEW_PAGE); + if (!backgroundUpdatesWorker.isDone()) backgroundUpdatesWorker.cancel(true); + if (!backgroundWorker.isDone()) backgroundWorker.cancel(true); + + showDialog(); + } else { + // checks version -> loads on new + backgroundUpdatesWorker.execute(); + } + } + + private void showDialog() { + this.setModal(true); + this.setResizable(true); + getRootPane().setDefaultButton(buttonCancel); + this.setSize(800, 600); + + // windows settings + MageFrame.getDesktop().remove(this); + if (this.isModal()) { + MageFrame.getDesktop().add(this, JLayeredPane.MODAL_LAYER); + } else { + MageFrame.getDesktop().add(this, JLayeredPane.PALETTE_LAYER); + } + this.makeWindowCentered(); + + // Close on "ESC" + registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + + this.setVisible(true); + } + + + /** + * Store cookies in preferences + */ + private class PersistentCookieStore implements CookieStore, Runnable { + private CookieStore store; + + public PersistentCookieStore() { + store = new CookieManager().getCookieStore(); + + // restore data + loadFromPrefs(); + + // save data on app close + Runtime.getRuntime().addShutdownHook(new Thread(this)); + } + + private void loadFromPrefs() { + String sourceValue = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_NEWS_PAGE_COOKIES, ""); + + Gson gson = new GsonBuilder().create(); + List httpCookies = new ArrayList<>(); + Type type = new TypeToken>() { + }.getType(); + try { + httpCookies = gson.fromJson(sourceValue, type); + if (httpCookies != null) { + for (HttpCookie cookie : httpCookies) { + store.add(URI.create(cookie.getDomain()), cookie); + } + } + } catch (Exception e) { + logger.error("Wrong news page cookies", e); + } + } + + private void saveToPrefs() { + List httpCookies = store.getCookies(); + Gson gson = new GsonBuilder().create(); + String destValue = gson.toJson(httpCookies); + PreferencesDialog.saveValue(PreferencesDialog.KEY_NEWS_PAGE_COOKIES, destValue); + } + + @Override + public void run() { + saveToPrefs(); + } + + @Override + public void add(URI uri, HttpCookie cookie) { + store.add(uri, cookie); + } + + @Override + public List get(URI uri) { + return store.get(uri); + } + + @Override + public List getCookies() { + return store.getCookies(); + } + + @Override + public List getURIs() { + return store.getURIs(); + } + + @Override + public boolean remove(URI uri, HttpCookie cookie) { + return store.remove(uri, cookie); + } + + @Override + public boolean removeAll() { + return store.removeAll(); + } + } + + private void createWebView() { + + // init web engine and events + // https://docs.oracle.com/javafx/2/swing/swing-fx-interoperability.htm + + Platform.runLater(new Runnable() { + @Override + public void run() { + + webView = new WebView(); + engine = webView.getEngine(); + engine.setUserAgent(engine.getUserAgent() + " XMage/" + clientVersion.toString(false)); + webView.contextMenuEnabledProperty().setValue(false); + + CookieManager cookieManager = new CookieManager(new PersistentCookieStore(), CookiePolicy.ACCEPT_ALL); + CookieHandler.setDefault(cookieManager); + + // on error + engine.getLoadWorker().exceptionProperty().addListener(new ChangeListener() { + public void changed(ObservableValue o, Throwable old, final Throwable value) { + if (engine.getLoadWorker().getState() == Worker.State.FAILED) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + logger.error("Can't load news page: " + (value != null ? value.getMessage() : "null"), value); + } + }); + } + } + }); + + // on completed + engine.getLoadWorker().stateProperty().addListener(new ChangeListener() { + public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) { + if (newState == Worker.State.SUCCEEDED) { + + // 1. replace urls with custom click processing + // all classes from org.w3c.dom + org.w3c.dom.events.EventListener listener = new EventListener() { + public void handleEvent(org.w3c.dom.events.Event ev) { + String href = ((org.w3c.dom.Element) ev.getTarget()).getAttribute("href"); + ev.preventDefault(); + + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (Desktop.isDesktopSupported()) { + Desktop desktop = Desktop.getDesktop(); + try { + URI uri = new URI(href); + desktop.browse(uri); + } catch (IOException | URISyntaxException ex) { + // do nothing + } + } + } + }); + } + }; + org.w3c.dom.Document doc = engine.getDocument(); + org.w3c.dom.NodeList listA = doc.getElementsByTagName("a"); + for (int i = 0; i < listA.getLength(); i++) { + ((org.w3c.dom.events.EventTarget) listA.item(i)).addEventListener("click", listener, false); + } + + // 2. page can be shown + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + isPageReady = true; + } + }); + } + } + }); + + fxPanel.setScene(new Scene(webView)); + } + }); + } + + public void loadURL(final String url) { + Platform.runLater(new Runnable() { + @Override + public void run() { + String tmp = toURL(url); + if (url == null) { + tmp = toURL("http://" + url); + } + engine.load(tmp); + } + }); + } + + private static String toURL(String str) { + try { + return new URL(str).toExternalForm(); + } catch (MalformedURLException exception) { + return null; + } + } + + + private void onCancel() { + this.hideDialog(); + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonCancel = new javax.swing.JButton(); + buttonRefresh = new javax.swing.JButton(); + panelData = new javax.swing.JPanel(); + + buttonCancel.setText("Close"); + buttonCancel.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonCancelActionPerformed(evt); + } + }); + + buttonRefresh.setText("Refresh"); + buttonRefresh.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonRefreshActionPerformed(evt); + } + }); + + panelData.setLayout(new java.awt.BorderLayout()); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(panelData, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(buttonRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(panelData, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(buttonCancel, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(buttonRefresh, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void buttonCancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonCancelActionPerformed + onCancel(); + }//GEN-LAST:event_buttonCancelActionPerformed + + private void buttonRefreshActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonRefreshActionPerformed + loadURL(WHATS_NEW_PAGE); + }//GEN-LAST:event_buttonRefreshActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton buttonCancel; + private javax.swing.JButton buttonRefresh; + private javax.swing.JPanel panelData; + // End of variables declaration//GEN-END:variables +} diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java index 2ebb71df7a..d5b41eb9e0 100644 --- a/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPanel.java @@ -21,7 +21,6 @@ import mage.client.util.audio.AudioManager; import mage.client.util.gui.BufferedImageBuilder; import mage.constants.PlayerAction; import mage.view.*; -import org.apache.log4j.Logger; import javax.swing.*; import javax.swing.Timer; @@ -31,21 +30,16 @@ import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.image.BufferedImage; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; import java.text.SimpleDateFormat; import java.util.*; +import java.util.List; -/** + /** * * @author BetaSteward_at_googlemail.com */ public class DraftPanel extends javax.swing.JPanel { - private static final Logger LOGGER = Logger.getLogger(DraftPanel.class); - private UUID draftId; private Timer countdown; private int timeout; @@ -63,8 +57,11 @@ public class DraftPanel extends javax.swing.JPanel { // id of card with popup menu protected UUID cardIdPopupMenu; - // Filename for the draft log (only updated if writing the log). - private String logFilename; + // Helper for writing the draft log. + private DraftPickLogger draftLogger; + + // List of set codes (for draft log writing). + private List setCodes; // Number of the current booster (for draft log writing). private int packNo; @@ -73,7 +70,6 @@ public class DraftPanel extends javax.swing.JPanel { private int pickNo; // Cached booster data to be written into the log (see logLastPick). - private String currentBoosterHeader; private String[] currentBooster; private static final CardsView EMPTY_VIEW = new CardsView(); @@ -139,17 +135,11 @@ public class DraftPanel extends javax.swing.JPanel { } if (isLogging()) { - // If we are logging the draft create a file that will contain - // the log. SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss"); - logFilename = "Draft_" + sdf.format(new Date()) + '_' + draftId + ".txt"; - try { - Files.write(pathToDraftLog(), "".getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); - } catch (IOException ex) { - LOGGER.error(null, ex); - } + String logFilename = "Draft_" + sdf.format(new Date()) + '_' + draftId + ".draft"; + draftLogger = new DraftPickLogger(new File("gamelogs"), logFilename); } else { - logFilename = null; + draftLogger = new DraftPickLogger(); } } @@ -171,6 +161,8 @@ public class DraftPanel extends javax.swing.JPanel { packNo = draftView.getBoosterNum(); pickNo = draftView.getCardNum(); + setCodes = draftView.getSetCodes(); + draftLogger.updateDraft(draftId, draftView); int right = draftView.getPlayers().size() / 2; int left = draftView.getPlayers().size() - right; @@ -251,7 +243,7 @@ public class DraftPanel extends javax.swing.JPanel { } } - public void loadBooster(DraftPickView draftPickView) { + public void loadBooster(DraftPickView draftPickView) { logLastPick(draftPickView); // upper area that shows the picks loadCardsToPickedCardsArea(draftPickView.getPicks()); @@ -416,13 +408,21 @@ public class DraftPanel extends javax.swing.JPanel { if (currentBooster != null) { String lastPick = getCardName(getLastPick(pickView.getPicks().values())); if (lastPick != null && currentBooster.length > 1) { - logPick(lastPick); + draftLogger.logPick(getCurrentSetCode(), packNo, pickNo-1, lastPick, currentBooster); } currentBooster = null; } setCurrentBoosterForLog(pickView.getBooster()); if (currentBooster.length == 1) { - logPick(currentBooster[0]); + draftLogger.logPick(getCurrentSetCode(), packNo, pickNo, currentBooster[0], currentBooster); + } + } + + private String getCurrentSetCode() { + if (!setCodes.isEmpty()) { + return setCodes.get(packNo-1); + } else { + return ""; } } @@ -440,39 +440,10 @@ public class DraftPanel extends javax.swing.JPanel { } } - currentBoosterHeader = "Pack " + packNo + " pick " + pickNo + ":\n"; currentBooster = cards.toArray(new String[cards.size()]); } - private void logPick(String pick) { - StringBuilder b = new StringBuilder(); - b.append(currentBoosterHeader); - for (String name : currentBooster) { - b.append(pick.equals(name) ? "--> " : " "); - b.append(name); - b.append('\n'); - } - b.append('\n'); - appendToDraftLog(b.toString()); - } - - private Path pathToDraftLog() { - File saveDir = new File("gamelogs"); - if (!saveDir.exists()) { - saveDir.mkdirs(); - } - return new File(saveDir, logFilename).toPath(); - } - - private void appendToDraftLog(String data) { - try { - Files.write(pathToDraftLog(), data.getBytes(), StandardOpenOption.APPEND); - } catch (IOException ex) { - LOGGER.error(null, ex); - } - } - - private static SimpleCardView getLastPick(Collection picks) { + private static SimpleCardView getLastPick(Collection picks) { SimpleCardView last = null; for (SimpleCardView pick : picks) { last = pick; diff --git a/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java new file mode 100644 index 0000000000..db585e1a22 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/draft/DraftPickLogger.java @@ -0,0 +1,85 @@ +package mage.client.draft; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; + +import org.apache.log4j.Logger; + +import mage.view.DraftView; + +public class DraftPickLogger { + + private static final Logger LOGGER = Logger.getLogger(DraftPickLogger.class); + + private final Path logPath; + private final boolean logging; + private boolean headerWritten = false; + + public DraftPickLogger(File directory, String logFilename) { + this.logging = true; + if (!directory.exists()) { + directory.mkdirs(); + } + this.logPath = new File(directory, logFilename).toPath(); + try { + Files.write(logPath, new byte[0], StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (IOException ex) { + LOGGER.error(null, ex); + } + } + + public DraftPickLogger() { + this.logging = false; + this.logPath = null; + } + + public void updateDraft(UUID draftId, DraftView draftView) { + if (headerWritten) { + return; + } + headerWritten = true; + Date now = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("M/d/yyyy h:mm:ss a"); + StringBuilder buffer = new StringBuilder() + .append("Event #: ").append(draftId).append("\n") + .append("Time: ").append(formatter.format(now)).append('\n'); + buffer.append("Players:\n"); + for (String player : draftView.getPlayers()) { + buffer.append(" ").append(player).append('\n'); + } + buffer.append('\n'); + appendToDraftLog(buffer.toString()); + } + + public void logPick(String setCode, int packNo, int pickNo, String pick, String[] currentBooster) { + StringBuilder b = new StringBuilder(); + if (pickNo == 1) { + b.append("------ ").append(setCode).append(" ------\n\n"); + } + b.append("Pack ").append(packNo).append(" pick ").append(pickNo).append(":\n"); + for (String name : currentBooster) { + b.append(pick.equals(name) ? "--> " : " "); + b.append(name); + b.append('\n'); + } + b.append('\n'); + appendToDraftLog(b.toString()); + } + + private void appendToDraftLog(String data) { + if (logging) { + try { + Files.write(logPath, data.getBytes(), StandardOpenOption.APPEND); + } catch (IOException ex) { + LOGGER.error(null, ex); + } + } + } + +} diff --git a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java index 3a050b3c54..08a6e2a41e 100644 --- a/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/BattlefieldPanel.java @@ -235,14 +235,10 @@ public class BattlefieldPanel extends javax.swing.JLayeredPane { private void addPermanent(PermanentView permanent, final int count) { if (cardDimension == null) { - cardDimension = new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight); + cardDimension = new Dimension(Config.dimensions.getFrameWidth(), Config.dimensions.getFrameHeight()); } final MagePermanent perm = Plugins.instance.getMagePermanent(permanent, bigCard, cardDimension, gameId, true); - if (!Plugins.instance.isCardPluginLoaded()) { - //perm.setBounds(findEmptySpace(new Dimension(Config.dimensions.frameWidth, Config.dimensions.frameHeight))); - } else { - //perm.setAlpha(0); - } + permanents.put(permanent.getId(), perm); BattlefieldPanel.this.jPanel.add(perm, 10); diff --git a/Mage.Client/src/main/java/mage/client/game/FirstButtonMousePressedAction.java b/Mage.Client/src/main/java/mage/client/game/FirstButtonMousePressedAction.java new file mode 100644 index 0000000000..881a6b1f13 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/game/FirstButtonMousePressedAction.java @@ -0,0 +1,58 @@ +package mage.client.game; + +import mage.client.components.KeyboundButton; + +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.function.Consumer; + +public class FirstButtonMousePressedAction extends MouseAdapter { + + private final Consumer callback; + private boolean pressed = false; + private boolean inside = false; + + public FirstButtonMousePressedAction(Consumer callback) { + this.callback = callback; + } + + @Override + public void mousePressed(MouseEvent e) { + pressed = true; + if (e.getSource() instanceof KeyboundButton) { + KeyboundButton button = (KeyboundButton) e.getSource(); + button.setTint(true); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + pressed = false; + if (e.getSource() instanceof KeyboundButton) { + KeyboundButton button = (KeyboundButton) e.getSource(); + button.setTint(false); + } + if (e.getButton() == MouseEvent.BUTTON1 && inside) { + callback.accept(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + inside = true; + if (pressed && e.getSource() instanceof KeyboundButton) { + KeyboundButton button = (KeyboundButton) e.getSource(); + button.setTint(true); + } + } + + @Override + public void mouseExited(MouseEvent e) { + inside = false; + if (e.getSource() instanceof KeyboundButton) { + KeyboundButton button = (KeyboundButton) e.getSource(); + button.setTint(false); + } + } + +} diff --git a/Mage.Client/src/main/java/mage/client/game/GamePanel.java b/Mage.Client/src/main/java/mage/client/game/GamePanel.java index 86ad18aa28..d4839275a9 100644 --- a/Mage.Client/src/main/java/mage/client/game/GamePanel.java +++ b/Mage.Client/src/main/java/mage/client/game/GamePanel.java @@ -1,4 +1,3 @@ - package mage.client.game; import mage.cards.Card; @@ -19,8 +18,8 @@ import mage.client.dialog.CardInfoWindowDialog.ShowType; import mage.client.game.FeedbackPanel.FeedbackMode; import mage.client.plugins.adapters.MageActionCallback; import mage.client.plugins.impl.Plugins; -import mage.client.util.*; import mage.client.util.Event; +import mage.client.util.*; import mage.client.util.audio.AudioManager; import mage.client.util.gui.ArrowBuilder; import mage.client.util.gui.MageDialogState; @@ -32,8 +31,8 @@ import org.mage.card.arcane.CardPanel; import org.mage.plugins.card.utils.impl.ImageManagerImpl; import javax.swing.*; -import javax.swing.GroupLayout.Alignment; import javax.swing.Timer; +import javax.swing.GroupLayout.Alignment; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; @@ -42,8 +41,8 @@ import javax.swing.plaf.basic.BasicSplitPaneUI; import java.awt.*; import java.awt.event.*; import java.io.Serializable; -import java.util.*; import java.util.List; +import java.util.*; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -52,7 +51,7 @@ import static mage.client.dialog.PreferencesDialog.*; import static mage.constants.PlayerAction.*; /** - * @author BetaSteward_at_googlemail.com, nantuko8 + * @author BetaSteward_at_googlemail.com, nantuko8, JayDi85 */ public final class GamePanel extends javax.swing.JPanel { @@ -87,6 +86,7 @@ public final class GamePanel extends javax.swing.JPanel { private String chosenHandKey = "You"; private boolean smallMode = false; private boolean initialized = false; + private skipButtonsList skipButtons = new skipButtonsList(); private boolean menuNameSet = false; private boolean handCardsOfOpponentAvailable = false; @@ -103,7 +103,6 @@ public final class GamePanel extends javax.swing.JPanel { private Timer resizeTimer; private enum PopUpMenuType { - TRIGGER_ORDER } @@ -320,7 +319,7 @@ public final class GamePanel extends javax.swing.JPanel { private void saveDividerLocations() { // save panel sizes and divider locations. Rectangle rec = MageFrame.getDesktop().getBounds(); - String sb = Double.toString(rec.getWidth()) + 'x' + Double.toString(rec.getHeight()); + String sb = Double.toString(rec.getWidth()) + 'x' + rec.getHeight(); PreferencesDialog.saveValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, sb); PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_0, Integer.toString(this.jSplitPane0.getDividerLocation())); PreferencesDialog.saveValue(PreferencesDialog.KEY_GAMEPANEL_DIVIDER_LOCATION_1, Integer.toString(this.jSplitPane1.getDividerLocation())); @@ -331,7 +330,7 @@ public final class GamePanel extends javax.swing.JPanel { Rectangle rec = MageFrame.getDesktop().getBounds(); if (rec != null) { String size = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, null); - String sb = Double.toString(rec.getWidth()) + 'x' + Double.toString(rec.getHeight()); + String sb = Double.toString(rec.getWidth()) + 'x' + rec.getHeight(); // use divider positions only if screen size is the same as it was the time the settings were saved if (size != null && size.equals(sb)) { @@ -697,6 +696,13 @@ public final class GamePanel extends javax.swing.JPanel { } } + List possibleBlockers = new ArrayList<>(); + if (options != null && options.containsKey(Constants.Option.POSSIBLE_BLOCKERS)) { + if (options.get(Constants.Option.POSSIBLE_BLOCKERS) instanceof List) { + possibleBlockers.addAll((List) options.get(Constants.Option.POSSIBLE_BLOCKERS)); + } + } + for (PlayerView player : game.getPlayers()) { if (players.containsKey(player.getPlayerId())) { if (!possibleAttackers.isEmpty()) { @@ -706,10 +712,16 @@ public final class GamePanel extends javax.swing.JPanel { } } } + if (!possibleBlockers.isEmpty()) { + for (UUID permanentId : possibleBlockers) { + if (player.getBattlefield().containsKey(permanentId)) { + player.getBattlefield().get(permanentId).setCanBlock(true); + } + } + } players.get(player.getPlayerId()).update(player); if (player.getPlayerId().equals(playerId)) { - updateSkipButtons(player.isPassedTurn(), player.isPassedUntilEndOfTurn(), player.isPassedUntilNextMain(), player.isPassedAllTurns(), player.isPassedUntilStackResolved(), - player.isPassedUntilEndStepBeforeMyTurn()); + skipButtons.updateFromPlayer(player); } // update open or remove closed graveyard windows graveyards.put(player.getName(), player.getGraveyard()); @@ -738,6 +750,8 @@ public final class GamePanel extends javax.swing.JPanel { // can happen at the game start before player list is initiated } } + updateSkipButtons(); + if (!menuNameSet) { StringBuilder sb = new StringBuilder(); if (playerId == null) { @@ -821,41 +835,169 @@ public final class GamePanel extends javax.swing.JPanel { this.repaint(); } + // skip buttons border private static final int BORDER_SIZE = 2; + private static final Border BORDER_ACTIVE = new LineBorder(Color.orange, BORDER_SIZE); + private static final Border BORDER_NON_ACTIVE = new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE); - private void updateSkipButtons(boolean turn, boolean endOfTurn, boolean nextMain, boolean allTurns, boolean stack, boolean endStepBeforeYourStep) { - if (turn) { //F4 - btnSkipToNextTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (endOfTurn) { // F5 - btnSkipToEndTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (nextMain) { // F7 - btnSkipToNextMain.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (stack) { // F8 - btnSkipStack.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); - } - if (allTurns) { // F9 - btnSkipToYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + // skip buttons info + private class skipButton { + + private final String text; + private final String extraFalse; + private final String extraTrue; + private final String hotkeyName; + private boolean extraMode = false; // extra option enabled from preferences + private boolean pressState = false; // activated by user or not + + skipButton(String text, String extraFalse, String extraTrue, String hotkeyName) { + this.text = text; + this.extraFalse = extraFalse; + this.extraTrue = extraTrue; + this.hotkeyName = hotkeyName; } - if (endStepBeforeYourStep) { // F11 - btnSkipToEndStepBeforeYourTurn.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); - } else { - btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + public void setExtraMode(boolean enable) { + this.extraMode = enable; } + public void setPressState(boolean enable) { + this.pressState = enable; + } + + public String getTooltip() { + // show hotkey and selects current button mode + + // text + String res = "" + + "" + getCachedKeyText(this.hotkeyName) + "" + + " - " + text; + + // mode + String mesTrue = this.extraTrue; + String mesFalse = this.extraFalse; + if (!this.extraTrue.isEmpty() || !this.extraFalse.isEmpty()) { + if (this.extraMode) { + mesTrue = "" + mesTrue + ""; + } else { + mesFalse = "" + mesFalse + ""; + } + res = res.replace("EXTRA_FALSE", mesFalse); + res = res.replace("EXTRA_TRUE", mesTrue); + res = res + " - adjust using preferences"; + } + return res; + } + + public Border getBorder() { + return this.pressState ? BORDER_ACTIVE : BORDER_NON_ACTIVE; + } + + } + + private class skipButtonsList { + + private final skipButton turn; + private final skipButton untilEndOfTurn; + private final skipButton untilNextMain; + private final skipButton allTurns; + private final skipButton untilStackResolved; + private final skipButton untilUntilEndStepBeforeMyTurn; + + skipButtonsList() { + this.turn = new skipButton("Skip to next turn", "", "", KEY_CONTROL_NEXT_TURN); + this.untilEndOfTurn = new skipButton("Skip to [EXTRA_TRUE / EXTRA_FALSE] END OF TURN step", "opponent", "next", KEY_CONTROL_END_STEP); + this.untilNextMain = new skipButton("Skip to [EXTRA_TRUE / EXTRA_FALSE] MAIN step", "opponent", "next", KEY_CONTROL_MAIN_STEP); + this.allTurns = new skipButton("Skip to YOUR turn", "", "", KEY_CONTROL_YOUR_TURN); + this.untilStackResolved = new skipButton("Skip until stack is resolved [EXTRA_TRUE]", "", "or stop on new objects added", KEY_CONTROL_SKIP_STACK); + this.untilUntilEndStepBeforeMyTurn = new skipButton("Skip to END OF TURN before YOUR", "", "", KEY_CONTROL_PRIOR_END); + } + + private void updateExtraMode(PlayerView player) { + this.turn.setExtraMode(false); // not used + this.untilEndOfTurn.setExtraMode(player.getUserData().getUserSkipPrioritySteps().isStopOnAllEndPhases()); + this.untilNextMain.setExtraMode(player.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases()); + this.allTurns.setExtraMode(false); // not used + this.untilStackResolved.setExtraMode(player.getUserData().getUserSkipPrioritySteps().isStopOnStackNewObjects()); + this.untilUntilEndStepBeforeMyTurn.setExtraMode(false); // not used + } + + private void updatePressState(PlayerView player) { + this.turn.setPressState(player.isPassedTurn()); + this.untilEndOfTurn.setPressState(player.isPassedUntilEndOfTurn()); + this.untilNextMain.setPressState(player.isPassedUntilNextMain()); + this.allTurns.setPressState(player.isPassedAllTurns()); + this.untilStackResolved.setPressState(player.isPassedUntilStackResolved()); + this.untilUntilEndStepBeforeMyTurn.setPressState(player.isPassedUntilEndStepBeforeMyTurn()); + } + + public void updateFromPlayer(PlayerView player) { + updateExtraMode(player); + updatePressState(player); + } + + private skipButton findButton(String hotkey) { + switch (hotkey) { + case KEY_CONTROL_NEXT_TURN: + return this.turn; + case KEY_CONTROL_END_STEP: + return this.untilEndOfTurn; + case KEY_CONTROL_MAIN_STEP: + return this.untilNextMain; + case KEY_CONTROL_YOUR_TURN: + return this.allTurns; + case KEY_CONTROL_SKIP_STACK: + return this.untilStackResolved; + case KEY_CONTROL_PRIOR_END: + return this.untilUntilEndStepBeforeMyTurn; + default: + logger.error("Unknown hotkey name " + hotkey); + return null; + } + } + + public String getTooltip(String hotkey) { + skipButton butt = findButton(hotkey); + return butt != null ? butt.getTooltip() : ""; + } + + public Border getBorder(String hotkey) { + skipButton butt = findButton(hotkey); + return butt != null ? butt.getBorder() : BORDER_NON_ACTIVE; + } + + public void activateSkipButton(String hotkey) { + // enable ONE button and disable all other (no needs to wait server feedback) + this.turn.setPressState(false); + this.untilEndOfTurn.setPressState(false); + this.untilNextMain.setPressState(false); + this.allTurns.setPressState(false); + this.untilStackResolved.setPressState(false); + this.untilUntilEndStepBeforeMyTurn.setPressState(false); + + if (!hotkey.isEmpty()) { + skipButton butt = findButton(hotkey); + if (butt != null) butt.setPressState(true); + } + } + } + + private void updateSkipButtons() { + // hints + btnSkipToNextTurn.setToolTipText(skipButtons.turn.getTooltip()); + btnSkipToEndTurn.setToolTipText(skipButtons.untilEndOfTurn.getTooltip()); + btnSkipToNextMain.setToolTipText(skipButtons.untilNextMain.getTooltip()); + btnSkipStack.setToolTipText(skipButtons.untilStackResolved.getTooltip()); + btnSkipToYourTurn.setToolTipText(skipButtons.allTurns.getTooltip()); + btnSkipToEndStepBeforeYourTurn.setToolTipText(skipButtons.untilUntilEndStepBeforeMyTurn.getTooltip()); + + // border + btnSkipToNextTurn.setBorder(skipButtons.turn.getBorder()); + btnSkipToEndTurn.setBorder(skipButtons.untilEndOfTurn.getBorder()); + btnSkipToNextMain.setBorder(skipButtons.untilNextMain.getBorder()); + btnSkipStack.setBorder(skipButtons.untilStackResolved.getBorder()); + btnSkipToYourTurn.setBorder(skipButtons.allTurns.getBorder()); + btnSkipToEndStepBeforeYourTurn.setBorder(skipButtons.untilUntilEndStepBeforeMyTurn.getBorder()); } /** @@ -921,6 +1063,8 @@ public final class GamePanel extends javax.swing.JPanel { case END_TURN: updateButton("Cleanup"); break; + default: + break; } } @@ -1027,6 +1171,8 @@ public final class GamePanel extends javax.swing.JPanel { case LOOKED_AT: cardInfoWindowDialog.loadCards((SimpleCardsView) cardsView, bigCard, gameId); break; + default: + break; } } } @@ -1041,6 +1187,114 @@ public final class GamePanel extends javax.swing.JPanel { this.feedbackPanel.getFeedback(FeedbackMode.QUESTION, question, false, options, messageId, true, gameView.getPhase()); } + private void prepareSelectableView(GameView gameView, Map options, Set targets) { + // make cards/perm selectable + // highlighting chosen + // code calls after each selects or updates, no needs in switch off cards + + Zone needZone = Zone.ALL; + if (options.containsKey("targetZone")) { + needZone = (Zone) options.get("targetZone"); + } + + List needChoosen = null; + if (options.containsKey("chosen")) { + needChoosen = (List) options.get("chosen"); + } + if (needChoosen == null) { + needChoosen = new ArrayList<>(); + } + + Set needSelectable; + if (targets != null) { + needSelectable = targets; + } else { + needSelectable = new HashSet<>(); + } + + if (needChoosen.size() == 0 && needSelectable.size() == 0) { + return; + } + + // hand + if (needZone == Zone.HAND || needZone == Zone.ALL) { + for (CardView card : gameView.getHand().values()) { + if (needSelectable.contains(card.getId())) { + card.setChoosable(true); + } + if (needChoosen.contains(card.getId())) { + card.setSelected(true); + } + } + } + + // stack + if (needZone == Zone.STACK || needZone == Zone.ALL) { + for (Map.Entry card : gameView.getStack().entrySet()) { + if (needSelectable.contains(card.getKey())) { + card.getValue().setChoosable(true); + } + if (needChoosen.contains(card.getKey())) { + card.getValue().setSelected(true); + } + } + } + + // battlefield + if (needZone == Zone.BATTLEFIELD || needZone == Zone.ALL) { + for (PlayerView player : gameView.getPlayers()) { + for (Map.Entry perm : player.getBattlefield().entrySet()) { + if (needSelectable.contains(perm.getKey())) { + perm.getValue().setChoosable(true); + } + if (needChoosen.contains(perm.getKey())) { + perm.getValue().setSelected(true); + } + } + } + } + + // graveyard + if (needZone == Zone.GRAVEYARD || needZone == Zone.ALL) { + for (PlayerView player : gameView.getPlayers()) { + for (Map.Entry card : player.getGraveyard().entrySet()) { + if (needSelectable.contains(card.getKey())) { + card.getValue().setChoosable(true); + } + if (needChoosen.contains(card.getKey())) { + card.getValue().setSelected(true); + } + } + } + } + + // exile + if (needZone == Zone.HAND || needZone == Zone.ALL) { + for (ExileView exile : gameView.getExile()) { + for (Map.Entry card : exile.entrySet()) { + if (needSelectable.contains(card.getKey())) { + card.getValue().setChoosable(true); + } + if (needChoosen.contains(card.getKey())) { + card.getValue().setSelected(true); + } + } + } + } + + // revealed + for (RevealedView rev : gameView.getRevealed()) { + for (Map.Entry card : rev.getCards().entrySet()) { + if (needSelectable.contains(card.getKey())) { + card.getValue().setChoosable(true); + } + if (needChoosen.contains(card.getKey())) { + card.getValue().setSelected(true); + } + } + } + } + /** * Shows a pick target dialog and allows the player to pick a target (e.g. * the pick triggered ability) @@ -1056,30 +1310,23 @@ public final class GamePanel extends javax.swing.JPanel { public void pickTarget(String message, CardsView cardView, GameView gameView, Set targets, boolean required, Map options, int messageId) { PopUpMenuType popupMenuType = null; if (options != null) { - if (options.containsKey("targetZone")) { - if (Zone.HAND == options.get("targetZone")) { // mark selectable target cards in hand - List choosen = null; - if (options.containsKey("chosen")) { - choosen = (List) options.get("chosen"); - } - for (CardView card : gameView.getHand().values()) { - if (targets == null || targets.isEmpty()) { - card.setPlayable(false); - card.setChoosable(true); - } else if (targets.contains(card.getId())) { - card.setPlayable(false); - card.setChoosable(true); - } - if (choosen != null && choosen.contains(card.getId())) { - card.setSelected(true); - } - } + if (options.containsKey("queryType")) { + PlayerQueryEvent.QueryType needType = (PlayerQueryEvent.QueryType) options.get("queryType"); + switch (needType) { + case PICK_ABILITY: + popupMenuType = PopUpMenuType.TRIGGER_ORDER; + prepareSelectableView(gameView, options, targets); + break; + case PICK_TARGET: + prepareSelectableView(gameView, options, targets); + break; + default: + logger.warn("Unknown query type in pick target: " + needType + " in " + message); + break; } } - if (options.containsKey("queryType") && PlayerQueryEvent.QueryType.PICK_ABILITY == options.get("queryType")) { - popupMenuType = PopUpMenuType.TRIGGER_ORDER; - } } + updateGame(gameView); Map options0 = options == null ? new HashMap<>() : options; ShowCardsDialog dialog = null; @@ -1360,20 +1607,15 @@ public final class GamePanel extends javax.swing.JPanel { btnToggleMacro.setToolTipText("Toggle Record Macro (" + getCachedKeyText(KEY_CONTROL_TOGGLE_MACRO) + ")."); btnToggleMacro.setFocusable(false); - btnToggleMacro.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnToggleMacroActionPerformed(null); - } - } - }); + btnToggleMacro.addMouseListener(new FirstButtonMousePressedAction(e -> + btnToggleMacroActionPerformed(null))); KeyStroke kst = getCachedKeystroke(KEY_CONTROL_TOGGLE_MACRO); this.getInputMap(c).put(kst, "F8_PRESS"); this.getActionMap().put("F8_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnToggleMacroActionPerformed(actionEvent); } }); @@ -1383,45 +1625,35 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("F3_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; restorePriorityActionPerformed(actionEvent); } }); + // SKIP BUTTONS (button's hint/state is dynamic) + btnCancelSkip.setContentAreaFilled(false); btnCancelSkip.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnCancelSkip.setIcon(new ImageIcon(ImageManagerImpl.instance.getCancelSkipButtonImage())); - btnCancelSkip.setToolTipText("Cancel all skip actions (" - + getCachedKeyText(KEY_CONTROL_CANCEL_SKIP) + ")."); + btnCancelSkip.setToolTipText("CANCEL all skips"); btnCancelSkip.setFocusable(false); - btnCancelSkip.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - restorePriorityActionPerformed(null); - } - } - }); + btnCancelSkip.addMouseListener(new FirstButtonMousePressedAction(e -> + restorePriorityActionPerformed(null))); btnSkipToNextTurn.setContentAreaFilled(false); btnSkipToNextTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipNextTurnButtonImage())); - btnSkipToNextTurn.setToolTipText("Skip to next turn (" - + getCachedKeyText(KEY_CONTROL_NEXT_TURN) + ")."); + btnSkipToNextTurn.setToolTipText("dynamic"); btnSkipToNextTurn.setFocusable(false); - btnSkipToNextTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnEndTurnActionPerformed(null); - } - } - }); + btnSkipToNextTurn.addMouseListener(new FirstButtonMousePressedAction(e -> + btnEndTurnActionPerformed(null))); KeyStroke ks = getCachedKeystroke(KEY_CONTROL_NEXT_TURN); this.getInputMap(c).put(ks, "F4_PRESS"); this.getActionMap().put("F4_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnEndTurnActionPerformed(actionEvent); } }); @@ -1429,23 +1661,17 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToEndTurn.setContentAreaFilled(false); btnSkipToEndTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipEndTurnButtonImage())); - btnSkipToEndTurn.setToolTipText("Skip to (opponents/next) end of turn step (" - + getCachedKeyText(KEY_CONTROL_END_STEP) + ") - adjust using preferences."); + btnSkipToEndTurn.setToolTipText("dynamic"); btnSkipToEndTurn.setFocusable(false); - btnSkipToEndTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnUntilEndOfTurnActionPerformed(null); - } - } - }); + btnSkipToEndTurn.addMouseListener(new FirstButtonMousePressedAction(e -> + btnUntilEndOfTurnActionPerformed(null))); ks = getCachedKeystroke(KEY_CONTROL_END_STEP); this.getInputMap(c).put(ks, "F5_PRESS"); this.getActionMap().put("F5_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnUntilEndOfTurnActionPerformed(actionEvent); } }); @@ -1455,6 +1681,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("F6_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnEndTurnSkipStackActionPerformed(actionEvent); } }); @@ -1462,23 +1689,17 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToNextMain.setContentAreaFilled(false); btnSkipToNextMain.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToNextMain.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipMainButtonImage())); - btnSkipToNextMain.setToolTipText("Skip to (your) next main phase (" - + getCachedKeyText(KEY_CONTROL_MAIN_STEP) + ") - adjust using preferences."); + btnSkipToNextMain.setToolTipText("dynamic"); btnSkipToNextMain.setFocusable(false); - btnSkipToNextMain.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnUntilNextMainPhaseActionPerformed(null); - } - } - }); + btnSkipToNextMain.addMouseListener(new FirstButtonMousePressedAction(e -> + btnUntilNextMainPhaseActionPerformed(null))); ks = getCachedKeystroke(KEY_CONTROL_MAIN_STEP); this.getInputMap(c).put(ks, "F7_PRESS"); this.getActionMap().put("F7_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnUntilNextMainPhaseActionPerformed(actionEvent); } }); @@ -1486,23 +1707,17 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToYourTurn.setContentAreaFilled(false); btnSkipToYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToYourTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipYourNextTurnButtonImage())); - btnSkipToYourTurn.setToolTipText("Skip to your next turn (" - + getCachedKeyText(KEY_CONTROL_YOUR_TURN) + ")."); + btnSkipToYourTurn.setToolTipText("dynamic"); btnSkipToYourTurn.setFocusable(false); - btnSkipToYourTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnPassPriorityUntilNextYourTurnActionPerformed(null); - } - } - }); + btnSkipToYourTurn.addMouseListener(new FirstButtonMousePressedAction(e -> + btnPassPriorityUntilNextYourTurnActionPerformed(null))); KeyStroke ks9 = getCachedKeystroke(KEY_CONTROL_YOUR_TURN); this.getInputMap(c).put(ks9, "F9_PRESS"); this.getActionMap().put("F9_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnPassPriorityUntilNextYourTurnActionPerformed(actionEvent); } }); @@ -1510,23 +1725,17 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipToEndStepBeforeYourTurn.setContentAreaFilled(false); btnSkipToEndStepBeforeYourTurn.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipToEndStepBeforeYourTurn.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipEndStepBeforeYourTurnButtonImage())); - btnSkipToEndStepBeforeYourTurn.setToolTipText("Skip to the end step before your turn (" - + getCachedKeyText(KEY_CONTROL_PRIOR_END) + ") - adjust using preferences."); + btnSkipToEndStepBeforeYourTurn.setToolTipText("dynamic"); btnSkipToEndStepBeforeYourTurn.setFocusable(false); - btnSkipToEndStepBeforeYourTurn.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnSkipToEndStepBeforeYourTurnActionPerformed(null); - } - } - }); + btnSkipToEndStepBeforeYourTurn.addMouseListener(new FirstButtonMousePressedAction(e -> + btnSkipToEndStepBeforeYourTurnActionPerformed(null))); KeyStroke ks11 = getCachedKeystroke(KEY_CONTROL_PRIOR_END); this.getInputMap(c).put(ks11, "F11_PRESS"); this.getActionMap().put("F11_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnSkipToEndStepBeforeYourTurnActionPerformed(actionEvent); } }); @@ -1534,23 +1743,17 @@ public final class GamePanel extends javax.swing.JPanel { btnSkipStack.setContentAreaFilled(false); btnSkipStack.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnSkipStack.setIcon(new ImageIcon(ImageManagerImpl.instance.getSkipStackButtonImage())); - btnSkipStack.setToolTipText("Skip until stack is resolved (" - + getCachedKeyText(KEY_CONTROL_SKIP_STACK) + ")."); + btnSkipStack.setToolTipText("dynamic"); btnSkipStack.setFocusable(false); - btnSkipStack.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnPassPriorityUntilStackResolvedActionPerformed(null); - } - } - }); + btnSkipStack.addMouseListener(new FirstButtonMousePressedAction(e -> + btnPassPriorityUntilStackResolvedActionPerformed(null))); ks = getCachedKeystroke(KEY_CONTROL_SKIP_STACK); this.getInputMap(c).put(ks, "F10_PRESS"); this.getActionMap().put("F10_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; btnPassPriorityUntilStackResolvedActionPerformed(actionEvent); } }); @@ -1558,33 +1761,49 @@ public final class GamePanel extends javax.swing.JPanel { btnConcede.setContentAreaFilled(false); btnConcede.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); btnConcede.setIcon(new ImageIcon(ImageManagerImpl.instance.getConcedeButtonImage())); - btnConcede.setToolTipText("Concede the current game."); + btnConcede.setToolTipText("CONCEDE current game"); btnConcede.setFocusable(false); - btnConcede.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnConcedeActionPerformed(null); - } - } - }); + btnConcede.addMouseListener(new FirstButtonMousePressedAction(e -> + btnConcedeActionPerformed(null))); + + // update button hint/states to default values + updateSkipButtons(); + + // HOTKEYS KeyStroke ks2 = getCachedKeystroke(KEY_CONTROL_CONFIRM); this.getInputMap(c).put(ks2, "F2_PRESS"); this.getActionMap().put("F2_PRESS", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; if (feedbackPanel != null) { feedbackPanel.pressOKYesOrDone(); } } }); + KeyStroke ks12 = getCachedKeystroke(KEY_CONTROL_SWITCH_CHAT); + this.getInputMap(c).put(ks12, "F12_PRESS"); + this.getActionMap().put("F12_PRESS", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent actionEvent) { + // switch in/out to chat, must triggers in chat input too + //if (isUserImputActive()) return; + if (isChatInputActive()) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearFocusOwner(); + } else if (!isUserImputActive()) { + userChatPanel.getTxtMessageInputComponent().requestFocusInWindow(); + } + } + }); + KeyStroke ksAltE = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.ALT_MASK); this.getInputMap(c).put(ksAltE, "ENLARGE"); this.getActionMap().put("ENLARGE", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; ActionCallback callback = Plugins.instance.getActionCallback(); ((MageActionCallback) callback).enlargeCard(EnlargeMode.NORMAL); } @@ -1595,6 +1814,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("ENLARGE_SOURCE", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; ActionCallback callback = Plugins.instance.getActionCallback(); ((MageActionCallback) callback).enlargeCard(EnlargeMode.ALTERNATE); } @@ -1605,6 +1825,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("BIG_IMAGE", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; imagePanelState = !imagePanelState; if (!imagePanelState) { jSplitPane0.resetToPreferredSizes(); @@ -1620,6 +1841,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("USEFIRSTMANAABILITY", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_ON, gameId, null); setMenuStates( PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), @@ -1644,6 +1866,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("ENLARGE_RELEASE", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; ActionCallback callback = Plugins.instance.getActionCallback(); ((MageActionCallback) callback).hideEnlargedCard(); } @@ -1654,6 +1877,7 @@ public final class GamePanel extends javax.swing.JPanel { this.getActionMap().put("USEFIRSTMANAABILITY_RELEASE", new AbstractAction() { @Override public void actionPerformed(ActionEvent actionEvent) { + if (isUserImputActive()) return; SessionHandler.sendPlayerAction(PlayerAction.USE_FIRST_MANA_ABILITY_OFF, gameId, null); setMenuStates( PreferencesDialog.getCachedValue(KEY_GAME_MANA_AUTOPAYMENT, "true").equals("true"), @@ -1668,28 +1892,16 @@ public final class GamePanel extends javax.swing.JPanel { btnSwitchHands.setIcon(new ImageIcon(ImageManagerImpl.instance.getSwitchHandsButtonImage())); btnSwitchHands.setFocusable(false); btnSwitchHands.setToolTipText("Switch between your hand cards and hand cards of controlled players."); - btnSwitchHands.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnSwitchHandActionPerformed(null); - } - } - }); + btnSwitchHands.addMouseListener(new FirstButtonMousePressedAction(e -> + btnSwitchHandActionPerformed(null))); btnStopWatching.setContentAreaFilled(false); btnStopWatching.setBorder(new EmptyBorder(0, 0, 0, 0)); btnStopWatching.setIcon(new ImageIcon(ImageManagerImpl.instance.getStopWatchButtonImage())); btnStopWatching.setFocusable(false); btnStopWatching.setToolTipText("Stop watching this game."); - btnStopWatching.addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent evt) { - if (evt.getButton() == MouseEvent.BUTTON1) { - btnStopWatchingActionPerformed(null); - } - } - }); + btnStopWatching.addMouseListener(new FirstButtonMousePressedAction(e -> + btnStopWatchingActionPerformed(null))); stackObjects.setBackgroundColor(new Color(0, 0, 0, 40)); @@ -1810,8 +2022,8 @@ public final class GamePanel extends javax.swing.JPanel { } }; String[] phases = {"Untap", "Upkeep", "Draw", "Main1", - "Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End", - "Main2", "Cleanup", "Next_Turn"}; + "Combat_Start", "Combat_Attack", "Combat_Block", "Combat_Damage", "Combat_End", + "Main2", "Cleanup", "Next_Turn"}; for (String name : phases) { createPhaseButton(name, phasesMouseAdapter); } @@ -2019,66 +2231,100 @@ public final class GamePanel extends javax.swing.JPanel { private void btnToggleMacroActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.TOGGLE_RECORD_MACRO, gameId, null); + skipButtons.activateSkipButton(""); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, false, false, false); - if (btnToggleMacro.getBorder() instanceof EmptyBorder) { - btnToggleMacro.setBorder(new LineBorder(Color.orange, BORDER_SIZE)); + if (btnToggleMacro.getBorder().equals(BORDER_ACTIVE)) { + btnToggleMacro.setBorder(BORDER_NON_ACTIVE); } else { - btnToggleMacro.setBorder(new EmptyBorder(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE)); + btnToggleMacro.setBorder(BORDER_ACTIVE); } } private void btnEndTurnActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_NEXT_TURN); + AudioManager.playOnSkipButton(); - updateSkipButtons(true, false, false, false, false, false); + updateSkipButtons(); + } + + private boolean isChatInputUnderCursor(Point p) { + Component c = this.getComponentAt(p); + return gameChatPanel.getTxtMessageInputComponent().equals(c) || userChatPanel.getTxtMessageInputComponent().equals(c); + } + + private boolean isChatInputActive() { + Component c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + return gameChatPanel.getTxtMessageInputComponent().equals(c) || userChatPanel.getTxtMessageInputComponent().equals(c); + } + + private boolean isUserImputActive() { + // any imput or choose dialog active (need to disable skip buttons in dialogs and chat) + return MageDialog.isModalDialogActivated() || isChatInputActive(); } private void btnUntilEndOfTurnActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_TURN_END_STEP, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_END_STEP); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, true, false, false, false, false); + updateSkipButtons(); } private void btnEndTurnSkipStackActionPerformed(java.awt.event.ActionEvent evt) { + logger.error("Skip action don't used", new Throwable()); + /* SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_TURN_SKIP_STACK, gameId, null); AudioManager.playOnSkipButton(); updateSkipButtons(true, false, false, false, true, false); + */ } private void btnUntilNextMainPhaseActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_NEXT_MAIN_PHASE, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_MAIN_STEP); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, true, false, false, false); + updateSkipButtons(); } private void btnPassPriorityUntilNextYourTurnActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_MY_NEXT_TURN, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_YOUR_TURN); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, true, false, false); + updateSkipButtons(); } private void btnPassPriorityUntilStackResolvedActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_STACK_RESOLVED, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_SKIP_STACK); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, false, true, false); + updateSkipButtons(); } private void btnSkipToEndStepBeforeYourTurnActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_END_STEP_BEFORE_MY_NEXT_TURN, gameId, null); + skipButtons.activateSkipButton(KEY_CONTROL_PRIOR_END); + AudioManager.playOnSkipButton(); - updateSkipButtons(false, false, false, false, false, true); + updateSkipButtons(); } private void restorePriorityActionPerformed(java.awt.event.ActionEvent evt) { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_CANCEL_ALL_ACTIONS, gameId, null); + skipButtons.activateSkipButton(""); + AudioManager.playOnSkipButtonCancel(); - updateSkipButtons(false, false, false, false, false, false); + updateSkipButtons(); } private void mouseClickPhaseBar(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) { // Left button PreferencesDialog.main(new String[]{PreferencesDialog.OPEN_PHASES_TAB}); + // TODO: add event handler on preferences closed and refresh game data from server } } @@ -2214,6 +2460,8 @@ public final class GamePanel extends javax.swing.JPanel { case CMD_AUTO_ORDER_RESET_ALL: SessionHandler.sendPlayerAction(TRIGGER_AUTO_ORDER_RESET_ALL, gameId, null); break; + default: + break; } for (ShowCardsDialog dialog : pickTarget) { dialog.removeDialog(); @@ -2279,6 +2527,13 @@ public final class GamePanel extends javax.swing.JPanel { boolean isActionEvent = false; if (id == MouseEvent.MOUSE_PRESSED) { isActionEvent = true; + // clear chat focus on click + if (event instanceof MouseEvent) { + MouseEvent me = (MouseEvent) event; + if (isChatInputActive() && !isChatInputUnderCursor(me.getPoint())) { + KeyboardFocusManager.getCurrentKeyboardFocusManager().clearFocusOwner(); + } + } } else if (id == KeyEvent.KEY_PRESSED) { KeyEvent key = (KeyEvent) event; int keyCode = key.getKeyCode(); diff --git a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java index c9a81633cc..45fc243a68 100644 --- a/Mage.Client/src/main/java/mage/client/game/HelperPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/HelperPanel.java @@ -1,40 +1,23 @@ package mage.client.game; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.util.ArrayList; -import java.util.UUID; -import javax.swing.JButton; -import javax.swing.JMenuItem; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.ScrollPaneConstants; -import javax.swing.SwingUtilities; -import javax.swing.ToolTipManager; -import javax.swing.UIManager; -import javax.swing.border.EmptyBorder; - import mage.client.SessionHandler; import mage.client.components.MageTextArea; import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; import mage.client.game.FeedbackPanel.FeedbackMode; - -import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION; import mage.client.util.GUISizeHelper; import mage.constants.TurnPhase; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_NO; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_ID_YES; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_NO; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_TEXT_YES; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import java.awt.*; +import java.awt.event.*; +import java.util.ArrayList; +import java.util.UUID; + +import static mage.client.game.FeedbackPanel.FeedbackMode.QUESTION; +import static mage.constants.PlayerAction.*; /** * Panel with buttons that copy the state of feedback panel. @@ -326,10 +309,18 @@ public class HelperPanel extends JPanel { this.buttonGrid.setPreferredSize(null); ArrayList buttons = new ArrayList<>(); - if (this.btnSpecial.isVisible()) { buttons.add(this.btnSpecial); } - if (this.btnLeft.isVisible()) { buttons.add(this.btnLeft); } - if (this.btnRight.isVisible()) { buttons.add(this.btnRight); } - if (this.btnUndo.isVisible()) { buttons.add(this.btnUndo); } + if (this.btnSpecial.isVisible()) { + buttons.add(this.btnSpecial); + } + if (this.btnLeft.isVisible()) { + buttons.add(this.btnLeft); + } + if (this.btnRight.isVisible()) { + buttons.add(this.btnRight); + } + if (this.btnUndo.isVisible()) { + buttons.add(this.btnUndo); + } // color panel on player's feedback waiting if (this.gameNeedFeedback) { @@ -360,10 +351,14 @@ public class HelperPanel extends JPanel { case COMBAT: backColor = ACTIVE_FEEDBACK_BACKGROUND_COLOR_BATTLE; break; + default: + break; } } this.mainPanel.setBackground(backColor); break; + default: + break; } } else { // inform about other players @@ -500,6 +495,8 @@ public class HelperPanel extends JPanel { case CMD_AUTO_ANSWER_RESET_ALL: SessionHandler.sendPlayerAction(REQUEST_AUTO_ANSWER_RESET_ALL, gameId, null); break; + default: + break; } } diff --git a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java index 42541329f9..b266d991c8 100644 --- a/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java +++ b/Mage.Client/src/main/java/mage/client/game/PlayAreaPanel.java @@ -20,7 +20,8 @@ import javax.swing.JPopupMenu; import javax.swing.LayoutStyle.ComponentPlacement; import javax.swing.MenuSelectionManager; import javax.swing.event.ChangeListener; -import mage.cards.decks.importer.DeckImporterUtil; + +import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.cards.BigCard; @@ -167,6 +168,8 @@ public class PlayAreaPanel extends javax.swing.JPanel { SessionHandler.sendPlayerAction(PlayerAction.PASS_PRIORITY_UNTIL_END_STEP_BEFORE_MY_NEXT_TURN, gameId, null); break; } + default: + break; } }; @@ -408,6 +411,8 @@ public class PlayAreaPanel extends javax.swing.JPanel { MageFrame.getInstance().showUserRequestDialog(message); break; } + default: + break; } }; @@ -569,7 +574,7 @@ public class PlayAreaPanel extends javax.swing.JPanel { } private void btnCheatActionPerformed(java.awt.event.ActionEvent evt) { - SessionHandler.cheat(gameId, playerId, DeckImporterUtil.importDeck("cheat.dck")); + SessionHandler.cheat(gameId, playerId, DeckImporter.importDeckFromFile("cheat.dck")); } public boolean isSmallMode() { diff --git a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java index 344e62c1b6..bd3d34052b 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java +++ b/Mage.Client/src/main/java/mage/client/plugins/adapters/MageActionCallback.java @@ -1,22 +1,5 @@ package mage.client.plugins.adapters; -import java.awt.Component; -import java.awt.Image; -import java.awt.Point; -import java.awt.event.MouseEvent; -import java.awt.event.MouseWheelEvent; -import java.awt.image.BufferedImage; -import java.util.*; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import javax.swing.JComponent; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.Popup; -import javax.swing.PopupFactory; -import javax.swing.SwingUtilities; import mage.cards.MageCard; import mage.cards.action.ActionCallback; import mage.cards.action.TransferData; @@ -42,6 +25,18 @@ import org.jdesktop.swingx.JXPanel; import org.mage.card.arcane.CardPanel; import org.mage.plugins.card.images.ImageCache; +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.image.BufferedImage; +import java.util.List; +import java.util.*; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + /** * Class that handles the callbacks from the card panels to mage to display big * card images from the cards the mouse hovers on. Also handles tooltip text @@ -116,7 +111,7 @@ public class MageActionCallback implements ActionCallback { } private void showTooltipPopup(final TransferData data, final Component parentComponent, final Point parentPoint) { - if (data.component != null) { + if (data.getComponent() != null) { tooltipDelay = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_SHOW_TOOLTIPS_DELAY, 300); if (tooltipDelay == 0) { return; @@ -125,18 +120,18 @@ public class MageActionCallback implements ActionCallback { if (cardInfoPane == null) { PopupFactory factory = PopupFactory.getSharedInstance(); - if (data.locationOnScreen == null) { - if (data.component == null) { + if (data.getLocationOnScreen() == null) { + if (data.getComponent() == null) { return; } - data.locationOnScreen = data.component.getLocationOnScreen(); + data.setLocationOnScreen(data.getComponent().getLocationOnScreen()); } - data.popupText.updateText(); - tooltipPopup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); + data.getPopupText().updateText(); + tooltipPopup = factory.getPopup(data.getComponent(), data.getPopupText(), (int) data.getLocationOnScreen().getX() + data.getPopupOffsetX(), (int) data.getLocationOnScreen().getY() + data.getPopupOffsetY() + 40); tooltipPopup.show(); // hack to get popup to resize to fit text tooltipPopup.hide(); - tooltipPopup = factory.getPopup(data.component, data.popupText, (int) data.locationOnScreen.getX() + data.popupOffsetX, (int) data.locationOnScreen.getY() + data.popupOffsetY + 40); + tooltipPopup = factory.getPopup(data.getComponent(), data.getPopupText(), (int) data.getLocationOnScreen().getX() + data.getPopupOffsetX(), (int) data.getLocationOnScreen().getY() + data.getPopupOffsetY() + 40); tooltipPopup.show(); } else { sumbitShowPopupTask(data, parentComponent, parentPoint); @@ -150,7 +145,7 @@ public class MageActionCallback implements ActionCallback { ThreadUtils.sleep(tooltipDelay); if (tooltipCard == null - || !tooltipCard.equals(data.card) + || !tooltipCard.equals(data.getCard()) || SessionHandler.getSession() == null || !popupTextWindowOpen || enlargedWindowState != EnlargedWindowState.CLOSED) { @@ -159,35 +154,33 @@ public class MageActionCallback implements ActionCallback { try { final Component popupContainer = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); - Component popup2 = MageFrame.getUI().getComponent(MageComponents.CARD_INFO_PANE); - - ((CardInfoPane) popup2).setCard(data.card, popupContainer); - - showPopup(popupContainer, popup2); - + Component popupInfo = MageFrame.getUI().getComponent(MageComponents.CARD_INFO_PANE); + ((CardInfoPane) popupInfo).setCard(data.getCard(), popupContainer); + showPopup(popupContainer, popupInfo); } catch (InterruptedException e) { - LOGGER.warn(e.getMessage()); + LOGGER.error("Can't show card tooltip", e); + Thread.currentThread().interrupt(); } } public void showPopup(final Component popupContainer, final Component infoPane) throws InterruptedException { final Component c = MageFrame.getUI().getComponent(MageComponents.DESKTOP_PANE); SwingUtilities.invokeLater(() -> { - if (!popupTextWindowOpen - || enlargedWindowState != EnlargedWindowState.CLOSED) { - return; - } - if (data.locationOnScreen == null) { - data.locationOnScreen = data.component.getLocationOnScreen(); - } + if (!popupTextWindowOpen || enlargedWindowState != EnlargedWindowState.CLOSED) { + return; + } - Point location = new Point((int) data.locationOnScreen.getX() + data.popupOffsetX - 40, (int) data.locationOnScreen.getY() + data.popupOffsetY - 40); - location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, infoPane, parentComponent); - location.translate(-parentPoint.x, -parentPoint.y); - popupContainer.setLocation(location); - popupContainer.setVisible(true); - c.repaint(); - } + if (data.getLocationOnScreen() == null) { + data.setLocationOnScreen(data.getComponent().getLocationOnScreen()); + } + + Point location = new Point((int) data.getLocationOnScreen().getX() + data.getPopupOffsetX() - 40, (int) data.getLocationOnScreen().getY() + data.getPopupOffsetY() - 40); + location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, infoPane, parentComponent); + location.translate(-parentPoint.x, -parentPoint.y); + popupContainer.setLocation(location); + popupContainer.setVisible(true); + c.repaint(); + } ); } }); @@ -195,7 +188,7 @@ public class MageActionCallback implements ActionCallback { @Override public void mousePressed(MouseEvent e, TransferData data) { - data.component.requestFocusInWindow(); + data.getComponent().requestFocusInWindow(); // for some reason sometime mouseRelease happens before numerous Mouse_Dragged events // that results in not finished dragging @@ -206,23 +199,23 @@ public class MageActionCallback implements ActionCallback { prevCardPanel = null; cardPanels.clear(); Point mouse = new Point(e.getX(), e.getY()); - SwingUtilities.convertPointToScreen(mouse, data.component); + SwingUtilities.convertPointToScreen(mouse, data.getComponent()); initialMousePos = new Point((int) mouse.getX(), (int) mouse.getY()); - initialCardPos = data.component.getLocation(); + initialCardPos = data.getComponent().getLocation(); // Closes popup & enlarged view if a card/Permanent is selected hideTooltipPopup(); } @Override public void mouseReleased(MouseEvent e, TransferData transferData) { - CardPanel card = ((CardPanel) transferData.component); + CardPanel card = ((CardPanel) transferData.getComponent()); if (e.isPopupTrigger() /*&& card.getPopupMenu() != null*/) { hideTooltipPopup(); } else if (card.getZone() != null && card.getZone().equalsIgnoreCase("hand")) { int maxXOffset = 0; if (isDragging) { Point mouse = new Point(e.getX(), e.getY()); - SwingUtilities.convertPointToScreen(mouse, transferData.component); + SwingUtilities.convertPointToScreen(mouse, transferData.getComponent()); maxXOffset = Math.abs((int) (mouse.getX() - initialMousePos.x)); } @@ -230,15 +223,15 @@ public class MageActionCallback implements ActionCallback { this.startedDragging = false; if (maxXOffset < MIN_X_OFFSET_REQUIRED) { // we need this for protection from small card movements - transferData.component.requestFocusInWindow(); - DefaultActionCallback.instance.mouseClicked(transferData.gameId, transferData.card); + transferData.getComponent().requestFocusInWindow(); + DefaultActionCallback.instance.mouseClicked(transferData.getGameId(), transferData.getCard()); // Closes popup & enlarged view if a card/Permanent is selected hideTooltipPopup(); } e.consume(); } else { - transferData.component.requestFocusInWindow(); - DefaultActionCallback.instance.mouseClicked(transferData.gameId, transferData.card); + transferData.getComponent().requestFocusInWindow(); + DefaultActionCallback.instance.mouseClicked(transferData.getGameId(), transferData.getCard()); // Closes popup & enlarged view if a card/Permanent is selected hideTooltipPopup(); e.consume(); @@ -266,7 +259,7 @@ public class MageActionCallback implements ActionCallback { if (!Plugins.instance.isCardPluginLoaded()) { return; } - if (!popupData.card.equals(transferData.card)) { + if (!popupData.getCard().equals(transferData.getCard())) { this.popupData = transferData; handleOverNewView(transferData); @@ -279,7 +272,7 @@ public class MageActionCallback implements ActionCallback { @Override public void mouseDragged(MouseEvent e, TransferData transferData) { - CardPanel cardPanel = ((CardPanel) transferData.component); + CardPanel cardPanel = ((CardPanel) transferData.getComponent()); if (cardPanel.getZone() == null || !cardPanel.getZone().equalsIgnoreCase("hand")) { // drag'n'drop is allowed for HAND zone only return; @@ -292,7 +285,7 @@ public class MageActionCallback implements ActionCallback { prevCardPanel = cardPanel; Point cardPanelLocationOld = cardPanel.getLocation(); Point mouse = new Point(e.getX(), e.getY()); - SwingUtilities.convertPointToScreen(mouse, transferData.component); + SwingUtilities.convertPointToScreen(mouse, transferData.getComponent()); int xOffset = cardPanel.getXOffset(cardPanel.getCardWidth()); int newX = Math.max(initialCardPos.x + (int) (mouse.getX() - initialMousePos.x) - xOffset, 0); cardPanel.setCardBounds( @@ -311,7 +304,7 @@ public class MageActionCallback implements ActionCallback { @Override public void mouseExited(MouseEvent e, final TransferData data) { if (data != null) { - hideAll(data.gameId); + hideAll(data.getGameId()); } else { hideAll(null); } @@ -367,20 +360,20 @@ public class MageActionCallback implements ActionCallback { // Prevent to show tooltips from panes not in front MagePane topPane = MageFrame.getTopMost(null); if (topPane instanceof GamePane) { - if (!((GamePane) topPane).getGameId().equals(data.gameId)) { + if (!((GamePane) topPane).getGameId().equals(data.getGameId())) { return; } - } else if (data.gameId != null) { + } else if (data.getGameId() != null) { return; } hideTooltipPopup(); cancelTimeout(); - Component parentComponent = SwingUtilities.getRoot(data.component); + Component parentComponent = SwingUtilities.getRoot(data.getComponent()); Point parentPoint = parentComponent.getLocationOnScreen(); - if (data.locationOnScreen == null) { - data.locationOnScreen = data.component.getLocationOnScreen(); + if (data.getLocationOnScreen() == null) { + data.setLocationOnScreen(data.getComponent().getLocationOnScreen()); } ArrowUtil.drawArrowsForTargets(data, parentPoint); @@ -388,12 +381,13 @@ public class MageActionCallback implements ActionCallback { ArrowUtil.drawArrowsForPairedCards(data, parentPoint); ArrowUtil.drawArrowsForBandedCards(data, parentPoint); ArrowUtil.drawArrowsForEnchantPlayers(data, parentPoint); - tooltipCard = data.card; + + tooltipCard = data.getCard(); showTooltipPopup(data, parentComponent, parentPoint); } private void handlePopup(TransferData transferData) { - MageCard mageCard = (MageCard) transferData.component; + MageCard mageCard = (MageCard) transferData.getComponent(); if (!popupTextWindowOpen || !Objects.equals(mageCard.getOriginal().getId(), bigCard.getCardId())) { if (bigCard.getWidth() > 0) { @@ -419,13 +413,9 @@ public class MageActionCallback implements ActionCallback { @Override public void hideOpenComponents() { - this.hideTooltipPopup(); - this.hideEnlargedCard(); + hideAll(null); } - /** - * Hides the text popup window - */ public void hideTooltipPopup() { this.tooltipCard = null; if (tooltipPopup != null) { @@ -438,11 +428,11 @@ public class MageActionCallback implements ActionCallback { if (SessionHandler.getSession() == null) { return; } - // set enlarged card display to visible = false Component popupContainer = MageFrame.getUI().getComponent(MageComponents.POPUP_CONTAINER); popupContainer.setVisible(false); - } catch (Exception e2) { - LOGGER.warn("Can't set tooltip to visible = false", e2); + } catch (InterruptedException e) { + LOGGER.error("Can't hide card tooltip", e); + Thread.currentThread().interrupt(); } } @@ -500,14 +490,14 @@ public class MageActionCallback implements ActionCallback { * Show the big card image on mouse position while hovering over a card * * @param showAlternative defines if the original image (if it's a copied - * card) or the opposite side of a transformable card will be shown + * card) or the opposite side of a transformable card will be shown */ public void enlargeCard(EnlargeMode showAlternative) { if (enlargedWindowState == EnlargedWindowState.CLOSED) { this.enlargeMode = showAlternative; CardView cardView = null; if (popupData != null) { - cardView = popupData.card; + cardView = popupData.getCard(); } if (this.popupTextWindowOpen) { hideTooltipPopup(); @@ -571,17 +561,17 @@ public class MageActionCallback implements ActionCallback { } final Component popupContainer = MageFrame.getUI().getComponent(mageComponentCardPreviewContainer); Component cardPreviewPane = MageFrame.getUI().getComponent(mageComponentCardPreviewPane); - Component parentComponent = SwingUtilities.getRoot(transferData.component); + Component parentComponent = SwingUtilities.getRoot(transferData.getComponent()); if (cardPreviewPane != null && parentComponent != null) { Point parentPoint = parentComponent.getLocationOnScreen(); - transferData.locationOnScreen = transferData.component.getLocationOnScreen(); - Point location = new Point((int) transferData.locationOnScreen.getX() + transferData.popupOffsetX - 40, (int) transferData.locationOnScreen.getY() + transferData.popupOffsetY - 40); + transferData.setLocationOnScreen(transferData.getComponent().getLocationOnScreen()); + Point location = new Point((int) transferData.getLocationOnScreen().getX() + transferData.getPopupOffsetX() - 40, (int) transferData.getLocationOnScreen().getY() + transferData.getPopupOffsetY() - 40); location = GuiDisplayUtil.keepComponentInsideParent(location, parentPoint, cardPreviewPane, parentComponent); location.translate(-parentPoint.x, -parentPoint.y); popupContainer.setLocation(location); popupContainer.setVisible(true); - MageCard mageCard = (MageCard) transferData.component; + MageCard mageCard = (MageCard) transferData.getComponent(); Image image = null; switch (enlargeMode) { case COPY: @@ -598,6 +588,8 @@ public class MageActionCallback implements ActionCallback { } } break; + default: + break; } if (image == null) { image = mageCard.getImage(); diff --git a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java index d9f1fef14f..e63d104219 100644 --- a/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java +++ b/Mage.Client/src/main/java/mage/client/plugins/impl/Plugins.java @@ -26,6 +26,8 @@ import mage.view.CardView; import mage.view.PermanentView; import net.xeoh.plugins.base.PluginManager; import net.xeoh.plugins.base.impl.PluginManagerFactory; +import net.xeoh.plugins.base.util.uri.ClassURI; + import org.apache.log4j.Logger; import org.mage.plugins.card.CardPluginImpl; import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; @@ -46,13 +48,15 @@ public enum Plugins implements MagePlugins { @Override public void loadPlugins() { - LOGGER.info("Loading plugins..."); pm = PluginManagerFactory.createPluginManager(); pm.addPluginsFrom(new File(PLUGINS_DIRECTORY + File.separator).toURI()); - this.cardPlugin = new CardPluginImpl(); + pm.addPluginsFrom(new ClassURI(CardPluginImpl.class).toURI()); + pm.addPluginsFrom(new ClassURI(ThemePluginImpl.class).toURI()); + + this.cardPlugin = pm.getPlugin(CardPlugin.class); this.counterPlugin = pm.getPlugin(CounterPlugin.class); - this.themePlugin = new ThemePluginImpl(); + this.themePlugin = pm.getPlugin(ThemePlugin.class); LOGGER.info("Done."); } @@ -65,15 +69,11 @@ public enum Plugins implements MagePlugins { @Override public void changeGUISize() { - setGUISize(); if (this.cardPlugin != null) { cardPlugin.changeGUISize(); } } - private void setGUISize() { - - } @Override public void updateGamePanel(Map ui) { diff --git a/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java index 7b17194867..37e84edc6d 100644 --- a/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java +++ b/Mage.Client/src/main/java/mage/client/preference/MagePreferences.java @@ -2,6 +2,7 @@ package mage.client.preference; import com.google.common.collect.Sets; import mage.client.MageFrame; +import mage.client.util.Config; import java.util.Set; import java.util.prefs.BackingStoreException; @@ -16,9 +17,13 @@ public final class MagePreferences { private static final String KEY_PASSWORD = "password"; private static final String KEY_EMAIL = "email"; private static final String KEY_AUTO_CONNECT = "autoConnect"; - private static final String NODE_KEY_IGNORE_LIST = "ignoreListString"; + private static String lastServerAddress = ""; + private static int lastServerPort = 0; + private static String lastServerUser = ""; + private static String lastServerPassword = ""; + private static Preferences prefs() { // TODO: Move MageFrame.prefs to this class. return MageFrame.getPreferences(); @@ -138,4 +143,26 @@ public final class MagePreferences { return prefs().node(NODE_KEY_IGNORE_LIST).node(serverAddress); } + public static void saveLastServer() { + lastServerAddress = getServerAddressWithDefault(Config.serverName); + lastServerPort = getServerPortWithDefault(Config.port); + lastServerUser = getUserName(lastServerAddress); + lastServerPassword = getPassword(lastServerAddress); + } + + public static String getLastServerAddress() { + return lastServerAddress.isEmpty() ? getServerAddress() : lastServerAddress; + } + + public static int getLastServerPort() { + return lastServerPort == 0 ? getServerPort() : lastServerPort; + } + + public static String getLastServerUser() { + return lastServerUser.isEmpty() ? getUserName(getLastServerAddress()) : lastServerUser; + } + + public static String getLastServerPassword() { + return lastServerPassword.isEmpty() ? getPassword(getLastServerAddress()) : lastServerPassword; + } } diff --git a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java index f71b122591..3f7501c184 100644 --- a/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java +++ b/Mage.Client/src/main/java/mage/client/remote/CallbackClientImpl.java @@ -1,10 +1,5 @@ - package mage.client.remote; -import java.awt.event.KeyEvent; -import java.util.List; -import java.util.UUID; -import javax.swing.*; import mage.cards.decks.Deck; import mage.client.MageFrame; import mage.client.SessionHandler; @@ -28,8 +23,12 @@ import mage.view.*; import mage.view.ChatMessage.MessageType; import org.apache.log4j.Logger; +import javax.swing.*; +import java.awt.event.KeyEvent; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class CallbackClientImpl implements CallbackClient { @@ -158,7 +157,7 @@ public class CallbackClientImpl implements CallbackClient { case GAME_INIT: { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { - appendJsonEvent("GAME_INIT", callback.getObjectId(), (GameView) callback.getData()); + appendJsonEvent("GAME_INIT", callback.getObjectId(), callback.getData()); panel.init((GameView) callback.getData()); } break; @@ -214,7 +213,7 @@ public class CallbackClientImpl implements CallbackClient { case GAME_CHOOSE_ABILITY: { GamePanel panel = MageFrame.getGame(callback.getObjectId()); if (panel != null) { - appendJsonEvent("GAME_CHOOSE_PILE", callback.getObjectId(), callback.getData()); + appendJsonEvent("GAME_CHOOSE_ABILITY", callback.getObjectId(), callback.getData()); panel.pickAbility((AbilityPickerView) callback.getData()); } break; @@ -353,8 +352,9 @@ public class CallbackClientImpl implements CallbackClient { } case DRAFT_UPDATE: { DraftPanel panel = MageFrame.getDraft(callback.getObjectId()); + DraftClientMessage message = (DraftClientMessage) callback.getData(); if (panel != null) { - panel.updateDraft((DraftView) callback.getData()); + panel.updateDraft(message.getDraftView()); } break; } @@ -371,6 +371,8 @@ public class CallbackClientImpl implements CallbackClient { case USER_REQUEST_DIALOG: frame.showUserRequestDialog((UserRequestMessage) callback.getData()); break; + default: + break; } messageId = callback.getMessageId(); } catch (Exception ex) { @@ -399,36 +401,41 @@ public class CallbackClientImpl implements CallbackClient { switch (usedPanel.getChatType()) { case GAME: usedPanel.receiveMessage("", new StringBuilder("You may use hot keys to play faster:") - .append("
Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over") - .append("
Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_CONFIRM, 113))) - .append(" - Confirm \"Ok\", \"Yes\" or \"Done\" button") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_NEXT_TURN, 115))) - .append(" - Skip current turn but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_END_STEP, 116))) - .append(" - Skip to next end step but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_SKIP_STEP, 117))) - .append(" - Skip current turn but stop on declare attackers/blockers") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_MAIN_STEP, 118))) - .append(" - Skip to next main phase but stop on declare attackers/blockers and something on the stack") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_YOUR_TURN, 120))) - .append(" - Skip everything until your next turn") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_PRIOR_END, 122))) - .append(" - Skip everything until the end step just prior to your turn") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP, 114))) - .append(" - Undo F4/F5/F7/F9/F11") - .append("
") - .append(KeyEvent.getKeyText(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CONTROL_TOGGLE_MACRO, 119))) - .append(" - Toggle recording a sequence of actions to repeat. Will not pause if interrupted and can fail if a selected card changes such as when scrying top card to bottom.") - .append("
").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click - Hold priority while casting a spell or activating an ability").toString(), + .append("
Turn mousewheel up (ALT-e) - enlarge image of card the mousepointer hovers over") + .append("
Turn mousewheel down (ALT-s) - enlarge original/alternate image of card the mousepointer hovers over") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CONFIRM))) + .append(" - Confirm \"Ok\", \"Yes\" or \"Done\" button") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_NEXT_TURN))) + .append(" - Skip current turn but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_END_STEP))) + .append(" - Skip to next end step but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SKIP_STEP))) + .append(" - Skip current turn but stop on declare attackers/blockers") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_MAIN_STEP))) + .append(" - Skip to next main phase but stop on declare attackers/blockers and something on the stack") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_YOUR_TURN))) + .append(" - Skip everything until your next turn") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_PRIOR_END))) + .append(" - Skip everything until the end step just prior to your turn") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_CANCEL_SKIP))) + .append(" - Undo F4/F5/F7/F9/F11") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_SWITCH_CHAT))) + .append(" - Switth in/out to chat text field") + .append("
") + .append(KeyEvent.getKeyText(PreferencesDialog.getCurrentControlKey(PreferencesDialog.KEY_CONTROL_TOGGLE_MACRO))) + .append(" - Toggle recording a sequence of actions to repeat. Will not pause if interrupted and can fail if a selected card changes such as when scrying top card to bottom.") + .append("
").append(System.getProperty("os.name").contains("Mac OS X") ? "Cmd" : "Ctrl").append(" + click - Hold priority while casting a spell or activating an ability") + .append("
").append("Type /FIX message in chat to fix freezed game") + .toString(), null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; case TOURNAMENT: @@ -437,12 +444,14 @@ public class CallbackClientImpl implements CallbackClient { break; case TABLES: usedPanel.receiveMessage("", new StringBuilder("Download card images by using the \"Images\" menu to the top right .") - .append("
Download icons and symbols by using the \"Symbols\" menu to the top right.") - .append("
\\list - Show a list of available chat commands.") - .append("
").append(IgnoreList.usage()) - .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), + .append("
Download icons and symbols by using the \"Symbols\" menu to the top right.") + .append("
\\list - Show a list of available chat commands.") + .append("
").append(IgnoreList.usage()) + .append("
Type \\w yourUserName profanity 0 (or 1 or 2) to turn off/on the profanity filter").toString(), null, MessageType.USER_INFO, ChatMessage.MessageColor.BLUE); break; + default: + break; } } diff --git a/Mage.Client/src/main/java/mage/client/table/ColumnInfo.java b/Mage.Client/src/main/java/mage/client/table/ColumnInfo.java new file mode 100644 index 0000000000..d8a3a9ebba --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/ColumnInfo.java @@ -0,0 +1,41 @@ +package mage.client.table; + +/** + * @author JayDi85 + */ +public class ColumnInfo { + private Integer index; + private Integer width; + private String headerName; + private String headerHint; + private Class colClass; + + public ColumnInfo(Integer index, Integer width, Class colClass, String headerName, String headerHint) { + this.index = index; + this.width = width; + this.colClass = colClass; + this.headerName = headerName; + this.headerHint = headerHint; + } + + + public Integer getIndex() { + return index; + } + + public Integer getWidth() { + return width; + } + + public String getHeaderName() { + return headerName; + } + + public String getHeaderHint() { + return headerHint; + } + + public Class getColClass() { + return colClass; + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/MageTable.java b/Mage.Client/src/main/java/mage/client/table/MageTable.java new file mode 100644 index 0000000000..2162acaf3e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/MageTable.java @@ -0,0 +1,69 @@ +package mage.client.table; + +import mage.client.util.GUISizeHelper; +import org.apache.log4j.Logger; + +import javax.swing.*; +import javax.swing.table.JTableHeader; +import javax.swing.table.TableColumn; +import java.awt.event.MouseEvent; + +/** + * @author JayDi85 + */ +public class MageTable extends JTable { + + private static final Logger logger = Logger.getLogger(MageTable.class); + private TableInfo tableInfo; + + public MageTable() { + this(null); + } + + public MageTable(TableInfo tableInfo) { + this.tableInfo = tableInfo; + } + + @Override + public String getToolTipText(MouseEvent e) { + // default tooltip for cells + java.awt.Point p = e.getPoint(); + int viewRow = rowAtPoint(p); + int viewCol = columnAtPoint(p); + int modelRow = TablesUtil.getModelRowFromView(this, viewRow); + int modelCol = this.convertColumnIndexToModel(viewCol); + String tip = null; + if (modelRow != -1 && modelCol != -1) { + tip = this.getModel().getValueAt(modelRow, modelCol).toString(); + } + return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont); + } + + @Override + protected JTableHeader createDefaultTableHeader() { + // default tooltip for headers + return new JTableHeader(columnModel) { + public String getToolTipText(MouseEvent e) { + // html tooltip + java.awt.Point p = e.getPoint(); + int colIndex = columnModel.getColumnIndexAtX(p.x); + TableColumn col = columnModel.getColumn(colIndex); + int realIndex = col.getModelIndex(); + + String tip; + if (tableInfo != null) { + // custom hint from table info + tip = tableInfo.getColumnByIndex(realIndex).getHeaderHint(); + if (tip == null) { + tip = tableInfo.getColumnByIndex(realIndex).getHeaderName(); + } + } else { + // default hint from header + tip = col.getHeaderValue().toString(); + } + + return GUISizeHelper.textToHtmlWithSize(tip, GUISizeHelper.tableFont); + } + }; + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java b/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java new file mode 100644 index 0000000000..b842686d6e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/MatchesTableModel.java @@ -0,0 +1,146 @@ +package mage.client.table; + +import mage.remote.MageRemoteException; +import mage.view.MatchView; + +import javax.swing.table.AbstractTableModel; +import java.util.Collection; +import java.util.Date; +import java.util.UUID; + +public class MatchesTableModel extends AbstractTableModel { + + private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Duration", "Start Time", "End Time", "Action"}; + public static final int COLUMN_DURATION = 5; + public static final int COLUMN_START = 6; + public static final int COLUMN_END = 7; + public static final int COLUMN_ACTION = 8; // column the action is located (starting with 0) + + private MatchView[] matches = new MatchView[0]; + + public void loadData(Collection matches) throws MageRemoteException { + this.matches = matches.toArray(new MatchView[0]); + this.fireTableDataChanged(); + } + + MatchesTableModel() { + } + + + public String getTableAndGameInfo(int row) { + return this.matches[row].getTableId().toString() + ";" + (!matches[row].getGames().isEmpty() ? matches[row].getGames().get(0).toString() : "null"); + } + + public String findTableAndGameInfoByRow(int row) { + if (row >= 0 && row < this.matches.length) { + return getTableAndGameInfo(row); + } else { + return null; + } + } + + public int findRowByTableAndGameInfo(String tableAndGame) { + for (int i = 0; i < this.matches.length; i++) { + String rowID = this.matches[i].getTableId().toString() + ";" + (!this.matches[i].getGames().isEmpty() ? this.matches[i].getGames().get(0).toString() : "null"); + if (tableAndGame.equals(rowID)) { + return i; + } + } + return -1; + } + + @Override + public int getRowCount() { + return matches.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int arg0, int arg1) { + switch (arg1) { + case 0: + return matches[arg0].getDeckType(); + case 1: + return matches[arg0].getPlayers(); + case 2: + return matches[arg0].getGameType(); + case 3: + return matches[arg0].isRated() ? TablesTableModel.RATED_VALUE_YES : TablesTableModel.RATED_VALUE_NO; + case 4: + return matches[arg0].getResult(); + case 5: + if (matches[arg0].getEndTime() != null) { + return matches[arg0].getEndTime().getTime() - matches[arg0].getStartTime().getTime() + new Date().getTime(); + } else { + return 0L; + } + case 6: + return matches[arg0].getStartTime(); + case 7: + return matches[arg0].getEndTime(); + case 8: + if (matches[arg0].isTournament()) { + return "Show"; + } else if (matches[arg0].isReplayAvailable()) { + return "Replay"; + } else { + return "None"; + } + case 9: + return matches[arg0].getGames(); + default: + return ""; + } + } + + public java.util.List getListofGames(int row) { + return matches[row].getGames(); + } + + public boolean isTournament(int row) { + return matches[row].isTournament(); + } + + public UUID getMatchId(int row) { + return matches[row].getMatchId(); + } + + public UUID getTableId(int row) { + return matches[row].getTableId(); + } + + @Override + public String getColumnName(int columnIndex) { + String colName = ""; + + if (columnIndex <= getColumnCount()) { + colName = columnNames[columnIndex]; + } + + return colName; + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case COLUMN_DURATION: + return Long.class; + case COLUMN_START: + return Date.class; + case COLUMN_END: + return Date.class; + default: + return String.class; + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == COLUMN_ACTION; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/table/NewPlayerPanel.java b/Mage.Client/src/main/java/mage/client/table/NewPlayerPanel.java index f2e8b484a8..c735906900 100644 --- a/Mage.Client/src/main/java/mage/client/table/NewPlayerPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/NewPlayerPanel.java @@ -12,6 +12,8 @@ import java.io.IOException; import java.util.Locale; import javax.swing.*; import javax.swing.filechooser.FileFilter; + +import mage.cards.decks.DeckFileFilter; import mage.client.MageFrame; import mage.client.deck.generator.DeckGenerator; import mage.client.util.Config; @@ -31,7 +33,7 @@ public class NewPlayerPanel extends javax.swing.JPanel { initComponents(); fcSelectDeck = new JFileChooser(); fcSelectDeck.setAcceptAllFileFilterUsed(false); - fcSelectDeck.addChoosableFileFilter(new DeckFilter()); + fcSelectDeck.addChoosableFileFilter(new DeckFileFilter("dck", "XMage's deck files (*.dck)")); String deckPath = MageFrame.getPreferences().get("defaultDeckPath", ""); if (deckPath.isEmpty()) { if (Config.defaultDeckPath != null) { @@ -197,29 +199,4 @@ public class NewPlayerPanel extends javax.swing.JPanel { private javax.swing.JTextField txtPlayerName; // End of variables declaration//GEN-END:variables -} - -class DeckFilter extends FileFilter { - - @Override - public boolean accept(File f) { - if (f.isDirectory()) { - return true; - } - - String ext = null; - String s = f.getName(); - int i = s.lastIndexOf('.'); - - if (i > 0 && i < s.length() - 1) { - ext = s.substring(i + 1).toLowerCase(Locale.ENGLISH); - } - return (ext == null) ? false : ext.equals("dck"); - } - - @Override - public String getDescription() { - return "Deck Files"; - } - -} +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java index 732e6f21a1..032ef1ea65 100644 --- a/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/PlayersChatPanel.java @@ -1,13 +1,5 @@ - - - /* - * ChatPanel.java - * - * Created on 15-Dec-2009, 11:04:31 PM - */ package mage.client.table; -import mage.client.MageFrame; import mage.client.chat.ChatPanelBasic; import mage.client.util.GUISizeHelper; import mage.client.util.MageTableRowSorter; @@ -16,18 +8,15 @@ import mage.client.util.gui.countryBox.CountryCellRenderer; import mage.remote.MageRemoteException; import mage.view.RoomUsersView; import mage.view.UsersView; -import net.java.balloontip.utils.ToolTipUtils; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.table.AbstractTableModel; import javax.swing.table.JTableHeader; -import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import java.awt.*; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionAdapter; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import static mage.client.chat.ChatPanelBasic.CHAT_ALPHA; @@ -35,20 +24,45 @@ import static mage.client.dialog.PreferencesDialog.KEY_USERS_COLUMNS_ORDER; import static mage.client.dialog.PreferencesDialog.KEY_USERS_COLUMNS_WIDTH; /** - * - * @author BetaSteward_at_googlemail.com, nantuko + * @author BetaSteward_at_googlemail.com, nantuko, JayDi85 */ public class PlayersChatPanel extends javax.swing.JPanel { private final List players = new ArrayList<>(); private final UserTableModel userTableModel; - private static final int[] DEFAULT_COLUMNS_WIDTH = {20, 100, 40, 40, 40, 100, 40, 100, 80, 80}; + private static final TableInfo tableInfo = new TableInfo() + .addColumn(0, 20, Icon.class, "Flag", null) + .addColumn(1, 100, String.class, "Players", + "User name" + + "
(the number behind the header text is the number of users online)") + .addColumn(2, 40, Integer.class, "Constructed Rating", null) + .addColumn(3, 40, Integer.class, "Limited Rating", null) + .addColumn(4, 40, String.class, "Matches", + "Number of matches the user played so far" + + "
Q = number of matches quit" + + "
I = number of matches lost because of idle timeout" + + "
T = number of matches lost because of match timeout") + .addColumn(5, 100, Integer.class, "MQP", + "Percent-Ratio of matches played related to matches quit" + + "
this calculation does not include tournament matches") + .addColumn(6, 40, String.class, "Tourneys", + "Number of tournaments the user played so far" + + "
D = number of tournaments left during draft phase" + + "
C = number of tournaments left during constructing phase" + + "
R = number of tournaments left during rounds") + .addColumn(7, 100, Integer.class, "TQP", + "Percent-Ratio of tournament matches played related to tournament matches quit" + + "
this calculation does not include non tournament matches") + .addColumn(8, 80, String.class, "Games", + "Current activities of the player" + + "
the header itself shows the number of currently active games" + + "
T: = number of games threads " + + "
(that can vary from active games because of sideboarding or crashed games)" + + "
limt: the maximum of games the server is configured to" + + "
(if the number of started games exceed that limit, the games have to wait" + + "
until active games end)
") + .addColumn(9, 80, String.class, "Ping", null); - - /* - * Creates new form ChatPanel - * - */ public PlayersChatPanel() { userTableModel = new UserTableModel(); // needs to be set before initComponents(); @@ -60,8 +74,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { jTablePlayers.setRowSorter(new MageTableRowSorter(userTableModel)); setGUISize(); - TableUtil.setColumnWidthAndOrder(jTablePlayers, DEFAULT_COLUMNS_WIDTH, KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); - userTableModel.initHeaderTooltips(); + TableUtil.setColumnWidthAndOrder(jTablePlayers, tableInfo.getColumnsWidth(), KEY_USERS_COLUMNS_WIDTH, KEY_USERS_COLUMNS_ORDER); jTablePlayers.setDefaultRenderer(Icon.class, new CountryCellRenderer()); @@ -122,7 +135,6 @@ public class PlayersChatPanel extends javax.swing.JPanel { class UserTableModel extends AbstractTableModel { - private final String[] columnNames = new String[]{"Loc", "Players", "Constructed Rating", "Limited Rating", "Matches", "MQP", "Tourneys", "TQP", "Games", "Connection"}; private UsersView[] players = new UsersView[0]; public void loadData(Collection roomUserInfoList) throws MageRemoteException { @@ -131,9 +143,9 @@ public class PlayersChatPanel extends javax.swing.JPanel { JTableHeader th = jTablePlayers.getTableHeader(); TableColumnModel tcm = th.getColumnModel(); - tcm.getColumn(jTablePlayers.convertColumnIndexToView(1)).setHeaderValue("Players (" + this.players.length + ')'); - tcm.getColumn(jTablePlayers.convertColumnIndexToView(8)).setHeaderValue( - "Games " + roomUserInfo.getNumberActiveGames() + tcm.getColumn(jTablePlayers.convertColumnIndexToView(tableInfo.getColumnByName("Players").getIndex())).setHeaderValue("Players (" + this.players.length + ')'); + tcm.getColumn(jTablePlayers.convertColumnIndexToView(tableInfo.getColumnByName("Games").getIndex())).setHeaderValue("Games " + + roomUserInfo.getNumberActiveGames() + (roomUserInfo.getNumberActiveGames() != roomUserInfo.getNumberGameThreads() ? " (T:" + roomUserInfo.getNumberGameThreads() : " (") + " limit: " + roomUserInfo.getNumberMaxGames() + ')'); th.repaint(); @@ -147,117 +159,45 @@ public class PlayersChatPanel extends javax.swing.JPanel { @Override public int getColumnCount() { - return columnNames.length; + return tableInfo.getColumns().size(); } @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { + public Object getValueAt(int rowIndex, int colIndex) { + switch (colIndex) { case 0: - return players[arg0].getFlagName(); + return players[rowIndex].getFlagName(); case 1: - return players[arg0].getUserName(); + return players[rowIndex].getUserName(); case 2: - return players[arg0].getConstructedRating(); + return players[rowIndex].getConstructedRating(); case 3: - return players[arg0].getLimitedRating(); + return players[rowIndex].getLimitedRating(); case 4: - return players[arg0].getMatchHistory(); + return players[rowIndex].getMatchHistory(); case 5: - return players[arg0].getMatchQuitRatio(); + return players[rowIndex].getMatchQuitRatio(); case 6: - return players[arg0].getTourneyHistory(); + return players[rowIndex].getTourneyHistory(); case 7: - return players[arg0].getTourneyQuitRatio(); + return players[rowIndex].getTourneyQuitRatio(); case 8: - return players[arg0].getInfoGames(); + return players[rowIndex].getInfoGames(); case 9: - return players[arg0].getInfoPing(); + return players[rowIndex].getInfoPing(); + default: + return ""; } - return ""; - } - - public void initHeaderTooltips() { - ColumnHeaderToolTips tips = new ColumnHeaderToolTips(); - for (int c = 0; c < jTablePlayers.getColumnCount(); c++) { - String tooltipText = ""; - switch (c) { - case 0: - tooltipText = "The flag the user has assigned to his profile" - + "
You can assign the flag in the connect to server dialog window"; - break; - case 1: - tooltipText = "Name of the user" - + "
(the number behind the header text is the number of currently connected users to the server)"; - break; - case 2: - tooltipText = "Constructed player rating"; - break; - case 3: - tooltipText = "Limited player rating"; - break; - case 4: - tooltipText = "Number of matches the user played so far" - + "
Q = number of matches quit" - + "
I = number of matches lost because of idle timeout" - + "
T = number of matches lost because of match timeout"; - break; - case 5: - tooltipText = "Percent-Ratio of matches played related to matches quit" - + "
this calculation does not include tournament matches"; - break; - case 6: - tooltipText = "Number of tournaments the user played so far" - + "
D = number of tournaments left during draft phase" - + "
C = number of tournaments left during constructing phase" - + "
R = number of tournaments left during rounds"; - break; - case 7: - tooltipText = "Percent-Ratio of tournament matches played related to tournament matches quit" - + "
this calculation does not include non tournament matches"; - break; - case 8: - tooltipText = "Current activities of the player" - + "
the header itself shows the number of currently active games" - + "
T: = number of games threads " - + "
(that can vary from active games because of sideboarding or crashed games)" - + "
limt: the maximum of games the server is configured to" - + "
(if the number of started games exceed that limit, the games have to wait" - + "
until active games end)
"; - break; - case 9: - tooltipText = "Latency of the user's connection to the server"; - break; - } - tips.setToolTip(c, tooltipText); - } - JTableHeader header = jTablePlayers.getTableHeader(); - header.addMouseMotionListener(tips); } @Override public String getColumnName(int columnIndex) { - String colName = ""; - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; + return tableInfo.getColumnByIndex(columnIndex).getHeaderName(); } @Override public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case 0: - return Icon.class; - case 2: - case 3: - case 5: - case 7: - return Integer.class; - default: - return String.class; - } + return tableInfo.getColumnByIndex(columnIndex).getColClass(); } @Override @@ -279,7 +219,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { jSpinner1 = new javax.swing.JSpinner(); jSplitPane1 = new javax.swing.JSplitPane(); jScrollPanePlayers = new javax.swing.JScrollPane(); - jTablePlayers = new javax.swing.JTable(); + jTablePlayers = new MageTable(tableInfo); jTabbedPaneText = new javax.swing.JTabbedPane(); jScrollPaneTalk = new mage.client.chat.ChatPanelSeparated(); jScrollPaneSystem = new javax.swing.JScrollPane(); @@ -332,14 +272,14 @@ public class PlayersChatPanel extends javax.swing.JPanel { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 350, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jSplitPane1) - .addGap(0, 0, 0)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jSplitPane1) + .addGap(0, 0, 0)) ); }// //GEN-END:initComponents @@ -350,6 +290,7 @@ public class PlayersChatPanel extends javax.swing.JPanel { this.players.clear(); } } + // Variables declaration - do not modify//GEN-BEGIN:variables private mage.client.components.ColorPane colorPaneSystem; private javax.swing.JScrollPane jScrollPanePlayers; @@ -358,45 +299,6 @@ public class PlayersChatPanel extends javax.swing.JPanel { private javax.swing.JSpinner jSpinner1; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JTabbedPane jTabbedPaneText; - private javax.swing.JTable jTablePlayers; + private MageTable jTablePlayers; // End of variables declaration//GEN-END:variables - - static class ColumnHeaderToolTips extends MouseMotionAdapter { - - int curCol; - final Map tips = new HashMap<>(); - - public void setToolTip(Integer mCol, String tooltip) { - if (tooltip == null) { - tips.remove(mCol); - } else { - tips.put(mCol, tooltip); - } - } - - @Override - public void mouseMoved(MouseEvent evt) { - JTableHeader header = (JTableHeader) evt.getSource(); - JTable table = header.getTable(); - TableColumnModel colModel = table.getColumnModel(); - int vColIndex = colModel.getColumnIndexAtX(evt.getX()); - TableColumn col = null; - if (vColIndex >= 0) { - col = colModel.getColumn(table.convertColumnIndexToModel(vColIndex)); - } - if (table.convertColumnIndexToModel(vColIndex) != curCol) { - if (col != null) { - MageFrame.getInstance().getBalloonTip().setAttachedComponent(header); - JLabel content = new JLabel(tips.get(table.convertColumnIndexToModel(vColIndex))); - content.setFont(GUISizeHelper.balloonTooltipFont); - MageFrame.getInstance().getBalloonTip().setContents(content); - ToolTipUtils.balloonToToolTip(MageFrame.getInstance().getBalloonTip(), 600, 10000); - } else { - MageFrame.getInstance().getBalloonTip().setTextContents(""); - } - curCol = table.convertColumnIndexToModel(vColIndex); - } - } - } - } diff --git a/Mage.Client/src/main/java/mage/client/table/TableInfo.java b/Mage.Client/src/main/java/mage/client/table/TableInfo.java new file mode 100644 index 0000000000..a3570c4287 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TableInfo.java @@ -0,0 +1,44 @@ +package mage.client.table; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author JayDi85 + */ +public class TableInfo { + + private List columns = new ArrayList<>(); + + + public TableInfo addColumn(Integer index, Integer width, Class colClass, String headerName, String headerHint) { + this.columns.add(new ColumnInfo(index, width, colClass, headerName, headerHint)); + return this; + } + + public int[] getColumnsWidth() { + return this.columns.stream().mapToInt(ColumnInfo::getIndex).toArray(); + } + + public List getColumns() { + return this.columns; + } + + public ColumnInfo getColumnByIndex(int index) { + for (ColumnInfo col : this.columns) { + if (col.getIndex().equals(index)) { + return col; + } + } + return null; + } + + public ColumnInfo getColumnByName(String name) { + for (ColumnInfo col : this.columns) { + if (col.getHeaderName().equals(name)) { + return col; + } + } + return null; + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablePlayerPanel.java b/Mage.Client/src/main/java/mage/client/table/TablePlayerPanel.java index d18df6ef69..99d0dae109 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablePlayerPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablePlayerPanel.java @@ -8,7 +8,7 @@ package mage.client.table; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.importer.DeckImporter; import mage.client.SessionHandler; import mage.client.util.Config; import mage.client.util.Event; @@ -53,7 +53,7 @@ public class TablePlayerPanel extends javax.swing.JPanel { public boolean joinTable(UUID roomId, UUID tableId) throws IOException, ClassNotFoundException { if (this.cbPlayerType.getSelectedItem() != PlayerType.HUMAN) { - return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporterUtil.importDeck(this.newPlayerPanel.getDeckFile()), ""); + return SessionHandler.joinTable(roomId, tableId, this.newPlayerPanel.getPlayerName(), (PlayerType) this.cbPlayerType.getSelectedItem(), this.newPlayerPanel.getLevel(), DeckImporter.importDeckFromFile(this.newPlayerPanel.getDeckFile()), ""); } return true; } diff --git a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java b/Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java similarity index 88% rename from Mage.Client/src/main/java/mage/client/util/ButtonColumn.java rename to Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java index 91e16d9d03..baaa57846e 100644 --- a/Mage.Client/src/main/java/mage/client/util/ButtonColumn.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesButtonColumn.java @@ -1,25 +1,21 @@ +package mage.client.table; -package mage.client.util; +import mage.client.util.GUISizeHelper; -import java.awt.Component; +import javax.swing.*; +import javax.swing.table.TableCellEditor; +import javax.swing.table.TableCellRenderer; +import javax.swing.table.TableColumnModel; +import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; -import javax.swing.AbstractCellEditor; -import javax.swing.Action; -import javax.swing.JButton; -import javax.swing.JTable; -import javax.swing.UIManager; -import javax.swing.table.TableCellEditor; -import javax.swing.table.TableCellRenderer; -import javax.swing.table.TableColumnModel; /** - * * @author BetaSteward_at_googlemail.com */ -public class ButtonColumn extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener { +public class TablesButtonColumn extends AbstractCellEditor implements TableCellRenderer, TableCellEditor, ActionListener, MouseListener { private final JTable table; private final Action action; @@ -28,7 +24,7 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere private String text; private boolean isButtonColumnEditor; - public ButtonColumn(JTable table, Action action, int column) { + public TablesButtonColumn(JTable table, Action action, int column) { super(); this.table = table; this.action = action; @@ -88,7 +84,7 @@ public class ButtonColumn extends AbstractCellEditor implements TableCellRendere if (table.getRowCount() > 0 && table.getRowCount() >= table.getEditingRow() && table.getEditingRow() >= 0) { int row = table.convertRowIndexToModel(table.getEditingRow()); fireEditingStopped(); - ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, String.valueOf(row)); + ActionEvent event = new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, row)); action.actionPerformed(event); } } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPane.java b/Mage.Client/src/main/java/mage/client/table/TablesPane.java index 3b6c6533b5..5e781aac79 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPane.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPane.java @@ -105,7 +105,7 @@ public class TablesPane extends MagePane { @Override public void activated() { - tablesPanel.startTasks(); + tablesPanel.startUpdateTasks(false); } @Override diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form index b764e01770..52b892737d 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.form +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.form @@ -44,7 +44,7 @@ - + @@ -265,6 +265,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -351,7 +387,23 @@
- + + +
+ + + + + + + + + + + + + + @@ -544,6 +596,9 @@ + + + @@ -613,18 +668,29 @@ - + - + - + - + + + + + + + + + + + + @@ -634,7 +700,7 @@ - + diff --git a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java index d28badf2f7..877fb9d9b4 100644 --- a/Mage.Client/src/main/java/mage/client/table/TablesPanel.java +++ b/Mage.Client/src/main/java/mage/client/table/TablesPanel.java @@ -1,42 +1,11 @@ - - - /* - * TablesPanel.java - * - * Created on 15-Dec-2009, 10:54:01 PM - */ package mage.client.table; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.beans.PropertyVetoException; -import java.io.File; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import javax.swing.*; -import javax.swing.table.AbstractTableModel; -import javax.swing.table.DefaultTableCellRenderer; -import javax.swing.table.TableCellRenderer; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.importer.DeckImporter; import mage.client.MageFrame; import mage.client.SessionHandler; import mage.client.chat.ChatPanelBasic; import mage.client.components.MageComponents; import mage.client.dialog.*; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_ORDER; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_COLUMNS_WIDTH; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_FILTER_SETTINGS; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_1; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_2; -import static mage.client.dialog.PreferencesDialog.KEY_TABLES_DIVIDER_LOCATION_3; -import mage.client.util.ButtonColumn; import mage.client.util.GUISizeHelper; import mage.client.util.IgnoreList; import mage.client.util.MageTableRowSorter; @@ -47,25 +16,59 @@ import mage.constants.*; import mage.game.match.MatchOptions; import mage.players.PlayerType; import mage.remote.MageRemoteException; +import mage.util.RandomUtil; import mage.view.MatchView; import mage.view.RoomUsersView; import mage.view.TableView; import mage.view.UserRequestMessage; import org.apache.log4j.Logger; +import org.mage.card.arcane.CardRendererUtils; import org.ocpsoft.prettytime.Duration; import org.ocpsoft.prettytime.PrettyTime; +import org.ocpsoft.prettytime.TimeFormat; import org.ocpsoft.prettytime.units.JustNow; +import javax.swing.*; +import javax.swing.border.EmptyBorder; +import javax.swing.border.LineBorder; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.TableModelEvent; +import javax.swing.event.TableModelListener; +import javax.swing.table.DefaultTableCellRenderer; +import javax.swing.table.TableCellRenderer; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.beans.PropertyVetoException; +import java.io.File; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.List; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +import static mage.client.dialog.PreferencesDialog.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class TablesPanel extends javax.swing.JPanel { private static final Logger LOGGER = Logger.getLogger(TablesPanel.class); - private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 120, 180, 80, 120, 80, 60, 40, 40, 60}; + private static final int[] DEFAULT_COLUMNS_WIDTH = {35, 150, 100, 50, 120, 180, 80, 120, 80, 60, 40, 40, 60}; - private final TableTableModel tableModel; + // refresh timeouts for data downloads from server + public static final int REFRESH_ACTIVE_TABLES_SECS = 5; + public static final int REFRESH_FINISHED_TABLES_SECS = 30; + public static final int REFRESH_PLAYERS_SECS = 10; + public static final double REFRESH_TIMEOUTS_INCREASE_FACTOR = 0.8; // can increase timeouts by 80% (0.8) + + private final TablesTableModel tableModel; private final MatchesTableModel matchesModel; private UUID roomId; private UpdateTablesTask updateTablesTask; @@ -80,13 +83,14 @@ public class TablesPanel extends javax.swing.JPanel { private final MageTableRowSorter activeTablesSorter; private final MageTableRowSorter completedTablesSorter; - private final ButtonColumn actionButton1; - private final ButtonColumn actionButton2; + private final TablesButtonColumn actionButton1; + private final TablesButtonColumn actionButton2; + private final Map tablesLastSelection = new HashMap<>(); final JToggleButton[] filterButtons; // time formater - private PrettyTime timeFormater = new PrettyTime(); + private PrettyTime timeFormater = new PrettyTime(Locale.ENGLISH); // time ago renderer TableCellRenderer timeAgoCellRenderer = new DefaultTableCellRenderer() { @@ -134,12 +138,94 @@ public class TablesPanel extends javax.swing.JPanel { } }; + // skill renderer + TableCellRenderer skillCellRenderer = new DefaultTableCellRenderer() { + + // base panel to render + private JPanel renderPanel = new JPanel(); + private ImageIcon skillIcon = new ImageIcon(this.getClass().getResource("/info/yellow_star_16.png")); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + + // get table text cell settings + DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class); + JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + String skillCode = baseComp.getText(); + + // apply settings to render panel from parent + renderPanel.setOpaque(baseComp.isOpaque()); + renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground())); + renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground())); + renderPanel.setBorder(baseComp.getBorder()); + + // create each skill symbol as child label + renderPanel.removeAll(); + renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS)); + for (char skillSymbol : skillCode.toCharArray()) { + JLabel symbolLabel = new JLabel(); + symbolLabel.setBorder(new EmptyBorder(0, 3, 0, 0)); + symbolLabel.setIcon(skillIcon); + renderPanel.add(symbolLabel); + } + + return renderPanel; + } + }; + + // seats render + TableCellRenderer seatsCellRenderer = new DefaultTableCellRenderer() { + + JLabel greenLabel = new JLabel(); + + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + JLabel defaultLabel = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + defaultLabel.setHorizontalAlignment(JLabel.CENTER); + // colors + String val = (String) value; + int[] seats = parseSeatsInfo(val); + if (seats[0] != seats[1]) { + // green draw + Color defaultBack = defaultLabel.getBackground(); + greenLabel.setText(val); + greenLabel.setHorizontalAlignment(JLabel.CENTER); + greenLabel.setFont(defaultLabel.getFont()); + greenLabel.setForeground(Color.black); + greenLabel.setOpaque(true); + greenLabel.setBackground(new Color(156, 240, 146)); + greenLabel.setBorder(new LineBorder(defaultBack, 1)); + return greenLabel; + } else { + // default draw + return defaultLabel; + } + } + }; + + private int[] parseSeatsInfo(String info) { + String[] valsList = info.split("/"); + int[] res = {0, 0}; + if (valsList.length == 2) { + res[0] = Integer.parseInt(valsList[0]); + res[1] = Integer.parseInt(valsList[1]); + } + return res; + } + + public static int randomizeTimout(int minTimout) { + // randomize timeouts to fix calls waves -- slow server can creates queue and moves all clients to same call window + int increase = (int) (minTimout * REFRESH_TIMEOUTS_INCREASE_FACTOR); + return minTimout + RandomUtil.nextInt(increase); + } + + /** * Creates new form TablesPanel */ public TablesPanel() { - tableModel = new TableTableModel(); + tableModel = new TablesTableModel(); matchesModel = new MatchesTableModel(); gameChooser = new GameChooser(); @@ -147,28 +233,77 @@ public class TablesPanel extends javax.swing.JPanel { // tableModel.setSession(session); // formater - timeFormater.setLocale(Locale.ENGLISH); - JustNow jn = timeFormater.getUnit(JustNow.class); - jn.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs) + // change default just now from 60 to 30 secs + // see workaround for 4.0 versions: https://github.com/ocpsoft/prettytime/issues/152 + TimeFormat timeFormat = timeFormater.removeUnit(JustNow.class); + JustNow newJustNow = new JustNow(); + newJustNow.setMaxQuantity(1000L * 30L); // 30 seconds gap (show "just now" from 0 to 30 secs) + timeFormater.registerUnit(newJustNow, timeFormat); // 1. TABLE CURRENT tableTables.createDefaultColumnsFromModel(); - activeTablesSorter = new MageTableRowSorter(tableModel); + activeTablesSorter = new MageTableRowSorter(tableModel) { + @Override + public void toggleSortOrder(int column) { + // special sort for created and seat column + if (column == TablesTableModel.COLUMN_CREATED || column == TablesTableModel.COLUMN_SEATS) { + List sortKeys = getSortKeys(); + if (!sortKeys.isEmpty() && sortKeys.size() == 2) { + // clear sort on second click + setSortKeys(null); + } else { + // setup sort on first click + List list = new ArrayList<>(); + list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_SEATS, SortOrder.ASCENDING)); + list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_CREATED, SortOrder.DESCENDING)); + setSortKeys(list); + } + } else { + super.toggleSortOrder(column); + } + } + }; tableTables.setRowSorter(activeTablesSorter); // time ago - tableTables.getColumnModel().getColumn(TableTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer); + tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_CREATED).setCellRenderer(timeAgoCellRenderer); + // skill level + tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SKILL).setCellRenderer(skillCellRenderer); + // seats + tableTables.getColumnModel().getColumn(TablesTableModel.COLUMN_SEATS).setCellRenderer(seatsCellRenderer); + /* date sorter (not need, default is good - see getColumnClass) - activeTablesSorter.setComparator(TableTableModel.COLUMN_CREATED, new Comparator() { + activeTablesSorter.setComparator(TablesTableModel.COLUMN_CREATED, new Comparator() { @Override public int compare(Date v1, Date v2) { return v1.compareTo(v2); } });*/ + + // seats sorter (free tables must be first) + activeTablesSorter.setComparator(TablesTableModel.COLUMN_SEATS, new Comparator() { + @Override + public int compare(String v1, String v2) { + int[] seats1 = parseSeatsInfo(v1); + int[] seats2 = parseSeatsInfo(v2); + boolean free1 = seats1[0] != seats1[1]; + boolean free2 = seats2[0] != seats2[1]; + + // free seats go first + if (free1 || free2) { + return Boolean.compare(free2, free1); + } + + // all other seats go without sorts + return 0; + } + }); + // default sort by created date (last games from above) - ArrayList list = new ArrayList(); - list.add(new RowSorter.SortKey(TableTableModel.COLUMN_CREATED, SortOrder.DESCENDING)); + ArrayList list = new ArrayList<>(); + list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_SEATS, SortOrder.ASCENDING)); + list.add(new RowSorter.SortKey(TablesTableModel.COLUMN_CREATED, SortOrder.DESCENDING)); activeTablesSorter.setSortKeys(list); TableUtil.setColumnWidthAndOrder(tableTables, DEFAULT_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_WIDTH, KEY_TABLES_COLUMNS_ORDER); @@ -183,7 +318,7 @@ public class TablesPanel extends javax.swing.JPanel { tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_START).setCellRenderer(datetimeCellRenderer); tableCompleted.getColumnModel().getColumn(MatchesTableModel.COLUMN_END).setCellRenderer(datetimeCellRenderer); // default sort by ended date (last games from above) - ArrayList list2 = new ArrayList(); + ArrayList list2 = new ArrayList<>(); list2.add(new RowSorter.SortKey(MatchesTableModel.COLUMN_END, SortOrder.DESCENDING)); completedTablesSorter.setSortKeys(list2); @@ -194,9 +329,9 @@ public class TablesPanel extends javax.swing.JPanel { // 4. BUTTONS filterButtons = new JToggleButton[]{btnStateWaiting, btnStateActive, btnStateFinished, - btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, - btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, - btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword}; + btnTypeMatch, btnTypeTourneyConstructed, btnTypeTourneyLimited, + btnFormatBlock, btnFormatStandard, btnFormatModern, btnFormatLegacy, btnFormatVintage, btnFormatPremodern, btnFormatCommander, btnFormatTinyLeader, btnFormatLimited, btnFormatOther, + btnSkillBeginner, btnSkillCasual, btnSkillSerious, btnRated, btnUnrated, btnOpen, btnPassword}; JComponent[] components = new JComponent[]{chatPanelMain, jSplitPane1, jScrollPaneTablesActive, jScrollPaneTablesFinished, jPanelTop, jPanelTables}; for (JComponent component : components) { @@ -213,14 +348,18 @@ public class TablesPanel extends javax.swing.JPanel { openTableAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - int modelRow = Integer.valueOf(e.getActionCommand()); - UUID tableId = (UUID) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 3); - UUID gameId = (UUID) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 2); - String action = (String) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN); - String deckType = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_DECK_TYPE); - boolean isTournament = (Boolean) tableModel.getValueAt(modelRow, TableTableModel.ACTION_COLUMN + 1); - String owner = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_OWNER); - String pwdColumn = (String) tableModel.getValueAt(modelRow, TableTableModel.COLUMN_PASSWORD); + String searchID = e.getActionCommand(); + int modelRow = TablesUtil.findTableRowFromSearchId(tableModel, searchID); + if (modelRow == -1) { + return; + } + UUID tableId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 3); + UUID gameId = (UUID) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 2); + String action = (String) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN); + String deckType = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_DECK_TYPE); + boolean isTournament = (Boolean) tableModel.getValueAt(modelRow, TablesTableModel.ACTION_COLUMN + 1); + String owner = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_OWNER); + String pwdColumn = (String) tableModel.getValueAt(modelRow, TablesTableModel.COLUMN_PASSWORD); switch (action) { case "Join": if (owner.equals(SessionHandler.getUserName()) || owner.startsWith(SessionHandler.getUserName() + ',')) { @@ -247,7 +386,7 @@ public class TablesPanel extends javax.swing.JPanel { if (isTournament) { LOGGER.info("Joining tournament " + tableId); if (deckType.startsWith("Limited")) { - if (TableTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) { + if (TablesTableModel.PASSWORD_VALUE_YES.equals(pwdColumn)) { joinTableDialog.showDialog(roomId, tableId, true, deckType.startsWith("Limited")); } else { SessionHandler.joinTournamentTable(roomId, tableId, SessionHandler.getUserName(), PlayerType.HUMAN, 1, null, ""); @@ -290,7 +429,11 @@ public class TablesPanel extends javax.swing.JPanel { closedTableAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - int modelRow = Integer.valueOf(e.getActionCommand()); + String searchID = e.getActionCommand(); + int modelRow = TablesUtil.findTableRowFromSearchId(matchesModel, searchID); + if (modelRow == -1) { + return; + } String action = (String) matchesModel.getValueAt(modelRow, MatchesTableModel.COLUMN_ACTION); switch (action) { case "Replay": @@ -315,20 +458,61 @@ public class TablesPanel extends javax.swing.JPanel { }; // !!!! adds action buttons to the table panel (don't delete this) - actionButton1 = new ButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TableTableModel.ACTION_COLUMN)); - actionButton2 = new ButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION)); - // !!!! + actionButton1 = new TablesButtonColumn(tableTables, openTableAction, tableTables.convertColumnIndexToView(TablesTableModel.ACTION_COLUMN)); + actionButton2 = new TablesButtonColumn(tableCompleted, closedTableAction, tableCompleted.convertColumnIndexToView(MatchesTableModel.COLUMN_ACTION)); + // selection + tablesLastSelection.put(tableTables, ""); + tablesLastSelection.put(tableCompleted, ""); + addTableSelectListener(tableTables); + addTableSelectListener(tableCompleted); + // double click addTableDoubleClickListener(tableTables, openTableAction); addTableDoubleClickListener(tableCompleted, closedTableAction); } + private void addTableSelectListener(JTable table) { + // https://stackoverflow.com/a/26142800/1276632 + + // save last selection + table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + int modelRow = TablesUtil.getSelectedModelRow(table); + if (modelRow != -1) { + // needs only selected + String rowId = TablesUtil.getSearchIdFromTable(table, modelRow); + tablesLastSelection.put(table, rowId); + } + } + }); + + // restore selection + table.getModel().addTableModelListener(new TableModelListener() { + @Override + public void tableChanged(TableModelEvent e) { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + String lastRowID = tablesLastSelection.get(table); + int needModelRow = TablesUtil.findTableRowFromSearchId(table.getModel(), lastRowID); + int needViewRow = TablesUtil.getViewRowFromModel(table, needModelRow); + if (needViewRow != -1) { + table.clearSelection(); + table.addRowSelectionInterval(needViewRow, needViewRow); + } + } + }); + } + }); + } + private void addTableDoubleClickListener(JTable table, Action action) { table.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { - int row = table.rowAtPoint(e.getPoint()); - if (e.getClickCount() == 2 && row != -1) { - action.actionPerformed(new ActionEvent(e.getSource(), e.getID(), "" + row)); + int modelRow = TablesUtil.getSelectedModelRow(table); + if (e.getClickCount() == 2 && modelRow != -1) { + action.actionPerformed(new ActionEvent(table, ActionEvent.ACTION_PERFORMED, TablesUtil.getSearchIdFromTable(table, modelRow))); } } }); @@ -337,6 +521,7 @@ public class TablesPanel extends javax.swing.JPanel { public void cleanUp() { saveGuiSettings(); chatPanelMain.cleanUp(); + stopTasks(); } public void changeGUISize() { @@ -392,9 +577,9 @@ public class TablesPanel extends javax.swing.JPanel { Dimension newDimension = new Dimension((int) jPanelBottom.getPreferredSize().getWidth(), GUISizeHelper.menuFont.getSize() + 28); jPanelBottom.setMinimumSize(newDimension); jPanelBottom.setPreferredSize(newDimension); - jButtonFooterNext.setFont(GUISizeHelper.menuFont); - jLabelFooterLabel.setFont(new Font(GUISizeHelper.menuFont.getName(), Font.BOLD, GUISizeHelper.menuFont.getSize())); - jLabelFooterText.setFont(GUISizeHelper.menuFont); + buttonNextMessage.setFont(GUISizeHelper.menuFont); + labelMessageHeader.setFont(new Font(GUISizeHelper.menuFont.getName(), Font.BOLD, GUISizeHelper.menuFont.getSize())); + labelMessageText.setFont(GUISizeHelper.menuFont); } private void saveDividerLocations() { @@ -456,23 +641,31 @@ public class TablesPanel extends javax.swing.JPanel { } } - public void startTasks() { + public void startUpdateTasks(boolean refreshImmediately) { if (SessionHandler.getSession() != null) { - if (updateTablesTask == null || updateTablesTask.isDone()) { + // active tables and server messages + if (updateTablesTask == null || updateTablesTask.isDone() || refreshImmediately) { + if (updateTablesTask != null) updateTablesTask.cancel(true); updateTablesTask = new UpdateTablesTask(roomId, this); updateTablesTask.execute(); } - if (updatePlayersTask == null || updatePlayersTask.isDone()) { - updatePlayersTask = new UpdatePlayersTask(roomId, this.chatPanelMain); - updatePlayersTask.execute(); - } + + // finished tables if (this.btnStateFinished.isSelected()) { - if (updateMatchesTask == null || updateMatchesTask.isDone()) { + if (updateMatchesTask == null || updateMatchesTask.isDone() || refreshImmediately) { + if (updateMatchesTask != null) updateMatchesTask.cancel(true); updateMatchesTask = new UpdateMatchesTask(roomId, this); updateMatchesTask.execute(); } - } else if (updateMatchesTask != null) { - updateMatchesTask.cancel(true); + } else { + if (updateMatchesTask != null) updateMatchesTask.cancel(true); + } + + // players list + if (updatePlayersTask == null || updatePlayersTask.isDone() || refreshImmediately) { + if (updatePlayersTask != null) updatePlayersTask.cancel(true); + updatePlayersTask = new UpdatePlayersTask(roomId, this.chatPanelMain); + updatePlayersTask.execute(); } } } @@ -511,7 +704,7 @@ public class TablesPanel extends javax.swing.JPanel { } if (chatRoomId != null) { this.chatPanelMain.getUserChatPanel().connect(chatRoomId); - startTasks(); + startUpdateTasks(true); this.setVisible(true); this.repaint(); } else { @@ -519,7 +712,7 @@ public class TablesPanel extends javax.swing.JPanel { } //tableModel.setSession(session); - reloadMessages(); + reloadServerMessages(); MageFrame.getUI().addButton(MageComponents.NEW_GAME_BUTTON, btnNewTable); @@ -528,20 +721,25 @@ public class TablesPanel extends javax.swing.JPanel { } - protected void reloadMessages() { + protected void reloadServerMessages() { // reload server messages java.util.List serverMessages = SessionHandler.getServerMessages(); synchronized (this) { - this.messages = serverMessages; + if (serverMessages != null) { + this.messages = serverMessages; + } else { + this.messages = new ArrayList<>(); + } + this.currentMessage = 0; } - if (serverMessages.isEmpty()) { + if (this.messages.isEmpty()) { this.jPanelBottom.setVisible(false); } else { this.jPanelBottom.setVisible(true); - URLHandler.RemoveMouseAdapter(jLabelFooterText); - URLHandler.handleMessage(serverMessages.get(0), this.jLabelFooterText); - this.jButtonFooterNext.setVisible(serverMessages.size() > 1); + URLHandler.RemoveMouseAdapter(labelMessageText); + URLHandler.handleMessage(this.messages.get(0), this.labelMessageText); + this.buttonNextMessage.setVisible(this.messages.size() > 1); } } @@ -572,86 +770,90 @@ public class TablesPanel extends javax.swing.JPanel { // state java.util.List> stateFilterList = new ArrayList<>(); if (btnStateWaiting.isSelected()) { - stateFilterList.add(RowFilter.regexFilter("Waiting", TableTableModel.COLUMN_STATUS)); + stateFilterList.add(RowFilter.regexFilter("Waiting", TablesTableModel.COLUMN_STATUS)); } if (btnStateActive.isSelected()) { - stateFilterList.add(RowFilter.regexFilter("Dueling|Constructing|Drafting|Sideboard", TableTableModel.COLUMN_STATUS)); + stateFilterList.add(RowFilter.regexFilter("Dueling|Constructing|Drafting|Sideboard", TablesTableModel.COLUMN_STATUS)); } // type java.util.List> typeFilterList = new ArrayList<>(); if (btnTypeMatch.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Two|Commander|Free|Tiny|Momir", TableTableModel.COLUMN_GAME_TYPE)); + typeFilterList.add(RowFilter.regexFilter("Two|Commander|Free|Tiny|Momir", TablesTableModel.COLUMN_GAME_TYPE)); } if (btnTypeTourneyConstructed.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Constructed", TableTableModel.COLUMN_GAME_TYPE)); + typeFilterList.add(RowFilter.regexFilter("Constructed", TablesTableModel.COLUMN_GAME_TYPE)); } if (btnTypeTourneyLimited.isSelected()) { - typeFilterList.add(RowFilter.regexFilter("Booster|Sealed", TableTableModel.COLUMN_GAME_TYPE)); + typeFilterList.add(RowFilter.regexFilter("Booster|Sealed", TablesTableModel.COLUMN_GAME_TYPE)); } // format java.util.List> formatFilterList = new ArrayList<>(); if (btnFormatBlock.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed.*Block", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Constructed.*Block", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatStandard.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Standard", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Constructed - Standard", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatModern.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Constructed - Modern", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatLegacy.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Constructed - Legacy", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatVintage.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Constructed - Vintage", TablesTableModel.COLUMN_DECK_TYPE)); + } + if (btnFormatPremodern.isSelected()) { + formatFilterList.add(RowFilter.regexFilter("^Constructed - Premodern", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatCommander.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Commander|^Duel Commander|^Penny Dreadful Commander|^Freeform Commander|^MTGO 1v1 Commander|^Duel Brawl|^Brawl", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatTinyLeader.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Tiny", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Tiny", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatLimited.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Limited", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Limited", TablesTableModel.COLUMN_DECK_TYPE)); } if (btnFormatOther.isSelected()) { - formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^Canadian Highlander|^Constructed - Old", TableTableModel.COLUMN_DECK_TYPE)); + formatFilterList.add(RowFilter.regexFilter("^Momir Basic|^Constructed - Pauper|^Constructed - Frontier|^Constructed - Extended|^Constructed - Eternal|^Constructed - Historical|^Constructed - Super|^Constructed - Freeform|^Australian Highlander|^Canadian Highlander|^Constructed - Old", TablesTableModel.COLUMN_DECK_TYPE)); } + // skill java.util.List> skillFilterList = new ArrayList<>(); if (btnSkillBeginner.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(SkillLevel.BEGINNER.toString(), TableTableModel.COLUMN_SKILL)); + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.BEGINNER, true), TablesTableModel.COLUMN_SKILL)); } if (btnSkillCasual.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(SkillLevel.CASUAL.toString(), TableTableModel.COLUMN_SKILL)); + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.CASUAL, true), TablesTableModel.COLUMN_SKILL)); } if (btnSkillSerious.isSelected()) { - skillFilterList.add(RowFilter.regexFilter(SkillLevel.SERIOUS.toString(), TableTableModel.COLUMN_SKILL)); + skillFilterList.add(RowFilter.regexFilter(this.tableModel.getSkillLevelAsCode(SkillLevel.SERIOUS, true), TablesTableModel.COLUMN_SKILL)); } - String ratedMark = TableTableModel.RATED_VALUE_YES; + String ratedMark = TablesTableModel.RATED_VALUE_YES; java.util.List> ratingFilterList = new ArrayList<>(); if (btnRated.isSelected()) { // yes word - ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TableTableModel.COLUMN_RATING)); + ratingFilterList.add(RowFilter.regexFilter("^" + ratedMark, TablesTableModel.COLUMN_RATING)); } if (btnUnrated.isSelected()) { // not yes word, see https://stackoverflow.com/a/406408/1276632 - ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TableTableModel.COLUMN_RATING)); + ratingFilterList.add(RowFilter.regexFilter("^((?!" + ratedMark + ").)*$", TablesTableModel.COLUMN_RATING)); } // Password - String passwordMark = TableTableModel.PASSWORD_VALUE_YES; + String passwordMark = TablesTableModel.PASSWORD_VALUE_YES; java.util.List> passwordFilterList = new ArrayList<>(); if (btnPassword.isSelected()) { // yes - passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TableTableModel.COLUMN_PASSWORD)); + passwordFilterList.add(RowFilter.regexFilter("^" + passwordMark, TablesTableModel.COLUMN_PASSWORD)); } if (btnOpen.isSelected()) { // no - passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TableTableModel.COLUMN_PASSWORD)); + passwordFilterList.add(RowFilter.regexFilter("^((?!" + passwordMark + ").)*$", TablesTableModel.COLUMN_PASSWORD)); } // Hide games of ignored players @@ -662,7 +864,7 @@ public class TablesPanel extends javax.swing.JPanel { ignoreListFilterList.add(new RowFilter() { @Override public boolean include(Entry entry) { - final String owner = entry.getStringValue(TableTableModel.COLUMN_OWNER); + final String owner = entry.getStringValue(TablesTableModel.COLUMN_OWNER); return !ignoreListCopy.contains(owner); } }); @@ -671,7 +873,7 @@ public class TablesPanel extends javax.swing.JPanel { if (stateFilterList.isEmpty() || typeFilterList.isEmpty() || formatFilterList.isEmpty() || skillFilterList.isEmpty() || ratingFilterList.isEmpty() || passwordFilterList.isEmpty()) { // no selection - activeTablesSorter.setRowFilter(RowFilter.regexFilter("Nothing", TableTableModel.COLUMN_SKILL)); + activeTablesSorter.setRowFilter(RowFilter.regexFilter("Nothing", TablesTableModel.COLUMN_SKILL)); } else { java.util.List> filterList = new ArrayList<>(); @@ -750,7 +952,7 @@ public class TablesPanel extends javax.swing.JPanel { btnSkillBeginner = new javax.swing.JToggleButton(); btnSkillCasual = new javax.swing.JToggleButton(); btnSkillSerious = new javax.swing.JToggleButton(); - jSeparator5 = new javax.swing.JToolBar.Separator(); + jSeparator6 = new javax.swing.JToolBar.Separator(); btnRated = new javax.swing.JToggleButton(); btnUnrated = new javax.swing.JToggleButton(); filterBar2 = new javax.swing.JToolBar(); @@ -759,6 +961,7 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatModern = new javax.swing.JToggleButton(); btnFormatLegacy = new javax.swing.JToggleButton(); btnFormatVintage = new javax.swing.JToggleButton(); + btnFormatPremodern = new javax.swing.JToggleButton(); jSeparator3 = new javax.swing.JToolBar.Separator(); btnFormatCommander = new javax.swing.JToggleButton(); btnFormatTinyLeader = new javax.swing.JToggleButton(); @@ -773,14 +976,15 @@ public class TablesPanel extends javax.swing.JPanel { jPanelTables = new javax.swing.JPanel(); jSplitPaneTables = new javax.swing.JSplitPane(); jScrollPaneTablesActive = new javax.swing.JScrollPane(); - tableTables = new javax.swing.JTable(); + tableTables = new MageTable(); jScrollPaneTablesFinished = new javax.swing.JScrollPane(); tableCompleted = new javax.swing.JTable(); chatPanelMain = new mage.client.table.PlayersChatPanel(); jPanelBottom = new javax.swing.JPanel(); - jButtonFooterNext = new javax.swing.JButton(); - jLabelFooterLabel = new javax.swing.JLabel(); - jLabelFooterText = new javax.swing.JLabel(); + buttonWhatsNew = new javax.swing.JButton(); + buttonNextMessage = new javax.swing.JButton(); + labelMessageHeader = new javax.swing.JLabel(); + labelMessageText = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); @@ -790,12 +994,20 @@ public class TablesPanel extends javax.swing.JPanel { btnNewTable.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/match_new.png"))); // NOI18N btnNewTable.setToolTipText("Creates a new match table."); btnNewTable.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnNewTable.addActionListener(evt -> btnNewTableActionPerformed(evt)); + btnNewTable.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNewTableActionPerformed(evt); + } + }); btnNewTournament.setIcon(new javax.swing.ImageIcon(getClass().getResource("/buttons/tourney_new.png"))); // NOI18N btnNewTournament.setToolTipText("Creates a new tourney table."); btnNewTournament.setMargin(new java.awt.Insets(2, 2, 2, 2)); - btnNewTournament.addActionListener(evt -> btnNewTournamentActionPerformed(evt)); + btnNewTournament.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnNewTournamentActionPerformed(evt); + } + }); filterBar1.setFloatable(false); filterBar1.setForeground(new java.awt.Color(102, 102, 255)); @@ -811,7 +1023,11 @@ public class TablesPanel extends javax.swing.JPanel { btnStateWaiting.setRequestFocusEnabled(false); btnStateWaiting.setVerifyInputWhenFocusTarget(false); btnStateWaiting.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateWaiting.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnStateWaiting.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnStateWaiting); btnStateActive.setSelected(true); @@ -823,7 +1039,11 @@ public class TablesPanel extends javax.swing.JPanel { btnStateActive.setRequestFocusEnabled(false); btnStateActive.setVerifyInputWhenFocusTarget(false); btnStateActive.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateActive.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnStateActive.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnStateActive); btnStateFinished.setSelected(true); @@ -835,7 +1055,11 @@ public class TablesPanel extends javax.swing.JPanel { btnStateFinished.setRequestFocusEnabled(false); btnStateFinished.setVerifyInputWhenFocusTarget(false); btnStateFinished.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnStateFinished.addActionListener(evt -> btnStateFinishedActionPerformed(evt)); + btnStateFinished.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnStateFinishedActionPerformed(evt); + } + }); filterBar1.add(btnStateFinished); filterBar1.add(jSeparator1); @@ -849,7 +1073,11 @@ public class TablesPanel extends javax.swing.JPanel { btnTypeMatch.setRequestFocusEnabled(false); btnTypeMatch.setVerifyInputWhenFocusTarget(false); btnTypeMatch.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnTypeMatch.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnTypeMatch.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnTypeMatch); btnTypeTourneyConstructed.setSelected(true); @@ -860,7 +1088,11 @@ public class TablesPanel extends javax.swing.JPanel { btnTypeTourneyConstructed.setFocusable(false); btnTypeTourneyConstructed.setRequestFocusEnabled(false); btnTypeTourneyConstructed.setVerifyInputWhenFocusTarget(false); - btnTypeTourneyConstructed.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnTypeTourneyConstructed.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnTypeTourneyConstructed); btnTypeTourneyLimited.setSelected(true); @@ -872,7 +1104,11 @@ public class TablesPanel extends javax.swing.JPanel { btnTypeTourneyLimited.setMaximumSize(new java.awt.Dimension(72, 20)); btnTypeTourneyLimited.setRequestFocusEnabled(false); btnTypeTourneyLimited.setVerifyInputWhenFocusTarget(false); - btnTypeTourneyLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnTypeTourneyLimited.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnTypeTourneyLimited); filterBar1.add(jSeparator4); @@ -886,7 +1122,11 @@ public class TablesPanel extends javax.swing.JPanel { btnSkillBeginner.setRequestFocusEnabled(false); btnSkillBeginner.setVerifyInputWhenFocusTarget(false); btnSkillBeginner.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillBeginner.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnSkillBeginner.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnSkillBeginner); btnSkillCasual.setSelected(true); @@ -899,7 +1139,11 @@ public class TablesPanel extends javax.swing.JPanel { btnSkillCasual.setRequestFocusEnabled(false); btnSkillCasual.setVerifyInputWhenFocusTarget(false); btnSkillCasual.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillCasual.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnSkillCasual.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnSkillCasual); btnSkillSerious.setSelected(true); @@ -912,36 +1156,48 @@ public class TablesPanel extends javax.swing.JPanel { btnSkillSerious.setRequestFocusEnabled(false); btnSkillSerious.setVerifyInputWhenFocusTarget(false); btnSkillSerious.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnSkillSerious.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnSkillSerious.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar1.add(btnSkillSerious); - - filterBar1.add(jSeparator4); + filterBar1.add(jSeparator6); btnRated.setSelected(true); btnRated.setText("Rated"); btnRated.setToolTipText("Shows all rated tables."); + btnRated.setActionCommand("typeMatch"); btnRated.setFocusPainted(false); btnRated.setFocusable(false); btnRated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); btnRated.setRequestFocusEnabled(false); btnRated.setVerifyInputWhenFocusTarget(false); btnRated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnRated.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnRated.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnRatedbtnFilterActionPerformed(evt); + } + }); filterBar1.add(btnRated); btnUnrated.setSelected(true); btnUnrated.setText("Unrated"); btnUnrated.setToolTipText("Shows all unrated tables."); + btnUnrated.setActionCommand("typeMatch"); btnUnrated.setFocusPainted(false); btnUnrated.setFocusable(false); btnUnrated.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); btnUnrated.setRequestFocusEnabled(false); btnUnrated.setVerifyInputWhenFocusTarget(false); btnUnrated.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnUnrated.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnUnrated.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnUnratedbtnFilterActionPerformed(evt); + } + }); filterBar1.add(btnUnrated); - // second filter line filterBar2.setFloatable(false); filterBar2.setFocusable(false); filterBar2.setOpaque(false); @@ -955,7 +1211,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatBlock.setRequestFocusEnabled(false); btnFormatBlock.setVerifyInputWhenFocusTarget(false); btnFormatBlock.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatBlock.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatBlock.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatBlock); btnFormatStandard.setSelected(true); @@ -967,7 +1227,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatStandard.setRequestFocusEnabled(false); btnFormatStandard.setVerifyInputWhenFocusTarget(false); btnFormatStandard.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatStandard.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatStandard.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatStandard); btnFormatModern.setSelected(true); @@ -977,7 +1241,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatModern.setFocusable(false); btnFormatModern.setRequestFocusEnabled(false); btnFormatModern.setVerifyInputWhenFocusTarget(false); - btnFormatModern.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatModern.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatModern); btnFormatLegacy.setSelected(true); @@ -989,7 +1257,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatLegacy.setRequestFocusEnabled(false); btnFormatLegacy.setVerifyInputWhenFocusTarget(false); btnFormatLegacy.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatLegacy.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatLegacy.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatLegacy); btnFormatVintage.setSelected(true); @@ -1001,8 +1273,28 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatVintage.setRequestFocusEnabled(false); btnFormatVintage.setVerifyInputWhenFocusTarget(false); btnFormatVintage.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatVintage.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatVintage.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFormatVintageActionPerformed(evt); + } + }); filterBar2.add(btnFormatVintage); + + btnFormatPremodern.setSelected(true); + btnFormatPremodern.setText("Premodern"); + btnFormatPremodern.setToolTipText("Premodern format."); + btnFormatPremodern.setFocusPainted(false); + btnFormatPremodern.setFocusable(false); + btnFormatPremodern.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + btnFormatPremodern.setRequestFocusEnabled(false); + btnFormatPremodern.setVerifyInputWhenFocusTarget(false); + btnFormatPremodern.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + btnFormatPremodern.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFormatPremodernActionPerformed(evt); + } + }); + filterBar2.add(btnFormatPremodern); filterBar2.add(jSeparator3); btnFormatCommander.setSelected(true); @@ -1014,7 +1306,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatCommander.setRequestFocusEnabled(false); btnFormatCommander.setVerifyInputWhenFocusTarget(false); btnFormatCommander.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatCommander.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatCommander.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatCommander); btnFormatTinyLeader.setSelected(true); @@ -1024,7 +1320,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatTinyLeader.setFocusable(false); btnFormatTinyLeader.setRequestFocusEnabled(false); btnFormatTinyLeader.setVerifyInputWhenFocusTarget(false); - btnFormatTinyLeader.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatTinyLeader.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatTinyLeader); filterBar2.add(jSeparator2); @@ -1037,7 +1337,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatLimited.setRequestFocusEnabled(false); btnFormatLimited.setVerifyInputWhenFocusTarget(false); btnFormatLimited.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnFormatLimited.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatLimited.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatLimited); btnFormatOther.setSelected(true); @@ -1047,7 +1351,11 @@ public class TablesPanel extends javax.swing.JPanel { btnFormatOther.setFocusable(false); btnFormatOther.setRequestFocusEnabled(false); btnFormatOther.setVerifyInputWhenFocusTarget(false); - btnFormatOther.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnFormatOther.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnFormatOther); filterBar2.add(jSeparator5); @@ -1060,7 +1368,11 @@ public class TablesPanel extends javax.swing.JPanel { btnOpen.setRequestFocusEnabled(false); btnOpen.setVerifyInputWhenFocusTarget(false); btnOpen.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnOpen.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnOpen.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnOpen); btnPassword.setSelected(true); @@ -1072,47 +1384,55 @@ public class TablesPanel extends javax.swing.JPanel { btnPassword.setRequestFocusEnabled(false); btnPassword.setVerifyInputWhenFocusTarget(false); btnPassword.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnPassword.addActionListener(evt -> btnFilterActionPerformed(evt)); + btnPassword.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnFilterActionPerformed(evt); + } + }); filterBar2.add(btnPassword); btnQuickStart.setText("Quick Start"); btnQuickStart.setFocusable(false); btnQuickStart.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); btnQuickStart.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - btnQuickStart.addActionListener(evt -> btnQuickStartActionPerformed(evt)); + btnQuickStart.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + btnQuickStartActionPerformed(evt); + } + }); javax.swing.GroupLayout jPanelTopLayout = new javax.swing.GroupLayout(jPanelTop); jPanelTop.setLayout(jPanelTopLayout); jPanelTopLayout.setHorizontalGroup( - jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addContainerGap() - .addComponent(btnNewTable) - .addGap(6, 6, 6) - .addComponent(btnNewTournament) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 491, Short.MAX_VALUE) - .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(btnQuickStart) - .addContainerGap(835, Short.MAX_VALUE)) + jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addContainerGap() + .addComponent(btnNewTable) + .addGap(6, 6, 6) + .addComponent(btnNewTournament) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(btnQuickStart) + .addContainerGap(792, Short.MAX_VALUE)) ); jPanelTopLayout.setVerticalGroup( - jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(btnNewTable) - .addComponent(btnNewTournament)) - .addGroup(jPanelTopLayout.createSequentialGroup() - .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnQuickStart)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) - .addContainerGap()) + jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addContainerGap() + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(btnNewTable) + .addComponent(btnNewTournament)) + .addGroup(jPanelTopLayout.createSequentialGroup() + .addGroup(jPanelTopLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(filterBar1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnQuickStart)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(filterBar2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addContainerGap()) ); gridBagConstraints = new java.awt.GridBagConstraints(); @@ -1149,12 +1469,12 @@ public class TablesPanel extends javax.swing.JPanel { javax.swing.GroupLayout jPanelTablesLayout = new javax.swing.GroupLayout(jPanelTables); jPanelTables.setLayout(jPanelTablesLayout); jPanelTablesLayout.setHorizontalGroup( - jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPaneTables, javax.swing.GroupLayout.PREFERRED_SIZE, 23, Short.MAX_VALUE) + jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPaneTables, javax.swing.GroupLayout.DEFAULT_SIZE, 23, Short.MAX_VALUE) ); jPanelTablesLayout.setVerticalGroup( - jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jSplitPaneTables, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE) + jPanelTablesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jSplitPaneTables, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE) ); jSplitPane1.setLeftComponent(jPanelTables); @@ -1172,22 +1492,37 @@ public class TablesPanel extends javax.swing.JPanel { jPanelBottom.setPreferredSize(new java.awt.Dimension(516, 37)); jPanelBottom.setLayout(new java.awt.FlowLayout(java.awt.FlowLayout.LEFT)); - jButtonFooterNext.setText("Next"); - jButtonFooterNext.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jButtonFooterNext.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); - jButtonFooterNext.setOpaque(false); - jButtonFooterNext.addActionListener(evt -> jButtonFooterNextActionPerformed(evt)); - jPanelBottom.add(jButtonFooterNext); + buttonWhatsNew.setText("Show that's new"); + buttonWhatsNew.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + buttonWhatsNew.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonWhatsNew.setOpaque(false); + buttonWhatsNew.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonWhatsNewActionPerformed(evt); + } + }); + jPanelBottom.add(buttonWhatsNew); - jLabelFooterLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N - jLabelFooterLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jLabelFooterLabel.setText("Message of the Day:"); - jLabelFooterLabel.setAlignmentY(0.3F); - jPanelBottom.add(jLabelFooterLabel); + buttonNextMessage.setText("Next message"); + buttonNextMessage.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + buttonNextMessage.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + buttonNextMessage.setOpaque(false); + buttonNextMessage.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + buttonNextMessageActionPerformed(evt); + } + }); + jPanelBottom.add(buttonNextMessage); - jLabelFooterText.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); - jLabelFooterText.setText("You are playing Mage version 0.7.5. Welcome! -- Mage dev team --"); - jPanelBottom.add(jLabelFooterText); + labelMessageHeader.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N + labelMessageHeader.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + labelMessageHeader.setText("Message of the Day:"); + labelMessageHeader.setAlignmentY(0.3F); + jPanelBottom.add(labelMessageHeader); + + labelMessageText.setHorizontalAlignment(javax.swing.SwingConstants.LEFT); + labelMessageText.setText("You are playing Mage version 0.7.5. Welcome! -- Mage dev team --"); + jPanelBottom.add(labelMessageText); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridy = 2; @@ -1196,11 +1531,11 @@ public class TablesPanel extends javax.swing.JPanel { add(jPanelBottom, gridBagConstraints); }// //GEN-END:initComponents - private void btnNewTournamentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTournamentActionPerformed + private void btnNewTournamentActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTournamentActionPerformed newTournamentDialog.showDialog(roomId); -}//GEN-LAST:event_btnNewTournamentActionPerformed + }//GEN-LAST:event_btnNewTournamentActionPerformed - private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed + private void btnQuickStartActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnQuickStartActionPerformed TableView table; try { File f = new File("test.dck"); @@ -1221,23 +1556,24 @@ public class TablesPanel extends javax.swing.JPanel { options.setSkillLevel(SkillLevel.CASUAL); options.setRollbackTurnsAllowed(true); options.setQuitRatio(100); + options.setMinimumRating(0); String serverAddress = SessionHandler.getSession().getServerHostname().orElseGet(() -> ""); options.setBannedUsers(IgnoreList.ignoreList(serverAddress)); table = SessionHandler.createTable(roomId, options); - SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporterUtil.importDeck("test.dck"), ""); - SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporterUtil.importDeck("test.dck"), ""); + SessionHandler.joinTable(roomId, table.getTableId(), "Human", PlayerType.HUMAN, 1, DeckImporter.importDeckFromFile("test.dck"), ""); + SessionHandler.joinTable(roomId, table.getTableId(), "Computer", PlayerType.COMPUTER_MAD, 5, DeckImporter.importDeckFromFile("test.dck"), ""); SessionHandler.startMatch(roomId, table.getTableId()); } catch (HeadlessException ex) { handleError(ex); } -}//GEN-LAST:event_btnQuickStartActionPerformed + }//GEN-LAST:event_btnQuickStartActionPerformed private void btnNewTableActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnNewTableActionPerformed newTableDialog.showDialog(roomId); }//GEN-LAST:event_btnNewTableActionPerformed - private void jButtonFooterNextActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonFooterNextActionPerformed + private void buttonNextMessageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonNextMessageActionPerformed synchronized (this) { if (messages != null && !messages.isEmpty()) { currentMessage++; @@ -1245,11 +1581,11 @@ public class TablesPanel extends javax.swing.JPanel { currentMessage = 0; } - URLHandler.RemoveMouseAdapter(jLabelFooterText); - URLHandler.handleMessage(messages.get(currentMessage), this.jLabelFooterText); + URLHandler.RemoveMouseAdapter(labelMessageText); + URLHandler.handleMessage(messages.get(currentMessage), this.labelMessageText); } } - }//GEN-LAST:event_jButtonFooterNextActionPerformed + }//GEN-LAST:event_buttonNextMessageActionPerformed private void btnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFilterActionPerformed setTableFilter(); @@ -1261,9 +1597,29 @@ public class TablesPanel extends javax.swing.JPanel { } else { this.jSplitPaneTables.setDividerLocation(this.jPanelTables.getHeight()); } - this.startTasks(); + this.startUpdateTasks(true); }//GEN-LAST:event_btnStateFinishedActionPerformed + private void btnRatedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnRatedbtnFilterActionPerformed + setTableFilter(); + }//GEN-LAST:event_btnRatedbtnFilterActionPerformed + + private void btnUnratedbtnFilterActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnUnratedbtnFilterActionPerformed + setTableFilter(); + }//GEN-LAST:event_btnUnratedbtnFilterActionPerformed + + private void btnFormatPremodernActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatPremodernActionPerformed + setTableFilter(); + }//GEN-LAST:event_btnFormatPremodernActionPerformed + + private void btnFormatVintageActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnFormatVintageActionPerformed + setTableFilter(); + }//GEN-LAST:event_btnFormatVintageActionPerformed + + private void buttonWhatsNewActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buttonWhatsNewActionPerformed + MageFrame.getInstance().showWhatsNewDialog(true); + }//GEN-LAST:event_buttonWhatsNewActionPerformed + private void handleError(Exception ex) { LOGGER.fatal("Error loading deck: ", ex); JOptionPane.showMessageDialog(MageFrame.getDesktop(), "Error loading deck.", "Error", JOptionPane.ERROR_MESSAGE); @@ -1276,6 +1632,7 @@ public class TablesPanel extends javax.swing.JPanel { private javax.swing.JToggleButton btnFormatLimited; private javax.swing.JToggleButton btnFormatModern; private javax.swing.JToggleButton btnFormatOther; + private javax.swing.JToggleButton btnFormatPremodern; private javax.swing.JToggleButton btnFormatStandard; private javax.swing.JToggleButton btnFormatTinyLeader; private javax.swing.JToggleButton btnFormatVintage; @@ -1284,23 +1641,22 @@ public class TablesPanel extends javax.swing.JPanel { private javax.swing.JToggleButton btnOpen; private javax.swing.JToggleButton btnPassword; private javax.swing.JButton btnQuickStart; + private javax.swing.JToggleButton btnRated; private javax.swing.JToggleButton btnSkillBeginner; private javax.swing.JToggleButton btnSkillCasual; private javax.swing.JToggleButton btnSkillSerious; - private javax.swing.JToggleButton btnRated; - private javax.swing.JToggleButton btnUnrated; private javax.swing.JToggleButton btnStateActive; private javax.swing.JToggleButton btnStateFinished; private javax.swing.JToggleButton btnStateWaiting; private javax.swing.JToggleButton btnTypeMatch; private javax.swing.JToggleButton btnTypeTourneyConstructed; private javax.swing.JToggleButton btnTypeTourneyLimited; + private javax.swing.JToggleButton btnUnrated; + private javax.swing.JButton buttonNextMessage; + private javax.swing.JButton buttonWhatsNew; private mage.client.table.PlayersChatPanel chatPanelMain; private javax.swing.JToolBar filterBar1; private javax.swing.JToolBar filterBar2; - private javax.swing.JButton jButtonFooterNext; - private javax.swing.JLabel jLabelFooterLabel; - private javax.swing.JLabel jLabelFooterText; private javax.swing.JPanel jPanelBottom; private javax.swing.JPanel jPanelTables; private javax.swing.JPanel jPanelTop; @@ -1311,163 +1667,22 @@ public class TablesPanel extends javax.swing.JPanel { private javax.swing.JToolBar.Separator jSeparator3; private javax.swing.JToolBar.Separator jSeparator4; private javax.swing.JToolBar.Separator jSeparator5; + private javax.swing.JToolBar.Separator jSeparator6; private javax.swing.JSplitPane jSplitPane1; private javax.swing.JSplitPane jSplitPaneTables; + private javax.swing.JLabel labelMessageHeader; + private javax.swing.JLabel labelMessageText; private javax.swing.JTable tableCompleted; private javax.swing.JTable tableTables; // End of variables declaration//GEN-END:variables } -class TableTableModel extends AbstractTableModel { - - final ImageIcon tourneyIcon = new javax.swing.ImageIcon(getClass().getResource("/tables/tourney_icon.png")); - final ImageIcon matchIcon = new javax.swing.ImageIcon(getClass().getResource("/tables/match_icon.png")); - - public static final int COLUMN_ICON = 0; - public static final int COLUMN_DECK_TYPE = 1; // column the deck type is located (starting with 0) Start string is used to check for Limited - public static final int COLUMN_OWNER = 2; - public static final int COLUMN_GAME_TYPE = 3; - public static final int COLUMN_INFO = 4; - public static final int COLUMN_STATUS = 5; - public static final int COLUMN_PASSWORD = 6; - public static final int COLUMN_CREATED = 7; - public static final int COLUMN_SKILL = 8; - public static final int COLUMN_RATING = 9; - public static final int COLUMN_QUIT_RATIO = 10; - public static final int ACTION_COLUMN = 11; // column the action is located (starting with 0) - - public static final String RATED_VALUE_YES = "YES"; - public static final String RATED_VALUE_NO = ""; - - public static final String PASSWORD_VALUE_YES = "YES"; - - private final String[] columnNames = new String[]{"M/T", "Deck Type", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rating", "Quit %", "Action"}; - - private TableView[] tables = new TableView[0]; - - TableTableModel() { - } - - public void loadData(Collection tables) throws MageRemoteException { - this.tables = tables.toArray(new TableView[0]); - this.fireTableDataChanged(); - } - - @Override - public int getRowCount() { - return tables.length; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { - case 0: - return tables[arg0].isTournament() ? tourneyIcon : matchIcon; - case 1: - return tables[arg0].getDeckType(); - case 2: - return tables[arg0].getControllerName(); - case 3: - return tables[arg0].getGameType(); - case 4: - return tables[arg0].getAdditionalInfo(); - case 5: - return tables[arg0].getTableStateText(); - case 6: - return tables[arg0].isPassworded() ? PASSWORD_VALUE_YES : ""; - case 7: - return tables[arg0].getCreateTime(); // use cell render, not format here - case 8: - return tables[arg0].getSkillLevel(); - case 9: - return tables[arg0].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO; - case 10: - return tables[arg0].getQuitRatio(); - case 11: - switch (tables[arg0].getTableState()) { - - case WAITING: - String owner = tables[arg0].getControllerName(); - if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { - return ""; - } - return "Join"; - case CONSTRUCTING: - case DRAFTING: - if (tables[arg0].isTournament()) { - return "Show"; - } - case DUELING: - if (tables[arg0].isTournament()) { - return "Show"; - } else { - owner = tables[arg0].getControllerName(); - if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { - return ""; - } - if (tables[arg0].getSpectatorsAllowed()) { - return "Watch"; - } - return ""; - } - default: - return ""; - } - case 12: - return tables[arg0].isTournament(); - case 13: - if (!tables[arg0].getGames().isEmpty()) { - return tables[arg0].getGames().get(0); - } - return null; - case 14: - return tables[arg0].getTableId(); - } - return ""; - } - - @Override - public String getColumnName(int columnIndex) { - String colName = ""; - - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case COLUMN_ICON: - return Icon.class; - case COLUMN_SKILL: - return SkillLevel.class; - case COLUMN_CREATED: - return Date.class; - default: - return String.class; - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == ACTION_COLUMN; - } - -} - class UpdateTablesTask extends SwingWorker> { private final UUID roomId; private final TablesPanel panel; + private boolean isFirstRun = true; private static final Logger logger = Logger.getLogger(UpdateTablesTask.class); @@ -1486,7 +1701,7 @@ class UpdateTablesTask extends SwingWorker> { if (tables != null) { this.publish(tables); } - TimeUnit.SECONDS.sleep(3); + TimeUnit.SECONDS.sleep(TablesPanel.randomizeTimout(TablesPanel.REFRESH_ACTIVE_TABLES_SECS)); } return null; } @@ -1494,10 +1709,13 @@ class UpdateTablesTask extends SwingWorker> { @Override protected void process(java.util.List> view) { panel.updateTables(view.get(0)); + + // update server messages count++; - if (count > 60) { + if (isFirstRun || count > 60) { count = 0; - panel.reloadMessages(); + isFirstRun = false; + panel.reloadServerMessages(); } } @@ -1530,7 +1748,7 @@ class UpdatePlayersTask extends SwingWorker> { protected Void doInBackground() throws Exception { while (!isCancelled()) { this.publish(SessionHandler.getRoomUsers(roomId)); - TimeUnit.SECONDS.sleep(3); + TimeUnit.SECONDS.sleep(TablesPanel.randomizeTimout(TablesPanel.REFRESH_PLAYERS_SECS)); } return null; } @@ -1552,119 +1770,6 @@ class UpdatePlayersTask extends SwingWorker> { } -class MatchesTableModel extends AbstractTableModel { - - private final String[] columnNames = new String[]{"Deck Type", "Players", "Game Type", "Rating", "Result", "Duration", "Start Time", "End Time", "Action"}; - public static final int COLUMN_DURATION = 5; - public static final int COLUMN_START = 6; - public static final int COLUMN_END = 7; - public static final int COLUMN_ACTION = 8; // column the action is located (starting with 0) - - private MatchView[] matches = new MatchView[0]; - - public void loadData(Collection matches) throws MageRemoteException { - this.matches = matches.toArray(new MatchView[0]); - this.fireTableDataChanged(); - } - - MatchesTableModel() { - } - - @Override - public int getRowCount() { - return matches.length; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { - case 0: - return matches[arg0].getDeckType(); - case 1: - return matches[arg0].getPlayers(); - case 2: - return matches[arg0].getGameType(); - case 3: - return matches[arg0].isRated() ? TableTableModel.RATED_VALUE_YES : TableTableModel.RATED_VALUE_NO; - case 4: - return matches[arg0].getResult(); - case 5: - if (matches[arg0].getEndTime() != null) { - return matches[arg0].getEndTime().getTime() - matches[arg0].getStartTime().getTime() + new Date().getTime(); - } else { - return 0L; - } - case 6: - return matches[arg0].getStartTime(); - case 7: - return matches[arg0].getEndTime(); - case 8: - if (matches[arg0].isTournament()) { - return "Show"; - } else if (matches[arg0].isReplayAvailable()) { - return "Replay"; - } else { - return "None"; - } - case 9: - return matches[arg0].getGames(); - } - return ""; - } - - public java.util.List getListofGames(int row) { - return matches[row].getGames(); - } - - public boolean isTournament(int row) { - return matches[row].isTournament(); - } - - public UUID getMatchId(int row) { - return matches[row].getMatchId(); - } - - public UUID getTableId(int row) { - return matches[row].getTableId(); - } - - @Override - public String getColumnName(int columnIndex) { - String colName = ""; - - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; - } - - @Override - public Class getColumnClass(int columnIndex) { - switch (columnIndex) { - case COLUMN_DURATION: - return Long.class; - case COLUMN_START: - return Date.class; - case COLUMN_END: - return Date.class; - default: - return String.class; - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == COLUMN_ACTION; - } - -} - class UpdateMatchesTask extends SwingWorker> { private final UUID roomId; @@ -1680,11 +1785,8 @@ class UpdateMatchesTask extends SwingWorker> { @Override protected Void doInBackground() throws Exception { while (!isCancelled()) { - Collection matches = SessionHandler.getFinishedMatches(roomId); - if (!matches.isEmpty()) { - this.publish(matches); - } - TimeUnit.SECONDS.sleep(10); + this.publish(SessionHandler.getFinishedMatches(roomId)); + TimeUnit.SECONDS.sleep(TablesPanel.randomizeTimout(TablesPanel.REFRESH_FINISHED_TABLES_SECS)); } return null; } @@ -1740,5 +1842,4 @@ class GameChooser extends JPopupMenu { } } - } diff --git a/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java new file mode 100644 index 0000000000..1348887d81 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TablesTableModel.java @@ -0,0 +1,223 @@ +package mage.client.table; + +import mage.client.SessionHandler; +import mage.constants.SkillLevel; +import mage.remote.MageRemoteException; +import mage.view.TableView; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.util.Collection; +import java.util.Date; + +public class TablesTableModel extends AbstractTableModel { + + // icons with tostring for tables hints + final ImageIcon tourneyIcon = new ImageIcon(getClass().getResource("/tables/tourney_icon.png")) { + @Override + public String toString() { + return "Tourney"; + } + }; + final ImageIcon matchIcon = new ImageIcon(getClass().getResource("/tables/match_icon.png")) { + @Override + public String toString() { + return "Match"; + } + }; + + public static final int COLUMN_ICON = 0; + public static final int COLUMN_DECK_TYPE = 1; // column the deck type is located (starting with 0) Start string is used to check for Limited + public static final int COLUMN_NAME = 2; + public static final int COLUMN_SEATS = 3; + public static final int COLUMN_OWNER = 4; + public static final int COLUMN_GAME_TYPE = 5; + public static final int COLUMN_INFO = 6; + public static final int COLUMN_STATUS = 7; + public static final int COLUMN_PASSWORD = 8; + public static final int COLUMN_CREATED = 9; + public static final int COLUMN_SKILL = 10; + public static final int COLUMN_RATING = 11; + public static final int COLUMN_QUIT_RATIO = 12; + public static final int COLUMN_MINIMUM_RATING = 13; + public static final int ACTION_COLUMN = 14; // column the action is located (starting with 0) + + public static final String RATED_VALUE_YES = "YES"; + public static final String RATED_VALUE_NO = ""; + + public static final String PASSWORD_VALUE_YES = "YES"; + + private final String[] columnNames = new String[]{"M/T", "Deck Type", "Name", "Seats", "Owner / Players", "Game Type", "Info", "Status", "Password", "Created / Started", "Skill Level", "Rated", "Quit %", "Min Rating", "Action"}; + + private TableView[] tables = new TableView[0]; + + TablesTableModel() { + } + + public void loadData(Collection tables) throws MageRemoteException { + this.tables = tables.toArray(new TableView[0]); + this.fireTableDataChanged(); + } + + public String getTableAndGameInfo(int row) { + return this.tables[row].getTableId().toString() + ";" + (!tables[row].getGames().isEmpty() ? tables[row].getGames().get(0).toString() : "null"); + } + + public String findTableAndGameInfoByRow(int row) { + if (row >= 0 && row < this.tables.length) { + return getTableAndGameInfo(row); + } else { + return null; + } + } + + public int findRowByTableAndGameInfo(String tableAndGame) { + for (int i = 0; i < this.tables.length; i++) { + String rowID = this.tables[i].getTableId().toString() + ";" + (!this.tables[i].getGames().isEmpty() ? this.tables[i].getGames().get(0).toString() : "null"); + if (tableAndGame.equals(rowID)) { + return i; + } + } + return -1; + } + + public String getSkillLevelAsCode(SkillLevel skill, boolean asRegExp) { + String res; + switch (skill) { + case BEGINNER: + res = "*"; + break; + case CASUAL: + res = "**"; + break; + case SERIOUS: + res = "***"; + break; + default: + res = ""; + break; + } + + // regexp format for search table rows + if (asRegExp) { + res = String.format("^%s$", res.replace("*", "\\*")); + } + + return res; + } + + @Override + public int getRowCount() { + return tables.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + switch (columnIndex) { + case 0: + return tables[rowIndex].isTournament() ? tourneyIcon : matchIcon; + case 1: + return tables[rowIndex].getDeckType(); + case 2: + return tables[rowIndex].getTableName(); + case 3: + return tables[rowIndex].getSeatsInfo(); + case 4: + return tables[rowIndex].getControllerName(); + case 5: + return tables[rowIndex].getGameType(); + case 6: + return tables[rowIndex].getAdditionalInfo(); + case 7: + return tables[rowIndex].getTableStateText(); + case 8: + return tables[rowIndex].isPassworded() ? PASSWORD_VALUE_YES : ""; + case 9: + return tables[rowIndex].getCreateTime(); // use cell render, not format here + case 10: + return this.getSkillLevelAsCode(tables[rowIndex].getSkillLevel(), false); + case 11: + return tables[rowIndex].isRated() ? RATED_VALUE_YES : RATED_VALUE_NO; + case 12: + return tables[rowIndex].getQuitRatio(); + case 13: + return tables[rowIndex].getMinimumRating(); + case 14: + switch (tables[rowIndex].getTableState()) { + + case WAITING: + String owner = tables[rowIndex].getControllerName(); + if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { + return ""; + } + return "Join"; + case CONSTRUCTING: + case DRAFTING: + if (tables[rowIndex].isTournament()) { + return "Show"; + } + case DUELING: + if (tables[rowIndex].isTournament()) { + return "Show"; + } else { + owner = tables[rowIndex].getControllerName(); + if (SessionHandler.getSession() != null && owner.equals(SessionHandler.getUserName())) { + return ""; + } + if (tables[rowIndex].getSpectatorsAllowed()) { + return "Watch"; + } + return ""; + } + default: + return ""; + } + case 15: + return tables[rowIndex].isTournament(); + case 16: + if (!tables[rowIndex].getGames().isEmpty()) { + return tables[rowIndex].getGames().get(0); + } + return null; + case 17: + return tables[rowIndex].getTableId(); + } + return ""; + } + + @Override + public String getColumnName(int columnIndex) { + String colName = ""; + + if (columnIndex <= getColumnCount()) { + colName = columnNames[columnIndex]; + } + + return colName; + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case COLUMN_ICON: + return Icon.class; + case COLUMN_SKILL: + return SkillLevel.class; + case COLUMN_CREATED: + return Date.class; + default: + return String.class; + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == ACTION_COLUMN; + } + +} diff --git a/Mage.Client/src/main/java/mage/client/table/TablesUtil.java b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java new file mode 100644 index 0000000000..6fd2b8445e --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TablesUtil.java @@ -0,0 +1,63 @@ +package mage.client.table; + +import org.apache.log4j.Logger; + +import javax.swing.*; + +/** + * @author JayDi85 + */ +public class TablesUtil { + + private static final Logger logger = Logger.getLogger(TablesUtil.class); + + public static String getSearchIdFromTable(JTable table, int row) { + // tableUUID;gameUUID + String searchId = null; + if (table.getModel() instanceof TablesTableModel) { + searchId = ((TablesTableModel) table.getModel()).findTableAndGameInfoByRow(row); + } else if (table.getModel() instanceof MatchesTableModel) { + searchId = ((MatchesTableModel) table.getModel()).findTableAndGameInfoByRow(row); + } else if (table.getModel() instanceof TournamentMatchesTableModel) { + searchId = ((TournamentMatchesTableModel) table.getModel()).findTableAndGameInfoByRow(row); + } else { + logger.error("Not supported tables model " + table.getModel().getClass().toString()); + } + return searchId; + } + + public static int findTableRowFromSearchId(Object tableModel, String searchId) { + // tableUUID;gameUUID + int row = -1; + if (searchId != null) { + if (tableModel instanceof TablesTableModel) { + row = ((TablesTableModel) tableModel).findRowByTableAndGameInfo(searchId); + } else if (tableModel instanceof MatchesTableModel) { + row = ((MatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId); + } else if (tableModel instanceof TournamentMatchesTableModel) { + row = ((TournamentMatchesTableModel) tableModel).findRowByTableAndGameInfo(searchId); + } else { + logger.error("Not supported tables model " + tableModel.getClass().toString()); + } + } + return row; + } + + public static int getSelectedModelRow(JTable table) { + return getModelRowFromView(table, table.getSelectedRow()); + } + + public static int getModelRowFromView(JTable table, int viewRow) { + if (viewRow != -1 && viewRow < table.getModel().getRowCount()) { + return table.convertRowIndexToModel(viewRow); + } + return -1; + } + + public static int getViewRowFromModel(JTable table, int modelRow) { + if (modelRow != -1 && modelRow < table.getModel().getRowCount()) { + return table.convertRowIndexToView(modelRow); + } + return -1; + } +} diff --git a/Mage.Client/src/main/java/mage/client/table/TournamentMatchesTableModel.java b/Mage.Client/src/main/java/mage/client/table/TournamentMatchesTableModel.java new file mode 100644 index 0000000000..288a5c70f7 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/table/TournamentMatchesTableModel.java @@ -0,0 +1,116 @@ +package mage.client.table; + +import mage.view.RoundView; +import mage.view.TournamentGameView; +import mage.view.TournamentView; + +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.List; + +/** + * @author JayDi85 + */ +public class TournamentMatchesTableModel extends AbstractTableModel { + public static final int ACTION_COLUMN = 4; // column the action is located + + private final String[] columnNames = new String[]{"Round Number", "Players", "State", "Result", "Action"}; + private TournamentGameView[] games = new TournamentGameView[0]; + private boolean watchingAllowed; + + public void loadData(TournamentView tournament) { + List views = new ArrayList<>(); + watchingAllowed = tournament.isWatchingAllowed(); + for (RoundView round : tournament.getRounds()) { + for (TournamentGameView game : round.getGames()) { + views.add(game); + } + } + games = views.toArray(new TournamentGameView[0]); + this.fireTableDataChanged(); + } + + public String getTableAndGameInfo(int row) { + return this.games[row].getTableId().toString() + ";" + games[row].toString(); + } + + public String findTableAndGameInfoByRow(int row) { + if (row >= 0 && row < this.games.length) { + return getTableAndGameInfo(row); + } else { + return null; + } + } + + public int findRowByTableAndGameInfo(String tableAndGame) { + for (int i = 0; i < this.games.length; i++) { + String rowID = this.games[i].getTableId().toString() + ";" + this.games[i].toString(); + if (tableAndGame.equals(rowID)) { + return i; + } + } + return -1; + } + + @Override + public int getRowCount() { + return games.length; + } + + @Override + public int getColumnCount() { + return columnNames.length; + } + + @Override + public Object getValueAt(int arg0, int arg1) { + switch (arg1) { + case 0: + return Integer.toString(games[arg0].getRoundNum()); + case 1: + return games[arg0].getPlayers(); + case 2: + return games[arg0].getState(); + case 3: + return games[arg0].getResult(); + case 4: +// if (games[arg0].getState().equals("Finished")) { +// return "Replay"; +// } + if (watchingAllowed && games[arg0].getState().startsWith("Dueling")) { + return "Watch"; + } + return ""; + case 5: + return games[arg0].getTableId().toString(); + case 6: + return games[arg0].getMatchId().toString(); + case 7: + return games[arg0].getGameId().toString(); + + } + return ""; + } + + @Override + public String getColumnName(int columnIndex) { + String colName = ""; + + if (columnIndex <= getColumnCount()) { + colName = columnNames[columnIndex]; + } + + return colName; + } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == ACTION_COLUMN; + } + +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java index 3965214f35..19eeb84fdb 100644 --- a/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java +++ b/Mage.Client/src/main/java/mage/client/tournament/TournamentPanel.java @@ -1,52 +1,37 @@ - - - /* - * TournamentPanel.java - * - * Created on 20-Jan-2011, 9:18:30 PM - */ package mage.client.tournament; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Rectangle; +import mage.client.MageFrame; +import mage.client.SessionHandler; +import mage.client.chat.ChatPanelBasic; +import mage.client.dialog.PreferencesDialog; +import mage.client.table.TablesButtonColumn; +import mage.client.table.TablesUtil; +import mage.client.table.TournamentMatchesTableModel; +import mage.client.util.Format; +import mage.client.util.GUISizeHelper; +import mage.client.util.gui.TableUtil; +import mage.client.util.gui.countryBox.CountryCellRenderer; +import mage.constants.PlayerAction; +import mage.view.TournamentPlayerView; +import mage.view.TournamentView; +import mage.view.UserRequestMessage; +import org.apache.log4j.Logger; + +import javax.swing.*; +import javax.swing.table.AbstractTableModel; +import java.awt.*; import java.awt.event.ActionEvent; import java.text.DateFormat; -import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.UUID; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.Icon; -import javax.swing.SwingWorker; -import javax.swing.table.AbstractTableModel; -import mage.client.MageFrame; -import mage.client.SessionHandler; -import mage.client.chat.ChatPanelBasic; -import mage.client.dialog.PreferencesDialog; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_ORDER; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_MATCH_COLUMNS_WIDTH; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_ORDER; -import static mage.client.dialog.PreferencesDialog.KEY_TOURNAMENT_PLAYER_COLUMNS_WIDTH; -import mage.client.util.ButtonColumn; -import mage.client.util.Format; -import mage.client.util.GUISizeHelper; -import mage.client.util.gui.TableUtil; -import mage.client.util.gui.countryBox.CountryCellRenderer; -import mage.constants.PlayerAction; -import mage.view.RoundView; -import mage.view.TournamentGameView; -import mage.view.TournamentPlayerView; -import mage.view.TournamentView; -import mage.view.UserRequestMessage; -import org.apache.log4j.Logger; + +import static mage.client.dialog.PreferencesDialog.*; /** - * * @author BetaSteward_at_googlemail.com */ public class TournamentPanel extends javax.swing.JPanel { @@ -64,7 +49,7 @@ public class TournamentPanel extends javax.swing.JPanel { private UpdateTournamentTask updateTask; private final DateFormat df; - private final ButtonColumn actionButtonColumn1; + private final TablesButtonColumn actionButtonColumn1; /** * Creates new form TournamentPanel @@ -92,7 +77,11 @@ public class TournamentPanel extends javax.swing.JPanel { Action action = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { - int modelRow = Integer.valueOf(e.getActionCommand()); + String searchID = e.getActionCommand(); + int modelRow = TablesUtil.findTableRowFromSearchId(matchesModel, searchID); + if (modelRow == -1) { + return; + } String state = (String) tableMatches.getValueAt(modelRow, tableMatches.convertColumnIndexToView(2)); String actionText = (String) tableMatches.getValueAt(modelRow, tableMatches.convertColumnIndexToView(TournamentMatchesTableModel.ACTION_COLUMN)); @@ -111,7 +100,7 @@ public class TournamentPanel extends javax.swing.JPanel { }; // action button, don't delete this - actionButtonColumn1 = new ButtonColumn(tableMatches, action, tableMatches.convertColumnIndexToView(TournamentMatchesTableModel.ACTION_COLUMN)); + actionButtonColumn1 = new TablesButtonColumn(tableMatches, action, tableMatches.convertColumnIndexToView(TournamentMatchesTableModel.ACTION_COLUMN)); setGUISize(); } @@ -150,7 +139,7 @@ public class TournamentPanel extends javax.swing.JPanel { private void saveDividerLocations() { // save panel sizes and divider locations. Rectangle rec = MageFrame.getDesktop().getBounds(); - String sb = Double.toString(rec.getWidth()) + 'x' + Double.toString(rec.getHeight()); + String sb = Double.toString(rec.getWidth()) + 'x' + rec.getHeight(); PreferencesDialog.saveValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, sb); PreferencesDialog.saveValue(PreferencesDialog.KEY_TOURNAMENT_DIVIDER_LOCATION_1, Integer.toString(this.jSplitPane1.getDividerLocation())); PreferencesDialog.saveValue(PreferencesDialog.KEY_TOURNAMENT_DIVIDER_LOCATION_2, Integer.toString(this.jSplitPane2.getDividerLocation())); @@ -160,7 +149,7 @@ public class TournamentPanel extends javax.swing.JPanel { Rectangle rec = MageFrame.getDesktop().getBounds(); if (rec != null) { String size = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE, null); - String sb = Double.toString(rec.getWidth()) + 'x' + Double.toString(rec.getHeight()); + String sb = Double.toString(rec.getWidth()) + 'x' + rec.getHeight(); // use divider positions only if screen size is the same as it was the time the settings were saved if (size != null && size.equals(sb)) { String location = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_TOURNAMENT_DIVIDER_LOCATION_1, null); @@ -390,67 +379,67 @@ public class TournamentPanel extends javax.swing.JPanel { javax.swing.GroupLayout actionPanelLayout = new javax.swing.GroupLayout(actionPanel); actionPanel.setLayout(actionPanelLayout); actionPanelLayout.setHorizontalGroup( - actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addContainerGap() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblName) - .addComponent(lblState) - .addComponent(txtName, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE) - .addComponent(txtTournamentState)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(lblType) - .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtStartTime, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(lblStartTime)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(lblEndTime) - .addComponent(txtEndTime)))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 126, Short.MAX_VALUE) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(btnQuitTournament, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(btnCloseWindow, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblName) + .addComponent(lblState) + .addComponent(txtName, javax.swing.GroupLayout.DEFAULT_SIZE, 260, Short.MAX_VALUE) + .addComponent(txtTournamentState)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(lblType) + .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, 440, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtStartTime, javax.swing.GroupLayout.PREFERRED_SIZE, 220, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(lblStartTime)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(lblEndTime) + .addComponent(txtEndTime)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 126, Short.MAX_VALUE) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addComponent(btnQuitTournament, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(btnCloseWindow, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); actionPanelLayout.setVerticalGroup( - actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGap(7, 7, 7) - .addComponent(lblName)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, actionPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(lblType))) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(btnQuitTournament)) - .addGap(13, 13, 13) - .addComponent(btnCloseWindow)) - .addGroup(actionPanelLayout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(lblState) - .addComponent(lblStartTime) - .addComponent(lblEndTime)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(actionPanelLayout.createSequentialGroup() - .addComponent(txtTournamentState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) - .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(txtStartTime) - .addComponent(txtEndTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addContainerGap()) + actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGap(7, 7, 7) + .addComponent(lblName)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, actionPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(lblType))) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(txtType, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(btnQuitTournament)) + .addGap(13, 13, 13) + .addComponent(btnCloseWindow)) + .addGroup(actionPanelLayout.createSequentialGroup() + .addGap(6, 6, 6) + .addComponent(txtName, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lblState) + .addComponent(lblStartTime) + .addComponent(lblEndTime)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(actionPanelLayout.createSequentialGroup() + .addComponent(txtTournamentState, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) + .addGroup(actionPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(txtStartTime) + .addComponent(txtEndTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addContainerGap()) ); jSplitPane2.setResizeWeight(1.0); @@ -481,17 +470,17 @@ public class TournamentPanel extends javax.swing.JPanel { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(actionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(actionPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jSplitPane2, javax.swing.GroupLayout.Alignment.TRAILING) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(actionPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 454, Short.MAX_VALUE) - .addContainerGap()) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(actionPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jSplitPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 454, Short.MAX_VALUE) + .addContainerGap()) ); }// //GEN-END:initComponents @@ -603,88 +592,6 @@ class TournamentPlayersTableModel extends AbstractTableModel { } -class TournamentMatchesTableModel extends AbstractTableModel { - - public static final int ACTION_COLUMN = 4; // column the action is located - - private final String[] columnNames = new String[]{"Round Number", "Players", "State", "Result", "Action"}; - private TournamentGameView[] games = new TournamentGameView[0]; - private boolean watchingAllowed; - - public void loadData(TournamentView tournament) { - List views = new ArrayList<>(); - watchingAllowed = tournament.isWatchingAllowed(); - for (RoundView round : tournament.getRounds()) { - for (TournamentGameView game : round.getGames()) { - views.add(game); - } - } - games = views.toArray(new TournamentGameView[0]); - this.fireTableDataChanged(); - } - - @Override - public int getRowCount() { - return games.length; - } - - @Override - public int getColumnCount() { - return columnNames.length; - } - - @Override - public Object getValueAt(int arg0, int arg1) { - switch (arg1) { - case 0: - return Integer.toString(games[arg0].getRoundNum()); - case 1: - return games[arg0].getPlayers(); - case 2: - return games[arg0].getState(); - case 3: - return games[arg0].getResult(); - case 4: -// if (games[arg0].getState().equals("Finished")) { -// return "Replay"; -// } - if (watchingAllowed && games[arg0].getState().startsWith("Dueling")) { - return "Watch"; - } - return ""; - case 5: - return games[arg0].getTableId().toString(); - case 6: - return games[arg0].getMatchId().toString(); - case 7: - return games[arg0].getGameId().toString(); - - } - return ""; - } - - @Override - public String getColumnName(int columnIndex) { - String colName = ""; - - if (columnIndex <= getColumnCount()) { - colName = columnNames[columnIndex]; - } - - return colName; - } - - @Override - public Class getColumnClass(int columnIndex) { - return String.class; - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return columnIndex == ACTION_COLUMN; - } - -} class UpdateTournamentTask extends SwingWorker { @@ -727,4 +634,4 @@ class UpdateTournamentTask extends SwingWorker { } } -} +} \ No newline at end of file diff --git a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatDialog.java b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatDialog.java index c1f7d8df52..f3f8e826a4 100644 --- a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatDialog.java +++ b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatDialog.java @@ -1,7 +1,7 @@ /* - * CombatDialog.java + * COMBAT.java * * Created on Feb 10, 2010, 3:35:02 PM */ @@ -33,7 +33,7 @@ public class CombatDialog extends MageDialog { private int lastX = 500; private int lastY = 300; - /** Creates new form CombatDialog */ + /** Creates new form COMBAT */ public CombatDialog() { JPanel contentPane = new JPanel() { diff --git a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java index d6bef0a6a1..da6b77dae1 100644 --- a/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java +++ b/Mage.Client/src/main/java/mage/client/unusedFiles/CombatGroup.java @@ -61,9 +61,9 @@ public class CombatGroup extends javax.swing.JPanel { attackers = new mage.client.cards.Cards(); lblDefender = new javax.swing.JLabel(); - blockers.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25)); + blockers.setPreferredSize(new java.awt.Dimension(Config.dimensions.getFrameWidth() + 8, Config.dimensions.getFrameHeight() + 25)); - attackers.setPreferredSize(new java.awt.Dimension(Config.dimensions.frameWidth + 8, Config.dimensions.frameHeight + 25)); + attackers.setPreferredSize(new java.awt.Dimension(Config.dimensions.getFrameWidth() + 8, Config.dimensions.getFrameHeight() + 25)); lblDefender.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); lblDefender.setText("Defender"); diff --git a/Mage.Client/src/main/java/mage/client/util/CardLanguage.java b/Mage.Client/src/main/java/mage/client/util/CardLanguage.java new file mode 100644 index 0000000000..2be99682c2 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/CardLanguage.java @@ -0,0 +1,68 @@ +package mage.client.util; + +import java.util.ArrayList; + +/** + * @author JayDi85 + */ +public enum CardLanguage { + + ENGLISH("en", "English"), + SPANISH("es", "Spanish"), + FRENCH("fr", "French"), + GERMAN("de", "German"), + ITALIAN("it", "Italian"), + PORTUGUESE("pt", "Portuguese"), + JAPANESE("jp", "Japanese"), + KOREAN("ko", "Korean"), + RUSSIAN("ru", "Russian"), + CHINES_SIMPLE("cns", "Chinese Simplified"), + CHINES_TRADITION("cnt", "Chinese Traditional"); + + private final String code; + private final String text; + + CardLanguage(String code, String text) { + this.code = code; + this.text = text; + } + + @Override + public String toString() { + return code; + } + + public String getCode() { + return code; + } + + public String getText() { + return text; + } + + public static String[] toList() { + ArrayList res = new ArrayList<>(); + for (CardLanguage l : values()) { + res.add(l.toString()); + } + return res.toArray(new String[0]); + } + + public static CardLanguage valueByText(String text) { + for (CardLanguage type : values()) { + if (type.text.equals(text)) { + return type; + } + } + return CardLanguage.ENGLISH; + } + + public static CardLanguage valueByCode(String code) { + for (CardLanguage type : values()) { + if (type.code.equals(code)) { + return type; + } + } + return CardLanguage.ENGLISH; + } +} diff --git a/Mage.Client/src/main/java/mage/client/util/CardViewColorIdentityComparator.java b/Mage.Client/src/main/java/mage/client/util/CardViewColorIdentityComparator.java index 162ea9182b..60ce0dda9a 100644 --- a/Mage.Client/src/main/java/mage/client/util/CardViewColorIdentityComparator.java +++ b/Mage.Client/src/main/java/mage/client/util/CardViewColorIdentityComparator.java @@ -2,7 +2,7 @@ package mage.client.util; import java.util.Comparator; -import mage.utils.CardUtil; +import mage.utils.CardColorUtil; import mage.view.CardView; /** @@ -13,7 +13,7 @@ public class CardViewColorIdentityComparator implements Comparator { @Override public int compare(CardView o1, CardView o2) { - return CardUtil.getColorIdentitySortValue(o1.getManaCost(), o1.getColor(), o1.getRules()) - - CardUtil.getColorIdentitySortValue(o2.getManaCost(), o2.getColor(), o2.getRules()); + return CardColorUtil.getColorIdentitySortValue(o1.getManaCost(), o1.getColor(), o1.getRules()) + - CardColorUtil.getColorIdentitySortValue(o2.getManaCost(), o2.getColor(), o2.getRules()); } } diff --git a/Mage.Client/src/main/java/mage/client/util/CardViewEDHPowerLevelComparator.java b/Mage.Client/src/main/java/mage/client/util/CardViewEDHPowerLevelComparator.java index 31239d1d95..9d4f614020 100644 --- a/Mage.Client/src/main/java/mage/client/util/CardViewEDHPowerLevelComparator.java +++ b/Mage.Client/src/main/java/mage/client/util/CardViewEDHPowerLevelComparator.java @@ -428,7 +428,7 @@ public class CardViewEDHPowerLevelComparator implements Comparator { || cn.equals("krosan restorer") || cn.equals("laboratory maniac") || cn.equals("leovold, emissary of trest") || cn.equals("leonin relic-warder") || cn.equals("leyline of the void") - || cn.equals("memnarch") || cn.equals("memnarch") + || cn.equals("memnarch") || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed") || cn.equals("mindcrank") || cn.equals("mindslaver") || cn.equals("minion reflector") || cn.equals("mycosynth lattice") @@ -446,7 +446,7 @@ public class CardViewEDHPowerLevelComparator implements Comparator { || cn.equals("sunder") || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box") || cn.equals("tangle wire") - || cn.equals("teferi, mage of zhalfir") || cn.equals("teferi, mage of zhalfir") + || cn.equals("teferi, mage of zhalfir") || cn.equals("tezzeret the seeker") || cn.equals("time stretch") || cn.equals("time warp") || cn.equals("training grounds") || cn.equals("triskelavus") || cn.equals("triskelion") diff --git a/Mage.Client/src/main/java/mage/client/util/Config.java b/Mage.Client/src/main/java/mage/client/util/Config.java index 466f2ad08c..459ee469b9 100644 --- a/Mage.Client/src/main/java/mage/client/util/Config.java +++ b/Mage.Client/src/main/java/mage/client/util/Config.java @@ -1,4 +1,3 @@ - package mage.client.util; import java.io.File; @@ -33,38 +32,41 @@ public final class Config { static { Properties p = new Properties(); - try(FileInputStream fis =new FileInputStream(new File("config/config.properties"))) { + boolean fileFound = true; + try (FileInputStream fis = new FileInputStream(new File("config/config.properties"))) { p.load(fis); } catch (IOException ex) { - logger.fatal("Config error ", ex); + fileFound = false; } - serverName = p.getProperty("server-name"); - port = Integer.parseInt(p.getProperty("port")); - remoteServer = p.getProperty("remote-server"); - cardScalingFactor = Double.valueOf(p.getProperty("card-scaling-factor")); - cardScalingFactorEnlarged = Double.valueOf(p.getProperty("card-scaling-factor-enlarged")); - handScalingFactor = Double.valueOf(p.getProperty("hand-scaling-factor")); - defaultGameType = p.getProperty("default-game-type", "Human"); - defaultDeckPath = p.getProperty("default-deck-path"); - defaultOtherPlayerIndex = p.getProperty("default-other-player-index"); - defaultComputerName = p.getProperty("default-computer-name"); + if (fileFound) { + serverName = p.getProperty("server-name"); + port = Integer.parseInt(p.getProperty("port")); + remoteServer = p.getProperty("remote-server"); + cardScalingFactor = Double.valueOf(p.getProperty("card-scaling-factor")); + cardScalingFactorEnlarged = Double.valueOf(p.getProperty("card-scaling-factor-enlarged")); + handScalingFactor = Double.valueOf(p.getProperty("hand-scaling-factor")); + defaultGameType = p.getProperty("default-game-type", "Human"); + defaultDeckPath = p.getProperty("default-deck-path"); + defaultOtherPlayerIndex = p.getProperty("default-other-player-index"); + defaultComputerName = p.getProperty("default-computer-name"); - dimensions = new CardDimensions(cardScalingFactor); - dimensionsEnlarged = new CardDimensions(cardScalingFactorEnlarged); -// activate instead this part, to run the UI editor for some panels without error -// serverName = "localhost"; -// port = 17171; -// remoteServer = "mage-server"; -// cardScalingFactor = 0.4; -// cardScalingFactorEnlarged = 0.5; -// handScalingFactor = 1.3; -// defaultGameType = p.getProperty("default-game-type", "Human"); -// defaultDeckPath = ""; -// defaultOtherPlayerIndex = "1"; -// defaultComputerName = "Computer"; -// -// dimensions = new CardDimensions(cardScalingFactor); -// dimensionsEnlarged = new CardDimensions(cardScalingFactorEnlarged); + dimensions = new CardDimensions(cardScalingFactor); + dimensionsEnlarged = new CardDimensions(cardScalingFactorEnlarged); + } else { // Take some default valies for netbeans design view + serverName = "localhost"; + port = 17171; + remoteServer = "mage-server"; + cardScalingFactor = 0.4; + cardScalingFactorEnlarged = 0.5; + handScalingFactor = 1.3; + defaultGameType = p.getProperty("default-game-type", "Human"); + defaultDeckPath = ""; + defaultOtherPlayerIndex = "1"; + defaultComputerName = "AI Computer"; + + dimensions = new CardDimensions(cardScalingFactor); + dimensionsEnlarged = new CardDimensions(cardScalingFactorEnlarged); + } } diff --git a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java index 790fe34e03..3f187e19f4 100644 --- a/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java +++ b/Mage.Client/src/main/java/mage/client/util/GUISizeHelper.java @@ -8,6 +8,7 @@ package mage.client.util; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; +import java.util.Locale; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; @@ -22,9 +23,9 @@ import org.mage.card.arcane.CardRenderer; public final class GUISizeHelper { // relate the native image card size to a value of the size scale - final static int CARD_IMAGE_WIDTH = 312; - final static int CARD_IMAGE_HEIGHT = 445; - final static int CARD_IMAG_VALUE = 42; + static final int CARD_IMAGE_WIDTH = 312; + static final int CARD_IMAGE_HEIGHT = 445; + static final int CARD_IMAG_VALUE = 42; public static String basicSymbolSize = "small"; @@ -178,4 +179,11 @@ public final class GUISizeHelper { } } } + + public static String textToHtmlWithSize(String text, Font font) { + if (text != null && !text.toLowerCase(Locale.ENGLISH).startsWith("")) { + return "

" + text + "

"; + } + return text; + } } diff --git a/Mage.Client/src/main/java/mage/client/util/IgnoreList.java b/Mage.Client/src/main/java/mage/client/util/IgnoreList.java index 89906031fa..7249cac157 100644 --- a/Mage.Client/src/main/java/mage/client/util/IgnoreList.java +++ b/Mage.Client/src/main/java/mage/client/util/IgnoreList.java @@ -9,12 +9,12 @@ import mage.view.ChatMessage; public final class IgnoreList { - private static final String USAGE = "
\\ignore - shows current ignore list on this server." - + "
\\ignore [username] - add a username to your ignore list on this server." + private static final String USAGE = "
\\ignore - shows your ignore list on this server." + + "
\\ignore [username] - add username to ignore list (they won't be able to chat or join to your game)." + "
\\unignore [username] - remove a username from your ignore list on this server.
"; public static final int MAX_IGNORE_LIST_SIZE = 50; - public static Set IGNORED_MESSAGE_TYPES + public static final Set IGNORED_MESSAGE_TYPES = ImmutableSet.of(ChatMessage.MessageType.TALK, ChatMessage.MessageType.WHISPER_FROM); diff --git a/Mage.Client/src/main/java/mage/client/util/ImageCaches.java b/Mage.Client/src/main/java/mage/client/util/ImageCaches.java index cf22680495..479370288a 100644 --- a/Mage.Client/src/main/java/mage/client/util/ImageCaches.java +++ b/Mage.Client/src/main/java/mage/client/util/ImageCaches.java @@ -2,7 +2,8 @@ package mage.client.util; import java.util.ArrayList; -import java.util.Map; + +import com.google.common.cache.Cache; /** * @@ -10,20 +11,20 @@ import java.util.Map; */ public final class ImageCaches { - private final static ArrayList IMAGE_CACHES; + private final static ArrayList> IMAGE_CACHES; static { IMAGE_CACHES = new ArrayList<>(); } - public static Map register(Map map) { + public static , K, V> C register(C map) { IMAGE_CACHES.add(map); return map; } public static void flush() { - for (Map map : IMAGE_CACHES) { - map.clear(); + for (Cache map : IMAGE_CACHES) { + map.invalidateAll(); } } } diff --git a/Mage.Client/src/main/java/mage/client/util/SoftValuesLoadingCache.java b/Mage.Client/src/main/java/mage/client/util/SoftValuesLoadingCache.java new file mode 100644 index 0000000000..40e1550c91 --- /dev/null +++ b/Mage.Client/src/main/java/mage/client/util/SoftValuesLoadingCache.java @@ -0,0 +1,67 @@ +package mage.client.util; + +import static com.google.common.cache.CacheBuilder.newBuilder; + +import java.util.Optional; +import java.util.concurrent.ExecutionException; + +import com.google.common.base.Function; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.ForwardingLoadingCache; +import com.google.common.cache.LoadingCache; +import org.apache.log4j.Logger; + +public class SoftValuesLoadingCache extends ForwardingLoadingCache> { + + private final LoadingCache> cache; + private static final Logger logger = Logger.getLogger(SoftValuesLoadingCache.class); + + public SoftValuesLoadingCache(CacheLoader> loader) { + cache = newBuilder().softValues().build(loader); + } + + @Override + protected LoadingCache> delegate() { + return cache; + } + + public V getOrThrow(K key) { + V v = getOrNull(key); + if (v == null) { + throw new NullPointerException(); + } + return v; + } + + public V getOrNull(K key) { + try { + return get(key).orElse(null); + } catch (ExecutionException e) { + if (e.getCause() instanceof OutOfMemoryError) { + logger.warn("Out of memory error: try to increase free memory in launcher options (-xmx param)"); + return null; + } else { + throw new RuntimeException(e); + } + } catch (Throwable e) { + return null; + } + } + + public V peekIfPresent(K key) { + Optional value = getIfPresent(key); + if (value != null) { + return value.orElse(null); + } + return null; + } + + public static SoftValuesLoadingCache from(CacheLoader> loader) { + return new SoftValuesLoadingCache<>(loader); + } + + public static SoftValuesLoadingCache from(Function loader) { + return from(CacheLoader.from(k -> Optional.ofNullable(loader.apply(k)))); + } + +} diff --git a/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java b/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java index b8abf2e553..a5bac22407 100644 --- a/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java +++ b/Mage.Client/src/main/java/mage/client/util/TransformedImageCache.java @@ -5,16 +5,16 @@ */ package mage.client.util; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; -import com.mortennobel.imagescaling.ResampleOp; -import java.awt.Graphics2D; -import java.awt.GraphicsConfiguration; -import java.awt.GraphicsDevice; -import java.awt.GraphicsEnvironment; -import java.awt.Transparency; +import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Map; + +import javax.annotation.Nullable; + +import com.google.common.base.Function; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.mortennobel.imagescaling.ResampleOp; /** * @@ -22,7 +22,7 @@ import java.util.Map; */ public final class TransformedImageCache { - private final static class Key { + private static final class Key { final int width; final int height; @@ -68,19 +68,23 @@ public final class TransformedImageCache { } } - private static final Map> IMAGE_CACHE; + private static final SoftValuesLoadingCache> IMAGE_CACHE; static { // TODO: can we use a single map? - IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function>) key -> new MapMaker().weakKeys().softValues().makeComputingMap(image -> { + IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(TransformedImageCache::createTransformedImageCache)); + } + + private static SoftValuesLoadingCache createTransformedImageCache(Key key) { + return SoftValuesLoadingCache.from(image -> { if (key.width != image.getWidth() || key.height != image.getHeight()) { image = resizeImage(image, key.width, key.height); } if (key.angle != 0.0) { image = rotateImage(image, key.angle); } - return image; - }))); + return image; + }); } private static BufferedImage rotateImage(BufferedImage image, double angle) { @@ -145,6 +149,6 @@ public final class TransformedImageCache { if (resHeight < 3) { resHeight = 3; } - return IMAGE_CACHE.get(new Key(resWidth, resHeight, angle)).get(image); + return IMAGE_CACHE.getOrThrow(new Key(resWidth, resHeight, angle)).getOrThrow(image); } } diff --git a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java index da018d0d8f..5e310ddbf1 100644 --- a/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java +++ b/Mage.Client/src/main/java/mage/client/util/audio/AudioManager.java @@ -57,7 +57,7 @@ public class AudioManager { try { linePool = new LinePool(); } catch (Exception e) { - log.warn("Failed to initialize AudioManager. No sounds will be played.", e); + log.warn("Failed to initialize AudioManager (can't find compatible sound device). No sounds will be played."); } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java index 991a40add4..c6088f2089 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/ArrowUtil.java @@ -19,32 +19,32 @@ public final class ArrowUtil { private ArrowUtil() {} public static void drawArrowsForPairedCards(TransferData data, Point parentPoint) { - if (data.card.getPairedCard() != null) { - Point me = new Point(data.locationOnScreen); + if (data.getCard().getPairedCard() != null) { + Point me = new Point(data.getLocationOnScreen()); me.translate(-parentPoint.x, -parentPoint.y); - UUID uuid = data.card.getPairedCard(); - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + UUID uuid = data.getCard().getPairedCard(); + for (PlayAreaPanel pa : MageFrame.getGame(data.getGameId()).getPlayers().values()) { MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); if (permanent != null) { Point target = permanent.getLocationOnScreen(); target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.green, ArrowBuilder.Type.PAIRED); } } } } public static void drawArrowsForBandedCards(TransferData data, Point parentPoint) { - if (data.card.getBandedCards() != null && !data.card.getBandedCards().isEmpty()) { - Point me = new Point(data.locationOnScreen); + if (data.getCard().getBandedCards() != null && !data.getCard().getBandedCards().isEmpty()) { + Point me = new Point(data.getLocationOnScreen()); me.translate(-parentPoint.x, -parentPoint.y); - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { - for (UUID uuid : data.card.getBandedCards()) { + for (PlayAreaPanel pa : MageFrame.getGame(data.getGameId()).getPlayers().values()) { + for (UUID uuid : data.getCard().getBandedCards()) { MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); if (permanent != null) { Point target = permanent.getLocationOnScreen(); target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 55, (int) me.getY() + 25, (int) target.getX() + 60, (int) target.getY() + 35, Color.yellow, ArrowBuilder.Type.BANDED); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) me.getX() + 55, (int) me.getY() + 25, (int) target.getX() + 60, (int) target.getY() + 35, Color.yellow, ArrowBuilder.Type.BANDED); } } } @@ -52,17 +52,17 @@ public final class ArrowUtil { } public static void drawArrowsForEnchantPlayers(TransferData data, Point parentPoint) { - if (data.gameId != null && MageFrame.getGame(data.gameId) != null) { - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + if (data.getGameId() != null && MageFrame.getGame(data.getGameId()) != null) { + for (PlayAreaPanel pa : MageFrame.getGame(data.getGameId()).getPlayers().values()) { PlayerPanelExt playAreaPanel = pa.getPlayerPanel(); if (playAreaPanel != null && playAreaPanel.getPlayer() != null && playAreaPanel.getPlayer().hasAttachments()) { - Point me = new Point(data.locationOnScreen); + Point me = new Point(data.getLocationOnScreen()); me.translate(-parentPoint.x, -parentPoint.y); for (UUID attachmentId : playAreaPanel.getPlayer().getAttachments()) { - if (attachmentId.equals(data.card.getId())) { + if (attachmentId.equals(data.getCard().getId())) { Point player = pa.getLocationOnScreen(); player.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId,(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS); + ArrowBuilder.getBuilder().addArrow(data.getGameId(),(int) me.getX() + 35, (int) me.getY(), (int) player.getX() + 40, (int) player.getY() - 40, Color.magenta, ArrowBuilder.Type.ENCHANT_PLAYERS); } } } @@ -71,45 +71,45 @@ public final class ArrowUtil { } public static void drawArrowsForSource(TransferData data, Point parentPoint) { - if (data.card.isAbility()) { - Point me = new Point(data.locationOnScreen); + if (data.getCard().isAbility()) { + Point me = new Point(data.getLocationOnScreen()); me.translate(-parentPoint.x, -parentPoint.y); - UUID uuid = data.card.getParentId(); - for (PlayAreaPanel pa : MageFrame.getGame(data.gameId).getPlayers().values()) { + UUID uuid = data.getCard().getParentId(); + for (PlayAreaPanel pa : MageFrame.getGame(data.getGameId()).getPlayers().values()) { MagePermanent permanent = pa.getBattlefieldPanel().getPermanents().get(uuid); if (permanent != null) { Point source = permanent.getLocationOnScreen(); source.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) source.getX() + 40, (int) source.getY() + 10, (int) me.getX() + 35, (int) me.getY() + 20, Color.blue, ArrowBuilder.Type.SOURCE); } } } } public static void drawArrowsForTargets(TransferData data, Point parentPoint) { - java.util.List targets = data.card.getTargets(); + java.util.List targets = data.getCard().getTargets(); if (targets == null) { return; } - Point me = new Point(data.locationOnScreen); + Point me = new Point(data.getLocationOnScreen()); me.translate(-parentPoint.x, -parentPoint.y); for (UUID uuid : targets) { - PlayAreaPanel p = MageFrame.getGame(data.gameId).getPlayers().get(uuid); + PlayAreaPanel p = MageFrame.getGame(data.getGameId()).getPlayers().get(uuid); if (p != null) { Point target = p.getLocationOnScreen(); target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() - 40, Color.red, ArrowBuilder.Type.TARGET); continue; } - for (PlayAreaPanel panel : MageFrame.getGame(data.gameId).getPlayers().values()) { + for (PlayAreaPanel panel : MageFrame.getGame(data.getGameId()).getPlayers().values()) { MagePermanent permanent = panel.getBattlefieldPanel().getPermanents().get(uuid); if (permanent != null) { Point target = permanent.getLocationOnScreen(); target.translate(-parentPoint.x, -parentPoint.y); - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 40, (int) target.getY() + 10, Color.red, ArrowBuilder.Type.TARGET); continue; } @@ -117,12 +117,12 @@ public final class ArrowUtil { if (view != null) { CardsView graveyard = view.getGraveyard(); if (graveyard.containsKey(uuid)) { - p = MageFrame.getGame(data.gameId).getPlayers().get(view.getPlayerId()); + p = MageFrame.getGame(data.getGameId()).getPlayers().get(view.getPlayerId()); if (p != null) { Point target = p.getLocationOnScreen(); target.translate(-parentPoint.x, -parentPoint.y); int yOffset = p.isSmallMode() ? (PlayAreaPanel.PANEL_HEIGHT - PlayAreaPanel.PANEL_HEIGHT_SMALL) : 0; - ArrowBuilder.getBuilder().addArrow(data.gameId, (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET); + ArrowBuilder.getBuilder().addArrow(data.getGameId(), (int) me.getX() + 35, (int) me.getY(), (int) target.getX() + 15, (int) target.getY() + 145 - yOffset, Color.red, ArrowBuilder.Type.TARGET); } } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java index f1a22f6f3f..533b0c95cd 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/FastSearchUtil.java @@ -1,41 +1,44 @@ package mage.client.util.gui; import mage.choices.ChoiceImpl; +import mage.client.dialog.CheckBoxList; import mage.client.dialog.PickCheckBoxDialog; import mage.client.dialog.PickChoiceDialog; -import mage.client.dialog.CheckBoxList; - import javax.swing.*; import java.util.HashMap; import java.util.Map; /** - * * @author JayDi85 */ public class FastSearchUtil { - public static String DEFAULT_EXPANSION_SEARCH_MESSAGE = "Select set or expansion"; - public static String DEFAULT_EXPANSION_TOOLTIP_MESSAGE = "Fast search set or expansion"; + public static final String DEFAULT_EXPANSION_SEARCH_MESSAGE = "Select set or expansion"; + public static final String DEFAULT_EXPANSION_TOOLTIP_MESSAGE = "Fast search set or expansion"; + + public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage) { + showFastSearchForStringComboBox(combo, chooseMessage, 300, 500); + } /** * Show fast choice modal dialog with incremental searching for any string combobox components - * @param combo combobox control with default data model + * + * @param combo combobox control with default data model * @param chooseMessage caption message for dialog */ - public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage){ + public static void showFastSearchForStringComboBox(JComboBox combo, String chooseMessage, int windowWidth, int windowHeight) { // fast search/choice dialog for string combobox mage.choices.Choice choice = new ChoiceImpl(false); // collect data from expansion combobox (String) - DefaultComboBoxModel comboModel = (DefaultComboBoxModel)combo.getModel(); + DefaultComboBoxModel comboModel = (DefaultComboBoxModel) combo.getModel(); Map choiceItems = new HashMap<>(comboModel.getSize()); Map choiceSorting = new HashMap<>(comboModel.getSize()); String item; - for(int i = 0; i < comboModel.getSize(); i++){ + for (int i = 0; i < comboModel.getSize(); i++) { item = comboModel.getElementAt(i).toString(); choiceItems.put(item, item); choiceSorting.put(item, i); // need so sorting @@ -51,37 +54,38 @@ public class FastSearchUtil { // ask for new value PickChoiceDialog dlg = new PickChoiceDialog(); - dlg.setWindowSize(300, 500); + dlg.setWindowSize(windowWidth, windowHeight); dlg.showDialog(choice, needSelectValue); - if(choice.isChosen()){ + if (choice.isChosen()) { item = choice.getChoiceKey(); // compatible select for object's models (use setSelectedIndex instead setSelectedObject) - for(int i = 0; i < comboModel.getSize(); i++){ - if(comboModel.getElementAt(i).toString().equals(item)){ + for (int i = 0; i < comboModel.getSize(); i++) { + if (comboModel.getElementAt(i).toString().equals(item)) { combo.setSelectedIndex(i); } } } } - + /** * Show fast choice modal dialog with incremental searching for any string CheckBoxList components - * @param combo CheckBoxList control with default data model + * + * @param combo CheckBoxList control with default data model * @param chooseMessage caption message for dialog */ - public static void showFastSearchForStringComboBox(CheckBoxList combo, String chooseMessage){ + public static void showFastSearchForStringComboBox(CheckBoxList combo, String chooseMessage) { // fast search/choice dialog for string combobox mage.choices.Choice choice = new ChoiceImpl(false); // collect data from expansion combobox (String) - DefaultListModel comboModel = (DefaultListModel)combo.getModel(); + DefaultListModel comboModel = (DefaultListModel) combo.getModel(); Map choiceItems = new HashMap<>(comboModel.getSize()); Map choiceSorting = new HashMap<>(comboModel.getSize()); String item; - for(int i = 0; i < comboModel.size(); i++){ + for (int i = 0; i < comboModel.size(); i++) { item = comboModel.getElementAt(i).toString(); choiceItems.put(item, item); choiceSorting.put(item, i); // need so sorting @@ -92,21 +96,22 @@ public class FastSearchUtil { choice.setMessage(chooseMessage); // current selection value restore - String needSelectValue; - needSelectValue = comboModel.firstElement().toString(); + String needSelectValue = null; + if (comboModel.size() > 0) { + needSelectValue = comboModel.firstElement().toString(); + } // ask for new value - - PickCheckBoxDialog dlg = new PickCheckBoxDialog(combo); + PickCheckBoxDialog dlg = new PickCheckBoxDialog(combo); dlg.setWindowSize(300, 500); dlg.showDialog(choice, needSelectValue); - if(choice.isChosen()){ + if (choice.isChosen()) { item = choice.getChoiceKey(); // compatible select for object's models (use setSelectedIndex instead setSelectedObject) - for(int i = 0; i < comboModel.getSize(); i++){ - if(comboModel.getElementAt(i).toString().equals(item)){ + for (int i = 0; i < comboModel.getSize(); i++) { + if (comboModel.getElementAt(i).toString().equals(item)) { combo.setSelectedIndex(i); } } diff --git a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java index 2261c9e2a7..d075cefeeb 100644 --- a/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java +++ b/Mage.Client/src/main/java/mage/client/util/gui/GuiDisplayUtil.java @@ -1,14 +1,9 @@ package mage.client.util.gui; -import java.awt.*; -import java.util.ArrayList; -import java.util.Locale; -import javax.swing.*; -import mage.client.dialog.PreferencesDialog; -import static mage.client.dialog.PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE; import mage.client.MageFrame; +import mage.client.dialog.PreferencesDialog; +import mage.client.table.PlayersChatPanel; import mage.client.util.GUISizeHelper; -import mage.client.table.*; import mage.constants.*; import mage.view.CardView; import mage.view.CounterView; @@ -17,6 +12,13 @@ import org.jdesktop.swingx.JXPanel; import org.mage.card.arcane.ManaSymbols; import org.mage.card.arcane.UI; +import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; +import java.util.Locale; + +import static mage.client.dialog.PreferencesDialog.KEY_MAGE_PANEL_LAST_SIZE; + public final class GuiDisplayUtil { private static final Font cardNameFont = new Font("Calibri", Font.BOLD, 15); @@ -25,37 +27,53 @@ public final class GuiDisplayUtil { public static class TextLines { - public int basicTextLength; - public ArrayList lines; + private int basicTextLength; + private java.util.List lines; + + public int getBasicTextLength() { + return basicTextLength; + } + + public void setBasicTextLength(int basicTextLength) { + this.basicTextLength = basicTextLength; + } + + public java.util.List getLines() { + return lines; + } + + public void setLines(java.util.List lines) { + this.lines = lines; + } } public static void restoreDividerLocations(Rectangle bounds, String lastDividerLocation, JComponent component) { - String currentBounds = Double.toString(bounds.getWidth()) + 'x' + Double.toString(bounds.getHeight()); - String savedBounds = PreferencesDialog.getCachedValue(KEY_MAGE_PANEL_LAST_SIZE, null); - // use divider positions only if screen size is the same as it was the time the settings were saved - if (savedBounds != null && savedBounds.equals(currentBounds)) { - if (lastDividerLocation != null && component != null) { - if (component instanceof JSplitPane) { - JSplitPane jSplitPane = (JSplitPane) component; - jSplitPane.setDividerLocation(Integer.parseInt(lastDividerLocation)); - } + String currentBounds = Double.toString(bounds.getWidth()) + 'x' + bounds.getHeight(); + String savedBounds = PreferencesDialog.getCachedValue(KEY_MAGE_PANEL_LAST_SIZE, null); + // use divider positions only if screen size is the same as it was the time the settings were saved + if (savedBounds != null && savedBounds.equals(currentBounds)) { + if (lastDividerLocation != null && component != null) { + if (component instanceof JSplitPane) { + JSplitPane jSplitPane = (JSplitPane) component; + jSplitPane.setDividerLocation(Integer.parseInt(lastDividerLocation)); + } - if (component instanceof PlayersChatPanel) { - PlayersChatPanel playerChatPanel = (PlayersChatPanel) component; - playerChatPanel.setSplitDividerLocation(Integer.parseInt(lastDividerLocation)); - } + if (component instanceof PlayersChatPanel) { + PlayersChatPanel playerChatPanel = (PlayersChatPanel) component; + playerChatPanel.setSplitDividerLocation(Integer.parseInt(lastDividerLocation)); + } + } } - } } public static void saveCurrentBoundsToPrefs() { - Rectangle rec = MageFrame.getDesktop().getBounds(); - String currentBounds = Double.toString(rec.getWidth()) + 'x' + Double.toString(rec.getHeight()); - PreferencesDialog.saveValue(KEY_MAGE_PANEL_LAST_SIZE, currentBounds); + Rectangle rec = MageFrame.getDesktop().getBounds(); + String currentBounds = Double.toString(rec.getWidth()) + 'x' + rec.getHeight(); + PreferencesDialog.saveValue(KEY_MAGE_PANEL_LAST_SIZE, currentBounds); } public static void saveDividerLocationToPrefs(String dividerPrefKey, int position) { - PreferencesDialog.saveValue(dividerPrefKey, Integer.toString(position)); + PreferencesDialog.saveValue(dividerPrefKey, Integer.toString(position)); } public static JXPanel getDescription(CardView card, int width, int height) { @@ -163,9 +181,9 @@ public final class GuiDisplayUtil { public static TextLines getTextLinesfromCardView(CardView card) { TextLines textLines = new TextLines(); - textLines.lines = new ArrayList<>(card.getRules()); + textLines.setLines(new ArrayList<>(card.getRules())); for (String rule : card.getRules()) { - textLines.basicTextLength += rule.length(); + textLines.setBasicTextLength(textLines.getBasicTextLength() + rule.length()); } if (card.getMageObjectType().canHaveCounters()) { ArrayList counters = new ArrayList<>(); @@ -190,20 +208,24 @@ public final class GuiDisplayUtil { index++; } } - textLines.lines.add(sb.toString()); - textLines.basicTextLength += 50; + textLines.getLines().add(sb.toString()); + textLines.setBasicTextLength(textLines.getBasicTextLength() + 50); } } if (card.getMageObjectType().isPermanent() && card instanceof PermanentView) { int damage = ((PermanentView) card).getDamage(); if (damage > 0) { - textLines.lines.add("Damage dealt: " + damage + ""); - textLines.basicTextLength += 50; + textLines.getLines().add("Damage dealt: " + damage + ""); + textLines.setBasicTextLength(textLines.getBasicTextLength() + 50); } } return textLines; } + public static String getHintIconHtml(String iconName, int symbolSize) { + return "" + iconName + ""; + } + public static StringBuilder getRulefromCardView(CardView card, TextLines textLines) { String manaCost = ""; for (String m : card.getManaCost()) { @@ -236,7 +258,7 @@ public final class GuiDisplayUtil { buffer.append(""); buffer.append(card.getDisplayName()); if (card.isGameObject()) { - buffer.append(" [").append(card.getId().toString().substring(0, 3)).append(']'); + buffer.append(" [").append(card.getId().toString(), 0, 3).append(']'); } buffer.append("").append(textLine).append("

"); } diff --git a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java index 93efaaafba..37d050fc46 100644 --- a/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java +++ b/Mage.Client/src/main/java/mage/client/util/sets/ConstructedFormats.java @@ -1,15 +1,13 @@ package mage.client.util.sets; -import java.util.ArrayList; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import mage.cards.repository.ExpansionInfo; import mage.cards.repository.ExpansionRepository; +import mage.cards.repository.RepositoryEvent; import mage.constants.SetType; import mage.deck.Standard; +import mage.game.events.Listener; + +import java.util.*; /** * Utility class for constructed formats (expansions and other editions). @@ -18,17 +16,42 @@ import mage.deck.Standard; */ public final class ConstructedFormats { - public static final String ALL = "- All Sets"; + public static final String ALL_SETS = "- All Sets"; public static final String STANDARD = "- Standard"; public static final String EXTENDED = "- Extended"; public static final String FRONTIER = "- Frontier"; public static final String MODERN = "- Modern"; public static final String VINTAGE_LEGACY = "- Vintage / Legacy"; + public static final String JOKE = "- Joke Sets"; public static final String CUSTOM = "- Custom"; public static final Standard STANDARD_CARDS = new Standard(); + // Attention -Month is 0 Based so Feb = 1 for example. // + private static final Date extendedDate = new GregorianCalendar(2009, 7, 20).getTime(); + private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime(); + private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime(); + + // for all sets just return empty list + private static final List all = new ArrayList<>(); + private static final Map> underlyingSetCodesPerFormat = new HashMap<>(); private static final List formats = new ArrayList<>(); + private static final Listener setsDbListener; + + static { + buildLists(); + + // auto-update sets list on changes + setsDbListener = new Listener() { + @Override + public void event(RepositoryEvent event) { + if (event.getEventType().equals(RepositoryEvent.RepositoryEventType.DB_UPDATED)) { + buildLists(); + } + } + }; + ExpansionRepository.instance.subscribe(setsDbListener); + } private ConstructedFormats() { } @@ -42,7 +65,7 @@ public final class ConstructedFormats { } public static List getSetsByFormat(final String format) { - if (!format.equals(ALL)) { + if (!format.equals(ALL_SETS)) { return underlyingSetCodesPerFormat.get(format); } return all; @@ -55,46 +78,69 @@ public final class ConstructedFormats { } } - private static void buildLists() { + public static void buildLists() { underlyingSetCodesPerFormat.put(STANDARD, new ArrayList<>()); underlyingSetCodesPerFormat.put(EXTENDED, new ArrayList<>()); underlyingSetCodesPerFormat.put(FRONTIER, new ArrayList<>()); underlyingSetCodesPerFormat.put(MODERN, new ArrayList<>()); underlyingSetCodesPerFormat.put(VINTAGE_LEGACY, new ArrayList<>()); + underlyingSetCodesPerFormat.put(JOKE, new ArrayList<>()); underlyingSetCodesPerFormat.put(CUSTOM, new ArrayList<>()); final Map expansionInfo = new HashMap<>(); formats.clear(); // prevent NPE on sorting if this is not the first try + + // Because this is also called in Netbeans Design view, but the object does not exist in that case, + // we have to return here to prevent exception in design view. (Does not hurt at design time) + if (!ExpansionRepository.instance.instanceInitialized) { + return; + } + + // build formats list for deck validators for (ExpansionInfo set : ExpansionRepository.instance.getAll()) { expansionInfo.put(set.getName(), set); formats.add(set.getName()); + // full list underlyingSetCodesPerFormat.put(set.getName(), new ArrayList<>()); underlyingSetCodesPerFormat.get(set.getName()).add(set.getCode()); - // create the play formats - if (set.getType() == SetType.CUSTOM_SET) { + // custom + if (set.getType().isCustomSet()) { underlyingSetCodesPerFormat.get(CUSTOM).add(set.getCode()); continue; } - underlyingSetCodesPerFormat.get(VINTAGE_LEGACY).add(set.getCode()); - if (set.getType() == SetType.CORE || set.getType() == SetType.EXPANSION || set.getType() == SetType.SUPPLEMENTAL_STANDARD_LEGAL) { - if (STANDARD_CARDS.getSetCodes().contains(set.getCode())) { - underlyingSetCodesPerFormat.get(STANDARD).add(set.getCode()); - } - if (set.getType() != SetType.SUPPLEMENTAL_STANDARD_LEGAL) { - if (set.getReleaseDate().after(extendedDate) && (set.getType() == SetType.EXPANSION || set.getType() == SetType.CORE)) { - underlyingSetCodesPerFormat.get(EXTENDED).add(set.getCode()); - } - if (set.getReleaseDate().after(frontierDate) && (set.getType() == SetType.EXPANSION || set.getType() == SetType.CORE)) { - underlyingSetCodesPerFormat.get(FRONTIER).add(set.getCode()); - } - if (set.getReleaseDate().after(modernDate) && (set.getType() == SetType.EXPANSION || set.getType() == SetType.CORE)) { - underlyingSetCodesPerFormat.get(MODERN).add(set.getCode()); - } - } + + // joke + if (set.getType().isJokeSet()) { + underlyingSetCodesPerFormat.get(JOKE).add(set.getCode()); + continue; } - // Create the Block formats + // vintage/legacy (any set, TODO: even ?custom set?) + underlyingSetCodesPerFormat.get(VINTAGE_LEGACY).add(set.getCode()); + + // standard (dependent on current date) + if (STANDARD_CARDS.getSetCodes().contains(set.getCode())) { + underlyingSetCodesPerFormat.get(STANDARD).add(set.getCode()); + } + + // extended + if (set.getType().isStandardLegal() && set.getReleaseDate().after(extendedDate)) { + underlyingSetCodesPerFormat.get(EXTENDED).add(set.getCode()); + } + + // frontier + if (set.getType().isStandardLegal() && set.getReleaseDate().after(frontierDate)) { + underlyingSetCodesPerFormat.get(FRONTIER).add(set.getCode()); + } + + // modern + if (set.getType().isModernLegal() && set.getReleaseDate().after(modernDate)) { + underlyingSetCodesPerFormat.get(MODERN).add(set.getCode()); + } + + // BLOCKS formats + if (set.getType() == SetType.EXPANSION && set.getBlockName() != null) { String blockDisplayName = getBlockDisplayName(set.getBlockName()); underlyingSetCodesPerFormat.computeIfAbsent(blockDisplayName, k -> new ArrayList<>()); @@ -109,7 +155,6 @@ public final class ConstructedFormats { if (expansionInfo.get(blockDisplayName).getReleaseDate().after(set.getReleaseDate())) { expansionInfo.put(blockDisplayName, set); } - } if (set.getType() == SetType.SUPPLEMENTAL && set.getBlockName() != null) { @@ -200,30 +245,20 @@ public final class ConstructedFormats { } return expansionInfo1.getType().compareTo(expansionInfo2.getType()); }); + if (!formats.isEmpty()) { formats.add(0, CUSTOM); + formats.add(0, JOKE); formats.add(0, VINTAGE_LEGACY); formats.add(0, MODERN); - formats.add(0, EXTENDED); formats.add(0, FRONTIER); + formats.add(0, EXTENDED); formats.add(0, STANDARD); - } - formats.add(0, ALL); + formats.add(0, ALL_SETS); } private static String getBlockDisplayName(String blockName) { return "* " + blockName + " Block"; } - // Attention -Month is 0 Based so Feb = 1 for example. - private static final Date extendedDate = new GregorianCalendar(2009, 7, 20).getTime(); - private static final Date frontierDate = new GregorianCalendar(2014, 6, 17).getTime(); - private static final Date modernDate = new GregorianCalendar(2003, 6, 20).getTime(); - - // for all sets just return empty list - private static final List all = new ArrayList<>(); - - static { - buildLists(); - } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/Animation.java b/Mage.Client/src/main/java/org/mage/card/arcane/Animation.java index 34a44b66e2..d5d679aa7b 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/Animation.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/Animation.java @@ -125,16 +125,16 @@ public abstract class Animation { @Override protected void update(float percentage) { if (tapped) { - panel.tappedAngle = CardPanel.TAPPED_ANGLE * percentage; + panel.setTappedAngle(CardPanel.TAPPED_ANGLE * percentage); // reverse movement if untapping if (!panel.isTapped()) { - panel.tappedAngle = CardPanel.TAPPED_ANGLE - panel.tappedAngle; + panel.setTappedAngle(CardPanel.TAPPED_ANGLE - panel.getTappedAngle()); } } if (flipped) { - panel.flippedAngle = CardPanel.FLIPPED_ANGLE * percentage; + panel.setFlippedAngle(CardPanel.FLIPPED_ANGLE * percentage); if (!panel.isFlipped()) { - panel.flippedAngle = CardPanel.FLIPPED_ANGLE - panel.flippedAngle; + panel.setFlippedAngle(CardPanel.FLIPPED_ANGLE - panel.getFlippedAngle()); } } panel.repaint(); @@ -143,10 +143,10 @@ public abstract class Animation { @Override protected void end() { if (tapped) { - panel.tappedAngle = panel.isTapped() ? CardPanel.TAPPED_ANGLE : 0; + panel.setTappedAngle(panel.isTapped() ? CardPanel.TAPPED_ANGLE : 0); } if (flipped) { - panel.flippedAngle = panel.isFlipped() ? CardPanel.FLIPPED_ANGLE : 0; + panel.setFlippedAngle(panel.isFlipped() ? CardPanel.FLIPPED_ANGLE : 0); } parent.onEndAnimation(); parent.repaint(); @@ -334,7 +334,7 @@ public abstract class Animation { currentX = Math.min(currentX, layeredPane.getWidth() - currentWidth); int currentY = Math.max(0, centerY - Math.round(currentHeight / 2f)); currentY = Math.min(currentY, layeredPane.getHeight() - currentHeight); - animationPanel.tappedAngle = overPanel.tappedAngle * percentage; + animationPanel.setTappedAngle(overPanel.getTappedAngle() * percentage); animationPanel.setCardBounds(currentX, currentY, currentWidth, currentHeight); } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java index 9c670224dd..b39cf150b9 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanel.java @@ -48,14 +48,14 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, private static final float ROT_CENTER_TO_TOP_CORNER = 1.0295630140987000315797369464196f; private static final float ROT_CENTER_TO_BOTTOM_CORNER = 0.7071067811865475244008443621048f; - public CardView gameCard; - public CardView updateCard; + private CardView gameCard; + private CardView updateCard; // for two faced cards - public CardView temporary; + private CardView temporary; - public double tappedAngle = 0; - public double flippedAngle = 0; + private double tappedAngle = 0; + private double flippedAngle = 0; private final List links = new ArrayList<>(); @@ -99,14 +99,14 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, public CardPanel(CardView newGameCard, UUID gameId, final boolean loadImage, ActionCallback callback, final boolean foil, Dimension dimension) { // Store away params - this.gameCard = newGameCard; + this.setGameCard(newGameCard); this.callback = callback; this.gameId = gameId; // Gather info about the card - this.isPermanent = this.gameCard instanceof PermanentView && !this.gameCard.inViewerOnly(); + this.isPermanent = this.getGameCard() instanceof PermanentView && !this.getGameCard().inViewerOnly(); if (isPermanent) { - this.hasSickness = ((PermanentView) this.gameCard).hasSummoningSickness(); + this.hasSickness = ((PermanentView) this.getGameCard()).hasSummoningSickness(); } // Set to requested size @@ -120,7 +120,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, add(buttonPanel); // Both card rendering implementations have a transform button - if (this.gameCard.canTransform()) { + if (this.getGameCard().canTransform()) { // Create the day night button dayNightButton = new JButton(""); dayNightButton.setSize(32, 32); @@ -142,12 +142,12 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, } // Both card rendering implementations have a view copy source button - if (this.gameCard instanceof PermanentView) { + if (this.getGameCard() instanceof PermanentView) { // Create the show source button showCopySourceButton = new JButton(""); showCopySourceButton.setSize(32, 32); showCopySourceButton.setToolTipText("This permanent is copying a target. To see original card, push this button or turn mouse wheel down while hovering with the mouse pointer over the permanent."); - showCopySourceButton.setVisible(((PermanentView) this.gameCard).isCopy()); + showCopySourceButton.setVisible(((PermanentView) this.getGameCard()).isCopy()); showCopySourceButton.setIcon(new ImageIcon(ImageManagerImpl.instance.getCopyInformIconImage())); showCopySourceButton.addActionListener(e -> { ActionCallback callback1 = Plugins.instance.getActionCallback(); @@ -174,8 +174,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, tooltipText.setText(getText(cardType, newGameCard)); // Animation setup - tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0; - flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0; + setTappedAngle(isTapped() ? CardPanel.TAPPED_ANGLE : 0); + setFlippedAngle(isFlipped() ? CardPanel.FLIPPED_ANGLE : 0); } @Override @@ -197,7 +197,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, public final void initialDraw() { // Kick off - if (gameCard.isTransformed()) { + if (getGameCard().isTransformed()) { // this calls updateImage toggleTransformed(); } else { @@ -325,10 +325,10 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, g2d.translate(edgeOffset * (1 - transformAngle), 0); g2d.scale(transformAngle, 1); } - if (tappedAngle + flippedAngle > 0) { + if (getTappedAngle() + getFlippedAngle() > 0) { g2d = (Graphics2D) g2d.create(); float edgeOffset = cardWidth / 2f; - double angle = tappedAngle + (Math.abs(flippedAngle - FLIPPED_ANGLE) < 0.001 ? 0 : flippedAngle); + double angle = getTappedAngle() + (Math.abs(getFlippedAngle() - FLIPPED_ANGLE) < 0.001 ? 0 : getFlippedAngle()); g2d.rotate(angle, cardXOffset + edgeOffset, cardYOffset + cardHeight - edgeOffset); } super.paint(g2d); @@ -347,7 +347,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public String toString() { - return gameCard.toString(); + return getGameCard().toString(); } @Override @@ -433,7 +433,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, } public final CardView getCard() { - return this.gameCard; + return this.getGameCard(); } @Override @@ -457,7 +457,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public final boolean isTapped() { if (isPermanent) { - return ((PermanentView) gameCard).isTapped(); + return ((PermanentView) getGameCard()).isTapped(); } return false; } @@ -465,7 +465,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public final boolean isFlipped() { if (isPermanent) { - return ((PermanentView) gameCard).isFlipped(); + return ((PermanentView) getGameCard()).isFlipped(); } return false; } @@ -473,7 +473,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public final boolean isTransformed() { if (isPermanent) { - if (gameCard.isTransformed()) { + if (getGameCard().isTransformed()) { return !this.transformed; } else { return this.transformed; @@ -503,7 +503,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, */ @Override public void update(CardView card) { - this.updateCard = card; + this.setUpdateCard(card); // Animation update if (isPermanent && (card instanceof PermanentView)) { @@ -527,11 +527,11 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, // Update art? boolean mustUpdateArt - = (!gameCard.getName().equals(card.getName())) - || (gameCard.isFaceDown() != card.isFaceDown()); + = (!getGameCard().getName().equals(card.getName())) + || (getGameCard().isFaceDown() != card.isFaceDown()); // Set the new card - this.gameCard = card; + this.setGameCard(card); // Update tooltip text String cardType = getType(card); @@ -580,7 +580,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public CardView getOriginal() { - return this.gameCard; + return this.getGameCard(); } @Override @@ -589,7 +589,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public void mouseEntered(MouseEvent e) { - if (gameCard.hideInfo()) { + if (getGameCard().hideInfo()) { return; } if (!tooltipShowing) { @@ -607,22 +607,22 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public void mouseDragged(MouseEvent e) { - data.component = this; + data.setComponent(this); callback.mouseDragged(e, data); } @Override public void mouseMoved(MouseEvent e) { - if (gameCard.hideInfo()) { + if (getGameCard().hideInfo()) { return; } - data.component = this; + data.setComponent(this); callback.mouseMoved(e, data); } @Override public void mouseExited(MouseEvent e) { - if (gameCard.hideInfo()) { + if (getGameCard().hideInfo()) { return; } @@ -630,9 +630,9 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, synchronized (this) { if (tooltipShowing) { tooltipShowing = false; - data.component = this; - data.card = this.gameCard; - data.popupText = tooltipText; + data.setComponent(this); + data.setCard(this.getGameCard()); + data.setPopupText(tooltipText); callback.mouseExited(e, data); } } @@ -641,9 +641,9 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public void mousePressed(MouseEvent e) { - data.component = this; - data.card = this.gameCard; - data.gameId = this.gameId; + data.setComponent(this); + data.setCard(this.getGameCard()); + data.setGameId(this.gameId); callback.mousePressed(e, data); } @@ -658,13 +658,13 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, * @return */ private TransferData getTransferDataForMouseEntered() { - data.component = this; - data.card = this.gameCard; - data.popupText = tooltipText; - data.gameId = this.gameId; - data.locationOnScreen = data.component.getLocationOnScreen(); // we need this for popup - data.popupOffsetX = isTapped() ? cardHeight + cardXOffset + POPUP_X_GAP : cardWidth + cardXOffset + POPUP_X_GAP; - data.popupOffsetY = 40; + data.setComponent(this); + data.setCard(this.getGameCard()); + data.setPopupText(tooltipText); + data.setGameId(this.gameId); + data.setLocationOnScreen(data.getComponent().getLocationOnScreen()); // we need this for popup + data.setPopupOffsetX(isTapped() ? cardHeight + cardXOffset + POPUP_X_GAP : cardWidth + cardXOffset + POPUP_X_GAP); + data.setPopupOffsetY(40); return data; } @@ -734,7 +734,7 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, @Override public PermanentView getOriginalPermanent() { if (isPermanent) { - return (PermanentView) this.gameCard; + return (PermanentView) this.getGameCard(); } throw new IllegalStateException("Is not permanent."); } @@ -757,13 +757,13 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, BufferedImage night = ImageManagerImpl.instance.getNightImage(); dayNightButton.setIcon(new ImageIcon(night)); } - if (this.gameCard.getSecondCardFace() == null) { + if (this.getGameCard().getSecondCardFace() == null) { LOGGER.error("no second side for card to transform!"); return; } if (!isPermanent) { // use only for custom transformation (when pressing day-night button) - this.temporary = this.gameCard; - update(this.gameCard.getSecondCardFace()); + this.setTemporary(this.getGameCard()); + update(this.getGameCard().getSecondCardFace()); } } else { if (dayNightButton != null) { // if transformbable card is copied, button can be null @@ -771,22 +771,22 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, dayNightButton.setIcon(new ImageIcon(day)); } if (!isPermanent) { // use only for custom transformation (when pressing day-night button) - update(this.temporary); - this.temporary = null; + update(this.getTemporary()); + this.setTemporary(null); } } - String temp = this.gameCard.getAlternateName(); - this.gameCard.setAlternateName(this.gameCard.getOriginalName()); - this.gameCard.setOriginalName(temp); + String temp = this.getGameCard().getAlternateName(); + this.getGameCard().setAlternateName(this.getGameCard().getOriginalName()); + this.getGameCard().setOriginalName(temp); updateArtImage(); } @Override public void mouseWheelMoved(MouseWheelEvent e) { - if (gameCard.hideInfo()) { + if (getGameCard().hideInfo()) { return; } - data.component = this; + data.setComponent(this); callback.mouseWheelMoved(e, data); } @@ -800,8 +800,8 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, // this update removes the isChoosable mark from targetCardsInLibrary // so only done for permanents because it's needed to redraw counters in different size, if window size was changed // no perfect solution yet (maybe also other not wanted effects for PermanentView objects) - if ((updateCard instanceof PermanentView)) { - update(updateCard); + if ((getUpdateCard() instanceof PermanentView)) { + update(getUpdateCard()); } } @@ -836,4 +836,43 @@ public abstract class CardPanel extends MagePermanent implements MouseListener, this.popupMenu = popupMenu; } + public CardView getGameCard() { + return gameCard; + } + + public void setGameCard(CardView gameCard) { + this.gameCard = gameCard; + } + + public CardView getUpdateCard() { + return updateCard; + } + + public void setUpdateCard(CardView updateCard) { + this.updateCard = updateCard; + } + + public CardView getTemporary() { + return temporary; + } + + public void setTemporary(CardView temporary) { + this.temporary = temporary; + } + + public double getTappedAngle() { + return tappedAngle; + } + + public void setTappedAngle(double tappedAngle) { + this.tappedAngle = tappedAngle; + } + + public double getFlippedAngle() { + return flippedAngle; + } + + public void setFlippedAngle(double flippedAngle) { + this.flippedAngle = flippedAngle; + } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java index d7812ba2aa..a237318a17 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelComponentImpl.java @@ -1,11 +1,11 @@ package org.mage.card.arcane; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; import mage.cards.action.ActionCallback; +import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; import mage.client.util.ImageCaches; import mage.client.util.ImageHelper; +import mage.client.util.SoftValuesLoadingCache; import mage.components.ImagePanel; import mage.components.ImagePanelStyle; import mage.constants.AbilityType; @@ -17,12 +17,10 @@ import org.apache.log4j.Logger; import org.jdesktop.swingx.graphics.GraphicsUtilities; import org.mage.plugins.card.images.ImageCache; import org.mage.plugins.card.utils.impl.ImageManagerImpl; -import mage.client.constants.Constants; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Map; import java.util.StringTokenizer; import java.util.UUID; @@ -52,12 +50,12 @@ public class CardPanelComponentImpl extends CardPanel { private static final int CARD_MAX_SIZE_FOR_ICONS = 200; public final ScaledImagePanel imagePanel; - public ImagePanel overlayPanel; + private ImagePanel overlayPanel; - public JPanel iconPanel; + private JPanel iconPanel; private JButton typeButton; - public JPanel counterPanel; + private JPanel counterPanel; private JLabel loyaltyCounterLabel; private JLabel plusCounterLabel; private JLabel otherCounterLabel; @@ -78,7 +76,31 @@ public class CardPanelComponentImpl extends CardPanel { private boolean displayTitleAnyway; private boolean displayFullImagePath; - private final static Map IMAGE_CACHE; + private final static SoftValuesLoadingCache IMAGE_CACHE; + + public ImagePanel getOverlayPanel() { + return overlayPanel; + } + + public void setOverlayPanel(ImagePanel overlayPanel) { + this.overlayPanel = overlayPanel; + } + + public JPanel getIconPanel() { + return iconPanel; + } + + public void setIconPanel(JPanel iconPanel) { + this.iconPanel = iconPanel; + } + + public JPanel getCounterPanel() { + return counterPanel; + } + + public void setCounterPanel(JPanel counterPanel) { + this.counterPanel = counterPanel; + } static class Key { @@ -93,8 +115,9 @@ public class CardPanelComponentImpl extends CardPanel { final boolean isChoosable; final boolean isPlayable; final boolean canAttack; + final boolean canBlock; - public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack) { + public Key(int width, int height, int cardWidth, int cardHeight, int cardXOffset, int cardYOffset, boolean hasImage, boolean isSelected, boolean isChoosable, boolean isPlayable, boolean canAttack, boolean canBlock) { this.width = width; this.height = height; this.cardWidth = cardWidth; @@ -106,6 +129,7 @@ public class CardPanelComponentImpl extends CardPanel { this.isChoosable = isChoosable; this.isPlayable = isPlayable; this.canAttack = canAttack; + this.canBlock = canBlock; } @Override @@ -122,6 +146,7 @@ public class CardPanelComponentImpl extends CardPanel { hash = 19 * hash + (this.isChoosable ? 1 : 0); hash = 19 * hash + (this.isPlayable ? 1 : 0); hash = 19 * hash + (this.canAttack ? 1 : 0); + hash = 19 * hash + (this.canBlock ? 1 : 0); return hash; } @@ -170,28 +195,28 @@ public class CardPanelComponentImpl extends CardPanel { if (this.canAttack != other.canAttack) { return false; } - return true; + return this.canBlock == other.canBlock; } } static { - IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function) key -> createImage(key))); + IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(CardPanelComponentImpl::createImage)); } - static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage){ + static private boolean canShowCardIcons(int cardFullWidth, boolean cardHasImage) { // cards without images show icons and text always // TODO: apply "card names on card" setting to icon too? // TODO: fix card min-max size to hide (compare to settings size, not direct 60 and 200) return ((cardFullWidth > 60) && (cardFullWidth < 200)) || (!cardHasImage); } - private static class CardSizes{ + private static class CardSizes { Rectangle rectFull; Rectangle rectSelection; Rectangle rectBorder; Rectangle rectCard; - CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight){ + CardSizes(int offsetX, int offsetY, int fullWidth, int fullHeight) { int realBorderSizeX = Math.round(fullWidth * BLACK_BORDER_SIZE); int realBorderSizeY = Math.round(fullWidth * BLACK_BORDER_SIZE); @@ -213,27 +238,27 @@ public class CardPanelComponentImpl extends CardPanel { // Counter panel if (!newGameCard.isAbility()) { // panel to show counters on the card - counterPanel = new JPanel(); - counterPanel.setLayout(null); - counterPanel.setOpaque(false); - add(counterPanel); + setCounterPanel(new JPanel()); + getCounterPanel().setLayout(null); + getCounterPanel().setOpaque(false); + add(getCounterPanel()); plusCounterLabel = new JLabel(""); plusCounterLabel.setToolTipText("+1/+1"); - counterPanel.add(plusCounterLabel); + getCounterPanel().add(plusCounterLabel); minusCounterLabel = new JLabel(""); minusCounterLabel.setToolTipText("-1/-1"); - counterPanel.add(minusCounterLabel); + getCounterPanel().add(minusCounterLabel); loyaltyCounterLabel = new JLabel(""); loyaltyCounterLabel.setToolTipText("loyalty"); - counterPanel.add(loyaltyCounterLabel); + getCounterPanel().add(loyaltyCounterLabel); otherCounterLabel = new JLabel(""); - counterPanel.add(otherCounterLabel); + getCounterPanel().add(otherCounterLabel); - counterPanel.setVisible(false); + getCounterPanel().setVisible(false); } // Ability icon @@ -246,7 +271,7 @@ public class CardPanelComponentImpl extends CardPanel { } // Token icon - if (this.gameCard.isToken()) { + if (this.getGameCard().isToken()) { setTypeIcon(ImageManagerImpl.instance.getTokenIconImage(), "Token Permanent"); } @@ -255,7 +280,7 @@ public class CardPanelComponentImpl extends CardPanel { // Title Text titleText = new GlowText(); - setText(gameCard); + setText(getGameCard()); // int fontSize = (int) cardHeight / 11; // titleText.setFont(getFont().deriveFont(Font.BOLD, fontSize)); titleText.setForeground(Color.white); @@ -271,10 +296,10 @@ public class CardPanelComponentImpl extends CardPanel { // PT Text ptText = new GlowText(); - if (gameCard.isCreature()) { - ptText.setText(gameCard.getPower() + '/' + gameCard.getToughness()); - } else if (gameCard.isPlanesWalker()) { - ptText.setText(gameCard.getLoyalty()); + if (getGameCard().isCreature()) { + ptText.setText(getGameCard().getPower() + '/' + getGameCard().getToughness()); + } else if (getGameCard().isPlanesWalker()) { + ptText.setText(getGameCard().getLoyalty()); } // ptText.setFont(getFont().deriveFont(Font.BOLD, fontSize)); ptText.setForeground(Color.white); @@ -283,9 +308,9 @@ public class CardPanelComponentImpl extends CardPanel { // Sickness overlay BufferedImage sickness = ImageManagerImpl.instance.getSicknessImage(); - overlayPanel = new ImagePanel(sickness, ImagePanelStyle.SCALED); - overlayPanel.setOpaque(false); - add(overlayPanel); + setOverlayPanel(new ImagePanel(sickness, ImagePanelStyle.SCALED)); + getOverlayPanel().setOpaque(false); + add(getOverlayPanel()); // Imagel panel imagePanel = new ScaledImagePanel(); @@ -301,27 +326,27 @@ public class CardPanelComponentImpl extends CardPanel { } private void setTypeIcon(BufferedImage bufferedImage, String toolTipText) { - iconPanel = new JPanel(); - iconPanel.setLayout(null); - iconPanel.setOpaque(false); - add(iconPanel); + setIconPanel(new JPanel()); + getIconPanel().setLayout(null); + getIconPanel().setOpaque(false); + add(getIconPanel()); typeButton = new JButton(""); typeButton.setLocation(2, 2); typeButton.setSize(25, 25); - iconPanel.setVisible(true); + getIconPanel().setVisible(true); typeButton.setIcon(new ImageIcon(bufferedImage)); if (toolTipText != null) { typeButton.setToolTipText(toolTipText); } - iconPanel.add(typeButton); + getIconPanel().add(typeButton); } @Override public void cleanUp() { super.cleanUp(); - this.counterPanel = null; + this.setCounterPanel(null); } private void setText(CardView card) { @@ -380,9 +405,10 @@ public class CardPanelComponentImpl extends CardPanel { } g2d.drawImage( - IMAGE_CACHE.get( + IMAGE_CACHE.getOrThrow( new Key(getWidth(), getHeight(), getCardWidth(), getCardHeight(), getCardXOffset(), getCardYOffset(), - hasImage, isSelected(), isChoosable(), gameCard.isPlayable(), gameCard.isCanAttack())), + hasImage, isSelected(), isChoosable(), getGameCard().isPlayable(), getGameCard().isCanAttack(), + getGameCard().isCanBlock())), 0, 0, null); g2d.dispose(); } @@ -418,6 +444,12 @@ public class CardPanelComponentImpl extends CardPanel { g2d.fillRoundRect(sizes.rectSelection.x, sizes.rectSelection.y, sizes.rectSelection.width, sizes.rectSelection.height, cornerSizeSelection, cornerSizeSelection); } + // draw attack or block border (?inner part of selection?) + if (key.canAttack || key.canBlock) { + g2d.setColor(new Color(255, 50, 50, 230)); + g2d.fillRoundRect(sizes.rectSelection.x + 1, sizes.rectSelection.y + 1, sizes.rectSelection.width - 2, sizes.rectSelection.height - 2, cornerSizeSelection, cornerSizeSelection); + } + // draw empty card with border if (!key.hasImage) { // gray 1 px border @@ -428,12 +460,6 @@ public class CardPanelComponentImpl extends CardPanel { g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder); } - // draw attack border (inner part of selection) - if (key.canAttack) { - g2d.setColor(new Color(0, 0, 255, 230)); - g2d.fillRoundRect(sizes.rectBorder.x + 1, sizes.rectBorder.y + 1, sizes.rectBorder.width - 2, sizes.rectBorder.height - 2, cornerSizeBorder, cornerSizeBorder); - } - // draw real card by component (see imagePanel and other layout's items) //TODO:uncomment @@ -477,7 +503,7 @@ public class CardPanelComponentImpl extends CardPanel { int symbolMarginX = 2; // 2 px between icons - String manaCost = ManaSymbols.getStringManaCost(gameCard.getManaCost()); + String manaCost = ManaSymbols.getStringManaCost(getGameCard().getManaCost()); int manaWidth = getManaWidth(manaCost, symbolMarginX); // right top corner with margin (sizes from any sample card, length from black border to mana icon) @@ -497,7 +523,7 @@ public class CardPanelComponentImpl extends CardPanel { StringTokenizer tok = new StringTokenizer(manaCost, " "); while (tok.hasMoreTokens()) { tok.nextToken(); - if(width != 0) { + if (width != 0) { width += symbolMarginX; } width += getSymbolWidth(); @@ -521,32 +547,32 @@ public class CardPanelComponentImpl extends CardPanel { imagePanel.setLocation(realCardSize.x, realCardSize.y); imagePanel.setSize(realCardSize.width, realCardSize.height); - if (hasSickness() && gameCard.isCreature() && isPermanent()) { - overlayPanel.setLocation(realCardSize.x, realCardSize.y); - overlayPanel.setSize(realCardSize.width, realCardSize.height); + if (hasSickness() && getGameCard().isCreature() && isPermanent()) { + getOverlayPanel().setLocation(realCardSize.x, realCardSize.y); + getOverlayPanel().setSize(realCardSize.width, realCardSize.height); } else { - overlayPanel.setVisible(false); + getOverlayPanel().setVisible(false); } - if (iconPanel != null) { - iconPanel.setLocation(realCardSize.x, realCardSize.y); - iconPanel.setSize(realCardSize.width, realCardSize.height); + if (getIconPanel() != null) { + getIconPanel().setLocation(realCardSize.x, realCardSize.y); + getIconPanel().setSize(realCardSize.width, realCardSize.height); } - if (counterPanel != null) { - counterPanel.setLocation(realCardSize.x, realCardSize.y); - counterPanel.setSize(realCardSize.width, realCardSize.height); + if (getCounterPanel() != null) { + getCounterPanel().setLocation(realCardSize.x, realCardSize.y); + getCounterPanel().setSize(realCardSize.width, realCardSize.height); int size = cardWidth > WIDTH_LIMIT ? 40 : 20; - minusCounterLabel.setLocation(counterPanel.getWidth() - size, counterPanel.getHeight() - size * 2); + minusCounterLabel.setLocation(getCounterPanel().getWidth() - size, getCounterPanel().getHeight() - size * 2); minusCounterLabel.setSize(size, size); - plusCounterLabel.setLocation(5, counterPanel.getHeight() - size * 2); + plusCounterLabel.setLocation(5, getCounterPanel().getHeight() - size * 2); plusCounterLabel.setSize(size, size); - loyaltyCounterLabel.setLocation(counterPanel.getWidth() - size, counterPanel.getHeight() - size); + loyaltyCounterLabel.setLocation(getCounterPanel().getWidth() - size, getCounterPanel().getHeight() - size); loyaltyCounterLabel.setSize(size, size); - otherCounterLabel.setLocation(5, counterPanel.getHeight() - size); + otherCounterLabel.setLocation(5, getCounterPanel().getHeight() - size); otherCounterLabel.setSize(size, size); } @@ -601,7 +627,7 @@ public class CardPanelComponentImpl extends CardPanel { @Override public String toString() { - return gameCard.toString(); + return getGameCard().toString(); } @Override @@ -635,8 +661,8 @@ public class CardPanelComponentImpl extends CardPanel { @Override public void updateArtImage() { - tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0; - flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0; + setTappedAngle(isTapped() ? CardPanel.TAPPED_ANGLE : 0); + setFlippedAngle(isFlipped() ? CardPanel.FLIPPED_ANGLE : 0); //final CardView gameCard = this.gameCard; final int stamp = ++updateArtImageStamp; @@ -644,20 +670,20 @@ public class CardPanelComponentImpl extends CardPanel { Util.threadPool.submit(() -> { try { final BufferedImage srcImage; - if (gameCard.isFaceDown()) { + if (getGameCard().isFaceDown()) { srcImage = getFaceDownImage(); } else if (getCardWidth() > Constants.THUMBNAIL_SIZE_FULL.width) { - srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight()); + srcImage = ImageCache.getImage(getGameCard(), getCardWidth(), getCardHeight()); } else { - srcImage = ImageCache.getThumbnail(gameCard); + srcImage = ImageCache.getThumbnail(getGameCard()); } if (srcImage == null) { - setFullPath(ImageCache.getFilePath(gameCard, getCardWidth())); + setFullPath(ImageCache.getFilePath(getGameCard(), getCardWidth())); } UI.invokeLater(() -> { if (stamp == updateArtImageStamp) { hasImage = srcImage != null; - setText(gameCard); + setText(getGameCard()); setImage(srcImage); } }); @@ -671,12 +697,12 @@ public class CardPanelComponentImpl extends CardPanel { private BufferedImage getFaceDownImage() { if (isPermanent()) { - if (((PermanentView) gameCard).isMorphed()) { + if (((PermanentView) getGameCard()).isMorphed()) { return ImageCache.getMorphImage(); } else { return ImageCache.getManifestImage(); } - } else if (this.gameCard instanceof StackAbilityView) { + } else if (this.getGameCard() instanceof StackAbilityView) { return ImageCache.getMorphImage(); } else { return ImageCache.getCardbackImage(); @@ -686,7 +712,7 @@ public class CardPanelComponentImpl extends CardPanel { @Override public void showCardTitle() { displayTitleAnyway = true; - setText(gameCard); + setText(getGameCard()); } @Override @@ -708,13 +734,13 @@ public class CardPanelComponentImpl extends CardPanel { // Summoning Sickness overlay if (hasSickness() && card.isCreature() && isPermanent()) { - overlayPanel.setVisible(true); + getOverlayPanel().setVisible(true); } else { - overlayPanel.setVisible(false); + getOverlayPanel().setVisible(false); } // Update counters panel - if (counterPanel != null) { + if (getCounterPanel() != null) { updateCounters(card); } @@ -773,13 +799,13 @@ public class CardPanelComponentImpl extends CardPanel { } } - counterPanel.setVisible(true); + getCounterPanel().setVisible(true); } else { plusCounterLabel.setVisible(false); minusCounterLabel.setVisible(false); loyaltyCounterLabel.setVisible(false); otherCounterLabel.setVisible(false); - counterPanel.setVisible(false); + getCounterPanel().setVisible(false); } } @@ -805,10 +831,10 @@ public class CardPanelComponentImpl extends CardPanel { @Override public Image getImage() { if (this.hasImage) { - if (gameCard.isFaceDown()) { + if (getGameCard().isFaceDown()) { return getFaceDownImage(); } else { - return ImageCache.getImageOriginal(gameCard); + return ImageCache.getImageOriginal(getGameCard()); } } return null; diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java index 10182f6654..cf62e7cb43 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardPanelRenderImpl.java @@ -1,7 +1,9 @@ package org.mage.card.arcane; -import com.google.common.collect.MapMaker; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; import mage.cards.action.ActionCallback; +import mage.client.constants.Constants; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; @@ -12,12 +14,11 @@ import mage.view.StackAbilityView; import org.apache.log4j.Logger; import org.jdesktop.swingx.graphics.GraphicsUtilities; import org.mage.plugins.card.images.ImageCache; -import mage.client.constants.Constants; import java.awt.*; import java.awt.image.BufferedImage; -import java.util.Map; import java.util.UUID; +import java.util.concurrent.ExecutionException; public class CardPanelRenderImpl extends CardPanel { @@ -104,9 +105,7 @@ public class CardPanelRenderImpl extends CardPanel { // are the same for a and b return false; } - if (aa.getDamage() != bb.getDamage()) { - return false; - } + return aa.getDamage() == bb.getDamage(); } return true; } @@ -140,6 +139,7 @@ public class CardPanelRenderImpl extends CardPanel { sb.append((char) (isChoosable ? 1 : 0)); sb.append((char) (this.view.isPlayable() ? 1 : 0)); sb.append((char) (this.view.isCanAttack() ? 1 : 0)); + sb.append((char) (this.view.isCanBlock() ? 1 : 0)); sb.append((char) (this.view.isFaceDown() ? 1 : 0)); sb.append((char) this.view.getFrameStyle().ordinal()); if (this.view instanceof PermanentView) { @@ -215,7 +215,7 @@ public class CardPanelRenderImpl extends CardPanel { } // Map of generated images - private final static Map IMAGE_CACHE = new MapMaker().softValues().makeMap(); + private final static Cache IMAGE_CACHE = CacheBuilder.newBuilder().softValues().build(); // The art image for the card, loaded in from the disk private BufferedImage artImage; @@ -236,7 +236,7 @@ public class CardPanelRenderImpl extends CardPanel { super(newGameCard, gameId, loadImage, callback, foil, dimension); // Renderer - cardRenderer = cardRendererFactory.create(gameCard, isTransformed()); + cardRenderer = cardRendererFactory.create(getGameCard(), isTransformed()); // Draw the parts initialDraw(); @@ -262,10 +262,14 @@ public class CardPanelRenderImpl extends CardPanel { if (cardImage == null) { // Try to get card image from cache based on our card characteristics ImageKey key - = new ImageKey(gameCard, artImage, - getCardWidth(), getCardHeight(), - isChoosable(), isSelected()); - cardImage = IMAGE_CACHE.computeIfAbsent(key, k -> renderCard()); + = new ImageKey(getGameCard(), artImage, + getCardWidth(), getCardHeight(), + isChoosable(), isSelected()); + try { + cardImage = IMAGE_CACHE.get(key, this::renderCard); + } catch (ExecutionException e) { + throw new RuntimeException(e); + } // No cached copy exists? Render one and cache it } @@ -317,8 +321,8 @@ public class CardPanelRenderImpl extends CardPanel { cardRenderer.setFaceArtImage(null); // Stop animation - tappedAngle = isTapped() ? CardPanel.TAPPED_ANGLE : 0; - flippedAngle = isFlipped() ? CardPanel.FLIPPED_ANGLE : 0; + setTappedAngle(isTapped() ? CardPanel.TAPPED_ANGLE : 0); + setFlippedAngle(isFlipped() ? CardPanel.FLIPPED_ANGLE : 0); // Schedule a repaint repaint(); @@ -333,16 +337,16 @@ public class CardPanelRenderImpl extends CardPanel { try { final BufferedImage srcImage; final BufferedImage faceArtSrcImage; - if (gameCard.isFaceDown()) { + if (getGameCard().isFaceDown()) { // Nothing to do srcImage = null; faceArtSrcImage = null; } else if (getCardWidth() > Constants.THUMBNAIL_SIZE_FULL.width) { - srcImage = ImageCache.getImage(gameCard, getCardWidth(), getCardHeight()); - faceArtSrcImage = ImageCache.getFaceImage(gameCard, getCardWidth(), getCardHeight()); + srcImage = ImageCache.getImage(getGameCard(), getCardWidth(), getCardHeight()); + faceArtSrcImage = ImageCache.getFaceImage(getGameCard(), getCardWidth(), getCardHeight()); } else { - srcImage = ImageCache.getThumbnail(gameCard); - faceArtSrcImage = ImageCache.getFaceImage(gameCard, getCardWidth(), getCardHeight()); + srcImage = ImageCache.getThumbnail(getGameCard()); + faceArtSrcImage = ImageCache.getFaceImage(getGameCard(), getCardWidth(), getCardHeight()); } UI.invokeLater(() -> { @@ -375,7 +379,7 @@ public class CardPanelRenderImpl extends CardPanel { // Update renderer cardImage = null; - cardRenderer = cardRendererFactory.create(gameCard, isTransformed()); + cardRenderer = cardRendererFactory.create(getGameCard(), isTransformed()); cardRenderer.setArtImage(artImage); cardRenderer.setFaceArtImage(faceArtImage); @@ -398,12 +402,12 @@ public class CardPanelRenderImpl extends CardPanel { private BufferedImage getFaceDownImage() { if (isPermanent()) { - if (((PermanentView) gameCard).isMorphed()) { + if (((PermanentView) getGameCard()).isMorphed()) { return ImageCache.getMorphImage(); } else { return ImageCache.getManifestImage(); } - } else if (this.gameCard instanceof StackAbilityView) { + } else if (this.getGameCard() instanceof StackAbilityView) { return ImageCache.getMorphImage(); } else { return ImageCache.getCardbackImage(); @@ -433,10 +437,10 @@ public class CardPanelRenderImpl extends CardPanel { @Override public Image getImage() { if (artImage != null) { - if (gameCard.isFaceDown()) { + if (getGameCard().isFaceDown()) { return getFaceDownImage(); } else { - return ImageCache.getImageOriginal(gameCard); + return ImageCache.getImageOriginal(getGameCard()); } } return null; diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java index a042e9665c..eed6403067 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRenderer.java @@ -5,6 +5,7 @@ */ package org.mage.card.arcane; +import mage.abilities.hint.HintUtils; import mage.cards.ArtRect; import mage.client.dialog.PreferencesDialog; import mage.constants.AbilityType; @@ -137,12 +138,18 @@ public abstract class CardRenderer { } protected void parseRules(List stringRules, ArrayList keywords, ArrayList rules) { - // Translate the textbox text + // Translate the textbox text and remove card hints for (String rule : stringRules) { + // remove all card hints + if (rule.equals(HintUtils.HINT_START_MARK)) { + break; + } + // Kill reminder text if (PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_RENDERING_REMINDER_TEXT, "false").equals("false")) { rule = CardRendererUtils.killReminderText(rule).trim(); } + if (!rule.isEmpty()) { TextboxRule tbRule = TextboxRuleParser.parse(cardView, rule); if (tbRule.type == TextboxRuleType.SIMPLE_KEYWORD) { @@ -388,7 +395,7 @@ public abstract class CardRenderer { // Return the width of the drawn symbol protected int drawExpansionSymbol(Graphics2D g, int x, int y, int w, int h) { // Draw the expansion symbol - Image setSymbol = ManaSymbols.getSetSymbolImage(cardView.getExpansionSetCode(), cardView.getRarity().getCode()); + Image setSymbol = ManaSymbols.getSetSymbolImage(cardView.getExpansionSetCode(), cardView.getRarity()); int setSymbolWidth; if (setSymbol == null) { // Don't draw anything when we don't have a set symbol diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java index 3702f176cb..f32c08e972 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/CardRendererUtils.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package org.mage.card.arcane; import java.awt.*; @@ -63,26 +58,26 @@ public final class CardRendererUtils { int plus_b = (int) ((255 - b) / 2); return new Color(r + plus_r, - g + plus_g, - b + plus_b, - alpha); + g + plus_g, + b + plus_b, + alpha); } - + public static Color abitdarker(Color c) { int r = c.getRed(); int g = c.getGreen(); int b = c.getBlue(); int alpha = c.getAlpha(); - int plus_r = (int) (Math.min (255 - r, r) / 2); - int plus_g = (int) (Math.min (255 - g, g) / 2); - int plus_b = (int) (Math.min (255 - b, b) / 2); + int plus_r = (int) (Math.min(255 - r, r) / 2); + int plus_g = (int) (Math.min(255 - g, g) / 2); + int plus_b = (int) (Math.min(255 - b, b) / 2); return new Color(r - plus_r, - g - plus_g, - b - plus_b, - alpha); - } + g - plus_g, + b - plus_b, + alpha); + } // Draw a rounded box with a 2-pixel border // Used on various card parts. @@ -192,4 +187,12 @@ public final class CardRendererUtils { .replaceAll("", "") .replaceAll("", ""); } + + public static Color copyColor(Color color) { + if (color != null) { + return new Color(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + } else { + return null; + } + } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/GlowText.java b/Mage.Client/src/main/java/org/mage/card/arcane/GlowText.java index bc7ac1617d..8d95a11ac0 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/GlowText.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/GlowText.java @@ -1,7 +1,5 @@ package org.mage.card.arcane; -import com.google.common.base.Function; -import com.google.common.collect.MapMaker; import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.font.LineBreakMeasurer; @@ -15,10 +13,18 @@ import java.text.BreakIterator; import java.util.Locale; import java.util.Map; import java.util.Objects; + import javax.swing.*; -import mage.client.util.ImageCaches; + import org.jdesktop.swingx.graphics.GraphicsUtilities; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +import mage.client.util.ImageCaches; +import mage.client.util.SoftValuesLoadingCache; + public class GlowText extends JLabel { private static final long serialVersionUID = 1827677946939348001L; @@ -28,9 +34,9 @@ public class GlowText extends JLabel { private Color glowColor; private boolean wrap; private int lineCount = 0; - private final static Map IMAGE_CACHE; + private static final SoftValuesLoadingCache IMAGE_CACHE; - private final static class Key { + private static final class Key { final int width; final int height; @@ -125,7 +131,7 @@ public class GlowText extends JLabel { } static { - IMAGE_CACHE = ImageCaches.register(new MapMaker().softValues().makeComputingMap((Function) GlowText::createImage)); + IMAGE_CACHE = ImageCaches.register(SoftValuesLoadingCache.from(GlowText::createGlowImage)); } public void setGlow(Color glowColor, int size, float intensity) { @@ -152,10 +158,10 @@ public class GlowText extends JLabel { return; } - g.drawImage(IMAGE_CACHE.get(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap)), 0, 0, null); + g.drawImage(IMAGE_CACHE.getOrThrow(new Key(getWidth(), getHeight(), getText(), getFont(), getForeground(), glowSize, glowIntensity, glowColor, wrap)), 0, 0, null); } - private static BufferedImage createImage(Key key) { + private static BufferedImage createGlowImage(Key key) { Dimension size = new Dimension(key.width, key.height); BufferedImage image = GraphicsUtilities.createCompatibleTranslucentImage(size.width, size.height); Graphics2D g2d = image.createGraphics(); diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java index 1f972175eb..75d361cbf7 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbols.java @@ -1,43 +1,6 @@ package org.mage.card.arcane; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Toolkit; -import java.awt.image.BufferedImage; -import java.awt.image.FilteredImageSource; -import java.awt.image.ImageProducer; -import java.awt.image.RGBImageFilter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.FileSystems; -import java.nio.file.FileVisitResult; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.nio.file.Paths; -import java.nio.file.SimpleFileVisitor; -import java.nio.file.StandardCopyOption; -import java.nio.file.attribute.BasicFileAttributes; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.regex.Pattern; -import java.util.stream.IntStream; -import javax.imageio.ImageIO; -import javax.swing.*; - +import mage.abilities.hint.HintUtils; import mage.cards.repository.ExpansionRepository; import mage.client.MageFrame; import mage.client.constants.Constants; @@ -46,8 +9,10 @@ import mage.client.constants.Constants.ResourceSymbolSize; import mage.client.util.GUISizeHelper; import mage.client.util.ImageHelper; import mage.client.util.gui.BufferedImageBuilder; +import mage.client.util.gui.GuiDisplayUtil; +import mage.constants.Rarity; import mage.utils.StreamUtils; -import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.anim.dom.SVGDOMImplementation; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; @@ -57,6 +22,26 @@ import org.apache.batik.util.SVGConstants; import org.apache.log4j.Logger; import org.mage.plugins.card.utils.CardImageUtils; +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageProducer; +import java.awt.image.RGBImageFilter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Pattern; +import java.util.stream.IntStream; + import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; public final class ManaSymbols { @@ -64,10 +49,10 @@ public final class ManaSymbols { private static final Logger LOGGER = Logger.getLogger(ManaSymbols.class); private static final Map> manaImages = new HashMap<>(); - private static final Map> setImages = new ConcurrentHashMap<>(); + private static final Map> setImages = new ConcurrentHashMap<>(); - private static final HashSet onlyMythics = new HashSet<>(); - private static final HashSet withoutSymbols = new HashSet<>(); + private static final Set onlyMythics = new HashSet<>(); + private static final Set withoutSymbols = new HashSet<>(); static { onlyMythics.add("DRB"); @@ -86,11 +71,13 @@ public final class ManaSymbols { private static final Map setImagesExist = new HashMap<>(); private static final Pattern REPLACE_SYMBOLS_PATTERN = Pattern.compile("\\{([^}/]*)/?([^}]*)\\}"); - private static final String[] symbols = new String[]{"0", "1", "10", "11", "12", "15", "16", "2", "3", "4", "5", "6", "7", "8", "9", + private static final String[] symbols = new String[]{ + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "B", "BG", "BR", "BP", "2B", "G", "GU", "GW", "GP", "2G", "R", "RG", "RW", "RP", "2R", - "S", "T", + "S", "T", "Q", "U", "UB", "UR", "UP", "2U", "W", "WB", "WU", "WP", "2W", "X", "C", "E"}; @@ -186,19 +173,19 @@ public final class ManaSymbols { continue; } - String[] codes; + Set codes; if (onlyMythics.contains(set)) { - codes = new String[]{"M"}; + codes = EnumSet.of(Rarity.MYTHIC); } else { - codes = new String[]{"C", "U", "R", "M"}; + codes = EnumSet.of(Rarity.COMMON, Rarity.UNCOMMON, Rarity.RARE, Rarity.MYTHIC); } - Map rarityImages = new HashMap<>(); + Map rarityImages = new EnumMap<>(Rarity.class); setImages.put(set, rarityImages); // load medium size - for (String rarityCode : codes) { - File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + rarityCode + ".jpg"); + for (Rarity rarityCode : codes) { + File file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + rarityCode.getCode() + ".jpg"); try { Image image = UI.getImageIcon(file.getAbsolutePath()).getImage(); int width = image.getWidth(null); @@ -223,7 +210,7 @@ public final class ManaSymbols { file.mkdirs(); } String pathRoot = getResourceSetsPath(ResourceSetSize.SMALL) + set; - for (String code : codes) { + for (Rarity code : codes) { File newFile = new File(pathRoot + '-' + code + ".png"); if (!(MageFrame.isSkipSmallSymbolGenerationForExisting() && newFile.exists())) {// skip if option enabled and file already exists file = new File(getResourceSetsPath(ResourceSetSize.MEDIUM) + set + '-' + code + ".png"); @@ -784,7 +771,18 @@ public final class ManaSymbols { "$1$2"; + Integer width = setImagesExist.get(set).width * factor; + Integer height = setImagesExist.get(set).height * factor; + return "" + rarity + ""; } else { return set; } } public static Image getSetSymbolImage(String set) { - return getSetSymbolImage(set, "C"); + return getSetSymbolImage(set, Rarity.COMMON); } - public static Image getSetSymbolImage(String set, String rarity) { - Map rarityImages = setImages.get(set); + public static Image getSetSymbolImage(String set, Rarity rarity) { + Map rarityImages = setImages.get(set); if (rarityImages != null) { return rarityImages.get(rarity); } else { diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java index 46a0e3f1c2..bd9731ec6a 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ManaSymbolsCellRenderer.java @@ -9,10 +9,13 @@ import java.awt.*; import java.awt.image.BufferedImage; import java.util.StringTokenizer; +/** + * @author JayDi85 + */ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer { // base panel to render - private JPanel manaPanel = new JPanel(); + private JPanel renderPanel = new JPanel(); @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, @@ -20,47 +23,47 @@ public final class ManaSymbolsCellRenderer extends DefaultTableCellRenderer { // get table text cell settings DefaultTableCellRenderer baseRenderer = (DefaultTableCellRenderer) table.getDefaultRenderer(String.class); - JLabel baseLabel = (JLabel)baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + JLabel baseComp = (JLabel) baseRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // apply settings to mana panel from parent - manaPanel.setOpaque(baseLabel.isOpaque()); - manaPanel.setForeground(baseLabel.getForeground()); - manaPanel.setBackground(baseLabel.getBackground()); + renderPanel.setOpaque(baseComp.isOpaque()); + renderPanel.setForeground(CardRendererUtils.copyColor(baseComp.getForeground())); + renderPanel.setBackground(CardRendererUtils.copyColor(baseComp.getBackground())); + renderPanel.setBorder(baseComp.getBorder()); // icons size with margin int symbolWidth = GUISizeHelper.symbolTableSize; int symbolHorizontalMargin = 2; // create each mana symbol as child label - String manaCost = (String)value; - manaPanel.removeAll(); - manaPanel.setLayout(new BoxLayout(manaPanel, BoxLayout.X_AXIS)); - if(manaCost != null){ + String manaCost = (String) value; + renderPanel.removeAll(); + renderPanel.setLayout(new BoxLayout(renderPanel, BoxLayout.X_AXIS)); + if (manaCost != null) { StringTokenizer tok = new StringTokenizer(manaCost, " "); while (tok.hasMoreTokens()) { String symbol = tok.nextToken(); JLabel symbolLabel = new JLabel(); //symbolLabel.setBorder(new LineBorder(new Color(150, 150, 150))); // debug - symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin,0, 0)); + symbolLabel.setBorder(new EmptyBorder(0, symbolHorizontalMargin, 0, 0)); BufferedImage image = ManaSymbols.getSizedManaSymbol(symbol, symbolWidth); - if (image != null){ + if (image != null) { // icon symbolLabel.setIcon(new ImageIcon(image)); - }else - { + } else { // text symbolLabel.setText("{" + symbol + "}"); - symbolLabel.setOpaque(baseLabel.isOpaque()); - symbolLabel.setForeground(baseLabel.getForeground()); - symbolLabel.setBackground(baseLabel.getBackground()); + symbolLabel.setOpaque(baseComp.isOpaque()); + symbolLabel.setForeground(baseComp.getForeground()); + symbolLabel.setBackground(baseComp.getBackground()); } - manaPanel.add(symbolLabel); + renderPanel.add(symbolLabel); } } - return manaPanel; + return renderPanel; } } diff --git a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java index 4aea652c0b..fbdac1c3fa 100644 --- a/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java +++ b/Mage.Client/src/main/java/org/mage/card/arcane/ModernCardRenderer.java @@ -5,24 +5,6 @@ */ package org.mage.card.arcane; -import java.awt.*; -import java.awt.font.*; -import java.awt.geom.Arc2D; -import java.awt.geom.Area; -import java.awt.geom.Path2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.text.CharacterIterator; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import javax.swing.*; import mage.ObjectColor; import mage.cards.ArtRect; import mage.cards.FrameStyle; @@ -34,6 +16,22 @@ import mage.util.SubTypeList; import mage.view.CardView; import mage.view.PermanentView; import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.*; +import java.awt.font.*; +import java.awt.geom.*; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.text.CharacterIterator; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; @@ -56,14 +54,15 @@ import static org.mage.card.arcane.ManaSymbols.getSizedManaSymbol; render.draw(g, cardWidth, cardHeight); } */ + /** * @author stravant@gmail.com - * + *

* Base rendering class for new border cards */ public class ModernCardRenderer extends CardRenderer { - private final static Logger LOGGER = Logger.getLogger(ModernCardRenderer.class); + private static final Logger LOGGER = Logger.getLogger(ModernCardRenderer.class); /////////////////////////////////////////////////////////////////////////// // Textures for modern frame cards @@ -98,6 +97,7 @@ public class ModernCardRenderer extends CardRenderer { } return new Font("Arial", Font.PLAIN, 1); } + public static final Font BASE_BELEREN_FONT = loadFont("beleren-bold"); public static final Paint BG_TEXTURE_WHITE = loadBackgroundTexture("white"); @@ -275,7 +275,9 @@ public class ModernCardRenderer extends CardRenderer { } else if (cardView.isPlayable()) { borderColor = new Color(153, 102, 204, 200); } else if (cardView.isCanAttack()) { - borderColor = new Color(0, 0, 255, 230); + borderColor = new Color(255, 50, 50, 230); + } else if (cardView.isCanBlock()) { + borderColor = new Color(255, 50, 50, 230); } else { borderColor = Color.BLACK; } @@ -480,7 +482,7 @@ public class ModernCardRenderer extends CardRenderer { g.setPaint(borderPaint); if (cardView.getFrameStyle() == FrameStyle.KLD_INVENTION) { - g.drawImage(FRAME_INVENTION, 0, 0, cardWidth, cardHeight, null); + g.drawImage(FRAME_INVENTION, 3, 3, cardWidth - 6, cardHeight - 6, null); g.drawRect( totalContentInset, typeLineY, contentWidth - 1, cardHeight - borderWidth * 3 - typeLineY - 1); @@ -659,7 +661,7 @@ public class ModernCardRenderer extends CardRenderer { } public void drawZendikarCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - Color boxColor, Paint paint) { + Color boxColor, Paint paint) { BufferedImage artToUse = faceArtImage; boolean hadToUseFullArt = false; @@ -707,8 +709,8 @@ public class ModernCardRenderer extends CardRenderer { } public void drawBFZCurvedFace(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - int topxdelta, int endydelta, - Color boxColor, Paint paint) { + int topxdelta, int endydelta, + Color boxColor, Paint paint) { BufferedImage artToUse = faceArtImage; boolean hadToUseFullArt = false; if (faceArtImage == null) { @@ -764,10 +766,10 @@ public class ModernCardRenderer extends CardRenderer { } public void drawUSTCurves(Graphics2D g2, BufferedImage image, int x, int y, int x2, int y2, - int topxdelta, int endydelta, - Color boxColor, Paint paint) { + int topxdelta, int endydelta, + Color boxColor, Paint paint) { BufferedImage artToUse = artImage; - + int srcW = x2; int srcH = y2; if (artToUse != null) { @@ -999,23 +1001,23 @@ public class ModernCardRenderer extends CardRenderer { Polygon symbol = new Polygon( new int[]{ - x + w / 2, - (int) (x + w * 0.9), - x + w, - (int) (x + w * 0.6), - x + w / 2, - (int) (x + w * 0.4), - x, - (int) (x + w * 0.1),}, + x + w / 2, + (int) (x + w * 0.9), + x + w, + (int) (x + w * 0.6), + x + w / 2, + (int) (x + w * 0.4), + x, + (int) (x + w * 0.1),}, new int[]{ - y + h, - (int) (y + 0.8 * h), - y, - (int) (y - 0.2 * h), - y, - (int) (y - 0.2 * h), - y, - (int) (y + 0.8 * h),}, + y + h, + (int) (y + 0.8 * h), + y, + (int) (y - 0.2 * h), + y, + (int) (y - 0.2 * h), + y, + (int) (y + 0.8 * h),}, 8); // Draw + stroke @@ -1124,7 +1126,7 @@ public class ModernCardRenderer extends CardRenderer { drawBasicManaTextbox(g, x, y, w, h, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); return; } else // Big circle in the middle for Zendikar lands - if (allRules.size() == 1) { + if (allRules.size() == 1) { // Size of mana symbol = 9/4 * h, 3/4h above line if (allRules.get(0) instanceof TextboxBasicManaRule) { drawBasicManaSymbol(g, x + w / 2 - 9 * h / 8 + 1, y - 3 * h / 4, 9 * h / 4, 9 * h / 4, ((TextboxBasicManaRule) allRules.get(0)).getBasicManaSymbol()); @@ -1278,45 +1280,45 @@ public class ModernCardRenderer extends CardRenderer { if (loyaltyRule.loyaltyChange < 0 || loyaltyRule.loyaltyChange == TextboxLoyaltyRule.MINUS_X) { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX + symbolWidth / 2, - symbolX,}, + symbolX, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX + symbolWidth / 2, + symbolX,}, new int[]{ - symbolY, - symbolY, - symbolY + symbolHeight - 3, - symbolY + symbolHeight + 3, - symbolY + symbolHeight - 3,}, + symbolY, + symbolY, + symbolY + symbolHeight - 3, + symbolY + symbolHeight + 3, + symbolY + symbolHeight - 3,}, 5); } else if (loyaltyRule.loyaltyChange > 0) { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth / 2, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX,}, + symbolX, + symbolX + symbolWidth / 2, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX,}, new int[]{ - symbolY + 3, - symbolY - 3, - symbolY + 3, - symbolY + symbolHeight, - symbolY + symbolHeight,}, + symbolY + 3, + symbolY - 3, + symbolY + 3, + symbolY + symbolHeight, + symbolY + symbolHeight,}, 5); } else { symbol = new Polygon( new int[]{ - symbolX, - symbolX + symbolWidth, - symbolX + symbolWidth, - symbolX,}, + symbolX, + symbolX + symbolWidth, + symbolX + symbolWidth, + symbolX,}, new int[]{ - symbolY, - symbolY, - symbolY + symbolHeight, - symbolY + symbolHeight,}, + symbolY, + symbolY, + symbolY + symbolHeight, + symbolY + symbolHeight,}, 4); } g.setColor(new Color(0, 0, 0, 128)); @@ -1610,13 +1612,13 @@ public class ModernCardRenderer extends CardRenderer { Color[] translatedColors; if (types.contains(CardType.LAND)) { translatedColors = new Color[]{ - getLandTextboxColor(twoColors.get(0)), - getLandTextboxColor(twoColors.get(1)) + getLandTextboxColor(twoColors.get(0)), + getLandTextboxColor(twoColors.get(1)) }; } else { translatedColors = new Color[]{ - getTextboxColor(twoColors.get(0)), - getTextboxColor(twoColors.get(1)) + getTextboxColor(twoColors.get(0)), + getTextboxColor(twoColors.get(1)) }; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java index c8a403dc3d..4e690bf1a5 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/CardPluginImpl.java @@ -1,26 +1,9 @@ package org.mage.plugins.card; -import java.awt.BorderLayout; -import java.awt.Dimension; -import java.awt.Frame; -import java.awt.Rectangle; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import javax.swing.JComponent; -import javax.swing.JDialog; -import javax.swing.JLayeredPane; import mage.cards.MagePermanent; import mage.cards.action.ActionCallback; import mage.client.dialog.PreferencesDialog; import mage.client.util.GUISizeHelper; -import mage.constants.Rarity; import mage.interfaces.plugin.CardPlugin; import mage.view.CardView; import mage.view.CounterView; @@ -41,14 +24,21 @@ import org.mage.plugins.card.dl.sources.ScryfallSymbolsSource; import org.mage.plugins.card.images.ImageCache; import org.mage.plugins.card.info.CardInfoPaneImpl; +import javax.swing.*; +import java.awt.*; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; +import java.util.*; +import java.util.concurrent.TimeUnit; + /** * {@link CardPlugin} implementation. * - * @author nantuko - * @version 0.1 01.11.2010 Mage permanents. Sorting card layout. - * @version 0.6 17.07.2011 #sortPermanents got option to display non-land - * permanents in one pile - * @version 0.7 29.07.2011 face down cards support + * @author nantuko, JayDi85 */ @PluginImplementation @Author(name = "nantuko") @@ -584,6 +574,10 @@ public class CardPluginImpl implements CardPlugin { } } + private void symbolsOnFinish() { + + } + /** * Download various symbols (mana, tap, set). * @@ -591,23 +585,25 @@ public class CardPluginImpl implements CardPlugin { */ @Override public void downloadSymbols(String imagesDir) { - final DownloadGui g = new DownloadGui(new Downloader()); + final Downloader downloader = new Downloader(); + final DownloadGui downloadGui = new DownloadGui(downloader); - Iterable it; + LOGGER.info("Symbols download prepare..."); + Iterable jobs; - it = new GathererSymbols(); - for (DownloadJob job : it) { - g.getDownloader().add(job); + jobs = new GathererSymbols(); + for (DownloadJob job : jobs) { + downloader.add(job); } - it = new GathererSets(); - for (DownloadJob job : it) { - g.getDownloader().add(job); + jobs = new GathererSets(); + for (DownloadJob job : jobs) { + downloader.add(job); } - it = new ScryfallSymbolsSource(); - for (DownloadJob job : it) { - g.getDownloader().add(job); + jobs = new ScryfallSymbolsSource(); + for (DownloadJob job : jobs) { + downloader.add(job); } /* @@ -615,26 +611,56 @@ public class CardPluginImpl implements CardPlugin { for (DownloadJob job : it) { g.getDownloader().add(job); } - */ - it = new DirectLinksForDownload(); - for (DownloadJob job : it) { - g.getDownloader().add(job); + */ + + jobs = new DirectLinksForDownload(); + for (DownloadJob job : jobs) { + downloader.add(job); } - JDialog d = new JDialog((Frame) null, "Download symbols", false); - d.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); - d.addWindowListener(new WindowAdapter() { + LOGGER.info("Symbols download needs " + downloader.getJobs().size() + " files"); + + // download GUI dialog + JDialog dialog = new JDialog((Frame) null, "Download symbols", false); + dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); + dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { - g.getDownloader().dispose(); - ManaSymbols.loadImages(); - // TODO: check reload process after download (icons do not update) + // user force to close window/downloader + downloader.cleanup(); } }); - d.setLayout(new BorderLayout()); - d.add(g); - d.pack(); - d.setVisible(true); + dialog.setLayout(new BorderLayout()); + dialog.add(downloadGui); + dialog.pack(); + dialog.setVisible(true); + + // downloader controller thread + SwingWorker worker = new SwingWorker() { + @Override + protected Void doInBackground() throws Exception { + downloader.publishAllJobs(); + downloader.waitFinished(); + downloader.cleanup(); + return null; + } + }; + // downloader finisher + worker.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals("state")) { + if (evt.getNewValue() == SwingWorker.StateValue.DONE) { + // all done, can close dialog and refresh symbols for UI + LOGGER.info("Symbols download finished"); + dialog.dispose(); + ManaSymbols.loadImages(); + ImageCache.clearCache(); + } + } + } + }); + worker.execute(); } @Override diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadGui.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadGui.java index e3ff2ca179..3ae0601657 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadGui.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadGui.java @@ -1,113 +1,105 @@ -/** - * DownloadGui.java - * - * Created on 25.08.2010 - */ - package org.mage.plugins.card.dl; +import org.mage.plugins.card.dl.DownloadJob.State; -import java.awt.BorderLayout; -import java.awt.Dimension; +import javax.swing.*; +import java.awt.*; import java.beans.IndexedPropertyChangeEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.Map; -import javax.swing.BorderFactory; -import javax.swing.BoundedRangeModel; -import javax.swing.BoxLayout; -import javax.swing.DefaultBoundedRangeModel; -import javax.swing.JButton; -import javax.swing.JPanel; -import javax.swing.JProgressBar; -import javax.swing.JScrollPane; - -import org.mage.plugins.card.dl.DownloadJob.State; - /** - * The class DownloadGui. - * - * @version V0.0 25.08.2010 + * Downloader GUI to control and show progress + * * @author Clemens Koza */ public class DownloadGui extends JPanel { - private static final long serialVersionUID = -7346572382493844327L; + private static final long serialVersionUID = -7346572382493844327L; - private final Downloader d; - private final DownloadListener l = new DownloadListener(); - private final BoundedRangeModel model = new DefaultBoundedRangeModel(0, 0, 0, 0); - private final JProgressBar progress = new JProgressBar(model); + private final Downloader downloader; + private final DownloadListener listener = new DownloadListener(); + private final BoundedRangeModel progressModel = new DefaultBoundedRangeModel(0, 0, 0, 0); + private final JProgressBar progressBar = new JProgressBar(progressModel); - private final Map progresses = new HashMap<>(); - private final JPanel panel = new JPanel(); + private final Map jobPanels = new HashMap<>(); + private final JPanel basicPanel = new JPanel(); public DownloadGui(Downloader downloader) { super(new BorderLayout()); - this.d = downloader; - downloader.addPropertyChangeListener(l); + this.downloader = downloader; + downloader.addPropertyChangeListener(listener); JPanel p = new JPanel(new BorderLayout()); p.setBorder(BorderFactory.createTitledBorder("Progress:")); - p.add(progress); - JButton b = new JButton("X"); - b.addActionListener(e -> { - d.dispose(); + p.add(progressBar); + JButton closeButton = new JButton("X"); + closeButton.addActionListener(e -> { + this.downloader.cleanup(); }); - p.add(b, BorderLayout.EAST); + p.add(closeButton, BorderLayout.EAST); add(p, BorderLayout.NORTH); - panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); - JScrollPane pane = new JScrollPane(panel); + basicPanel.setLayout(new BoxLayout(basicPanel, BoxLayout.Y_AXIS)); + JScrollPane pane = new JScrollPane(basicPanel); pane.setPreferredSize(new Dimension(500, 300)); add(pane); - for(int i = 0; i < downloader.getJobs().size(); i++) { + for (int i = 0; i < downloader.getJobs().size(); i++) { addJob(i, downloader.getJobs().get(i)); } } public Downloader getDownloader() { - return d; + return downloader; } private class DownloadListener implements PropertyChangeListener { + @Override public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); - if(evt.getSource() instanceof DownloadJob) { - DownloadPanel p = progresses.get(evt.getSource()); + if (evt.getSource() instanceof DownloadJob) { + // one job changes + DownloadPanel panel = jobPanels.get(evt.getSource()); switch (name) { case "state": - if(evt.getOldValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { + if (evt.getOldValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { + // started changeProgress(-1, 0); - } if(evt.getNewValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { - changeProgress(+1, 0); - } if(p != null) { - p.setVisible(p.getJob().getState() != State.FINISHED); - p.revalidate(); - } break; + } + if (evt.getNewValue() == State.FINISHED || evt.getOldValue() == State.ABORTED) { + // finished + changeProgress(+1, 0); + } + if (panel != null) { + panel.setVisible(panel.getJob().getState() != State.FINISHED); + panel.revalidate(); + } + break; case "message": - if(p != null) { - JProgressBar bar = p.getBar(); - String message = p.getJob().getMessage(); + if (panel != null) { + JProgressBar bar = panel.getBar(); + String message = panel.getJob().getMessage(); bar.setStringPainted(message != null); bar.setString(message); - } break; + } + break; } - } else if(evt.getSource() == d) { - if("jobs".equals(name)) { + } else if (evt.getSource() == downloader) { + // all jobs changes (add/delete) + if ("jobs".equals(name)) { IndexedPropertyChangeEvent ev = (IndexedPropertyChangeEvent) evt; int index = ev.getIndex(); DownloadJob oldValue = (DownloadJob) ev.getOldValue(); - if(oldValue != null) { + if (oldValue != null) { removeJob(index, oldValue); } DownloadJob newValue = (DownloadJob) ev.getNewValue(); - if(newValue != null) { + if (newValue != null) { addJob(index, newValue); } } @@ -116,39 +108,39 @@ public class DownloadGui extends JPanel { } private synchronized void addJob(int index, DownloadJob job) { - job.addPropertyChangeListener(l); + job.addPropertyChangeListener(listener); changeProgress(0, +1); DownloadPanel p = new DownloadPanel(job); - progresses.put(job, p); - panel.add(p, index); - panel.revalidate(); + jobPanels.put(job, p); + basicPanel.add(p, index); + basicPanel.revalidate(); } private synchronized void removeJob(int index, DownloadJob job) { - assert progresses.get(job) == panel.getComponent(index); - job.removePropertyChangeListener(l); + assert jobPanels.get(job) == basicPanel.getComponent(index); + job.removePropertyChangeListener(listener); changeProgress(0, -1); - progresses.remove(job); - panel.remove(index); - panel.revalidate(); + jobPanels.remove(job); + basicPanel.remove(index); + basicPanel.revalidate(); } private synchronized void changeProgress(int progress, int total) { - progress += model.getValue(); - total += model.getMaximum(); - model.setMaximum(total); - model.setValue(progress); - this.progress.setStringPainted(true); - this.progress.setString(progress + "/" + total); + progress += progressModel.getValue(); + total += progressModel.getMaximum(); + progressModel.setMaximum(total); + progressModel.setValue(progress); + this.progressBar.setStringPainted(true); + this.progressBar.setString(progress + "/" + total); } private class DownloadPanel extends JPanel { private static final long serialVersionUID = 1187986738303477168L; - private final DownloadJob job; - private final JProgressBar bar; + private final DownloadJob job; + private final JProgressBar bar; - public DownloadPanel(DownloadJob job) { + DownloadPanel(DownloadJob job) { super(new BorderLayout()); this.job = job; @@ -156,7 +148,7 @@ public class DownloadGui extends JPanel { add(bar = new JProgressBar(job.getProgress())); JButton b = new JButton("X"); b.addActionListener(e -> { - switch(this.job.getState()) { + switch (this.job.getState()) { case NEW: case PREPARING: case WORKING: @@ -165,7 +157,7 @@ public class DownloadGui extends JPanel { }); add(b, BorderLayout.EAST); - if(job.getState() == State.FINISHED | job.getState() == State.ABORTED) { + if (job.getState() == State.FINISHED | job.getState() == State.ABORTED) { changeProgress(+1, 0); } setVisible(job.getState() != State.FINISHED); @@ -177,15 +169,13 @@ public class DownloadGui extends JPanel { Dimension d = getPreferredSize(); d.width = Integer.MAX_VALUE; setMaximumSize(d); -// d.width = 500; -// setMinimumSize(d); } - public DownloadJob getJob() { + DownloadJob getJob() { return job; } - public JProgressBar getBar() { + JProgressBar getBar() { return bar; } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java index c39fb6d163..72c99422ab 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/DownloadJob.java @@ -1,28 +1,18 @@ -/** - * DownloadJob.java - * - * Created on 25.08.2010 - */ package org.mage.plugins.card.dl; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Proxy; -import java.net.URL; -import java.net.URLConnection; -import javax.swing.BoundedRangeModel; -import javax.swing.DefaultBoundedRangeModel; import org.mage.plugins.card.dl.beans.properties.Property; import org.mage.plugins.card.dl.lm.AbstractLaternaBean; import org.mage.plugins.card.utils.CardImageUtils; +import javax.swing.*; +import java.io.*; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; + /** - * The class DownloadJob. + * Downloader job to download one resource * - * @version V0.0 25.08.2010 * @author Clemens Koza, JayDi85 */ public class DownloadJob extends AbstractLaternaBean { @@ -88,11 +78,8 @@ public class DownloadJob extends AbstractLaternaBean { */ public void setError(String message, Exception error) { if (message == null) { - - message = "Download of " + name + "from " + source.toString() + " caused error: " + error.toString(); + message = "Download of " + name + " from " + source.toString() + " caused error: " + error.toString(); } -// log.warn(message, error); - log.warn(message); this.state.setValue(State.ABORTED); this.error.setValue(error); this.message.setValue(message); @@ -116,7 +103,7 @@ public class DownloadJob extends AbstractLaternaBean { return; } - // change to working state on good prepare call + // can continue this.state.setValue(State.WORKING); } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java index 497ee62d62..815083b901 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/Downloader.java @@ -1,26 +1,9 @@ -/** - * Downloader.java - * - * Created on 25.08.2010 - */ package org.mage.plugins.card.dl; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.ConnectException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import javax.swing.BoundedRangeModel; import org.apache.log4j.Logger; import org.jetlang.channels.Channel; import org.jetlang.channels.MemoryChannel; import org.jetlang.core.Callback; -import org.jetlang.core.Disposable; import org.jetlang.fibers.Fiber; import org.jetlang.fibers.PoolFiberFactory; import org.mage.plugins.card.dl.DownloadJob.Destination; @@ -28,41 +11,56 @@ import org.mage.plugins.card.dl.DownloadJob.Source; import org.mage.plugins.card.dl.DownloadJob.State; import org.mage.plugins.card.dl.lm.AbstractLaternaBean; +import javax.swing.*; +import java.io.*; +import java.net.ConnectException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + /** - * The class Downloader. + * Downloader * - * @version V0.0 25.08.2010 - * @author Clemens Koza + * @author Clemens Koza, JayDi85 */ -public class Downloader extends AbstractLaternaBean implements Disposable { +public class Downloader extends AbstractLaternaBean { private static final Logger logger = Logger.getLogger(Downloader.class); private final List jobs = properties.list("jobs"); - private final Channel channel = new MemoryChannel<>(); + private final Channel jobsQueue = new MemoryChannel<>(); + private CountDownLatch worksCount = null; private final ExecutorService pool = Executors.newCachedThreadPool(); private final List fibers = new ArrayList<>(); public Downloader() { + // prepare 10 threads and start to waiting new download jobs from queue PoolFiberFactory f = new PoolFiberFactory(pool); - //subscribe multiple fibers for parallel execution for (int i = 0, numThreads = 10; i < numThreads; i++) { Fiber fiber = f.create(); fiber.start(); fibers.add(fiber); - channel.subscribe(fiber, new DownloadCallback()); + jobsQueue.subscribe(fiber, new DownloadCallback()); } } - @Override - public void dispose() { + public void cleanup() { + // close all threads and jobs for (DownloadJob j : jobs) { switch (j.getState()) { case NEW: case PREPARING: case WORKING: j.setState(State.ABORTED); + break; + case ABORTED: + case FINISHED: + // don't change state + break; } } @@ -70,16 +68,10 @@ public class Downloader extends AbstractLaternaBean implements Disposable { f.dispose(); } pool.shutdown(); - } - /** - * - * @throws Throwable - */ - @Override - protected void finalize() throws Throwable { - dispose(); - super.finalize(); + while (worksCount.getCount() != 0) { + worksCount.countDown(); + } } public void add(DownloadJob job) { @@ -94,7 +86,27 @@ public class Downloader extends AbstractLaternaBean implements Disposable { } job.setState(State.NEW); jobs.add(job); - channel.publish(job); + } + + public void publishAllJobs() { + worksCount = new CountDownLatch(jobs.size()); + for (DownloadJob job : jobs) { + jobsQueue.publish(job); + } + } + + public void waitFinished() { + try { + while (worksCount.getCount() != 0) { + worksCount.await(60, TimeUnit.SECONDS); + + if (worksCount.getCount() != 0) { + logger.warn("Symbols download too long..."); + } + } + } catch (InterruptedException e) { + logger.error("Need to stop symbols download..."); + } } public List getJobs() { @@ -111,20 +123,23 @@ public class Downloader extends AbstractLaternaBean implements Disposable { @Override public void onMessage(DownloadJob job) { - // start to work - // the job won't be processed by multiple threads + // each 10 threads gets same jobs, but take to work only one NEW synchronized (job) { - if (job.getState() != State.NEW) { - return; - } - - job.doPrepareAndStartWork(); - - if (job.getState() != State.WORKING) { + if (job.getState() == State.NEW) { + // take new job + job.doPrepareAndStartWork(); + if (job.getState() != State.WORKING) { + logger.warn("Can't prepare symbols download job: " + job.getName()); + worksCount.countDown(); + return; + } + } else { + // skip job (other thread takes it) return; } } + // real work for new job // download and save data try { Source src = job.getSource(); @@ -132,9 +147,11 @@ public class Downloader extends AbstractLaternaBean implements Disposable { BoundedRangeModel progress = job.getProgress(); if (dst.isValid()) { + // already done progress.setMaximum(1); progress.setValue(1); } else { + // downloading if (dst.exists()) { try { dst.delete(); @@ -149,7 +166,7 @@ public class Downloader extends AbstractLaternaBean implements Disposable { try { byte[] buf = new byte[8 * 1024]; int total = 0; - for (int len; (len = is.read(buf)) != -1;) { + for (int len; (len = is.read(buf)) != -1; ) { if (job.getState() == State.ABORTED) { throw new IOException("Job was aborted"); } @@ -193,6 +210,8 @@ public class Downloader extends AbstractLaternaBean implements Disposable { logger.warn("Error resource download " + job.getName() + " from " + job.getSource().toString() + ": " + message); } catch (IOException ex) { job.setError(ex); + } finally { + worksCount.countDown(); } } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java index be462e1829..224a1b036e 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/lm/AbstractLaternaBean.java @@ -1,6 +1,6 @@ /** * AbstractLaternaBean.java - * + *

* Created on 25.08.2010 */ @@ -16,12 +16,12 @@ import org.mage.plugins.card.dl.beans.properties.bound.BoundProperties; /** * The class AbstractLaternaBean. - * - * @version V0.0 25.08.2010 + * * @author Clemens Koza + * @version V0.0 25.08.2010 */ public class AbstractLaternaBean extends AbstractBoundBean { protected static final Logger log = Logger.getLogger(AbstractLaternaBean.class); - protected final Properties properties = new BoundProperties(s); - protected EventListenerList listeners = new EventListenerList(); + protected final Properties properties = new BoundProperties(s); + protected EventListenerList listeners = new EventListenerList(); } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/AltMtgOnlTokensImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/AltMtgOnlTokensImageSource.java index df290687c1..f8216028ba 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/AltMtgOnlTokensImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/AltMtgOnlTokensImageSource.java @@ -1,4 +1,3 @@ - package org.mage.plugins.card.dl.sources; import org.apache.log4j.Logger; @@ -59,7 +58,7 @@ public enum AltMtgOnlTokensImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { return null; } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java index f2d0fabf75..758f38881e 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CardImageSource.java @@ -1,15 +1,16 @@ package org.mage.plugins.card.dl.sources; -import java.util.ArrayList; +import mage.client.util.CardLanguage; import org.mage.plugins.card.images.CardDownloadData; +import java.util.ArrayList; + /** - * - * @author North + * @author North, JayDi85 */ public interface CardImageSource { - CardImageUrls generateURL(CardDownloadData card) throws Exception; + CardImageUrls generateCardUrl(CardDownloadData card) throws Exception; CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception; @@ -31,17 +32,32 @@ public interface CardImageSource { return false; } + default boolean isLanguagesSupport() { + return false; + } + + default void setCurrentLanguage(CardLanguage cardLanguage) { + } + + default CardLanguage getCurrentLanguage() { + return CardLanguage.ENGLISH; + } + void doPause(String httpImageUrl); default ArrayList getSupportedSets() { - return null; + return new ArrayList<>(); } default boolean isSetSupportedComplete(String setCode) { return true; } - default boolean isImageProvided(String setCode, String cardName) { + default boolean isCardImageProvided(String setCode, String cardName) { + return false; + } + + default boolean isTokenImageProvided(String setCode, String cardName, Integer tokenNumber) { return false; } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CopyPasteImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CopyPasteImageSource.java index 0fc6561b97..766208bdf1 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CopyPasteImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/CopyPasteImageSource.java @@ -1,6 +1,10 @@ package org.mage.plugins.card.dl.sources; -import java.awt.Toolkit; +import mage.cards.Sets; +import org.mage.plugins.card.images.CardDownloadData; + +import javax.swing.*; +import java.awt.*; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.io.IOException; @@ -10,12 +14,8 @@ import java.util.LinkedHashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.swing.JOptionPane; -import mage.cards.Sets; -import org.mage.plugins.card.images.CardDownloadData; /** - * * @author spjspj */ public enum CopyPasteImageSource implements CardImageSource { @@ -74,7 +74,7 @@ public enum CopyPasteImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { if (singleLinks == null) { setupLinks(); } @@ -198,7 +198,7 @@ public enum CopyPasteImageSource implements CardImageSource { @Override public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException { try { - return generateURL(card); + return generateCardUrl(card); } catch (Exception ex) { } return null; @@ -239,7 +239,7 @@ public enum CopyPasteImageSource implements CardImageSource { } @Override - public boolean isImageProvided(String setCode, String cardName) { + public boolean isCardImageProvided(String setCode, String cardName) { missingCards.add(setCode + "/" + cardName); if (singleLinks != null) { @@ -248,6 +248,11 @@ public enum CopyPasteImageSource implements CardImageSource { return false; } + @Override + public boolean isTokenImageProvided(String setCode, String cardName, Integer tokenNumber) { + return false; + } + @Override public boolean isSetSupportedComplete(String setCode) { return false; 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 8d3e12236c..e38898760f 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 @@ -1,6 +1,8 @@ - package org.mage.plugins.card.dl.sources; +import org.apache.log4j.Logger; +import org.mage.plugins.card.images.CardDownloadData; + import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -9,9 +11,6 @@ import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import org.apache.log4j.Logger; -import org.mage.plugins.card.images.CardDownloadData; - /** * @author spjspj */ @@ -48,7 +47,7 @@ public enum GrabbagImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { if (singleLinks == null) { setupLinks(); } @@ -450,7 +449,7 @@ public enum GrabbagImageSource implements CardImageSource { @Override public CardImageUrls generateTokenUrl(CardDownloadData card) throws IOException { try { - return generateURL(card); + return generateCardUrl(card); } catch (Exception ex) { java.util.logging.Logger.getLogger(GrabbagImageSource.class.getName()).log(Level.SEVERE, null, ex); } @@ -501,7 +500,7 @@ public enum GrabbagImageSource implements CardImageSource { } @Override - public boolean isImageProvided(String setCode, String cardName) { + public boolean isCardImageProvided(String setCode, String cardName) { if (singleLinks == null) { setupLinks(); } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java deleted file mode 100644 index dfee0c9a46..0000000000 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagicCardsImageSource.java +++ /dev/null @@ -1,439 +0,0 @@ -package org.mage.plugins.card.dl.sources; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - -import mage.client.dialog.PreferencesDialog; -import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.utils.CardImageUtils; - -/** - * @author North - */ -public enum MagicCardsImageSource implements CardImageSource { - - instance; - - private static final Set supportedSets = new LinkedHashSet() { - { - // add("PTC"); // Prerelease Events - add("LEA"); - add("LEB"); - add("2ED"); - add("ARN"); - add("ATQ"); - add("3ED"); - add("LEG"); - add("DRK"); - add("FEM"); - add("4ED"); - add("ICE"); - add("CHR"); - add("HML"); - add("ALL"); - add("MIR"); - add("VIS"); - add("5ED"); - add("POR"); - add("WTH"); - add("TMP"); - add("STH"); - add("EXO"); - add("P02"); - add("UGL"); - add("USG"); - add("DD3DVD"); - add("DD3EVG"); - add("DD3GVL"); - add("DD3JVC"); - - add("ULG"); - add("6ED"); - add("UDS"); - add("PTK"); - add("S99"); - add("MMQ"); - // add("BRB");Battle Royale Box Set - add("NEM"); - add("S00"); - add("PCY"); - add("INV"); - // add("BTD"); // Beatdown Boxset - add("PLS"); - add("7ED"); - add("APC"); - add("ODY"); - // add("DKM"); // Deckmasters 2001 - add("TOR"); - add("JUD"); - add("ONS"); - add("LGN"); - add("SCG"); - add("8ED"); - add("MRD"); - add("DST"); - add("5DN"); - add("CHK"); - add("UNH"); - add("BOK"); - add("SOK"); - add("9ED"); - add("RAV"); - add("GPT"); - add("DIS"); - add("CSP"); - add("TSP"); - add("TSB"); - add("PLC"); - add("FUT"); - add("10E"); - add("MED"); - add("LRW"); - add("EVG"); - add("MOR"); - add("SHM"); - add("EVE"); - add("DRB"); - add("ME2"); - add("ALA"); - add("DD2"); - add("CON"); - add("DDC"); - add("ARB"); - add("M10"); - // add("TD0"); // Magic Online Deck Series - add("V09"); - add("HOP"); - add("ME3"); - add("ZEN"); - add("DDD"); - add("H09"); - add("WWK"); - add("DDE"); - add("ROE"); - add("DPA"); - add("ARC"); - add("M11"); - add("V10"); - add("DDF"); - add("SOM"); - // add("TD0"); // Commander Theme Decks - add("PD2"); - add("ME4"); - add("MBS"); - add("DDG"); - add("NPH"); - add("CMD"); - add("M12"); - add("V11"); - add("DDH"); - add("ISD"); - add("PD3"); - add("DKA"); - add("DDI"); - add("AVR"); - add("PC2"); - add("M13"); - add("V12"); - add("DDJ"); - add("RTR"); - add("CM1"); - // add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia - add("GTC"); - add("DDK"); - add("DGM"); - add("MMA"); - add("M14"); - add("V13"); - add("DDL"); - add("THS"); - add("C13"); - add("BNG"); - add("DDM"); - add("JOU"); - // add("MD1"); // Modern Event Deck - add("CNS"); - add("VMA"); - add("M15"); - add("V14"); - add("DDN"); - add("KTK"); - add("C14"); - // add("DD3"); // Duel Decks Anthology - add("FRF"); - add("DDO"); - add("DTK"); - add("TPR"); - add("MM2"); - add("ORI"); - add("V15"); - add("DDP"); - add("BFZ"); - add("EXP"); - add("C15"); - // add("PZ1"); // Legendary Cube - add("OGW"); - add("DDQ"); - add("W16"); - add("SOI"); - add("EMA"); - add("EMN"); - add("V16"); - add("CN2"); - add("DDR"); - add("KLD"); - add("MPS"); - // add("PZ2"); // Treasure Chests - add("C16"); - add("PCA"); - add("AER"); - add("MM3"); - add("DDS"); - add("W17"); - add("AKH"); - add("MPS"); - add("CMA"); - add("E01"); - add("HOU"); - add("C17"); - add("XLN"); - add("DDT"); - add("DDU"); - add("IMA"); - add("E02"); - add("V17"); - add("UST"); - add("RIX"); - add("A25"); - add("DOM"); -// add("CM2"); -// add("M19"); - } - }; - - private static final Map setNameTokenReplacement = new HashMap() { - { - put("10E", "tenth-edition"); - put("AER", "aether-revolt"); - put("AKH", "amonkhet"); - put("ALA", "shards-of-alara"); - put("ANB", "archenemy-nicol-bolas"); - put("APAC", "asia-pacific-land-program"); - put("APC", "player-rewards-2001"); - put("ARB", "alara-reborn"); - put("ARC", "archenemy"); - put("ARENA", "arena-league"); - put("AVR", "avacyn-restored"); - put("BFZ", "battle-for-zendikar"); - put("BNG", "born-of-the-gods"); - put("C13", "commander-2013-edition"); - put("C14", "commander-2014"); - put("C15", "commander-2015"); - put("C16", "commander-2016"); - put("CLASH", "clash-pack"); - put("CMA", "commander-anthology"); - put("CMA", "commanders-arsenal"); - put("CMD", "commander"); - put("CN2", "conspiracy-take-the-crown"); - put("CNS", "conspiracy"); - put("CON", "conflux"); - put("CP", "champs"); - put("CSP", "coldsnap"); - put("DD2", "duel-decks-jace-vs-chandra"); - put("DD3DVD", "duel-decks-anthology-divine-vs-demonic"); - put("DD3EVG", "duel-decks-anthology-elves-vs-goblins"); - put("DD3GVL", "duel-decks-anthology-garruk-vs-liliana"); - put("DD3JVC", "duel-decks-anthology-jace-vs-chandra"); - put("DDC", "duel-decks-divine-vs-demonic"); - put("DDD", "duel-decks-garruk-vs-liliana"); - put("DDE", "duel-decks-phyrexia-vs-the-coalition"); - put("DDF", "duel-decks-elspeth-vs-tezzeret"); - put("DDG", "duel-decks-knights-vs-dragons"); - put("DDH", "duel-decks-ajani-vs-nicol-bolas"); - put("DDI", "duel-decks-venser-vs-koth"); - put("DDJ", "duel-decks-izzet-vs-golgari"); - put("DDK", "duel-decks-sorin-vs-tibalt"); - put("DDL", "duel-decks-heroes-vs-monsters"); - put("DDM", "duel-decks-jace-vs-vraska"); - put("DDN", "duel-decks-speed-vs-cunning"); - put("DDO", "duel-decks-elspeth-vs-kiora"); - put("DDP", "duel-decks-zendikar-vs-eldrazi"); - put("DDQ", "duel-decks-blessed-vs-cursed"); - put("DDR", "duel-decks-nissa-vs-ob-nixilis"); - put("DDS", "duel-decks-mind-vs-might"); - put("DDT", "duel-decks-merfolk-vs-goblin"); - put("DDU", "duel-decks-elves-vs-inventors"); - put("DGM", "dragons-maze"); - put("DKA", "dark-ascension"); - put("DRB", "from-the-vault-dragons"); - put("DTK", "dragons-of-tarkir"); - put("EMA", "eternal-masters"); - put("EMN", "eldritch-moon"); - put("EURO", "european-land-program"); - put("EVE", "eventide"); - put("EVG", "duel-decks-elves-vs-goblins"); - put("EXP", "zendikar-expeditions"); - put("FNMP", "friday-night-magic"); - put("FRF", "fate-reforged"); - put("GPX", "grand-prix"); - put("GRC", "wpngateway"); - put("GTC", "gatecrash"); - put("HOP", "planechase"); - put("HOU", "hour-of-devastation"); - put("INV", "player-rewards-2001"); - put("ISD", "innistrad"); - put("JOU", "journey-into-nyx"); - put("JR", "judge-gift-program"); - put("KLD", "kaladesh"); - put("KTK", "khans-of-tarkir"); - put("LRW", "lorwyn"); - put("M10", "magic-2010"); - put("M11", "magic-2011"); - put("M12", "magic-2012"); - put("M13", "magic-2013"); - put("M14", "magic-2014"); - put("M15", "magic-2015"); - put("MBP", "media-inserts"); - put("MBS", "mirrodin-besieged"); - put("MGDC", "magic-game-day-cards"); - put("MLP", "launch-party"); - put("MM2", "modern-masters-2015"); - put("MM3", "modern-masters-2017"); - put("MMA", "modern-masters"); - put("MOR", "morningtide"); - put("MPRP", "magic-player-rewards"); - put("MPS", "masterpiece-series"); - put("NPH", "new-phyrexia"); - put("ODY", "player-rewards-2002"); - put("OGW", "oath-of-the-gatewatch"); - put("ORG", "oath-of-the-gatewatch"); - put("ORI", "magic-origins"); - put("PC2", "planechase-2012-edition"); - put("PO2", "portal-second-age"); - put("PLS", "player-rewards-2001"); - put("POR", "portal"); - put("PTC", "prerelease-events"); - put("PTK", "portal-three-kingdoms"); - put("ROE", "rise-of-the-eldrazi"); - put("RTR", "return-to-ravnica"); - put("SHM", "shadowmoor"); - put("SOI", "shadows-over-innistrad"); - put("SOM", "scars-of-mirrodin"); - put("SUS", "super-series"); - put("THS", "theros"); - put("TPR", "tempest-remastered"); - put("UGIN", "ugins-fate"); - put("V09", "from-the-vault-exiled"); - put("V10", "from-the-vault-relics"); - put("V11", "from-the-vault-legends"); - put("V12", "from-the-vault-realms"); - put("V13", "from-the-vault-twenty"); - put("V14", "from-the-vault-annihilation"); - put("V15", "from-the-vault-angels"); - put("V16", "from-the-vault-lore"); - put("VMA", "vintage-masters"); - put("W16", "welcome-deck-2016"); - put("W17", "welcome-deck-2017"); - put("WMCQ", "world-magic-cup-qualifier"); - put("WWK", "worldwake"); - put("ZEN", "zendikar"); - } - - private static final long serialVersionUID = 1L; - }; - - @Override - public String getSourceName() { - return "magiccards.info"; - } - - @Override - public String getNextHttpImageUrl() { - return null; - } - - @Override - public String getFileForHttpImage(String httpImageUrl) { - return null; - } - - @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { - String collectorId = card.getCollectorId(); - String cardSet = card.getSet(); - if (collectorId == null || cardSet == null) { - throw new Exception("Wrong parameters for image: collector id: " + collectorId + ",card set: " + cardSet); - } - String set = CardImageUtils.updateSet(cardSet, true); - - String preferedLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); - - StringBuilder url = new StringBuilder("http://magiccards.info/scans/").append(preferedLanguage).append('/'); - url.append(set.toLowerCase(Locale.ENGLISH)).append('/').append(collectorId); - - if (card.isTwoFacedCard()) { - url.append(card.isSecondSide() ? "b" : "a"); - } - if (card.isSplitCard()) { - url.append('a'); - } - if (card.isFlipCard()) { - if (card.isFlippedSide()) { // download rotated by 180 degree image - url.append('b'); - } else { - url.append('a'); - } - } - url.append(".jpg"); - - return new CardImageUrls(url.toString()); - } - - @Override - public CardImageUrls generateTokenUrl(CardDownloadData card) { - String name = card.getName(); - // add type to name if it's not 0 - if (card.getType() > 0) { - name = name + ' ' + card.getType(); - } - name = name.replaceAll(" ", "-").replace(",", "").toLowerCase(Locale.ENGLISH); - String set = "not-supported-set"; - if (setNameTokenReplacement.containsKey(card.getSet())) { - set = setNameTokenReplacement.get(card.getSet()); - } else { - set += '-' + card.getSet(); - } - return new CardImageUrls("http://magiccards.info/extras/token/" + set + '/' + name + ".jpg"); - } - - @Override - public float getAverageSize() { - return 70.0f; - } - - @Override - public int getTotalImages() { - return -1; - } - - @Override - public boolean isTokenSource() { - return true; - } - - @Override - public ArrayList getSupportedSets() { - ArrayList supportedSetsCopy = new ArrayList<>(); - supportedSetsCopy.addAll(supportedSets); - return supportedSetsCopy; - } - - @Override - public void doPause(String httpImageUrl) { - } - -} diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java index c2ddfcc987..4bd2c49433 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MagidexImageSource.java @@ -1,16 +1,10 @@ - package org.mage.plugins.card.dl.sources; -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; - import org.mage.plugins.card.images.CardDownloadData; +import java.net.URI; +import java.util.*; + /** * @author Pete Rossi */ @@ -234,7 +228,7 @@ public enum MagidexImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { String cardDownloadName = card.getDownloadName().toLowerCase(Locale.ENGLISH); String cardSet = card.getSet(); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgImageSource.java index f5104a2226..7c8a368579 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgImageSource.java @@ -1,10 +1,9 @@ - package org.mage.plugins.card.dl.sources; -import java.util.Locale; - import org.mage.plugins.card.images.CardDownloadData; +import java.util.Locale; + /** * Site was shutdown by wizards Feb. 2015 * @@ -30,7 +29,7 @@ public enum MtgImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { String collectorId = card.getCollectorId(); String cardSet = card.getSet(); if (collectorId == null || cardSet == null) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgOnlTokensImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgOnlTokensImageSource.java index 9d82cbb425..f43baec92c 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgOnlTokensImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MtgOnlTokensImageSource.java @@ -1,12 +1,11 @@ - package org.mage.plugins.card.dl.sources; -import java.io.IOException; -import java.util.HashMap; - import org.apache.log4j.Logger; import org.mage.plugins.card.images.CardDownloadData; +import java.io.IOException; +import java.util.HashMap; + /** * @author spjspj */ @@ -59,7 +58,7 @@ public enum MtgOnlTokensImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { return null; } @@ -352,8 +351,12 @@ public enum MtgOnlTokensImageSource implements CardImageSource { } @Override - public boolean isImageProvided(String setCode, String cardName) { - return true; + public boolean isCardImageProvided(String setCode, String cardName) { + return false; } + @Override + public boolean isTokenImageProvided(String setCode, String cardName, Integer tokenNumber) { + return true; + } } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java index 86f80a6fea..1c0ecaf857 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/MythicspoilerComSource.java @@ -1,22 +1,5 @@ package org.mage.plugins.card.dl.sources; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.net.URL; -import java.net.URLEncoder; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.prefs.Preferences; import mage.client.MageFrame; import mage.remote.Connection; import mage.remote.Connection.ProxyType; @@ -26,6 +9,13 @@ import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import org.mage.plugins.card.images.CardDownloadData; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.*; +import java.util.*; +import java.util.prefs.Preferences; + /** * @author LevelX2 */ @@ -330,7 +320,7 @@ public enum MythicspoilerComSource implements CardImageSource { } private Map getSetLinksFromPage(String cardSet, Set aliasesStart, Preferences prefs, - ProxyType proxyType, String baseUrl, String pageUrl) throws IOException { + ProxyType proxyType, String baseUrl, String pageUrl) throws IOException { Map pageLinks = new HashMap<>(); String urlDocument; @@ -392,7 +382,7 @@ public enum MythicspoilerComSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { String collectorId = card.getCollectorId(); String cardSet = card.getSet(); if (collectorId == null || cardSet == null) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java index 7f2bc5825f..133bebf5b0 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSource.java @@ -1,305 +1,113 @@ package org.mage.plugins.card.dl.sources; -import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import org.mage.plugins.card.images.CardDownloadData; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; /** - * @author Quercitron, JayDi85 + * @author JayDi85 */ public enum ScryfallImageSource implements CardImageSource { instance; - private final Set supportedSets; - private final Map languageAliases; + private final Map languageAliases; + private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language ScryfallImageSource() { + // LANGUAGES // https://scryfall.com/docs/api/languages languageAliases = new HashMap<>(); - languageAliases.put("en", "en"); - languageAliases.put("es", "es"); - languageAliases.put("jp", "ja"); - languageAliases.put("it", "it"); - languageAliases.put("fr", "fr"); - languageAliases.put("cn", "zhs"); // Simplified Chinese - languageAliases.put("de", "de"); - languageAliases.put("ko", "ko"); - languageAliases.put("pt", "pt"); - languageAliases.put("ru", "ru"); - - supportedSets = new LinkedHashSet<>(); - // supportedSets.add("PTC"); // - supportedSets.add("LEA"); - supportedSets.add("LEB"); - supportedSets.add("2ED"); - supportedSets.add("ARN"); - supportedSets.add("ATQ"); - supportedSets.add("3ED"); - supportedSets.add("LEG"); - supportedSets.add("DRK"); - supportedSets.add("FEM"); - supportedSets.add("4ED"); - supportedSets.add("ICE"); - supportedSets.add("CHR"); - supportedSets.add("HML"); - supportedSets.add("ALL"); - supportedSets.add("MIR"); - supportedSets.add("VIS"); - supportedSets.add("5ED"); - supportedSets.add("POR"); - supportedSets.add("WTH"); - supportedSets.add("TMP"); - supportedSets.add("STH"); - supportedSets.add("EXO"); - supportedSets.add("P02"); - supportedSets.add("UGL"); - supportedSets.add("USG"); - supportedSets.add("DD3DVD"); - supportedSets.add("DD3EVG"); - supportedSets.add("DD3GVL"); - supportedSets.add("DD3JVC"); - - supportedSets.add("ULG"); - supportedSets.add("6ED"); - supportedSets.add("UDS"); - supportedSets.add("PTK"); - supportedSets.add("S99"); - supportedSets.add("MMQ"); - // supportedSets.add("BRB");Battle Royale Box Set - supportedSets.add("NEM"); - supportedSets.add("S00"); - supportedSets.add("PCY"); - supportedSets.add("INV"); - // supportedSets.add("BTD"); // Beatdown Boxset - supportedSets.add("PLS"); - supportedSets.add("7ED"); - supportedSets.add("APC"); - supportedSets.add("ODY"); - // supportedSets.add("DKM"); // Deckmasters 2001 - supportedSets.add("TOR"); - supportedSets.add("JUD"); - supportedSets.add("ONS"); - supportedSets.add("LGN"); - supportedSets.add("SCG"); - supportedSets.add("8ED"); - supportedSets.add("MRD"); - supportedSets.add("DST"); - supportedSets.add("5DN"); - supportedSets.add("CHK"); - supportedSets.add("UNH"); - supportedSets.add("BOK"); - supportedSets.add("SOK"); - supportedSets.add("9ED"); - supportedSets.add("RAV"); - supportedSets.add("GPT"); - supportedSets.add("DIS"); - supportedSets.add("CSP"); - supportedSets.add("TSP"); - supportedSets.add("TSB"); - supportedSets.add("PLC"); - supportedSets.add("FUT"); - supportedSets.add("10E"); - supportedSets.add("MED"); - supportedSets.add("LRW"); - supportedSets.add("EVG"); - supportedSets.add("MOR"); - supportedSets.add("SHM"); - supportedSets.add("EVE"); - supportedSets.add("DRB"); - supportedSets.add("ME2"); - supportedSets.add("ALA"); - supportedSets.add("DD2"); - supportedSets.add("CON"); - supportedSets.add("DDC"); - supportedSets.add("ARB"); - supportedSets.add("M10"); - // supportedSets.add("TD0"); // Magic Online Deck Series - supportedSets.add("V09"); - supportedSets.add("HOP"); - supportedSets.add("ME3"); - supportedSets.add("ZEN"); - supportedSets.add("DDD"); - supportedSets.add("H09"); - supportedSets.add("WWK"); - supportedSets.add("DDE"); - supportedSets.add("ROE"); - // duels of the planewalkers: - supportedSets.add("DPA"); - supportedSets.add("DPAP"); - // - supportedSets.add("ARC"); - supportedSets.add("M11"); - supportedSets.add("V10"); - supportedSets.add("DDF"); - supportedSets.add("SOM"); - // supportedSets.add("TD0"); // Commander Theme Decks - supportedSets.add("PD2"); - supportedSets.add("ME4"); - supportedSets.add("MBS"); - supportedSets.add("DDG"); - supportedSets.add("NPH"); - supportedSets.add("CMD"); - supportedSets.add("M12"); - supportedSets.add("V11"); - supportedSets.add("DDH"); - supportedSets.add("ISD"); - supportedSets.add("PD3"); - supportedSets.add("DKA"); - supportedSets.add("DDI"); - supportedSets.add("AVR"); - supportedSets.add("PC2"); - supportedSets.add("M13"); - supportedSets.add("V12"); - supportedSets.add("DDJ"); - supportedSets.add("RTR"); - supportedSets.add("CM1"); - // supportedSets.add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia - supportedSets.add("GTC"); - supportedSets.add("DDK"); - supportedSets.add("DGM"); - supportedSets.add("MMA"); - supportedSets.add("M14"); - supportedSets.add("V13"); - supportedSets.add("DDL"); - supportedSets.add("THS"); - supportedSets.add("C13"); - supportedSets.add("BNG"); - supportedSets.add("DDM"); - supportedSets.add("JOU"); - // supportedSets.add("MD1"); // Modern Event Deck - supportedSets.add("CNS"); - supportedSets.add("VMA"); - supportedSets.add("M15"); - supportedSets.add("V14"); - supportedSets.add("DDN"); - supportedSets.add("KTK"); - supportedSets.add("C14"); - // supportedSets.add("DD3"); // Duel Decks Anthology - supportedSets.add("FRF"); - supportedSets.add("DDO"); - supportedSets.add("DTK"); - supportedSets.add("TPR"); - supportedSets.add("MM2"); - supportedSets.add("ORI"); - supportedSets.add("V15"); - supportedSets.add("DDP"); - supportedSets.add("BFZ"); - supportedSets.add("EXP"); - supportedSets.add("C15"); - // supportedSets.add("PZ1"); // Legendary Cube - supportedSets.add("OGW"); - supportedSets.add("DDQ"); - supportedSets.add("W16"); - supportedSets.add("SOI"); - supportedSets.add("EMA"); - supportedSets.add("EMN"); - supportedSets.add("V16"); - supportedSets.add("CN2"); - supportedSets.add("DDR"); - supportedSets.add("KLD"); - supportedSets.add("MPS"); - // supportedSets.add("PZ2"); - supportedSets.add("C16"); - supportedSets.add("PCA"); - supportedSets.add("AER"); - supportedSets.add("MM3"); - supportedSets.add("DDS"); - supportedSets.add("W17"); - supportedSets.add("AKH"); - supportedSets.add("CMA"); - supportedSets.add("E01"); - supportedSets.add("HOU"); - supportedSets.add("C17"); - supportedSets.add("XLN"); - supportedSets.add("DDT"); - supportedSets.add("IMA"); - supportedSets.add("E02"); - supportedSets.add("V17"); - supportedSets.add("UST"); - supportedSets.add("DDU"); - supportedSets.add("RIX"); - supportedSets.add("WMCQ"); - supportedSets.add("PPRO"); - supportedSets.add("A25"); - supportedSets.add("DOM"); - supportedSets.add("BBD"); - supportedSets.add("C18"); - supportedSets.add("CM2"); - supportedSets.add("M19"); - supportedSets.add("GS1"); - supportedSets.add("GRN"); - supportedSets.add("GK1"); - // - supportedSets.add("EURO"); - supportedSets.add("GPX"); - supportedSets.add("ATH"); - supportedSets.add("GRC"); + languageAliases.put(CardLanguage.ENGLISH, "en"); + languageAliases.put(CardLanguage.SPANISH, "es"); + languageAliases.put(CardLanguage.FRENCH, "fr"); + languageAliases.put(CardLanguage.GERMAN, "de"); + languageAliases.put(CardLanguage.ITALIAN, "it"); + languageAliases.put(CardLanguage.PORTUGUESE, "pt"); + languageAliases.put(CardLanguage.JAPANESE, "ja"); + languageAliases.put(CardLanguage.KOREAN, "ko"); + languageAliases.put(CardLanguage.RUSSIAN, "ru"); + languageAliases.put(CardLanguage.CHINES_SIMPLE, "zhs"); + languageAliases.put(CardLanguage.CHINES_TRADITION, "zht"); } - @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { - - String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); - String defaultCode = "en"; - String localizedCode = languageAliases.getOrDefault(preferredLanguage, defaultCode); + private CardImageUrls innerGenerateURL(CardDownloadData card, boolean isToken) { + String defaultCode = CardLanguage.ENGLISH.getCode(); + String localizedCode = languageAliases.getOrDefault(this.getCurrentLanguage(), defaultCode); // loc example: https://api.scryfall.com/cards/xln/121/ru?format=image - // TODO: do not use API at all? It's can help with scryfall request limits (1 request instead 2) + // WARNING, some cards haven't direct images and uses random GUID: + // As example: Raging Ravine - https://scryfall.com/card/uma/249/raging-ravine + // https://img.scryfall.com/cards/large/front/5/4/54f41726-e0bb-4154-a2db-4b68b50f5032.jpg String baseUrl = null; String alternativeUrl = null; - // direct links to images (non localization) - if (baseUrl == null) { + // TOKENS TRY - // set/card/number - String linkCode1 = card.getSet() + "/" + card.getName() + "/" + card.getCollectorId(); - if (directDownloadLinks.containsKey(linkCode1)) { - baseUrl = directDownloadLinks.get(linkCode1); - alternativeUrl = null; - } - - // set/card - String linkCode2 = card.getSet() + "/" + card.getName(); - if (directDownloadLinks.containsKey(linkCode2)) { - baseUrl = directDownloadLinks.get(linkCode2); - alternativeUrl = null; - } + // tokens support only direct links + if (baseUrl == null && isToken) { + baseUrl = ScryfallImageSupportTokens.findTokenLink(card.getSet(), card.getName(), card.getType()); + alternativeUrl = null; } - // special card number like "103a" already compatible + // CARDS TRY + + // direct links to images (non localization) + if (baseUrl == null) { + baseUrl = ScryfallImageSupportCards.findDirectDownloadLink(card.getSet(), card.getName(), card.getCollectorId()); + alternativeUrl = null; + } + + // special card number like "103a" and "U123" already compatible if (baseUrl == null && card.isCollectorIdWithStr()) { - baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/" - + card.getCollectorId() + ".jpg"; - alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/" - + card.getCollectorId() + ".jpg"; + // WARNING, after 2018 it's not compatible and some new sets have GUID files instead card numbers + // TODO: replace card number links to API calls (need test with lands, alternative images and double faces), replace not working images by direct links + + if (card.getCollectorId().startsWith("U") || card.getCollectorIdAsInt() == -1) { + // fix for Ultimate Box Topper (PUMA) and Mythic Edition (MED) -- need to use API + // ignored and go to API call at the end + } else { + baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet(), isToken) + "/" + + card.getCollectorId() + ".jpg"; + alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet(), isToken) + "/" + + card.getCollectorId() + ".jpg"; + } } // double faced cards do not supports by API (need direct link for img) // example: https://img.scryfall.com/cards/large/en/xln/173b.jpg if (baseUrl == null && card.isTwoFacedCard()) { - baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet()) + "/" + baseUrl = "https://img.scryfall.com/cards/large/" + localizedCode + "/" + formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg"; - alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet()) + "/" + alternativeUrl = "https://img.scryfall.com/cards/large/" + defaultCode + "/" + formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + (card.isSecondSide() ? "b" : "a") + ".jpg"; } // basic cards by api call (redirect to img link) // example: https://api.scryfall.com/cards/xln/121/en?format=image if (baseUrl == null) { - baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/" + baseUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + "/" + localizedCode + "?format=image"; - alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet()) + "/" + alternativeUrl = "https://api.scryfall.com/cards/" + formatSetName(card.getSet(), isToken) + "/" + card.getCollectorId() + "/" + defaultCode + "?format=image"; } return new CardImageUrls(baseUrl, alternativeUrl); } + @Override + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { + return innerGenerateURL(card, false); + + } + @Override public CardImageUrls generateTokenUrl(CardDownloadData card) throws Exception { - return null; + return innerGenerateURL(card, true); } @Override @@ -329,7 +137,22 @@ public enum ScryfallImageSource implements CardImageSource { @Override public boolean isTokenSource() { - return false; + return true; + } + + @Override + public boolean isLanguagesSupport() { + return true; + } + + @Override + public void setCurrentLanguage(CardLanguage cardLanguage) { + this.currentLanguage = cardLanguage; + } + + @Override + public CardLanguage getCurrentLanguage() { + return currentLanguage; } @Override @@ -337,131 +160,41 @@ public enum ScryfallImageSource implements CardImageSource { } - private String formatSetName(String setName) { - if (setNameReplacement.containsKey(setName)) { - setName = setNameReplacement.get(setName); + private String formatSetName(String setName, boolean isToken) { + if (isToken) { + // token uses direct link download, not set + return setName.toLowerCase(Locale.ENGLISH); + } else { + return ScryfallImageSupportCards.findScryfallSetCode(setName); } - return setName.toLowerCase(Locale.ENGLISH); } - private static final Map setNameReplacement = new HashMap() { - { - put("DD3GVL", "gvl"); - put("DD3JVC", "jvc"); - put("DD3DVD", "dvd"); - put("DD3EVG", "evg"); - put("MPS-AKH", "mp2"); - put("MBP", "pmei"); - put("WMCQ", "pwcq"); - put("EURO", "pelp"); - put("GPX", "pgpx"); - } - }; - - private static final Map directDownloadLinks = new HashMap() { - { - // direct links to download images for special cards - - // Duels of the Planeswalkers Promos -- xmage uses one set (DPAP), but scryfall store it by years - // 2009 - https://scryfall.com/sets/pdtp - put("DPAP/Garruk Wildspeaker", "https://img.scryfall.com/cards/large/en/pdtp/1.jpg"); - // 2010 - https://scryfall.com/sets/pdp10 - put("DPAP/Liliana Vess", "https://img.scryfall.com/cards/large/en/pdp10/1.jpg"); - put("DPAP/Nissa Revane", "https://img.scryfall.com/cards/large/en/pdp10/2.jpg"); - // 2011 - https://scryfall.com/sets/pdp11 - put("DPAP/Frost Titan", "https://img.scryfall.com/cards/large/en/pdp11/1.jpg"); - put("DPAP/Grave Titan", "https://img.scryfall.com/cards/large/en/pdp11/2.jpg"); - put("DPAP/Inferno Titan", "https://img.scryfall.com/cards/large/en/pdp11/3.jpg"); - // 2012 - https://scryfall.com/sets/pdp12 - put("DPAP/Primordial Hydra", "https://img.scryfall.com/cards/large/en/pdp12/1.jpg"); - put("DPAP/Serra Avatar", "https://img.scryfall.com/cards/large/en/pdp12/2.jpg"); - put("DPAP/Vampire Nocturnus", "https://img.scryfall.com/cards/large/en/pdp12/3.jpg"); - // 2013 - https://scryfall.com/sets/pdp13 - put("DPAP/Bonescythe Sliver", "https://img.scryfall.com/cards/large/en/pdp13/1.jpg"); - put("DPAP/Ogre Battledriver", "https://img.scryfall.com/cards/large/en/pdp13/2.jpg"); - put("DPAP/Scavenging Ooze", "https://img.scryfall.com/cards/large/en/pdp13/3.jpg"); - // 2014 - https://scryfall.com/sets/pdp14 - put("DPAP/Soul of Ravnica", "https://img.scryfall.com/cards/large/en/pdp14/1.jpg"); - put("DPAP/Soul of Zendikar", "https://img.scryfall.com/cards/large/en/pdp14/2.jpg"); - - // Gateway Promos -- xmage uses one set (GRC), but scryfall store it by years - // 2006 - https://scryfall.com/sets/pgtw - put("GRC/Fiery Temper", "https://img.scryfall.com/cards/large/en/pgtw/3.jpg"); - put("GRC/Icatian Javelineers", "https://img.scryfall.com/cards/large/en/pgtw/2.jpg"); - put("GRC/Wood Elves", "https://img.scryfall.com/cards/large/en/pgtw/1.jpg"); - // 2007 - https://scryfall.com/sets/pg07 - put("GRC/Boomerang", "https://img.scryfall.com/cards/large/en/pg07/4.jpg"); - put("GRC/Calciderm", "https://img.scryfall.com/cards/large/en/pg07/5.jpg"); - put("GRC/Dauntless Dourbark", "https://img.scryfall.com/cards/large/en/pg07/12.jpg"); - put("GRC/Llanowar Elves", "https://img.scryfall.com/cards/large/en/pg07/9.jpg"); - put("GRC/Mind Stone", "https://img.scryfall.com/cards/large/en/pg07/11.jpg"); - put("GRC/Mogg Fanatic", "https://img.scryfall.com/cards/large/en/pg07/10.jpg"); - put("GRC/Reckless Wurm", "https://img.scryfall.com/cards/large/en/pg07/6.jpg"); - put("GRC/Yixlid Jailer", "https://img.scryfall.com/cards/large/en/pg07/7.jpg"); - put("GRC/Zoetic Cavern", "https://img.scryfall.com/cards/large/en/pg07/8.jpg"); - // 2008a - https://scryfall.com/sets/pg08 - put("GRC/Boggart Ram-Gang", "https://img.scryfall.com/cards/large/en/pg08/17.jpg"); - put("GRC/Cenn's Tactician", "https://img.scryfall.com/cards/large/en/pg08/14.jpg"); - put("GRC/Duergar Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/19.jpg"); - put("GRC/Gravedigger", "https://img.scryfall.com/cards/large/en/pg08/16.jpg"); - put("GRC/Lava Axe", "https://img.scryfall.com/cards/large/en/pg08/13.jpg"); - put("GRC/Oona's Blackguard", "https://img.scryfall.com/cards/large/en/pg08/15.jpg"); - put("GRC/Selkie Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/20.jpg"); - put("GRC/Wilt-Leaf Cavaliers", "https://img.scryfall.com/cards/large/en/pg08/18.jpg"); - - // Wizards Play Network Promos -- xmage uses one set (GRC), but scryfall store it by years - // 2008b - https://scryfall.com/sets/pwpn - put("GRC/Sprouting Thrinax", "https://img.scryfall.com/cards/large/en/pwpn/21.jpg"); - put("GRC/Woolly Thoctar", "https://img.scryfall.com/cards/large/en/pwpn/22.jpg"); - // 2009 - https://scryfall.com/sets/pwp09 - put("GRC/Hellspark Elemental", "https://img.scryfall.com/cards/large/en/pwp09/25.jpg"); - put("GRC/Kor Duelist", "https://img.scryfall.com/cards/large/en/pwp09/32.jpg"); - put("GRC/Marisi's Twinclaws", "https://img.scryfall.com/cards/large/en/pwp09/26.jpg"); - put("GRC/Mind Control", "https://img.scryfall.com/cards/large/en/pwp09/30.jpg"); - put("GRC/Path to Exile", "https://img.scryfall.com/cards/large/en/pwp09/24.jpg"); - put("GRC/Rise from the Grave", "https://img.scryfall.com/cards/large/en/pwp09/31.jpg"); - put("GRC/Slave of Bolas", "https://img.scryfall.com/cards/large/en/pwp09/27.jpg"); - put("GRC/Vampire Nighthawk", "https://img.scryfall.com/cards/large/en/pwp09/33.jpg"); - // 2010 - https://scryfall.com/sets/pwp10 - put("GRC/Kor Firewalker", "https://img.scryfall.com/cards/large/en/pwp10/36.jpg"); - put("GRC/Leatherback Baloth", "https://img.scryfall.com/cards/large/en/pwp10/37.jpg"); - put("GRC/Syphon Mind", "https://img.scryfall.com/cards/large/en/pwp10/40.jpg"); - put("GRC/Pathrazer of Ulamog", "https://img.scryfall.com/cards/large/en/pwp10/46.jpg"); - put("GRC/Curse of Wizardry", "https://img.scryfall.com/cards/large/en/pwp10/47.jpg"); - put("GRC/Fling/50", "https://img.scryfall.com/cards/large/en/pwp10/50.jpg"); // same card but different year - put("GRC/Sylvan Ranger/51", "https://img.scryfall.com/cards/large/en/pwp10/51.jpg"); // same card but different year - put("GRC/Plague Stinger", "https://img.scryfall.com/cards/large/en/pwp10/59.jpg"); - put("GRC/Golem's Heart", "https://img.scryfall.com/cards/large/en/pwp10/60.jpg"); - put("GRC/Skinrender", "https://img.scryfall.com/cards/large/en/pwp10/63.jpg"); - // 2011 - https://scryfall.com/sets/pwp11 - put("GRC/Auramancer", "https://img.scryfall.com/cards/large/en/pwp11/77.jpg"); - put("GRC/Bloodcrazed Neonate", "https://img.scryfall.com/cards/large/en/pwp11/83.jpg"); - put("GRC/Boneyard Wurm", "https://img.scryfall.com/cards/large/en/pwp11/84.jpg"); - put("GRC/Circle of Flame", "https://img.scryfall.com/cards/large/en/pwp11/78.jpg"); - put("GRC/Curse of the Bloody Tome", "https://img.scryfall.com/cards/large/en/pwp11/80.jpg"); - put("GRC/Fling/69", "https://img.scryfall.com/cards/large/en/pwp11/69.jpg"); // same card but different year - put("GRC/Master's Call", "https://img.scryfall.com/cards/large/en/pwp11/64.jpg"); - put("GRC/Maul Splicer", "https://img.scryfall.com/cards/large/en/pwp11/72.jpg"); - put("GRC/Plague Myr", "https://img.scryfall.com/cards/large/en/pwp11/65.jpg"); - put("GRC/Shrine of Burning Rage", "https://img.scryfall.com/cards/large/en/pwp11/73.jpg"); - put("GRC/Signal Pest", "https://img.scryfall.com/cards/large/en/pwp11/66.jpg"); - put("GRC/Sylvan Ranger/70", "https://img.scryfall.com/cards/large/en/pwp11/70.jpg"); // same card but different year - put("GRC/Tormented Soul", "https://img.scryfall.com/cards/large/en/pwp11/76.jpg"); - put("GRC/Vault Skirge", "https://img.scryfall.com/cards/large/en/pwp11/71.jpg"); - // 2012 - https://scryfall.com/sets/pwp12 - put("GRC/Curse of Thirst", "https://img.scryfall.com/cards/large/en/pwp12/81.jpg"); - put("GRC/Gather the Townsfolk", "https://img.scryfall.com/cards/large/en/pwp12/79.jpg"); - put("GRC/Nearheath Stalker", "https://img.scryfall.com/cards/large/en/pwp12/82.jpg"); - - // TODO: remove Grand Prix fix after scryfall fix image's link (that's link must be work: https://img.scryfall.com/cards/large/en/pgpx/2016b.jpg ) - put("GPX/Sword of Feast and Famine", "https://img.scryfall.com/cards/large/en/pgpx/1%E2%98%85.jpg"); - } - }; - @Override public ArrayList getSupportedSets() { ArrayList supportedSetsCopy = new ArrayList<>(); - supportedSetsCopy.addAll(supportedSets); + + // cards + supportedSetsCopy.addAll(ScryfallImageSupportCards.getSupportedSets()); + + // tokens + for (String code : ScryfallImageSupportTokens.getSupportedSets().keySet()) { + if (!supportedSetsCopy.contains(code)) { + supportedSetsCopy.add(code); + } + } + return supportedSetsCopy; } + + @Override + public boolean isCardImageProvided(String setCode, String cardName) { + // all cards from set + return ScryfallImageSupportCards.getSupportedSets().contains(setCode); + } + + @Override + public boolean isTokenImageProvided(String setCode, String cardName, Integer tokenNumber) { + // only direct tokens from set + return ScryfallImageSupportTokens.findTokenLink(setCode, cardName, tokenNumber) != null; + } } 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 new file mode 100644 index 0000000000..2f847fc3ee --- /dev/null +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportCards.java @@ -0,0 +1,395 @@ +package org.mage.plugins.card.dl.sources; + +import com.google.common.collect.ImmutableMap; +import org.tritonus.share.ArraySet; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Set; + +/** + * @author JayDi85 + */ +public class ScryfallImageSupportCards { + + private static final Map xmageSetsToScryfall = ImmutableMap.builder().put("DD3GVL", "gvl"). + put("DD3JVC", "jvc"). + put("DD3DVD", "dvd"). + put("DD3EVG", "evg"). + put("MPS-AKH", "mp2"). + put("MBP", "pmei"). + put("WMCQ", "pwcq"). + put("EURO", "pelp"). + put("GPX", "pgpx"). + put("MED", "me1"). + put("MEDM", "med").build(); + + + + private static final Set supportedSets = new ArraySet() { + { + // xmage set codes + // add("PTC"); // + add("LEA"); + add("LEB"); + add("2ED"); + add("ARN"); + add("ATQ"); + add("3ED"); + add("LEG"); + add("DRK"); + add("FEM"); + add("4ED"); + add("ICE"); + add("CHR"); + add("HML"); + add("ALL"); + add("MIR"); + add("VIS"); + add("5ED"); + add("POR"); + add("WTH"); + add("TMP"); + add("STH"); + add("EXO"); + add("P02"); + add("UGL"); + add("USG"); + add("DD3DVD"); + add("DD3EVG"); + add("DD3GVL"); + add("DD3JVC"); + + add("ULG"); + add("6ED"); + add("UDS"); + add("PTK"); + add("S99"); + add("MMQ"); + // add("BRB");Battle Royale Box Set + add("NEM"); + add("S00"); + add("PCY"); + add("INV"); + // add("BTD"); // Beatdown Boxset + add("PLS"); + add("7ED"); + add("APC"); + add("ODY"); + // add("DKM"); // Deckmasters 2001 + add("TOR"); + add("JUD"); + add("ONS"); + add("LGN"); + add("SCG"); + add("8ED"); + add("MRD"); + add("DST"); + add("5DN"); + add("CHK"); + add("UNH"); + add("BOK"); + add("SOK"); + add("9ED"); + add("RAV"); + add("GPT"); + add("DIS"); + add("CSP"); + add("TSP"); + add("TSB"); + add("PLC"); + add("FUT"); + add("10E"); + add("MED"); + add("LRW"); + add("EVG"); + add("MOR"); + add("SHM"); + add("EVE"); + add("DRB"); + add("ME2"); + add("ALA"); + add("DD2"); + add("CON"); + add("DDC"); + add("ARB"); + add("M10"); + // add("TD0"); // Magic Online Deck Series + add("V09"); + add("HOP"); + add("ME3"); + add("ZEN"); + add("DDD"); + add("H09"); + add("WWK"); + add("DDE"); + add("ROE"); + // duels of the planewalkers: + add("DPA"); + add("DPAP"); + // + add("ARC"); + add("M11"); + add("V10"); + add("DDF"); + add("SOM"); + // add("TD0"); // Commander Theme Decks + add("PD2"); + add("ME4"); + add("MBS"); + add("DDG"); + add("NPH"); + add("CMD"); + add("M12"); + add("V11"); + add("DDH"); + add("ISD"); + add("PD3"); + add("DKA"); + add("DDI"); + add("AVR"); + add("PC2"); + add("M13"); + add("V12"); + add("DDJ"); + add("RTR"); + add("CM1"); + // add("TD2"); // Duel Decks: Mirrodin Pure vs. New Phyrexia + add("GTC"); + add("DDK"); + add("DGM"); + add("MMA"); + add("M14"); + add("V13"); + add("DDL"); + add("THS"); + add("C13"); + add("BNG"); + add("DDM"); + add("JOU"); + // add("MD1"); // Modern Event Deck + add("CNS"); + add("VMA"); + add("M15"); + add("V14"); + add("DDN"); + add("KTK"); + add("C14"); + // add("DD3"); // Duel Decks Anthology + add("FRF"); + add("DDO"); + add("DTK"); + add("TPR"); + add("MM2"); + add("ORI"); + add("V15"); + add("DDP"); + add("BFZ"); + add("EXP"); + add("C15"); + // add("PZ1"); // Legendary Cube + add("OGW"); + add("DDQ"); + add("W16"); + add("SOI"); + add("EMA"); + add("EMN"); + add("V16"); + add("CN2"); + add("DDR"); + add("KLD"); + add("MPS"); + // add("PZ2"); + add("C16"); + add("PCA"); + add("AER"); + add("MM3"); + add("DDS"); + add("W17"); + add("AKH"); + add("CMA"); + add("E01"); + add("HOU"); + add("C17"); + add("XLN"); + add("DDT"); + add("IMA"); + add("E02"); + add("V17"); + add("UST"); + add("DDU"); + add("RIX"); + add("WMCQ"); + add("PPRO"); + add("A25"); + add("DOM"); + add("BBD"); + add("C18"); + add("CM2"); + add("M19"); + add("GS1"); + add("GRN"); + add("GK1"); + add("GNT"); + add("UMA"); + add("PUMA"); + add("RNA"); + add("MEDM"); + add("GK2"); + add("MH1"); + add("WAR"); + // + add("EURO"); + add("GPX"); + add("ATH"); + add("GRC"); + add("ANA"); + } + }; + + private static final Map directDownloadLinks = new HashMap() { + { + // xmage card -> direct or api link: + // examples: + // direct example: https://img.scryfall.com/cards/large/en/trix/6.jpg + // api example: https://api.scryfall.com/cards/trix/6/en?format=image + // api example: https://api.scryfall.com/cards/trix/6?format=image + // api format is primary + // + // code form for one card: + // set/card_name + // + // code form for same name cards (alternative images): + // set/card_name/card_number + // set/card_name/card_number + + // Duels of the Planeswalkers Promos -- xmage uses one set (DPAP), but scryfall store it by years + // 2009 - https://scryfall.com/sets/pdtp + put("DPAP/Garruk Wildspeaker", "https://img.scryfall.com/cards/large/en/pdtp/1.jpg"); + // 2010 - https://scryfall.com/sets/pdp10 + put("DPAP/Liliana Vess", "https://img.scryfall.com/cards/large/en/pdp10/1.jpg"); + put("DPAP/Nissa Revane", "https://img.scryfall.com/cards/large/en/pdp10/2.jpg"); + // 2011 - https://scryfall.com/sets/pdp11 + put("DPAP/Frost Titan", "https://img.scryfall.com/cards/large/en/pdp11/1.jpg"); + put("DPAP/Grave Titan", "https://img.scryfall.com/cards/large/en/pdp11/2.jpg"); + put("DPAP/Inferno Titan", "https://img.scryfall.com/cards/large/en/pdp11/3.jpg"); + // 2012 - https://scryfall.com/sets/pdp12 + put("DPAP/Primordial Hydra", "https://img.scryfall.com/cards/large/en/pdp12/1.jpg"); + put("DPAP/Serra Avatar", "https://img.scryfall.com/cards/large/en/pdp12/2.jpg"); + put("DPAP/Vampire Nocturnus", "https://img.scryfall.com/cards/large/en/pdp12/3.jpg"); + // 2013 - https://scryfall.com/sets/pdp13 + put("DPAP/Bonescythe Sliver", "https://img.scryfall.com/cards/large/en/pdp13/1.jpg"); + put("DPAP/Ogre Battledriver", "https://img.scryfall.com/cards/large/en/pdp13/2.jpg"); + put("DPAP/Scavenging Ooze", "https://img.scryfall.com/cards/large/en/pdp13/3.jpg"); + // 2014 - https://scryfall.com/sets/pdp14 + put("DPAP/Soul of Ravnica", "https://img.scryfall.com/cards/large/en/pdp14/1.jpg"); + put("DPAP/Soul of Zendikar", "https://img.scryfall.com/cards/large/en/pdp14/2.jpg"); + + // Gateway Promos -- xmage uses one set (GRC), but scryfall store it by years + // 2006 - https://scryfall.com/sets/pgtw + put("GRC/Fiery Temper", "https://img.scryfall.com/cards/large/en/pgtw/3.jpg"); + put("GRC/Icatian Javelineers", "https://img.scryfall.com/cards/large/en/pgtw/2.jpg"); + put("GRC/Wood Elves", "https://img.scryfall.com/cards/large/en/pgtw/1.jpg"); + // 2007 - https://scryfall.com/sets/pg07 + put("GRC/Boomerang", "https://img.scryfall.com/cards/large/en/pg07/4.jpg"); + put("GRC/Calciderm", "https://img.scryfall.com/cards/large/en/pg07/5.jpg"); + put("GRC/Dauntless Dourbark", "https://img.scryfall.com/cards/large/en/pg07/12.jpg"); + put("GRC/Llanowar Elves", "https://img.scryfall.com/cards/large/en/pg07/9.jpg"); + put("GRC/Mind Stone", "https://img.scryfall.com/cards/large/en/pg07/11.jpg"); + put("GRC/Mogg Fanatic", "https://img.scryfall.com/cards/large/en/pg07/10.jpg"); + put("GRC/Reckless Wurm", "https://img.scryfall.com/cards/large/en/pg07/6.jpg"); + put("GRC/Yixlid Jailer", "https://img.scryfall.com/cards/large/en/pg07/7.jpg"); + put("GRC/Zoetic Cavern", "https://img.scryfall.com/cards/large/en/pg07/8.jpg"); + // 2008a - https://scryfall.com/sets/pg08 + put("GRC/Boggart Ram-Gang", "https://img.scryfall.com/cards/large/en/pg08/17.jpg"); + put("GRC/Cenn's Tactician", "https://img.scryfall.com/cards/large/en/pg08/14.jpg"); + put("GRC/Duergar Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/19.jpg"); + put("GRC/Gravedigger", "https://img.scryfall.com/cards/large/en/pg08/16.jpg"); + put("GRC/Lava Axe", "https://img.scryfall.com/cards/large/en/pg08/13.jpg"); + put("GRC/Oona's Blackguard", "https://img.scryfall.com/cards/large/en/pg08/15.jpg"); + put("GRC/Selkie Hedge-Mage", "https://img.scryfall.com/cards/large/en/pg08/20.jpg"); + put("GRC/Wilt-Leaf Cavaliers", "https://img.scryfall.com/cards/large/en/pg08/18.jpg"); + + // Wizards Play Network Promos -- xmage uses one set (GRC), but scryfall store it by years + // 2008b - https://scryfall.com/sets/pwpn + put("GRC/Sprouting Thrinax", "https://img.scryfall.com/cards/large/en/pwpn/21.jpg"); + put("GRC/Woolly Thoctar", "https://img.scryfall.com/cards/large/en/pwpn/22.jpg"); + // 2009 - https://scryfall.com/sets/pwp09 + put("GRC/Hellspark Elemental", "https://img.scryfall.com/cards/large/en/pwp09/25.jpg"); + put("GRC/Kor Duelist", "https://img.scryfall.com/cards/large/en/pwp09/32.jpg"); + put("GRC/Marisi's Twinclaws", "https://img.scryfall.com/cards/large/en/pwp09/26.jpg"); + put("GRC/Mind Control", "https://img.scryfall.com/cards/large/en/pwp09/30.jpg"); + put("GRC/Path to Exile", "https://img.scryfall.com/cards/large/en/pwp09/24.jpg"); + put("GRC/Rise from the Grave", "https://img.scryfall.com/cards/large/en/pwp09/31.jpg"); + put("GRC/Slave of Bolas", "https://img.scryfall.com/cards/large/en/pwp09/27.jpg"); + put("GRC/Vampire Nighthawk", "https://img.scryfall.com/cards/large/en/pwp09/33.jpg"); + // 2010 - https://scryfall.com/sets/pwp10 + put("GRC/Kor Firewalker", "https://img.scryfall.com/cards/large/en/pwp10/36.jpg"); + put("GRC/Leatherback Baloth", "https://img.scryfall.com/cards/large/en/pwp10/37.jpg"); + put("GRC/Syphon Mind", "https://img.scryfall.com/cards/large/en/pwp10/40.jpg"); + put("GRC/Pathrazer of Ulamog", "https://img.scryfall.com/cards/large/en/pwp10/46.jpg"); + put("GRC/Curse of Wizardry", "https://img.scryfall.com/cards/large/en/pwp10/47.jpg"); + put("GRC/Fling/50", "https://img.scryfall.com/cards/large/en/pwp10/50.jpg"); // same card but different year + put("GRC/Sylvan Ranger/51", "https://img.scryfall.com/cards/large/en/pwp10/51.jpg"); // same card but different year + put("GRC/Plague Stinger", "https://img.scryfall.com/cards/large/en/pwp10/59.jpg"); + put("GRC/Golem's Heart", "https://img.scryfall.com/cards/large/en/pwp10/60.jpg"); + put("GRC/Skinrender", "https://img.scryfall.com/cards/large/en/pwp10/63.jpg"); + // 2011 - https://scryfall.com/sets/pwp11 + put("GRC/Auramancer", "https://img.scryfall.com/cards/large/en/pwp11/77.jpg"); + put("GRC/Bloodcrazed Neonate", "https://img.scryfall.com/cards/large/en/pwp11/83.jpg"); + put("GRC/Boneyard Wurm", "https://img.scryfall.com/cards/large/en/pwp11/84.jpg"); + put("GRC/Circle of Flame", "https://img.scryfall.com/cards/large/en/pwp11/78.jpg"); + put("GRC/Curse of the Bloody Tome", "https://img.scryfall.com/cards/large/en/pwp11/80.jpg"); + put("GRC/Fling/69", "https://img.scryfall.com/cards/large/en/pwp11/69.jpg"); // same card but different year + put("GRC/Master's Call", "https://img.scryfall.com/cards/large/en/pwp11/64.jpg"); + put("GRC/Maul Splicer", "https://img.scryfall.com/cards/large/en/pwp11/72.jpg"); + put("GRC/Plague Myr", "https://img.scryfall.com/cards/large/en/pwp11/65.jpg"); + put("GRC/Shrine of Burning Rage", "https://img.scryfall.com/cards/large/en/pwp11/73.jpg"); + put("GRC/Signal Pest", "https://img.scryfall.com/cards/large/en/pwp11/66.jpg"); + put("GRC/Sylvan Ranger/70", "https://img.scryfall.com/cards/large/en/pwp11/70.jpg"); // same card but different year + put("GRC/Tormented Soul", "https://img.scryfall.com/cards/large/en/pwp11/76.jpg"); + put("GRC/Vault Skirge", "https://img.scryfall.com/cards/large/en/pwp11/71.jpg"); + // 2012 - https://scryfall.com/sets/pwp12 + put("GRC/Curse of Thirst", "https://img.scryfall.com/cards/large/en/pwp12/81.jpg"); + put("GRC/Gather the Townsfolk", "https://img.scryfall.com/cards/large/en/pwp12/79.jpg"); + put("GRC/Nearheath Stalker", "https://img.scryfall.com/cards/large/en/pwp12/82.jpg"); + + // TODO: remove Grand Prix fix after scryfall fix image's link (that's link must be work: https://img.scryfall.com/cards/large/en/pgpx/2016b.jpg ) + put("GPX/Sword of Feast and Famine", "https://img.scryfall.com/cards/large/en/pgpx/1%E2%98%85.jpg"); + + // TODO: remove after scryfall add lands to RNA (that's link must works: https://api.scryfall.com/cards/rna/262/en?format=image) + put("RNA/Plains", "https://api.scryfall.com/cards/grn/260/en?format=image"); + put("RNA/Island", "https://api.scryfall.com/cards/grn/261/en?format=image"); + put("RNA/Swamp", "https://api.scryfall.com/cards/grn/262/en?format=image"); + put("RNA/Mountain", "https://api.scryfall.com/cards/grn/263/en?format=image"); + put("RNA/Forest", "https://api.scryfall.com/cards/grn/264/en?format=image"); + } + }; + + public static String findScryfallSetCode(String xmageCode) { + return xmageSetsToScryfall.getOrDefault(xmageCode, xmageCode).toLowerCase(Locale.ENGLISH); + } + + public static Set getSupportedSets() { + return supportedSets; + } + + public static String findDirectDownloadLink(String setCode, String cardName, String cardNumber) { + + // set/card/number + String linkCode1 = setCode + "/" + cardName + "/" + cardNumber; + if (directDownloadLinks.containsKey(linkCode1)) { + return directDownloadLinks.get(linkCode1); + } + + // set/card + String linkCode2 = setCode + "/" + cardName; + if (directDownloadLinks.containsKey(linkCode2)) { + return directDownloadLinks.get(linkCode2); + } + + // default + return null; + } +} 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 new file mode 100644 index 0000000000..6be07dc523 --- /dev/null +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallImageSupportTokens.java @@ -0,0 +1,92 @@ +package org.mage.plugins.card.dl.sources; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author JayDi85 + */ +public class ScryfallImageSupportTokens { + + private static final Map supportedSets = new HashMap<>(); + + private static final Map supportedCards = new HashMap() { + { + // xmage token -> direct or api link: + // examples: + // direct example: https://img.scryfall.com/cards/large/en/trix/6.jpg + // api example: https://api.scryfall.com/cards/trix/6/en?format=image + // api example: https://api.scryfall.com/cards/trix/6?format=image + // api format is primary + // + // code form for one token: + // set/token_name + // + // code form for same name tokens (alternative images): + // set/token_name/1 + // set/token_name/2 + + // RIX + put("RIX/City's Blessing", "https://api.scryfall.com/cards/trix/6/en?format=image"); // TODO: missing from tokens data + 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"); + put("RIX/Emblem Huatli, Radiant Champion", "https://api.scryfall.com/cards/trix/5/en?format=image"); + put("RIX/Saproling", "https://api.scryfall.com/cards/trix/3/en?format=image"); + + // RNA + put("RNA/Beast", "https://api.scryfall.com/cards/trna/8/en?format=image"); + put("RNA/Centaur", "https://api.scryfall.com/cards/trna/5/en?format=image"); + put("RNA/Emblem Domri, Chaos Bringer", "https://api.scryfall.com/cards/trna/13/en?format=image"); + put("RNA/Frog Lizard", "https://api.scryfall.com/cards/trna/6/en?format=image"); + put("RNA/Goblin", "https://api.scryfall.com/cards/trna/4/en?format=image"); + put("RNA/Human", "https://api.scryfall.com/cards/trna/1/en?format=image"); + put("RNA/Illusion", "https://api.scryfall.com/cards/trna/2/en?format=image"); + put("RNA/Ooze", "https://api.scryfall.com/cards/trna/7/en?format=image"); + put("RNA/Sphinx", "https://api.scryfall.com/cards/trna/9/en?format=image"); + put("RNA/Spirit", "https://api.scryfall.com/cards/trna/10/en?format=image"); + put("RNA/Thopter", "https://api.scryfall.com/cards/trna/11/en?format=image"); + put("RNA/Treasure", "https://api.scryfall.com/cards/trna/12/en?format=image"); + put("RNA/Zombie", "https://api.scryfall.com/cards/trna/3/en?format=image"); + + // WAR + put("WAR/Angel", "https://api.scryfall.com/cards/twar/2/en?format=image"); + put("WAR/Assassin", "https://api.scryfall.com/cards/twar/6/en?format=image"); + put("WAR/Citizen", "https://api.scryfall.com/cards/twar/16/en?format=image"); + put("WAR/Devil", "https://api.scryfall.com/cards/twar/12/en?format=image"); + put("WAR/Dragon", "https://api.scryfall.com/cards/twar/13/en?format=image"); + put("WAR/Goblin", "https://api.scryfall.com/cards/twar/14/en?format=image"); + put("WAR/Emblem Nissa, Who Shakes the World", "https://api.scryfall.com/cards/twar/19/en?format=image"); + put("WAR/Servo", "https://api.scryfall.com/cards/twar/18/en?format=image"); + put("WAR/Soldier", "https://api.scryfall.com/cards/twar/3/en?format=image"); + put("WAR/Spirit", "https://api.scryfall.com/cards/twar/1/en?format=image"); + put("WAR/Voja, Friend to Elves", "https://api.scryfall.com/cards/twar/17/en?format=image"); + put("WAR/Wall", "https://api.scryfall.com/cards/twar/4/en?format=image"); + put("WAR/Wizard", "https://api.scryfall.com/cards/twar/5/en?format=image"); + put("WAR/Wolf", "https://api.scryfall.com/cards/twar/15/en?format=image"); + put("WAR/Zombie Army/1", "https://api.scryfall.com/cards/twar/10/en?format=image"); + put("WAR/Zombie Army/2", "https://api.scryfall.com/cards/twar/8/en?format=image"); + put("WAR/Zombie Army/3", "https://api.scryfall.com/cards/twar/9/en?format=image"); + put("WAR/Zombie Warrior", "https://api.scryfall.com/cards/twar/11/en?format=image"); + put("WAR/Zombie", "https://api.scryfall.com/cards/twar/7/en?format=image"); + + // generate supported sets + supportedSets.clear(); + for (String cardName : this.keySet()) { + String[] s = cardName.split("\\/"); + if (s.length > 1) { + supportedSets.putIfAbsent(s[0], s[0]); + } + } + } + }; + + public static Map getSupportedSets() { + return supportedSets; + } + + public static String findTokenLink(String setCode, String tokenName, Integer tokenNumber) { + String search = setCode + "/" + tokenName + (!tokenNumber.equals(0) ? "/" + tokenNumber : ""); + return supportedCards.getOrDefault(search, null); + } +} diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java index 483bb27e86..714310c5a8 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/ScryfallSymbolsSource.java @@ -70,10 +70,7 @@ public class ScryfallSymbolsSource implements Iterable { } // gen symbols list - ArrayList allMageSymbols = new ArrayList<>(); - for (int i = 0; i < SYMBOLS_LIST.length; i++) { - allMageSymbols.add(SYMBOLS_LIST[i]); - } + List allMageSymbols = new ArrayList<>(Arrays.asList(SYMBOLS_LIST)); for (Integer i = SYMBOLS_NUMBER_START; i <= SYMBOLS_NUMBER_END; i++) { allMageSymbols.add(String.valueOf(SYMBOLS_NUMBER_START + i)); } @@ -111,21 +108,17 @@ public class ScryfallSymbolsSource implements Iterable { if (destFile.exists() && (destFile.length() > 0)) { continue; } - FileOutputStream stream = null; - try { + try(FileOutputStream stream = new FileOutputStream(destFile)) { // base64 transform String data64 = foundedData.get(searchCode); Base64.Decoder dec = Base64.getDecoder(); byte[] fileData = dec.decode(data64); - stream = new FileOutputStream(destFile); stream.write(fileData); LOGGER.info("New svg symbol downloaded: " + needCode); } catch (Exception e) { LOGGER.error("Can't decode svg icon and save to file: " + destFile.getPath() + ", reason: " + e.getMessage()); - } finally { - StreamUtils.closeQuietly(stream); } } } @@ -166,7 +159,7 @@ public class ScryfallSymbolsSource implements Iterable { org.jsoup.nodes.Document doc = CardImageUtils.downloadHtmlDocument(CSS_SOURCE_URL); org.jsoup.select.Elements cssList = doc.select(CSS_SOURCE_SELECTOR); if (cssList.size() == 1) { - this.cssUrl = cssList.first().attr("href").toString(); + this.cssUrl = cssList.first().attr("href"); } if (this.cssUrl.isEmpty()) { diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java index da76bfc8b6..5ac33a0b0a 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/TokensMtgImageSource.java @@ -1,6 +1,11 @@ - package org.mage.plugins.card.dl.sources; +import mage.constants.SubType; +import org.apache.log4j.Logger; +import org.mage.plugins.card.images.CardDownloadData; +import org.mage.plugins.card.images.DownloadPicturesService; +import org.mage.plugins.card.utils.CardImageUtils; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; @@ -8,21 +13,9 @@ import java.io.InputStreamReader; import java.net.Proxy; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.logging.Level; -import mage.constants.SubType; -import org.apache.log4j.Logger; -import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.images.DownloadPictures; -import org.mage.plugins.card.utils.CardImageUtils; - /** * @author Quercitron */ @@ -32,7 +25,7 @@ public enum TokensMtgImageSource implements CardImageSource { private static final Logger logger = Logger.getLogger(TokensMtgImageSource.class); // [[EXP/Name, TokenData> - private HashMap> tokensData; + private HashMap> tokensData; private static final Set supportedSets = new LinkedHashSet(); private final Object tokensDataSync = new Object(); @@ -58,7 +51,7 @@ public enum TokensMtgImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { return null; } @@ -71,7 +64,7 @@ public enum TokensMtgImageSource implements CardImageSource { private String getEmblemName(String originalName) { - for (SubType subType : SubType.getPlaneswalkerTypes(true)) { + for (SubType subType : SubType.getPlaneswalkerTypes()) { if (originalName.toLowerCase(Locale.ENGLISH).contains(subType.toString().toLowerCase(Locale.ENGLISH))) { return subType.getDescription() + " Emblem"; } @@ -96,7 +89,7 @@ public enum TokensMtgImageSource implements CardImageSource { } // Image URL contains token number - // e.g. http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg -- token number 010 + // e.g. https://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg -- token number 010 // We don't know these numbers, but we can take them from a file // with tokens information that can be downloaded from the site. if (tokensData.isEmpty()) { @@ -122,7 +115,7 @@ public enum TokensMtgImageSource implements CardImageSource { tokenData = list.get(card.getType() - 1); } - String url = "http://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_' + String url = "https://tokens.mtg.onl/tokens/" + tokenData.getExpansionSetCode().trim() + '_' + tokenData.getNumber().trim() + '-' + tokenData.getName().trim() + ".jpg"; url = url.replace(' ', '-'); return new CardImageUrls(url); @@ -160,7 +153,12 @@ public enum TokensMtgImageSource implements CardImageSource { } @Override - public boolean isImageProvided(String setCode, String cardName) { + public boolean isCardImageProvided(String setCode, String cardName) { + return false; + } + + @Override + public boolean isTokenImageProvided(String setCode, String cardName, Integer tokenNumber) { String searchName = cardName; if (cardName.toLowerCase(Locale.ENGLISH).contains("emblem")) { searchName = getEmblemName(cardName); @@ -179,10 +177,10 @@ public enum TokensMtgImageSource implements CardImageSource { return false; } - private HashMap> getTokensData() throws IOException { + private HashMap> getTokensData() throws IOException { synchronized (tokensDataSync) { if (tokensData == null) { - DownloadPictures.getInstance().updateAndViewMessage("Creating token data..."); + DownloadPicturesService.getInstance().updateAndViewMessage("Find tokens data..."); tokensData = new HashMap<>(); // get tokens data from resource file @@ -190,7 +188,7 @@ public enum TokensMtgImageSource implements CardImageSource { List fileTokensData = parseTokensData(inputStream); for (TokenData tokenData : fileTokensData) { String key = tokenData.getExpansionSetCode() + "/" + tokenData.getName(); - ArrayList list = tokensData.get(key); + List list = tokensData.get(key); if (list == null) { list = new ArrayList<>(); tokensData.put(key, list); @@ -215,7 +213,7 @@ public enum TokensMtgImageSource implements CardImageSource { // logger.info("TOK: " + siteData.getExpansionSetCode() + "/" + siteData.getName()); String key = siteData.getExpansionSetCode() + "/" + siteData.getName(); supportedSets.add(siteData.getExpansionSetCode()); - ArrayList list = tokensData.get(key); + List list = tokensData.get(key); if (list == null) { list = new ArrayList<>(); tokensData.put(key, list); @@ -233,10 +231,10 @@ public enum TokensMtgImageSource implements CardImageSource { } } } - DownloadPictures.getInstance().updateAndViewMessage(""); + DownloadPicturesService.getInstance().updateAndViewMessage(""); } catch (Exception ex) { logger.warn("Failed to get tokens description from tokens.mtg.onl", ex); - DownloadPictures.getInstance().updateAndViewMessage(ex.getMessage()); + DownloadPicturesService.getInstance().updateAndViewMessage(ex.getMessage()); } } } @@ -251,7 +249,7 @@ public enum TokensMtgImageSource implements CardImageSource { BufferedReader reader = new BufferedReader(inputReader)) { // we have to specify encoding to read special comma - reader.readLine(); // skip header + String header = reader.readLine(); // skip header String line = reader.readLine(); // states // 0 - wait set name diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java index 5d39a943f6..0d434ec1c0 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/dl/sources/WizardCardsImageSource.java @@ -1,22 +1,10 @@ package org.mage.plugins.card.dl.sources; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import mage.cards.Sets; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import org.apache.log4j.Logger; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -24,6 +12,12 @@ import org.jsoup.select.Elements; import org.mage.plugins.card.images.CardDownloadData; import org.mage.plugins.card.utils.CardImageUtils; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + /** * @author North */ @@ -34,9 +28,10 @@ public enum WizardCardsImageSource implements CardImageSource { private static final Logger logger = Logger.getLogger(WizardCardsImageSource.class); private final Map setsAliases; - private final Map languageAliases; + private final Map languageAliases; private final Map> sets; private final Set supportedSets; + private CardLanguage currentLanguage = CardLanguage.ENGLISH; // working language @Override public String getSourceName() { @@ -44,6 +39,20 @@ public enum WizardCardsImageSource implements CardImageSource { } WizardCardsImageSource() { + + languageAliases = new EnumMap<>(CardLanguage.class); + languageAliases.put(CardLanguage.ENGLISH, "English"); + languageAliases.put(CardLanguage.SPANISH, "Spanish"); + languageAliases.put(CardLanguage.FRENCH, "French"); + languageAliases.put(CardLanguage.GERMAN, "German"); + languageAliases.put(CardLanguage.ITALIAN, "Italian"); + languageAliases.put(CardLanguage.PORTUGUESE, "Portuguese (Brazil)"); + languageAliases.put(CardLanguage.JAPANESE, "Japanese"); + languageAliases.put(CardLanguage.KOREAN, "Korean"); + languageAliases.put(CardLanguage.RUSSIAN, "Russian"); + languageAliases.put(CardLanguage.CHINES_SIMPLE, "Chinese Simplified"); + languageAliases.put(CardLanguage.CHINES_TRADITION, "Chinese Traditional "); + supportedSets = new LinkedHashSet<>(); // supportedSets.add("PTC"); // Prerelease Events supportedSets.add("LEA"); @@ -430,18 +439,6 @@ public enum WizardCardsImageSource implements CardImageSource { setsAliases.put("WTH", "Weatherlight"); setsAliases.put("WWK", "Worldwake"); setsAliases.put("ZEN", "Zendikar"); - - languageAliases = new HashMap<>(); - languageAliases.put("en", "English"); - languageAliases.put("es", "Spanish"); - languageAliases.put("jp", "Japanese"); - languageAliases.put("it", "Italian"); - languageAliases.put("fr", "French"); - languageAliases.put("cn", "Chinese Simplified"); - languageAliases.put("de", "German"); - languageAliases.put("ko", "Korean"); - languageAliases.put("pt", "Portuguese (Brazil)"); - languageAliases.put("ru", "Russian"); } @Override @@ -455,7 +452,7 @@ public enum WizardCardsImageSource implements CardImageSource { } @Override - public CardImageUrls generateURL(CardDownloadData card) throws Exception { + public CardImageUrls generateCardUrl(CardDownloadData card) throws Exception { String collectorId = card.getCollectorId(); String cardSet = card.getSet(); if (collectorId == null || cardSet == null) { @@ -517,7 +514,7 @@ public enum WizardCardsImageSource implements CardImageSource { if (setNames == null) { setNames = Sets.getInstance().get(cardSet).getName(); } - String preferredLanguage = PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_PREF_LANGUAGE, "en"); + for (String setName : setNames.split("\\^")) { // String URLSetName = URLEncoder.encode(setName, "UTF-8"); String URLSetName = setName.replaceAll(" ", "%20"); @@ -547,15 +544,15 @@ public enum WizardCardsImageSource implements CardImageSource { getLandVariations(setLinks, cardSet, multiverseId, cardName); } else { String numberChar = ""; - int pos1 = cardName.indexOf("("); + int pos1 = cardName.indexOf('('); if (pos1 > 0) { - int pos2 = cardName.indexOf("(", pos1 + 1); + int pos2 = cardName.indexOf('(', pos1 + 1); if (pos2 > 0) { numberChar = cardName.substring(pos2 + 1, pos2 + 2); cardName = cardName.substring(0, pos1); } } - Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId); + Integer preferredMultiverseId = getLocalizedMultiverseId(getCurrentLanguage(), multiverseId); setLinks.put(cardName.toLowerCase(Locale.ENGLISH) + numberChar, generateLink(preferredMultiverseId)); } } @@ -617,8 +614,8 @@ public enum WizardCardsImageSource implements CardImageSource { return "/Handlers/Image.ashx?multiverseid=" + landMultiverseId + "&type=card"; } - private int getLocalizedMultiverseId(String preferredLanguage, Integer multiverseId) throws IOException { - if (preferredLanguage.equals("en")) { + private int getLocalizedMultiverseId(CardLanguage preferredLanguage, Integer multiverseId) throws IOException { + if (preferredLanguage.equals(CardLanguage.ENGLISH)) { return multiverseId; } @@ -682,43 +679,6 @@ public enum WizardCardsImageSource implements CardImageSource { return 60.0f; } - // private final class GetImageLinkTask implements Runnable { -// -// private int multiverseId; -// private String cardName; -// private String preferredLanguage; -// private LinkedHashMap setLinks; -// -// public GetImageLinkTask(int multiverseId, String cardName, String preferredLanguage, LinkedHashMap setLinks) { -// try { -// this.multiverseId = multiverseId; -// this.cardName = cardName; -// this.preferredLanguage = preferredLanguage; -// this.setLinks = setLinks; -// } catch (Exception ex) { -// logger.error(ex.getMessage()); -// logger.error("multiverseId: " + multiverseId); -// logger.error("cardName: " + cardName); -// logger.error("preferredLanguage: " + preferredLanguage); -// logger.error("setLinks: " + setLinks.toString()); -// } -// } -// -// @Override -// public void run() { -// try { -// if (cardName.equals("Forest") || cardName.equals("Swamp") || cardName.equals("Mountain") || cardName.equals("Island") || cardName.equals("Plains")) { -// setLinks.putAll(getLandVariations(multiverseId, cardName)); -// } else { -// Integer preferredMultiverseId = getLocalizedMultiverseId(preferredLanguage, multiverseId); -// setLinks.put(cardName.toLowerCase(Locale.ENGLISH), generateLink(preferredMultiverseId)); -// } -// } catch (IOException | NumberFormatException ex) { -// logger.error("Exception when parsing the wizards page: " + ex.getMessage()); -// } -// } -// -// } @Override public int getTotalImages() { return -1; @@ -729,6 +689,21 @@ public enum WizardCardsImageSource implements CardImageSource { return false; } + @Override + public boolean isLanguagesSupport() { + return true; + } + + @Override + public void setCurrentLanguage(CardLanguage cardLanguage) { + this.currentLanguage = cardLanguage; + } + + @Override + public CardLanguage getCurrentLanguage() { + return currentLanguage; + } + @Override public void doPause(String httpImageUrl) { } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java similarity index 55% rename from Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java rename to Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java index 7be47db2d1..2ffc11bad1 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPictures.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/DownloadPicturesService.java @@ -1,93 +1,82 @@ package org.mage.plugins.card.images; -import java.awt.*; -import java.awt.event.ItemEvent; -import java.io.*; -import java.net.*; -import java.nio.file.AccessDeniedException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import javax.swing.*; - import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.client.MageFrame; +import mage.client.dialog.DownloadImagesDialog; import mage.client.dialog.PreferencesDialog; +import mage.client.util.CardLanguage; import mage.client.util.sets.ConstructedFormats; import mage.remote.Connection; -import mage.util.StreamUtils; import net.java.truevfs.access.TFile; import net.java.truevfs.access.TFileOutputStream; import net.java.truevfs.access.TVFS; import net.java.truevfs.kernel.spec.FsSyncException; import org.apache.log4j.Logger; import org.mage.plugins.card.dl.sources.*; -import org.mage.plugins.card.properties.SettingsManager; import org.mage.plugins.card.utils.CardImageUtils; +import javax.swing.*; +import java.awt.*; +import java.awt.event.ItemEvent; +import java.io.*; +import java.net.*; +import java.nio.file.AccessDeniedException; +import java.util.List; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + import static org.mage.plugins.card.utils.CardImageUtils.getImagesDir; -public class DownloadPictures extends DefaultBoundedRangeModel implements Runnable { +/** + * @author JayDi85 + */ +public class DownloadPicturesService extends DefaultBoundedRangeModel implements Runnable { - // don't forget to remove new sets from ignore.urls to download (propeties file in resources) - private static DownloadPictures instance; + // don't forget to remove new sets from ignore.urls to download (properties file in resources) + private static DownloadPicturesService instance; + private static final Logger logger = Logger.getLogger(DownloadPicturesService.class); - private static final Logger logger = Logger.getLogger(DownloadPictures.class); + private static final String ALL_IMAGES = "- ALL images from selected source (can be slow)"; + private static final String ALL_MODERN_IMAGES = "- MODERN images (can be slow)"; + private static final String ALL_STANDARD_IMAGES = "- STANDARD images"; + private static final String ALL_TOKENS = "- TOKEN images"; - public static final String ALL_IMAGES = "- ALL images from selected source (CAN BE VERY SLOW)"; - public static final String ALL_STANDARD_IMAGES = "- Only images from STANDARD sets"; - public static final String ALL_TOKENS = "- Only token images from selected source"; + private static final int MAX_ERRORS_COUNT_BEFORE_CANCEL = 50; - private JDialog dialog; - private final JProgressBar bar; - private final JOptionPane dlg; - private boolean cancel; - private final JButton closeButton; - private final JButton startDownloadButton; + private DownloadImagesDialog uiDialog; + private boolean needCancel; + private int errorCount; private int cardIndex; - private List allCardsMissingImage; - private List cardsToDownload; - private int missingCards = 0; - private int missingTokens = 0; + private List cardsAll; + private List cardsMissing; + private List cardsDownloadQueue; + private int missingCardsCount = 0; + private int missingTokensCount = 0; - List selectedSetCodes = new ArrayList<>(); - - private final JComboBox jComboBoxServer; - private final JLabel jLabelMessage; - private final JLabel jLabelAllMissing; - private final JLabel jLabelServer; - - private final JComboBox jComboBoxSet; - private final JLabel jLabelSet; + private List selectedSets = new ArrayList<>(); + private static CardImageSource selectedSource; private final Object sync = new Object(); - - private static CardImageSource cardImageSource; - private Proxy p = Proxy.NO_PROXY; enum DownloadSources { - WIZARDS("1. wizards.com - low quality CARDS, multi-language, can be SLOW", WizardCardsImageSource.instance), + WIZARDS("1. wizards.com - low quality CARDS, multi-language, slow download", WizardCardsImageSource.instance), TOKENS("2. tokens.mtg.onl - high quality TOKENS", TokensMtgImageSource.instance), - SCRYFALL("3. scryfall.com - high quality CARDS, multi-language", ScryfallImageSource.instance), + SCRYFALL("3. scryfall.com - high quality CARDS and TOKENS, multi-language", ScryfallImageSource.instance), MAGIDEX("4. magidex.com - high quality CARDS", MagidexImageSource.instance), GRAB_BAG("5. GrabBag - STAR WARS cards and tokens", GrabbagImageSource.instance), MYTHICSPOILER("6. mythicspoiler.com", MythicspoilerComSource.instance), ALTERNATIVE("7. alternative.mtg.onl", AltMtgOnlTokensImageSource.instance), COPYPASTE("8. Copy and Paste Image URLs", CopyPasteImageSource.instance); // MTG_ONL("mtg.onl", MtgOnlTokensImageSource.instance), Not working correctly yet - // MAGICCARDS("magiccards.info", MagicCardsImageSource.instance) private final String text; private final CardImageSource source; @@ -108,7 +97,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } - public static DownloadPictures getInstance() { + public static DownloadPicturesService getInstance() { return instance; } @@ -117,245 +106,252 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } public static void startDownload() { + // load images info in background task + instance = new DownloadPicturesService(MageFrame.getInstance()); + new Thread(new LoadMissingCardDataNew(instance)).start(); - /* - * if (cards == null || cards.isEmpty()) { - * JOptionPane.showMessageDialog(null, - * "All card pictures have been downloaded."); return; } - */ - instance = new DownloadPictures(MageFrame.getInstance()); - Thread t1 = new Thread(new LoadMissingCardData(instance)); - t1.start(); - instance.getDlg().setVisible(true); - instance.getDlg().dispose(); - instance.cancel = true; + // show dialog + instance.setNeedCancel(false); + instance.resetErrorCount(); + instance.uiDialog.showDialog(); + instance.uiDialog.dispose(); + instance.setNeedCancel(true); } - public JDialog getDlg() { - return dialog; + private boolean getNeedCancel() { + return this.needCancel || (this.errorCount > MAX_ERRORS_COUNT_BEFORE_CANCEL); } - public void setCancel(boolean cancel) { - this.cancel = cancel; + private void setNeedCancel(boolean needCancel) { + this.needCancel = needCancel; } - static int WIDTH = 400; + private void incErrorCount() { + this.errorCount = this.errorCount + 1; + } - public DownloadPictures(JFrame frame) { + private void resetErrorCount() { + this.errorCount = 0; + } - cardsToDownload = new ArrayList<>(); + public DownloadPicturesService(JFrame frame) { + // init service and dialog + cardsAll = Collections.synchronizedList(new ArrayList<>()); + cardsMissing = Collections.synchronizedList(new ArrayList<>()); + cardsDownloadQueue = Collections.synchronizedList(new ArrayList<>()); + uiDialog = new DownloadImagesDialog(); - JPanel p0 = new JPanel(); - p0.setLayout(new BoxLayout(p0, BoxLayout.Y_AXIS)); + // MESSAGE + uiDialog.setGlobalInfo("Initializing image download..."); - p0.add(Box.createVerticalStrut(5)); - - jLabelMessage = new JLabel(); - jLabelMessage.setAlignmentX(Component.CENTER_ALIGNMENT); - jLabelMessage.setText("Initializing image download..."); - p0.add(jLabelMessage); - p0.add(Box.createVerticalStrut(5)); - - jLabelAllMissing = new JLabel(); - - jLabelAllMissing.setAlignmentX(Component.LEFT_ALIGNMENT); - // jLabelAllMissing.setText("Computing number of missing images..."); - p0.add(jLabelAllMissing); - p0.add(Box.createVerticalStrut(5)); - - jLabelServer = new JLabel(); - jLabelServer.setText("Please select image source:"); - jLabelServer.setAlignmentX(Component.LEFT_ALIGNMENT); - jLabelServer.setVisible(false); - p0.add(jLabelServer); - - p0.add(Box.createVerticalStrut(5)); - - jComboBoxServer = new JComboBox(); - jComboBoxServer.setModel(new DefaultComboBoxModel(DownloadSources.values())); - jComboBoxServer.setAlignmentX(Component.LEFT_ALIGNMENT); - jComboBoxServer.setAlignmentY(Component.LEFT_ALIGNMENT); - jComboBoxServer.addItemListener((ItemEvent event) -> { + // SOURCES - scryfall is default source + uiDialog.getSourcesCombo().setModel(new DefaultComboBoxModel(DownloadSources.values())); + uiDialog.getSourcesCombo().setSelectedItem(DownloadSources.SCRYFALL); + selectedSource = ScryfallImageSource.instance; + uiDialog.getSourcesCombo().addItemListener((ItemEvent event) -> { if (event.getStateChange() == ItemEvent.SELECTED) { - comboBoxServerItemSelected(event); - } - }); - Dimension d = jComboBoxServer.getPreferredSize(); - d.width = WIDTH; - jComboBoxServer.setPreferredSize(d); - p0.add(jComboBoxServer); - jComboBoxServer.setVisible(false); - - // set the first source as default - cardImageSource = WizardCardsImageSource.instance; - - p0.add(Box.createVerticalStrut(5)); - - // Set selection --------------------------------- - jLabelSet = new JLabel(); - jLabelSet.setText("Please select sets to download the images for:"); - jLabelSet.setAlignmentX(Component.LEFT_ALIGNMENT); - jLabelSet.setVisible(false); - p0.add(jLabelSet); - - jComboBoxSet = new JComboBox(); -// jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); - jComboBoxSet.setAlignmentX(Component.LEFT_ALIGNMENT); - jComboBoxSet.addItemListener((ItemEvent event) -> { - if (event.getStateChange() == ItemEvent.SELECTED) { - comboBoxSetItemSelected(event); + comboboxSourceSelected(event); } }); - p0.add(jComboBoxSet); - jComboBoxSet.setVisible(false); + // LANGUAGES + uiDialog.getLaunguagesCombo().setModel(new DefaultComboBoxModel(CardLanguage.values())); + uiDialog.getLaunguagesCombo().setSelectedItem(PreferencesDialog.getPrefImagesLanguage()); + reloadLanguagesForSelectedSource(); - p0.add(Box.createVerticalStrut(5)); + // REDOWNLOAD + uiDialog.getRedownloadCheckbox().setSelected(false); + uiDialog.getRedownloadCheckbox().addItemListener(this::checkboxRedowloadChanged); - // Start - startDownloadButton = new JButton("Start download"); - startDownloadButton.addActionListener(e -> { - new Thread(DownloadPictures.this).start(); - startDownloadButton.setEnabled(false); + + // SETS (fills after source and language select) + //uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel(DownloadSources.values())); + uiDialog.getSetsCombo().addItemListener((ItemEvent event) -> { + if (event.getStateChange() == ItemEvent.SELECTED) { + comboboxSetSelected(event); + } }); - p0.add(Box.createVerticalStrut(5)); - // Progress - bar = new JProgressBar(this); - p0.add(bar); - bar.setStringPainted(true); + // BUTTON START + uiDialog.getStartButton().addActionListener(e -> { + // selected language setup + if (selectedSource != null) { + if (selectedSource.isLanguagesSupport()) { + selectedSource.setCurrentLanguage((CardLanguage) uiDialog.getLaunguagesCombo().getSelectedItem()); + } + } - d = bar.getPreferredSize(); - d.width = WIDTH; - bar.setPreferredSize(d); - bar.setVisible(false); + // run + uiDialog.enableActionControls(false); + uiDialog.getStartButton().setEnabled(false); + new Thread(DownloadPicturesService.this).start(); + }); - // JOptionPane - Object[] options = {startDownloadButton, closeButton = new JButton("Cancel")}; - startDownloadButton.setVisible(false); - closeButton.addActionListener(e -> dialog.setVisible(false)); - closeButton.setVisible(false); + // BUTTON CANCEL (dialog and loading) + uiDialog.getCancelButton().addActionListener(e -> uiDialog.setVisible(false)); + uiDialog.getStopButton().addActionListener(e -> uiDialog.setVisible(false)); - dlg = new JOptionPane(p0, JOptionPane.PLAIN_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[1]); - dialog = this.dlg.createDialog(frame, "Downloading images"); + // PROGRESS BAR + uiDialog.getProgressBar().setValue(0); } - public void setAllMissingCards() { - updateAndViewMessage("Get all available cards from the repository..."); - List cards = CardRepository.instance.findCards(new CardCriteria()); - updateAndViewMessage("Check which images are missing ..."); - this.allCardsMissingImage = getNeededCards(cards); - updateAndViewMessage("Check which images the current source is providing ..."); - jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + public void findMissingCards() { + updateAndViewMessage("Loading..."); + this.cardsAll.clear(); + this.cardsMissing.clear(); + this.cardsDownloadQueue.clear(); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + updateAndViewMessage("Loading cards list..."); + this.cardsAll = Collections.synchronizedList(CardRepository.instance.findCards(new CardCriteria())); - jComboBoxServer.setVisible(true); - jLabelServer.setVisible(true); - jComboBoxSet.setVisible(true); - jLabelSet.setVisible(true); - bar.setVisible(true); - startDownloadButton.setVisible(true); - closeButton.setVisible(true); + updateAndViewMessage("Finding missing images..."); + this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()); + updateAndViewMessage("Finding available sets from selected source..."); + this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString()); + + this.uiDialog.showDownloadControls(true); updateAndViewMessage(""); } - private void comboBoxServerItemSelected(ItemEvent evt) { - if (jComboBoxServer.isEnabled()) { - cardImageSource = ((DownloadSources) evt.getItem()).getSource(); - // update the available sets / token comboBox - jComboBoxSet.setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + private void reloadLanguagesForSelectedSource() { + this.uiDialog.showLanguagesSupport(selectedSource != null && selectedSource.isLanguagesSupport()); + } + + private void reloadSetsForSelectedSource() { + // update the available sets / token combobox + Object oldSelection = this.uiDialog.getSetsCombo().getSelectedItem(); + this.uiDialog.getSetsCombo().setModel(new DefaultComboBoxModel<>(getSetsForCurrentImageSource())); + if (oldSelection != null) { + this.uiDialog.getSetsCombo().setSelectedItem(oldSelection); + } + reloadCardsToDownload(this.uiDialog.getSetsCombo().getSelectedItem().toString()); + } + + private void comboboxSourceSelected(ItemEvent evt) { + if (this.uiDialog.getSourcesCombo().isEnabled()) { + selectedSource = ((DownloadSources) evt.getItem()).getSource(); + reloadSetsForSelectedSource(); + reloadLanguagesForSelectedSource(); } } public void updateAndViewMessage(String text) { - jLabelMessage.setText(text); - if (dialog != null) { - dialog.pack(); - dialog.validate(); - dialog.repaint(); + this.uiDialog.setGlobalInfo(text); + + // auto-size on empty message (on complete) + if (text.isEmpty()) { + this.uiDialog.showDownloadControls(true); } } + private String getSetNameWithYear(ExpansionSet exp) { + Calendar cal = Calendar.getInstance(); + cal.setTime(exp.getReleaseDate()); + String year = String.valueOf(cal.get(Calendar.YEAR)); + + return exp.getName() + " (" + exp.getCode() + ", " + year + ")"; + + /* + if (!exp.getName().contains(year)) { + return exp.getName() + " (" + year + ")"; + } else { + return exp.getName(); + } + */ + } + + private ExpansionSet findSetByNameWithYear(String name) { + return Sets.getInstance().values().stream() + .filter(exp -> getSetNameWithYear(exp).equals(name)) + .findFirst() + .orElse(null); + } + private Object[] getSetsForCurrentImageSource() { // Set the available sets to the combo box - ArrayList supportedSets = cardImageSource.getSupportedSets(); + ArrayList supportedSets = selectedSource.getSupportedSets(); List setNames = new ArrayList<>(); - if (supportedSets != null) { - setNames.add(ALL_IMAGES); - setNames.add(ALL_STANDARD_IMAGES); - } - if (cardImageSource.isTokenSource()) { + + // multiple sets selection + setNames.add(ALL_IMAGES); + setNames.add(ALL_MODERN_IMAGES); + setNames.add(ALL_STANDARD_IMAGES); + if (selectedSource.isTokenSource()) { setNames.add(ALL_TOKENS); } - if (supportedSets != null) { - for (String setCode : supportedSets) { - ExpansionSet expansionSet = Sets.findSet(setCode); - if (expansionSet != null) { - setNames.add(expansionSet.getName()); - } else { - logger.warn("Source: " + cardImageSource.getSourceName() + ": Expansion set for code " + setCode + " not found in xmage sets!"); - } - } - } + // single set selection + Collection dbSets = Sets.getInstance().values(); + Collection comboSets = dbSets.stream() + .filter(exp -> supportedSets.contains(exp.getCode())) + .sorted(Comparator.comparing(ExpansionSet::getReleaseDate).reversed()) + .map(this::getSetNameWithYear) + .collect(Collectors.toList()); + setNames.addAll(comboSets); + if (setNames.isEmpty()) { - logger.error("Source " + cardImageSource.getSourceName() + " creates no selectable items."); - setNames.add("not avalable"); + logger.error("Source " + selectedSource.getSourceName() + " creates no selectable items."); + setNames.add("not available"); } return setNames.toArray(new String[0]); } - private void updateCardsToDownload(String itemText) { - selectedSetCodes.clear(); - switch (itemText) { + private void reloadCardsToDownload(String selectedItem) { + // find selected sets + selectedSets.clear(); + List formatSets; + List sourceSets = selectedSource.getSupportedSets(); + switch (selectedItem) { + case ALL_IMAGES: - if (cardImageSource.getSupportedSets() == null) { - selectedSetCodes = cardImageSource.getSupportedSets(); - } else { - selectedSetCodes.addAll(cardImageSource.getSupportedSets()); - } + selectedSets.addAll(selectedSource.getSupportedSets()); break; + case ALL_STANDARD_IMAGES: - List standardSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); - for (String setCode : cardImageSource.getSupportedSets()) { - if (standardSets.contains(setCode)) { - selectedSetCodes.add(setCode); - } else { - logger.debug("Set code " + setCode + " from download source " + cardImageSource.getSourceName()); - } - } + formatSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); + formatSets.stream() + .filter(sourceSets::contains) + .forEachOrdered(selectedSets::add); break; + + case ALL_MODERN_IMAGES: + formatSets = ConstructedFormats.getSetsByFormat(ConstructedFormats.MODERN); + formatSets.stream() + .filter(sourceSets::contains) + .forEachOrdered(selectedSets::add); + break; + case ALL_TOKENS: break; + default: - int nonSetEntries = 0; - if (cardImageSource.getSupportedSets() != null) { - nonSetEntries = 2; + // selects one set + ExpansionSet selectedExp = findSetByNameWithYear(selectedItem); + if (selectedExp != null) { + selectedSets.add(selectedExp.getCode()); } - if (cardImageSource.isTokenSource()) { - nonSetEntries++; - } - selectedSetCodes.add(cardImageSource.getSupportedSets().get(jComboBoxSet.getSelectedIndex() - nonSetEntries)); + break; } - cardsToDownload.clear(); + + // find missing cards to download + cardsDownloadQueue.clear(); int numberTokenImagesAvailable = 0; int numberCardImagesAvailable = 0; - for (CardDownloadData data : allCardsMissingImage) { + for (CardDownloadData data : cardsMissing) { if (data.isToken()) { - if (cardImageSource.isTokenSource() && cardImageSource.isImageProvided(data.getSet(), data.getName())) { + if (selectedSource.isTokenSource() && selectedSource.isTokenImageProvided(data.getSet(), data.getName(), data.getType())) { numberTokenImagesAvailable++; - cardsToDownload.add(data); + cardsDownloadQueue.add(data); } else { //logger.warn("Source do not support token (set " + data.getSet() + ", token " + data.getName() + ")"); } } else { - if (selectedSetCodes != null && selectedSetCodes.contains(data.getSet())) { - if (cardImageSource.isSetSupportedComplete(data.getSet()) || cardImageSource.isImageProvided(data.getSet(), data.getName())) { + if (selectedSets != null && selectedSets.contains(data.getSet())) { + if (selectedSource.isSetSupportedComplete(data.getSet()) || selectedSource.isCardImageProvided(data.getSet(), data.getName())) { numberCardImagesAvailable++; - cardsToDownload.add(data); + cardsDownloadQueue.add(data); } } } @@ -363,24 +359,40 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab updateProgressText(numberCardImagesAvailable, numberTokenImagesAvailable); } - private void comboBoxSetItemSelected(ItemEvent event) { + private void comboboxSetSelected(ItemEvent event) { // Update the cards to download related to the selected set - updateCardsToDownload(event.getItem().toString()); + reloadCardsToDownload(event.getItem().toString()); + } + + private void checkboxRedowloadChanged(ItemEvent event) { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.WAIT_CURSOR)); + try { + this.cardsMissing.clear(); + this.cardsMissing = prepareMissingCards(this.cardsAll, uiDialog.getRedownloadCheckbox().isSelected()); + reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString()); + } finally { + MageFrame.getDesktop().setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + } } private void updateProgressText(int cardCount, int tokenCount) { - missingTokens = 0; - for (CardDownloadData card : allCardsMissingImage) { + missingTokensCount = 0; + for (CardDownloadData card : cardsMissing) { if (card.isToken()) { - missingTokens++; + missingTokensCount++; } } - missingCards = allCardsMissingImage.size() - missingTokens; - jLabelAllMissing.setText("Missing: " + missingCards + " card images / " + missingTokens + " token images"); + missingCardsCount = cardsMissing.size() - missingTokensCount; + + uiDialog.setCurrentInfo("Missing: " + missingCardsCount + " card images / " + missingTokensCount + " token images"); int imageSum = cardCount + tokenCount; - float mb = (imageSum * cardImageSource.getAverageSize()) / 1024; - bar.setString(String.format(cardIndex == imageSum ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!" - : "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", 0, imageSum, cardCount, tokenCount, mb)); + float mb = (imageSum * selectedSource.getAverageSize()) / 1024; + uiDialog.getProgressBar().setString(String.format( + cardIndex == imageSum + ? "%d of %d (%d cards/%d tokens) image downloads finished! Please close!" + : "%d of %d (%d cards/%d tokens) image downloads finished! Please wait! [%.1f Mb]", + 0, imageSum, cardCount, tokenCount, mb + )); } private static String createDownloadName(CardInfo card) { @@ -388,16 +400,9 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab return className.substring(className.lastIndexOf('.') + 1); } - private static List getNeededCards(List allCards) { + private static List prepareMissingCards(List allCards, boolean redownloadMode) { - /** - * read all card names and urls - */ - HashSet ignoreUrls = SettingsManager.getIntance().getIgnoreUrls(); - - /** - * get filter for Standard Type 2 cards - */ + // get filter for Standard Type 2 cards Set type2SetsFilter = new HashSet<>(); List constructedFormats = ConstructedFormats.getSetsByFormat(ConstructedFormats.STANDARD); if (constructedFormats != null && !constructedFormats.isEmpty()) { @@ -406,11 +411,11 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab logger.warn("No formats defined. Try connecting to a server first!"); } + // prepare checking list List allCardsUrls = Collections.synchronizedList(new ArrayList<>()); try { allCards.parallelStream().forEach(card -> { - if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty() - && !ignoreUrls.contains(card.getSetCode())) { + if (!card.getCardNumber().isEmpty() && !"0".equals(card.getCardNumber()) && !card.getSetCode().isEmpty()) { String cardName = card.getName(); boolean isType2 = type2SetsFilter.contains(card.getSetCode()); CardDownloadData url = new CardDownloadData(cardName, card.getSetCode(), card.getCardNumber(), card.usesVariousArt(), 0, "", "", false, card.isDoubleFaced(), card.isNightCard()); @@ -455,32 +460,33 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab logger.info("Card was not selected: " + card.getName()); } }); + allCardsUrls.addAll(getTokenCardUrls()); } catch (Exception e) { logger.error(e); } - /** - * check to see which cards we already have - */ + // find missing files List cardsToDownload = Collections.synchronizedList(new ArrayList<>()); allCardsUrls.parallelStream().forEach(card -> { - File file = new TFile(CardImageUtils.buildImagePathToCard(card)); - logger.debug(card.getName() + " (is_token=" + card.isToken() + "). Image is here:" + file.getAbsolutePath() + " (exists=" + file.exists() + ')'); - if (!file.exists()) { - logger.debug("Missing: " + file.getAbsolutePath()); - // logger.info("Missing image: " + (card.isToken() ? "TOKEN " : "CARD ") + card.getSet() + "/" + card.getName() + " type: " + card.getType()); + if (redownloadMode) { + // need all cards cardsToDownload.add(card); + } else { + // need missing cards + File file = new TFile(CardImageUtils.buildImagePathToCard(card)); + if (!file.exists()) { + cardsToDownload.add(card); + } } }); - return new ArrayList<>(cardsToDownload); + return Collections.synchronizedList(new ArrayList<>(cardsToDownload)); } public static ArrayList getTokenCardUrls() throws RuntimeException { ArrayList list = new ArrayList<>(); - InputStream in = DownloadPictures.class - .getClassLoader().getResourceAsStream("card-pictures-tok.txt"); + InputStream in = DownloadPicturesService.class.getClassLoader().getResourceAsStream("card-pictures-tok.txt"); if (in == null) { logger.error("resources input stream is null"); @@ -498,7 +504,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab if (params.length >= 5) { int type = 0; if (params[4] != null && !params[4].isEmpty()) { - type = Integer.parseInt(params[4].trim()); + type = Integer.parseInt(params[4].trim()); // token number for same names } String fileName = ""; if (params.length > 5 && params[5] != null && !params[5].isEmpty()) { @@ -545,8 +551,18 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } catch (Exception ex) { logger.error(ex); - throw new RuntimeException("DownloadPictures : readFile() error"); + throw new RuntimeException("DownloadPicturesService : readFile() error"); } + + // TODO: delete and move to copy-pate images download mode + /* + for (CardDownloadData card : list) { + if (card.isToken()) { + System.out.println(card.getSet() + "/" + card.getName() + (!card.getType().equals(0) ? "/" + card.getType() : "")); + } + } + */ + return list; } @@ -581,62 +597,60 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab Integer port = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_PROXY_PORT, "80")); p = new Proxy(type, new InetSocketAddress(address, port)); } catch (Exception ex) { - throw new RuntimeException("Gui_DownloadPictures : error 1 - " + ex); + throw new RuntimeException("Gui_DownloadPicturesService : error 1 - " + ex); } } if (p != null) { - HashSet ignoreUrls = SettingsManager.getIntance().getIgnoreUrls(); - - update(0, cardsToDownload.size()); - logger.info("Started download of " + cardsToDownload.size() + " images from source: " + cardImageSource.getSourceName()); + update(0, cardsDownloadQueue.size()); + logger.info("Started download of " + cardsDownloadQueue.size() + " images" + + " from source: " + selectedSource.getSourceName() + + ", language: " + selectedSource.getCurrentLanguage().getCode()); int numberOfThreads = Integer.parseInt(PreferencesDialog.getCachedValue(PreferencesDialog.KEY_CARD_IMAGES_THREADS, "10")); ExecutorService executor = Executors.newFixedThreadPool(numberOfThreads); - for (int i = 0; i < cardsToDownload.size() && !cancel; i++) { + for (int i = 0; i < cardsDownloadQueue.size() && !this.getNeedCancel(); i++) { try { - - CardDownloadData card = cardsToDownload.get(i); + CardDownloadData card = cardsDownloadQueue.get(i); logger.debug("Downloading image: " + card.getName() + " (" + card.getSet() + ')'); CardImageUrls urls; - - if (ignoreUrls.contains(card.getSet()) || card.isToken()) { + if (card.isToken()) { if (!"0".equals(card.getCollectorId())) { continue; } - urls = cardImageSource.generateTokenUrl(card); + urls = selectedSource.generateTokenUrl(card); } else { - urls = cardImageSource.generateURL(card); + urls = selectedSource.generateCardUrl(card); } if (urls == null) { - String imageRef = cardImageSource.getNextHttpImageUrl(); - String fileName = cardImageSource.getFileForHttpImage(imageRef); + String imageRef = selectedSource.getNextHttpImageUrl(); + String fileName = selectedSource.getFileForHttpImage(imageRef); if (imageRef != null && fileName != null) { - imageRef = cardImageSource.getSourceName() + imageRef; + imageRef = selectedSource.getSourceName() + imageRef; try { - card.setToken(cardImageSource.isTokenSource()); - Runnable task = new DownloadTask(card, imageRef, fileName, cardImageSource.getTotalImages()); + card.setToken(selectedSource.isTokenSource()); + Runnable task = new DownloadTask(card, imageRef, fileName, selectedSource.getTotalImages()); executor.execute(task); } catch (Exception ex) { } - } else if (cardImageSource.getTotalImages() == -1) { - logger.info("Image not available on " + cardImageSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')'); + } else if (selectedSource.getTotalImages() == -1) { + logger.info("Image not available on " + selectedSource.getSourceName() + ": " + card.getName() + " (" + card.getSet() + ')'); synchronized (sync) { - update(cardIndex + 1, cardsToDownload.size()); + update(cardIndex + 1, cardsDownloadQueue.size()); } } } else { - Runnable task = new DownloadTask(card, urls, cardsToDownload.size()); + Runnable task = new DownloadTask(card, urls, cardsDownloadQueue.size()); executor.execute(task); } - } catch (Exception ex) { logger.error(ex, ex); } } + executor.shutdown(); while (!executor.isTerminated()) { try { @@ -645,6 +659,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } } + try { TVFS.umount(); } catch (FsSyncException e) { @@ -653,11 +668,15 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } finally { // } - closeButton.setText("Close"); - updateCardsToDownload(jComboBoxSet.getSelectedItem().toString()); + + // stop + reloadCardsToDownload(uiDialog.getSetsCombo().getSelectedItem().toString()); + + // reset images cache + ImageCache.clearCache(); } - static String convertStreamToString(java.io.InputStream is) { + static String convertStreamToString(InputStream is) { java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); return s.hasNext() ? s.next() : ""; } @@ -670,10 +689,6 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab private final String actualFilename; private final boolean useSpecifiedPaths; - DownloadTask(CardDownloadData card, String baseUrl, int count) { - this(card, new CardImageUrls(baseUrl, null), count); - } - DownloadTask(CardDownloadData card, CardImageUrls urls, int count) { this.card = card; this.urls = urls; @@ -692,7 +707,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab @Override public void run() { - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { synchronized (sync) { update(cardIndex + 1, count); } @@ -736,20 +751,23 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } // FILE already exists (in zip or in dir) + // don't use, images can be re-downloaded + /* if (destFile.exists()) { synchronized (sync) { update(cardIndex + 1, count); } return; } + */ - // zip can't be read + // check zip access TFile testArchive = destFile.getTopLevelArchive(); if (testArchive != null && testArchive.exists()) { try { testArchive.list(); } catch (Exception e) { - logger.error("Error reading archive, may be it was corrapted. Try to delete it: " + testArchive.toString()); + logger.error("Error reading archive, it's can be corrupted. Try to delete it: " + testArchive.toString()); synchronized (sync) { update(cardIndex + 1, count); @@ -773,53 +791,63 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab URL url = new URL(currentUrl); // on download cancel need to stop - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { return; } // download - cardImageSource.doPause(url.getPath()); + selectedSource.doPause(url.getPath()); + httpConn = url.openConnection(p); - httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); - httpConn.connect(); - int responseCode = ((HttpURLConnection) httpConn).getResponseCode(); + if (httpConn != null) { - // check result - if (responseCode != 200) { - // show errors only on full fail (all urls were not work) - errorsList.add("Image download for " + card.getName() - + (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "") - + " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); - - if (logger.isDebugEnabled()) { - // Shows the returned html from the request to the web server - logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream())); + httpConn.setRequestProperty("User-Agent", "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.2.2) Gecko/20100316 Firefox/3.6.2"); + try { + httpConn.connect(); + } catch (SocketException e) { + incErrorCount(); + errorsList.add("Wrong image URL or java app is not allowed to use network. Check your firewall or proxy settings. Error: " + e.getMessage() + ". Image URL: " + url.toString()); + break; + } catch (UnknownHostException e) { + incErrorCount(); + errorsList.add("Unknown site. Check your DNS settings. Error: " + e.getMessage() + ". Image URL: " + url.toString()); + break; } + int responseCode = ((HttpURLConnection) httpConn).getResponseCode(); - // go to next try - continue; - } else { - // all fine - isDownloadOK = true; - break; + // check result + if (responseCode != 200) { + // show errors only on full fail (all urls were not work) + errorsList.add("Image download for " + card.getName() + + (!card.getDownloadName().equals(card.getName()) ? " downloadname: " + card.getDownloadName() : "") + + " (" + card.getSet() + ") failed - responseCode: " + responseCode + " url: " + url.toString()); + + if (logger.isDebugEnabled()) { + // Shows the returned html from the request to the web server + logger.debug("Returned HTML ERROR:\n" + convertStreamToString(((HttpURLConnection) httpConn).getErrorStream())); + } + + // go to next try + continue; + } else { + // all fine + isDownloadOK = true; + break; + } } } // can save result if (isDownloadOK & httpConn != null) { // save data to temp - OutputStream out = null; - OutputStream tfileout = null; - InputStream in = null; - try { - in = new BufferedInputStream(httpConn.getInputStream()); - tfileout = new TFileOutputStream(fileTempImage); - out = new BufferedOutputStream(tfileout); + try (InputStream in = new BufferedInputStream(httpConn.getInputStream()); + OutputStream tfileout = new TFileOutputStream(fileTempImage); + OutputStream out = new BufferedOutputStream(tfileout)) { byte[] buf = new byte[1024]; int len; while ((len = in.read(buf)) != -1) { // user cancelled - if (cancel) { + if (DownloadPicturesService.getInstance().getNeedCancel()) { // stop download, save current state and exit TFile archive = destFile.getTopLevelArchive(); ///* not need to unmout/close - it's auto action @@ -840,13 +868,7 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } out.write(buf, 0, len); } - } finally { - StreamUtils.closeQuietly(in); - StreamUtils.closeQuietly(out); - StreamUtils.closeQuietly(tfileout); } - - // TODO: add two faces card correction? (WTF) // SAVE final data if (fileTempImage.exists()) { @@ -869,9 +891,11 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } catch (AccessDeniedException e) { + incErrorCount(); logger.error("Can't access to files: " + card.getName() + "(" + card.getSet() + "). Try rebooting your system to remove the file lock."); } catch (Exception e) { - logger.error(e.getMessage(), e); + incErrorCount(); + logger.error("Unknown error: " + e.getMessage(), e); } finally { } @@ -881,34 +905,38 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } } - private void update(int card, int count) { - this.cardIndex = card; + private void update(int lastCardIndex, int needDownloadCount) { + this.cardIndex = lastCardIndex; - if (cardIndex < count) { - float mb = ((count - card) * cardImageSource.getAverageSize()) / 1024; - bar.setString(String.format("%d of %d image downloads finished! Please wait! [%.1f Mb]", - card, count, mb)); + if (cardIndex < needDownloadCount) { + // downloading + float mb = ((needDownloadCount - lastCardIndex) * selectedSource.getAverageSize()) / 1024; + uiDialog.getProgressBar().setString(String.format("%d of %d image downloads finished! Please wait! [%.1f Mb]", + lastCardIndex, needDownloadCount, mb)); } else { - List remainingCards = Collections.synchronizedList(new ArrayList<>()); - DownloadPictures.this.allCardsMissingImage.parallelStream().forEach(cardDownloadData -> { + // finished + List downloadedCards = Collections.synchronizedList(new ArrayList<>()); + DownloadPicturesService.this.cardsMissing.parallelStream().forEach(cardDownloadData -> { TFile file = new TFile(CardImageUtils.buildImagePathToCard(cardDownloadData)); - if (!file.exists()) { - remainingCards.add(cardDownloadData); + if (file.exists()) { + downloadedCards.add(cardDownloadData); } }); - // remove the cards not downloaded to get the siccessfull downloaded cards - DownloadPictures.this.cardsToDownload.removeAll(remainingCards); - DownloadPictures.this.allCardsMissingImage.removeAll(DownloadPictures.this.cardsToDownload); + // remove all downloaded cards, missing must be remains + this.cardsDownloadQueue.removeAll(downloadedCards); + this.cardsMissing.removeAll(downloadedCards); - count = remainingCards.size(); - - if (count == 0) { - bar.setString("0 images remaining! Please close!"); + if (this.cardsDownloadQueue.isEmpty()) { + // stop download + uiDialog.getProgressBar().setString("0 images remaining. Please close."); } else { -// bar.setString(String.format("%d cards remaining! Please choose another source!", count)); - startDownloadButton.setEnabled(true); + // try download again } + + this.uiDialog.getRedownloadCheckbox().setSelected(false); + uiDialog.enableActionControls(true); + uiDialog.getStartButton().setEnabled(true); } } @@ -916,22 +944,20 @@ public class DownloadPictures extends DefaultBoundedRangeModel implements Runnab } -class LoadMissingCardData implements Runnable { +class LoadMissingCardDataNew implements Runnable { - private static DownloadPictures downloadPictures; + private static DownloadPicturesService downloadPicturesService; - public LoadMissingCardData(DownloadPictures downloadPictures) { - LoadMissingCardData.downloadPictures = downloadPictures; + public LoadMissingCardDataNew(DownloadPicturesService downloadPicturesService) { + LoadMissingCardDataNew.downloadPicturesService = downloadPicturesService; } @Override public void run() { - downloadPictures.setAllMissingCards(); + downloadPicturesService.findMissingCards(); } public static void main() { - - (new Thread(new LoadMissingCardData(downloadPictures))).start(); + (new Thread(new LoadMissingCardDataNew(downloadPicturesService))).start(); } - } diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java index ffe80ecdf5..92927b0509 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/images/ImageCache.java @@ -1,35 +1,42 @@ package org.mage.plugins.card.images; -import com.google.common.base.Function; -import com.google.common.collect.ComputationException; -import com.google.common.collect.MapMaker; import java.awt.*; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; + +import javax.annotation.Nullable; import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; +import org.mage.plugins.card.dl.sources.DirectLinksForDownload; +import org.mage.plugins.card.utils.CardImageUtils; + +import com.google.common.base.Function; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.google.common.collect.ComputationException; + import mage.client.constants.Constants; import mage.client.dialog.PreferencesDialog; +import mage.client.util.SoftValuesLoadingCache; import mage.client.util.TransformedImageCache; import mage.view.CardView; import net.java.truevfs.access.TFile; import net.java.truevfs.access.TFileInputStream; import net.java.truevfs.access.TFileOutputStream; -import org.apache.log4j.Logger; -import org.mage.plugins.card.dl.sources.DirectLinksForDownload; -import org.mage.plugins.card.utils.CardImageUtils; /** * This class stores ALL card images in a cache with soft values. this means * that the images may be garbage collected when they are not needed any more, * but will be kept as long as possible. - * + *

* Key format: "[cardname]#[setname]#[type]#[collectorID]#[param]" - * + *

* where param is: *

    *
  • size of image
  • @@ -44,8 +51,8 @@ public final class ImageCache { private static final Logger LOGGER = Logger.getLogger(ImageCache.class); - private static final Map IMAGE_CACHE; - private static final Map FACE_IMAGE_CACHE; + private static final SoftValuesLoadingCache IMAGE_CACHE; + private static final SoftValuesLoadingCache FACE_IMAGE_CACHE; /** * Common pattern for keys. Format: "##" @@ -54,11 +61,10 @@ public final class ImageCache { static { // softValues() = Specifies that each value (not key) stored in the map should be wrapped in a SoftReference (by default, strong references are used). Softly-referenced objects will be garbage-collected in a globally least-recently-used manner, in response to memory demand. - IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function() { + IMAGE_CACHE = SoftValuesLoadingCache.from(new Function() { @Override public BufferedImage apply(String key) { try { - boolean usesVariousArt = false; if (key.matches(".*#usesVariousArt.*")) { usesVariousArt = true; @@ -178,56 +184,46 @@ public final class ImageCache { } }); - FACE_IMAGE_CACHE = new MapMaker().softValues().makeComputingMap(new Function() { - @Override - public BufferedImage apply(String key) { - try { + FACE_IMAGE_CACHE = SoftValuesLoadingCache.from(key -> { + try { + Matcher m = KEY_PATTERN.matcher(key); - Matcher m = KEY_PATTERN.matcher(key); + if (m.matches()) { + String name = m.group(1); + String set = m.group(2); + //Integer artid = Integer.parseInt(m.group(2)); - if (m.matches()) { - String name = m.group(1); - String set = m.group(2); - //Integer artid = Integer.parseInt(m.group(2)); + String path; + path = CardImageUtils.generateFaceImagePath(name, set); - String path; - path = CardImageUtils.generateFaceImagePath(name, set); - - if (path == null) { - return null; - } - TFile file = getTFile(path); - if (file == null) { - return null; - } - - BufferedImage image = loadImage(file); - return image; - } else { - throw new RuntimeException( - "Requested face image doesn't fit the requirement for key (##: " + key); + if (path == null) { + return null; } - } catch (Exception ex) { - if (ex instanceof ComputationException) { - throw (ComputationException) ex; - } else { - throw new ComputationException(ex); + TFile file = getTFile(path); + if (file == null) { + return null; } - } - } - public BufferedImage makeThumbnailByFile(String key, TFile file, String thumbnailPath) { - BufferedImage image = loadImage(file); - image = getWizardsCard(image); - if (image == null) { - return null; + BufferedImage image = loadImage(file); + return image; + } else { + throw new RuntimeException( + "Requested face image doesn't fit the requirement for key (##: " + key); + } + } catch (Exception ex) { + if (ex instanceof ComputationException) { + throw (ComputationException) ex; + } else { + throw new ComputationException(ex); } - LOGGER.debug("creating thumbnail for " + key); - return makeThumbnail(image, thumbnailPath); } }); } + public static void clearCache() { + IMAGE_CACHE.invalidateAll(); + } + public static String getFilePath(CardView card, int width) { String key = getKey(card, card.getName(), Integer.toString(width)); boolean usesVariousArt = false; @@ -389,7 +385,7 @@ public final class ImageCache { return getImage(getKey(card, card.getName(), "")); } -// public static BufferedImage getImageFaceOriginal(CardView card) { + // public static BufferedImage getImageFaceOriginal(CardView card) { // return getFaceImage(getFaceKey(card, card.getName(), card.getExpansionSetCode())); // } public static BufferedImage getImageOriginalAlternateName(CardView card) { @@ -401,14 +397,9 @@ public final class ImageCache { */ private static BufferedImage getImage(String key) { try { - return IMAGE_CACHE.get(key); - } catch (NullPointerException ex) { - // unfortunately NullOutputException, thrown when apply() returns - // null, is not public - // NullOutputException is a subclass of NullPointerException - // legitimate, happens when a card has no image - return null; + return IMAGE_CACHE.getOrNull(key); } catch (ComputationException ex) { + // too low memory if (ex.getCause() instanceof NullPointerException) { return null; } @@ -422,13 +413,7 @@ public final class ImageCache { */ private static BufferedImage getFaceImage(String key) { try { - return FACE_IMAGE_CACHE.get(key); - } catch (NullPointerException ex) { - // unfortunately NullOutputException, thrown when apply() returns - // null, is not public - // NullOutputException is a subclass of NullPointerException - // legitimate, happens when a card has no image - return null; + return FACE_IMAGE_CACHE.getOrNull(key); } catch (ComputationException ex) { if (ex.getCause() instanceof NullPointerException) { return null; @@ -443,7 +428,7 @@ public final class ImageCache { * the cache. */ private static BufferedImage tryGetImage(String key) { - return IMAGE_CACHE.containsKey(key) ? IMAGE_CACHE.get(key) : null; + return IMAGE_CACHE.peekIfPresent(key); } /** @@ -471,6 +456,7 @@ public final class ImageCache { // return alternateName + "#" + card.getExpansionSetCode() + "#" +card.getType()+ "#" + card.getCardNumber() + "#" // + (card.getTokenSetCode() == null ? "":card.getTokenSetCode()); // } + /** * Load image from file * diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java b/Mage.Client/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java index aabbc302d4..1ec644ec77 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/info/CardInfoPaneImpl.java @@ -57,7 +57,7 @@ public class CardInfoPaneImpl extends JEditorPane implements CardInfoPane { SwingUtilities.invokeLater(() -> { TextLines textLines = GuiDisplayUtil.getTextLinesfromCardView(card); StringBuilder buffer = GuiDisplayUtil.getRulefromCardView(card, textLines); - resizeTooltipIfNeeded(container, textLines.basicTextLength, textLines.lines.size()); + resizeTooltipIfNeeded(container, textLines.getBasicTextLength(), textLines.getLines().size()); setText(buffer.toString()); setCaretPosition(0); }); diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java b/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java deleted file mode 100644 index c7a6b87d62..0000000000 --- a/Mage.Client/src/main/java/org/mage/plugins/card/properties/SettingsManager.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.mage.plugins.card.properties; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Properties; -import mage.client.constants.Constants; - -public class SettingsManager { - - private static SettingsManager settingsManager = null; - - public static synchronized SettingsManager getIntance() { - if (settingsManager == null) { - settingsManager = new SettingsManager(); - } - return settingsManager; - } - - private SettingsManager() { - loadImageProperties(); - } - - public void reloadImageProperties() { - loadImageProperties(); - } - - private void loadImageProperties() { - imageUrlProperties = new Properties(); - try { - InputStream is = SettingsManager.class.getClassLoader().getResourceAsStream(Constants.IO.IMAGE_PROPERTIES_FILE); - if (is == null) { - throw new RuntimeException("Couldn't load " + Constants.IO.IMAGE_PROPERTIES_FILE); - } - imageUrlProperties.load(is); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - - public String getSetNameReplacement(String setName) { - String result = setName; - if (imageUrlProperties != null) { - result = imageUrlProperties.getProperty(setName, setName); - } - return result; - } - - public HashSet getIgnoreUrls() { - HashSet ignoreUrls = new HashSet<>(); - if (imageUrlProperties != null) { - String result = imageUrlProperties.getProperty("ignore.urls"); - if (result != null) { - String[] ignore = result.split(","); - ignoreUrls.addAll(Arrays.asList(ignore)); - } - } - return ignoreUrls; - } - - public ArrayList getTokenLookupOrder() { - ArrayList order = new ArrayList<>(); - if (imageUrlProperties != null) { - String result = imageUrlProperties.getProperty("token.lookup.order"); - if (result != null) { - String[] sets = result.split(","); - order.addAll(Arrays.asList(sets)); - } - } - return order; - } - - private Properties imageUrlProperties; -} diff --git a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java index fb7c42aa09..c7dae39355 100644 --- a/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java +++ b/Mage.Client/src/main/java/org/mage/plugins/card/utils/CardImageUtils.java @@ -1,5 +1,16 @@ package org.mage.plugins.card.utils; +import mage.client.MageFrame; +import mage.client.constants.Constants; +import mage.client.dialog.PreferencesDialog; +import mage.remote.Connection; +import mage.remote.Connection.ProxyType; +import net.java.truevfs.access.TFile; +import org.apache.log4j.Logger; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.mage.plugins.card.images.CardDownloadData; + import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -12,18 +23,6 @@ import java.util.HashMap; import java.util.Locale; import java.util.prefs.Preferences; -import mage.client.MageFrame; -import mage.client.constants.Constants; -import mage.client.dialog.PreferencesDialog; -import mage.remote.Connection; -import mage.remote.Connection.ProxyType; -import net.java.truevfs.access.TFile; -import org.apache.log4j.Logger; -import org.jsoup.Jsoup; -import org.jsoup.nodes.Document; -import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.properties.SettingsManager; - public final class CardImageUtils { private static final HashMap pathCache = new HashMap<>(); @@ -53,7 +52,7 @@ public final class CardImageUtils { return filePath; } - log.warn("Token image file not found. Set: " + card.getSet() + " Token Set Code: " + card.getTokenSetCode() + " Name: " + card.getName() + " File path: " + filePath); + log.warn("Token image file not found. Set: " + card.getSet() + " Token Set Code: " + card.getTokenSetCode() + " Name: " + card.getName() + " File path: " + getTokenImagePath(card)); } else { log.warn("Trying to get token path for non token card. Set: " + card.getSet() + " Set Code: " + card.getTokenSetCode() + " Name: " + card.getName()); } @@ -85,20 +84,6 @@ public final class CardImageUtils { } } return filename; - -// makes no longer sense -// file = new TFile(filename); -// if (!file.exists()) { -// CardDownloadData updated = new CardDownloadData(card); -// updated.setName(card.getName() + " 1"); -// filename = buildImagePathToCard(updated); -// file = new TFile(filename); -// if (!file.exists()) { -// updated = new CardDownloadData(card); -// updated.setName(card.getName() + " 2"); -// filename = buildImagePathToCard(updated); -// } -// } } private static String searchForCardImage(CardDownloadData card) { @@ -112,30 +97,9 @@ public final class CardImageUtils { pathCache.put(card, path); return path; } - -// for (String set : SettingsManager.getIntance().getTokenLookupOrder()) { -// c.setSet(set); -// path = getTokenImagePath(c); -// file = new TFile(path); -// if (file.exists()) { -// pathCache.put(card, path); -// return path; -// } -// } return generateTokenDescriptorImagePath(card); } - public static String updateSet(String cardSet, boolean forUrl) { - String set = cardSet.toLowerCase(Locale.ENGLISH); - if (set.equals("con")) { - set = "cfx"; - } - if (forUrl) { - set = SettingsManager.getIntance().getSetNameReplacement(set); - } - return set; - } - public static String prepareCardNameForFile(String cardName) { return cardName.replace(":", "").replace("\"", "").replace("//", "-"); } @@ -162,6 +126,15 @@ public final class CardImageUtils { return path; } + public static String fixSetNameForWindows(String set) { + // windows can't create con folders + if (set.equals("CON") || set.equals("con")) { + return "COX"; + } else { + return set; + } + } + public static String buildImagePathToTokens() { String imagesPath = getImagesDir() + File.separator; @@ -182,7 +155,7 @@ public final class CardImageUtils { throw new IllegalArgumentException("Card " + card.getName() + " have empty set."); } - String set = updateSet(card.getSet(), false).toUpperCase(Locale.ENGLISH); // TODO: research auto-replace... old code? + String set = card.getSet().toUpperCase(Locale.ENGLISH); if (card.isToken()) { return buildImagePathToSetAsToken(set); @@ -195,14 +168,14 @@ public final class CardImageUtils { String imagesPath = getImagesDir() + File.separator; if (PreferencesDialog.isSaveImagesToZip()) { - return imagesPath + set + ".zip" + File.separator + set + File.separator; + return imagesPath + fixSetNameForWindows(set) + ".zip" + File.separator + fixSetNameForWindows(set) + File.separator; } else { - return imagesPath + set + File.separator; + return imagesPath + fixSetNameForWindows(set) + File.separator; } } private static String buildImagePathToSetAsToken(String set) { - return buildImagePathToTokens() + set + File.separator; + return buildImagePathToTokens() + fixSetNameForWindows(set) + File.separator; } public static String buildImagePathToCard(CardDownloadData card) { @@ -211,7 +184,7 @@ public final class CardImageUtils { String prefixType = ""; if (card.getType() != 0) { - prefixType = " " + Integer.toString(card.getType()); + prefixType = " " + card.getType(); } String cardName = card.getFileName(); @@ -228,6 +201,7 @@ public final class CardImageUtils { finalFileName = cardName + prefixType + ".full.jpg"; } + /* 2019-01-12: no needs in name corrections, all files must be same and auto-downloaded // if image file exists, correct name (for case sensitive systems) // use TFile for zips TFile dirFile = new TFile(setPath); @@ -246,12 +220,13 @@ public final class CardImageUtils { } catch (Exception ex) { log.error("Can't read card name from file, may be it broken: " + setPath); } + */ return setPath + finalFileName; } public static String generateFaceImagePath(String cardname, String set) { - return getImagesDir() + File.separator + "FACE" + File.separator + set + File.separator + prepareCardNameForFile(cardname) + ".jpg"; + return getImagesDir() + File.separator + "FACE" + File.separator + fixSetNameForWindows(set) + File.separator + prepareCardNameForFile(cardname) + ".jpg"; } public static String generateTokenDescriptorImagePath(CardDownloadData card) { diff --git a/Mage.Client/src/main/resources/META-INF/MANIFEST.MF b/Mage.Client/src/main/resources/META-INF/MANIFEST.MF deleted file mode 100644 index 342098cf3f..0000000000 --- a/Mage.Client/src/main/resources/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build -SplashScreen-Image: splash.jpg diff --git a/Mage.Client/src/main/resources/buttons/copy_128.png b/Mage.Client/src/main/resources/buttons/copy_128.png new file mode 100644 index 0000000000..cb3442c04c Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/copy_128.png differ diff --git a/Mage.Client/src/main/resources/buttons/copy_24.png b/Mage.Client/src/main/resources/buttons/copy_24.png new file mode 100644 index 0000000000..9a2920c9a1 Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/copy_24.png differ diff --git a/Mage.Client/src/main/resources/buttons/copy_32.png b/Mage.Client/src/main/resources/buttons/copy_32.png new file mode 100644 index 0000000000..9e8be51fac Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/copy_32.png differ diff --git a/Mage.Client/src/main/resources/buttons/paste_128.png b/Mage.Client/src/main/resources/buttons/paste_128.png new file mode 100644 index 0000000000..45f8a68c34 Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/paste_128.png differ diff --git a/Mage.Client/src/main/resources/buttons/paste_24.png b/Mage.Client/src/main/resources/buttons/paste_24.png new file mode 100644 index 0000000000..12ba4b619a Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/paste_24.png differ diff --git a/Mage.Client/src/main/resources/buttons/paste_32.png b/Mage.Client/src/main/resources/buttons/paste_32.png new file mode 100644 index 0000000000..aa72ebba80 Binary files /dev/null and b/Mage.Client/src/main/resources/buttons/paste_32.png differ diff --git a/Mage.Client/src/main/resources/card-pictures-tok.txt b/Mage.Client/src/main/resources/card-pictures-tok.txt index 0598855512..98099ba71d 100644 --- a/Mage.Client/src/main/resources/card-pictures-tok.txt +++ b/Mage.Client/src/main/resources/card-pictures-tok.txt @@ -86,6 +86,8 @@ |Generate|EMBLEM:MMA|Elspeth, Knight Errant||Emblem Elspeth|ElspethKnightErrantEmblem| |Generate|EMBLEM:SWS|Obi-Wan Kenobi||Emblem Obi-Wan Kenobi|ObiWanKenobiEmblem| |Generate|EMBLEM:RIX|Huatli, Radiant Champion||Emblem Huatli|HuatliRadiantChampionEmblem| +|Generate|EMBLEM:RNA|Domri, Chaos Bringer||Emblem Domri|DomriChaosBringerEmblem| +|Generate|EMBLEM:WAR|Nissa, Who Shakes the World||Emblem Nissa|NissaWhoShakesTheWorldEmblem| |Generate|PLANE:PCA|Plane - Academy At Tolaria West|||AcademyAtTolariaWestPlane| |Generate|PLANE:PCA|Plane - Agyrem|||AgyremPlane| |Generate|PLANE:PCA|Plane - Akoum|||AkoumPlane| @@ -105,6 +107,8 @@ |Generate|PLANE:PCA|Plane - Truga Jungle|||TrugaJunglePlane| |Generate|PLANE:PCA|Plane - Turri Island|||TurriIslandPlane| |Generate|PLANE:PCA|Plane - Undercity Reaches|||UndercityReachesPlane| +|Generate|TOK:ANA|Goblin|||GoblinToken| +|Generate|TOK:ANA|Spirit|||SpiritWhiteToken| |Generate|TOK:PCA|Eldrazi|||EldraziAnnihilatorToken| |Generate|TOK:10E|Ape|||PongifyApeToken| |Generate|TOK:10E|Dragon|||DragonToken2| @@ -185,6 +189,7 @@ |Generate|TOK:ALL|Graveborn|||SekKuarDeathkeeperGravebornToken| |Generate|TOK:ALL|Hippo|||HippoToken| |Generate|TOK:ALL|Soldier|||SoldierToken| +|Generate|TOK:ALL|Starfish|||StarfishToken| |Generate|TOK:ALL|Zombie|||ZombieToken| |Generate|TOK:APC|Angel|||HauntedAngelToken| |Generate|TOK:APC|Cat|||PenumbraBobcatToken| @@ -1182,3 +1187,39 @@ |Generate|TOK:ZEN|Vampire|| |Generate|TOK:ZEN|Wolf|||WolfToken| |Generate|TOK:ZEN|Zombie Giant|||QuestForTheGravelordZombieToken| +|Generate|TOK:RNA|Beast|||RedGreenBeastToken| +|Generate|TOK:RNA|Centaur|||CentaurToken| +|Generate|TOK:RNA|Frog Lizard|||FrogLizardToken| +|Generate|TOK:RNA|Goblin|||GoblinToken| +|Generate|TOK:RNA|Human|||HumanToken| +|Generate|TOK:RNA|Illusion|||MesmerizingBenthidToken| +|Generate|TOK:RNA|Ooze|||BiogenicOozeToken| +|Generate|TOK:RNA|Sphinx|||WardenSphinxToken| +|Generate|TOK:RNA|Spirit|||SpiritWhiteToken| +|Generate|TOK:RNA|Thopter|||ThopterToken| +|Generate|TOK:RNA|Treasure|||TreasureToken| +|Generate|TOK:RNA|Zombie|||ZombieToken| +|Generate|TOK:WAR|Angel|||AngelVigilanceToken| +|Generate|TOK:WAR|Assassin|||AssassinToken2| +|Generate|TOK:WAR|Devil|||DevilToken| +|Generate|TOK:WAR|Dragon|||DragonToken| +|Generate|TOK:WAR|Goblin|||GoblinToken| +|Generate|TOK:WAR|Servo|||ServoToken| +|Generate|TOK:WAR|Soldier|||SoldierVigilanceToken| +|Generate|TOK:WAR|Spirit|||UginTheIneffableToken| +|Generate|TOK:WAR|Voja, Friend to Elves|||VojaFriendToElvesToken| +|Generate|TOK:WAR|Wall|||TeyoToken| +|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| + + + + + + + diff --git a/Mage.Client/src/main/resources/hint/bad.png b/Mage.Client/src/main/resources/hint/bad.png new file mode 100644 index 0000000000..963626b1e0 Binary files /dev/null and b/Mage.Client/src/main/resources/hint/bad.png differ diff --git a/Mage.Client/src/main/resources/hint/bad_old.png b/Mage.Client/src/main/resources/hint/bad_old.png new file mode 100644 index 0000000000..6b4497d5ef Binary files /dev/null and b/Mage.Client/src/main/resources/hint/bad_old.png differ diff --git a/Mage.Client/src/main/resources/hint/good.png b/Mage.Client/src/main/resources/hint/good.png new file mode 100644 index 0000000000..14a87bd4a3 Binary files /dev/null and b/Mage.Client/src/main/resources/hint/good.png differ diff --git a/Mage.Client/src/main/resources/hint/good_old.png b/Mage.Client/src/main/resources/hint/good_old.png new file mode 100644 index 0000000000..3b7a6907ee Binary files /dev/null and b/Mage.Client/src/main/resources/hint/good_old.png differ diff --git a/Mage.Client/src/main/resources/hint/restrict.png b/Mage.Client/src/main/resources/hint/restrict.png new file mode 100644 index 0000000000..a977004e62 Binary files /dev/null and b/Mage.Client/src/main/resources/hint/restrict.png differ diff --git a/Mage.Client/src/main/resources/image.url.properties b/Mage.Client/src/main/resources/image.url.properties deleted file mode 100644 index d3ab400892..0000000000 --- a/Mage.Client/src/main/resources/image.url.properties +++ /dev/null @@ -1,78 +0,0 @@ -tsp=ts -tor=tr -mor=mt -ody=od -lrw=lw -plc=pc -gpt=gp -inv=in -ons=on -scg=sc -jud=ju -mmq=mm -pls=ps -mrd=mi -mir=mr -tst=ts -usg=us -apc=ap -nem=ne -dis=di -vis=vi -9ed=9e -8ed=8e -7ed=7e -4ed=4e -tsb=tsts -ulg=ul -5ed=5e -6ed=6e -btd=bd -sth=sh -por=po -s99=st -lgn=le -ice=ia -csp=cs -tmp=tp -s00=st2k -dst=ds -pcy=pr -uds=ud -exo=ex -lea=al -hop=pch -chr=ch -arn=an -wth=wl -leb=be -2ed=un -3ed=rv -brb=br -atq=aq -fem=fe -leg=lg -hml=hl -all=ai -drk=dk -ptk=p3k -gur=guru -ddc=dvd -dd2=jvc -ddd=gvl -unh=uh -dde=pvc -v09=fve -v10=fvr -v11=fvl -drb=fvd -h09=pds -ugl=ug -dd3dvd=ddadvd -dd3evg=ddaevg -dd3gvl=ddagvl -dd3jvc=ddajvc -# Remove setname as soon as the images can be downloaded -ignore.urls=TOK,H17 -# sets ordered by release time (newest goes first) -token.lookup.order=C18,M19,A25,DOM,E02,RIX,UST,XLN,IMA,H17,C17,V17,E01,DDT,CMA,HOU,MM3,DDS,AKH,DD3DVD,DD3EVG,DD3GVL,DD3JVC,H09,AER,PCA,C16,V16,MPS,KLD,DDR,CN2,EMN,EMA,SOI,DDQ,CP,CMA,ARENA,SUS,APAC,EURO,UGIN,C15,OGW,EXP,DDP,BFZ,DRB,V09,V10,V11,V12,V13,V14,V15,TPR,MPRP,DD3,DDO,ORI,MM2,PTC,DTK,FRF,KTK,M15,VMA,CNS,JOU,BNG,THS,DDL,M14,MMA,DGM,GTC,RTR,M13,AVR,DDI,DKA,ISD,M12,NPH,MBS,SOM,M11,ROE,DDE,WWK,ZEN,M10,GVL,ARB,DVD,CFX,JVC,ALA,EVE,SHM,EVG,MOR,LRW,10E,CLS,CHK,GRC \ No newline at end of file diff --git a/Mage.Client/src/main/resources/info/yellow_star_16.png b/Mage.Client/src/main/resources/info/yellow_star_16.png new file mode 100644 index 0000000000..849916980a Binary files /dev/null and b/Mage.Client/src/main/resources/info/yellow_star_16.png differ diff --git a/Mage.Client/src/main/resources/info/yellow_star_24.png b/Mage.Client/src/main/resources/info/yellow_star_24.png new file mode 100644 index 0000000000..41d21f49db Binary files /dev/null and b/Mage.Client/src/main/resources/info/yellow_star_24.png differ diff --git a/Mage.Client/src/main/resources/info/yellow_star_32.png b/Mage.Client/src/main/resources/info/yellow_star_32.png new file mode 100644 index 0000000000..029025a9a9 Binary files /dev/null and b/Mage.Client/src/main/resources/info/yellow_star_32.png differ diff --git a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java index 1974187c4d..ddcc9b34a7 100644 --- a/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java +++ b/Mage.Client/src/test/java/mage/client/game/MultiConnectTest.java @@ -1,8 +1,5 @@ package mage.client.game; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import javax.swing.*; import mage.client.components.MageUI; import mage.interfaces.MageClient; import mage.interfaces.callback.ClientCallback; @@ -13,6 +10,10 @@ import mage.utils.MageVersion; import org.apache.log4j.Logger; import org.junit.Ignore; +import javax.swing.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + /** * Test for emulating the connection from multi mage clients. * @@ -30,7 +31,7 @@ public class MultiConnectTest { private static final CountDownLatch latch = new CountDownLatch(USER_CONNECT_COUNT); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(MultiConnectTest.class); private static volatile int connected; @@ -70,7 +71,7 @@ public class MultiConnectTest { } @Override - public void disconnected(boolean errorCall) { + public void disconnected(boolean askToReconnect) { logger.info("disconnected"); } diff --git a/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java b/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java index 16f4e618f1..6ec7139d3e 100644 --- a/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java +++ b/Mage.Client/src/test/java/mage/client/game/TokensMtgImageSourceTest.java @@ -19,15 +19,15 @@ public class TokensMtgImageSourceTest { CardImageSource imageSource = TokensMtgImageSource.instance; CardImageUrls url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 1, "ORI", "")); - Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url.baseUrl); + Assert.assertEquals("https://tokens.mtg.onl/tokens/ORI_010-Thopter.jpg", url.baseUrl); url = imageSource.generateTokenUrl(new CardDownloadData("Thopter", "ORI", "0", false, 2, "ORI", "")); - Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url.baseUrl); + Assert.assertEquals("https://tokens.mtg.onl/tokens/ORI_011-Thopter.jpg", url.baseUrl); url = imageSource.generateTokenUrl(new CardDownloadData("Ashaya, the Awoken World", "ORI", "0", false, 0, "ORI", "")); - Assert.assertEquals("http://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url.baseUrl); + Assert.assertEquals("https://tokens.mtg.onl/tokens/ORI_007-Ashaya,-the-Awoken-World.jpg", url.baseUrl); url = imageSource.generateTokenUrl(new CardDownloadData("Emblem Gideon, Ally of Zendikar", "BFZ", "0", false, 0, null, "")); - Assert.assertEquals("http://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url.baseUrl); + Assert.assertEquals("https://tokens.mtg.onl/tokens/BFZ_012-Gideon-Emblem.jpg", url.baseUrl); } } diff --git a/Mage.Common/pom.xml b/Mage.Common/pom.xml index a139eab960..b82542869a 100644 --- a/Mage.Common/pom.xml +++ b/Mage.Common/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-common @@ -34,12 +34,12 @@ org.jboss jboss-common-core - 2.2.22.GA + 2.5.0.Final jboss jboss-serialization - 1.0.3.GA + 4.2.2.GA concurrent @@ -54,7 +54,7 @@ com.google.code.gson gson - 2.8.2 + 2.8.5 diff --git a/Mage.Common/src/main/java/mage/cards/CardDimensions.java b/Mage.Common/src/main/java/mage/cards/CardDimensions.java index f989042f25..79c2e20aa8 100644 --- a/Mage.Common/src/main/java/mage/cards/CardDimensions.java +++ b/Mage.Common/src/main/java/mage/cards/CardDimensions.java @@ -9,19 +9,19 @@ import static mage.constants.Constants.*; */ public class CardDimensions { - public int frameHeight; - public int frameWidth; - public int symbolHeight; - public int symbolWidth; - public int contentXOffset; - public int nameYOffset; - public int typeYOffset; - public int textYOffset; - public int textWidth; - public int textHeight; - public int powBoxTextTop; - public int powBoxTextLeft; - public int nameFontSize; + private final int frameHeight; + private final int frameWidth; + private final int symbolHeight; + private final int symbolWidth; + private final int contentXOffset; + private final int nameYOffset; + private final int typeYOffset; + private final int textYOffset; + private final int textWidth; + private final int textHeight; + private final int powBoxTextTop; + private final int powBoxTextLeft; + private final int nameFontSize; public CardDimensions(double scaleFactor) { frameHeight = (int) (FRAME_MAX_HEIGHT * scaleFactor); @@ -39,4 +39,55 @@ public class CardDimensions { nameFontSize = Math.max(9, (int) (NAME_FONT_MAX_SIZE * scaleFactor)); } + public int getFrameHeight() { + return frameHeight; + } + + public int getFrameWidth() { + return frameWidth; + } + + public int getSymbolHeight() { + return symbolHeight; + } + + public int getSymbolWidth() { + return symbolWidth; + } + + public int getContentXOffset() { + return contentXOffset; + } + + public int getNameYOffset() { + return nameYOffset; + } + + public int getTypeYOffset() { + return typeYOffset; + } + + public int getTextYOffset() { + return textYOffset; + } + + public int getTextWidth() { + return textWidth; + } + + public int getTextHeight() { + return textHeight; + } + + public int getPowBoxTextTop() { + return powBoxTextTop; + } + + public int getPowBoxTextLeft() { + return powBoxTextLeft; + } + + public int getNameFontSize() { + return nameFontSize; + } } diff --git a/Mage.Common/src/main/java/mage/cards/action/TransferData.java b/Mage.Common/src/main/java/mage/cards/action/TransferData.java index 11228aa5ea..815adb8893 100644 --- a/Mage.Common/src/main/java/mage/cards/action/TransferData.java +++ b/Mage.Common/src/main/java/mage/cards/action/TransferData.java @@ -7,11 +7,67 @@ import mage.cards.TextPopup; import mage.view.CardView; public class TransferData { - public Component component; - public TextPopup popupText; - public Point locationOnScreen; - public int popupOffsetX; - public int popupOffsetY; - public UUID gameId; - public CardView card; + private Component component; + private TextPopup popupText; + private Point locationOnScreen; + private int popupOffsetX; + private int popupOffsetY; + private UUID gameId; + private CardView card; + + public Component getComponent() { + return component; + } + + public void setComponent(Component component) { + this.component = component; + } + + public TextPopup getPopupText() { + return popupText; + } + + public void setPopupText(TextPopup popupText) { + this.popupText = popupText; + } + + public Point getLocationOnScreen() { + return locationOnScreen; + } + + public void setLocationOnScreen(Point locationOnScreen) { + this.locationOnScreen = locationOnScreen; + } + + public int getPopupOffsetX() { + return popupOffsetX; + } + + public void setPopupOffsetX(int popupOffsetX) { + this.popupOffsetX = popupOffsetX; + } + + public int getPopupOffsetY() { + return popupOffsetY; + } + + public void setPopupOffsetY(int popupOffsetY) { + this.popupOffsetY = popupOffsetY; + } + + public UUID getGameId() { + return gameId; + } + + public void setGameId(UUID gameId) { + this.gameId = gameId; + } + + public CardView getCard() { + return card; + } + + public void setCard(CardView card) { + this.card = card; + } } diff --git a/Mage.Common/src/main/java/mage/constants/Constants.java b/Mage.Common/src/main/java/mage/constants/Constants.java index dbcc030101..400b9df9ef 100644 --- a/Mage.Common/src/main/java/mage/constants/Constants.java +++ b/Mage.Common/src/main/java/mage/constants/Constants.java @@ -1,8 +1,6 @@ - package mage.constants; /** - * * @author BetaSteward_at_googlemail.com */ public final class Constants { @@ -50,19 +48,14 @@ public final class Constants { */ public static final int PRIORITY_TIME_SEC = 1200; - - public enum Option { - ; - public static final String POSSIBLE_ATTACKERS = "possibleAttackers"; + public static final String POSSIBLE_BLOCKERS = "possibleBlockers"; public static final String SPECIAL_BUTTON = "specialButton"; // used to control automatic answers of optional effects public static final String ORIGINAL_ID = "originalId"; public static final String SECOND_MESSAGE = "secondMessage"; public static final String HINT_TEXT = "hintText"; - } - } diff --git a/Mage.Common/src/main/java/mage/db/model/Feedback.java b/Mage.Common/src/main/java/mage/db/model/Feedback.java index bbc2f52c00..735569d66e 100644 --- a/Mage.Common/src/main/java/mage/db/model/Feedback.java +++ b/Mage.Common/src/main/java/mage/db/model/Feedback.java @@ -1,5 +1,6 @@ package mage.db.model; +import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; import java.util.Date; @@ -23,7 +24,7 @@ public class Feedback { private String email; @DatabaseField private String host; - @DatabaseField(columnName = "created_dt") + @DatabaseField(columnName = "created_dt", dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss") private Date createdDate; @DatabaseField diff --git a/Mage.Common/src/main/java/mage/db/model/Log.java b/Mage.Common/src/main/java/mage/db/model/Log.java index ff11495f1d..b80fadbea8 100644 --- a/Mage.Common/src/main/java/mage/db/model/Log.java +++ b/Mage.Common/src/main/java/mage/db/model/Log.java @@ -1,5 +1,6 @@ package mage.db.model; +import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; @@ -15,7 +16,7 @@ public class Log { @DatabaseField private String key; - @DatabaseField(columnName = "created_dt") + @DatabaseField(columnName = "created_dt", dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss") private Date createdDate; @DatabaseField private String arg0; diff --git a/Mage.Common/src/main/java/mage/interfaces/MageClient.java b/Mage.Common/src/main/java/mage/interfaces/MageClient.java index 09c079152f..e1612c3f72 100644 --- a/Mage.Common/src/main/java/mage/interfaces/MageClient.java +++ b/Mage.Common/src/main/java/mage/interfaces/MageClient.java @@ -1,11 +1,9 @@ - package mage.interfaces; import mage.interfaces.callback.CallbackClient; import mage.utils.MageVersion; /** - * * @author BetaSteward_at_googlemail.com */ public interface MageClient extends CallbackClient { @@ -14,7 +12,7 @@ public interface MageClient extends CallbackClient { void connected(String message); - void disconnected(boolean errorCall); + void disconnected(boolean askToReconnect); void showMessage(String message); diff --git a/Mage.Common/src/main/java/mage/remote/MageVersionException.java b/Mage.Common/src/main/java/mage/remote/MageVersionException.java index b5f317be3e..d67093874f 100644 --- a/Mage.Common/src/main/java/mage/remote/MageVersionException.java +++ b/Mage.Common/src/main/java/mage/remote/MageVersionException.java @@ -1,11 +1,9 @@ - package mage.remote; import mage.MageException; import mage.utils.MageVersion; /** - * * @author BetaSteward_at_googlemail.com */ public class MageVersionException extends MageException { @@ -13,7 +11,11 @@ public class MageVersionException extends MageException { private final MageVersion serverVersion; public MageVersionException(MageVersion clientVersion, MageVersion serverVersion) { - super("Wrong client version " + clientVersion + ", expecting version " + serverVersion + ". \r\n\r\nPlease download needed version from http://XMage.de or http://www.slightlymagic.net/forum/viewforum.php?f=70"); + super("Wrong client version." + + "
    Your version: " + clientVersion + + "
    Server version: " + serverVersion + + "
    Release app download: http://xmage.de" + + "
    BETA app download: http://xmage.today"); this.serverVersion = serverVersion; } diff --git a/Mage.Common/src/main/java/mage/remote/SessionImpl.java b/Mage.Common/src/main/java/mage/remote/SessionImpl.java index 91878a9797..71f982f69f 100644 --- a/Mage.Common/src/main/java/mage/remote/SessionImpl.java +++ b/Mage.Common/src/main/java/mage/remote/SessionImpl.java @@ -1,15 +1,5 @@ - package mage.remote; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.UndeclaredThrowableException; -import java.net.*; -import java.util.*; -import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; @@ -38,8 +28,16 @@ import org.jboss.remoting.transport.bisocket.Bisocket; import org.jboss.remoting.transport.socket.SocketWrapper; import org.jboss.remoting.transporter.TransporterClient; +import javax.swing.*; +import java.io.*; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.*; +import java.util.*; +import java.util.concurrent.CancellationException; +import java.util.concurrent.TimeUnit; + /** - * @author BetaSteward_at_googlemail.com + * @author BetaSteward_at_googlemail.com, JayDi85 */ public class SessionImpl implements Session { @@ -58,13 +56,15 @@ public class SessionImpl implements Session { private ServerState serverState; private SessionState sessionState = SessionState.DISCONNECTED; private Connection connection; - private final static int PING_CYCLES = 10; + private RemotingTask lastRemotingTask = null; + private static final int PING_CYCLES = 10; private final LinkedList pingTime = new LinkedList<>(); private String pingInfo = ""; private static boolean debugMode = false; private boolean canceled = false; private boolean jsonLogActive = false; + private String lastError = ""; static { debugMode = System.getProperty("debug.mage") != null; @@ -79,99 +79,129 @@ public class SessionImpl implements Session { return sessionId; } - // RemotingTask encapsulates a task which is involved with some JBoss Remoting. This is - // intended to be used with handleRemotingTaskExceptions for sharing the common exception - // handling. - public interface RemotingTask { + // RemotingTask - do server side works in background and return result, can be canceled at any time + public abstract class RemotingTask { - public boolean run() throws Throwable; + SwingWorker worker = null; + Throwable lastError = null; + + abstract public boolean work() throws Throwable; + + boolean doWork() throws Throwable { + worker = new SwingWorker() { + @Override + protected Boolean doInBackground() { + try { + return work(); + } catch (Throwable t) { + lastError = t; + return false; + } + } + }; + worker.execute(); + + boolean res = worker.get(); + if (lastError != null) { + throw lastError; + } + return res; + } + + public void cancel() { + if (worker != null) { + worker.cancel(true); + } + } } - // handleRemotingTaskExceptions runs the given task and handles exceptions appropriately. This - // way we can share the common exception handling. - private boolean handleRemotingTaskExceptions(RemotingTask remoting) { + private void showMessageToUser(String message) { + client.showMessage("Remote task error. " + message); + } + + private boolean doRemoteWorkAndHandleErrors(RemotingTask remoting) { + // execute remote task and wait result, can be canceled + lastRemotingTask = remoting; try { - return remoting.run(); + return remoting.doWork(); + } catch (InterruptedException | CancellationException t) { + // was canceled by user, nothing to show } catch (MalformedURLException ex) { - logger.fatal("", ex); - client.showMessage("Unable to connect to server. " + ex.getMessage()); + logger.fatal("Connect: wrong server address", ex); + showMessageToUser(ex.getMessage()); } catch (UndeclaredThrowableException ex) { String addMessage = ""; Throwable cause = ex.getCause(); if (cause instanceof InvocationFailureException) { InvocationFailureException exep = (InvocationFailureException) cause; if (exep.getCause() instanceof IOException) { - if (exep.getCause().getMessage().startsWith("Field hash null is not available on current")) { - addMessage = "Probabaly the server version is not compatible to the client. "; + if ((exep.getCause().getMessage() != null) && (exep.getCause().getMessage().startsWith("Field hash null is not available on current") + || exep.getCause().getMessage().endsWith("end of file"))) { + addMessage = "Probably the server version is not compatible with the client. "; } + } else { + logger.error("Connect: unknown server error", exep.getCause()); } } else if (cause instanceof NoSuchMethodException) { // NoSuchMethodException is thrown on an invocation of an unknow JBoss remoting // method, so it's likely to be because of a version incompatibility. addMessage = "The following method is not available in the server, probably the " - + "server version is not compatible to the client: " + cause.getMessage(); + + "server version is not compatible with the client: " + cause.getMessage(); } if (addMessage.isEmpty()) { - logger.fatal("", ex); + logger.fatal("Connect: unknown error", ex); } - client.showMessage("Unable to connect to server. " + addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); + showMessageToUser(addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); } catch (IOException ex) { - logger.fatal("", ex); + logger.fatal("Connect: unknown IO error", ex); String addMessage = ""; if (ex.getMessage() != null && ex.getMessage().startsWith("Unable to perform invocation")) { addMessage = "Maybe the server version is not compatible. "; } - client.showMessage("Unable to connect to server. " + addMessage + ex.getMessage() != null ? ex.getMessage() : ""); + showMessageToUser(addMessage + (ex.getMessage() != null ? ex.getMessage() : "")); } catch (MageVersionException ex) { - if (!canceled) { - client.showMessage("Unable to connect to server. " + ex.getMessage()); - } + logger.warn("Connect: wrong versions"); disconnect(false); + if (!canceled) { + showMessageToUser(ex.getMessage()); + } } catch (CannotConnectException ex) { if (!canceled) { handleCannotConnectException(ex); } } catch (Throwable t) { - logger.fatal("Unable to connect to server - ", t); + logger.fatal("Connect: FAIL", t); + disconnect(false); if (!canceled) { - disconnect(false); - StringBuilder sb = new StringBuilder(); - sb.append("Unable to connect to server.\n"); - for (StackTraceElement element : t.getStackTrace()) { - sb.append(element.toString()).append('\n'); - } - client.showMessage(sb.toString()); + showMessageToUser(t.getMessage()); } + } finally { + lastRemotingTask = null; } return false; } @Override public synchronized boolean register(final Connection connection) { - return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + return doRemoteConnection(connection) && doRemoteWorkAndHandleErrors(new RemotingTask() { @Override - public boolean run() throws Throwable { - logger.info("Trying to register as " + getUserName() + " to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); - boolean registerResult = server.registerUser(sessionId, connection.getUsername(), - connection.getPassword(), connection.getEmail()); - if (registerResult) { - logger.info("Registered as " + getUserName() + " to MAGE server at " + connection.getHost() + ':' + connection.getPort()); - } - return registerResult; + public boolean work() throws Throwable { + logger.info("Registration: username " + getUserName() + " for email " + getEmail()); + boolean result = server.registerUser(sessionId, connection.getUsername(), connection.getPassword(), connection.getEmail()); + logger.info("Registration: " + (result ? "DONE, check your email for new password" : "FAIL")); + return result; } }); } @Override public synchronized boolean emailAuthToken(final Connection connection) { - return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + return doRemoteConnection(connection) && doRemoteWorkAndHandleErrors(new RemotingTask() { @Override - public boolean run() throws Throwable { - logger.info("Trying to ask for an auth token to " + getEmail() + " to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); + public boolean work() throws Throwable { + logger.info("Auth request: requesting auth token for username " + getUserName() + " to email " + getEmail()); boolean result = server.emailAuthToken(sessionId, connection.getEmail()); - if (result) { - logger.info("An auth token is emailed to " + getEmail() + " from MAGE server at " + connection.getHost() + ':' + connection.getPort()); - } + logger.info("Auth request: " + (result ? "DONE, check your email for auth token" : "FAIL")); return result; } }); @@ -179,14 +209,12 @@ public class SessionImpl implements Session { @Override public synchronized boolean resetPassword(final Connection connection) { - return establishJBossRemotingConnection(connection) && handleRemotingTaskExceptions(new RemotingTask() { + return doRemoteConnection(connection) && doRemoteWorkAndHandleErrors(new RemotingTask() { @Override - public boolean run() throws Throwable { - logger.info("Trying reset the password in XMAGE server at " + connection.getHost() + ':' + connection.getPort()); + public boolean work() throws Throwable { + logger.info("Password reset: reseting password for username " + getUserName()); boolean result = server.resetPassword(sessionId, connection.getEmail(), connection.getAuthToken(), connection.getPassword()); - if (result) { - logger.info("Password is successfully reset in MAGE server at " + connection.getHost() + ':' + connection.getPort()); - } + logger.info("Password reset: " + (result ? "DONE, check your email for new password" : "FAIL")); return result; } }); @@ -194,58 +222,71 @@ public class SessionImpl implements Session { @Override public synchronized boolean connect(final Connection connection) { - return establishJBossRemotingConnection(connection) - && handleRemotingTaskExceptions(new RemotingTask() { - @Override - public boolean run() throws Throwable { - logger.info("Trying to log-in as " + getUserName() + " to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); - boolean registerResult; - if (connection.getAdminPassword() == null) { - // for backward compatibility. don't remove twice call - first one does nothing but for version checking - registerResult = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion(), connection.getUserIdStr()); - if (registerResult) { - server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString(), connection.getUserIdStr()); - } - } else { - registerResult = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); - } - if (registerResult) { - serverState = server.getServerState(); - if (!connection.getUsername().equals("Admin")) { - updateDatabase(connection.isForceDBComparison(), serverState); - } - logger.info("Logged-in as " + getUserName() + " to MAGE server at " + connection.getHost() + ':' + connection.getPort()); - client.connected(getUserName() + '@' + connection.getHost() + ':' + connection.getPort() + ' '); - return true; - } - disconnect(false); - return false; + return doRemoteConnection(connection) && doRemoteWorkAndHandleErrors(new RemotingTask() { + @Override + public boolean work() throws Throwable { + setLastError(""); + logger.info("Logging: as username " + getUserName() + " to server " + connection.getHost() + ':' + connection.getPort()); + boolean result; + + if (connection.getAdminPassword() == null) { + // for backward compatibility. don't remove twice call - first one does nothing but for version checking + result = server.connectUser(connection.getUsername(), connection.getPassword(), sessionId, client.getVersion(), connection.getUserIdStr()); + } else { + result = server.connectAdmin(connection.getAdminPassword(), sessionId, client.getVersion()); + } + + if (result) { + serverState = server.getServerState(); + + // client side check for incompatible versions + if (client.getVersion().compareTo(serverState.getVersion()) != 0) { + throw new MageVersionException(client.getVersion(), serverState.getVersion()); } - }); + + if (!connection.getUsername().equals("Admin")) { + server.setUserData(connection.getUsername(), sessionId, connection.getUserData(), client.getVersion().toString(), connection.getUserIdStr()); + updateDatabase(connection.isForceDBComparison(), serverState); + } + + logger.info("Logging: DONE"); + client.connected(getUserName() + '@' + connection.getHost() + ':' + connection.getPort() + ' '); + return true; + } + + logger.info("Logging: FAIL"); + disconnect(false); + return false; + } + }); } @Override public Optional getServerHostname() { - return isConnected() ? Optional.of(connection.getHost()) : Optional.empty(); + return isConnected() ? Optional.of(connection.getHost()) : Optional.empty(); } @Override public boolean stopConnecting() { canceled = true; + if (lastRemotingTask != null) { + lastRemotingTask.cancel(); + } return true; } - private boolean establishJBossRemotingConnection(final Connection connection) { + private boolean doRemoteConnection(final Connection connection) { + // connect to server and setup all data, can be canceled if (isConnected()) { disconnect(true); } this.connection = connection; this.canceled = false; sessionState = SessionState.CONNECTING; - boolean result = handleRemotingTaskExceptions(new RemotingTask() { + lastRemotingTask = new RemotingTask() { @Override - public boolean run() throws Throwable { - logger.info("Trying to connect to XMAGE server at " + connection.getHost() + ':' + connection.getPort()); + public boolean work() throws Throwable { + logger.info("Connect: connecting to server " + connection.getHost() + ':' + connection.getPort()); System.setProperty("http.nonProxyHosts", "code.google.com"); System.setProperty("socksNonProxyHosts", "code.google.com"); @@ -256,6 +297,9 @@ public class SessionImpl implements Session { System.clearProperty("http.proxyHost"); System.clearProperty("http.proxyPort"); + if (connection.getProxyType() != Connection.ProxyType.NONE) { + logger.info("Connect: using proxy " + connection.getProxyHost() + ":" + connection.getProxyPort()); + } switch (connection.getProxyType()) { case SOCKS: System.setProperty("socksProxyHost", connection.getProxyHost()); @@ -383,38 +427,46 @@ public class SessionImpl implements Session { sessionId = callbackClient.getSessionId(); sessionState = SessionState.CONNECTED; - logger.info("Connected to MAGE server at " + connection.getHost() + ':' + connection.getPort()); + logger.info("Connect: DONE"); return true; } - }); + }; + + boolean result; + try { + result = doRemoteWorkAndHandleErrors(lastRemotingTask); + } finally { + lastRemotingTask = null; + } + if (result) { return true; + } else { + disconnect(false); + return false; } - disconnect(false); - return false; } private void updateDatabase(boolean forceDBComparison, ServerState serverState) { - long cardDBVersion = CardRepository.instance.getContentVersionFromDB(); - if (forceDBComparison || serverState.getCardsContentVersion() > cardDBVersion) { - List classNames = CardRepository.instance.getClassNames(); - List cards = server.getMissingCardsData(classNames); - CardRepository.instance.addCards(cards); - CardRepository.instance.setContentVersion(serverState.getCardsContentVersion()); - logger.info("Updating client cards DB - existing cards: " + classNames.size() + " new cards: " + cards.size() - + " content versions - server: " + serverState.getCardsContentVersion() + " client: " + cardDBVersion); - } + // download NEW cards/sets, but do not download data fixes (it's an old and rare feature from old clients, e.g. one client for different servers with different cards) + // use case: server gets new minor version with new cards, old client can get that cards too without donwload new version + // sets long expansionDBVersion = ExpansionRepository.instance.getContentVersionFromDB(); if (forceDBComparison || serverState.getExpansionsContentVersion() > expansionDBVersion) { List setCodes = ExpansionRepository.instance.getSetCodes(); List expansions = server.getMissingExpansionData(setCodes); - for (ExpansionInfo expansion : expansions) { - ExpansionRepository.instance.add(expansion); - } - ExpansionRepository.instance.setContentVersion(serverState.getExpansionsContentVersion()); - logger.info("Updating client expansions DB - existing sets: " + setCodes.size() + " new sets: " + expansions.size() - + " content versions - server: " + serverState.getExpansionsContentVersion() + " client: " + expansionDBVersion); + logger.info("DB: updating sets... Found new: " + expansions.size()); + ExpansionRepository.instance.saveSets(expansions, null, serverState.getExpansionsContentVersion()); + } + + // cards + long cardDBVersion = CardRepository.instance.getContentVersionFromDB(); + if (forceDBComparison || serverState.getCardsContentVersion() > cardDBVersion) { + List classNames = CardRepository.instance.getClassNames(); + List cards = server.getMissingCardsData(classNames); + logger.info("DB: updating cards... Found new: " + cards.size()); + CardRepository.instance.saveCards(cards, serverState.getCardsContentVersion()); } } @@ -442,7 +494,7 @@ public class SessionImpl implements Session { t = t.getCause(); } - client.showMessage("Unable to connect to server. " + message); + client.showMessage("Unable connect to server. " + message); if (logger.isTraceEnabled()) { logger.trace("StackTrace", t); } @@ -450,12 +502,12 @@ public class SessionImpl implements Session { /** * @param askForReconnect - true = connection was lost because of error and - * ask the user if he want to try to reconnect + * ask the user if he want to try to reconnect */ @Override public synchronized void disconnect(boolean askForReconnect) { if (isConnected()) { - logger.info("DISCONNECT (still connected)"); + logger.info("Disconnecting..."); sessionState = SessionState.DISCONNECTING; } if (connection == null || sessionState == SessionState.DISCONNECTED) { @@ -463,18 +515,20 @@ public class SessionImpl implements Session { } try { - callbackClient.removeListener(callbackHandler); - callbackClient.disconnect(); + if (callbackClient.isConnected()) { + callbackClient.removeListener(callbackHandler); + callbackClient.disconnect(); + } TransporterClient.destroyTransporterClient(server); } catch (Throwable ex) { - logger.fatal("Error disconnecting ...", ex); + logger.fatal("Disconnecting FAIL", ex); } if (sessionState == SessionState.DISCONNECTING || sessionState == SessionState.CONNECTING) { sessionState = SessionState.DISCONNECTED; - logger.info("Disconnected ... "); + logger.info("Disconnecting DONE"); if (askForReconnect) { - client.showError("Network error. You have been disconnected from " + connection.getHost()); + client.showError("Network error. You have been disconnected from " + connection.getHost()); } client.disconnected(askForReconnect); // MageFrame with check to reconnect pingTime.clear(); @@ -483,7 +537,6 @@ public class SessionImpl implements Session { @Override public synchronized void reconnect(Throwable throwable) { - logger.info("RECONNECT - Connected: " + isConnected()); client.disconnected(true); } @@ -514,7 +567,7 @@ public class SessionImpl implements Session { @Override public void handleConnectionException(Throwable throwable, Client client) { - logger.info("connection to server lost - " + throwable.getMessage(), throwable); + logger.info("Connect: lost connection to server.", throwable); reconnect(throwable); } } @@ -1530,10 +1583,24 @@ public class SessionImpl implements Session { } private void handleThrowable(Throwable t) { - logger.fatal("Communication error", t); - // Probably this can cause hanging the client under certain circumstances as the disconnect method is synchronized - // so check if it's needed - // disconnect(true); + + // ignore interrupted exceptions -- it's connection problem or user's close + if (t instanceof InterruptedException) { + //logger.error("Connection error: was interrupted", t); + Thread.currentThread().interrupt(); + return; + } + + if (t instanceof RuntimeException) { + RuntimeException re = (RuntimeException) t; + if (t.getCause() instanceof InterruptedException) { + //logger.error("Connection error: was interrupted by runtime exception", t.getCause()); + Thread.currentThread().interrupt(); + return; + } + } + + logger.fatal("Connection error: other", t); } private void handleMageException(MageException ex) { @@ -1580,7 +1647,7 @@ public class SessionImpl implements Session { @Override public boolean ping() { try { - if (isConnected()) { + if (isConnected() && sessionId != null) { long startTime = System.nanoTime(); if (!server.ping(sessionId, pingInfo)) { logger.error("Ping failed: " + this.getUserName() + " Session: " + sessionId + " to MAGE server at " + connection.getHost() + ':' + connection.getPort()); @@ -1628,6 +1695,15 @@ public class SessionImpl implements Session { this.jsonLogActive = jsonLogActive; } + private void setLastError(String error) { + lastError = error; + } + + @Override + public String getLastError() { + return lastError; + } + } class MageAuthenticator extends Authenticator { diff --git a/Mage.Common/src/main/java/mage/remote/interfaces/Connect.java b/Mage.Common/src/main/java/mage/remote/interfaces/Connect.java index 747f5e63c5..4795578ffc 100644 --- a/Mage.Common/src/main/java/mage/remote/interfaces/Connect.java +++ b/Mage.Common/src/main/java/mage/remote/interfaces/Connect.java @@ -1,4 +1,3 @@ - package mage.remote.interfaces; import mage.remote.Connection; @@ -37,10 +36,12 @@ public interface Connect { boolean muteUserChat(String userName, long durationMinute); boolean setActivation(String userName, boolean active); - + boolean toggleActivation(String userName); boolean lockUser(String userName, long durationMinute); String getSessionId(); + + String getLastError(); } diff --git a/Mage.Common/src/main/java/mage/utils/CardUtil.java b/Mage.Common/src/main/java/mage/utils/CardColorUtil.java similarity index 98% rename from Mage.Common/src/main/java/mage/utils/CardUtil.java rename to Mage.Common/src/main/java/mage/utils/CardColorUtil.java index ccd928f988..8556bfd698 100644 --- a/Mage.Common/src/main/java/mage/utils/CardUtil.java +++ b/Mage.Common/src/main/java/mage/utils/CardColorUtil.java @@ -13,7 +13,7 @@ import java.util.List; * @version 0.1 02.11.2010 * @author nantuko */ -public final class CardUtil { +public final class CardColorUtil { private static final String regexBlack = ".*\\x7b.{0,2}B.{0,2}\\x7d.*"; private static final String regexBlue = ".*\\x7b.{0,2}U.{0,2}\\x7d.*"; diff --git a/Mage.Common/src/main/java/mage/utils/DeckBuilder.java b/Mage.Common/src/main/java/mage/utils/DeckBuilder.java index 74615c9bff..6d599f935c 100644 --- a/Mage.Common/src/main/java/mage/utils/DeckBuilder.java +++ b/Mage.Common/src/main/java/mage/utils/DeckBuilder.java @@ -164,10 +164,7 @@ public final class DeckBuilder { } } if (count > 0) { - Integer typeCount = colorCount.get(symbol); - if (typeCount == null) { - typeCount = 0; - } + Integer typeCount = colorCount.getOrDefault(symbol, 0); typeCount += 1; colorCount.put(symbol, typeCount); } @@ -243,9 +240,9 @@ public final class DeckBuilder { int type; if (card.isCreature()) { type = 10; - } else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) { + } else if (card.hasSubtype(SubType.EQUIPMENT, null)) { type = 8; - } else if (card.getSubtype(null).contains(SubType.AURA)) { + } else if (card.hasSubtype(SubType.AURA, null)) { type = 5; } else if (card.isInstant()) { type = 7; @@ -283,10 +280,7 @@ public final class DeckBuilder { multicolor += 1; colors.add(symbol); } - Integer typeCount = singleCount.get(symbol); - if (typeCount == null) { - typeCount = 0; - } + Integer typeCount = singleCount.getOrDefault(symbol, 0); typeCount += 1; singleCount.put(symbol, typeCount); maxSingleCount = Math.max(maxSingleCount, typeCount); diff --git a/Mage.Common/src/main/java/mage/utils/MageVersion.java b/Mage.Common/src/main/java/mage/utils/MageVersion.java index 4a0feb9728..d2283709cf 100644 --- a/Mage.Common/src/main/java/mage/utils/MageVersion.java +++ b/Mage.Common/src/main/java/mage/utils/MageVersion.java @@ -1,35 +1,43 @@ package mage.utils; +import mage.util.JarVersion; + import java.io.Serializable; /** - * * @author BetaSteward_at_googlemail.com */ public class MageVersion implements Serializable, Comparable { - /** - * - */ - public final static int MAGE_VERSION_MAJOR = 1; - public final static int MAGE_VERSION_MINOR = 4; - public final static int MAGE_VERSION_PATCH = 31; - public final static String MAGE_VERSION_MINOR_PATCH = "V4"; - public final static String MAGE_VERSION_INFO = ""; + public static final int MAGE_VERSION_MAJOR = 1; + public static final int MAGE_VERSION_MINOR = 4; + public static final int MAGE_VERSION_PATCH = 35; + public static final String MAGE_EDITION_INFO = ""; // set "-beta" for 1.4.32-betaV0 + public static final String MAGE_VERSION_MINOR_PATCH = "V1"; // default + // strict mode + private static final boolean MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME = false; // set true on uncompatible github changes, set false after new major release (after MAGE_VERSION_PATCH changes) + public static final boolean MAGE_VERSION_SHOW_BUILD_TIME = true; private final int major; private final int minor; private final int patch; private final String minorPatch; // doesn't matter for compatibility + private final String buildTime; + private String editionInfo; - private String info = ""; + public MageVersion(Class sourceClass) { + this(MAGE_VERSION_MAJOR, MAGE_VERSION_MINOR, MAGE_VERSION_PATCH, MAGE_VERSION_MINOR_PATCH, MAGE_EDITION_INFO, sourceClass); + } - public MageVersion(int major, int minor, int patch, String minorPatch, String info) { + public MageVersion(int major, int minor, int patch, String minorPatch, String editionInfo, Class sourceClass) { this.major = major; this.minor = minor; this.patch = patch; this.minorPatch = minorPatch; - this.info = info; + this.editionInfo = editionInfo; + + // build time + this.buildTime = JarVersion.getBuildTime(sourceClass); } public int getMajor() { @@ -48,9 +56,18 @@ public class MageVersion implements Serializable, Comparable { return minorPatch; } + public String toString(boolean showBuildTime) { + // 1.4.32-betaV0 (build: time) + String res = major + "." + minor + '.' + patch + editionInfo + minorPatch; + if (showBuildTime && !this.buildTime.isEmpty()) { + res += " (build: " + this.buildTime + ")"; + } + return res; + } + @Override public String toString() { - return major + "." + minor + '.' + patch + info + minorPatch; + return toString(MAGE_VERSION_SHOW_BUILD_TIME); } @Override @@ -64,7 +81,9 @@ public class MageVersion implements Serializable, Comparable { if (patch != o.patch) { return patch - o.patch; } - return info.compareTo(o.info); + if (MAGE_VERSION_MINOR_PATCH_MUST_BE_SAME && !minorPatch.equals(o.minorPatch)) { + return minorPatch.compareTo(o.minorPatch); + } + return editionInfo.compareTo(o.editionInfo); } - } diff --git a/Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java b/Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java index 0a220e12fd..17fe10e05b 100644 --- a/Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java +++ b/Mage.Common/src/main/java/mage/utils/properties/PropertiesUtil.java @@ -21,7 +21,11 @@ public final class PropertiesUtil { static { try (InputStream in = PropertiesUtil.class.getResourceAsStream("/xmage.properties")) { - properties.load(in); + if(in != null) { + properties.load(in); + } else { + logger.warn("No xmage.properties were found"); + } } catch (FileNotFoundException fnfe) { logger.warn("No xmage.properties were found on classpath"); } catch (IOException e) { diff --git a/Mage.Common/src/main/java/mage/view/CardView.java b/Mage.Common/src/main/java/mage/view/CardView.java index cdd9b22e66..8505589a47 100644 --- a/Mage.Common/src/main/java/mage/view/CardView.java +++ b/Mage.Common/src/main/java/mage/view/CardView.java @@ -1,9 +1,6 @@ - package mage.view; import com.google.gson.annotations.Expose; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; @@ -29,6 +26,9 @@ import mage.target.Target; import mage.target.Targets; import mage.util.SubTypeList; +import java.util.*; +import java.util.stream.Collectors; + /** * @author BetaSteward_at_googlemail.com */ @@ -108,8 +108,11 @@ public class CardView extends SimpleCardView { protected boolean isChoosable; protected boolean selected; protected boolean canAttack; + protected boolean canBlock; protected boolean inViewerOnly; + protected Card originalCard = null; + public CardView(Card card) { this(card, null, false); } @@ -126,6 +129,7 @@ public class CardView extends SimpleCardView { public CardView(CardView cardView) { super(cardView.id, cardView.expansionSetCode, cardView.cardNumber, cardView.usesVariousArt, cardView.tokenSetCode, cardView.gameObject, cardView.tokenDescriptor); + this.originalCard = cardView.originalCard; this.id = UUID.randomUUID(); this.parentId = cardView.parentId; @@ -198,15 +202,17 @@ public class CardView extends SimpleCardView { this.isChoosable = cardView.isChoosable; this.selected = cardView.selected; this.canAttack = cardView.canAttack; + this.canBlock = cardView.canBlock; this.inViewerOnly = cardView.inViewerOnly; + this.originalCard = cardView.originalCard.copy(); } /** * @param card * @param game * @param controlled is the card view created for the card controller - used - * for morph / face down cards to know which player may see information for - * the card + * for morph / face down cards to know which player may see information for + * the card */ public CardView(Card card, Game game, boolean controlled) { this(card, game, controlled, false, false); @@ -232,15 +238,17 @@ public class CardView extends SimpleCardView { /** * @param card * @param game - * @param controlled is the card view created for the card controller - used - * for morph / face down cards to know which player may see information for - * the card + * @param controlled is the card view created for the card controller - used + * for morph / face down cards to know which player may see information for + * the card * @param showFaceDownCard if true and the card is not on the battlefield, - * also a face down card is shown in the view, face down cards will be shown - * @param storeZone if true the card zone will be set in the zone attribute. + * also a face down card is shown in the view, face down cards will be shown + * @param storeZone if true the card zone will be set in the zone attribute. */ public CardView(Card card, Game game, boolean controlled, boolean showFaceDownCard, boolean storeZone) { super(card.getId(), card.getExpansionSetCode(), card.getCardNumber(), card.getUsesVariousArt(), card.getTokenSetCode(), game != null, card.getTokenDescriptor()); + this.originalCard = card; + // no information available for face down cards as long it's not a controlled face down morph card // TODO: Better handle this in Framework (but currently I'm not sure how to do it there) LevelX2 boolean showFaceUp = true; @@ -279,7 +287,7 @@ public class CardView extends SimpleCardView { this.power = Integer.toString(card.getPower().getValue()); this.toughness = Integer.toString(card.getToughness().getValue()); this.cardTypes = card.getCardType(); - this.faceDown = ((Permanent) card).isFaceDown(game); + this.faceDown = card.isFaceDown(game); } else { // this.hideInfo = true; return; @@ -289,9 +297,9 @@ public class CardView extends SimpleCardView { SplitCard splitCard = null; if (card.isSplitCard()) { splitCard = (SplitCard) card; - rotate = (((SplitCard) card).getSpellAbility().getSpellAbilityType()) != SpellAbilityType.SPLIT_AFTERMATH; + rotate = (card.getSpellAbility().getSpellAbilityType()) != SpellAbilityType.SPLIT_AFTERMATH; } else if (card instanceof Spell) { - switch (((Spell) card).getSpellAbility().getSpellAbilityType()) { + switch (card.getSpellAbility().getSpellAbilityType()) { case SPLIT_FUSED: splitCard = (SplitCard) ((Spell) card).getCard(); rotate = true; @@ -383,12 +391,12 @@ public class CardView extends SimpleCardView { this.cardNumber = ((PermanentToken) card).getToken().getOriginalCardNumber(); } else { // a created token - this.expansionSetCode = ((PermanentToken) card).getExpansionSetCode(); - this.tokenDescriptor = ((PermanentToken) card).getTokenDescriptor(); + this.expansionSetCode = card.getExpansionSetCode(); + this.tokenDescriptor = card.getTokenDescriptor(); } // // set code und card number for token copies to get the image - this.rules = ((PermanentToken) card).getRules(game); + this.rules = card.getRules(game); this.type = ((PermanentToken) card).getToken().getTokenType(); } else { this.rarity = card.getRarity(); @@ -460,10 +468,14 @@ public class CardView extends SimpleCardView { // Get starting loyalty this.startingLoyalty = "" + card.getStartingLoyalty(); + + } public CardView(MageObject object) { super(object.getId(), "", "0", false, "", true, ""); + this.originalCard = null; + this.name = object.getName(); this.displayName = object.getName(); if (object instanceof Permanent) { @@ -984,6 +996,14 @@ public class CardView extends SimpleCardView { this.canAttack = canAttack; } + public boolean isCanBlock() { + return canBlock; + } + + public void setCanBlock(boolean canBlock) { + this.canBlock = canBlock; + } + public boolean isCreature() { return cardTypes.contains(CardType.CREATURE); } @@ -1046,4 +1066,8 @@ public class CardView extends SimpleCardView { public boolean inViewerOnly() { return inViewerOnly; } + + public Card getOriginalCard() { + return this.originalCard; + } } diff --git a/Mage.Common/src/main/java/mage/view/DraftClientMessage.java b/Mage.Common/src/main/java/mage/view/DraftClientMessage.java index 33bf75f212..dfaaf2bc22 100644 --- a/Mage.Common/src/main/java/mage/view/DraftClientMessage.java +++ b/Mage.Common/src/main/java/mage/view/DraftClientMessage.java @@ -13,21 +13,12 @@ public class DraftClientMessage implements Serializable { private DraftView draftView; private DraftPickView draftPickView; - private String message; - public DraftClientMessage(DraftView draftView) { + public DraftClientMessage(DraftView draftView, DraftPickView draftPickView) { this.draftView = draftView; - } - - public DraftClientMessage(DraftPickView draftPickView) { this.draftPickView = draftPickView; } - public DraftClientMessage(DraftView draftView, String message) { - this.message = message; - this.draftView = draftView; - } - public DraftPickView getDraftPickView() { return draftPickView; } diff --git a/Mage.Common/src/main/java/mage/view/DraftView.java b/Mage.Common/src/main/java/mage/view/DraftView.java index 241c6a840f..b1f2b960a4 100644 --- a/Mage.Common/src/main/java/mage/view/DraftView.java +++ b/Mage.Common/src/main/java/mage/view/DraftView.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.List; import mage.cards.ExpansionSet; import mage.game.draft.Draft; +import mage.game.draft.DraftCube; import mage.game.draft.DraftPlayer; /** @@ -17,6 +18,7 @@ public class DraftView implements Serializable { private static final long serialVersionUID = 1L; private final List sets = new ArrayList<>(); + private final List setCodes = new ArrayList<>(); private final int boosterNum; private final int cardNum; private final List players = new ArrayList<>(); @@ -24,11 +26,14 @@ public class DraftView implements Serializable { public DraftView(Draft draft) { if (draft.getDraftCube() != null) { for (int i = 0; i < draft.getNumberBoosters(); i++) { - sets.add(draft.getDraftCube().getName()); + DraftCube cube = draft.getDraftCube(); + sets.add(cube.getName()); + setCodes.add(cube.getCode()); } } else { for (ExpansionSet set: draft.getSets()) { sets.add(set.getName()); + setCodes.add(set.getCode()); } } this.boosterNum = draft.getBoosterNum(); @@ -42,6 +47,10 @@ public class DraftView implements Serializable { return sets; } + public List getSetCodes() { + return setCodes; + } + public List getPlayers() { return players; } diff --git a/Mage.Common/src/main/java/mage/view/GameView.java b/Mage.Common/src/main/java/mage/view/GameView.java index ffc10011df..f0466f6950 100644 --- a/Mage.Common/src/main/java/mage/view/GameView.java +++ b/Mage.Common/src/main/java/mage/view/GameView.java @@ -1,14 +1,7 @@ - package mage.view; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.costs.Cost; import mage.cards.Card; @@ -32,8 +25,10 @@ import mage.players.Player; import mage.watchers.common.CastSpellLastTurnWatcher; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class GameView implements Serializable { @@ -90,7 +85,7 @@ public class GameView implements Serializable { if (object != null) { if (object instanceof Permanent) { boolean controlled = ((Permanent) object).getControllerId().equals(createdForPlayerId); - stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, ((Permanent) object).getName(), new CardView(((Permanent) object), game, controlled, false, false))); + stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), new CardView(((Permanent) object), game, controlled, false, false))); } else { stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, card.getName(), new CardView(card, game, false, false, false))); } @@ -109,14 +104,14 @@ public class GameView implements Serializable { } else if (object instanceof Emblem) { CardView cardView = new CardView(new EmblemView((Emblem) object)); // Card sourceCard = (Card) ((Emblem) object).getSourceObject(); - ((StackAbility) stackObject).setName(((Emblem) object).getName()); + stackObject.setName(object.getName()); // ((StackAbility) stackObject).setExpansionSetCode(sourceCard.getExpansionSetCode()); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); } else if (object instanceof Plane) { CardView cardView = new CardView(new PlaneView((Plane) object)); - ((StackAbility) stackObject).setName(((Plane) object).getName()); + stackObject.setName(object.getName()); stack.put(stackObject.getId(), new StackAbilityView(game, (StackAbility) stackObject, object.getName(), cardView)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); @@ -131,7 +126,7 @@ public class GameView implements Serializable { } else if (object instanceof StackAbility) { StackAbility stackAbility = ((StackAbility) object); stackAbility.newId(); - stack.put(stackObject.getId(), new CardView(((StackAbility) stackObject))); + stack.put(stackObject.getId(), new CardView(stackObject)); checkPaid(stackObject.getId(), ((StackAbility) stackObject)); } else { LOGGER.fatal("Object can't be cast to StackAbility: " + object.getName() + ' ' + object.toString() + ' ' + object.getClass().toString()); @@ -182,7 +177,7 @@ public class GameView implements Serializable { this.special = false; } - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { spellsCastCurrentTurn = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn(); } else { diff --git a/Mage.Common/src/main/java/mage/view/TableView.java b/Mage.Common/src/main/java/mage/view/TableView.java index c3d748c344..efd42d3239 100644 --- a/Mage.Common/src/main/java/mage/view/TableView.java +++ b/Mage.Common/src/main/java/mage/view/TableView.java @@ -1,11 +1,5 @@ - package mage.view; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.UUID; import mage.constants.SkillLevel; import mage.constants.TableState; import mage.game.Game; @@ -15,6 +9,12 @@ import mage.game.draft.Draft; import mage.game.match.MatchPlayer; import mage.game.tournament.TournamentPlayer; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -32,10 +32,12 @@ public class TableView implements Serializable { private TableState tableState; private final SkillLevel skillLevel; private final String tableStateText; + private final String seatsInfo; private boolean isTournament; private List seats = new ArrayList<>(); private List games = new ArrayList<>(); private final String quitRatio; + private final String minimumRating; private final boolean limited; private final boolean rated; private final boolean passworded; @@ -45,10 +47,6 @@ public class TableView implements Serializable { this.tableId = table.getId(); this.gameType = table.getGameType(); this.tableName = table.getName(); - String tableNameInfo = null; - if (tableName != null && !tableName.isEmpty()) { - tableNameInfo = " [" + table.getName() + ']'; - } this.controllerName = table.getControllerName(); this.tableState = table.getState(); if (table.getState() == TableState.WAITING @@ -68,8 +66,9 @@ public class TableView implements Serializable { } if (!table.isTournament()) { // MATCH + seatsInfo = "" + table.getMatch().getPlayers().size() + '/' + table.getSeats().length; if (table.getState() == TableState.WAITING || table.getState() == TableState.READY_TO_START) { - tableStateText = table.getState().toString() + " (" + table.getMatch().getPlayers().size() + '/' + table.getSeats().length + ')'; + tableStateText = table.getState().toString() + " (" + seatsInfo + ')'; } else { tableStateText = table.getState().toString(); } @@ -93,7 +92,7 @@ public class TableView implements Serializable { sbScore.append(" Draws: ").append(table.getMatch().getDraws()); } this.controllerName += sb.toString(); - this.deckType = table.getDeckType() + (tableNameInfo != null ? tableNameInfo : ""); + this.deckType = table.getDeckType(); StringBuilder addInfo = new StringBuilder(); if (table.getMatch().getGames().isEmpty()) { addInfo.append("Wins:").append(table.getMatch().getWinsNeeded()); @@ -111,6 +110,7 @@ public class TableView implements Serializable { this.additionalInfo = addInfo.toString(); this.skillLevel = table.getMatch().getOptions().getSkillLevel(); this.quitRatio = Integer.toString(table.getMatch().getOptions().getQuitRatio()); + this.minimumRating = Integer.toString(table.getMatch().getOptions().getMinimumRating()); this.limited = table.getMatch().getOptions().isLimited(); this.rated = table.getMatch().getOptions().isRated(); this.passworded = !table.getMatch().getOptions().getPassword().isEmpty(); @@ -127,10 +127,11 @@ public class TableView implements Serializable { } } this.controllerName += sb1.toString(); + this.seatsInfo = "" + table.getTournament().getPlayers().size() + "/" + table.getNumberOfSeats(); StringBuilder infoText = new StringBuilder(); StringBuilder stateText = new StringBuilder(table.getState().toString()); infoText.append("Wins:").append(table.getTournament().getOptions().getMatchOptions().getWinsNeeded()); - infoText.append(" Seats: ").append(table.getTournament().getPlayers().size()).append('/').append(table.getNumberOfSeats()); + infoText.append(" Seats: ").append(this.seatsInfo); switch (table.getState()) { case WAITING: stateText.append(" (").append(table.getTournament().getPlayers().size()).append('/').append(table.getNumberOfSeats()).append(')'); @@ -156,9 +157,10 @@ public class TableView implements Serializable { } this.additionalInfo = infoText.toString(); this.tableStateText = stateText.toString(); - this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo() + (tableNameInfo != null ? tableNameInfo : ""); + this.deckType = table.getDeckType() + ' ' + table.getTournament().getBoosterInfo(); this.skillLevel = table.getTournament().getOptions().getMatchOptions().getSkillLevel(); this.quitRatio = Integer.toString(table.getTournament().getOptions().getQuitRatio()); + this.minimumRating = Integer.toString(table.getTournament().getOptions().getMinimumRating()); this.limited = table.getTournament().getOptions().getMatchOptions().isLimited(); this.rated = table.getTournament().getOptions().getMatchOptions().isRated(); this.passworded = !table.getTournament().getOptions().getPassword().isEmpty(); @@ -177,11 +179,11 @@ public class TableView implements Serializable { public String getControllerName() { return controllerName; } - + public boolean getSpectatorsAllowed() { return spectatorsAllowed; } - + public String getGameType() { return gameType; @@ -207,6 +209,10 @@ public class TableView implements Serializable { return games; } + public String getSeatsInfo() { + return seatsInfo; + } + public boolean isTournament() { return this.isTournament; } @@ -227,6 +233,10 @@ public class TableView implements Serializable { return quitRatio; } + public String getMinimumRating() { + return minimumRating; + } + public boolean isLimited() { return limited; } diff --git a/Mage.Common/src/main/java/mage/view/TournamentGameView.java b/Mage.Common/src/main/java/mage/view/TournamentGameView.java index c50662f21e..e2ca098709 100644 --- a/Mage.Common/src/main/java/mage/view/TournamentGameView.java +++ b/Mage.Common/src/main/java/mage/view/TournamentGameView.java @@ -43,7 +43,7 @@ public class TournamentGameView implements Serializable { String duelingTime = ""; if (game.hasEnded()) { - if (game.getEndTime() != null) { + if (game.getEndTime() != null && game.getStartTime() != null) { duelingTime = " (" + DateFormat.getDuration((game.getEndTime().getTime() - game.getStartTime().getTime())/1000) + ')'; } this.state = "Finished" + duelingTime; diff --git a/Mage.Common/src/main/java/mage/view/UserRequestMessage.java b/Mage.Common/src/main/java/mage/view/UserRequestMessage.java index 71c582b229..51cb913d0e 100644 --- a/Mage.Common/src/main/java/mage/view/UserRequestMessage.java +++ b/Mage.Common/src/main/java/mage/view/UserRequestMessage.java @@ -1,19 +1,18 @@ - package mage.view; +import mage.constants.PlayerAction; + import java.io.Serializable; import java.util.UUID; -import mage.constants.PlayerAction; /** - * * @author LevelX2 */ public class UserRequestMessage implements Serializable { private static final long serialVersionUID = 1L; - private final String titel; + private final String title; private final String message; private UUID relatedUserId; private String relatedUserName; @@ -32,8 +31,8 @@ public class UserRequestMessage implements Serializable { private String button3Text; private PlayerAction button3Action; - public UserRequestMessage(String titel, String message) { - this.titel = titel; + public UserRequestMessage(String title, String message) { + this.title = title; this.message = message; this.button1Action = null; this.button2Action = null; @@ -68,8 +67,8 @@ public class UserRequestMessage implements Serializable { this.button3Action = buttonAction; } - public String getTitel() { - return titel; + public String getTitle() { + return title; } public static long getSerialVersionUID() { diff --git a/Mage.Plugins/Mage.Counter.Plugin/pom.xml b/Mage.Plugins/Mage.Counter.Plugin/pom.xml index a8af62ad9d..576fd8497d 100644 --- a/Mage.Plugins/Mage.Counter.Plugin/pom.xml +++ b/Mage.Plugins/Mage.Counter.Plugin/pom.xml @@ -7,7 +7,7 @@ org.mage mage-plugins - 1.4.31 + 1.4.35 mage-counter-plugin @@ -35,8 +35,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Plugins/pom.xml b/Mage.Plugins/pom.xml index 19abee5bda..98b9b80e55 100644 --- a/Mage.Plugins/pom.xml +++ b/Mage.Plugins/pom.xml @@ -7,7 +7,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-plugins diff --git a/Mage.Server.Console/pom.xml b/Mage.Server.Console/pom.xml index a48379e45c..ac1e109629 100644 --- a/Mage.Server.Console/pom.xml +++ b/Mage.Server.Console/pom.xml @@ -6,10 +6,9 @@ org.mage mage-root - 1.4.31 + 1.4.35 - org.mage mage.server.console jar Mage Server Console @@ -53,7 +52,6 @@ maven-jar-plugin - ${manifest.file} true mage.server.console.ConsoleFrame diff --git a/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java b/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java index 80737a9b56..1ee9285c39 100644 --- a/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java +++ b/Mage.Server.Console/src/main/java/mage/server/console/ConsoleFrame.java @@ -1,11 +1,3 @@ - - -/* - * ConsoleFrame.java - * - * Created on May 13, 2011, 2:39:10 PM - */ - package mage.server.console; import mage.interfaces.MageClient; @@ -25,7 +17,6 @@ import java.util.concurrent.TimeUnit; import java.util.prefs.Preferences; /** - * * @author BetaSteward_at_googlemail.com */ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { @@ -35,9 +26,10 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { private static Session session; private ConnectDialog connectDialog; private static final Preferences prefs = Preferences.userNodeForPackage(ConsoleFrame.class); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); - + private static final MageVersion version = new MageVersion(ConsoleFrame.class); + private static final ScheduledExecutorService pingTaskExecutor = Executors.newSingleThreadScheduledExecutor(); + /** * @return the session */ @@ -54,7 +46,9 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { return version; } - /** Creates new form ConsoleFrame */ + /** + * Creates new form ConsoleFrame + */ public ConsoleFrame() { addWindowListener(new WindowAdapter() { @@ -72,11 +66,11 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { } catch (Exception ex) { logger.fatal("", ex); } - + pingTaskExecutor.scheduleAtFixedRate(() -> session.ping(), 60, 60, TimeUnit.SECONDS); } - public boolean connect(Connection connection) { + public boolean connect(Connection connection) { if (session.connect(connection)) { this.consolePanel1.start(); return true; @@ -100,7 +94,8 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { btnSendMessage.setEnabled(false); } - /** This method is called from within the constructor to + /** + * This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. @@ -143,16 +138,16 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) - .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jToolBar1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) + .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 933, Short.MAX_VALUE) ); layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 432, Short.MAX_VALUE)) + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(jToolBar1, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0) + .addComponent(consolePanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 432, Short.MAX_VALUE)) ); pack(); @@ -177,9 +172,9 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { }//GEN-LAST:event_btnSendMessageActionPerformed /** - * @param args the command line arguments - */ - public static void main(String args[]) { + * @param args the command line arguments + */ + public static void main(String[] args) { logger.info("Starting MAGE server console version " + version); logger.info("Logging level: " + logger.getEffectiveLevel()); @@ -205,9 +200,8 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void connected(final String message) { if (SwingUtilities.isEventDispatchThread()) { setStatusText(message); - enableButtons(); - } - else { + enableButtons(); + } else { SwingUtilities.invokeLater(() -> { setStatusText(message); enableButtons(); @@ -216,13 +210,12 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { } @Override - public void disconnected(boolean errorCall) { + public void disconnected(boolean askToReconnect) { if (SwingUtilities.isEventDispatchThread()) { consolePanel1.stop(); setStatusText("Not connected"); disableButtons(); - } - else { + } else { SwingUtilities.invokeLater(() -> { consolePanel1.stop(); setStatusText("Not connected"); @@ -235,8 +228,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void showMessage(final String message) { if (SwingUtilities.isEventDispatchThread()) { JOptionPane.showMessageDialog(this, message); - } - else { + } else { SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(getFrame(), message)); } } @@ -245,8 +237,7 @@ public class ConsoleFrame extends javax.swing.JFrame implements MageClient { public void showError(final String message) { if (SwingUtilities.isEventDispatchThread()) { JOptionPane.showMessageDialog(this, message, "Error", JOptionPane.ERROR_MESSAGE); - } - else { + } else { SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(getFrame(), message, "Error", JOptionPane.ERROR_MESSAGE)); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml index 34ac2c8b53..9aba1692b5 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-deck-constructed @@ -34,8 +34,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java index 112563f76d..51bbb20fc0 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/AusHighlander.java @@ -1,20 +1,19 @@ package mage.deck; -import java.util.HashMap; -import java.util.Map; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; + +import java.util.HashMap; +import java.util.Map; /** - * * @author spjspj */ public class AusHighlander extends Constructed { - public static final Map pointMap = new HashMap(); + public static final Map pointMap = new HashMap<>(); static { pointMap.put("Ancestral Recall", 4); @@ -29,20 +28,18 @@ public class AusHighlander extends Constructed { pointMap.put("Mox Sapphire", 3); pointMap.put("Sol Ring", 3); pointMap.put("Time Walk", 3); - pointMap.put("Tinker", 3); pointMap.put("Vampiric Tutor", 3); - pointMap.put("Yawgmoth’s Will", 3); + pointMap.put("Yawgmoth's Will", 3); pointMap.put("Channel", 2); pointMap.put("Dig Through Time", 2); pointMap.put("Library of Alexandria", 2); pointMap.put("Mana Crypt", 2); + pointMap.put("Mind Twist", 2); pointMap.put("Mystical Tutor", 2); pointMap.put("Protean Hulk", 2); - pointMap.put("Skullclamp", 2); - pointMap.put("Strip Mine", 2); + pointMap.put("Tinker", 2); pointMap.put("Tolarian Academy", 2); pointMap.put("Treasure Cruise", 2); - pointMap.put("Back to Basics", 1); pointMap.put("Balance", 1); pointMap.put("Birthing Pod", 1); pointMap.put("Crop Rotation", 1); @@ -51,38 +48,40 @@ public class AusHighlander extends Constructed { pointMap.put("Fastbond", 1); pointMap.put("Force of Will", 1); pointMap.put("Gifts Ungiven", 1); - pointMap.put("Green Sun’s Zenith", 1); + pointMap.put("Green Sun's Zenith", 1); pointMap.put("Hermit Druid", 1); pointMap.put("Intuition", 1); pointMap.put("Jace, the Mind Sculptor", 1); pointMap.put("Karakas", 1); - pointMap.put("Lim-Dul’s Vault", 1); + pointMap.put("Life from the Loam", 1); + pointMap.put("Lim-Dul's Vault", 1); pointMap.put("Mana Drain", 1); pointMap.put("Mana Vault", 1); pointMap.put("Memory Jar", 1); pointMap.put("Merchant Scroll", 1); - pointMap.put("Mind Twist", 1); - pointMap.put("Mishra’s Workshop", 1); + pointMap.put("Mishra's Workshop", 1); pointMap.put("Natural Order", 1); pointMap.put("Oath of Druids", 1); pointMap.put("Personal Tutor", 1); - pointMap.put("Sensei’s Divining Top", 1); + pointMap.put("Sensei's Divining Top", 1); + pointMap.put("Skullclamp", 1); pointMap.put("Snapcaster Mage", 1); pointMap.put("Stoneforge Mystic", 1); + pointMap.put("Strip Mine", 1); pointMap.put("Survival of the Fittest", 1); pointMap.put("Tainted Pact", 1); pointMap.put("Time Spiral", 1); pointMap.put("Timetwister", 1); pointMap.put("True-Name Nemesis", 1); - pointMap.put("Umezawa’s Jitte", 1); + pointMap.put("Umezawa's Jitte", 1); pointMap.put("Wasteland", 1); - pointMap.put("Yawgmoth’s Bargain", 1); + pointMap.put("Yawgmoth's Bargain", 1); } public AusHighlander() { this("Australian Highlander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -96,8 +95,8 @@ public class AusHighlander extends Constructed { public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 60) { - invalid.put("Deck", "Must contain 60 singleton cards: has " + (deck.getCards().size()) + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " singleton cards: has " + (deck.getCards().size()) + " cards"); valid = false; } if (deck.getSideboard().size() > 15) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java index 7e13650658..08e1f2e4aa 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Brawl.java @@ -1,14 +1,14 @@ package mage.deck; -import java.util.*; import mage.abilities.common.CanBeYourCommanderAbility; import mage.cards.Card; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author spjspj */ public class Brawl extends Constructed { @@ -30,13 +30,18 @@ public class Brawl extends Constructed { super(name); } + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); - if (deck.getCards().size() + deck.getSideboard().size() != 60) { - invalid.put("Deck", "Must contain 60 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + if (deck.getCards().size() + deck.getSideboard().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java index 23f5c57f2f..ad5665628d 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/CanadianHighlander.java @@ -1,25 +1,24 @@ package mage.deck; -import java.util.HashMap; -import java.util.Map; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; + +import java.util.HashMap; +import java.util.Map; /** - * * @author spjspj */ public class CanadianHighlander extends Constructed { - public static final Map pointMap = new HashMap(); + public static final Map pointMap = new HashMap<>(); static { pointMap.put("Ancestral Recall", 7); pointMap.put("Balance", 1); - pointMap.put("Birthing Pod", 3); + pointMap.put("Birthing Pod", 2); pointMap.put("Black Lotus", 7); pointMap.put("Demonic Tutor", 3); pointMap.put("Dig Through Time", 1); @@ -27,11 +26,10 @@ public class CanadianHighlander extends Constructed { pointMap.put("Fastbond", 1); pointMap.put("Flash", 7); pointMap.put("Gifts Ungiven", 2); - pointMap.put("Hermit Druid", 1); pointMap.put("Imperial Seal", 1); pointMap.put("Intuition", 1); pointMap.put("Library of Alexandria", 1); - pointMap.put("Mana Crypt", 2); + pointMap.put("Mana Crypt", 3); pointMap.put("Mana Drain", 1); pointMap.put("Mana Vault", 1); pointMap.put("Merchant Scroll", 1); @@ -43,9 +41,9 @@ public class CanadianHighlander extends Constructed { pointMap.put("Mox Sapphire", 3); pointMap.put("Mystical Tutor", 2); pointMap.put("Natural Order", 4); - pointMap.put("Personal Tutor", 1); pointMap.put("Protean Hulk", 3); pointMap.put("Sol Ring", 3); + pointMap.put("Spellseeker", 1); pointMap.put("Stoneforge Mystic", 1); pointMap.put("Strip Mine", 2); pointMap.put("Summoner's Pact", 2); @@ -64,7 +62,7 @@ public class CanadianHighlander extends Constructed { public CanadianHighlander() { this("Canadian Highlander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java index 439e7bf928..d944f8068f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Commander.java @@ -1,6 +1,5 @@ package mage.deck; -import java.util.*; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; @@ -12,11 +11,11 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author Plopman */ public class Commander extends Constructed { @@ -27,7 +26,7 @@ public class Commander extends Constructed { public Commander() { this("Commander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -75,13 +74,23 @@ public class Commander extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 98; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + invalid.put("Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } @@ -632,7 +641,7 @@ public class Commander extends Constructed { || cn.equals("krark-clan ironworks") || cn.equals("krenko, mob boss") || cn.equals("krosan restorer") || cn.equals("laboratory maniac") || cn.equals("leonin relic-warder") || cn.equals("leyline of the void") - || cn.equals("memnarch") || cn.equals("memnarch") + || cn.equals("memnarch") || cn.equals("meren of clan nel toth") || cn.equals("mikaeus, the unhallowed") || cn.equals("mindcrank") || cn.equals("mindslaver") || cn.equals("minion reflector") || cn.equals("mycosynth lattice") @@ -650,7 +659,7 @@ public class Commander extends Constructed { || cn.equals("sunder") || cn.equals("storm cauldron") || cn.equals("teferi's puzzle box") || cn.equals("tangle wire") - || cn.equals("teferi, mage of zhalfir") || cn.equals("teferi, mage of zhalfir") + || cn.equals("teferi, mage of zhalfir") || cn.equals("tezzeret the seeker") || cn.equals("time stretch") || cn.equals("time warp") || cn.equals("training grounds") || cn.equals("triskelavus") || cn.equals("triskelion") @@ -744,7 +753,7 @@ public class Commander extends Constructed { } edhPowerLevel += numberInfinitePieces * 12; - edhPowerLevel = (int) Math.round(edhPowerLevel / 10); + edhPowerLevel = Math.round(edhPowerLevel / 10); if (edhPowerLevel >= 100) { edhPowerLevel = 99; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java index c9fd0ae21a..2b0ec13871 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Eternal.java @@ -1,10 +1,8 @@ - package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** * This class implements the new casual format "Eternal", which is legacy with @@ -18,7 +16,7 @@ public class Eternal extends Constructed { public Eternal() { super("Constructed - Eternal"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Extended.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Extended.java index c37f03fece..fccedcb81f 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Extended.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Extended.java @@ -1,17 +1,13 @@ - - package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; import java.util.Calendar; import java.util.GregorianCalendar; /** - * * @author BetaSteward_at_googlemail.com */ public class Extended extends Constructed { @@ -22,13 +18,11 @@ public class Extended extends Constructed { GregorianCalendar cutoff; if (current.get(Calendar.MONTH) > 9) { cutoff = new GregorianCalendar(current.get(Calendar.YEAR) - 3, Calendar.SEPTEMBER, 1); - } - else { + } else { cutoff = new GregorianCalendar(current.get(Calendar.YEAR) - 4, Calendar.SEPTEMBER, 1); } - for (ExpansionSet set: Sets.getInstance().values()) { - if (set.getReleaseDate().after(cutoff.getTime()) && - (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + for (ExpansionSet set : Sets.getInstance().values()) { + if (set.getSetType().isStandardLegal() && set.getReleaseDate().after(cutoff.getTime())) { setCodes.add(set.getCode()); } } @@ -38,6 +32,6 @@ public class Extended extends Constructed { banned.add("Ponder"); banned.add("Preordain"); banned.add("Stoneforge Mystic"); - + } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java index 70e6d0feaf..41733f9116 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Freeform.java @@ -1,11 +1,9 @@ - package mage.deck; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; /** - * * @author fireshoes */ public class Freeform extends DeckValidator { @@ -14,12 +12,22 @@ public class Freeform extends DeckValidator { super("Constructed - Freeform"); } + @Override + public int getDeckMinSize() { + return 40; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; // http://magic.wizards.com/en/gameinfo/gameplay/formats/freeform - if (deck.getCards().size() < 40) { - invalid.put("Deck", "Must contain at least 40 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } return valid; diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java index 14811d576c..5e2ce9b0d2 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/FreeformCommander.java @@ -1,7 +1,5 @@ - package mage.deck; -import java.util.*; import mage.abilities.Ability; import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.PartnerWithAbility; @@ -12,8 +10,9 @@ import mage.cards.decks.Constructed; import mage.cards.decks.Deck; import mage.filter.FilterMana; +import java.util.*; + /** - * * @author spjspj */ public class FreeformCommander extends Constructed { @@ -26,19 +25,32 @@ public class FreeformCommander extends Constructed { for (ExpansionSet set : Sets.getInstance().values()) { setCodes.add(set.getCode()); } + + // no banned cards + this.banned.clear(); } public FreeformCommander(String name) { super(name); } + @Override + public int getDeckMinSize() { + return 98; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + invalid.put("Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } @@ -48,7 +60,7 @@ public class FreeformCommander extends Constructed { for (Map.Entry entry : counts.entrySet()) { if (entry.getValue() > 1) { - if (!basicLandNames.contains(entry.getKey())) { + if (!basicLandNames.contains(entry.getKey()) && !anyNumberCardsAllowed.contains(entry.getKey())) { invalid.put(entry.getKey(), "Too many: " + entry.getValue()); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Frontier.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Frontier.java index 843825bdf5..28aa7cc776 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Frontier.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Frontier.java @@ -1,15 +1,13 @@ - package mage.deck; -import java.util.Date; -import java.util.GregorianCalendar; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; + +import java.util.Date; +import java.util.GregorianCalendar; /** - * * @author fireshoes */ public class Frontier extends Constructed { @@ -19,8 +17,7 @@ public class Frontier extends Constructed { Date cutoff = new GregorianCalendar(2014, 6, 18).getTime(); // M15 release date for (ExpansionSet set : Sets.getInstance().values()) { - if ((set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff)) - && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + if (set.getSetType().isStandardLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalType2.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalType2.java index 02aff6b5ab..04a6957064 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalType2.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/HistoricalType2.java @@ -1,24 +1,19 @@ package mage.deck; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; + +import java.util.*; /** * This class represents a deck from any past standard. - * + *

    * This class was originally made to work with the historical standard ruleset. * Data taken from http://thattournament.website/historic-tournament.php (site * changed, originally http://mtgt.nfshost.com/historic-tournament.php) - * + *

    * If there are any questions or corrections, feel free to contact me. * * @author Marthinwurer (at gmail.com) @@ -30,54 +25,54 @@ public class HistoricalType2 extends Constructed { * Kamigawa/Ravnica standard, where rotation stabilized. */ protected static final String[][] standards = { - // 1st standard: The Dark, Fallen Empires, and 4th. - {"DRK", "FEM", "4ED"}, - // 2nd standard: 4th, Fallen Empires, Ice Age, Chronicles, Homelands, - // Alliances, and Mirage. - {"FEM", "4ED", "ICE", "CHR", "HML", "ALL", "MIR"}, - // 3rd standard: 4th, Chronicles, Alliances, Mirage, Visions. - {"4ED", "CHR", "ALL", "MIR", "VIS"}, - // 4th Standard: Ice Age, Homelands, Alliances, Mirage, Visions, 5th, - // and Weatherlight. - {"ICE", "HML", "ALL", "MIR", "VIS", "5ED", "WTH"}, - // 5th Standard: Mirage, Visions, 5th, Weatherlight, Tempest, - // Stronghold, and Exodus. - {"MIR", "VIS", "5ED", "WTH", "TMP", "STH", "EXO"}, - // 6th Standard: 5th, Tempest, Stronghold, Exodus, Urza's Saga, Urza's - // Legacy, Urza's Destiny. - {"5ED", "TMP", "STH", "EXO", "USG", "ULG"}, - // 7th Standard: Tempest, Stronghold, Exodus, Urza's Saga, Urza's - // Legacy, 6th, Urza's Destiny. - {"TMP", "STH", "EXO", "USG", "ULG", "6ED", "UDS"}, - // 8th Standard: Urza's Saga, Urza's Legacy, 6th, Urza's Destiny, - // Mercadian Masques, Nemesis, Prophecy. - {"USG", "ULG", "6ED", "UDS", "MMQ", "NEM", "PCY"}, - // 9th Standard - {"6ED", "MMQ", "NEM", "PCY", "INV", "PLS"}, - // 10th Standard - {"7ED", "MMQ", "NEM", "PCY", "INV", "PLS", "APC"}, - // 11th Standard - {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, - // 12th Standard - {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, - // 13th Standard - {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, - // 14th Standard - {"8ED", "ONS", "LGN", "SCG", "MRD", "DST", "5DN"}, - // 15th Standard - {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, - // 16th Standard - {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, - // 17th Standard - {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, - // 18th Standard - {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, - // 19th Standard - {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, - // 20th Standard - {"10E", "CSP", "TSP", "TSB", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, - // 21st Standard - {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} + // 1st standard: The Dark, Fallen Empires, and 4th. + {"DRK", "FEM", "4ED"}, + // 2nd standard: 4th, Fallen Empires, Ice Age, Chronicles, Homelands, + // Alliances, and Mirage. + {"FEM", "4ED", "ICE", "CHR", "HML", "ALL", "MIR"}, + // 3rd standard: 4th, Chronicles, Alliances, Mirage, Visions. + {"4ED", "CHR", "ALL", "MIR", "VIS"}, + // 4th Standard: Ice Age, Homelands, Alliances, Mirage, Visions, 5th, + // and Weatherlight. + {"ICE", "HML", "ALL", "MIR", "VIS", "5ED", "WTH"}, + // 5th Standard: Mirage, Visions, 5th, Weatherlight, Tempest, + // Stronghold, and Exodus. + {"MIR", "VIS", "5ED", "WTH", "TMP", "STH", "EXO"}, + // 6th Standard: 5th, Tempest, Stronghold, Exodus, Urza's Saga, Urza's + // Legacy, Urza's Destiny. + {"5ED", "TMP", "STH", "EXO", "USG", "ULG"}, + // 7th Standard: Tempest, Stronghold, Exodus, Urza's Saga, Urza's + // Legacy, 6th, Urza's Destiny. + {"TMP", "STH", "EXO", "USG", "ULG", "6ED", "UDS"}, + // 8th Standard: Urza's Saga, Urza's Legacy, 6th, Urza's Destiny, + // Mercadian Masques, Nemesis, Prophecy. + {"USG", "ULG", "6ED", "UDS", "MMQ", "NEM", "PCY"}, + // 9th Standard + {"6ED", "MMQ", "NEM", "PCY", "INV", "PLS"}, + // 10th Standard + {"7ED", "MMQ", "NEM", "PCY", "INV", "PLS", "APC"}, + // 11th Standard + {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, + // 12th Standard + {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, + // 13th Standard + {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, + // 14th Standard + {"8ED", "ONS", "LGN", "SCG", "MRD", "DST", "5DN"}, + // 15th Standard + {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + // 16th Standard + {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + // 17th Standard + {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, + // 18th Standard + {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + // 19th Standard + {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + // 20th Standard + {"10E", "CSP", "TSP", "TSB", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, + // 21st Standard + {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} }; /** @@ -109,15 +104,6 @@ public class HistoricalType2 extends Constructed { @Override public boolean validate(Deck deck) { - // debug code for finding set info -// System.out.println(); -// for (ExpansionSet set : Sets.getInstance().values()) { -// if (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION) { -// System.out.println("Set:\t" + set.getCode() + "\t" + set.getReleaseDate() + "\t" + set.getName() + "\t" + set.getBlockName()); -// } -// } - - Map leastInvalid = null; boolean valid = false; @@ -187,9 +173,9 @@ public class HistoricalType2 extends Constructed { // Get the sets in that time period. // (code taken from standard.java) for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getReleaseDate().after(start.getTime()) - && set.getReleaseDate().before(end.getTime()) - && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + if (set.getSetType().isStandardLegal() + && set.getReleaseDate().after(start.getTime()) + && set.getReleaseDate().before(end.getTime())) { setCodes.add(set.getCode()); } } 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 90f4ee51ba..59df80af48 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 @@ -3,10 +3,8 @@ package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** - * * LevelX2 */ public class Legacy extends Constructed { @@ -14,7 +12,7 @@ public class Legacy extends Constructed { public Legacy() { super("Constructed - Legacy"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } 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 a64c82dde8..44d2031e34 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 @@ -1,16 +1,13 @@ - package mage.deck; -import java.util.Date; -import java.util.GregorianCalendar; - import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; + +import java.util.Date; +import java.util.GregorianCalendar; /** - * * @author LevelX2 */ public class Modern extends Constructed { @@ -20,8 +17,7 @@ public class Modern extends Constructed { Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date for (ExpansionSet set : Sets.getInstance().values()) { - if ((set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff)) - && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { setCodes.add(set.getCode()); } } @@ -42,6 +38,7 @@ public class Modern extends Constructed { banned.add("Great Furnace"); banned.add("Green Sun's Zenith"); banned.add("Hypergenesis"); + banned.add("Krark-Clan Ironworks"); banned.add("Mental Misstep"); banned.add("Ponder"); banned.add("Preordain"); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ModernNoBannedList.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ModernNoBannedList.java index b01961163a..1718cc3b3a 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ModernNoBannedList.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/ModernNoBannedList.java @@ -1,17 +1,13 @@ - - package mage.deck; -import java.util.Date; -import java.util.GregorianCalendar; - import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; + +import java.util.Date; +import java.util.GregorianCalendar; /** - * * @author LevelX2 */ public class ModernNoBannedList extends Constructed { @@ -21,8 +17,7 @@ public class ModernNoBannedList extends Constructed { Date cutoff = new GregorianCalendar(2003, 6, 28).getTime(); // Eight edition release date for (ExpansionSet set : Sets.getInstance().values()) { - if ((set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff)) - && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + if (set.getSetType().isModernLegal() && (set.getReleaseDate().after(cutoff) || set.getReleaseDate().equals(cutoff))) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java index a9e2407759..ab5500ebd2 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Momir.java @@ -1,15 +1,14 @@ - package mage.deck; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.cards.Card; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author nigelzor */ public class Momir extends DeckValidator { @@ -22,12 +21,22 @@ public class Momir extends DeckValidator { super(name); } + @Override + public int getDeckMinSize() { + return 60; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 60) { - invalid.put("Deck", "Must contain 60 cards: has " + deck.getCards().size() + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); valid = false; } 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 7e14fd8480..7fdb3ca6a4 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 @@ -9,10 +9,8 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.constants.Rarity; -import mage.constants.SetType; /** - * * @author LevelX2 */ public class Pauper extends Constructed { @@ -22,7 +20,7 @@ public class Pauper extends Constructed { //TODO: Add only Magic Online sets for pauper for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java index bf23f9f9dd..6479df83be 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/PennyDreadfulCommander.java @@ -1,8 +1,5 @@ - package mage.deck; -import java.util.*; -import java.util.Map.Entry; import mage.abilities.Ability; import mage.abilities.common.CanBeYourCommanderAbility; import mage.abilities.keyword.PartnerAbility; @@ -12,11 +9,12 @@ import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; +import java.util.*; +import java.util.Map.Entry; + /** - * * @author spjspj */ public class PennyDreadfulCommander extends Constructed { @@ -28,7 +26,7 @@ public class PennyDreadfulCommander extends Constructed { public PennyDreadfulCommander() { this("Penny Dreadful Commander"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -38,13 +36,23 @@ public class PennyDreadfulCommander extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 98; + } + + @Override + public int getSideboardMinSize() { + return 1; + } + @Override public boolean validate(Deck deck) { boolean valid = true; FilterMana colorIdentity = new FilterMana(); if (deck.getCards().size() + deck.getSideboard().size() != 100) { - invalid.put("Deck", "Must contain 100 cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); + invalid.put("Deck", "Must contain " + 100 + " cards: has " + (deck.getCards().size() + deck.getSideboard().size()) + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java index 9f8781d3cf..138a97fe9e 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Premodern.java @@ -24,6 +24,7 @@ public class Premodern extends Constructed { setCodes.add(mage.sets.Weatherlight.getInstance().getCode()); setCodes.add(mage.sets.Tempest.getInstance().getCode()); setCodes.add(mage.sets.Stronghold.getInstance().getCode()); + setCodes.add(mage.sets.Exodus.getInstance().getCode()); setCodes.add(mage.sets.UrzasSaga.getInstance().getCode()); setCodes.add(mage.sets.UrzasLegacy.getInstance().getCode()); setCodes.add(mage.sets.ClassicSixthEdition.getInstance().getCode()); diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java index 2e2098244a..dd54b019f3 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Standard.java @@ -1,19 +1,13 @@ package mage.deck; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.List; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.constants.SetType; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class Standard extends Constructed { @@ -23,25 +17,18 @@ public class Standard extends Constructed { setCodes.addAll(makeLegalSets()); - banned.add("Attune with Aether"); // since 2018-01-15 - banned.add("Aetherworks Marvel"); - banned.add("Felidar Guardian"); banned.add("Rampaging Ferocidon"); // since 2018-01-15 - banned.add("Ramunap Ruins"); // since 2018-01-15 - banned.add("Rogue Refiner"); // since 2018-01-15 - banned.add("Smuggler's Copter"); } private static boolean isFallSet(ExpansionSet set) { Calendar cal = Calendar.getInstance(); cal.setTime(set.getReleaseDate()); // Fall sets are normally released during or after September - return set.getSetType() == SetType.EXPANSION - && (cal.get(Calendar.MONTH) > 7); + return set.getSetType() == SetType.EXPANSION && (cal.get(Calendar.MONTH) > 7); } public static List makeLegalSets() { - List codes = new ArrayList(); + List codes = new ArrayList<>(); GregorianCalendar current = new GregorianCalendar(); List sets = new ArrayList(Sets.getInstance().values()); Collections.sort(sets, new Comparator() { @@ -65,13 +52,10 @@ public class Standard extends Constructed { } } } - // Get all sets released on or after the second most recent fall set's release + for (ExpansionSet set : sets) { - if ((set.getSetType() == SetType.CORE - || set.getSetType() == SetType.EXPANSION - || set.getSetType() == SetType.SUPPLEMENTAL_STANDARD_LEGAL) - && !set.getReleaseDate().before(earliestDate)) { -// && !set.getReleaseDate().after(current.getTime()))) { + boolean isDateCompatible = earliestDate != null && !set.getReleaseDate().before(earliestDate) /*!set.getReleaseDate().after(current.getTime())*/; // no after date restrict for early tests and beta + if (set.getSetType().isStandardLegal() && isDateCompatible) { codes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperType2.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperType2.java index 70780d4579..8bf79d1f69 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperType2.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/SuperType2.java @@ -1,25 +1,20 @@ package mage.deck; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.HashMap; -import java.util.Map; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; + +import java.util.*; /** * This class represents a deck conforming to the rules contained in the * subreddit /r/SuperStandard. - * + *

    * This class was originally made to work with the historical standard ruleset. * Data taken from http://thattournament.website/historic-tournament.php (site * changed, originally http://mtgt.nfshost.com/historic-tournament.php) - * + *

    * If there are any questions or corrections, feel free to contact me. * * @author Marthinwurer (at gmail.com) @@ -32,28 +27,28 @@ public class SuperType2 extends Constructed { * Data taken from http://thattournament.website/historic-tournament.php */ protected static final String[][] standards = { - // 11th Standard - {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, - // 12th Standard - {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, - // 13th Standard - {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, - // 14th Standard - {"8ED", "ONS", "LGN", "SCG", "MRD", "DST", "5DN"}, - // 15th Standard - {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, - // 16th Standard - {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, - // 17th Standard - {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, - // 18th Standard - {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, - // 19th Standard - {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, - // 20th Standard - {"10E", "CSP", "TSP", "TSB", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, - // 21st Standard - {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} + // 11th Standard + {"7ED", "INV", "APC", "PLS", "ODY", "TOR", "JUD"}, + // 12th Standard + {"7ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, + // 13th Standard + {"8ED", "ODY", "TOR", "JUD", "ONS", "LGN", "SCG"}, + // 14th Standard + {"8ED", "ONS", "LGN", "SCG", "MRD", "DST", "5DN"}, + // 15th Standard + {"8ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + // 16th Standard + {"9ED", "MRD", "DST", "5DN", "CHK", "BOK", "SOK"}, + // 17th Standard + {"9ED", "CHK", "BOK", "SOK", "RAV", "GPT", "DIS", "CSP"}, + // 18th Standard + {"9ED", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + // 19th Standard + {"10E", "RAV", "GPT", "DIS", "CSP", "TSP", "TSB", "PLC", "FUT"}, + // 20th Standard + {"10E", "CSP", "TSP", "TSB", "PLC", "FUT", "LRW", "MOR", "SHM", "EVE"}, + // 21st Standard + {"10E", "LRW", "MOR", "SHM", "EVE", "ALA", "CON", "ARB"} }; /** @@ -159,9 +154,9 @@ public class SuperType2 extends Constructed { // Get the sets in that time period. // (code taken from standard.java) for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getReleaseDate().after(start.getTime()) - && set.getReleaseDate().before(end.getTime()) - && (set.getSetType() == SetType.CORE || set.getSetType() == SetType.EXPANSION)) { + if (set.getSetType().isStandardLegal() + && set.getReleaseDate().after(start.getTime()) + && set.getReleaseDate().before(end.getTime())) { setCodes.add(set.getCode()); } } diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java index ab94951f68..0ae64e86e4 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/TinyLeaders.java @@ -1,10 +1,5 @@ - package mage.deck; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; import mage.abilities.common.CanBeYourCommanderAbility; import mage.cards.Card; import mage.cards.ExpansionSet; @@ -12,12 +7,15 @@ import mage.cards.Sets; import mage.cards.SplitCard; import mage.cards.decks.Constructed; import mage.cards.decks.Deck; -import mage.constants.SetType; import mage.filter.FilterMana; import mage.game.GameTinyLeadersImpl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + /** - * * @author JRHerlehy */ public class TinyLeaders extends Constructed { @@ -27,7 +25,7 @@ public class TinyLeaders extends Constructed { public TinyLeaders() { this("Tiny Leaders"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -84,8 +82,17 @@ public class TinyLeaders extends Constructed { super(name); } + @Override + public int getDeckMinSize() { + return 49; // commander gives from deck name + } + + @Override + public int getSideboardMinSize() { + return 0; + } + /** - * * @param deck * @return - True if deck is valid */ @@ -93,8 +100,8 @@ public class TinyLeaders extends Constructed { public boolean validate(Deck deck) { boolean valid = true; - if (deck.getCards().size() != 49) { - invalid.put("Deck", "Must contain 49 cards: has " + deck.getCards().size() + " cards"); + if (deck.getCards().size() != getDeckMinSize()) { + invalid.put("Deck", "Must contain " + getDeckMinSize() + " cards: has " + deck.getCards().size() + " cards"); valid = false; } @@ -212,9 +219,8 @@ public class TinyLeaders extends Constructed { } /** - * * @param commander FilterMana object with Color Identity of Commander set - * @param card Card to validate + * @param card Card to validate * @return True if card has a valid color identity */ public boolean cardHasValideColor(FilterMana commander, Card card) { diff --git a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java index 5c8ac0ec49..481479cbc2 100644 --- a/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java +++ b/Mage.Server.Plugins/Mage.Deck.Constructed/src/mage/deck/Vintage.java @@ -1,13 +1,10 @@ - package mage.deck; import mage.cards.ExpansionSet; import mage.cards.Sets; import mage.cards.decks.Constructed; -import mage.constants.SetType; /** - * * @author BetaSteward_at_googlemail.com */ public class Vintage extends Constructed { @@ -15,7 +12,7 @@ public class Vintage extends Constructed { public Vintage() { super("Constructed - Vintage"); for (ExpansionSet set : Sets.getInstance().values()) { - if (set.getSetType() != SetType.CUSTOM_SET) { + if (set.getSetType().isEternalLegal()) { setCodes.add(set.getCode()); } } @@ -91,6 +88,5 @@ public class Vintage extends Constructed { restricted.add("Wheel of Fortune"); restricted.add("Windfall"); restricted.add("Yawgmoth's Will"); - } } diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml index 831c92012e..b791930d78 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml +++ b/Mage.Server.Plugins/Mage.Deck.Limited/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-deck-limited @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java index 727425721e..30d32964e0 100644 --- a/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java +++ b/Mage.Server.Plugins/Mage.Deck.Limited/src/mage/deck/Limited.java @@ -1,12 +1,9 @@ - - package mage.deck; import mage.cards.decks.Deck; import mage.cards.decks.DeckValidator; /** - * * @author BetaSteward_at_googlemail.com */ public class Limited extends DeckValidator { @@ -15,12 +12,22 @@ public class Limited extends DeckValidator { super("Limited"); } + @Override + public int getDeckMinSize() { + return 40; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { - boolean valid = true; + boolean valid = true; //20091005 - 100.2b - if (deck.getCards().size() < 40) { - invalid.put("Deck", "Must contain at least 40 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } diff --git a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml index be720b6a91..166ba661c8 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-brawlduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuel.java b/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuel.java index 9684dc0d1d..8aa8ba425e 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuel.java +++ b/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuel.java @@ -5,11 +5,12 @@ package mage.game; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; public class BrawlDuel extends GameCommanderImpl { - public BrawlDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public BrawlDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public BrawlDuel(final BrawlDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuelMatch.java b/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuelMatch.java index e0a56eb0e2..4e3437879b 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.BrawlDuel/src/mage/game/BrawlDuelMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -17,8 +18,8 @@ public class BrawlDuelMatch extends MatchImpl { @Override public void startGame() throws GameException { int startLife = 25; - boolean alsoHand = true; - BrawlDuel game = new BrawlDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + BrawlDuel game = new BrawlDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setCheckCommanderDamage(false); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(true); diff --git a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml index 4566602604..524a4c0311 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-brawlfreeforall @@ -28,8 +28,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAll.java b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAll.java index b697be6a01..29cc7f22e0 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAll.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -15,8 +16,8 @@ public class BrawlFreeForAll extends GameCommanderImpl { private int numPlayers; - public BrawlFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public BrawlFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public BrawlFreeForAll(final BrawlFreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAllMatch.java index 857323e0c6..0e00a6ab9d 100644 --- a/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.BrawlFreeForAll/src/mage/game/BrawlFreeForAllMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -17,10 +18,10 @@ public class BrawlFreeForAllMatch extends MatchImpl { @Override public void startGame() throws GameException { int startLife = 30; - boolean alsoHand = true; - BrawlFreeForAll game = new BrawlFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + BrawlFreeForAll game = new BrawlFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); - game.setAlsoHand(alsoHand); + game.setAlsoHand(true); game.setCheckCommanderDamage(false); game.setAlsoLibrary(true); initGame(game); diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml index 5b32376a59..a0d09a5690 100644 --- a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-canadianhighlanderduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java index 6abcd7a9df..79fe97333b 100644 --- a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuel.java @@ -5,11 +5,12 @@ package mage.game; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; public class CanadianHighlanderDuel extends GameCanadianHighlanderImpl { - public CanadianHighlanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public CanadianHighlanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public CanadianHighlanderDuel(final CanadianHighlanderDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java index 1d55a41507..42d5336660 100644 --- a/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CanadianHighlanderDuel/src/mage/game/CanadianHighlanderDuelMatch.java @@ -3,6 +3,9 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; + +import static mage.game.mulligan.MulliganType.CANADIAN_HIGHLANDER; /** * @@ -17,7 +20,8 @@ public class CanadianHighlanderDuelMatch extends MatchImpl { @Override public void startGame() throws GameException { int startLife = 20; - CanadianHighlanderDuel game = new CanadianHighlanderDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().orDefault(CANADIAN_HIGHLANDER).getMulligan(options.getFreeMulligans()); + CanadianHighlanderDuel game = new CanadianHighlanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); initGame(game); games.add(game); diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml index 3bc9525794..5a3fc823de 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-commanderduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java index 9859fde690..6e5df00b82 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuel.java @@ -5,11 +5,12 @@ package mage.game; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; public class CommanderDuel extends GameCommanderImpl { - public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public CommanderDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public CommanderDuel(final CommanderDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java index 89d589224b..654930db5b 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderDuel/src/mage/game/CommanderDuelMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -29,7 +30,8 @@ public class CommanderDuelMatch extends MatchImpl { startLife = 30; alsoHand = true; // commander going to hand allowed to go to command zone effective July 17, 2015 } - CommanderDuel game = new CommanderDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + CommanderDuel game = new CommanderDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setCheckCommanderDamage(checkCommanderDamage); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(alsoHand); diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml index 1888b3a1fb..5758e3ff5e 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-commanderfreeforall @@ -28,8 +28,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java index 8bfc3ef63a..2c1a9e7d18 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAll.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -15,8 +16,8 @@ public class CommanderFreeForAll extends GameCommanderImpl { private int numPlayers; - public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public CommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public CommanderFreeForAll(final CommanderFreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java index a1a8651437..efdc7aa305 100644 --- a/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.CommanderFreeForAll/src/mage/game/CommanderFreeForAllMatch.java @@ -4,6 +4,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -23,7 +24,8 @@ public class CommanderFreeForAllMatch extends MatchImpl { startLife = 30; alsoHand = true; // commander going to hand allowed to go to command zone effective July 17, 2015 } - CommanderFreeForAll game = new CommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + CommanderFreeForAll game = new CommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(alsoHand); game.setAlsoLibrary(true); diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml index 239c59dcdf..079718579d 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-freeforall @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java index f14cacd16b..44209f3388 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAll.java @@ -4,6 +4,7 @@ package mage.game; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -13,8 +14,8 @@ public class FreeForAll extends GameImpl { private int numPlayers; - public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public FreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public FreeForAll(final FreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java index da37d693b6..d0bb1b34e8 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.FreeForAll/src/mage/game/FreeForAllMatch.java @@ -4,6 +4,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -17,7 +18,8 @@ public class FreeForAllMatch extends MatchImpl { @Override public void startGame() throws GameException { - FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), 20); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + FreeForAll game = new FreeForAll(options.getAttackOption(), options.getRange(), mulligan, 20); game.setStartMessage(this.createGameStartMessage()); initGame(game); games.add(game); diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml index eaa55ae4e9..7755e2fec4 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-freeformcommanderfreeforall @@ -28,8 +28,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAll.java b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAll.java index 37918129fa..2f9aa0e29f 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAll.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -15,8 +16,8 @@ public class FreeformCommanderFreeForAll extends GameCommanderImpl { private int numPlayers; - public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public FreeformCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public FreeformCommanderFreeForAll(final FreeformCommanderFreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAllMatch.java index 518c9f263e..5c62374042 100644 --- a/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.FreeformCommanderFreeForAll/src/mage/game/FreeformCommanderFreeForAllMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -18,7 +19,8 @@ public class FreeformCommanderFreeForAllMatch extends MatchImpl { public void startGame() throws GameException { int startLife = 40; boolean alsoHand = true; - FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + FreeformCommanderFreeForAll game = new FreeformCommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(alsoHand); game.setAlsoLibrary(true); diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml index e4ec5b48a7..80676f0433 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-momirduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java index 8ebf139746..ac51137df9 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuel.java @@ -13,6 +13,7 @@ import mage.constants.RangeOfInfluence; import mage.constants.Zone; import mage.game.command.emblems.MomirEmblem; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; @@ -22,8 +23,8 @@ import mage.players.Player; */ public class MomirDuel extends GameImpl { - public MomirDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public MomirDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public MomirDuel(final MomirDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuelMatch.java b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuelMatch.java index 80dca4df70..6ae458432e 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.MomirDuel/src/mage/game/MomirDuelMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -19,7 +20,8 @@ public class MomirDuelMatch extends MatchImpl { // Momir Vig, Simic Visionary gives +4 starting life int startLife = 24; - MomirDuel game = new MomirDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + MomirDuel game = new MomirDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); this.initGame(game); diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml index e17bfe1289..03eba8da4f 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-momirfreeforall @@ -34,8 +34,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java index 0aa7adb2aa..9b8eddf38b 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirFreeForAllMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -19,7 +20,8 @@ public class MomirFreeForAllMatch extends MatchImpl { // Momir Vig, Simic Visionary gives +4 starting life int startLife = 24; - MomirGame game = new MomirGame(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + MomirGame game = new MomirGame(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); this.initGame(game); diff --git a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java index 542b4925c2..0750d4d7cb 100644 --- a/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java +++ b/Mage.Server.Plugins/Mage.Game.MomirGame/src/mage/game/MomirGame.java @@ -13,6 +13,7 @@ import mage.constants.RangeOfInfluence; import mage.constants.Zone; import mage.game.command.emblems.MomirEmblem; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; @@ -24,8 +25,8 @@ public class MomirGame extends GameImpl { private int numPlayers; - public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public MomirGame(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public MomirGame(final MomirGame game) { diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml index 60538dc66c..2b5cb442a6 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/pom.xml @@ -6,7 +6,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-pennydreadfulcommanderfreeforall @@ -28,8 +28,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAll.java b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAll.java index 1cd80dc09e..add9c578a9 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAll.java +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAll.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -15,8 +16,8 @@ public class PennyDreadfulCommanderFreeForAll extends GameCommanderImpl { private int numPlayers; - public PennyDreadfulCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public PennyDreadfulCommanderFreeForAll(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public PennyDreadfulCommanderFreeForAll(final PennyDreadfulCommanderFreeForAll game) { diff --git a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAllMatch.java b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAllMatch.java index 9ee1d3f2e8..e9deed1700 100644 --- a/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAllMatch.java +++ b/Mage.Server.Plugins/Mage.Game.PennyDreadfulCommanderFreeForAll/src/mage/game/PennyDreadfulCommanderFreeForAllMatch.java @@ -4,6 +4,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -23,7 +24,8 @@ public class PennyDreadfulCommanderFreeForAllMatch extends MatchImpl { startLife = 30; alsoHand = true; // commander going to hand allowed to go to command zone effective July 17, 2015 } - PennyDreadfulCommanderFreeForAll game = new PennyDreadfulCommanderFreeForAll(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + PennyDreadfulCommanderFreeForAll game = new PennyDreadfulCommanderFreeForAll(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); game.setAlsoHand(alsoHand); game.setAlsoLibrary(true); diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml index 111fedc13f..f50fbebfaf 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-tinyleadersduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuel.java b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuel.java index 675768e215..83044e4361 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuel.java +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuel.java @@ -5,6 +5,7 @@ package mage.game; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; /** * @@ -12,8 +13,8 @@ import mage.game.match.MatchType; */ public class TinyLeadersDuel extends GameTinyLeadersImpl { - public TinyLeadersDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public TinyLeadersDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public TinyLeadersDuel(final TinyLeadersDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuelMatch.java b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuelMatch.java index 8a6847d314..426f8fc1c7 100644 --- a/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuelMatch.java +++ b/Mage.Server.Plugins/Mage.Game.TinyLeadersDuel/src/mage/game/TinyLeadersDuelMatch.java @@ -4,6 +4,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -19,8 +20,9 @@ public class TinyLeadersDuelMatch extends MatchImpl { public void startGame() throws GameException { //Tiny Leaders Play Rule 13: Players begin the game with 25 life. int startLife = 25; - - TinyLeadersDuel game = new TinyLeadersDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), startLife); + + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + TinyLeadersDuel game = new TinyLeadersDuel(options.getAttackOption(), options.getRange(), mulligan, startLife); game.setStartMessage(this.createGameStartMessage()); //Tucking a Tiny Leader is legal diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml index 5d5ba7eb62..0cc888e958 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-game-twoplayerduel @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java index d3fe05e57c..b5e7f2b334 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerDuel.java @@ -1,17 +1,19 @@ package mage.game; -import java.util.UUID; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; +import java.util.UUID; + public class TwoPlayerDuel extends GameImpl { - public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public TwoPlayerDuel(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public TwoPlayerDuel(final TwoPlayerDuel game) { diff --git a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java index ea10bf4d0e..9705f03e5d 100644 --- a/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java +++ b/Mage.Server.Plugins/Mage.Game.TwoPlayerDuel/src/mage/game/TwoPlayerMatch.java @@ -3,6 +3,7 @@ package mage.game; import mage.game.match.MatchImpl; import mage.game.match.MatchOptions; +import mage.game.mulligan.Mulligan; /** * @@ -16,7 +17,8 @@ public class TwoPlayerMatch extends MatchImpl { @Override public void startGame() throws GameException { - TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange(), options.getFreeMulligans(), 20); + Mulligan mulligan = options.getMulliganType().getMulligan(options.getFreeMulligans()); + TwoPlayerDuel game = new TwoPlayerDuel(options.getAttackOption(), options.getRange(), mulligan, 20); // Sets a start message about the match score game.setStartMessage(this.createGameStartMessage()); initGame(game); diff --git a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml index 75c0e75822..ff76ee638c 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.DraftBot/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-ai-draftbot @@ -34,8 +34,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml index 9f8a8b0e53..85cef7803d 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-ai-ma @@ -34,8 +34,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java index f38270bec6..5b19c6ac35 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer6.java @@ -1,28 +1,12 @@ - package mage.player.ai; -import java.io.File; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; import mage.abilities.SpellAbility; import mage.abilities.common.PassAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.SearchEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.ExaltedAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.*; import mage.cards.Card; import mage.cards.Cards; import mage.choices.Choice; @@ -49,8 +33,12 @@ import mage.target.Targets; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.File; +import java.util.*; +import java.util.concurrent.*; +import mage.abilities.StaticAbility; + /** - * * @author nantuko */ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { @@ -180,10 +168,9 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { if (!suggested.isEmpty() && !(ability instanceof PassAbility)) { Iterator it = suggested.iterator(); while (it.hasNext()) { - Card card = game.getCard(ability.getSourceId()); String action = it.next(); - logger.info("Suggested action=" + action + ";card=" + card); - if (action.equals(card.getName())) { + Card card = game.getCard(ability.getSourceId()); + if (card != null && action.equals(card.getName())) { logger.info("-> removed from suggested=" + action); it.remove(); } @@ -479,7 +466,8 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } Game sim = game.copy(); sim.setSimulation(true); - if (sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { + if (!(action instanceof StaticAbility) //for MorphAbility, etc + && sim.getPlayer(currentPlayer.getId()).activateAbility((ActivatedAbility) action.copy(), sim)) { sim.applyEffects(); if (checkForRepeatedAction(sim, node, action, currentPlayer.getId())) { logger.debug("Sim Prio [" + depth + "] -- repeated action: " + action.toString()); @@ -612,28 +600,45 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { } Collections.sort(allActions, new Comparator() { @Override - public int compare(Ability ability, Ability ability1) { - String rule = ability.toString(); + public int compare(Ability ability1, Ability ability2) { String rule1 = ability1.toString(); - if (rule.equals("Pass")) { - return 1; + String rule2 = ability2.toString(); + + // pass + boolean pass1 = rule1.startsWith("Pass"); + boolean pass2 = rule2.startsWith("Pass"); + if (pass1 != pass2) { + if (pass1) { + return 1; + } else { + return -1; + } } - if (rule1.equals("Pass")) { - return -1; + + // play + boolean play1 = rule1.startsWith("Play"); + boolean play2 = rule2.startsWith("Play"); + if (play1 != play2) { + if (play1) { + return -1; + } else { + return 1; + } } - if (rule.startsWith("Play")) { - return -1; + + // cast + boolean cast1 = rule1.startsWith("Cast"); + boolean cast2 = rule2.startsWith("Cast"); + if (cast1 != cast2) { + if (cast1) { + return -1; + } else { + return 1; + } } - if (rule1.startsWith("Play")) { - return 1; - } - if (rule.startsWith("Cast")) { - return -1; - } - if (rule1.startsWith("Cast")) { - return 1; - } - return ability.getRule().compareTo(ability1.getRule()); + + // default + return ability1.getRule().compareTo(ability2.getRule()); } }); } @@ -930,7 +935,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { String line = scanner.nextLine(); if (line.startsWith("cast:") || line.startsWith("play:")) { - suggested.add(line.substring(5, line.length())); + suggested.add(line.substring(5)); } } System.out.println("suggested::"); @@ -953,7 +958,7 @@ public class ComputerPlayer6 extends ComputerPlayer /*implements Player*/ { if (action != null && (action.startsWith("cast:") || action.startsWith("play:"))) { - suggested.add(action.substring(5, action.length())); + suggested.add(action.substring(5)); } } diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java index 628472299c..448105209f 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/ComputerPlayer7.java @@ -111,9 +111,8 @@ public class ComputerPlayer7 extends ComputerPlayer6 { Game sim = createSimulation(game); SimulationNode2.resetCount(); root = new SimulationNode2(null, sim, maxDepth, playerId); - addActionsTimed(); - if (root.children != null - && !root.children.isEmpty()) { + addActionsTimed(); // TODO: root can be null again after addActionsTimed O_o need to research (it's a CPU AI problem?) + if (root != null && root.children != null && !root.children.isEmpty()) { logger.trace("After add actions timed: root.children.size = " + root.children.size()); root = root.children.get(0); // prevent repeating always the same action with no cost diff --git a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java index 018ef807a1..a546d9b698 100644 --- a/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java +++ b/Mage.Server.Plugins/Mage.Player.AI.MA/src/mage/player/ai/SimulatedPlayer2.java @@ -1,4 +1,3 @@ - package mage.player.ai; import mage.MageObject; @@ -25,7 +24,6 @@ import java.util.*; import java.util.concurrent.ConcurrentLinkedQueue; /** - * * @author BetaSteward_at_googlemail.com */ public class SimulatedPlayer2 extends ComputerPlayer { @@ -173,6 +171,7 @@ public class SimulatedPlayer2 extends ComputerPlayer { // allActions.add(new SimulatedAction(sim, actions)); // } // } + /** * if suggested abilities exist, return only those from playables * @@ -191,11 +190,13 @@ public class SimulatedPlayer2 extends ComputerPlayer { List filtered = new ArrayList<>(); for (Ability ability : playables) { Card card = game.getCard(ability.getSourceId()); - for (String s : suggested) { - if (s.equals(card.getName())) { - logger.debug("matched: " + s); - forced = true; - filtered.add(ability); + if (card != null) { + for (String s : suggested) { + if (s.equals(card.getName())) { + logger.debug("matched: " + s); + forced = true; + filtered.add(ability); + } } } } @@ -216,26 +217,28 @@ public class SimulatedPlayer2 extends ComputerPlayer { for (Ability option : options) { if (!option.getTargets().isEmpty() && option.getTargets().get(0).getMaxNumberOfTargets() == 1) { Card card = game.getCard(ability.getSourceId()); - for (String s : suggested) { - String[] groups = s.split(";"); - logger.trace("s=" + s + ";groups=" + groups.length); - if (groups.length == 2) { - if (groups[0].equals(card.getName()) && groups[1].startsWith("name=")) { - // extract target and compare to suggested - String targetName = groups[1].split("=")[1]; - Player player = game.getPlayer(option.getFirstTarget()); - if (player != null && targetName.equals(player.getName())) { - System.out.println("matched(option): " + s); - filtered.add(option); - return filtered; - } else { - Card target = game.getCard(option.getFirstTarget()); - if (target != null && target.getName().equals(targetName)) { + if (card != null) { + for (String s : suggested) { + String[] groups = s.split(";"); + logger.trace("s=" + s + ";groups=" + groups.length); + if (groups.length == 2) { + if (groups[0].equals(card.getName()) && groups[1].startsWith("name=")) { + // extract target and compare to suggested + String targetName = groups[1].split("=")[1]; + Player player = game.getPlayer(option.getFirstTarget()); + if (player != null && targetName.equals(player.getName())) { System.out.println("matched(option): " + s); filtered.add(option); return filtered; + } else { + Card target = game.getCard(option.getFirstTarget()); + if (target != null && target.getName().equals(targetName)) { + System.out.println("matched(option): " + s); + filtered.add(option); + return filtered; + } + System.out.println("not equal UUID for target, player=" + player); } - System.out.println("not equal UUID for target, player=" + player); } } } diff --git a/Mage.Server.Plugins/Mage.Player.AI/pom.xml b/Mage.Server.Plugins/Mage.Player.AI/pom.xml index 81f988b734..5e79f6d396 100644 --- a/Mage.Server.Plugins/Mage.Player.AI/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AI/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-ai @@ -38,8 +38,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 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 8362963995..879718fdc1 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 @@ -1,10 +1,5 @@ - package mage.player.ai; -import java.io.IOException; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -22,6 +17,8 @@ import mage.cards.Card; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidator; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -37,6 +34,7 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.draft.Draft; +import mage.game.draft.RateCard; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.match.Match; @@ -47,7 +45,6 @@ import mage.game.tournament.Tournament; import mage.player.ai.simulators.CombatGroupSimulator; import mage.player.ai.simulators.CombatSimulator; import mage.player.ai.simulators.CreatureSimulator; -import mage.player.ai.utils.RateCard; import mage.players.Player; import mage.players.PlayerImpl; import mage.players.net.UserData; @@ -60,8 +57,12 @@ import mage.util.TournamentUtil; import mage.util.TreeNode; import org.apache.log4j.Logger; +import java.io.IOException; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; + /** - * * suitable for two player games and some multiplayer games * * @author BetaSteward_at_googlemail.com @@ -94,6 +95,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { protected ComputerPlayer(UUID id) { super(id); + human = false; + userData = UserData.getDefaultUserDataView(); + userData.setAvatarId(64); + userData.setGroupId(UserGroup.COMPUTER.getGroupId()); + userData.setFlagName("computer.png"); pickedCards = new ArrayList<>(); } @@ -134,7 +140,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { UUID randomOpponentId; if (target.getTargetController() != null) { - randomOpponentId = getRandomOpponent(target.getTargetController(), game);; + randomOpponentId = getRandomOpponent(target.getTargetController(), game); } else if (abilityControllerId != null) { randomOpponentId = getRandomOpponent(abilityControllerId, game); } else { @@ -144,6 +150,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetPlayer) { return setTargetPlayer(outcome, target, null, sourceId, abilityControllerId, randomOpponentId, game); } + if (target.getOriginalTarget() instanceof TargetDiscard) { findPlayables(game); if (!unplayable.isEmpty()) { @@ -168,40 +175,45 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return false; } + if (target.getOriginalTarget() instanceof TargetControlledPermanent) { List targets; - targets = threats(abilityControllerId, sourceId, ((TargetControlledPermanent) target).getFilter(), game, target.getTargets()); + TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); + targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets()); if (!outcome.isGood()) { Collections.reverse(targets); } for (Permanent permanent : targets) { - if (((TargetControlledPermanent) target).canTarget(abilityControllerId, permanent.getId(), sourceId, game, false) && !target.getTargets().contains(permanent.getId())) { + if (origTarget.canTarget(abilityControllerId, permanent.getId(), sourceId, game, false) && !target.getTargets().contains(permanent.getId())) { target.add(permanent.getId(), game); return true; } } return false; } + if (target.getOriginalTarget() instanceof TargetPermanent) { + TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget(); List targets; if (outcome.isCanTargetAll()) { - targets = threats(null, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(null, sourceId, origTarget.getFilter(), game, target.getTargets()); } else { if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, sourceId, origTarget.getFilter(), game, target.getTargets()); } if (targets.isEmpty() && target.isRequired()) { if (!outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, sourceId, origTarget.getFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((TargetPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, sourceId, origTarget.getFilter(), game, target.getTargets()); } } } + for (Permanent permanent : targets) { - if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) { + if (target.canTarget(abilityControllerId, permanent.getId(), null, game) && !target.getTargets().contains(permanent.getId())) { // stop to add targets if not needed and outcome is no advantage for AI player if (target.getNumberOfTargets() == target.getTargets().size()) { if (outcome.isGood() && hasOpponent(permanent.getControllerId(), game)) { @@ -240,17 +252,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetAnyTarget) { List targets; - TargetAnyTarget t = ((TargetAnyTarget) target); + TargetAnyTarget origTarget = (TargetAnyTarget) target.getOriginalTarget(); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, sourceId, ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } for (Permanent permanent : targets) { List alreadyTargetted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), null, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), null, game)) { if (alreadyTargetted != null && !alreadyTargetted.contains(permanent.getId())) { target.add(permanent.getId(), game); return true; @@ -270,17 +283,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { return false; } } + if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) { List targets; - TargetCreatureOrPlayer t = ((TargetCreatureOrPlayer) target); + TargetCreatureOrPlayer origTarget = (TargetCreatureOrPlayer) target.getOriginalTarget(); if (outcome.isGood()) { - targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, sourceId, ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), null, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), null, game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { target.add(permanent.getId(), game); return true; @@ -303,9 +317,9 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { List targets; - TargetPermanentOrPlayer t = ((TargetPermanentOrPlayer) target); - List ownedTargets = threats(abilityControllerId, sourceId, ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); - List opponentTargets = threats(randomOpponentId, sourceId, ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); + TargetPermanentOrPlayer origTarget = (TargetPermanentOrPlayer) target.getOriginalTarget(); + List ownedTargets = threats(abilityControllerId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); + List opponentTargets = threats(randomOpponentId, sourceId, ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); if (outcome.isGood()) { targets = ownedTargets; } else { @@ -313,7 +327,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(permanent.getId(), game)) { + if (target.canTarget(permanent.getId(), game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { target.add(permanent.getId(), game); return true; @@ -347,7 +361,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(permanent.getId(), game)) { + if (target.canTarget(permanent.getId(), game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { target.add(permanent.getId(), game); return true; @@ -356,6 +370,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return false; } + if (target.getOriginalTarget() instanceof TargetCardInGraveyard) { List cards = new ArrayList<>(); for (Player player : game.getPlayers().values()) { @@ -389,15 +404,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return false; } + if (target.getOriginalTarget() instanceof TargetSource) { Set targets; - TargetSource t = ((TargetSource) target); - targets = t.possibleTargets(sourceId, abilityControllerId, game); + targets = target.possibleTargets(sourceId, abilityControllerId, game); for (UUID targetId : targets) { MageObject targetObject = game.getObject(targetId); if (targetObject != null) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(targetObject.getId(), game)) { + if (target.canTarget(targetObject.getId(), game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(targetObject.getId())) { target.add(targetObject.getId(), game); return true; @@ -427,7 +442,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { UUID randomOpponentId; if (target.getTargetController() != null) { - randomOpponentId = getRandomOpponent(target.getTargetController(), game);; + randomOpponentId = getRandomOpponent(target.getTargetController(), game); } else if (source != null && source.getControllerId() != null) { randomOpponentId = getRandomOpponent(source.getControllerId(), game); } else { @@ -438,8 +453,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return setTargetPlayer(outcome, target, source, source.getSourceId(), abilityControllerId, randomOpponentId, game); } - if (target.getOriginalTarget() instanceof TargetDiscard || target.getOriginalTarget() instanceof TargetCardInHand) { + if (target.getOriginalTarget() instanceof TargetDiscard + || target.getOriginalTarget() instanceof TargetCardInHand) { if (outcome.isGood()) { + // good Cards cards = new CardsImpl(target.possibleTargets(source.getSourceId(), getId(), game)); ArrayList cardsInHand = new ArrayList<>(cards.getCards(game)); while (!target.isChosen() @@ -457,6 +474,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } } else { + // bad findPlayables(game); if (!unplayable.isEmpty()) { for (int i = unplayable.size() - 1; i >= 0; i--) { @@ -481,14 +499,16 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return false; } + if (target.getOriginalTarget() instanceof TargetControlledPermanent) { + TargetControlledPermanent origTarget = (TargetControlledPermanent) target.getOriginalTarget(); List targets; - targets = threats(abilityControllerId, source.getSourceId(), ((TargetControlledPermanent) target).getFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), origTarget.getFilter(), game, target.getTargets()); if (!outcome.isGood()) { Collections.reverse(targets); } for (Permanent permanent : targets) { - if (((TargetControlledPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (target.getNumberOfTargets() <= target.getTargets().size() && (!outcome.isGood() || target.getMaxNumberOfTargets() <= target.getTargets().size())) { return true; @@ -498,8 +518,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetPermanent) { List targets; + TargetPermanent origTarget = (TargetPermanent) target.getOriginalTarget(); boolean outcomeTargets = true; if (outcome.isGood()) { targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetPermanent) target).getFilter(), game, target.getTargets()); @@ -512,8 +534,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { outcomeTargets = false; //targets = game.getBattlefield().getActivePermanents(((TargetPermanent)target).getFilter(), playerId, game); } + if (targets.isEmpty() && target.isRequired()) { + targets = game.getBattlefield().getActivePermanents(origTarget.getFilter(), playerId, game); + } for (Permanent permanent : targets) { - if (((TargetPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; @@ -522,130 +547,120 @@ public class ComputerPlayer extends PlayerImpl implements Player { } return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetCreatureOrPlayer) { List targets; - TargetCreatureOrPlayer t = ((TargetCreatureOrPlayer) target); + TargetCreatureOrPlayer origTarget = ((TargetCreatureOrPlayer) target); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } if (targets.isEmpty()) { if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } } if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((FilterCreatureOrPlayer) t.getFilter()).getCreatureFilter(), playerId, game); + targets = game.getBattlefield().getActivePermanents(((FilterCreatureOrPlayer) origTarget.getFilter()).getCreatureFilter(), playerId, game); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - return true; + return tryAddTarget(target, permanent.getId(), source, game); } } } if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } //if (!target.isRequired()) return false; } + if (target.getOriginalTarget() instanceof TargetAnyTarget) { List targets; - TargetAnyTarget t = ((TargetAnyTarget) target); + TargetAnyTarget origTarget = ((TargetAnyTarget) target); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) t.getFilter()).getCreatureFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source.getSourceId(), ((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), game, target.getTargets()); } if (targets.isEmpty()) { if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } } if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) t.getFilter()).getCreatureFilter(), playerId, game); + targets = game.getBattlefield().getActivePermanents(((FilterCreaturePlayerOrPlaneswalker) origTarget.getFilter()).getCreatureFilter(), playerId, game); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - return true; + tryAddTarget(target, permanent.getId(), source, game); } } } if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } //if (!target.isRequired()) return false; } + if (target.getOriginalTarget() instanceof TargetPermanentOrPlayer) { List targets; - TargetPermanentOrPlayer t = ((TargetPermanentOrPlayer) target); + TargetPermanentOrPlayer origTarget = ((TargetPermanentOrPlayer) target); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty()) { if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } } if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), playerId, game); + targets = game.getBattlefield().getActivePermanents(((FilterPermanentOrPlayer) origTarget.getFilter()).getPermanentFilter(), playerId, game); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - return true; + return tryAddTarget(target, permanent.getId(), source, game); } } } @@ -653,46 +668,41 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetPlayerOrPlaneswalker) { List targets; - TargetPlayerOrPlaneswalker t = ((TargetPlayerOrPlaneswalker) target); + TargetPlayerOrPlaneswalker origTarget = ((TargetPlayerOrPlaneswalker) target); if (outcome.isGood()) { - targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) t.getFilter()).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source.getSourceId(), ((FilterPermanentOrPlayer) target.getFilter()).getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty()) { if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } } if (targets.isEmpty() && target.isRequired(source)) { - targets = game.getBattlefield().getActivePermanents(((TargetPlayerOrPlaneswalker) t.getFilter()).getFilterPermanent(), playerId, game); + targets = game.getBattlefield().getActivePermanents(((TargetPlayerOrPlaneswalker) origTarget.getFilter()).getFilterPermanent(), playerId, game); } for (Permanent permanent : targets) { List alreadyTargeted = target.getTargets(); - if (t.canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { if (alreadyTargeted != null && !alreadyTargeted.contains(permanent.getId())) { - target.addTarget(permanent.getId(), source, game); - return true; + return tryAddTarget(target, permanent.getId(), source, game); } } } if (outcome.isGood()) { if (target.canTarget(getId(), abilityControllerId, source, game)) { - target.addTarget(abilityControllerId, source, game); - return true; + return tryAddTarget(target, abilityControllerId, source, game); } } else if (target.canTarget(getId(), randomOpponentId, source, game)) { - target.addTarget(randomOpponentId, source, game); - return true; + return tryAddTarget(target, randomOpponentId, source, game); } //if (!target.isRequired()) @@ -706,58 +716,61 @@ public class ComputerPlayer extends PlayerImpl implements Player { } Card card = pickTarget(cards, outcome, target, source, game); if (card != null) { - target.addTarget(card.getId(), source, game); - return true; + return tryAddTarget(target, card.getId(), source, game); } //if (!target.isRequired()) return false; } + if (target.getOriginalTarget() instanceof TargetCardInLibrary) { List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getLibrary().getCards(game)); Card card = pickTarget(cards, outcome, target, source, game); if (card != null) { - target.addTarget(card.getId(), source, game); - return true; + return tryAddTarget(target, card.getId(), source, game); } return false; } + if (target.getOriginalTarget() instanceof TargetCardInYourGraveyard) { List cards = new ArrayList<>(game.getPlayer(abilityControllerId).getGraveyard().getCards((FilterCard) target.getFilter(), game)); while (!target.isChosen() && !cards.isEmpty()) { Card card = pickTarget(cards, outcome, target, source, game); if (card != null) { target.addTarget(card.getId(), source, game); + cards.remove(card); // pickTarget don't remove cards (only on second+ tries) } } return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetSpell) { if (!game.getStack().isEmpty()) { for (StackObject o : game.getStack()) { if (o instanceof Spell && !source.getId().equals(o.getStackAbility().getId())) { - target.addTarget(o.getId(), source, game); - return true; + return tryAddTarget(target, o.getId(), source, game); } } } return false; } + if (target.getOriginalTarget() instanceof TargetSpellOrPermanent) { // TODO: Also check if a spell should be selected + TargetSpellOrPermanent origTarget = (TargetSpellOrPermanent) target.getOriginalTarget(); List targets; boolean outcomeTargets = true; if (outcome.isGood()) { - targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); + targets = threats(abilityControllerId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); } else { - targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); + targets = threats(randomOpponentId, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); } if (targets.isEmpty() && target.isRequired(source)) { - targets = threats(null, source == null ? null : source.getSourceId(), ((TargetSpellOrPermanent) target).getPermanentFilter(), game, target.getTargets()); + targets = threats(null, source == null ? null : source.getSourceId(), origTarget.getPermanentFilter(), game, target.getTargets()); Collections.reverse(targets); outcomeTargets = false; } for (Permanent permanent : targets) { - if (((TargetSpellOrPermanent) target).canTarget(abilityControllerId, permanent.getId(), source, game)) { + if (target.canTarget(abilityControllerId, permanent.getId(), source, game)) { target.addTarget(permanent.getId(), source, game); if (!outcomeTargets || target.getMaxNumberOfTargets() <= target.getTargets().size()) { return true; @@ -767,15 +780,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (!game.getStack().isEmpty()) { for (StackObject stackObject : game.getStack()) { if (stackObject instanceof Spell && source != null && !source.getId().equals(stackObject.getStackAbility().getId())) { - if (((TargetSpellOrPermanent) target).getFilter().match(stackObject, game)) { - target.addTarget(stackObject.getId(), source, game); - return true; + if (target.getFilter().match(stackObject, game)) { + return tryAddTarget(target, stackObject.getId(), source, game); } } } } return false; } + if (target.getOriginalTarget() instanceof TargetCardInOpponentsGraveyard) { List cards = new ArrayList<>(); for (UUID uuid : game.getOpponents(abilityControllerId)) { @@ -786,12 +799,12 @@ public class ComputerPlayer extends PlayerImpl implements Player { } Card card = pickTarget(cards, outcome, target, source, game); if (card != null) { - target.addTarget(card.getId(), source, game); - return true; + return tryAddTarget(target, card.getId(), source, game); } //if (!target.isRequired()) return false; } + if (target.getOriginalTarget() instanceof TargetDefender) { // TODO: Improve, now planeswalker is always chosen if it exits List targets; @@ -823,6 +836,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { Card pick = pickTarget(cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); + cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) } } return target.isChosen(); @@ -830,7 +844,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetCardInExile) { List cards = new ArrayList<>(); - for (UUID uuid : ((TargetCardInExile) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { Card card = game.getCard(uuid); if (card != null) { cards.add(card); @@ -840,13 +854,15 @@ public class ComputerPlayer extends PlayerImpl implements Player { Card pick = pickTarget(cards, outcome, target, source, game); if (pick != null) { target.addTarget(pick.getId(), source, game); + cards.remove(pick); // pickTarget don't remove cards (only on second+ tries) } } return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetActivatedAbility) { List stackObjects = new ArrayList<>(); - for (UUID uuid : ((TargetActivatedAbility) target).possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + for (UUID uuid : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { StackObject stackObject = game.getStack().getStackObject(uuid); if (stackObject != null) { stackObjects.add(stackObject); @@ -862,6 +878,18 @@ public class ComputerPlayer extends PlayerImpl implements Player { return target.isChosen(); } + if (target.getOriginalTarget() instanceof TargetCardInGraveyardOrBattlefield) { + List cards = new ArrayList<>(); + for (Player player : game.getPlayers().values()) { + cards.addAll(player.getGraveyard().getCards(game)); + cards.addAll(game.getBattlefield().getAllActivePermanents(new FilterPermanent(), player.getId(), game)); + } + Card card = pickTarget(cards, outcome, target, source, game); + if (card != null) { + return tryAddTarget(target, card.getId(), source, game); + } + } + throw new IllegalStateException("Target wasn't handled. class:" + target.getClass().toString()); } //end of chooseTarget method @@ -897,8 +925,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.getOriginalTarget() instanceof TargetCreatureOrPlayerAmount || target.getOriginalTarget() instanceof TargetAnyTargetAmount) { if (outcome == Outcome.Damage && game.getPlayer(opponentId).getLife() <= target.getAmountRemaining()) { - target.addTarget(opponentId, target.getAmountRemaining(), source, game); - return true; + return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); } List targets; if (outcome.isGood()) { @@ -909,24 +936,21 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (Permanent permanent : targets) { if (target.canTarget(getId(), permanent.getId(), source, game)) { if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { - target.addTarget(permanent.getId(), permanent.getToughness().getValue(), source, game); - return true; + return tryAddTarget(target, permanent.getId(), permanent.getToughness().getValue(), source, game); } } } if (outcome.isGood() && target.canTarget(getId(), getId(), source, game)) { - target.addTarget(opponentId, target.getAmountRemaining(), source, game); - return true; + return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); } else if (target.canTarget(getId(), opponentId, source, game)) { // no permanent target so take opponent - target.addTarget(opponentId, target.getAmountRemaining(), source, game); - return true; + return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); } else if (target.canTarget(getId(), playerId, source, game)) { - target.addTarget(opponentId, target.getAmountRemaining(), source, game); - return true; + return tryAddTarget(target, opponentId, target.getAmountRemaining(), source, game); } return false; } + if (target.getOriginalTarget() instanceof TargetCreatureOrPlaneswalkerAmount) { List targets; if (outcome.isGood()) { @@ -937,8 +961,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { for (Permanent permanent : targets) { if (target.canTarget(getId(), permanent.getId(), source, game)) { if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { - target.addTarget(permanent.getId(), permanent.getToughness().getValue(), source, game); - return true; + return tryAddTarget(target, permanent.getId(), permanent.getToughness().getValue(), source, game); } } } @@ -949,16 +972,14 @@ public class ComputerPlayer extends PlayerImpl implements Player { if (target.canTarget(getId(), permanent.getId(), source, game)) { if (permanent.isCreature()) { if (permanent.getToughness().getValue() <= target.getAmountRemaining()) { - target.addTarget(permanent.getId(), permanent.getToughness().getValue(), source, game); - return true; + tryAddTarget(target, permanent.getId(), permanent.getToughness().getValue(), source, game); } else { possibleTarget = permanent; } } else if (permanent.isPlaneswalker()) { int loy = permanent.getCounters(game).getCount(CounterType.LOYALTY); if (loy <= target.getAmountRemaining()) { - target.addTarget(permanent.getId(), loy, source, game); - return true; + return tryAddTarget(target, permanent.getId(), loy, source, game); } else { possibleTarget = permanent; } @@ -967,11 +988,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } if (possibleTarget != null) { - target.addTarget(possibleTarget.getId(), target.getAmountRemaining(), source, game); - return true; + return tryAddTarget(target, possibleTarget.getId(), target.getAmountRemaining(), source, game); } } } + log.warn("No proper AI target handling: " + target.getClass().getName()); return false; } @@ -1372,9 +1393,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { } // pay phyrexian life costs if (cost instanceof PhyrexianManaCost) { - if (cost.pay(null, game, null, playerId, false, null) || permittingObject != null) { - return true; - } + return cost.pay(null, game, null, playerId, false, null) || permittingObject != null; } return false; } @@ -1406,11 +1425,10 @@ public class ComputerPlayer extends PlayerImpl implements Player { } /** - * * returns a list of Permanents that produce mana sorted by the number of * mana the Permanent produces that match the unpaid costs in ascending * order - * + *

    * the idea is that we should pay costs first from mana producers that * produce only one type of mana and save the multi-mana producers for those * costs that can't be paid by any other producers @@ -1637,7 +1655,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { cardChoices.remove(card); } else { // We don't have any valid target to choose so stop choosing - return target.getTargets().size() < target.getNumberOfTargets(); + return target.getTargets().size() >= target.getNumberOfTargets(); } if (outcome == Outcome.Neutral && target.getTargets().size() > target.getNumberOfTargets() + (target.getMaxNumberOfTargets() - target.getNumberOfTargets()) / 2) { return true; @@ -1661,7 +1679,7 @@ public class ComputerPlayer extends PlayerImpl implements Player { cardChoices.remove(card); } else { // We don't have any valid target to choose so stop choosing - break; + return target.getTargets().size() >= target.getNumberOfTargets(); } if (outcome == Outcome.Neutral && target.getTargets().size() > target.getNumberOfTargets() + (target.getMaxNumberOfTargets() - target.getNumberOfTargets()) / 2) { return true; @@ -1843,22 +1861,22 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - public static Deck buildDeck(List cardPool, final List colors) { - return buildDeck(cardPool, colors, false); + public static Deck buildDeck(int deckMinSize, List cardPool, final List colors) { + return buildDeck(deckMinSize, cardPool, colors, false); } - public static Deck buildDeck(List cardPool, final List colors, boolean onlyBasicLands) { + public static Deck buildDeck(int deckMinSize, List cardPool, final List colors, boolean onlyBasicLands) { if (onlyBasicLands) { - return buildDeckWithOnlyBasicLands(cardPool); + return buildDeckWithOnlyBasicLands(deckMinSize, cardPool); } else { - return buildDeckWithNormalCards(cardPool, colors); + return buildDeckWithNormalCards(deckMinSize, cardPool, colors); } } - public static Deck buildDeckWithOnlyBasicLands(List cardPool) { + public static Deck buildDeckWithOnlyBasicLands(int deckMinSize, List cardPool) { // random cards from card pool Deck deck = new Deck(); - final int DECK_SIZE = 40; + final int DECK_SIZE = deckMinSize != 0 ? deckMinSize : 40; List sortedCards = new ArrayList<>(cardPool); if (sortedCards.size() > 0) { @@ -1872,11 +1890,11 @@ public class ComputerPlayer extends PlayerImpl implements Player { } } - public static Deck buildDeckWithNormalCards(List cardPool, final List colors) { + public static Deck buildDeckWithNormalCards(int deckMinSize, List cardPool, final List colors) { // top 23 cards plus basic lands until 40 deck size Deck deck = new Deck(); - final int DECK_SIZE = 40; - final int DECK_CARDS_COUNT = 23; + final int DECK_SIZE = deckMinSize != 0 ? deckMinSize : 40; + final int DECK_CARDS_COUNT = Math.floorDiv(deckMinSize * 23, 40); // 23 from 40 final int DECK_LANDS_COUNT = DECK_SIZE - DECK_CARDS_COUNT; // sort card pool by top score @@ -1961,15 +1979,17 @@ public class ComputerPlayer extends PlayerImpl implements Player { @Override public void construct(Tournament tournament, Deck deck) { - if (deck != null && deck.getCards().size() < 40 && !deck.getSideboard().isEmpty()) { - //pick the top 23 cards + DeckValidator deckValidator = DeckValidatorFactory.instance.createDeckValidator(tournament.getOptions().getMatchOptions().getDeckType()); + int deckMinSize = deckValidator != null ? deckValidator.getDeckMinSize() : 0; + + if (deck != null && deck.getCards().size() < deckMinSize && !deck.getSideboard().isEmpty()) { if (chosenColors == null) { for (Card card : deck.getSideboard()) { rememberPick(card, RateCard.rateCard(card, null)); } chosenColors = chooseDeckColorsIfPossible(); } - deck = buildDeck(new ArrayList<>(deck.getSideboard()), chosenColors); + deck = buildDeck(deckMinSize, new ArrayList<>(deck.getSideboard()), chosenColors); } tournament.submitDeck(playerId, deck); } @@ -2072,16 +2092,16 @@ public class ComputerPlayer extends PlayerImpl implements Player { try { Card bestCard = pickBestCard(cards, chosenColors); int maxScore = RateCard.rateCard(bestCard, chosenColors); - int pickedCardRate = RateCard.getCardRating(bestCard); + int pickedCardRate = RateCard.getBaseCardScore(bestCard); - if (pickedCardRate <= 3) { + if (pickedCardRate <= 30) { // if card is bad // try to counter pick without any color restriction Card counterPick = pickBestCard(cards, null); - int counterPickScore = RateCard.getCardRating(counterPick); + int counterPickScore = RateCard.getBaseCardScore(counterPick); // card is really good // take it! - if (counterPickScore >= 8) { + if (counterPickScore >= 80) { bestCard = counterPick; maxScore = RateCard.rateCard(bestCard, chosenColors); } @@ -2422,28 +2442,44 @@ public class ComputerPlayer extends PlayerImpl implements Player { return new ComputerPlayer(this); } + private boolean tryAddTarget(Target target, UUID id, Ability source, Game game) { + // workaround to to check successfull targets add + int before = target.getTargets().size(); + target.addTarget(id, source, game); + int after = target.getTargets().size(); + return before != after; + } + + private boolean tryAddTarget(Target target, UUID id, int amount, Ability source, Game game) { + // workaround to to check successfull targets add + int before = target.getTargets().size(); + target.addTarget(id, amount, source, game); + int after = target.getTargets().size(); + return before != after; + } + + /** * Sets a possible target player - * */ private boolean setTargetPlayer(Outcome outcome, Target target, Ability source, UUID sourceId, UUID abilityControllerId, UUID randomOpponentId, Game game) { if (target.getOriginalTarget() instanceof TargetOpponent) { if (source == null) { - if (((TargetOpponent) target).canTarget(randomOpponentId, game)) { + if (target.canTarget(randomOpponentId, game)) { target.add(randomOpponentId, game); return true; } - } else if (((TargetOpponent) target).canTarget(randomOpponentId, source, game)) { + } else if (target.canTarget(randomOpponentId, source, game)) { target.add(randomOpponentId, game); return true; } for (UUID currentId : game.getOpponents(abilityControllerId)) { if (source == null) { - if (((TargetOpponent) target).canTarget(currentId, game)) { + if (target.canTarget(currentId, game)) { target.add(currentId, game); return true; } - } else if (((TargetOpponent) target).canTarget(currentId, source, game)) { + } else if (target.canTarget(currentId, source, game)) { target.add(currentId, game); return true; } @@ -2548,4 +2584,21 @@ public class ComputerPlayer extends PlayerImpl implements Player { return this.getId().equals(obj.getId()); } + + @Override + public boolean isHuman() { + if (human) { + log.error("computer must be not human", new Throwable()); + } + return human; + } + + @Override + public void restore(Player player) { + super.restore(player); + + // restore used in AI simulations + // all human players converted to computer and analyse + this.human = false; + } } diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java b/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java deleted file mode 100644 index 5197c33536..0000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/java/mage/player/ai/utils/RateCard.java +++ /dev/null @@ -1,267 +0,0 @@ -package mage.player.ai.utils; - -import mage.abilities.Ability; -import mage.abilities.effects.Effect; -import mage.abilities.effects.common.DamageTargetEffect; -import mage.cards.Card; -import mage.constants.ColoredManaSymbol; -import mage.constants.Outcome; -import mage.target.Target; -import mage.target.common.TargetAnyTarget; -import mage.target.common.TargetCreaturePermanent; -import org.apache.log4j.Logger; - -import java.io.InputStream; -import java.util.*; -import mage.constants.SubType; - -/** - * Class responsible for reading ratings from resources and rating given cards. - * Based on card relative ratings from resources and card parameters. - * - * @author nantuko - */ -public final class RateCard { - - private static Map ratings; - private static final Map rated = new HashMap<>(); - private static Integer min = Integer.MAX_VALUE, max = 0; - - /** - * Rating that is given for new cards. - * Ratings are in [1,10] range, so setting it high will make new cards appear more often. - */ - private static final int DEFAULT_NOT_RATED_CARD_RATING = 4; - - private static final Logger log = Logger.getLogger(RateCard.class); - - /** - * Hide constructor. - */ - private RateCard() { - } - - /** - * Get absolute score of the card. - * Depends on type, manacost, rating. - * If allowedColors is null then the rating is retrieved from the cache - * - * @param card - * @param allowedColors - * @return - */ - public static int rateCard(Card card, List allowedColors) { - if (allowedColors == null && rated.containsKey(card.getName())) { - int rate = rated.get(card.getName()); -// log.info(card.getName() + " rate: " + rate); - return rate; - } - int type; - if (card.isPlaneswalker()) { - type = 15; - } else if (card.isCreature()) { - type = 10; - } else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) { - type = 8; - } else if (card.getSubtype(null).contains(SubType.AURA)) { - type = 5; - } else if (card.isInstant()) { - type = 7; - } else { - type = 6; - } - int score = 10 * getCardRating(card) + 2 * type + getManaCostScore(card, allowedColors) - + 40 * isRemoval(card); - if (allowedColors == null) - rated.put(card.getName(), score); - return score; - } - - private static int isRemoval(Card card) { - if (card.getSubtype(null).contains(SubType.AURA) || card.isInstant() || card.isSorcery()) { - - for (Ability ability : card.getAbilities()) { - for (Effect effect : ability.getEffects()) { - if (effect.getOutcome() == Outcome.Removal) { - log.debug("Found removal: " + card.getName()); - return 1; - } - if (effect.getOutcome() == Outcome.Damage) { - if (effect instanceof DamageTargetEffect) { - DamageTargetEffect damageEffect = (DamageTargetEffect) effect; - if (damageEffect.getAmount() > 1) { - for (Target target : ability.getTargets()) { - if (target instanceof TargetCreaturePermanent || target instanceof TargetAnyTarget) { - log.debug("Found damage dealer: " + card.getName()); - return 1; - } - } - } - } - } - if (effect.getOutcome() == Outcome.DestroyPermanent) { - for (Target target : ability.getTargets()) { - if (target instanceof TargetCreaturePermanent) { - log.debug("Found destroyer: " + card.getName()); - return 1; - } - } - } - } - } - } - return 0; - } - - /** - * Return rating of the card. - * - * @param card Card to rate. - * @return Rating number from [1;10]. - */ - public static int getCardRating(Card card) { - if (ratings == null) { - readRatings(); - } - if (ratings.containsKey(card.getName())) { - int r = ratings.get(card.getName()); - // normalize to [1..10] - float f = 10.0f * (r - min) / (max - min); - return (int) Math.round(f); - } - return DEFAULT_NOT_RATED_CARD_RATING; - } - - /** - * Reads ratings from resources. - */ - private synchronized static void readRatings() { - if (ratings == null) { - ratings = new HashMap<>(); - readFromFile("/m13.csv"); - } - } - - private static void readFromFile(String path) { - try { - InputStream is = RateCard.class.getResourceAsStream(path); - Scanner scanner = new Scanner(is); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - String[] s = line.split(":"); - if (s.length == 2) { - Integer rating = Integer.parseInt(s[1].trim()); - String name = s[0].trim(); - if (rating > max) { - max = rating; - } - if (rating < min) { - min = rating; - } - ratings.put(name, rating); - } - } - } catch (Exception e) { - e.printStackTrace(); - ratings.clear(); // no rating available on exception - } - } - - private static final int SINGLE_PENALTY[] = {0, 1, 1, 3, 6, 9}; - - /** - * Get manacost score. - * Depends on chosen colors. Returns negative score for those cards that doesn't fit allowed colors. - * If allowed colors are not chosen, then score based on converted cost is returned with penalty for heavy colored cards. - * - * - * @param card - * @param allowedColors Can be null. - * @return - */ - private static int getManaCostScore(Card card, List allowedColors) { - int converted = card.getManaCost().convertedManaCost(); - if (allowedColors == null) { - int colorPenalty = 0; - for (String symbol : card.getManaCost().getSymbols()) { - if (isColoredMana(symbol)) { - colorPenalty++; - } - } - return 2 * (converted - colorPenalty + 1); - } - final Map singleCount = new HashMap<>(); - int maxSingleCount = 0; - for (String symbol : card.getManaCost().getSymbols()) { - int count = 0; - symbol = symbol.replace("{", "").replace("}", ""); - if (isColoredMana(symbol)) { - for (ColoredManaSymbol allowed : allowedColors) { - if (allowed.toString().equals(symbol)) { - count++; - } - } - if (count == 0) { - return -100; - } - Integer typeCount = singleCount.get(symbol); - if (typeCount == null) { - typeCount = new Integer(0); - } - typeCount += 1; - singleCount.put(symbol, typeCount); - maxSingleCount = Math.max(maxSingleCount, typeCount); - } - } - if (maxSingleCount > 5) - maxSingleCount = 5; - return 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]/*-DOUBLE_PENALTY[doubleCount]*/); - } - - /** - * Determines whether mana symbol is color. - * - * @param symbol - * @return - */ - public static boolean isColoredMana(String symbol) { - String s = symbol; - if (s.length() > 1) { - s = s.replace("{","").replace("}",""); - } - if (s.length() > 1) { - return false; - } - return s.equals("W") || s.equals("G") || s.equals("U") || s.equals("B") || s.equals("R"); - } - - /** - * Return number of color mana symbols in manacost. - * @param card - * @return - */ - public static int getColorManaCount(Card card) { - int count = 0; - for (String symbol : card.getManaCost().getSymbols()) { - if (isColoredMana(symbol)) { - count++; - } - } - return count; - } - - /** - * Return number of different color mana symbols in manacost. - * @param card - * @return - */ - public static int getDifferentColorManaCount(Card card) { - Set symbols = new HashSet<>(); - for (String symbol : card.getManaCost().getSymbols()) { - if (isColoredMana(symbol)) { - symbols.add(symbol); - } - } - return symbols.size(); - } -} diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings.txt b/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings.txt deleted file mode 100644 index 6ccb175ffb..0000000000 --- a/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/ratings.txt +++ /dev/null @@ -1,1214 +0,0 @@ -1569 : Day of Judgment -1548 : Garruk Wildspeaker -1547 : Sword of Vengeance -1544 : Baneslayer Angel -1533 : Kargan Dragonlord -1526 : Frost Titan -1523 : Wurmcoil Engine -1522 : Ob Nixilis, the Fallen -1520 : Chandra Nalaar -1516 : Gideon Jura -1516 : Primeval Titan -1513 : Ajani Goldmane -1512 : Basilisk Collar -1511 : Vampire Nighthawk -1511 : Skithiryx, the Blight Dragon -1509 : Serra Angel -1508 : Koth of the Hammer -1507 : Jace, the Mind Sculptor -1507 : Avenger of Zendikar -1506 : Vengevine -1505 : Nissa Revane -1502 : Student of Warfare -1501 : Jace Beleren -1500 : Iona, Shield of Emeria -1500 : Glimmerpost -1500 : Transcendent Master -1500 : Guul Draz Assassin -1500 : Kozilek, Butcher of Truth -1500 : Omnath, Locus of Mana -1500 : Abyssal Persecutor -1500 : Dragonmaster Outcast -1500 : Kazuul, Tyrant of the Cliffs -1500 : Anowon, the Ruin Sage -1500 : Platinum Angel -1499 : Eldrazi Conscription -1499 : Drana, Kalastria Bloodchief -1499 : Conquering Manticore -1498 : Mul Daya Channelers -1498 : Lord of Shatterskull Pass -1498 : Admonition Angel -1498 : Archon of Redemption -1498 : Inferno Titan -1497 : Sorin Markov -1497 : Sword of Body and Mind -1496 : Terra Stomper -1496 : Carnifex Demon -1496 : Deathless Angel -1495 : Linvala, Keeper of Silence -1492 : Bloodghast -1492 : Steel Hellkite -1491 : Obsidian Fireheart -1489 : Guul Draz Specter -1489 : Kazandu Tuskcaller -1488 : Emrakul, the Aeons Torn -1488 : Coralhelm Commander -1488 : Wrexial, the Risen Deep -1487 : Nirkana Revenant -1486 : Scalding Tarn -1486 : Sphinx of Jwar Isle -1486 : Khalni Hydra -1485 : Felidar Sovereign -1485 : Halo Hunter -1485 : Sarkhan the Mad -1485 : Consume the Meek -1484 : Rampaging Baloths -1484 : Gigantiform -1483 : Consuming Vapors -1482 : It That Betrays -1481 : Eldrazi Monument -1481 : All Is Dust -1480 : Kalitas, Bloodchief of Ghet -1480 : Mimic Vat -1480 : Pestilence Demon -1480 : Stirring Wildwood -1480 : Mind Control -1479 : Comet Storm -1477 : Creeping Tar Pit -1476 : Harabaz Druid -1475 : Geth, Lord of the Vault -1475 : Pelakka Wurm -1473 : Lorthos, the Tidemaker -1473 : Elspeth Tirel -1473 : Grave Titan -1472 : Celestial Colonnade -1471 : Bear Umbra -1471 : Triskelion -1469 : Turntimber Ranger -1468 : Terastodon -1466 : Kazuul Warlord -1465 : Sphinx of Magosi -1464 : Luminarch Ascension -1464 : Lighthouse Chronologist -1464 : Stone Idol Trap -1464 : Chain Reaction -1463 : Sunblast Angel -1463 : Spawnsire of Ulamog -1463 : Royal Assassin -1462 : Misty Rainforest -1461 : Jwari Shapeshifter -1460 : Hellcarver Demon -1459 : Hellkite Charger -1459 : Rite of Replication -1458 : Eternity Vessel -1458 : Bala Ged Thief -1458 : Kalastria Highborn -1458 : Fireball -1456 : Precursor Golem -1456 : Venser, the Sojourner -1456 : Joraga Treespeaker -1456 : Wolfbriar Elemental -1456 : Mitotic Slime -1455 : Journey to Nowhere -1454 : Strata Scythe -1452 : Awakening Zone -1452 : Magmaw -1452 : Gaea's Revenge -1449 : Ezuri's Brigade -1448 : Strength of the Tajuru -1448 : Nantuko Shade -1446 : Ratchet Bomb -1445 : Sun Titan -1444 : Hand of the Praetors -1443 : Lotus Cobra -1441 : Nim Deathmantle -1440 : Arid Mesa -1439 : Scute Mob -1439 : Mystifying Maze -1437 : Argentum Armor -1436 : Chimeric Mass -1434 : Magma Phoenix -1433 : Chandra Ablaze -1433 : Scars of Mirrodin -1433 : Rise of the Eldrazi -1433 : Brittle Effigy -1432 : Blade of the Bloodchief -1432 : Oracle of Mul Daya -1432 : Kuldotha Phoenix -1432 : Mordant Dragon -1431 : Myr Battlesphere -1431 : Skinrender -1431 : Argent Sphinx -1431 : Talus Paladin -1430 : Vengeful Archon -1428 : Cunning Sparkmage -1426 : Celestial Mantle -1425 : Roil Elemental -1425 : Malakir Bloodwitch -1425 : Contagion Clasp -1424 : Trusty Machete -1424 : Sea Gate Loremaster -1424 : World Queller -1423 : Burst Lightning -1423 : Agadeem Occultist -1422 : Raging Ravine -1422 : Fauna Shaman -1421 : Valakut, the Molten Pinnacle -1421 : Seer's Sundial -1420 : Butcher of Malakir -1415 : Novablast Wurm -1414 : Liliana Vess -1413 : Marsh Flats -1412 : Obstinate Baloth -1412 : Condemn -1409 : Emeria Angel -1408 : Sphinx of Lost Truths -1408 : Goliath Sphinx -1407 : Kazandu Blademaster -1407 : Verdant Catacombs -1406 : Grasp of Darkness -1406 : Marshal's Anthem -1404 : Platinum Emperion -1404 : Doom Blade -1404 : Lightning Bolt -1403 : Grappling Hook -1403 : Ulamog, the Infinite Gyre -1402 : Conundrum Sphinx -1400 : Momentous Fall -1400 : Protean Hydra -1399 : Ancient Hellkite -1398 : Flame Slash -1396 : Kabira Evangel -1396 : Pacifism -1395 : Gelatinous Genesis -1394 : Arc Trail -1393 : Joraga Warcaller -1392 : Lavaclaw Reaches -1392 : Lodestone Golem -1390 : Liege of the Tangle -1389 : Grand Architect -1386 : Trigon of Corruption -1386 : Angelic Arbiter -1383 : True Conviction -1383 : Mox Opal -1383 : Spikeshot Elder -1380 : Devout Lightcaster -1379 : Gatekeeper of Malakir -1378 : Gigantomancer -1377 : Shepherd of the Lost -1375 : Bloodchief Ascension -1375 : Darksteel Axe -1375 : Livewire Lash -1372 : Hoarding Dragon -1368 : Darksteel Juggernaut -1367 : Conqueror's Pledge -1367 : Arrest -1367 : Pyroclasm -1364 : Galvanic Blast -1363 : Lux Cannon -1362 : Echo Mage -1361 : Quicksilver Gargantuan -1360 : Razor Hippogriff -1360 : Volition Reins -1360 : Rage Nimbus -1360 : Tuktuk the Explorer -1357 : Putrefax -1353 : Prototype Portal -1353 : Disaster Radius -1353 : Prodigal Pyromancer -1352 : Staggershock -1352 : Brimstone Mage -1351 : Punishing Fire -1348 : Rapacious One -1346 : Golem Artisan -1345 : Air Servant -1343 : Goblin Guide -1342 : Overwhelming Stampede -1342 : Cudgel Troll -1336 : Emeria, the Sky Ruin -1335 : Stoneforge Mystic -1334 : Engulfing Slagwurm -1333 : Kemba, Kha Regent -1332 : Etched Champion -1324 : Beastmaster Ascension -1324 : Warren Instigator -1315 : Plated Geopede -1315 : Kabira Vindicator -1315 : Chandra's Outrage -1313 : Oxidda Scrapmelter -1312 : Hideous End -1312 : Hedron Matrix -1312 : Blinding Mage -1311 : Slice in Twain -1311 : Knight Exemplar -1309 : Reassembling Skeleton -1308 : Embersmith -1308 : Hellion Eruption -1305 : Dispense Justice -1304 : Turn to Slag -1304 : Boar Umbra -1302 : Ulamog's Crusher -1299 : Artisan of Kozilek -1297 : Hada Freeblade -1296 : Eye of Ugin -1296 : Death's Shadow -1295 : Marsh Casualties -1295 : Kor Skyfisher -1294 : Summoning Trap -1293 : Smother -1292 : Howling Banshee -1290 : Domestication -1290 : Urge to Feed -1289 : Lightkeeper of Emeria -1287 : Demon of Death's Gate -1286 : Sylvok Replica -1286 : Vendetta -1284 : Broodwarden -1282 : Shatter -1281 : Asceticism -1280 : Assassinate -1279 : Cyclops Gladiator -1276 : Nomads' Assembly -1276 : Knight of Cliffhaven -1275 : Bestial Menace -1272 : Myrsmith -1272 : Necrotic Ooze -1272 : Aether Adept -1270 : Living Tsunami -1267 : Beastbreaker of Bala Ged -1264 : Adventuring Gear -1264 : Revoke Existence -1263 : Vampire Hexmage -1262 : Heavy Arbalest -1261 : Pathrazer of Ulamog -1260 : Disfigure -1258 : Forked Bolt -1258 : Stormfront Pegasus -1256 : Birds of Paradise -1253 : Nirkana Cutthroat -1253 : Voyager Drake -1251 : Heat Ray -1250 : Rust Tick -1250 : Crystal Ball -1248 : Windrider Eel -1245 : Acid Web Spider -1243 : Enclave Cryptologist -1238 : Myr Propagator -1238 : Kozilek's Predator -1237 : Vapor Snare -1236 : Steppe Lynx -1236 : Tempered Steel -1235 : Terminate -1234 : Palladium Myr -1234 : Tomb Hex -1234 : Garruk's Packleader -1233 : Electropotence -1231 : Black Knight -1230 : Narcolepsy -1229 : Acidic Slime -1226 : Oblivion Ring -1223 : Cystbearer -1221 : Rusted Relic -1221 : Azure Drake -1220 : Venerated Teacher -1220 : Splinter Twin -1220 : Searing Blaze -1219 : Tideforce Elemental -1218 : Trinket Mage -1218 : Whispersilk Cloak -1216 : Hada Spy Patrol -1216 : Jace's Ingenuity -1215 : Kor Aeronaut -1214 : Cerebral Eruption -1214 : Nest Invader -1214 : Water Servant -1213 : World at War -1212 : Bladetusk Boar -1211 : Traitorous Instinct -1210 : Plague Stinger -1210 : Ondu Giant -1210 : Cloud Crusader -1209 : Honor of the Pure -1207 : Barrage Ogre -1207 : Wall of Omens -1207 : Path to Exile -1206 : Umara Raptor -1206 : Mana Leak -1205 : Overgrown Battlement -1205 : Caustic Crawler -1205 : Behemoth Sledge -1203 : Growth Spasm -1202 : Bellowing Tanglewurm -1200 : Flesh Allergy -1199 : Cloud Elemental -1198 : Darkslick Drake -1198 : Quag Sickness -1197 : Myr Galvanizer -1195 : Barbed Battlegear -1195 : Assault Griffin -1193 : Foresee -1192 : Induce Despair -1192 : Greater Basilisk -1191 : Bloodhusk Ritualist -1189 : Leatherback Baloth -1188 : Kor Spiritdancer -1188 : Rise from the Grave -1187 : Kor Hookmaster -1187 : Sleep -1185 : Grafted Exoskeleton -1185 : Skywatcher Adept -1183 : Glimmerpoint Stag -1182 : Kuldotha Forgemaster -1182 : Mortician Beetle -1181 : Eldrazi Temple -1180 : Harrow -1178 : Ezuri, Renegade Leader -1175 : Hammer of Ruin -1172 : Contagious Nim -1169 : Cultivate -1168 : Mindbreak Trap -1168 : Pitfall Trap -1168 : Inferno Trap -1167 : Turntimber Basilisk -1167 : Ember Hauler -1166 : Martial Coup -1164 : Perilous Myr -1163 : Iona's Judgment -1163 : Child of Night -1161 : Painsmith -1161 : Ogre's Cleaver -1161 : Finest Hour -1160 : Myr Reservoir -1160 : Duskdale Wurm -1160 : Elspeth, Knight-Errant -1159 : Garruk's Companion -1158 : Horizon Drake -1157 : Emrakul's Hatcher -1157 : Jagwasp Swarm -1156 : Thought Gorger -1156 : Guard Gomazoa -1156 : Last Kiss -1155 : Thada Adel, Acquisitor -1154 : Quest for the Gravelord -1154 : Destructive Force -1154 : Armored Ascension -1153 : Trigon of Rage -1153 : Join the Ranks -1153 : Sylvan Ranger -1152 : Merfolk Seastalkers -1152 : Merfolk Skyscout -1152 : Kor Firewalker -1151 : Elvish Archdruid -1149 : Sadistic Sacrament -1149 : Glint Hawk -1148 : Predatory Urge -1148 : Liliana's Specter -1148 : Woolly Thoctar -1147 : Stonework Puma -1146 : Archive Trap -1146 : Wild Griffin -1146 : Llanowar Elves -1145 : Necrogen Scudder -1144 : Armament Master -1143 : Keening Stone -1141 : Blazing Torch -1141 : Dawnglare Invoker -1140 : Torch Slinger -1140 : Geyser Glider -1140 : Fire Servant -1138 : Heartstabber Mosquito -1138 : Caravan Escort -1138 : Wildheart Invoker -1137 : Welkin Tern -1137 : Squadron Hawk -1137 : Maelstrom Pulse -1136 : Throne of Geth -1136 : Bloodbraid Elf -1135 : Glint Hawk Idol -1135 : Trigon of Infestation -1135 : Clone -1135 : Putrid Leech -1134 : Giant Scorpion -1134 : Ajani Vengeant -1133 : Grazing Gladehart -1132 : Cosi's Trickster -1131 : Juggernaut -1130 : Hedron Crab -1130 : Into the Roil -1130 : Ichor Rats -1130 : Ogre Geargrabber -1129 : Lightning Helix -1128 : Oust -1127 : Act of Treason -1126 : Arrow Volley Trap -1126 : Vedalken Certarch -1126 : Deathforge Shaman -1126 : Bituminous Blast -1125 : Training Grounds -1124 : Mark of Mutiny -1124 : Knight of the White Orchid -1123 : Tumble Magnet -1121 : Lumengrid Drake -1121 : Necropede -1121 : Yavimaya Wurm -1120 : Noble Hierarch -1119 : River Boa -1119 : Scrapdiver Serpent -1119 : Renegade Doppelganger -1119 : Tajuru Preserver -1119 : White Knight -1119 : Vengeful Rebirth -1118 : Mindslaver -1118 : Genesis Wave -1118 : Frostwind Invoker -1118 : Ranger of Eos -1118 : Sarkhan Vol -1117 : Corrupt -1117 : Chandra's Spitfire -1116 : Bonds of Quicksilver -1115 : Surrakar Marauder -1114 : Explorer's Scope -1114 : Ice Cage -1114 : Steel Overseer -1114 : Earthquake -1113 : Vines of Vastwood -1113 : Strider Harness -1113 : Snapping Drake -1112 : Drake Umbra -1112 : Warlord's Axe -1111 : Sphinx of the Steel Wind -1110 : Hand of Emrakul -1109 : Aether Figment -1109 : Hagra Diabolist -1109 : Murasa Pyromancer -1107 : Apex Hawks -1107 : Dead Reckoning -1104 : Guul Draz Vampire -1104 : Overrun -1104 : Battlegrace Angel -1103 : Elvish Visionary -1102 : Goblin Ruinblaster -1102 : Smite -1099 : Graypelt Hunter -1099 : Rhox War Monk -1099 : Stun Sniper -1098 : Khalni Heart Expedition -1098 : Aven Squire -1097 : Greenweaver Druid -1097 : Broodmate Dragon -1096 : Goblin Bushwhacker -1096 : Riddlesmith -1096 : Steady Progress -1096 : Blight Mamba -1096 : Pawn of Ulamog -1094 : Spined Wurm -1094 : Glacial Fortress -1094 : Master of the Wild Hunt -1091 : Blood Seeker -1091 : Carapace Forger -1090 : Highland Berserker -1090 : Phylactery Lich -1089 : Skeletal Wurm -1089 : Refraction Trap -1089 : Tattered Drake -1087 : Tainted Strike -1087 : Lorescale Coatl -1087 : Sprouting Thrinax -1086 : Arbor Elf -1085 : Frontier Guide -1085 : Sign in Blood -1084 : Mammoth Umbra -1084 : Rakka Mar -1083 : Air Elemental -1082 : Madrush Cyclops -1080 : Preordain -1080 : Ant Queen -1080 : Fiery Fall -1078 : Ichorclaw Myr -1076 : Gomazoa -1076 : Horizon Spellbomb -1076 : War Priest of Thune -1076 : Scroll Thief -1075 : Might of Oaks -1074 : Hellfire Mongrel -1074 : Kor Cartographer -1074 : Kor Sanctifiers -1074 : Champion's Drake -1074 : Darklit Gargoyle -1074 : Knight of the Reliquary -1073 : Fledgling Griffin -1072 : Goblin Shortcutter -1072 : Infiltration Lens -1072 : Indomitable Archangel -1071 : Bogardan Hellkite -1071 : Kathari Remnant -1070 : See Beyond -1070 : Ethersworn Adjudicator -1069 : Deny Reality -1069 : Vampire Aristocrat -1069 : Ethercaste Knight -1068 : Bladed Pinions -1068 : Kemba's Skyguard -1068 : AEther Figment -1067 : Tajuru Archer -1067 : Tuktuk Grunts -1067 : Stoic Rebuttal -1067 : Auriok Edgewright -1067 : Great Sable Stag -1066 : Tangle Angler -1066 : Barony Vampire -1066 : Druid of the Anima -1065 : Court Archers -1064 : Mold Shambler -1064 : Feast of Blood -1064 : Ondu Cleric -1064 : Deadly Recluse -1064 : Thornling -1063 : Paralyzing Grasp -1063 : Aura Gnarlid -1062 : Zektar Shrine Expedition -1062 : Blood Tribute -1062 : Bleak Coven Vampires -1061 : Rafiq of the Many -1061 : Nulltread Gargantuan -1060 : Baloth Cage Trap -1060 : Loam Lion -1060 : Stormtide Leviathan -1060 : Ball Lightning -1059 : Spawning Breath -1059 : Shoreline Salvager -1059 : Jenara, Asura of War -1058 : Halt Order -1058 : Stabbing Pain -1056 : Courier's Capsule -1056 : Shock -1055 : Khalni Gem -1055 : Disperse -1055 : Sigiled Paladin -1054 : Timbermaw Larva -1054 : Puncturing Light -1054 : Canopy Cover -1053 : Windborne Charge -1053 : Lightmine Field -1053 : Reverberate -1052 : Crypt Ripper -1052 : Looming Shade -1051 : Spire Barrage -1051 : Cadaver Imp -1050 : Summoner's Bane -1050 : Perimeter Captain -1049 : Makindi Griffin -1048 : Lullmage Mentor -1048 : Primal Bellow -1048 : Surrakar Spellblade -1048 : Awakener Druid -1048 : Conquerors Pledge -1047 : Mind Sludge -1047 : Neurok Replica -1047 : Neurok Invisimancer -1047 : Trigon of Thought -1047 : Kitesail -1047 : Wild Nacatl -1046 : Reckless Scholar -1046 : Sky Ruin Drake -1046 : Grindclock -1046 : Explore -1045 : Nissa's Chosen -1045 : Flameborn Hellion -1045 : Ghalma's Warden -1045 : Berserkers of Blood Ridge -1045 : Goblin Outlander -1044 : Virulent Swipe -1044 : Time of Heroes -1044 : Nightwing Shade -1044 : Scarland Thrinax -1043 : Time Warp -1043 : Rhox Pikemaster -1042 : Zendikar -1042 : Lavaball Trap -1042 : Magma Rift -1042 : Snake Umbra -1042 : Giant Spider -1041 : Shatterskull Giant -1041 : Cliff Threader -1041 : Sea Gate Oracle -1041 : Nemesis Trap -1041 : Rootbound Crag -1040 : Auriok Sunchaser -1040 : Corpse Cur -1040 : Sacred Wolf -1040 : Beacon Behemoth -1040 : Hell's Thunder -1039 : Bloodhall Ooze -1039 : Winged Coatl -1038 : Regress -1038 : Tuktuk Scrapper -1038 : Ruthless Cullblade -1038 : Captivating Vampire -1038 : Mind Spring -1038 : Emerald Oryx -1038 : Steward of Valeron -1037 : Devastating Summons -1037 : Calcite Snapper -1037 : Blightning -1037 : Cloudheath Drake -1036 : Recurring Insight -1036 : Hellspark Elemental -1036 : Rhox Brute -1035 : Saberclaw Golem -1034 : Reality Spasm -1034 : Drowned Catacomb -1034 : Dragonskull Summit -1034 : Sigil of the Empty Throne -1033 : Tower of Calamities -1033 : Bojuka Brigand -1033 : Time Reversal -1032 : Bramblesnap -1032 : Groundswell -1032 : Treasure Hunt -1032 : Kathari Screecher -1031 : Vampire Lacerator -1031 : Daggerback Basilisk -1030 : Prey's Vengeance -1030 : Augury Owl -1030 : Fling -1029 : Blackcleave Goblin -1029 : Wall of Frost -1029 : Brave the Elements -1027 : Pyromancer Ascension -1027 : Grixis Slavedriver -1026 : Soulsurge Elemental -1026 : Putrefy -1025 : Makindi Shieldmate -1025 : Abuna Acolyte -1024 : Alpha Tyrannax -1023 : Quest for the Gemblades -1023 : Wind Zendikon -1023 : Mist Leopard -1023 : Esper Cormorants -1022 : Expedition Map -1022 : Dread Drone -1022 : Everflowing Chalice -1022 : Prized Unicorn -1022 : Griffin Sentinel -1022 : Skyknight Legionnaire -1022 : Ardent Plea -1021 : Nightguard Patrol -1020 : Giant Growth -1020 : Dregscape Zombie -1019 : Nacatl Outlander -1019 : Molten-Tail Masticore -1017 : Repel the Darkness -1017 : Gravitational Shift -1017 : Bloodthrone Vampire -1016 : Whiplash Trap -1016 : Bloodshot Trainee -1016 : Guard Duty -1016 : Akoum Battlesinger -1016 : Sejiri Merfolk -1016 : Gravedigger -1015 : Hyena Umbra -1014 : Æther Figment -1013 : Umbra Mystic -1013 : Akoum Boulderfoot -1012 : Crypt of Agadeem -1012 : Mnemonic Wall -1012 : Plummet -1012 : Watchwolf -1011 : Vastwood Gorger -1011 : Moriok Replica -1011 : Sky-Eel School -1011 : Zombie Outlander -1011 : Incurable Ogre -1010 : Emerge Unscathed -1010 : Runeclaw Bear -1010 : Vectis Silencers -1009 : Kor Duelist -1009 : Wall of Denial -1008 : Inexorable Tide -1007 : Chrome Steed -1007 : Survival Cache -1007 : Pilgrim's Eye -1006 : Jaddi Lifestrider -1006 : Vastwood Animist -1006 : Sigil of Distinction -1006 : Yoked Plowbeast -1005 : Sighted-Caste Sorcerer -1004 : Bala Ged Scorpion -1004 : Halimar Excavator -1004 : Sunpetal Grove -1004 : Stone Golem -1003 : Jwar Isle Refuge -1003 : Vectis Agents -1003 : Gold Myr -1002 : Mysteries of the Deep -1002 : Negate -1002 : Pestilent Kathari -1001 : Halimar Depths -1001 : Glass Golem -1000 : Lust for War -1000 : Realms Uncharted -1000 : Affa Guard Hound -1000 : Roc Egg -999 : Ajani's Pridemate -998 : Aether Tradewinds -998 : Weakness -997 : Eel Umbra -997 : Drudge Skeletons -995 : Vulshok Replica -995 : Ferrovore -995 : Molten Frame -995 : Jungle Weaver -994 : Akoum Refuge -994 : Wind Drake -993 : AEther Adept -992 : Cobra Trap -992 : Summit Apes -992 : Cylian Elf -992 : Talon Trooper -991 : Colossal Might -990 : Vulshok Heartstoker -990 : Warmonger's Chariot -990 : Silvercoat Lion -989 : Sunspear Shikari -988 : Slavering Nulls -986 : Spidersilk Net -986 : Unstable Footing -986 : Razorfield Thresher -986 : Gnarlid Pack -986 : Votary of the Conclave -986 : Zephyr Sprite -985 : Grappler Spider -985 : Grayscaled Gharial -984 : Snapsail Glider -984 : Goblin Chieftain -983 : Soul's Majesty -983 : Hellkite Overlord -982 : Diabolic Tutor -982 : Soul Warden -982 : Akrasan Squire -982 : Wildfield Borderpost -981 : Graypelt Refuge -980 : Sejiri Refuge -980 : Instill Infection -980 : Spider Umbra -980 : Celestial Purge -980 : Bone Saw -980 : Dispeller's Capsule -979 : Teetering Peaks -979 : Soliton -979 : Scepter of Insight -978 : Kazandu Refuge -978 : Valakut Fireboar -978 : Warpath Ghoul -977 : Filigree Angel -977 : Fume Spitter -976 : Inquisition of Kozilek -975 : Traumatize -975 : Tukatongue Thallid -975 : Aerie Mystics -974 : Savage Silhouette -974 : Kiln Fiend -973 : Rhox Bodyguard -972 : Vulshok Berserker -972 : Obelisk of Jund -971 : Marsh Threader -970 : Vampire's Bite -970 : Narrow Escape -970 : Wrap in Flames -970 : Diminish -970 : Cavern Thoctar -970 : Filigree Sages -969 : Stomper Cub -969 : Bazaar Trader -969 : Manic Vandal -969 : Scepter of Dominance -968 : Lavafume Invoker -968 : Font of Mythos -968 : Outrider of Jhess -968 : Undead Leotau -967 : Moriok Reaver -967 : Sporecap Spider -967 : Spell Contortion -967 : Arc Runner -967 : Firewild Borderpost -967 : Jhessian Lookout -966 : Brindle Boar -965 : Serra Ascendant -965 : Veinfire Borderpost -964 : Magosi, the Waterveil -964 : Deprive -964 : Lava Axe -962 : Thrummingbird -962 : Ezuri's Archers -962 : Copper Myr -962 : Lone Missionary -962 : Quest for Renewal -962 : Permafrost Trap -962 : Dimir Signet -962 : Etherium Abomination -962 : Glory of Warfare -961 : Hagra Crocodile -961 : Iron Myr -961 : Ikiral Outrider -961 : Null Champion -961 : Dreg Reaver -961 : Valeron Outlander -960 : Might of the Masses -960 : Golgari Signet -959 : Carrion Call -959 : Salvage Scout -958 : Ior Ruin Expedition -958 : Horned Turtle -957 : Molder Beast -957 : Halimar Wavewatch -956 : Molten Ravager -956 : Origin Spellbomb -956 : Goblin Roughrider -956 : Shiv's Embrace -955 : Alpha Tyrranax -954 : Vent Sentinel -954 : Gloomhunter -954 : Rampant Growth -953 : Kor Outfitter -953 : Needlebite Trap -953 : Wing Puncture -953 : Amulet of Vigor -952 : Obelisk of Naya -951 : Lifesmith -951 : Kranioceros -950 : Grim Discovery -950 : Kelinore Bat -950 : Quenchable Fire -949 : Slaughter Cry -949 : Merfolk Sovereign -948 : Seascape Aerialist -948 : Bant Battlemage -948 : Mistvein Borderpost -946 : Wall of Tanglecord -946 : Brood Birthing -946 : Guardians of Akrasa -945 : Joraga Bard -945 : Hedron Rover -944 : Goblin War Paint -944 : Exsanguinate -943 : Slingbow Trap -942 : Gloryscale Viashino -942 : Goblin Mountaineer -941 : Escaped Null -941 : Inspired Charge -941 : Terramorphic Expanse -941 : Temple Bell -941 : Excommunicate -941 : Onyx Goblet -940 : Culling Dais -940 : Elite Vanguard -939 : Kraken Hatchling -938 : Marble Chalice -937 : Quag Vampires -936 : Trailblazer's Boots -936 : Necrotic Plague -934 : Leyline of Vitality -933 : Wall of Bone -933 : Disorient -932 : Merfolk Wayfinder -932 : Withstand Death -931 : Distortion Strike -931 : Claws of Valakut -931 : Deathmark -930 : Soulbound Guardians -930 : Valiant Guard -930 : Spellbreaker Behemoth -930 : Vedalken Outlander -929 : Prophetic Prism -928 : Soul Stair Expedition -928 : Quest for Ula's Temple -926 : Cancel -926 : Ruinous Minotaur -926 : Psychic Miasma -924 : Skitter of Lizards -923 : Soul Parry -923 : Quest for the Nihil Stone -922 : Sylvok Lifestaff -922 : Pennon Blade -921 : Tempest Owl -921 : Combust -920 : Archmage Ascension -920 : Hedron Scrabbler -920 : Lagac Lizard -920 : Enclave Elite -920 : Obelisk of Grixis -919 : Selesnya Signet -918 : Scythe Tiger -918 : Flight Spellbomb -918 : Ruin Ghost -917 : Lay Bare -917 : Bog Wraith -917 : Acolyte of Xathrid -916 : Wall of Faith -914 : Surrakar Banisher -914 : Dread Statuary -914 : Obelisk of Esper -913 : Screeching Silcaw -913 : Furnace Celebration -913 : Snapping Creeper -912 : Battle Hurda -911 : Nether Horror -911 : Howling Mine -910 : Obelisk of Bant -910 : Knotvine Mystic -909 : Seismic Shudder -908 : Copperline Gorge -908 : Suffer the Past -907 : Corrupted Zendikon -907 : Oakenform -907 : Fieldmist Borderpost -906 : Dreamstone Hedron -905 : Fusion Elemental -904 : Terra Eternal -904 : Infantry Veteran -904 : Boros Signet -903 : Dreadwing -902 : Twitch -901 : Surreal Memoir -900 : Dross Hopper -900 : Quicksand -900 : Khalni Garden -899 : Earth Servant -899 : Constricting Tendrils -898 : Quest for Pure Flame -898 : Kabira Crossroads -898 : Leonin Arbiter -898 : Blackcleave Cliffs -897 : Ricochet Trap -897 : Gargoyle Sentinel -896 : Vastwood Zendikon -894 : Spreading Seas -894 : Seize the Initiative -894 : Seachrome Coast -894 : Baneful Omen -893 : Explosive Revelation -892 : Razorverge Thicket -891 : Roofstalker Wight -889 : Redirect -888 : Selective Memory -887 : Silver Myr -886 : Grotag Thrasher -886 : Sejiri Steppe -886 : Unsummon -884 : Shoal Serpent -884 : Darkslick Shores -884 : Semblance Anvil -882 : Goblin Arsonist -881 : Mind Rot -881 : Rotting Legion -880 : Crusher Zendikon -880 : Angel's Mercy -879 : Spell Pierce -879 : Corrupted Harvester -879 : Leaden Myr -878 : Alluring Siren -877 : Quest for the Holy Relic -877 : Cast Through Time -877 : Angelsong -876 : Shieldmate's Blessing -876 : Bold Defense -876 : Noble Vestige -876 : Tanglesap -876 : Scrib Nibblers -875 : Soaring Seacliff -875 : Landbind Ritual -874 : Nimbus Wings -874 : Pulse Tracker -874 : Canyon Minotaur -873 : Eland Umbra -872 : Zendikar Farguide -872 : Tunnel Ignus -872 : Goblin Piker -871 : Mighty Leap -870 : Luminous Wake -870 : Ogre Sentry -870 : Glory Seeker -868 : Quest for Ancient Secrets -868 : Turntimber Grove -868 : Brink of Disaster -868 : Kitesail Apprentice -867 : Auriok Replica -866 : Guardian Zendikon -865 : Relic Crush -865 : Fiery Hellhound -864 : Lethargy Trap -864 : Zof Shade -863 : Mire Blight -863 : Vector Asp -863 : Naturalize -863 : Silence -863 : Flashfreeze -860 : Dormant Gomazoa -860 : Leaf Arrow -859 : Call to Mind -859 : Inkwell Leviathan -858 : Caller of Gales -858 : Trapmaker's Snare -858 : Carnage Altar -858 : Memnite -858 : Nature's Claim -856 : Scoria Elemental -856 : Mass Polymorph -856 : Coral Merfolk -855 : Dark Tutelage -854 : Dissipation Field -853 : Kuldotha Rebirth -852 : Pillarfield Ox -851 : Irresistible Prey -848 : Shrivel -847 : Runeflare Trap -847 : Mindless Null -847 : Disentomb -846 : Veteran's Reflexes -845 : Cosi's Ravager -844 : Smoldering Spires -844 : Relentless Rats -842 : Piranha Marsh -842 : Oxidda Daredevil -842 : Thunder Strike -840 : Evolving Wilds -840 : Goblin Tunneler -840 : Viscera Seer -840 : Solemn Offering -838 : Rest for the Weary -838 : Palace Guard -836 : Nema Siltlurker -836 : Skittering Invasion -835 : Bog Tatters -835 : Siege Mastodon -833 : Plated Seastrider -833 : Volcanic Strength -833 : Kraken's Eye -832 : Copperhorn Scout -831 : Safe Passage -830 : Harmless Assault -830 : Armored Cancrix -829 : Bull Rush -828 : Harbor Serpent -828 : Merfolk Spy -827 : Leyline of Anticipation -827 : Unholy Strength -825 : Assault Strobe -821 : Holy Strength -821 : Jinxed Idol -819 : Beast Hunt -817 : Merfolk Observer -817 : Leyline of the Void -816 : Bog Raiders -816 : Goblin Balloon Brigade -816 : Phantom Beast -815 : Duress -814 : Repay In Kind -814 : Primal Cocoon -813 : Clone Shell -812 : Twisted Image -812 : Painful Quandary -812 : Haze Frog -810 : Panic Spellbomb -810 : Blunt the Assault -810 : Mire's Toll -808 : Necrogen Censer -808 : Curse of Wizardry -807 : Ravenous Trap -807 : Shared Discovery -806 : Desecrated Earth -806 : Accorder's Shield -806 : Venser's Journal -806 : Leyline of Punishment -805 : Turn Aside -805 : Fleeting Distraction -804 : Demolish -803 : Raid Bombardment -803 : Maritime Guard -803 : Wall of Vines -801 : Roiling Terrain -800 : Jace's Erasure -797 : Phantasmal Abomination -797 : Bojuka Bog -796 : Perish the Thought -796 : Demystify -793 : Sunspring Expedition -792 : Blistergrub -792 : Death Cultist -792 : Crab Umbra -790 : Caravan Hurda -790 : Ancient Stirrings -790 : Gravity Well -790 : Nature's Spiral -786 : Goblin Gaveleer -786 : Molten Psyche -786 : Dispel -785 : Ajani's Mantra -783 : Memoricide -782 : Razor Boomerang -782 : Feral Contest -780 : Hornet Sting -778 : Shape Anew -778 : Walking Atlas -777 : Jwari Scuttler -777 : Dragon's Claw -776 : Demon's Horn -775 : Leyline of Sanctity -775 : Tireless Missionaries -774 : Fulgent Distraction -774 : Loxodon Wayfarer -773 : Unified Will -764 : Trapfinder's Trick -763 : Trigon of Mending -758 : Quest for the Goblin Lord -756 : Pyretic Ritual -755 : Relic Putrescence -754 : Liquimetal Coating -750 : Darksteel Myr -750 : Nihil Spellbomb -750 : Goldenglow Moth -747 : Rumbling Aftershocks -745 : Fog -743 : Tome Scour -741 : Bloodcrazed Goblin -739 : Golem Foundry -739 : Viridian Revel -739 : Elixir of Immortality -739 : Wild Evocation -734 : Haunting Echoes -732 : Contaminated Ground -732 : Blood Tithe -726 : Enatu Golem -724 : Aura Finesse -723 : Back to Nature -721 : Demonic Appetite -715 : Vault Skyward -712 : Nighthaze -710 : Autumn's Veil -703 : Melt Terrain -702 : Reinforced Bulwark -696 : Vigil for the Lost -693 : Dryad's Favor -692 : Golden Urn -688 : Fissure Vent -686 : Living Destiny -684 : Ornithopter -679 : Echo Circlet -678 : Runed Servitor -669 : Hunters' Feast -650 : Liliana's Caress -644 : Not Of This World -640 : Golem's Heart -633 : Swamp -633 : Mountain -615 : Whitesun's Passage -612 : Sorcerer's Strongbox -604 : Incite -588 : Forest -586 : Voltaic Key -577 : Plains -574 : Island -572 : Tectonic Edge -554 : Angel's Feather -535 : Wurm's Tooth diff --git a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml index d8a75c7fde..1df762162d 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMCTS/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-ai-mcts @@ -39,8 +39,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 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 50e33f233c..37de07485a 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 @@ -234,7 +234,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } } if (possibleTargets.size() == 1) { - target.addTarget(possibleTargets.iterator().next(), source, game); + target.addTarget(possibleTargets.iterator().next(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } Iterator it = possibleTargets.iterator(); @@ -243,7 +243,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { for (int i = 0; i < targetNum; i++) { targetId = it.next(); } - target.addTarget(targetId, source, game); + target.addTarget(targetId, source, game);// todo: addtryaddtarget or return type (see computerPlayer) return true; } @@ -297,7 +297,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } Card card = cards.getRandom(game); if (card != null) { - target.addTarget(card.getId(), source, game); + target.addTarget(card.getId(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } return false; @@ -315,7 +315,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { } } if (possibleTargets.size() == 1) { - target.addTarget(possibleTargets.iterator().next(), target.getAmountRemaining(), source, game); + target.addTarget(possibleTargets.iterator().next(), target.getAmountRemaining(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } Iterator it = possibleTargets.iterator(); @@ -324,7 +324,7 @@ public class SimulatedPlayerMCTS extends MCTSPlayer { for (int i = 0; i < targetNum; i++) { targetId = it.next(); } - target.addTarget(targetId, RandomUtil.nextInt(target.getAmountRemaining()) + 1, source, game); + target.addTarget(targetId, RandomUtil.nextInt(target.getAmountRemaining()) + 1, source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } diff --git a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml index 1cc373afd2..ae10a64f82 100644 --- a/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.AIMinimax/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-aiminimax @@ -39,8 +39,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Player.Human/pom.xml b/Mage.Server.Plugins/Mage.Player.Human/pom.xml index b295f64ad4..83cb9d5fdb 100644 --- a/Mage.Server.Plugins/Mage.Player.Human/pom.xml +++ b/Mage.Server.Plugins/Mage.Player.Human/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-player-human @@ -39,8 +39,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 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 a8122e52b4..b03c0cc907 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 @@ -1,8 +1,5 @@ - package mage.player.human; -import java.io.Serializable; -import java.util.*; import mage.MageObject; import mage.abilities.*; import mage.abilities.costs.VariableCost; @@ -11,6 +8,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.RequirementEffect; +import mage.abilities.hint.HintUtils; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.Card; import mage.cards.Cards; @@ -18,8 +16,6 @@ import mage.cards.decks.Deck; import mage.choices.Choice; import mage.choices.ChoiceImpl; import mage.constants.*; -import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; -import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL; import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; @@ -42,16 +38,25 @@ import mage.target.Target; import mage.target.TargetAmount; import mage.target.TargetCard; import mage.target.TargetPermanent; -import mage.target.common.TargetAttackingCreature; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetAttackingCreature; import mage.target.common.TargetDefender; import mage.util.GameLog; import mage.util.ManaUtil; import mage.util.MessageToClient; import org.apache.log4j.Logger; +import java.awt.*; +import java.io.Serializable; +import java.util.List; +import java.util.Queue; +import java.util.*; +import java.util.stream.Collectors; + +import static mage.constants.PlayerAction.REQUEST_AUTO_ANSWER_RESET_ALL; +import static mage.constants.PlayerAction.TRIGGER_AUTO_ORDER_RESET_ALL; + /** - * * @author BetaSteward_at_googlemail.com */ public class HumanPlayer extends PlayerImpl { @@ -146,7 +151,7 @@ public class HumanPlayer extends PlayerImpl { protected boolean pullResponseFromQueue(Game game) { if (actionQueue.isEmpty() && actionIterations > 0 && !actionQueueSaved.isEmpty()) { - actionQueue = new LinkedList(actionQueueSaved); + actionQueue = new LinkedList<>(actionQueueSaved); actionIterations--; // logger.info("MACRO iteration: " + actionIterations); } @@ -232,9 +237,15 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("chooseMulligan", game); int nextHandSize = game.mulliganDownTo(playerId); do { - String message = "Mulligan " - + (getHand().size() > nextHandSize ? "down to " : "for free, draw ") - + nextHandSize + (nextHandSize == 1 ? " card?" : " cards?"); + String cardsCountInfo = nextHandSize + (nextHandSize == 1 ? " card" : " cards"); + String message; + if (getHand().size() > nextHandSize) { + // pay + message = "Mulligan " + HintUtils.prepareText("down to " + cardsCountInfo, Color.YELLOW) + "?"; + } else { + // free + message = "Mulligan " + HintUtils.prepareText("for free", Color.GREEN) + ", draw another " + cardsCountInfo + "?"; + } Map options = new HashMap<>(); options.put("UI.left.btn.text", "Mulligan"); options.put("UI.right.btn.text", "Keep"); @@ -341,7 +352,7 @@ public class HumanPlayer extends PlayerImpl { replacementEffectChoice.getChoices().clear(); replacementEffectChoice.setKeyChoices(rEffects); - + // Check if there are different ones int differentChoices = 0; String lastChoice = ""; @@ -418,6 +429,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + // choose one or multiple permanents updateGameStatePriority("choose(5)", game); UUID abilityControllerId = playerId; if (target.getTargetController() != null @@ -447,6 +459,14 @@ public class HumanPlayer extends PlayerImpl { } waitForResponse(game); if (response.getUUID() != null) { + // selected some target + + // remove selected + if (target.getTargets().contains(response.getUUID())) { + target.remove(response.getUUID()); + continue; + } + if (!targetIds.contains(response.getUUID())) { continue; } @@ -482,13 +502,17 @@ public class HumanPlayer extends PlayerImpl { } } } else { + // send other command like cancel or done (??sends other commands like concede??) + + // auto-complete on all selected if (target.getTargets().size() >= target.getNumberOfTargets()) { return true; } - if (!target.isRequired(sourceId, game)) { + + // cancel/done button + if (!required) { return false; } - } } return false; @@ -496,6 +520,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { + // choose one or multiple targets updateGameStatePriority("chooseTarget", game); UUID abilityControllerId = playerId; if (target.getAbilityController() != null) { @@ -511,14 +536,18 @@ public class HumanPlayer extends PlayerImpl { prepareForResponse(game); if (!isExecutingMacro()) { + // hmm game.fireSelectTargetEvent(getId(), new MessageToClient(target.getMessage(), getRelatedObjectName(source, game)), possibleTargets, required, getOptions(target, null)); } waitForResponse(game); if (response.getUUID() != null) { + + // remove selected if (target.getTargets().contains(response.getUUID())) { target.remove(response.getUUID()); continue; } + if (possibleTargets.contains(response.getUUID())) { if (target.canTarget(abilityControllerId, response.getUUID(), source, game)) { target.addTarget(response.getUUID(), source, game); @@ -553,6 +582,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + // choose one or multiple cards if (cards == null) { return false; } @@ -610,6 +640,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { + // choose one or multiple target cards updateGameStatePriority("chooseTarget(5)", game); while (!abort) { boolean required; @@ -672,6 +703,7 @@ public class HumanPlayer extends PlayerImpl { @Override public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + // choose amount updateGameStatePriority("chooseTargetAmount", game); while (!abort) { prepareForResponse(game); @@ -707,6 +739,7 @@ public class HumanPlayer extends PlayerImpl { controllingPlayer = (HumanPlayer) player; } } + if (getJustActivatedType() != null && !holdingPriority) { if (controllingPlayer.getUserData().isPassPriorityCast() && getJustActivatedType() == AbilityType.SPELL) { @@ -721,43 +754,74 @@ public class HumanPlayer extends PlayerImpl { return false; } } - if (isGameUnderControl()) { // Use the skip actions only if the player itself controls its turn - if (passedAllTurns - || passedTurnSkipStack) { + + // STOP conditions (temporary stop without skip reset) + boolean quickStop = false; + if (isGameUnderControl()) { + + // if was attacked - always stop BEFORE blocker step (to cast extra spells) + if (game.getTurn().getStepType() == PhaseStep.DECLARE_ATTACKERS + && game.getCombat().getPlayerDefenders(game).contains(playerId)) { + + FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy(); + filter.add(new ControllerIdPredicate(playerId)); + // stop skip on any/zero permanents available + int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game); + boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents(); + boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents(); + quickStop = canStopOnAny || canStopOnZero; + } + } + + // SKIP - use the skip actions only if the player itself controls its turn + if (!quickStop && isGameUnderControl()) { + + if (passedAllTurns || passedTurnSkipStack) { if (passWithManaPoolCheck(game)) { return false; } } - if (passedUntilEndStepBeforeMyTurn) { + if (passedUntilEndStepBeforeMyTurn) { if (game.getTurn().getStepType() != PhaseStep.END_TURN) { + // other step if (passWithManaPoolCheck(game)) { return false; } } else { + // end step - search yourself PlayerList playerList = game.getState().getPlayerList(playerId); if (!playerList.getPrevious().equals(game.getActivePlayerId())) { if (passWithManaPoolCheck(game)) { return false; } + } else { + // stop + passedUntilEndStepBeforeMyTurn = false; } } } + if (game.getStack().isEmpty()) { + // empty stack + boolean dontCheckPassStep = false; if (passedUntilStackResolved) { // Don't skip to next step with this action. It always only resolves a stack. If stack is empty it does nothing. + passedUntilStackResolved = false; dontCheckPassStep = true; } + if (passedTurn || passedTurnSkipStack) { if (passWithManaPoolCheck(game)) { return false; } } + if (passedUntilNextMain) { if (game.getTurn().getStepType() == PhaseStep.POSTCOMBAT_MAIN || game.getTurn().getStepType() == PhaseStep.PRECOMBAT_MAIN) { - // it's a main phase + // it's main step if (!skippedAtLeastOnce || (!playerId.equals(game.getActivePlayerId()) && !controllingPlayer.getUserData().getUserSkipPrioritySteps().isStopOnAllMainPhases())) { @@ -776,22 +840,23 @@ public class HumanPlayer extends PlayerImpl { } } } + if (passedUntilEndOfTurn) { if (game.getTurn().getStepType() == PhaseStep.END_TURN) { - // It's end of turn phase + // it's end of turn step if (!skippedAtLeastOnce || (playerId.equals(game.getActivePlayerId()) && !controllingPlayer - .getUserData() - .getUserSkipPrioritySteps() - .isStopOnAllEndPhases())) { + .getUserData() + .getUserSkipPrioritySteps() + .isStopOnAllEndPhases())) { skippedAtLeastOnce = true; if (passWithManaPoolCheck(game)) { return false; } } else { dontCheckPassStep = true; - passedUntilEndOfTurn = false; + passedUntilEndOfTurn = false; // reset skip action } } else { skippedAtLeastOnce = true; @@ -800,23 +865,39 @@ public class HumanPlayer extends PlayerImpl { } } } + if (!dontCheckPassStep && checkPassStep(game, controllingPlayer)) { if (passWithManaPoolCheck(game)) { return false; } } - } else if (passedUntilStackResolved) { - if (Objects.equals(dateLastAddedToStack, game.getStack().getDateLastAdded())) { - dateLastAddedToStack = game.getStack().getDateLastAdded(); + + } else { + // non empty stack + boolean haveNewObjectsOnStack = !Objects.equals(dateLastAddedToStack, game.getStack().getDateLastAdded()); + dateLastAddedToStack = game.getStack().getDateLastAdded(); + if (passedUntilStackResolved) { + if (haveNewObjectsOnStack + && (playerId.equals(game.getActivePlayerId()) + && controllingPlayer + .getUserData() + .getUserSkipPrioritySteps() + .isStopOnStackNewObjects())) { + // new objects on stack -- disable "pass until stack resolved" + passedUntilStackResolved = false; + } else { + // no new objects on stack -- go to next priority + } + } + if (passedUntilStackResolved) { if (passWithManaPoolCheck(game)) { return false; } - } else { - passedUntilStackResolved = false; } } } + while (canRespond()) { updateGameStatePriority("priority", game); holdingPriority = false; @@ -853,32 +934,33 @@ public class HumanPlayer extends PlayerImpl { if (object != null) { Zone zone = game.getState().getZone(object.getId()); if (zone != null) { + // look at card or try to cast/activate abilities + Player actingPlayer = null; + LinkedHashMap useableAbilities = null; + if (playerId.equals(game.getPriorityPlayerId())) { + actingPlayer = this; + } else if (getPlayersUnderYourControl().contains(game.getPriorityPlayerId())) { + actingPlayer = game.getPlayer(game.getPriorityPlayerId()); + } + if (actingPlayer != null) { + useableAbilities = actingPlayer.getUseableActivatedAbilities(object, zone, game); + } + if (object instanceof Card && ((Card) object).isFaceDown(game) - && lookAtFaceDownCard((Card) object, game)) { + && lookAtFaceDownCard((Card) object, game, useableAbilities == null ? 0 : useableAbilities.size())) { result = true; } else { - Player actingPlayer = null; - if (playerId.equals(game.getPriorityPlayerId())) { - actingPlayer = this; - } else if (getPlayersUnderYourControl().contains(game.getPriorityPlayerId())) { - actingPlayer = game.getPlayer(game.getPriorityPlayerId()); - } - if (actingPlayer != null) { - LinkedHashMap useableAbilities = actingPlayer.getUseableActivatedAbilities(object, zone, game); - if (useableAbilities != null - && !useableAbilities.isEmpty()) { - activateAbility(useableAbilities, object, game); - result = true; - } + if (useableAbilities != null + && !useableAbilities.isEmpty()) { + activateAbility(useableAbilities, object, game); + result = true; } } } } return result; - } else if (response.getManaType() != null) { - return false; - } + } else return response.getManaType() == null; return true; } return false; @@ -914,6 +996,7 @@ public class HumanPlayer extends PlayerImpl { @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { + // choose triggered abilitity from list String autoOrderRuleText = null; boolean autoOrderUse = getControllingPlayersUserData(game).isAutoOrderTrigger(); while (!abort) { @@ -990,6 +1073,7 @@ public class HumanPlayer extends PlayerImpl { } protected boolean playManaHandling(Ability abilityToCast, ManaCost unpaid, String promptText, Game game) { + // choose mana to pay (from permanents or from pool) updateGameStatePriority("playMana", game); Map options = new HashMap<>(); prepareForResponse(game); @@ -1123,11 +1207,23 @@ public class HumanPlayer extends PlayerImpl { filter.add(new ControllerIdPredicate(attackingPlayerId)); while (!abort) { + + List possibleAttackers = new ArrayList<>(); + for (Permanent possibleAttacker : game.getBattlefield().getActivePermanents(filter, attackingPlayerId, game)) { + if (possibleAttacker.canAttack(null, game)) { + possibleAttackers.add(possibleAttacker.getId()); + } + } + + // skip declare attack step + // old version: + // - passedAllTurns, passedUntilEndStepBeforeMyTurn: always skipped + // - other: on disabled option skipped if (passedAllTurns || passedUntilEndStepBeforeMyTurn || (!getControllingPlayersUserData(game) - .getUserSkipPrioritySteps() - .isStopOnDeclareAttackersDuringSkipAction() + .getUserSkipPrioritySteps() + .isStopOnDeclareAttackers() && (passedTurn || passedTurnSkipStack || passedUntilEndOfTurn @@ -1136,17 +1232,24 @@ public class HumanPlayer extends PlayerImpl { return; } } - Map options = new HashMap<>(); - List possibleAttackers = new ArrayList<>(); - for (Permanent possibleAttacker : game.getBattlefield().getActivePermanents(filter, attackingPlayerId, game)) { - if (possibleAttacker.canAttack(null, game)) { - possibleAttackers.add(possibleAttacker.getId()); + /* + // new version: + // - all: on disabled option skipped (if attackers selected) + if (!getControllingPlayersUserData(game) + .getUserSkipPrioritySteps() + .isStopOnDeclareAttackers() + && (possibleAttackers.size() > 0)) { + if (checkIfAttackersValid(game)) { + return; } } + */ + + Map options = new HashMap<>(); options.put(Constants.Option.POSSIBLE_ATTACKERS, (Serializable) possibleAttackers); if (!possibleAttackers.isEmpty()) { - options.put(Constants.Option.SPECIAL_BUTTON, (Serializable) "All attack"); + options.put(Constants.Option.SPECIAL_BUTTON, "All attack"); } prepareForResponse(game); @@ -1304,7 +1407,7 @@ public class HumanPlayer extends PlayerImpl { /** * Selects a defender for an attacker and adds the attacker to combat * - * @param defenders - list of possible defender + * @param defenders - list of possible defender * @param attackerId - UUID of attacker * @param game * @return @@ -1362,16 +1465,24 @@ public class HumanPlayer extends PlayerImpl { updateGameStatePriority("selectBlockers", game); FilterCreatureForCombatBlock filter = filterCreatureForCombatBlock.copy(); filter.add(new ControllerIdPredicate(defendingPlayerId)); - if (game.getBattlefield().count(filter, null, playerId, game) == 0 - && !getControllingPlayersUserData(game) - .getUserSkipPrioritySteps() - .isStopOnDeclareBlockerIfNoneAvailable()) { + + // stop skip on any/zero permanents available + int possibleBlockersCount = game.getBattlefield().count(filter, null, playerId, game); + boolean canStopOnAny = possibleBlockersCount != 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithAnyPermanents(); + boolean canStopOnZero = possibleBlockersCount == 0 && getControllingPlayersUserData(game).getUserSkipPrioritySteps().isStopOnDeclareBlockersWithZeroPermanents(); + if (!canStopOnAny && !canStopOnZero) { return; } + while (!abort) { prepareForResponse(game); if (!isExecutingMacro()) { - game.fireSelectEvent(playerId, "Select blockers"); + Map options = new HashMap<>(); + List possibleBlockers = game.getBattlefield().getActivePermanents(filter, playerId, game).stream() + .map(p -> p.getId()) + .collect(Collectors.toList()); + options.put(Constants.Option.POSSIBLE_BLOCKERS, (Serializable) possibleBlockers); + game.fireSelectEvent(playerId, "Select blockers", options); } waitForResponse(game); if (response.getBoolean() != null) { @@ -1443,9 +1554,21 @@ public class HumanPlayer extends PlayerImpl { TargetAttackingCreature target = new TargetAttackingCreature(); prepareForResponse(game); if (!isExecutingMacro()) { + // possible attackers to block + Set attackers = target.possibleTargets(null, playerId, game); + Permanent blocker = game.getPermanent(blockerId); + Set possibleTargets = new HashSet<>(); + for (UUID attackerId : attackers) { + CombatGroup group = game.getCombat().findGroup(attackerId); + if (group != null && blocker != null && group.canBlock(blocker, game)) { + possibleTargets.add(attackerId); + } + } + game.fireSelectTargetEvent(playerId, new MessageToClient("Select attacker to block", getRelatedObjectName(blockerId, game)), - target.possibleTargets(null, playerId, game), false, getOptions(target, null)); + possibleTargets, false, getOptions(target, null)); } + waitForResponse(game); if (response.getBoolean() != null) { // do nothing @@ -1650,6 +1773,7 @@ public class HumanPlayer extends PlayerImpl { @Override public Mode chooseMode(Modes modes, Ability source, Game game) { + // choose mode to activate updateGameStatePriority("chooseMode", game); if (modes.size() > 1) { MageObject obj = game.getObject(source.getSourceId()); diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml index f3cecab6e5..e3acf90a53 100644 --- a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-tournament-boosterdraft @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/ScgConCube2018December.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/ScgConCube2018December.java new file mode 100644 index 0000000000..424e09eae4 --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/ScgConCube2018December.java @@ -0,0 +1,375 @@ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * + * @author PirateHunter + */ +public class ScgConCube2018December extends DraftCube { + + public ScgConCube2018December() { + super("SCG Con Cube 2018 December"); + + cubeCards.add(new DraftCube.CardIdentity("Dauntless Bodyguard", "")); + cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", "")); + cubeCards.add(new DraftCube.CardIdentity("Mardu Woe-Reaper", "")); + cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", "")); + cubeCards.add(new DraftCube.CardIdentity("Skymarcher Aspirant", "")); + cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", "")); + cubeCards.add(new DraftCube.CardIdentity("Thraben Inspector", "")); + cubeCards.add(new DraftCube.CardIdentity("Toolcraft Exemplar", "")); + cubeCards.add(new DraftCube.CardIdentity("Accorder Paladin", "")); + cubeCards.add(new DraftCube.CardIdentity("Adanto Vanguard", "")); + cubeCards.add(new DraftCube.CardIdentity("Containment Priest", "")); + cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", "")); + cubeCards.add(new DraftCube.CardIdentity("Remorseful Cleric", "")); + cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", "")); + cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", "")); + cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Heretic Cathar", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", "")); + cubeCards.add(new DraftCube.CardIdentity("Palace Jailer", "")); + cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Invention", "")); + cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Sun Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new DraftCube.CardIdentity("Path to Exile", "")); + cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", "")); + cubeCards.add(new DraftCube.CardIdentity("Disenchant", "")); + cubeCards.add(new DraftCube.CardIdentity("Secure the Wastes", "")); + cubeCards.add(new DraftCube.CardIdentity("Balance", "")); + cubeCards.add(new DraftCube.CardIdentity("Declaration in Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", "")); + cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", "")); + cubeCards.add(new DraftCube.CardIdentity("Armageddon", "")); + cubeCards.add(new DraftCube.CardIdentity("Ravages of War", "")); + cubeCards.add(new DraftCube.CardIdentity("Wrath of God", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminus", "")); + cubeCards.add(new DraftCube.CardIdentity("Intangible Virtue", "")); + cubeCards.add(new DraftCube.CardIdentity("Journey to Nowhere", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Conclave Tribunal", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", "")); + cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", "")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", "")); + cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Champion of Wits", "")); + cubeCards.add(new DraftCube.CardIdentity("Man-o'-War", "")); + cubeCards.add(new DraftCube.CardIdentity("Nimble Obstructionist", "")); + cubeCards.add(new DraftCube.CardIdentity("Sea Gate Oracle", "")); + cubeCards.add(new DraftCube.CardIdentity("Spellseeker", "")); + cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", "")); + cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Whirler Rogue", "")); + cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Aetherling", "")); + cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", "")); + cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", "")); + cubeCards.add(new DraftCube.CardIdentity("Brainstorm", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", "")); + cubeCards.add(new DraftCube.CardIdentity("Counterspell", "")); + cubeCards.add(new DraftCube.CardIdentity("Impulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Jilt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Drain", "")); + cubeCards.add(new DraftCube.CardIdentity("Remand", "")); + cubeCards.add(new DraftCube.CardIdentity("Forbid", "")); + cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", "")); + cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", "")); + cubeCards.add(new DraftCube.CardIdentity("Force of Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Condescend", "")); + cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Walk", "")); + cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", "")); + cubeCards.add(new DraftCube.CardIdentity("Tinker", "")); + cubeCards.add(new DraftCube.CardIdentity("Bribery", "")); + cubeCards.add(new DraftCube.CardIdentity("Upheaval", "")); + cubeCards.add(new DraftCube.CardIdentity("Search for Azcanta", "")); + cubeCards.add(new DraftCube.CardIdentity("Opposition", "")); + cubeCards.add(new DraftCube.CardIdentity("Treachery", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Artist", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodghast", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", "")); + cubeCards.add(new DraftCube.CardIdentity("Pack Rat", "")); + cubeCards.add(new DraftCube.CardIdentity("Zulaport Cutthroat", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, Heretical Healer", "")); + cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Plaguecrafter", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", "")); + cubeCards.add(new DraftCube.CardIdentity("Braids, Cabal Minion", "")); + cubeCards.add(new DraftCube.CardIdentity("Kalitas, Traitor of Ghet", "")); + cubeCards.add(new DraftCube.CardIdentity("Ravenous Chupacabra", "")); + cubeCards.add(new DraftCube.CardIdentity("Custodi Lich", "")); + cubeCards.add(new DraftCube.CardIdentity("Doom Whisperer", "")); + cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", "")); + cubeCards.add(new DraftCube.CardIdentity("Grave Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Griselbrand", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, the Last Hope", "")); + cubeCards.add(new DraftCube.CardIdentity("Entomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Fatal Push", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampiric Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Diabolic Edict", "")); + cubeCards.add(new DraftCube.CardIdentity("Doom Blade", "")); + cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", "")); + cubeCards.add(new DraftCube.CardIdentity("Dismember", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", "")); + cubeCards.add(new DraftCube.CardIdentity("Duress", "")); + cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", "")); + cubeCards.add(new DraftCube.CardIdentity("Reanimate", "")); + cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", "")); + cubeCards.add(new DraftCube.CardIdentity("Collective Brutality", "")); + cubeCards.add(new DraftCube.CardIdentity("Demonic Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Exhume", "")); + cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", "")); + cubeCards.add(new DraftCube.CardIdentity("Damnation", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind Twist", "")); + cubeCards.add(new DraftCube.CardIdentity("Animate Dead", "")); + cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", "")); + cubeCards.add(new DraftCube.CardIdentity("Necromancy", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena", "")); + cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "")); + cubeCards.add(new DraftCube.CardIdentity("Soul-Scar Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", "")); + cubeCards.add(new DraftCube.CardIdentity("Earthshaker Khenra", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Cratermaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Hellspark Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Kari Zev, Skyship Raider", "")); + cubeCards.add(new DraftCube.CardIdentity("Mogg War Marshal", "")); + cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Legion Warboss", "")); + cubeCards.add(new DraftCube.CardIdentity("Rampaging Ferocidon", "")); + cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", "")); + cubeCards.add(new DraftCube.CardIdentity("Hazoret the Fervent", "")); + cubeCards.add(new DraftCube.CardIdentity("Hellrider", "")); + cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar", "")); + cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", "")); + cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", "")); + cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", "")); + cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Dead // Gone", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Abrade", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", "")); + cubeCards.add(new DraftCube.CardIdentity("Incinerate", "")); + cubeCards.add(new DraftCube.CardIdentity("Smash to Smithereens", "")); + cubeCards.add(new DraftCube.CardIdentity("Risk Factor", "")); + cubeCards.add(new DraftCube.CardIdentity("Fireblast", "")); + cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", "")); + cubeCards.add(new DraftCube.CardIdentity("Firebolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Arc Trail", "")); + cubeCards.add(new DraftCube.CardIdentity("Molten Rain", "")); + cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Burning of Xinye", "")); + cubeCards.add(new DraftCube.CardIdentity("Wildfire", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Bombardment", "")); + cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", "")); + cubeCards.add(new DraftCube.CardIdentity("Experimental Frenzy", "")); + cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", "")); + cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Duskwatch Recruiter", "")); + cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", "")); + cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", "")); + cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", "")); + cubeCards.add(new DraftCube.CardIdentity("Tarmogoyf", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", "")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", "")); + cubeCards.add(new DraftCube.CardIdentity("Manglehorn", "")); + cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tireless Tracker", "")); + cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", "")); + cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", "")); + cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", "")); + cubeCards.add(new DraftCube.CardIdentity("Thragtusk", "")); + cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Hornet Queen", "")); + cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Beast Within", "")); + cubeCards.add(new DraftCube.CardIdentity("Farseek", "")); + cubeCards.add(new DraftCube.CardIdentity("Cultivate", "")); + cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach", "")); + cubeCards.add(new DraftCube.CardIdentity("Natural Order", "")); + cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", "")); + cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", "")); + cubeCards.add(new DraftCube.CardIdentity("Fastbond", "")); + cubeCards.add(new DraftCube.CardIdentity("Survival of the Fittest", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", "")); + cubeCards.add(new DraftCube.CardIdentity("Song of the Dryads", "")); + cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", "")); + cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Queller", "")); + cubeCards.add(new DraftCube.CardIdentity("Teferi, Hero of Dominaria", "")); + cubeCards.add(new DraftCube.CardIdentity("Fractured Identity", "")); + cubeCards.add(new DraftCube.CardIdentity("The Scarab God", "")); + cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", "")); + cubeCards.add(new DraftCube.CardIdentity("Agony Warp", "")); + cubeCards.add(new DraftCube.CardIdentity("Daretti, Ingenious Iconoclast", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminate", "")); + cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Dreadbore", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", "")); + cubeCards.add(new DraftCube.CardIdentity("Gaddock Teeg", "")); + cubeCards.add(new DraftCube.CardIdentity("Qasali Pridemage", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", "")); + cubeCards.add(new DraftCube.CardIdentity("Knight of Autumn", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Dromoka", "")); + cubeCards.add(new DraftCube.CardIdentity("March of the Multitudes", "")); + cubeCards.add(new DraftCube.CardIdentity("Kambal, Consul of Allocation", "")); + cubeCards.add(new DraftCube.CardIdentity("Sorin, Solemn Visitor", "")); + cubeCards.add(new DraftCube.CardIdentity("Vindicate", "")); + cubeCards.add(new DraftCube.CardIdentity("Deathrite Shaman", "")); + cubeCards.add(new DraftCube.CardIdentity("Assassin's Trophy", "")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Coiling Oracle", "")); + cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Steward of Elements", "")); + cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", "")); + cubeCards.add(new DraftCube.CardIdentity("Electrolyze", "")); + cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", "")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", "")); + cubeCards.add(new DraftCube.CardIdentity("Wear // Tear", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn, Scion of Urza", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", "")); + cubeCards.add(new DraftCube.CardIdentity("Bomat Courier", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrapheap Scrounger", "")); + cubeCards.add(new DraftCube.CardIdentity("Spellskite", "")); + cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", "")); + cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", "")); + cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", "")); + cubeCards.add(new DraftCube.CardIdentity("Walking Ballista", "")); + cubeCards.add(new DraftCube.CardIdentity("Black Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonesplitter", "")); + cubeCards.add(new DraftCube.CardIdentity("Cursed Scroll", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Vault", "")); + cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", "")); + cubeCards.add(new DraftCube.CardIdentity("Skullclamp", "")); + cubeCards.add(new DraftCube.CardIdentity("Sol Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Ankh of Mishra", "")); + cubeCards.add(new DraftCube.CardIdentity("Azorius Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Dimir Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Gruul Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", "")); + cubeCards.add(new DraftCube.CardIdentity("Orzhov Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Simic Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", "")); + cubeCards.add(new DraftCube.CardIdentity("Sorcerous Spyglass", "")); + cubeCards.add(new DraftCube.CardIdentity("Thorn of Amethyst", "")); + cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", "")); + cubeCards.add(new DraftCube.CardIdentity("Winter Orb", "")); + cubeCards.add(new DraftCube.CardIdentity("Crucible of Worlds", "")); + cubeCards.add(new DraftCube.CardIdentity("Dimir Keyrune", "")); + cubeCards.add(new DraftCube.CardIdentity("Grafted Wargear", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Light and Shadow", "")); + cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", "")); + cubeCards.add(new DraftCube.CardIdentity("Vedalken Shackles", "")); + cubeCards.add(new DraftCube.CardIdentity("Smokestack", "")); + cubeCards.add(new DraftCube.CardIdentity("Batterskull", "")); + cubeCards.add(new DraftCube.CardIdentity("Engineered Explosives", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", "")); + cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", "")); + cubeCards.add(new DraftCube.CardIdentity("Badlands", "")); + cubeCards.add(new DraftCube.CardIdentity("Bayou", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", "")); + cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", "")); + cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", "")); + cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", "")); + cubeCards.add(new DraftCube.CardIdentity("Field of Ruin", "")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", "")); + cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", "")); + cubeCards.add(new DraftCube.CardIdentity("Gavony Township", "")); + cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", "")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", "")); + cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", "")); + cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", "")); + cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", "")); + cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", "")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", "")); + cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", "")); + cubeCards.add(new DraftCube.CardIdentity("Mutavault", "")); + cubeCards.add(new DraftCube.CardIdentity("Needle Spires", "")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Plateau", "")); + cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", "")); + cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", "")); + cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", "")); + cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", "")); + cubeCards.add(new DraftCube.CardIdentity("Savannah", "")); + cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrubland", "")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", "")); + cubeCards.add(new DraftCube.CardIdentity("Steam Vents", "")); + cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", "")); + cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", "")); + cubeCards.add(new DraftCube.CardIdentity("Strip Mine", "")); + cubeCards.add(new DraftCube.CardIdentity("Taiga", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple Garden", "")); + cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", "")); + cubeCards.add(new DraftCube.CardIdentity("Treetop Village", "")); + cubeCards.add(new DraftCube.CardIdentity("Tropical Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Tundra", "")); + cubeCards.add(new DraftCube.CardIdentity("Underground Sea", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", "")); + cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", "")); + cubeCards.add(new DraftCube.CardIdentity("Wasteland", "")); + cubeCards.add(new DraftCube.CardIdentity("Watery Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", "")); + cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", "")); + } +} diff --git a/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeDecember2018.java b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeDecember2018.java new file mode 100644 index 0000000000..f967f960fb --- /dev/null +++ b/Mage.Server.Plugins/Mage.Tournament.BoosterDraft/src/mage/tournament/cubes/VintageCubeDecember2018.java @@ -0,0 +1,556 @@ +package mage.tournament.cubes; + +import mage.game.draft.DraftCube; + +/** + * + * @author themogwi + */ +public class VintageCubeDecember2018 extends DraftCube { + + public VintageCubeDecember2018() { + super("MTGO Vintage Cube December 2018"); + + cubeCards.add(new DraftCube.CardIdentity("Dauntless Bodyguard", "")); + cubeCards.add(new DraftCube.CardIdentity("Kytheon, Hero of Akros", "")); + cubeCards.add(new DraftCube.CardIdentity("Mother of Runes", "")); + cubeCards.add(new DraftCube.CardIdentity("Student of Warfare", "")); + cubeCards.add(new DraftCube.CardIdentity("Adanto Vanguard", "")); + cubeCards.add(new DraftCube.CardIdentity("Leonin Relic-Warder", "")); + cubeCards.add(new DraftCube.CardIdentity("Remorseful Cleric", "")); + cubeCards.add(new DraftCube.CardIdentity("Selfless Spirit", "")); + cubeCards.add(new DraftCube.CardIdentity("Soulfire Grand Master", "")); + cubeCards.add(new DraftCube.CardIdentity("Stoneforge Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Thalia, Guardian of Thraben", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Omens", "")); + cubeCards.add(new DraftCube.CardIdentity("Banisher Priest", "")); + cubeCards.add(new DraftCube.CardIdentity("Blade Splicer", "")); + cubeCards.add(new DraftCube.CardIdentity("Brightling", "")); + cubeCards.add(new DraftCube.CardIdentity("Brimaz, King of Oreskos", "")); + cubeCards.add(new DraftCube.CardIdentity("Flickerwisp", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirran Crusader", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Mentor", "")); + cubeCards.add(new DraftCube.CardIdentity("Recruiter of the Guard", "")); + cubeCards.add(new DraftCube.CardIdentity("Silverblade Paladin", "")); + cubeCards.add(new DraftCube.CardIdentity("Emeria Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero of Bladehold", "")); + cubeCards.add(new DraftCube.CardIdentity("Linvala, Keeper of Silence", "")); + cubeCards.add(new DraftCube.CardIdentity("Palace Jailer", "")); + cubeCards.add(new DraftCube.CardIdentity("Restoration Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Invention", "")); + cubeCards.add(new DraftCube.CardIdentity("Angel of Sanctions", "")); + cubeCards.add(new DraftCube.CardIdentity("Archangel Avacyn", "")); + cubeCards.add(new DraftCube.CardIdentity("Baneslayer Angel", "")); + cubeCards.add(new DraftCube.CardIdentity("Lyra Dawnbringer", "")); + cubeCards.add(new DraftCube.CardIdentity("Reveillark", "")); + cubeCards.add(new DraftCube.CardIdentity("Sun Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Elesh Norn, Grand Cenobite", "")); + cubeCards.add(new DraftCube.CardIdentity("Avacyn, Angel of Hope", "")); + cubeCards.add(new DraftCube.CardIdentity("Iona, Shield of Emeria", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon of the Trials", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Knight-Errant", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon, Ally of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Gideon Jura", "")); + cubeCards.add(new DraftCube.CardIdentity("Elspeth, Sun's Champion", "")); + cubeCards.add(new DraftCube.CardIdentity("Porcelain Legionnaire", "")); + cubeCards.add(new DraftCube.CardIdentity("Condemn", "")); + cubeCards.add(new DraftCube.CardIdentity("Enlightened Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Tithe", "")); + cubeCards.add(new DraftCube.CardIdentity("Path to Exile", "")); + cubeCards.add(new DraftCube.CardIdentity("Swords to Plowshares", "")); + cubeCards.add(new DraftCube.CardIdentity("Disenchant", "")); + cubeCards.add(new DraftCube.CardIdentity("Unexpectedly Absent", "")); + cubeCards.add(new DraftCube.CardIdentity("Balance", "")); + cubeCards.add(new DraftCube.CardIdentity("Council's Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Lingering Souls", "")); + cubeCards.add(new DraftCube.CardIdentity("Spectral Procession", "")); + cubeCards.add(new DraftCube.CardIdentity("Timely Reinforcements", "")); + cubeCards.add(new DraftCube.CardIdentity("Armageddon", "")); + cubeCards.add(new DraftCube.CardIdentity("Day of Judgment", "")); + cubeCards.add(new DraftCube.CardIdentity("Ravages of War", "")); + cubeCards.add(new DraftCube.CardIdentity("Wrath of God", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminus", "")); + cubeCards.add(new DraftCube.CardIdentity("Land Tax", "")); + cubeCards.add(new DraftCube.CardIdentity("Legion's Landing", "")); + cubeCards.add(new DraftCube.CardIdentity("Honor of the Pure", "")); + cubeCards.add(new DraftCube.CardIdentity("Banishing Light", "")); + cubeCards.add(new DraftCube.CardIdentity("History of Benalia", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Faith's Fetters", "")); + cubeCards.add(new DraftCube.CardIdentity("Moat", "")); + cubeCards.add(new DraftCube.CardIdentity("Parallax Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Spear of Heliod", "")); + cubeCards.add(new DraftCube.CardIdentity("Karakas", "")); + cubeCards.add(new DraftCube.CardIdentity("Baral, Chief of Compliance", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Vryn's Prodigy", "")); + cubeCards.add(new DraftCube.CardIdentity("Looter il-Kor", "")); + cubeCards.add(new DraftCube.CardIdentity("Phantasmal Image", "")); + cubeCards.add(new DraftCube.CardIdentity("Snapcaster Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("Thing in the Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Arcane Artisan", "")); + cubeCards.add(new DraftCube.CardIdentity("Deceiver Exarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Pestermite", "")); + cubeCards.add(new DraftCube.CardIdentity("Trinket Mage", "")); + cubeCards.add(new DraftCube.CardIdentity("True-Name Nemesis", "")); + cubeCards.add(new DraftCube.CardIdentity("Vendilion Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Glen Elendra Archmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Sower of Temptation", "")); + cubeCards.add(new DraftCube.CardIdentity("Venser, Shaper Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Mulldrifter", "")); + cubeCards.add(new DraftCube.CardIdentity("Riftwing Cloudskate", "")); + cubeCards.add(new DraftCube.CardIdentity("Consecrated Sphinx", "")); + cubeCards.add(new DraftCube.CardIdentity("Frost Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Palinchron", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace Beleren", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, Architect of Thought", "")); + cubeCards.add(new DraftCube.CardIdentity("Jace, the Mind Sculptor", "")); + cubeCards.add(new DraftCube.CardIdentity("Tamiyo, the Moon Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tezzeret the Seeker", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Metamorph", "")); + cubeCards.add(new DraftCube.CardIdentity("Torrential Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Inkwell Leviathan", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Recall", "")); + cubeCards.add(new DraftCube.CardIdentity("Brainstorm", "")); + cubeCards.add(new DraftCube.CardIdentity("High Tide", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystical Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Pierce", "")); + cubeCards.add(new DraftCube.CardIdentity("Blink of an Eye", "")); + cubeCards.add(new DraftCube.CardIdentity("Brain Freeze", "")); + cubeCards.add(new DraftCube.CardIdentity("Counterspell", "")); + cubeCards.add(new DraftCube.CardIdentity("Daze", "")); + cubeCards.add(new DraftCube.CardIdentity("Impulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Drain", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Leak", "")); + cubeCards.add(new DraftCube.CardIdentity("Remand", "")); + cubeCards.add(new DraftCube.CardIdentity("Disallow", "")); + cubeCards.add(new DraftCube.CardIdentity("Frantic Search", "")); + cubeCards.add(new DraftCube.CardIdentity("Thirst for Knowledge", "")); + cubeCards.add(new DraftCube.CardIdentity("Cryptic Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Fact or Fiction", "")); + cubeCards.add(new DraftCube.CardIdentity("Gifts Ungiven", "")); + cubeCards.add(new DraftCube.CardIdentity("Turnabout", "")); + cubeCards.add(new DraftCube.CardIdentity("Force of Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Gush", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Repeal", "")); + cubeCards.add(new DraftCube.CardIdentity("Nexus of Fate", "")); + cubeCards.add(new DraftCube.CardIdentity("Dig Through Time", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancestral Vision", "")); + cubeCards.add(new DraftCube.CardIdentity("Gitaxian Probe", "")); + cubeCards.add(new DraftCube.CardIdentity("Ponder", "")); + cubeCards.add(new DraftCube.CardIdentity("Preordain", "")); + cubeCards.add(new DraftCube.CardIdentity("Chart a Course", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Walk", "")); + cubeCards.add(new DraftCube.CardIdentity("Compulsive Research", "")); + cubeCards.add(new DraftCube.CardIdentity("Show and Tell", "")); + cubeCards.add(new DraftCube.CardIdentity("Timetwister", "")); + cubeCards.add(new DraftCube.CardIdentity("Tinker", "")); + cubeCards.add(new DraftCube.CardIdentity("Bribery", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind's Desire", "")); + cubeCards.add(new DraftCube.CardIdentity("Time Spiral", "")); + cubeCards.add(new DraftCube.CardIdentity("Upheaval", "")); + cubeCards.add(new DraftCube.CardIdentity("Treasure Cruise", "")); + cubeCards.add(new DraftCube.CardIdentity("Search for Azcanta", "")); + cubeCards.add(new DraftCube.CardIdentity("Control Magic", "")); + cubeCards.add(new DraftCube.CardIdentity("Opposition", "")); + cubeCards.add(new DraftCube.CardIdentity("Treachery", "")); + cubeCards.add(new DraftCube.CardIdentity("Shelldock Isle", "")); + cubeCards.add(new DraftCube.CardIdentity("Tolarian Academy", "")); + cubeCards.add(new DraftCube.CardIdentity("Putrid Imp", "")); + cubeCards.add(new DraftCube.CardIdentity("Brain Maggot", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Confidant", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitesail Freebooter", "")); + cubeCards.add(new DraftCube.CardIdentity("Mesmeric Fiend", "")); + cubeCards.add(new DraftCube.CardIdentity("Oona's Prowler", "")); + cubeCards.add(new DraftCube.CardIdentity("Pack Rat", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrapheap Scrounger", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Hexmage", "")); + cubeCards.add(new DraftCube.CardIdentity("Bone Shredder", "")); + cubeCards.add(new DraftCube.CardIdentity("Hypnotic Specter", "")); + cubeCards.add(new DraftCube.CardIdentity("Ophiomancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampire Nighthawk", "")); + cubeCards.add(new DraftCube.CardIdentity("Gonti, Lord of Luxury", "")); + cubeCards.add(new DraftCube.CardIdentity("Nekrataal", "")); + cubeCards.add(new DraftCube.CardIdentity("Ravenous Chupacabra", "")); + cubeCards.add(new DraftCube.CardIdentity("Doom Whisperer", "")); + cubeCards.add(new DraftCube.CardIdentity("Puppeteer Clique", "")); + cubeCards.add(new DraftCube.CardIdentity("Shriekmaw", "")); + cubeCards.add(new DraftCube.CardIdentity("Demonlord Belzenlok", "")); + cubeCards.add(new DraftCube.CardIdentity("Grave Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Massacre Wurm", "")); + cubeCards.add(new DraftCube.CardIdentity("Tasigur, the Golden Fang", "")); + cubeCards.add(new DraftCube.CardIdentity("Sheoldred, Whispering One", "")); + cubeCards.add(new DraftCube.CardIdentity("Griselbrand", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana of the Veil", "")); + cubeCards.add(new DraftCube.CardIdentity("Liliana, Death's Majesty", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Entomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Fatal Push", "")); + cubeCards.add(new DraftCube.CardIdentity("Vampiric Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Cabal Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Cast Down", "")); + cubeCards.add(new DraftCube.CardIdentity("Go for the Throat", "")); + cubeCards.add(new DraftCube.CardIdentity("Shallow Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Ultimate Price", "")); + cubeCards.add(new DraftCube.CardIdentity("Corpse Dance", "")); + cubeCards.add(new DraftCube.CardIdentity("Dismember", "")); + cubeCards.add(new DraftCube.CardIdentity("Hero's Downfall", "")); + cubeCards.add(new DraftCube.CardIdentity("Makeshift Mannequin", "")); + cubeCards.add(new DraftCube.CardIdentity("Vraska's Contempt", "")); + cubeCards.add(new DraftCube.CardIdentity("Duress", "")); + cubeCards.add(new DraftCube.CardIdentity("Imperial Seal", "")); + cubeCards.add(new DraftCube.CardIdentity("Inquisition of Kozilek", "")); + cubeCards.add(new DraftCube.CardIdentity("Reanimate", "")); + cubeCards.add(new DraftCube.CardIdentity("Thoughtseize", "")); + cubeCards.add(new DraftCube.CardIdentity("Collective Brutality", "")); + cubeCards.add(new DraftCube.CardIdentity("Demonic Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Exhume", "")); + cubeCards.add(new DraftCube.CardIdentity("Hymn to Tourach", "")); + cubeCards.add(new DraftCube.CardIdentity("Night's Whisper", "")); + cubeCards.add(new DraftCube.CardIdentity("Buried Alive", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Tutor", "")); + cubeCards.add(new DraftCube.CardIdentity("Toxic Deluge", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Will", "")); + cubeCards.add(new DraftCube.CardIdentity("Damnation", "")); + cubeCards.add(new DraftCube.CardIdentity("Languish", "")); + cubeCards.add(new DraftCube.CardIdentity("Tendrils of Agony", "")); + cubeCards.add(new DraftCube.CardIdentity("Dark Petition", "")); + cubeCards.add(new DraftCube.CardIdentity("Living Death", "")); + cubeCards.add(new DraftCube.CardIdentity("Unburial Rites", "")); + cubeCards.add(new DraftCube.CardIdentity("Mind Twist", "")); + cubeCards.add(new DraftCube.CardIdentity("Animate Dead", "")); + cubeCards.add(new DraftCube.CardIdentity("Arguel's Blood Fast", "")); + cubeCards.add(new DraftCube.CardIdentity("Bitterblossom", "")); + cubeCards.add(new DraftCube.CardIdentity("Necromancy", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Arena", "")); + cubeCards.add(new DraftCube.CardIdentity("Recurring Nightmare", "")); + cubeCards.add(new DraftCube.CardIdentity("Yawgmoth's Bargain", "")); + cubeCards.add(new DraftCube.CardIdentity("Urborg, Tomb of Yawgmoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Firedrinker Satyr", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Guide", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Welder", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Lavamancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Jackal Pup", "")); + cubeCards.add(new DraftCube.CardIdentity("Monastery Swiftspear", "")); + cubeCards.add(new DraftCube.CardIdentity("Zurgo Bellstriker", "")); + cubeCards.add(new DraftCube.CardIdentity("Abbot of Keral Keep", "")); + cubeCards.add(new DraftCube.CardIdentity("Dire Fleet Daredevil", "")); + cubeCards.add(new DraftCube.CardIdentity("Eidolon of the Great Revel", "")); + cubeCards.add(new DraftCube.CardIdentity("Runaway Steam-Kin", "")); + cubeCards.add(new DraftCube.CardIdentity("Young Pyromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Rabblemaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Imperial Recruiter", "")); + cubeCards.add(new DraftCube.CardIdentity("Magus of the Moon", "")); + cubeCards.add(new DraftCube.CardIdentity("Manic Vandal", "")); + cubeCards.add(new DraftCube.CardIdentity("Pia Nalaar", "")); + cubeCards.add(new DraftCube.CardIdentity("Avalanche Riders", "")); + cubeCards.add(new DraftCube.CardIdentity("Flametongue Kavu", "")); + cubeCards.add(new DraftCube.CardIdentity("Hazoret the Fervent", "")); + cubeCards.add(new DraftCube.CardIdentity("Hellrider", "")); + cubeCards.add(new DraftCube.CardIdentity("Pia and Kiran Nalaar", "")); + cubeCards.add(new DraftCube.CardIdentity("Rekindling Phoenix", "")); + cubeCards.add(new DraftCube.CardIdentity("Glorybringer", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Dark-Dwellers", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiki-Jiki, Mirror Breaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Siege-Gang Commander", "")); + cubeCards.add(new DraftCube.CardIdentity("Thundermaw Hellkite", "")); + cubeCards.add(new DraftCube.CardIdentity("Zealous Conscripts", "")); + cubeCards.add(new DraftCube.CardIdentity("Inferno Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Torch of Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Daretti, Scrap Savant", "")); + cubeCards.add(new DraftCube.CardIdentity("Koth of the Hammer", "")); + cubeCards.add(new DraftCube.CardIdentity("Chandra, Flamecaller", "")); + cubeCards.add(new DraftCube.CardIdentity("Burst Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Bolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Abrade", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Grudge", "")); + cubeCards.add(new DraftCube.CardIdentity("Desperate Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Incinerate", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Strike", "")); + cubeCards.add(new DraftCube.CardIdentity("Magma Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Pyretic Ritual", "")); + cubeCards.add(new DraftCube.CardIdentity("Char", "")); + cubeCards.add(new DraftCube.CardIdentity("Seething Song", "")); + cubeCards.add(new DraftCube.CardIdentity("Through the Breach", "")); + cubeCards.add(new DraftCube.CardIdentity("Fireblast", "")); + cubeCards.add(new DraftCube.CardIdentity("Chain Lightning", "")); + cubeCards.add(new DraftCube.CardIdentity("Faithless Looting", "")); + cubeCards.add(new DraftCube.CardIdentity("Firebolt", "")); + cubeCards.add(new DraftCube.CardIdentity("Flame Slash", "")); + cubeCards.add(new DraftCube.CardIdentity("Mizzium Mortars", "")); + cubeCards.add(new DraftCube.CardIdentity("Pyroclasm", "")); + cubeCards.add(new DraftCube.CardIdentity("Collective Defiance", "")); + cubeCards.add(new DraftCube.CardIdentity("Sweltering Suns", "")); + cubeCards.add(new DraftCube.CardIdentity("Wheel of Fortune", "")); + cubeCards.add(new DraftCube.CardIdentity("Empty the Warrens", "")); + cubeCards.add(new DraftCube.CardIdentity("Fiery Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Burning of Xinye", "")); + cubeCards.add(new DraftCube.CardIdentity("Wildfire", "")); + cubeCards.add(new DraftCube.CardIdentity("Bonfire of the Damned", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Flare", "")); + cubeCards.add(new DraftCube.CardIdentity("Sulfuric Vortex", "")); + cubeCards.add(new DraftCube.CardIdentity("Experimental Frenzy", "")); + cubeCards.add(new DraftCube.CardIdentity("Sneak Attack", "")); + cubeCards.add(new DraftCube.CardIdentity("Splinter Twin", "")); + cubeCards.add(new DraftCube.CardIdentity("Arbor Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Avacyn's Pilgrim", "")); + cubeCards.add(new DraftCube.CardIdentity("Birds of Paradise", "")); + cubeCards.add(new DraftCube.CardIdentity("Elves of Deep Shadow", "")); + cubeCards.add(new DraftCube.CardIdentity("Elvish Mystic", "")); + cubeCards.add(new DraftCube.CardIdentity("Fyndhorn Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Joraga Treespeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Llanowar Elves", "")); + cubeCards.add(new DraftCube.CardIdentity("Noble Hierarch", "")); + cubeCards.add(new DraftCube.CardIdentity("Devoted Druid", "")); + cubeCards.add(new DraftCube.CardIdentity("Fauna Shaman", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Cobra", "")); + cubeCards.add(new DraftCube.CardIdentity("Rofellos, Llanowar Emissary", "")); + cubeCards.add(new DraftCube.CardIdentity("Sakura-Tribe Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Scavenging Ooze", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Caryatid", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Blossoms", "")); + cubeCards.add(new DraftCube.CardIdentity("Wall of Roots", "")); + cubeCards.add(new DraftCube.CardIdentity("Courser of Kruphix", "")); + cubeCards.add(new DraftCube.CardIdentity("Eternal Witness", "")); + cubeCards.add(new DraftCube.CardIdentity("Manglehorn", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Vastwood Seer", "")); + cubeCards.add(new DraftCube.CardIdentity("Ramunap Excavator", "")); + cubeCards.add(new DraftCube.CardIdentity("Reclamation Sage", "")); + cubeCards.add(new DraftCube.CardIdentity("Tireless Tracker", "")); + cubeCards.add(new DraftCube.CardIdentity("Yavimaya Elder", "")); + cubeCards.add(new DraftCube.CardIdentity("Master of the Wild Hunt", "")); + cubeCards.add(new DraftCube.CardIdentity("Obstinate Baloth", "")); + cubeCards.add(new DraftCube.CardIdentity("Oracle of Mul Daya", "")); + cubeCards.add(new DraftCube.CardIdentity("Polukranos, World Eater", "")); + cubeCards.add(new DraftCube.CardIdentity("Thrun, the Last Troll", "")); + cubeCards.add(new DraftCube.CardIdentity("Acidic Slime", "")); + cubeCards.add(new DraftCube.CardIdentity("Deranged Hermit", "")); + cubeCards.add(new DraftCube.CardIdentity("Thragtusk", "")); + cubeCards.add(new DraftCube.CardIdentity("Whisperwood Elemental", "")); + cubeCards.add(new DraftCube.CardIdentity("Carnage Tyrant", "")); + cubeCards.add(new DraftCube.CardIdentity("Primeval Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Avenger of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Craterhoof Behemoth", "")); + cubeCards.add(new DraftCube.CardIdentity("Terastodon", "")); + cubeCards.add(new DraftCube.CardIdentity("Woodfall Primus", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Voice of Zendikar", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Relentless", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk Wildspeaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Primal Hunter", "")); + cubeCards.add(new DraftCube.CardIdentity("Nissa, Worldwaker", "")); + cubeCards.add(new DraftCube.CardIdentity("Vivien Reid", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdurous Gearhulk", "")); + cubeCards.add(new DraftCube.CardIdentity("Nature's Claim", "")); + cubeCards.add(new DraftCube.CardIdentity("Beast Within", "")); + cubeCards.add(new DraftCube.CardIdentity("Channel", "")); + cubeCards.add(new DraftCube.CardIdentity("Regrowth", "")); + cubeCards.add(new DraftCube.CardIdentity("Kodama's Reach", "")); + cubeCards.add(new DraftCube.CardIdentity("Search for Tomorrow", "")); + cubeCards.add(new DraftCube.CardIdentity("Eureka", "")); + cubeCards.add(new DraftCube.CardIdentity("Harmonize", "")); + cubeCards.add(new DraftCube.CardIdentity("Natural Order", "")); + cubeCards.add(new DraftCube.CardIdentity("Plow Under", "")); + cubeCards.add(new DraftCube.CardIdentity("Primal Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Green Sun's Zenith", "")); + cubeCards.add(new DraftCube.CardIdentity("Tooth and Nail", "")); + cubeCards.add(new DraftCube.CardIdentity("Genesis Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Fastbond", "")); + cubeCards.add(new DraftCube.CardIdentity("Oath of Druids", "")); + cubeCards.add(new DraftCube.CardIdentity("Survival of the Fittest", "")); + cubeCards.add(new DraftCube.CardIdentity("Sylvan Library", "")); + cubeCards.add(new DraftCube.CardIdentity("Heartbeat of Spring", "")); + cubeCards.add(new DraftCube.CardIdentity("Gaea's Cradle", "")); + cubeCards.add(new DraftCube.CardIdentity("Geist of Saint Traft", "")); + cubeCards.add(new DraftCube.CardIdentity("Spell Queller", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Ojutai", "")); + cubeCards.add(new DraftCube.CardIdentity("Teferi, Hero of Dominaria", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx's Revelation", "")); + cubeCards.add(new DraftCube.CardIdentity("Celestial Colonnade", "")); + cubeCards.add(new DraftCube.CardIdentity("Flooded Strand", "")); + cubeCards.add(new DraftCube.CardIdentity("Hallowed Fountain", "")); + cubeCards.add(new DraftCube.CardIdentity("Seachrome Coast", "")); + cubeCards.add(new DraftCube.CardIdentity("Tundra", "")); + cubeCards.add(new DraftCube.CardIdentity("Thief of Sanity", "")); + cubeCards.add(new DraftCube.CardIdentity("Hostage Taker", "")); + cubeCards.add(new DraftCube.CardIdentity("The Scarab God", "")); + cubeCards.add(new DraftCube.CardIdentity("Ashiok, Nightmare Weaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Baleful Strix", "")); + cubeCards.add(new DraftCube.CardIdentity("Creeping Tar Pit", "")); + cubeCards.add(new DraftCube.CardIdentity("Darkslick Shores", "")); + cubeCards.add(new DraftCube.CardIdentity("Polluted Delta", "")); + cubeCards.add(new DraftCube.CardIdentity("Underground Sea", "")); + cubeCards.add(new DraftCube.CardIdentity("Watery Grave", "")); + cubeCards.add(new DraftCube.CardIdentity("Daretti, Ingenious Iconoclast", "")); + cubeCards.add(new DraftCube.CardIdentity("Terminate", "")); + cubeCards.add(new DraftCube.CardIdentity("Kolaghan's Command", "")); + cubeCards.add(new DraftCube.CardIdentity("Dreadbore", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos's Return", "")); + cubeCards.add(new DraftCube.CardIdentity("Badlands", "")); + cubeCards.add(new DraftCube.CardIdentity("Blackcleave Cliffs", "")); + cubeCards.add(new DraftCube.CardIdentity("Blood Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodstained Mire", "")); + cubeCards.add(new DraftCube.CardIdentity("Lavaclaw Reaches", "")); + cubeCards.add(new DraftCube.CardIdentity("Bloodbraid Elf", "")); + cubeCards.add(new DraftCube.CardIdentity("Huntmaster of the Fells", "")); + cubeCards.add(new DraftCube.CardIdentity("Dragonlord Atarka", "")); + cubeCards.add(new DraftCube.CardIdentity("Xenagos, the Reveler", "")); + cubeCards.add(new DraftCube.CardIdentity("Manamorphose", "")); + cubeCards.add(new DraftCube.CardIdentity("Copperline Gorge", "")); + cubeCards.add(new DraftCube.CardIdentity("Raging Ravine", "")); + cubeCards.add(new DraftCube.CardIdentity("Stomping Ground", "")); + cubeCards.add(new DraftCube.CardIdentity("Taiga", "")); + cubeCards.add(new DraftCube.CardIdentity("Wooded Foothills", "")); + cubeCards.add(new DraftCube.CardIdentity("Kitchen Finks", "")); + cubeCards.add(new DraftCube.CardIdentity("Knight of Autumn", "")); + cubeCards.add(new DraftCube.CardIdentity("Knight of the Reliquary", "")); + cubeCards.add(new DraftCube.CardIdentity("Trostani Discordant", "")); + cubeCards.add(new DraftCube.CardIdentity("Mirari's Wake", "")); + cubeCards.add(new DraftCube.CardIdentity("Razorverge Thicket", "")); + cubeCards.add(new DraftCube.CardIdentity("Savannah", "")); + cubeCards.add(new DraftCube.CardIdentity("Stirring Wildwood", "")); + cubeCards.add(new DraftCube.CardIdentity("Temple Garden", "")); + cubeCards.add(new DraftCube.CardIdentity("Windswept Heath", "")); + cubeCards.add(new DraftCube.CardIdentity("Tidehollow Sculler", "")); + cubeCards.add(new DraftCube.CardIdentity("Anguished Unmaking", "")); + cubeCards.add(new DraftCube.CardIdentity("Vindicate", "")); + cubeCards.add(new DraftCube.CardIdentity("Concealed Courtyard", "")); + cubeCards.add(new DraftCube.CardIdentity("Godless Shrine", "")); + cubeCards.add(new DraftCube.CardIdentity("Marsh Flats", "")); + cubeCards.add(new DraftCube.CardIdentity("Scrubland", "")); + cubeCards.add(new DraftCube.CardIdentity("Shambling Vent", "")); + cubeCards.add(new DraftCube.CardIdentity("Vraska, Relic Seeker", "")); + cubeCards.add(new DraftCube.CardIdentity("Garruk, Apex Predator", "")); + cubeCards.add(new DraftCube.CardIdentity("Abrupt Decay", "")); + cubeCards.add(new DraftCube.CardIdentity("Assassin's Trophy", "")); + cubeCards.add(new DraftCube.CardIdentity("Maelstrom Pulse", "")); + cubeCards.add(new DraftCube.CardIdentity("Bayou", "")); + cubeCards.add(new DraftCube.CardIdentity("Blooming Marsh", "")); + cubeCards.add(new DraftCube.CardIdentity("Hissing Quagmire", "")); + cubeCards.add(new DraftCube.CardIdentity("Overgrown Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Verdant Catacombs", "")); + cubeCards.add(new DraftCube.CardIdentity("Edric, Spymaster of Trest", "")); + cubeCards.add(new DraftCube.CardIdentity("Trygon Predator", "")); + cubeCards.add(new DraftCube.CardIdentity("Mystic Snake", "")); + cubeCards.add(new DraftCube.CardIdentity("Kiora, the Crashing Wave", "")); + cubeCards.add(new DraftCube.CardIdentity("Shardless Agent", "")); + cubeCards.add(new DraftCube.CardIdentity("Botanical Sanctum", "")); + cubeCards.add(new DraftCube.CardIdentity("Breeding Pool", "")); + cubeCards.add(new DraftCube.CardIdentity("Lumbering Falls", "")); + cubeCards.add(new DraftCube.CardIdentity("Misty Rainforest", "")); + cubeCards.add(new DraftCube.CardIdentity("Tropical Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Goblin Electromancer", "")); + cubeCards.add(new DraftCube.CardIdentity("Dack Fayden", "")); + cubeCards.add(new DraftCube.CardIdentity("Expansion // Explosion", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Charm", "")); + cubeCards.add(new DraftCube.CardIdentity("Thousand-Year Storm", "")); + cubeCards.add(new DraftCube.CardIdentity("Scalding Tarn", "")); + cubeCards.add(new DraftCube.CardIdentity("Spirebluff Canal", "")); + cubeCards.add(new DraftCube.CardIdentity("Steam Vents", "")); + cubeCards.add(new DraftCube.CardIdentity("Volcanic Island", "")); + cubeCards.add(new DraftCube.CardIdentity("Wandering Fumarole", "")); + cubeCards.add(new DraftCube.CardIdentity("Figure of Destiny", "")); + cubeCards.add(new DraftCube.CardIdentity("Aurelia, Exemplar of Justice", "")); + cubeCards.add(new DraftCube.CardIdentity("Ajani Vengeant", "")); + cubeCards.add(new DraftCube.CardIdentity("Nahiri, the Harbinger", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Helix", "")); + cubeCards.add(new DraftCube.CardIdentity("Arid Mesa", "")); + cubeCards.add(new DraftCube.CardIdentity("Inspiring Vantage", "")); + cubeCards.add(new DraftCube.CardIdentity("Needle Spires", "")); + cubeCards.add(new DraftCube.CardIdentity("Plateau", "")); + cubeCards.add(new DraftCube.CardIdentity("Sacred Foundry", "")); + cubeCards.add(new DraftCube.CardIdentity("Sphinx of the Steel Wind", "")); + cubeCards.add(new DraftCube.CardIdentity("Nicol Bolas, Planeswalker", "")); + cubeCards.add(new DraftCube.CardIdentity("Leovold, Emissary of Trest", "")); + cubeCards.add(new DraftCube.CardIdentity("Progenitus", "")); + cubeCards.add(new DraftCube.CardIdentity("Kozilek, Butcher of Truth", "")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Ceaseless Hunger", "")); + cubeCards.add(new DraftCube.CardIdentity("Ulamog, the Infinite Gyre", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Promised End", "")); + cubeCards.add(new DraftCube.CardIdentity("Emrakul, the Aeons Torn", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn, Scion of Urza", "")); + cubeCards.add(new DraftCube.CardIdentity("Karn Liberated", "")); + cubeCards.add(new DraftCube.CardIdentity("Ugin, the Spirit Dragon", "")); + cubeCards.add(new DraftCube.CardIdentity("Hangarback Walker", "")); + cubeCards.add(new DraftCube.CardIdentity("Phyrexian Revoker", "")); + cubeCards.add(new DraftCube.CardIdentity("Metalworker", "")); + cubeCards.add(new DraftCube.CardIdentity("Lodestone Golem", "")); + cubeCards.add(new DraftCube.CardIdentity("Solemn Simulacrum", "")); + cubeCards.add(new DraftCube.CardIdentity("Kuldotha Forgemaster", "")); + cubeCards.add(new DraftCube.CardIdentity("Duplicant", "")); + cubeCards.add(new DraftCube.CardIdentity("Wurmcoil Engine", "")); + cubeCards.add(new DraftCube.CardIdentity("Myr Battlesphere", "")); + cubeCards.add(new DraftCube.CardIdentity("Sundering Titan", "")); + cubeCards.add(new DraftCube.CardIdentity("Walking Ballista", "")); + cubeCards.add(new DraftCube.CardIdentity("Blightsteel Colossus", "")); + cubeCards.add(new DraftCube.CardIdentity("Black Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Chrome Mox", "")); + cubeCards.add(new DraftCube.CardIdentity("Everflowing Chalice", "")); + cubeCards.add(new DraftCube.CardIdentity("Lion's Eye Diamond", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Bloom", "")); + cubeCards.add(new DraftCube.CardIdentity("Lotus Petal", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Crypt", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Diamond", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Emerald", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Jet", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Pearl", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Ruby", "")); + cubeCards.add(new DraftCube.CardIdentity("Mox Sapphire", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Vault", "")); + cubeCards.add(new DraftCube.CardIdentity("Relic of Progenitus", "")); + cubeCards.add(new DraftCube.CardIdentity("Sensei's Divining Top", "")); + cubeCards.add(new DraftCube.CardIdentity("Skullclamp", "")); + cubeCards.add(new DraftCube.CardIdentity("Sol Ring", "")); + cubeCards.add(new DraftCube.CardIdentity("Azorius Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Boros Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Dimir Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Golgari Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Grim Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Gruul Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Izzet Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Lightning Greaves", "")); + cubeCards.add(new DraftCube.CardIdentity("Orzhov Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Pentad Prism", "")); + cubeCards.add(new DraftCube.CardIdentity("Rakdos Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Selesnya Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Shrine of Burning Rage", "")); + cubeCards.add(new DraftCube.CardIdentity("Simic Signet", "")); + cubeCards.add(new DraftCube.CardIdentity("Smuggler's Copter", "")); + cubeCards.add(new DraftCube.CardIdentity("Sorcerous Spyglass", "")); + cubeCards.add(new DraftCube.CardIdentity("Umezawa's Jitte", "")); + cubeCards.add(new DraftCube.CardIdentity("Winter Orb", "")); + cubeCards.add(new DraftCube.CardIdentity("Basalt Monolith", "")); + cubeCards.add(new DraftCube.CardIdentity("Coalition Relic", "")); + cubeCards.add(new DraftCube.CardIdentity("Crucible of Worlds", "")); + cubeCards.add(new DraftCube.CardIdentity("Oblivion Stone", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Body and Mind", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Feast and Famine", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Fire and Ice", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of Light and Shadow", "")); + cubeCards.add(new DraftCube.CardIdentity("Sword of War and Peace", "")); + cubeCards.add(new DraftCube.CardIdentity("Tangle Wire", "")); + cubeCards.add(new DraftCube.CardIdentity("Vedalken Shackles", "")); + cubeCards.add(new DraftCube.CardIdentity("Worn Powerstone", "")); + cubeCards.add(new DraftCube.CardIdentity("Coercive Portal", "")); + cubeCards.add(new DraftCube.CardIdentity("Smokestack", "")); + cubeCards.add(new DraftCube.CardIdentity("Thran Dynamo", "")); + cubeCards.add(new DraftCube.CardIdentity("Batterskull", "")); + cubeCards.add(new DraftCube.CardIdentity("Gilded Lotus", "")); + cubeCards.add(new DraftCube.CardIdentity("Memory Jar", "")); + cubeCards.add(new DraftCube.CardIdentity("Mindslaver", "")); + cubeCards.add(new DraftCube.CardIdentity("Academy Ruins", "")); + cubeCards.add(new DraftCube.CardIdentity("Ancient Tomb", "")); + cubeCards.add(new DraftCube.CardIdentity("Bazaar of Baghdad", "")); + cubeCards.add(new DraftCube.CardIdentity("Field of Ruin", "")); + cubeCards.add(new DraftCube.CardIdentity("Library of Alexandria", "")); + cubeCards.add(new DraftCube.CardIdentity("Mana Confluence", "")); + cubeCards.add(new DraftCube.CardIdentity("Maze of Ith", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Factory", "")); + cubeCards.add(new DraftCube.CardIdentity("Mishra's Workshop", "")); + cubeCards.add(new DraftCube.CardIdentity("Mutavault", "")); + cubeCards.add(new DraftCube.CardIdentity("Nykthos, Shrine to Nyx", "")); + cubeCards.add(new DraftCube.CardIdentity("Rishadan Port", "")); + cubeCards.add(new DraftCube.CardIdentity("Strip Mine", "")); + cubeCards.add(new DraftCube.CardIdentity("Wasteland", "")); + } +} + diff --git a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml index bec51f060a..9e3f659152 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Constructed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-tournament-constructed @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml index b9aab5d4f4..d359dd49a3 100644 --- a/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml +++ b/Mage.Server.Plugins/Mage.Tournament.Sealed/pom.xml @@ -7,7 +7,7 @@ org.mage mage-server-plugins - 1.4.31 + 1.4.35 mage-tournament-sealed @@ -29,8 +29,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.7 - 1.7 + 1.8 + 1.8 diff --git a/Mage.Server.Plugins/pom.xml b/Mage.Server.Plugins/pom.xml index a3ac123d03..cf0611b51e 100644 --- a/Mage.Server.Plugins/pom.xml +++ b/Mage.Server.Plugins/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-server-plugins diff --git a/Mage.Server/config/config.xml b/Mage.Server/config/config.xml index bab776da8f..0475c3cbe6 100644 --- a/Mage.Server/config/config.xml +++ b/Mage.Server/config/config.xml @@ -134,6 +134,8 @@ + + diff --git a/Mage.Server/manifest.mf b/Mage.Server/manifest.mf deleted file mode 100644 index 1574df4a2d..0000000000 --- a/Mage.Server/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build - diff --git a/Mage.Server/pom.xml b/Mage.Server/pom.xml index ef2b5d1b81..9386469d6c 100644 --- a/Mage.Server/pom.xml +++ b/Mage.Server/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-server @@ -22,8 +22,8 @@ org.apache.commons commons-lang3 - 3.3.2 - + 3.8.1 + ${project.groupId} mage-common @@ -42,7 +42,13 @@ com.sun.xml.bind jaxb-impl - 2.1.17 + 2.3.2 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.2 log4j @@ -76,16 +82,16 @@ ${project.version} runtime - + ${project.groupId} mage-game-brawlduel ${project.version} runtime - + org.apache.commons commons-compress - 1.16.1 + 1.18 @@ -194,58 +200,58 @@ org.apache.shiro shiro-core - 1.2.4 + 1.4.0 jar com.google.api-client google-api-client - 1.21.0 + 1.28.0 jar com.google.apis google-api-services-gmail - v1-rev35-1.21.0 + v1-rev20190120-1.28.0 jar com.google.oauth-client google-oauth-client-java6 - 1.19.0 + 1.28.0 jar com.google.oauth-client google-oauth-client-jetty - 1.19.0 + 1.28.0 jar javax.mail mail - 1.4.2 + 1.5.0-b01 jar com.sun.jersey jersey-core - 1.19 + 1.19.4 com.sun.jersey jersey-client - 1.19 + 1.19.4 com.sun.jersey.contribs jersey-multipart - 1.19 + 1.19.4 org.xerial sqlite-jdbc - 3.7.2 + 3.25.2 @@ -254,11 +260,10 @@ org.jvnet.jaxb2.maven2 maven-jaxb2-plugin - 0.12.3 + 0.14.0 mage.server.util.config ./src/main/xml-resources/jaxb/Config/ - -Xcommons-lang @@ -320,45 +325,10 @@ - + mage-server - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.1 - - - - - - - org.jvnet.jaxb2.maven2 - - - maven-jaxb2-plugin - - - [0.7.4,) - - - generate - - - - - - - - - - - - diff --git a/Mage.Server/release/config/config.xml b/Mage.Server/release/config/config.xml index 40a2f3ad72..2a294b3093 100644 --- a/Mage.Server/release/config/config.xml +++ b/Mage.Server/release/config/config.xml @@ -128,6 +128,8 @@ + + @@ -151,7 +153,8 @@ - + + diff --git a/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java b/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java index a081704944..f1915e72f1 100644 --- a/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java +++ b/Mage.Server/src/main/java/mage/server/AuthorizedUserRepository.java @@ -9,9 +9,6 @@ import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; -import java.io.File; -import java.sql.SQLException; -import java.util.List; import mage.cards.repository.CardRepository; import mage.cards.repository.RepositoryUtil; import org.apache.log4j.Logger; @@ -21,6 +18,10 @@ import org.apache.shiro.crypto.hash.Hash; import org.apache.shiro.crypto.hash.Sha256Hash; import org.apache.shiro.crypto.hash.SimpleHash; +import java.io.File; +import java.sql.SQLException; +import java.util.List; + public enum AuthorizedUserRepository { instance; @@ -108,7 +109,7 @@ public enum AuthorizedUserRepository { public void closeDB() { try { if (dao != null && dao.getConnectionSource() != null) { - DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(dao.getTableName()); conn.executeStatement("shutdown compact", 0); } } catch (SQLException ex) { diff --git a/Mage.Server/src/main/java/mage/server/ChatManager.java b/Mage.Server/src/main/java/mage/server/ChatManager.java index 4841a76643..755571becf 100644 --- a/Mage.Server/src/main/java/mage/server/ChatManager.java +++ b/Mage.Server/src/main/java/mage/server/ChatManager.java @@ -1,14 +1,5 @@ - package mage.server; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.server.exceptions.UserNotFoundException; @@ -20,6 +11,15 @@ import mage.view.ChatMessage.MessageType; import mage.view.ChatMessage.SoundToPlay; import org.apache.log4j.Logger; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * @author BetaSteward_at_googlemail.com */ @@ -107,7 +107,8 @@ public enum ChatManager { if (u.isPresent()) { User user = u.get(); - if (message.equals(userMessages.get(userName))) { + String messageId = chatId.toString() + message; + if (messageId.equals(userMessages.get(userName))) { // prevent identical messages String informUser = "Your message appears to be identical to your last message"; chatSessions.get(chatId).broadcastInfoToUser(user, informUser); @@ -144,7 +145,7 @@ public enum ChatManager { } } - userMessages.put(userName, message); + userMessages.put(userName, messageId); if (messageType == MessageType.TALK) { if (user.getChatLockedUntil() != null) { @@ -172,8 +173,8 @@ public enum ChatManager { + "
    \\whisper or \\w [player name] [text] - whisper to the player with the given name" + "
    \\card Card Name - Print oracle text for card" + "
    [Card Name] - Show a highlighted card name" - + "
    \\ignore - shows current ignore list on this server." - + "
    \\ignore [username] - add a username to your ignore list on this server." + + "
    \\ignore - shows your ignore list on this server." + + "
    \\ignore [username] - add username to ignore list (they won't be able to chat or join to your game)." + "
    \\unignore [username] - remove a username from your ignore list on this server."; final Pattern getCardTextPattern = Pattern.compile("^.card *(.*)"); @@ -203,7 +204,7 @@ public enum ChatManager { if (session != null && session.getInfo() != null) { String gameId = session.getInfo(); if (gameId.startsWith("Game ")) { - UUID id = java.util.UUID.fromString(gameId.substring(5, gameId.length())); + UUID id = java.util.UUID.fromString(gameId.substring(5)); for (Entry entry : GameManager.instance.getGameController().entrySet()) { if (entry.getKey().equals(id)) { GameController controller = entry.getValue(); @@ -224,7 +225,7 @@ public enum ChatManager { if (session != null && session.getInfo() != null) { String gameId = session.getInfo(); if (gameId.startsWith("Game ")) { - UUID id = java.util.UUID.fromString(gameId.substring(5, gameId.length())); + UUID id = java.util.UUID.fromString(gameId.substring(5)); for (Entry entry : GameManager.instance.getGameController().entrySet()) { if (entry.getKey().equals(id)) { GameController controller = entry.getValue(); @@ -238,7 +239,7 @@ public enum ChatManager { } } return true; - } + } if (command.startsWith("CARD ")) { Matcher matchPattern = getCardTextPattern.matcher(message.toLowerCase(Locale.ENGLISH)); if (matchPattern.find()) { diff --git a/Mage.Server/src/main/java/mage/server/MageServerImpl.java b/Mage.Server/src/main/java/mage/server/MageServerImpl.java index 899f113519..f36fc7f5e1 100644 --- a/Mage.Server/src/main/java/mage/server/MageServerImpl.java +++ b/Mage.Server/src/main/java/mage/server/MageServerImpl.java @@ -1,12 +1,8 @@ - package mage.server; -import java.security.SecureRandom; -import java.util.*; -import java.util.concurrent.ExecutorService; -import javax.management.timer.Timer; import mage.MageException; import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.repository.ExpansionInfo; @@ -43,6 +39,11 @@ import mage.view.ChatMessage.MessageColor; import org.apache.commons.lang3.StringEscapeUtils; import org.apache.log4j.Logger; +import javax.management.timer.Timer; +import java.security.SecureRandom; +import java.util.*; +import java.util.concurrent.ExecutorService; + /** * @author BetaSteward_at_googlemail.com, noxx */ @@ -142,7 +143,7 @@ public class MageServerImpl implements MageServer { return SessionManager.instance.connectUser(sessionId, userName, password, userIdStr); } catch (MageException ex) { if (ex instanceof MageVersionException) { - throw (MageVersionException) ex; + throw ex; } handleException(ex); } @@ -227,6 +228,20 @@ public class MageServerImpl implements MageServer { user.showUserMessage("Create tournament", message); throw new MageException("No message"); } + // check if the user satisfies the minimumRating requirement. + int minimumRating = options.getMinimumRating(); + int userRating; + if (options.getMatchOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Create tournament", message); + throw new MageException("No message"); + } Optional room = GamesRoomManager.instance.getRoom(roomId); if (!room.isPresent()) { @@ -246,24 +261,20 @@ public class MageServerImpl implements MageServer { @Override public void removeTable(final String sessionId, final UUID roomId, final UUID tableId) throws MageException { execute("removeTable", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); TableManager.instance.removeTable(userId, tableId); - } + }); }); } @Override - public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { + public boolean joinTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException { return executeWithResult("joinTable", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return false; } UUID userId = session.get().getUserId(); @@ -274,7 +285,6 @@ public class MageServerImpl implements MageServer { } Optional room = GamesRoomManager.instance.getRoom(roomId); if (!room.isPresent()) { - logger.error("room not found : " + roomId); return false; } return room.get().joinTable(userId, tableId, name, playerType, skill, deckList, password); @@ -284,13 +294,12 @@ public class MageServerImpl implements MageServer { } @Override - public boolean joinTournamentTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException, GameException { + public boolean joinTournamentTable(final String sessionId, final UUID roomId, final UUID tableId, final String name, final PlayerType playerType, final int skill, final DeckCardLists deckList, final String password) throws MageException { return executeWithResult("joinTournamentTable", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return false; } UUID userId = session.get().getUserId(); @@ -313,13 +322,12 @@ public class MageServerImpl implements MageServer { } @Override - public boolean submitDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException, GameException { + public boolean submitDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException { return executeWithResult("submitDeck", sessionId, new ActionWithBooleanResult() { @Override public Boolean execute() throws MageException { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return false; } else { UUID userId = session.get().getUserId(); @@ -332,7 +340,7 @@ public class MageServerImpl implements MageServer { } @Override - public void updateDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException, GameException { + public void updateDeck(final String sessionId, final UUID tableId, final DeckCardLists deckList) throws MageException { execute("updateDeck", sessionId, () -> { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { @@ -366,12 +374,7 @@ public class MageServerImpl implements MageServer { //FIXME: why no sessionId here??? public List getFinishedMatches(UUID roomId) throws MageException { try { - Optional room = GamesRoomManager.instance.getRoom(roomId); - if (room.isPresent()) { - return room.get().getFinished(); - } else { - return new ArrayList<>(); - } + return GamesRoomManager.instance.getRoom(roomId).map(GamesRoom::getFinished).orElse(new ArrayList<>()); } catch (Exception ex) { handleException(ex); } @@ -501,13 +504,11 @@ public class MageServerImpl implements MageServer { @Override public void joinChat(final UUID chatId, final String sessionId, final String userName) throws MageException { execute("joinChat", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + + UUID userId = session.getUserId(); ChatManager.instance.joinChat(chatId, userId); - } + }); }); } @@ -515,13 +516,10 @@ public class MageServerImpl implements MageServer { public void leaveChat(final UUID chatId, final String sessionId) throws MageException { execute("leaveChat", sessionId, () -> { if (chatId != null) { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); ChatManager.instance.leaveChat(chatId, userId); - } + }); } }); } @@ -560,7 +558,6 @@ public class MageServerImpl implements MageServer { public Boolean execute() { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return false; } else { UUID userId = session.get().getUserId(); @@ -573,13 +570,10 @@ public class MageServerImpl implements MageServer { @Override public void swapSeats(final String sessionId, final UUID roomId, final UUID tableId, final int seatNum1, final int seatNum2) throws MageException { execute("swapSeats", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); TableManager.instance.swapSeats(tableId, userId, seatNum1, seatNum2); - } + }); }); } @@ -593,19 +587,12 @@ public class MageServerImpl implements MageServer { return false; } execute("leaveTable", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); - Optional room = GamesRoomManager.instance.getRoom(roomId); - if (!room.isPresent()) { - logger.error("room not found : " + roomId); - } else { + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); + GamesRoomManager.instance.getRoom(roomId).ifPresent(room -> + room.leaveTable(userId, tableId)); - room.get().leaveTable(userId, tableId); - } - } + }); }); } else { // this can happen if a game ends and a player quits XMage or a match nearly at the same time as the game ends @@ -628,26 +615,20 @@ public class MageServerImpl implements MageServer { @Override public void joinGame(final UUID gameId, final String sessionId) throws MageException { execute("joinGame", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); GameManager.instance.joinGame(gameId, userId); - } + }); }); } @Override public void joinDraft(final UUID draftId, final String sessionId) throws MageException { execute("joinDraft", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); DraftManager.instance.joinDraft(draftId, userId); - } + }); }); } @@ -755,13 +736,10 @@ public class MageServerImpl implements MageServer { @Override public void sendCardMark(final UUID draftId, final String sessionId, final UUID cardPick) throws MageException { execute("sendCardMark", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); DraftManager.instance.sendCardMark(draftId, userId, cardPick); - } + }); }); } @@ -771,14 +749,10 @@ public class MageServerImpl implements MageServer { try { callExecutor.execute( () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); GameManager.instance.quitMatch(gameId, userId); - } - + }); } ); } catch (Exception ex) { @@ -793,14 +767,11 @@ public class MageServerImpl implements MageServer { try { callExecutor.execute( () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); TournamentManager.instance.quit(tournamentId, userId); - } + }); } ); } catch (Exception ex) { @@ -813,40 +784,35 @@ public class MageServerImpl implements MageServer { public void quitDraft(final UUID draftId, final String sessionId) throws MageException { execute("quitDraft", sessionId, () -> { - try { - callExecutor.execute( - () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); - UUID tableId = DraftManager.instance.getControllerByDraftId(draftId).getTableId(); - Table table = TableManager.instance.getTable(tableId); - if (table.isTournament()) { - UUID tournamentId = table.getTournament().getId(); - TournamentManager.instance.quit(tournamentId, userId); + try { + callExecutor.execute( + () -> { + SessionManager.instance.getSession(sessionId).ifPresent( + session -> { + UUID userId = session.getUserId(); + UUID tableId = DraftManager.instance.getControllerByDraftId(draftId).getTableId(); + Table table = TableManager.instance.getTable(tableId); + if (table.isTournament()) { + UUID tournamentId = table.getTournament().getId(); + TournamentManager.instance.quit(tournamentId, userId); + } + }); } - } - } - ); - } catch (Exception ex) { - handleException(ex); - } - } + ); + } catch (Exception ex) { + handleException(ex); + } + } ); } @Override public void sendPlayerAction(final PlayerAction playerAction, final UUID gameId, final String sessionId, final Object data) throws MageException { execute("sendPlayerAction", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); GameManager.instance.sendPlayerAction(playerAction, gameId, userId, data); - } + }); }); } @@ -881,14 +847,11 @@ public class MageServerImpl implements MageServer { return executeWithResult("watchGame", sessionId, new ActionWithResult() { @Override public Boolean execute() throws MageException { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - return false; - } else { - UUID userId = session.get().getUserId(); - return GameManager.instance.watchGame(gameId, userId); - } + return SessionManager.instance.getSession(sessionId) + .map(session -> { + UUID userId = session.getUserId(); + return GameManager.instance.watchGame(gameId, userId); + }).orElse(false); } @Override @@ -901,16 +864,13 @@ public class MageServerImpl implements MageServer { @Override public void stopWatching(final UUID gameId, final String sessionId) throws MageException { execute("stopWatching", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); UserManager.instance.getUser(userId).ifPresent(user -> { GameManager.instance.stopWatching(gameId, userId); user.removeGameWatchInfo(gameId); }); - } + }); }); } @@ -918,26 +878,20 @@ public class MageServerImpl implements MageServer { @Override public void replayGame(final UUID gameId, final String sessionId) throws MageException { execute("replayGame", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); ReplayManager.instance.replayGame(gameId, userId); - } + }); }); } @Override public void startReplay(final UUID gameId, final String sessionId) throws MageException { execute("startReplay", sessionId, () -> { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); ReplayManager.instance.startReplay(gameId, userId); - } + }); }); } @@ -1018,13 +972,10 @@ public class MageServerImpl implements MageServer { public void cheat(final UUID gameId, final String sessionId, final UUID playerId, final DeckCardLists deckList) throws MageException { execute("cheat", sessionId, () -> { if (testMode) { - Optional session = SessionManager.instance.getSession(sessionId); - if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); - } else { - UUID userId = session.get().getUserId(); + SessionManager.instance.getSession(sessionId).ifPresent(session -> { + UUID userId = session.getUserId(); GameManager.instance.cheat(gameId, userId, playerId, deckList); - } + }); } }); } @@ -1127,12 +1078,12 @@ public class MageServerImpl implements MageServer { public void toggleActivation(final String sessionId, final String userName) throws MageException { execute("toggleActivation", sessionId, () -> UserManager.instance.getUserByName(userName).ifPresent(user - -> { - user.setActive(!user.isActive()); - if (!user.isActive() && user.isConnected()) { - SessionManager.instance.disconnectUser(sessionId, user.getSessionId()); - } - })); + -> { + user.setActive(!user.isActive()); + if (!user.isActive() && user.isConnected()) { + SessionManager.instance.disconnectUser(sessionId, user.getSessionId()); + } + })); } @Override @@ -1167,8 +1118,8 @@ public class MageServerImpl implements MageServer { if (title != null && message != null) { execute("sendFeedbackMessage", sessionId, () -> SessionManager.instance.getSession(sessionId).ifPresent( - session -> FeedbackServiceImpl.instance.feedback(username, title, type, message, email, session.getHost()) - )); + session -> FeedbackServiceImpl.instance.feedback(username, title, type, message, email, session.getHost()) + )); } } @@ -1249,13 +1200,15 @@ public class MageServerImpl implements MageServer { result.add(expansionInfo); } } + logger.info("Missing exp downloaded: " + result.size()); return result; } @Override public List getMissingCardsData(List classNames) { - return CardRepository.instance.getMissingCards(classNames); - + List res = CardRepository.instance.getMissingCards(classNames); + logger.info("Missing cards downloaded: " + res.size()); + return res; } private static class MyActionWithNullNegativeResult extends ActionWithNullNegativeResult { @@ -1293,8 +1246,8 @@ public class MageServerImpl implements MageServer { logger.error("Session not found : " + sessionId); return null; } else { - UUID userId = session.get().getUserId(); - return GameManager.instance.getGameView(gameId, userId, playerId); + //UUID userId = session.get().getUserId(); + return GameManager.instance.getGameView(gameId, playerId); } } } @@ -1313,7 +1266,6 @@ public class MageServerImpl implements MageServer { public Boolean execute() throws MageException { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return false; } else { UUID userId = session.get().getUserId(); @@ -1364,7 +1316,6 @@ public class MageServerImpl implements MageServer { public TableView execute() throws MageException { Optional session = SessionManager.instance.getSession(sessionId); if (!session.isPresent()) { - logger.error("Session not found : " + sessionId); return null; } UUID userId = session.get().getUserId(); @@ -1386,7 +1337,19 @@ public class MageServerImpl implements MageServer { user.showUserMessage("Create table", "Your quit ratio " + user.getMatchQuitRatio() + "% is higher than the table requirement " + quitRatio + '%'); throw new MageException("No message"); } - + // check if the user satisfies the minimumRating requirement. + int minimumRating = options.getMinimumRating(); + int userRating; + if (options.isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating).append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Create table", message); + throw new MageException("No message"); + } Optional room = GamesRoomManager.instance.getRoom(roomId); if (room.isPresent()) { TableView table = room.get().createTable(userId, options); diff --git a/Mage.Server/src/main/java/mage/server/Main.java b/Mage.Server/src/main/java/mage/server/Main.java index cd64c6086d..877e0f8e09 100644 --- a/Mage.Server/src/main/java/mage/server/Main.java +++ b/Mage.Server/src/main/java/mage/server/Main.java @@ -1,22 +1,17 @@ - package mage.server; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.util.*; -import javax.management.MBeanServer; import mage.cards.ExpansionSet; import mage.cards.Sets; +import mage.cards.decks.DeckValidatorFactory; import mage.cards.repository.CardScanner; import mage.cards.repository.PluginClassloaderRegistery; +import mage.cards.repository.RepositoryUtil; +import mage.game.draft.RateCard; import mage.game.match.MatchType; import mage.game.tournament.TournamentType; import mage.interfaces.MageServer; import mage.remote.Connection; import mage.server.draft.CubeFactory; -import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.PlayerFactory; import mage.server.record.UserStatsRepository; @@ -39,13 +34,20 @@ import org.jboss.remoting.transporter.TransporterClient; import org.jboss.remoting.transporter.TransporterServer; import org.w3c.dom.Element; +import javax.management.MBeanServer; +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ public final class Main { private static final Logger logger = Logger.getLogger(Main.class); - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(Main.class); private static final String testModeArg = "-testMode="; private static final String fastDBModeArg = "-fastDbMode="; @@ -55,9 +57,9 @@ public final class Main { private static final File extensionFolder = new File("extensions"); public static final PluginClassLoader classLoader = new PluginClassLoader(); - public static TransporterServer server; - protected static boolean testMode; - protected static boolean fastDbMode; + private static TransporterServer server; + private static boolean testMode; + private static boolean fastDbMode; /** * @param args the command line arguments @@ -88,6 +90,10 @@ public final class Main { logger.info("Done."); } + // db init and updates checks (e.g. cleanup cards db on new version) + RepositoryUtil.bootstrapLocalDb(); + logger.info("Done."); + logger.info("Loading extension packages..."); if (!extensionFolder.exists()) { if (!extensionFolder.mkdirs()) { @@ -130,6 +136,12 @@ public final class Main { } logger.info("Done."); + // cards preload with ratings + if (RateCard.PRELOAD_CARD_RATINGS_ON_STARTUP) { + RateCard.bootstrapCardsAndRatings(); + logger.info("Done."); + } + logger.info("Updating user stats DB..."); UserStatsRepository.instance.updateUserStats(); logger.info("Done."); @@ -413,8 +425,10 @@ public final class Main { File[] files = directory.listFiles( (dir, name) -> name.endsWith(".game") ); - for (File file : files) { - file.delete(); + if (files != null) { + for (File file : files) { + file.delete(); + } } } diff --git a/Mage.Server/src/main/java/mage/server/Session.java b/Mage.Server/src/main/java/mage/server/Session.java index 39475db923..be7d035750 100644 --- a/Mage.Server/src/main/java/mage/server/Session.java +++ b/Mage.Server/src/main/java/mage/server/Session.java @@ -30,8 +30,8 @@ import org.jboss.remoting.callback.InvokerCallbackHandler; public class Session { private static final Logger logger = Logger.getLogger(Session.class); - private final static Pattern alphabetsPattern = Pattern.compile("[a-zA-Z]"); - private final static Pattern digitsPattern = Pattern.compile("[0-9]"); + private static final Pattern alphabetsPattern = Pattern.compile("[a-zA-Z]"); + private static final Pattern digitsPattern = Pattern.compile("[0-9]"); private final String sessionId; private UUID userId; diff --git a/Mage.Server/src/main/java/mage/server/SessionManager.java b/Mage.Server/src/main/java/mage/server/SessionManager.java index 66d9c7d8e1..20d201e6c3 100644 --- a/Mage.Server/src/main/java/mage/server/SessionManager.java +++ b/Mage.Server/src/main/java/mage/server/SessionManager.java @@ -1,14 +1,15 @@ package mage.server; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import javax.annotation.Nonnull; import mage.MageException; import mage.players.net.UserData; import org.apache.log4j.Logger; import org.jboss.remoting.callback.InvokerCallbackHandler; +import javax.annotation.Nonnull; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + /** * @author BetaSteward_at_googlemail.com */ @@ -29,7 +30,7 @@ public enum SessionManager { if (session.getUserId() != null && !UserManager.instance.getUser(session.getUserId()).isPresent()) { logger.error("User for session " + sessionId + " with userId " + session.getUserId() + " is missing. Session removed."); // can happen if user from same host signs in multiple time with multiple clients, after he disconnects with one client - disconnect(sessionId, DisconnectReason.ConnectingOtherInstance); + disconnect(sessionId, DisconnectReason.ConnectingOtherInstance, session); // direct disconnect return Optional.empty(); } return Optional.of(session); @@ -88,45 +89,52 @@ public enum SessionManager { } public boolean setUserData(String userName, String sessionId, UserData userData, String clientVersion, String userIdStr) throws MageException { - Session session = sessions.get(sessionId); - if (session != null) { - session.setUserData(userName, userData, clientVersion, userIdStr); - return true; - } - return false; + return getSession(sessionId) + .map(session -> session.setUserData(userName,userData, clientVersion, userIdStr)) + .orElse(false); + } public void disconnect(String sessionId, DisconnectReason reason) { - Session session = sessions.get(sessionId); - if (session != null) { - if (!sessions.containsKey(sessionId)) { - // session was removed meanwhile by another thread so we can return - return; - } - logger.debug("DISCONNECT " + reason.toString() + " - sessionId: " + sessionId); - sessions.remove(sessionId); - switch (reason) { - case AdminDisconnect: - session.kill(reason); - break; - case ConnectingOtherInstance: - case Disconnected: // regular session end or wrong client version - UserManager.instance.disconnect(session.getUserId(), reason); - break; - case SessionExpired: // session ends after no reconnect happens in the defined time span - break; - case LostConnection: // user lost connection - session expires countdown starts - session.userLostConnection(); - UserManager.instance.disconnect(session.getUserId(), reason); - break; - default: - logger.trace("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId); - } - - } - + disconnect(sessionId, reason, null); } + public void disconnect(String sessionId, DisconnectReason reason, Session directSession) { + if (directSession == null) { + // find real session to disconnects + getSession(sessionId).ifPresent(session -> { + if (!isValidSession(sessionId)) { + // session was removed meanwhile by another thread so we can return + return; + } + logger.debug("DISCONNECT " + reason.toString() + " - sessionId: " + sessionId); + sessions.remove(sessionId); + switch (reason) { + case AdminDisconnect: + session.kill(reason); + break; + case ConnectingOtherInstance: + case Disconnected: // regular session end or wrong client version + UserManager.instance.disconnect(session.getUserId(), reason); + break; + case SessionExpired: // session ends after no reconnect happens in the defined time span + break; + case LostConnection: // user lost connection - session expires countdown starts + session.userLostConnection(); + UserManager.instance.disconnect(session.getUserId(), reason); + break; + default: + logger.trace("endSession: unexpected reason " + reason.toString() + " - sessionId: " + sessionId); + } + }); + } else { + // direct session to disconnects + sessions.remove(sessionId); + directSession.kill(reason); + } + } + + /** * Admin requested the disconnect of a user * @@ -150,11 +158,9 @@ public enum SessionManager { } private Optional getUserFromSession(String sessionId) { - Optional session = getSession(sessionId); - if (!session.isPresent()) { - return Optional.empty(); - } - return UserManager.instance.getUser(session.get().getUserId()); + return getSession(sessionId) + .flatMap(s -> UserManager.instance.getUser(s.getUserId())); + } public void endUserSession(String sessionId, String userSessionId) { @@ -164,11 +170,8 @@ public enum SessionManager { } public boolean isAdmin(String sessionId) { - Session admin = sessions.get(sessionId); - if (admin != null) { - return admin.isAdmin(); - } - return false; + return getSession(sessionId).map(Session::isAdmin).orElse(false); + } public boolean isValidSession(@Nonnull String sessionId) { @@ -185,11 +188,9 @@ public enum SessionManager { } public boolean extendUserSession(String sessionId, String pingInfo) { - Session session = sessions.get(sessionId); - if (session != null) { - return UserManager.instance.extendUserSession(session.getUserId(), pingInfo); - } - return false; + return getSession(sessionId) + .map(session -> UserManager.instance.extendUserSession(session.getUserId(), pingInfo)) + .orElse(false); } public void sendErrorMessageToClient(String sessionId, String message) { diff --git a/Mage.Server/src/main/java/mage/server/TableController.java b/Mage.Server/src/main/java/mage/server/TableController.java index 1f4d9808cd..d7edea7572 100644 --- a/Mage.Server/src/main/java/mage/server/TableController.java +++ b/Mage.Server/src/main/java/mage/server/TableController.java @@ -1,18 +1,9 @@ - package mage.server; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; import mage.MageException; import mage.cards.decks.Deck; import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckValidatorFactory; import mage.constants.RangeOfInfluence; import mage.constants.TableState; import mage.game.*; @@ -29,12 +20,10 @@ import mage.game.tournament.TournamentPlayer; import mage.players.Player; import mage.players.PlayerType; import mage.server.draft.DraftManager; -import mage.server.game.DeckValidatorFactory; import mage.server.game.GameFactory; import mage.server.game.GameManager; import mage.server.game.PlayerFactory; import mage.server.record.TableRecorderImpl; -import mage.server.tournament.TournamentController; import mage.server.tournament.TournamentFactory; import mage.server.tournament.TournamentManager; import mage.server.util.ConfigSettings; @@ -43,6 +32,16 @@ import mage.server.util.ThreadExecutor; import mage.view.ChatMessage; import org.apache.log4j.Logger; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + /** * @author BetaSteward_at_googlemail.com */ @@ -172,6 +171,21 @@ public class TableController { return false; } + // Check minimum rating. + int minimumRating = table.getTournament().getOptions().getMinimumRating(); + int userRating; + if (table.getTournament().getOptions().getMatchOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Join Table", message); + return false; + } + Optional playerOptional = createPlayer(name, seat.getPlayerType(), skill); if (playerOptional.isPresent()) { Player player = playerOptional.get(); @@ -225,6 +239,7 @@ public class TableController { public synchronized boolean joinTable(UUID userId, String name, PlayerType playerType, int skill, DeckCardLists deckList, String password) throws MageException { Optional _user = UserManager.instance.getUser(userId); if (!_user.isPresent()) { + logger.error("Join Table: can't find user to join " + name + " Id = " + userId); return false; } User user = _user.get(); @@ -272,6 +287,21 @@ public class TableController { return false; } + // Check minimum rating. + int minimumRating = table.getMatch().getOptions().getMinimumRating(); + int userRating; + if (table.getMatch().getOptions().isLimited()) { + userRating = user.getUserData().getLimitedRating(); + } else { + userRating = user.getUserData().getConstructedRating(); + } + if (userRating < minimumRating) { + String message = new StringBuilder("Your rating ").append(userRating) + .append(" is lower than the table requirement ").append(minimumRating).toString(); + user.showUserMessage("Join Table", message); + return false; + } + // Check power level for table (currently only used for EDH/Commander table) int edhPowerLevel = table.getMatch().getOptions().getEdhPowerLevel(); if (edhPowerLevel > 0 && table.getValidator().getName().toLowerCase(Locale.ENGLISH).equals("commander")) { @@ -846,7 +876,7 @@ public class TableController { private void autoSideboard() { for (MatchPlayer player : match.getPlayers()) { if (!player.isDoneSideboarding()) { - match.submitDeck(player.getPlayer().getId(), player.generateDeck()); + match.submitDeck(player.getPlayer().getId(), player.generateDeck(table.getValidator())); } } } @@ -897,12 +927,10 @@ public class TableController { public boolean isTournamentStillValid() { if (table.getTournament() != null) { if (table.getState() != TableState.WAITING && table.getState() != TableState.READY_TO_START && table.getState() != TableState.STARTING) { - TournamentController tournamentController = TournamentManager.instance.getTournamentController(table.getTournament().getId()); - if (tournamentController != null) { - return tournamentController.isTournamentStillValid(table.getState()); - } else { - return false; - } + return TournamentManager.instance.getTournamentController(table.getTournament().getId()) + .map(tc -> tc.isTournamentStillValid(table.getState())) + .orElse(false); + } else { // check if table creator is still a valid user, if not removeUserFromAllTablesAndChat table return UserManager.instance.getUser(userId).isPresent(); diff --git a/Mage.Server/src/main/java/mage/server/User.java b/Mage.Server/src/main/java/mage/server/User.java index 0649e7ac20..930133aa73 100644 --- a/Mage.Server/src/main/java/mage/server/User.java +++ b/Mage.Server/src/main/java/mage/server/User.java @@ -334,10 +334,10 @@ public class User { } for (Iterator> iterator = userTournaments.entrySet().iterator(); iterator.hasNext();) { Entry next = iterator.next(); - TournamentController tournamentController = TournamentManager.instance.getTournamentController(next.getValue()); - if (tournamentController != null) { + Optional tournamentController = TournamentManager.instance.getTournamentController(next.getValue()); + if (tournamentController.isPresent()) { ccTournamentStarted(next.getValue(), next.getKey()); - tournamentController.rejoin(next.getKey()); + tournamentController.get().rejoin(next.getKey()); } else { iterator.remove(); // tournament has ended meanwhile } diff --git a/Mage.Server/src/main/java/mage/server/UserManager.java b/Mage.Server/src/main/java/mage/server/UserManager.java index 4473afb3e0..21ca15d278 100644 --- a/Mage.Server/src/main/java/mage/server/UserManager.java +++ b/Mage.Server/src/main/java/mage/server/UserManager.java @@ -1,11 +1,5 @@ - package mage.server; -import java.util.*; -import java.util.concurrent.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; import mage.server.User.UserState; import mage.server.record.UserStats; import mage.server.record.UserStatsRepository; @@ -13,6 +7,12 @@ import mage.server.util.ThreadExecutor; import mage.view.UserView; import org.apache.log4j.Logger; +import java.util.*; +import java.util.concurrent.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * manages users - if a user is disconnected and 10 minutes have passed with no * activity the user is removed @@ -22,6 +22,9 @@ import org.apache.log4j.Logger; public enum UserManager { instance; + private static final int SERVER_TIMEOUTS_USER_DISCONNECT_FROM_SERVER_AFTER_SECS = 3 * 60; // removes from all games and chats too (can be seen in users list with disconnected status) + private static final int SERVER_TIMEOUTS_USER_REMOVE_FROM_SERVER_AFTER_SECS = 8 * 60; // removes from users list + private static final Logger logger = Logger.getLogger(UserManager.class); protected final ScheduledExecutorService expireExecutor = Executors.newSingleThreadScheduledExecutor(); @@ -29,7 +32,6 @@ public enum UserManager { private List userInfoList = new ArrayList<>(); - private static final Logger LOGGER = Logger.getLogger(UserManager.class); private final ReadWriteLock lock = new ReentrantReadWriteLock(); private final ConcurrentHashMap users = new ConcurrentHashMap<>(); @@ -59,7 +61,7 @@ public enum UserManager { public Optional getUser(UUID userId) { if (!users.containsKey(userId)) { - LOGGER.trace(String.format("User with id %s could not be found", userId)); + //logger.warn(String.format("User with id %s could not be found", userId), new Throwable()); // TODO: remove after session freezes fixed return Optional.empty(); } else { return Optional.of(users.get(userId)); @@ -70,13 +72,8 @@ public enum UserManager { final Lock r = lock.readLock(); r.lock(); try { - Optional u = users.values().stream().filter(user -> user.getName().equals(userName)) + return users.values().stream().filter(user -> user.getName().equals(userName)) .findFirst(); - if (u.isPresent()) { - return u; - } else { - return Optional.empty(); - } } finally { r.unlock(); } @@ -84,7 +81,7 @@ public enum UserManager { } public Collection getUsers() { - ArrayList userList = new ArrayList<>(); + List userList = new ArrayList<>(); final Lock r = lock.readLock(); r.lock(); try { @@ -133,17 +130,17 @@ public enum UserManager { if (userId != null) { getUser(userId).ifPresent(user -> USER_EXECUTOR.execute( - () -> { - try { - LOGGER.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId + " [" + user.getGameInfo() + ']'); - user.removeUserFromAllTables(reason); - ChatManager.instance.removeUser(user.getId(), reason); - LOGGER.debug("USER REMOVE END - " + user.getName()); - } catch (Exception ex) { - handleException(ex); - } - } - )); + () -> { + try { + logger.info("USER REMOVE - " + user.getName() + " (" + reason.toString() + ") userId: " + userId + " [" + user.getGameInfo() + ']'); + user.removeUserFromAllTables(reason); + ChatManager.instance.removeUser(user.getId(), reason); + logger.debug("USER REMOVE END - " + user.getName()); + } catch (Exception ex) { + handleException(ex); + } + } + )); } } @@ -161,16 +158,15 @@ public enum UserManager { /** * Is the connection lost for more than 3 minutes, the user will be set to - * offline status. The user will be removed in validity check after 15 + * offline status. The user will be removed in validity check after 8 * minutes of no activities - * */ private void checkExpired() { try { Calendar calendarExp = Calendar.getInstance(); - calendarExp.add(Calendar.MINUTE, -3); + calendarExp.add(Calendar.SECOND, -1 * SERVER_TIMEOUTS_USER_DISCONNECT_FROM_SERVER_AFTER_SECS); Calendar calendarRemove = Calendar.getInstance(); - calendarRemove.add(Calendar.MINUTE, -8); + calendarRemove.add(Calendar.SECOND, -1 * SERVER_TIMEOUTS_USER_REMOVE_FROM_SERVER_AFTER_SECS); List toRemove = new ArrayList<>(); logger.debug("Start Check Expired"); ArrayList userList = new ArrayList<>(); @@ -185,18 +181,18 @@ public enum UserManager { try { if (user.getUserState() == UserState.Offline) { if (user.isExpired(calendarRemove.getTime())) { + // removes from users list toRemove.add(user); } } else { if (user.isExpired(calendarExp.getTime())) { + // set disconnected status and removes from all activities (tourney/tables/games/drafts/chats) if (user.getUserState() == UserState.Connected) { user.lostConnection(); disconnect(user.getId(), DisconnectReason.BecameInactive); } removeUserFromAllTablesAndChat(user.getId(), DisconnectReason.SessionExpired); user.setUserState(UserState.Offline); - // Remove the user from all tournaments - } } } catch (Exception ex) { @@ -221,7 +217,6 @@ public enum UserManager { /** * This method recreated the user list that will be send to all clients - * */ private void updateUserInfoList() { try { @@ -253,12 +248,12 @@ public enum UserManager { public void handleException(Exception ex) { if (ex != null) { - LOGGER.fatal("User manager exception ", ex); + logger.fatal("User manager exception ", ex); if (ex.getStackTrace() != null) { - LOGGER.fatal(ex.getStackTrace()); + logger.fatal(ex.getStackTrace()); } } else { - LOGGER.fatal("User manager exception - null"); + logger.fatal("User manager exception - null"); } } diff --git a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java index d1e087899a..d34848fdb1 100644 --- a/Mage.Server/src/main/java/mage/server/draft/DraftSession.java +++ b/Mage.Server/src/main/java/mage/server/draft/DraftSession.java @@ -24,7 +24,7 @@ import org.apache.log4j.Logger; */ public class DraftSession { - protected final static Logger logger = Logger.getLogger(DraftSession.class); + protected static final Logger logger = Logger.getLogger(DraftSession.class); protected final UUID userId; protected final UUID playerId; @@ -48,7 +48,8 @@ public class DraftSession { if (user.isPresent()) { if (futureTimeout != null && !futureTimeout.isDone()) { int remaining = (int) futureTimeout.getDelay(TimeUnit.SECONDS); - user.get().fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INIT, draft.getId(), new DraftClientMessage(getDraftPickView(remaining)))); + user.get().fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_INIT, draft.getId(), + new DraftClientMessage(getDraftView(), getDraftPickView(remaining)))); } return true; } @@ -60,8 +61,8 @@ public class DraftSession { if (!killed) { UserManager.instance .getUser(userId). - ifPresent(user -> user.fireCallback( - new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), getDraftView()))); + ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_UPDATE, draft.getId(), + new DraftClientMessage(getDraftView(), null)))); } } @@ -70,7 +71,6 @@ public class DraftSession { UserManager.instance .getUser(userId) .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_OVER, draft.getId()))); - } } @@ -79,7 +79,8 @@ public class DraftSession { setupTimeout(timeout); UserManager.instance .getUser(userId) - .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_PICK, draft.getId(), new DraftClientMessage(getDraftPickView(timeout))))); + .ifPresent(user -> user.fireCallback(new ClientCallback(ClientCallbackMethod.DRAFT_PICK, draft.getId(), + new DraftClientMessage(getDraftView(), getDraftPickView(timeout))))); } } diff --git a/Mage.Server/src/main/java/mage/server/game/GameController.java b/Mage.Server/src/main/java/mage/server/game/GameController.java index b3a1f6d7d1..8ec068a48e 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameController.java +++ b/Mage.Server/src/main/java/mage/server/game/GameController.java @@ -1,13 +1,5 @@ package mage.server.game; -import java.io.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.concurrent.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.zip.GZIPOutputStream; import mage.MageException; import mage.abilities.Ability; import mage.abilities.common.PassAbility; @@ -21,11 +13,7 @@ import mage.choices.Choice; import mage.constants.ManaType; import mage.constants.PlayerAction; import mage.constants.Zone; -import mage.game.Game; -import mage.game.GameException; -import mage.game.GameOptions; -import mage.game.GameState; -import mage.game.Table; +import mage.game.*; import mage.game.command.Plane; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; @@ -47,11 +35,23 @@ import mage.view.ChatMessage.MessageColor; import mage.view.ChatMessage.MessageType; import org.apache.log4j.Logger; +import java.io.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.*; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.zip.GZIPOutputStream; + /** * @author BetaSteward_at_googlemail.com */ public class GameController implements GameCallback { + private static final int GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS = 15; // checks and inform players about joining status + private static final int GAME_TIMEOUTS_CANCEL_PLAYER_GAME_JOINING_AFTER_INACTIVE_SECS = 4 * 60; // leave player from game if it don't join and inactive on server + private static final ExecutorService gameExecutor = ThreadExecutor.instance.getGameExecutor(); private static final Logger logger = Logger.getLogger(GameController.class); @@ -229,7 +229,7 @@ public class GameController implements GameCallback { } catch (Exception ex) { logger.fatal("Send info about player not joined yet:", ex); } - }, 15, 15, TimeUnit.SECONDS); + }, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, GAME_TIMEOUTS_CHECK_JOINING_STATUS_EVERY_SECS, TimeUnit.SECONDS); checkStart(); } @@ -323,6 +323,7 @@ public class GameController implements GameCallback { } private void sendInfoAboutPlayersNotJoinedYet() { + // runs every 15 secs untill all players join for (Player player : game.getPlayers().values()) { if (!player.hasLeft() && player.isHuman()) { Optional requestedUser = getUserByPlayerId(player.getId()); @@ -336,12 +337,12 @@ public class GameController implements GameCallback { logger.debug("Player " + player.getName() + " (disconnected) has joined gameId: " + game.getId()); } ChatManager.instance.broadcast(chatId, player.getName(), user.getPingInfo() + " is pending to join the game", MessageColor.BLUE, true, ChatMessage.MessageType.STATUS, null); - if (user.getSecondsDisconnected() > 240) { + if (user.getSecondsDisconnected() > GAME_TIMEOUTS_CANCEL_PLAYER_GAME_JOINING_AFTER_INACTIVE_SECS) { + // TODO: 2019.04.22 - if user playing another game on server but not joining (that's the reason?), then that's check will never trigger // Cancel player join possibility lately after 4 minutes logger.debug("Player " + player.getName() + " - canceled game (after 240 seconds) gameId: " + game.getId()); player.leave(); } - } } else if (!player.hasLeft()) { logger.debug("Player " + player.getName() + " canceled game (no user) gameId: " + game.getId()); @@ -627,7 +628,7 @@ public class GameController implements GameCallback { for (MatchPlayer p : TableManager.instance.getTable(tableId).getMatch().getPlayers()) { if (p.getPlayer().getId().equals(userIdRequester)) { Optional u = UserManager.instance.getUser(origId); - if (u != null && u.isPresent() && p.getDeck() != null) { + if (u.isPresent() && p.getDeck() != null) { u.get().ccViewLimitedDeck(p.getDeck(), tableId, requestsOpen, true); } } @@ -1172,7 +1173,13 @@ public class GameController implements GameCallback { return sb.toString(); } + private String getName(Player player) { + return player != null ? player.getName() : "-"; + } + public String attemptToFixGame() { + // try to fix disconnects + if (game == null) { return ""; } @@ -1185,15 +1192,14 @@ public class GameController implements GameCallback { sb.append(state); boolean fixedAlready = false; - sb.append("
    Active player is: "); - sb.append(game.getPlayer(state.getActivePlayerId()).getName()); + Player activePlayer = game.getPlayer(state.getActivePlayerId()); + + // fix active + sb.append("
    Checking active player: " + getName(activePlayer)); + if (activePlayer != null && activePlayer.hasLeft()) { + sb.append("
    Found disconnected player! Concede..."); + activePlayer.concede(game); - PassAbility pass = new PassAbility(); - if (game.getPlayer(state.getActivePlayerId()).hasLeft()) { - Player p = game.getPlayer(state.getActivePlayerId()); - if (p != null) { - p.concede(game); - } Phase currentPhase = game.getPhase(); if (currentPhase != null) { currentPhase.getStep().skipStep(game, state.getActivePlayerId()); @@ -1205,9 +1211,11 @@ public class GameController implements GameCallback { sb.append("
    Active player has left"); } - sb.append("
    getChoosingPlayerId: "); + // fix lost choosing dialog + sb.append("
    Checking choosing player: " + getName(game.getPlayer(state.getChoosingPlayerId()))); if (state.getChoosingPlayerId() != null) { if (game.getPlayer(state.getChoosingPlayerId()).hasLeft()) { + sb.append("
    Found disconnected player! Concede..."); Player p = game.getPlayer(state.getChoosingPlayerId()); if (p != null) { p.concede(game); @@ -1224,9 +1232,11 @@ public class GameController implements GameCallback { } } - sb.append("
    Player with Priority is: "); + // fix lost priority + sb.append("
    Checking priority player: " + getName(game.getPlayer(state.getPriorityPlayerId()))); if (state.getPriorityPlayerId() != null) { - if (game.getPlayer(state.getPriorityPlayerId()).hasLeft()) { + if (game.getPlayer(state.getPriorityPlayerId()).hasLeft()) { + sb.append("
    Found disconnected player! Concede..."); Player p = game.getPlayer(state.getPriorityPlayerId()); if (p != null) { p.concede(game); @@ -1242,7 +1252,8 @@ public class GameController implements GameCallback { sb.append("
    "); } - sb.append("
    Future Timeout:"); + // fix timeout + sb.append("
    Checking Future Timeout: "); if (futureTimeout != null) { sb.append("Cancelled?="); sb.append(futureTimeout.isCancelled()); @@ -1251,6 +1262,7 @@ public class GameController implements GameCallback { sb.append(",,,GetDelay?="); sb.append((int) futureTimeout.getDelay(TimeUnit.SECONDS)); if ((int) futureTimeout.getDelay(TimeUnit.SECONDS) < 25) { + PassAbility pass = new PassAbility(); game.endTurn(pass); sb.append("
    Forcibly passing the turn!"); } @@ -1260,5 +1272,4 @@ public class GameController implements GameCallback { sb.append(""); return sb.toString(); } - } diff --git a/Mage.Server/src/main/java/mage/server/game/GameManager.java b/Mage.Server/src/main/java/mage/server/game/GameManager.java index eb5e16b5a5..15884f453c 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GameManager.java @@ -1,6 +1,12 @@ - package mage.server.game; +import mage.cards.decks.DeckCardLists; +import mage.constants.ManaType; +import mage.constants.PlayerAction; +import mage.game.Game; +import mage.game.GameOptions; +import mage.view.GameView; + import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -9,15 +15,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -import mage.cards.decks.DeckCardLists; -import mage.constants.ManaType; -import mage.constants.PlayerAction; -import mage.game.Game; -import mage.game.GameOptions; -import mage.view.GameView; /** - * * @author BetaSteward_at_googlemail.com */ public enum GameManager { @@ -38,15 +37,25 @@ public enum GameManager { return gameController.getSessionId(); } + private GameController getGameControllerSafe(UUID gameId) { + final Lock r = gameControllersLock.readLock(); + r.lock(); + try { + return gameControllers.get(gameId); + } finally { + r.unlock(); + } + } + public void joinGame(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.join(userId); } } public Optional getChatId(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return Optional.of(gameController.getChatId()); } @@ -54,56 +63,56 @@ public enum GameManager { } public void sendPlayerUUID(UUID gameId, UUID userId, UUID data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerUUID(userId, data); } } public void sendPlayerString(UUID gameId, UUID userId, String data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerString(userId, data); } } public void sendPlayerManaType(UUID gameId, UUID playerId, UUID userId, ManaType data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerManaType(userId, playerId, data); } } public void sendPlayerBoolean(UUID gameId, UUID userId, Boolean data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerBoolean(userId, data); } } public void sendPlayerInteger(UUID gameId, UUID userId, Integer data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerInteger(userId, data); } } public void quitMatch(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.quitMatch(userId); } } public void sendPlayerAction(PlayerAction playerAction, UUID gameId, UUID userId, Object data) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.sendPlayerAction(playerAction, userId, data); } } public boolean watchGame(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.watch(userId); } @@ -111,21 +120,21 @@ public enum GameManager { } public void stopWatching(UUID gameId, UUID userId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.stopWatching(userId); } } public void cheat(UUID gameId, UUID userId, UUID playerId, DeckCardLists deckList) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.cheat(userId, playerId, deckList); } } public boolean cheat(UUID gameId, UUID userId, UUID playerId, String cardName) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.cheat(userId, playerId, cardName); } @@ -133,7 +142,7 @@ public enum GameManager { } public void removeGame(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { gameController.cleanUp(); final Lock w = gameControllersLock.writeLock(); @@ -147,15 +156,15 @@ public enum GameManager { } public boolean saveGame(UUID gameId) { - GameController gameController = gameControllers.get(gameId); + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.saveGame(); } return false; } - public GameView getGameView(UUID gameId, UUID userId, UUID playerId) { - GameController gameController = gameControllers.get(gameId); + public GameView getGameView(UUID gameId, UUID playerId) { + GameController gameController = getGameControllerSafe(gameId); if (gameController != null) { return gameController.getGameView(playerId); } @@ -163,7 +172,7 @@ public enum GameManager { } public int getNumberActiveGames() { - return gameControllers.size(); + return getGameController().size(); } public Map getGameController() { diff --git a/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java b/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java index daa075be50..086a1cc04d 100644 --- a/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java +++ b/Mage.Server/src/main/java/mage/server/game/GameSessionWatcher.java @@ -25,7 +25,7 @@ import java.util.UUID; */ public class GameSessionWatcher { - protected final static Logger logger = Logger.getLogger(GameSessionWatcher.class); + protected static final Logger logger = Logger.getLogger(GameSessionWatcher.class); protected final UUID userId; protected final Game game; diff --git a/Mage.Server/src/main/java/mage/server/game/GamesRoomManager.java b/Mage.Server/src/main/java/mage/server/game/GamesRoomManager.java index 1472a40c1b..83e78ed57e 100644 --- a/Mage.Server/src/main/java/mage/server/game/GamesRoomManager.java +++ b/Mage.Server/src/main/java/mage/server/game/GamesRoomManager.java @@ -2,6 +2,8 @@ package mage.server.game; +import org.apache.log4j.Logger; + import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -14,6 +16,7 @@ public enum GamesRoomManager { private final ConcurrentHashMap rooms = new ConcurrentHashMap<>(); private final UUID mainRoomId; + private static final Logger logger = Logger.getLogger(GamesRoomManager.class); GamesRoomManager() { @@ -36,6 +39,7 @@ public enum GamesRoomManager { if(rooms.containsKey(roomId)) { return Optional.of(rooms.get(roomId)); } + logger.error("room not found : " + roomId); return Optional.empty(); } diff --git a/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java b/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java index c5fec8d5c9..d6d7997c41 100644 --- a/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java +++ b/Mage.Server/src/main/java/mage/server/record/TableRecordRepository.java @@ -4,15 +4,18 @@ import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; -import java.io.File; -import java.sql.SQLException; -import java.util.List; import mage.cards.repository.RepositoryUtil; import org.apache.log4j.Logger; +import java.io.File; +import java.sql.SQLException; +import java.util.Collections; +import java.util.List; + public enum TableRecordRepository { instance; @@ -55,19 +58,19 @@ public enum TableRecordRepository { public List getAfter(long endTimeMs) { try { QueryBuilder qb = dao.queryBuilder(); - qb.where().gt("endTimeMs", endTimeMs); + qb.where().gt("endTimeMs", new SelectArg(endTimeMs)); qb.orderBy("endTimeMs", true); return dao.query(qb.prepare()); } catch (SQLException ex) { Logger.getLogger(TableRecordRepository.class).error("Error getting table_records from DB - ", ex); } - return null; + return Collections.emptyList(); } public void closeDB() { try { if (dao != null && dao.getConnectionSource() != null) { - DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(dao.getTableName()); conn.executeStatement("shutdown compact", 0); } } catch (SQLException ex) { diff --git a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java index b99eeed302..0bbe5cab29 100644 --- a/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java +++ b/Mage.Server/src/main/java/mage/server/record/UserStatsRepository.java @@ -4,6 +4,7 @@ import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.stmt.QueryBuilder; +import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; @@ -15,10 +16,7 @@ import org.apache.log4j.Logger; import java.io.File; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; public enum UserStatsRepository { @@ -70,7 +68,7 @@ public enum UserStatsRepository { public UserStats getUser(String userName) { try { QueryBuilder qb = dao.queryBuilder(); - qb.limit(1L).where().eq("userName", userName); + qb.limit(1L).where().eq("userName", new SelectArg(userName)); List users = dao.query(qb.prepare()); if (!users.isEmpty()) { return users.get(0); @@ -88,17 +86,17 @@ public enum UserStatsRepository { } catch (SQLException ex) { Logger.getLogger(UserStatsRepository.class).error("Error getting all users from DB - ", ex); } - return null; + return Collections.emptyList(); } public long getLatestEndTimeMs() { try { - QueryBuilder qb = dao.queryBuilder(); + QueryBuilder qb = dao.queryBuilder(); qb.orderBy("endTimeMs", false).limit(1L); - List users = dao.query(qb.prepare()); + List users = dao.query(qb.prepare()); if (!users.isEmpty()) { - return users.get(0).getEndTimeMs(); - } + return users.get(0).getEndTimeMs(); + } } catch (SQLException ex) { Logger.getLogger(UserStatsRepository.class).error("Error getting the latest end time from DB - ", ex); } @@ -110,7 +108,7 @@ public enum UserStatsRepository { public List updateUserStats() { Set updatedUsers = new HashSet<>(); // Lock the DB so that no other updateUserStats runs at the same time. - synchronized(this) { + synchronized (this) { long latestEndTimeMs = this.getLatestEndTimeMs(); List records = TableRecordRepository.instance.getAfter(latestEndTimeMs); for (TableRecord record : records) { @@ -125,9 +123,9 @@ public enum UserStatsRepository { for (ResultProtos.MatchPlayerProto player : match.getPlayersList()) { UserStats userStats = this.getUser(player.getName()); ResultProtos.UserStatsProto proto = - userStats != null - ? userStats.getProto() - : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); + userStats != null + ? userStats.getProto() + : ResultProtos.UserStatsProto.newBuilder().setName(player.getName()).build(); ResultProtos.UserStatsProto.Builder builder = ResultProtos.UserStatsProto.newBuilder(proto) .setMatches(proto.getMatches() + 1); switch (player.getQuit()) { @@ -369,7 +367,7 @@ public enum UserStatsRepository { public void closeDB() { try { if (dao != null && dao.getConnectionSource() != null) { - DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(); + DatabaseConnection conn = dao.getConnectionSource().getReadWriteConnection(dao.getTableName()); conn.executeStatement("shutdown compact", 0); } } catch (SQLException ex) { diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentManager.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentManager.java index d9a611d26c..da4844fed9 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentManager.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentManager.java @@ -16,8 +16,8 @@ public enum TournamentManager { instance; private final ConcurrentHashMap controllers = new ConcurrentHashMap<>(); - public TournamentController getTournamentController(UUID tournamentId) { - return controllers.get(tournamentId); + public Optional getTournamentController(UUID tournamentId) { + return Optional.ofNullable(controllers.get(tournamentId)); } public void createTournamentSession(Tournament tournament, ConcurrentHashMap userPlayerMap, UUID tableId) { diff --git a/Mage.Server/src/main/java/mage/server/tournament/TournamentSession.java b/Mage.Server/src/main/java/mage/server/tournament/TournamentSession.java index c93b8a056f..3317165991 100644 --- a/Mage.Server/src/main/java/mage/server/tournament/TournamentSession.java +++ b/Mage.Server/src/main/java/mage/server/tournament/TournamentSession.java @@ -21,7 +21,7 @@ import org.apache.log4j.Logger; */ public class TournamentSession { - protected final static Logger logger = Logger.getLogger(TournamentSession.class); + protected static final Logger logger = Logger.getLogger(TournamentSession.class); protected final UUID userId; protected final UUID playerId; diff --git a/Mage.Server/src/main/java/mage/server/util/Config.java b/Mage.Server/src/main/java/mage/server/util/Config.java index d21319ccba..73a1cf7a82 100644 --- a/Mage.Server/src/main/java/mage/server/util/Config.java +++ b/Mage.Server/src/main/java/mage/server/util/Config.java @@ -12,6 +12,8 @@ import org.apache.log4j.Logger; */ public final class Config { + private Config(){} + private static final Logger logger = Logger.getLogger(Config.class); static { diff --git a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java index 7c822046cd..b80e851806 100644 --- a/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/ServerMessagesUtil.java @@ -8,6 +8,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Scanner; import java.util.concurrent.Executors; @@ -52,7 +53,6 @@ public enum ServerMessagesUtil { } - public List getMessages() { lock.readLock().lock(); try { @@ -66,9 +66,7 @@ public enum ServerMessagesUtil { log.debug("Reading server messages..."); List motdMessages = readFromFile(); List newMessages = new ArrayList<>(); - if (motdMessages != null) { - newMessages.addAll(motdMessages); - } + newMessages.addAll(motdMessages); newMessages.add(getServerStatistics()); newMessages.add(getServerStatistics2()); @@ -83,7 +81,7 @@ public enum ServerMessagesUtil { private List readFromFile() { if (ignore) { - return null; + return Collections.emptyList(); } File externalFile = null; if (pathToExternalMessages != null) { @@ -120,23 +118,20 @@ public enum ServerMessagesUtil { } if (is == null) { log.warn("Couldn't find server.msg"); - return null; + return Collections.emptyList(); } - Scanner scanner = null; List newMessages = new ArrayList<>(); - try { - scanner = new Scanner(is); + try(Scanner scanner = new Scanner(is)) { while (scanner.hasNextLine()) { String message = scanner.nextLine(); if (!message.trim().isEmpty()) { newMessages.add(message.trim()); } } - } catch(Exception e) { - log.error(e,e); + } catch (Exception e) { + log.error(e, e); } finally { - StreamUtils.closeQuietly(scanner); StreamUtils.closeQuietly(is); } return newMessages; @@ -168,7 +163,7 @@ public enum ServerMessagesUtil { return statistics.toString(); } -// private Timer timer = new Timer(1000 * 60, new ActionListener() { + // private Timer timer = new Timer(1000 * 60, new ActionListener() { // public void actionPerformed(ActionEvent e) { // reloadMessages(); // } diff --git a/Mage.Server/src/main/java/mage/server/util/Splitter.java b/Mage.Server/src/main/java/mage/server/util/Splitter.java index 2a1b1f980d..6290a80d47 100644 --- a/Mage.Server/src/main/java/mage/server/util/Splitter.java +++ b/Mage.Server/src/main/java/mage/server/util/Splitter.java @@ -11,6 +11,8 @@ import mage.players.Player; */ public final class Splitter { + private Splitter(){} + public static List split(Game game, UUID playerId) { List players = new ArrayList<>(); //players.add(playerId); // add original player diff --git a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java index 395becdf94..382021e4cf 100644 --- a/Mage.Server/src/main/java/mage/server/util/SystemUtil.java +++ b/Mage.Server/src/main/java/mage/server/util/SystemUtil.java @@ -1,35 +1,38 @@ package mage.server.util; +import mage.abilities.Ability; +import mage.cards.Card; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.RandomUtil; + import java.io.File; import java.lang.reflect.Constructor; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; -import java.util.List; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; -import mage.abilities.Ability; -import mage.cards.Card; -import mage.cards.Cards; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; -import mage.util.RandomUtil; - /** * @author JayDi85 */ public final class SystemUtil { + private SystemUtil(){} + public static final DateFormat dateFormat = new SimpleDateFormat("yy-M-dd HH:mm:ss"); private static final String INIT_FILE_PATH = "config" + File.separator + "init.txt"; @@ -111,12 +114,15 @@ public final class SystemUtil { for (UUID cardID : cardsList) { Card card = game.getCard(cardID); + if (card == null) { + continue; + } // basic info (card + set) String cardInfo = card.getName() + " - " + card.getExpansionSetCode(); // optional info - ArrayList resInfo = new ArrayList<>(); + List resInfo = new ArrayList<>(); for (String param : commandParams) { switch (param) { case PARAM_COLOR_COST: @@ -143,7 +149,7 @@ public final class SystemUtil { } } - if (resInfo.size() > 0) { + if (!resInfo.isEmpty()) { cardInfo += ": " + resInfo.stream().collect(Collectors.joining("; ")); } @@ -225,7 +231,7 @@ public final class SystemUtil { *
    * Implementation note:
    * 1. Read init.txt line by line
    - * 2. Parse line using for searching groups like: [group 1] + * 2. Parse line using for searching groups like: [group 1] * 3. Parse line using the following format: line ::= * :::
    * 4. If zone equals to 'hand', add card to player's library
    @@ -432,6 +438,36 @@ public final class SystemUtil { game.addPlane((mage.game.command.Plane) plane, null, player.getId()); continue; } + } else if ("loyalty".equalsIgnoreCase(command.zone)) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents(player.getId())) { + if (perm.getName().equals(command.cardName) && perm.getCardType().contains(CardType.PLANESWALKER)) { + perm.addCounters(CounterType.LOYALTY.createInstance(command.Amount), null, game); + } + } + continue; + } else if ("stack".equalsIgnoreCase(command.zone)) { + // simple cast (without targets or modes) + + // find card info + CardInfo cardInfo = CardRepository.instance.findCard(command.cardName); + if (cardInfo == null) { + logger.warn("Unknown card for stack command [" + command.cardName + "]: " + line); + continue; + } + + // put card to game + Set cardsToLoad = new HashSet<>(); + for (int i = 0; i < command.Amount; i++) { + cardsToLoad.add(cardInfo.getCard()); + } + game.loadCards(cardsToLoad, player.getId()); + + // move card from exile to stack + for (Card card : cardsToLoad) { + swapWithAnyCard(game, player, card, Zone.STACK); + } + + continue; } Zone gameZone; @@ -505,6 +541,8 @@ public final class SystemUtil { game.getExile().getPermanentExile().remove(card); player.getLibrary().putOnTop(card, game); break; + case STACK: + card.cast(game, Zone.EXILED, card.getSpellAbility(), player.getId()); default: card.moveToZone(zone, null, game, false); } @@ -519,12 +557,9 @@ public final class SystemUtil { * @return */ private static Optional findPlayer(Game game, String name) { - for (Player player : game.getPlayers().values()) { - if (player.getName().equals(name)) { - return Optional.of(player); - } - } - return Optional.empty(); + return game.getPlayers().values().stream() + .filter(player -> player.getName().equals(name)).findFirst(); + } public static String sanitize(String input) { @@ -537,8 +572,8 @@ public final class SystemUtil { /** * Get a diff between two dates * - * @param date1 the oldest date - * @param date2 the newest date + * @param date1 the oldest date + * @param date2 the newest date * @param timeUnit the unit in which you want the diff * @return the diff value, in the provided unit */ diff --git a/Mage.Sets/pom.xml b/Mage.Sets/pom.xml index f478419c23..0b31d3522d 100644 --- a/Mage.Sets/pom.xml +++ b/Mage.Sets/pom.xml @@ -7,10 +7,9 @@ org.mage mage-root - 1.4.31 + 1.4.35 - org.mage mage-sets jar Mage Sets diff --git a/Mage.Sets/src/mage/cards/a/AAT1.java b/Mage.Sets/src/mage/cards/a/AAT1.java index 173888758e..3e17724d22 100644 --- a/Mage.Sets/src/mage/cards/a/AAT1.java +++ b/Mage.Sets/src/mage/cards/a/AAT1.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -21,8 +19,9 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Styxo */ public final class AAT1 extends CardImpl { @@ -74,7 +73,8 @@ public final class AAT1 extends CardImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Card card = game.getCard(event.getTargetId()); - if (event.getPlayerId().equals(game.getControllerId(sourceId)) + if (card != null + && event.getPlayerId().equals(game.getControllerId(sourceId)) && card.isCreature() && game.getState().getZone(card.getId()) == Zone.GRAVEYARD && event.getData().equals("repair")) { diff --git a/Mage.Sets/src/mage/cards/a/AbandonHope.java b/Mage.Sets/src/mage/cards/a/AbandonHope.java index a89f540751..635917a898 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonHope.java +++ b/Mage.Sets/src/mage/cards/a/AbandonHope.java @@ -1,26 +1,26 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.dynamicvalue.common.ManacostVariableValue; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.Game; import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author fireshoes */ public final class AbandonHope extends CardImpl { @@ -29,52 +29,35 @@ public final class AbandonHope extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}"); // As an additional cost to cast Abandon Hope, discard X cards. - Ability ability = new SimpleStaticAbility(Zone.ALL, new AbandonHopeRuleEffect()); + Ability ability = new SimpleStaticAbility(Zone.ALL, new InfoEffect("As an additional cost to cast this spell, discard X cards")); ability.setRuleAtTheTop(true); this.addAbility(ability); // Look at target opponent's hand and choose X cards from it. That player discards those cards. - ManacostVariableValue manaX = new ManacostVariableValue(); + ManacostVariableValue manaX = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect(manaX, TargetController.ANY)); this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().setCostAdjuster(AbandonHopeAdjuster.instance); } public AbandonHope(final AbandonHope card) { super(card); } - @Override - public void adjustCosts(Ability ability, Game game) { - int xValue = ability.getManaCostsToPay().getX(); - if (xValue > 0) { - ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, new FilterCard("cards")))); - } - } - @Override public AbandonHope copy() { return new AbandonHope(this); } } -class AbandonHopeRuleEffect extends OneShotEffect { - - public AbandonHopeRuleEffect() { - super(Outcome.Benefit); - this.staticText = "As an additional cost to cast this spell, discard X cards"; - } - - public AbandonHopeRuleEffect(final AbandonHopeRuleEffect effect) { - super(effect); - } +enum AbandonHopeAdjuster implements CostAdjuster { + instance; @Override - public AbandonHopeRuleEffect copy() { - return new AbandonHopeRuleEffect(this); + public void adjustCosts(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + if (xValue > 0) { + ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, StaticFilters.FILTER_CARD_CARDS))); + } } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java index 81a7e42baf..e66954c891 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java +++ b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java @@ -1,25 +1,12 @@ package mage.cards.a; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneAllEffect; import mage.abilities.keyword.CyclingAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.WatcherScope; -import mage.constants.Zone; +import mage.cards.*; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; @@ -31,8 +18,12 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class AbandonedSarcophagus extends CardImpl { @@ -55,7 +46,7 @@ public final class AbandonedSarcophagus extends CardImpl { } - public AbandonedSarcophagus(final AbandonedSarcophagus card) { + private AbandonedSarcophagus(final AbandonedSarcophagus card) { super(card); } @@ -67,15 +58,12 @@ public final class AbandonedSarcophagus extends CardImpl { class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { - boolean cardHasCycling; - boolean cardWasCycledThisTurn; - - public AbandonedSarcophagusReplacementEffect() { + AbandonedSarcophagusReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Exile); staticText = "If a card with cycling would be put into your graveyard from anywhere and it wasn't cycled, exile it instead"; } - public AbandonedSarcophagusReplacementEffect(final AbandonedSarcophagusReplacementEffect effect) { + private AbandonedSarcophagusReplacementEffect(final AbandonedSarcophagusReplacementEffect effect) { super(effect); } @@ -112,33 +100,33 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - cardWasCycledThisTurn = false; - cardHasCycling = false; - if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD - && !game.isSimulation()) { - Player controller = game.getPlayer(source.getControllerId()); - AbandonedSarcophagusWatcher watcher = (AbandonedSarcophagusWatcher) game.getState().getWatchers().get(AbandonedSarcophagusWatcher.class.getSimpleName()); - Card card = game.getCard(event.getTargetId()); - if (card != null - && watcher != null - && card.isOwnedBy(controller.getId())) { - for (Ability ability : card.getAbilities()) { - if (ability instanceof CyclingAbility) { - cardHasCycling = true; - } - } - Cards cards = watcher.getCardsCycledThisTurn(controller.getId()); - for (Card c : cards.getCards(game)) { - if (c == card) { - cardWasCycledThisTurn = true; - watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed - } - } - return (!cardWasCycledThisTurn - && cardHasCycling); + boolean cardWasCycledThisTurn = false; + boolean cardHasCycling = false; + if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) || game.isSimulation()) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class); + Card card = game.getCard(event.getTargetId()); + if (card == null + || controller == null + || watcher == null + || !card.isOwnedBy(controller.getId())) { + return false; + } + for (Ability ability : card.getAbilities()) { + if (ability instanceof CyclingAbility) { + cardHasCycling = true; } } - return false; + Cards cards = watcher.getCardsCycledThisTurn(controller.getId()); + for (Card c : cards.getCards(game)) { + if (c == card) { + cardWasCycledThisTurn = true; + watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed + } + } + return !cardWasCycledThisTurn && cardHasCycling; } } @@ -146,11 +134,11 @@ class AbandonedSarcophagusWatcher extends Watcher { private final Map cycledCardsThisTurn = new HashMap<>(); - public AbandonedSarcophagusWatcher() { - super(AbandonedSarcophagusWatcher.class.getSimpleName(), WatcherScope.GAME); + AbandonedSarcophagusWatcher() { + super(WatcherScope.GAME); } - public AbandonedSarcophagusWatcher(final AbandonedSarcophagusWatcher watcher) { + private AbandonedSarcophagusWatcher(final AbandonedSarcophagusWatcher watcher) { super(watcher); for (Entry entry : watcher.cycledCardsThisTurn.entrySet()) { cycledCardsThisTurn.put(entry.getKey(), entry.getValue().copy()); diff --git a/Mage.Sets/src/mage/cards/a/Abeyance.java b/Mage.Sets/src/mage/cards/a/Abeyance.java index d2692d74fd..2d44f2abf1 100644 --- a/Mage.Sets/src/mage/cards/a/Abeyance.java +++ b/Mage.Sets/src/mage/cards/a/Abeyance.java @@ -1,8 +1,5 @@ - package mage.cards.a; -import java.util.Optional; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; @@ -17,8 +14,10 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.target.TargetPlayer; +import java.util.Optional; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Abeyance extends CardImpl { @@ -46,12 +45,13 @@ public final class Abeyance extends CardImpl { class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl { - public AbeyanceEffect() { + AbeyanceEffect() { super(Duration.EndOfTurn, Outcome.Detriment); - staticText = "Until end of turn, target player can't cast instant or sorcery spells, and that player can't activate abilities that aren't mana abilities"; + staticText = "Until end of turn, target player can't cast instant or sorcery spells, " + + "and that player can't activate abilities that aren't mana abilities"; } - public AbeyanceEffect(final AbeyanceEffect effect) { + private AbeyanceEffect(final AbeyanceEffect effect) { super(effect); } @@ -69,26 +69,29 @@ class AbeyanceEffect extends ContinuousRuleModifyingEffectImpl { public String getInfoMessage(Ability source, GameEvent event, Game game) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { - return "You can't cast instant or sorcery spells or activate abilities that aren't mana abilities this turn (" + mageObject.getIdName() + ")."; + return "You can't cast instant or sorcery spells or activate abilities " + + "that aren't mana abilities this turn (" + mageObject.getIdName() + ")."; } return null; } @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (source.getFirstTarget() != null && source.getFirstTarget().equals(event.getPlayerId())) { - MageObject object = game.getObject(event.getSourceId()); - if (event.getType() == GameEvent.EventType.CAST_SPELL) { - if (object.isInstant() || object.isSorcery()) { - return true; - } - } - if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { - Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); - if (ability.isPresent() && !(ability.get() instanceof ActivatedManaAbilityImpl)) { - return true; - } - } + if (source.getFirstTarget() != null + && source.getFirstTarget().equals(event.getPlayerId())) { + return false; + } + MageObject object = game.getObject(event.getSourceId()); + if (object == null) { + return false; + } + if (event.getType() == GameEvent.EventType.CAST_SPELL + && (object.isInstant() || object.isSorcery())) { + return true; + } + if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { + Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); + return ability.isPresent() && !(ability.get() instanceof ActivatedManaAbilityImpl); } return false; } diff --git a/Mage.Sets/src/mage/cards/a/Abrade.java b/Mage.Sets/src/mage/cards/a/Abrade.java index 04f0720ef7..77c030fbbe 100644 --- a/Mage.Sets/src/mage/cards/a/Abrade.java +++ b/Mage.Sets/src/mage/cards/a/Abrade.java @@ -26,8 +26,8 @@ public final class Abrade extends CardImpl { // Destroy target artifact. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java b/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java index 63f6f8c100..187ee463f8 100644 --- a/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java +++ b/Mage.Sets/src/mage/cards/a/AbunaAcolyte.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class AbunaAcolyte extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); @@ -45,7 +45,7 @@ public final class AbunaAcolyte extends CardImpl { this.addAbility(ability2); } - public AbunaAcolyte(final AbunaAcolyte card) { + private AbunaAcolyte(final AbunaAcolyte card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AbunasChant.java b/Mage.Sets/src/mage/cards/a/AbunasChant.java index 77dbd3358c..f4b6f4438f 100644 --- a/Mage.Sets/src/mage/cards/a/AbunasChant.java +++ b/Mage.Sets/src/mage/cards/a/AbunasChant.java @@ -29,8 +29,8 @@ public final class AbunasChant extends CardImpl { this.getSpellAbility().addEffect(new GainLifeEffect(5)); //or prevent the next 5 damage that would be dealt to target creature this turn. Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 5)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} this.addAbility(new EntwineAbility("{2}")); diff --git a/Mage.Sets/src/mage/cards/a/AbzanAscendancy.java b/Mage.Sets/src/mage/cards/a/AbzanAscendancy.java index c64aeee0fb..0d84ef3c1e 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanAscendancy.java +++ b/Mage.Sets/src/mage/cards/a/AbzanAscendancy.java @@ -28,7 +28,7 @@ public final class AbzanAscendancy extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public AbzanAscendancy(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AbzanBattlePriest.java b/Mage.Sets/src/mage/cards/a/AbzanBattlePriest.java index c902e0f16b..878fb3b4d6 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanBattlePriest.java +++ b/Mage.Sets/src/mage/cards/a/AbzanBattlePriest.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -17,23 +16,23 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.CounterPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AbzanBattlePriest extends CardImpl { private static final FilterPermanent filter = new FilterPermanent(); + static { filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new CounterPredicate(CounterType.P1P1)); } - static final String rule = "Each creature you control with a +1/+1 counter on it has lifelink"; - public AbzanBattlePriest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); @@ -42,9 +41,15 @@ public final class AbzanBattlePriest extends CardImpl { // Outlast {W} this.addAbility(new OutlastAbility(new ManaCostsImpl<>("{W}"))); - + // Each creature you control with a +1/+1 counter on it has lifelink. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, filter, rule))); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAllEffect( + LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, + filter, "Each creature you control with a +1/+1 counter on it has lifelink" + ) + )); } public AbzanBattlePriest(final AbzanBattlePriest card) { diff --git a/Mage.Sets/src/mage/cards/a/AbzanCharm.java b/Mage.Sets/src/mage/cards/a/AbzanCharm.java index 18c2577c1e..a9519adabb 100644 --- a/Mage.Sets/src/mage/cards/a/AbzanCharm.java +++ b/Mage.Sets/src/mage/cards/a/AbzanCharm.java @@ -39,14 +39,14 @@ public final class AbzanCharm extends CardImpl { // *You draw two cards and you lose 2 life Mode mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(2)); - mode.getEffects().add(new LoseLifeSourceControllerEffect(2)); + mode.addEffect(new DrawCardSourceControllerEffect(2)); + mode.addEffect(new LoseLifeSourceControllerEffect(2)); this.getSpellAbility().addMode(mode); // *Distribute two +1/+1 counters among one or two target creatures. mode = new Mode(); - mode.getEffects().add(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures")); - mode.getTargets().add(new TargetCreaturePermanentAmount(2)); + mode.addEffect(new DistributeCountersEffect(CounterType.P1P1, 2, false, "one or two target creatures")); + mode.addTarget(new TargetCreaturePermanentAmount(2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AccursedHorde.java b/Mage.Sets/src/mage/cards/a/AccursedHorde.java index ec9d3d27b6..29c99ad77b 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedHorde.java +++ b/Mage.Sets/src/mage/cards/a/AccursedHorde.java @@ -24,7 +24,7 @@ import mage.target.common.TargetAttackingCreature; */ public final class AccursedHorde extends CardImpl { - private final static FilterAttackingCreature filter = new FilterAttackingCreature("attacking Zombie"); + private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking Zombie"); static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); @@ -43,7 +43,7 @@ public final class AccursedHorde extends CardImpl { this.addAbility(ability); } - public AccursedHorde(final AccursedHorde card) { + private AccursedHorde(final AccursedHorde card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AccursedWitch.java b/Mage.Sets/src/mage/cards/a/AccursedWitch.java index 1cefa7ff16..bcde8821e6 100644 --- a/Mage.Sets/src/mage/cards/a/AccursedWitch.java +++ b/Mage.Sets/src/mage/cards/a/AccursedWitch.java @@ -1,8 +1,6 @@ package mage.cards.a; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; @@ -20,8 +18,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import mage.target.common.TargetOpponent; import mage.util.CardUtil; +import java.util.UUID; + /** * @author halljared */ @@ -41,10 +42,12 @@ public final class AccursedWitch extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AccursedWitchSpellsCostReductionEffect())); // When Accursed Witch dies, return it to the battlefield transformed under your control attached to target opponent. this.addAbility(new TransformAbility()); - this.addAbility(new DiesTriggeredAbility(new AccursedWitchReturnTransformedEffect())); + Ability ability = new DiesTriggeredAbility(new AccursedWitchReturnTransformedEffect()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); } - public AccursedWitch(final AccursedWitch card) { + private AccursedWitch(final AccursedWitch card) { super(card); } @@ -56,12 +59,12 @@ public final class AccursedWitch extends CardImpl { class AccursedWitchReturnTransformedEffect extends OneShotEffect { - public AccursedWitchReturnTransformedEffect() { + AccursedWitchReturnTransformedEffect() { super(Outcome.PutCardInPlay); - this.staticText = "Put {this} from your graveyard onto the battlefield transformed"; + this.staticText = "Put {this} from your graveyard onto the battlefield transformed under your control attached to target opponent"; } - public AccursedWitchReturnTransformedEffect(final AccursedWitchReturnTransformedEffect effect) { + private AccursedWitchReturnTransformedEffect(final AccursedWitchReturnTransformedEffect effect) { super(effect); } @@ -73,29 +76,32 @@ class AccursedWitchReturnTransformedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { - game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); - //note: should check for null after game.getCard - Card card = game.getCard(source.getSourceId()); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - } - return true; + Player attachTo = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller == null || !(game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) || attachTo == null) { + return false; } - return false; + game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE); + UUID secondFaceId = game.getCard(source.getSourceId()).getSecondCardFace().getId(); + game.getState().setValue("attachTo:" + secondFaceId, attachTo.getId()); + //note: should check for null after game.getCard + Card card = game.getCard(source.getSourceId()); + if (card != null) { + if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + attachTo.addAttachment(card.getId(), game); + } + } + return true; } } class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl { - public AccursedWitchSpellsCostReductionEffect() { + AccursedWitchSpellsCostReductionEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment, CostModificationType.REDUCE_COST); this.staticText = "Spells your opponents cast that target {this} cost {1} less to cast."; } - protected AccursedWitchSpellsCostReductionEffect(AccursedWitchSpellsCostReductionEffect effect) { + private AccursedWitchSpellsCostReductionEffect(AccursedWitchSpellsCostReductionEffect effect) { super(effect); } @@ -107,17 +113,16 @@ class AccursedWitchSpellsCostReductionEffect extends CostModificationEffectImpl @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if (abilityToModify instanceof SpellAbility) { - if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { - for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { - Mode mode = abilityToModify.getModes().get(modeId); - for (Target target : mode.getTargets()) { - for (UUID targetUUID : target.getTargets()) { - Permanent permanent = game.getPermanent(targetUUID); - if (permanent != null && permanent.getId().equals(source.getSourceId())) { - return true; - } - } + if (!(abilityToModify instanceof SpellAbility) || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { + return false; + } + for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { + Mode mode = abilityToModify.getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetUUID : target.getTargets()) { + Permanent permanent = game.getPermanent(targetUUID); + if (permanent != null && permanent.getId().equals(source.getSourceId())) { + return true; } } } diff --git a/Mage.Sets/src/mage/cards/a/AchHansRun.java b/Mage.Sets/src/mage/cards/a/AchHansRun.java index 14a0b6d200..cbaeab9c00 100644 --- a/Mage.Sets/src/mage/cards/a/AchHansRun.java +++ b/Mage.Sets/src/mage/cards/a/AchHansRun.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -25,8 +24,9 @@ import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class AchHansRun extends CardImpl { @@ -38,7 +38,7 @@ public final class AchHansRun extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new AchHansRunEffect(), TargetController.YOU, true)); } - public AchHansRun(final AchHansRun card) { + private AchHansRun(final AchHansRun card) { super(card); } @@ -50,12 +50,12 @@ public final class AchHansRun extends CardImpl { class AchHansRunEffect extends OneShotEffect { - public AchHansRunEffect() { + AchHansRunEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "you may say \"Ach! Hans, run! It’s the …\" and the name of a creature card. If you do, search your library for a card with that name, put it onto the battlefield, then shuffle your library. That creature gains haste. Exile it at the beginning of the next end step"; } - public AchHansRunEffect(final AchHansRunEffect effect) { + private AchHansRunEffect(final AchHansRunEffect effect) { super(effect); } @@ -67,41 +67,41 @@ class AchHansRunEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ChoiceImpl cardChoice = new ChoiceImpl(true); - cardChoice.setChoices(CardRepository.instance.getCreatureNames()); - cardChoice.setMessage("Choose a creature card name"); - if (controller.choose(Outcome.Detriment, cardChoice, game)) { - String cardName = cardChoice.getChoice(); - if (!game.isSimulation()) { - game.informPlayers(controller.getLogName() + ": \"Ach! Hans, run! It's the " + cardName + "!\""); - } - FilterCard nameFilter = new FilterCard(); - nameFilter.add(new NamePredicate(cardName)); - TargetCardInLibrary target = new TargetCardInLibrary(1, 1, nameFilter); - if (controller.searchLibrary(target, game)) { - Card card = controller.getLibrary().remove(target.getFirstTarget(), game); - if (card != null) { - if (card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - Permanent creature = game.getPermanent(card.getId()); - if (creature != null) { - // gains haste - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature, game)); - game.addEffect(effect, source); - // Exile at begin of next end step - ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); - exileEffect.setTargetPointer(new FixedTarget(creature, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); - game.addDelayedTriggeredAbility(delayedAbility, source); - } - } - } - controller.shuffleLibrary(source, game); - } - return true; - } + if (controller == null) { + return false; } - return false; + ChoiceImpl cardChoice = new ChoiceImpl(true); + cardChoice.setChoices(CardRepository.instance.getCreatureNames()); + cardChoice.setMessage("Choose a creature card name"); + if (!controller.choose(Outcome.Detriment, cardChoice, game)) { + return false; + } + String cardName = cardChoice.getChoice(); + game.informPlayers(controller.getLogName() + ": \"Ach! Hans, run! It's the " + cardName + "!\""); + FilterCard nameFilter = new FilterCard(); + nameFilter.add(new NamePredicate(cardName)); + TargetCardInLibrary target = new TargetCardInLibrary(1, 1, nameFilter); + if (!controller.searchLibrary(target, source, game)) { + return false; + } + Card card = controller.getLibrary().remove(target.getFirstTarget(), game); + if (card == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent creature = game.getPermanent(card.getId()); + if (creature == null) { + return false; + } + // gains haste + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature, game)); + game.addEffect(effect, source); + // Exile at begin of next end step + ExileTargetEffect exileEffect = new ExileTargetEffect(null, null, Zone.BATTLEFIELD); + exileEffect.setTargetPointer(new FixedTarget(creature, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); + controller.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java b/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java index 108c8d3ea8..d6ee3adf34 100644 --- a/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java +++ b/Mage.Sets/src/mage/cards/a/AcidSpewerDragon.java @@ -27,7 +27,7 @@ public final class AcidSpewerDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other Dragon creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/a/AcolytesReward.java b/Mage.Sets/src/mage/cards/a/AcolytesReward.java index 012d5e1cc1..7f48be367e 100644 --- a/Mage.Sets/src/mage/cards/a/AcolytesReward.java +++ b/Mage.Sets/src/mage/cards/a/AcolytesReward.java @@ -98,19 +98,19 @@ class AcolytesRewardEffect extends PreventionEffectImpl { result = true; } if (toPrevent > 0) { - game.informPlayers(new StringBuilder("Acolyte's Reward ").append("prevented ").append(toPrevent).append(" to ").append(targetCreature.getName()).toString()); + game.informPlayers("Acolyte's Reward prevented " + toPrevent + " to " + targetCreature.getName()); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, source.getControllerId(), source.getSourceId(), source.getControllerId(), toPrevent)); Player targetPlayer = game.getPlayer(source.getTargets().get(1).getFirstTarget()); if (targetPlayer != null) { targetPlayer.damage(toPrevent, source.getSourceId(), game, false, true); - game.informPlayers(new StringBuilder("Acolyte's Reward ").append("deals ").append(toPrevent).append(" damage to ").append(targetPlayer.getLogName()).toString()); + game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetPlayer.getLogName()); } else { Permanent targetDamageCreature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (targetDamageCreature != null) { targetDamageCreature.damage(toPrevent, source.getSourceId(), game, false, true); - game.informPlayers(new StringBuilder("Acolyte's Reward ").append("deals ").append(toPrevent).append(" damage to ").append(targetDamageCreature.getName()).toString()); + game.informPlayers("Acolyte's Reward deals " + toPrevent + " damage to " + targetDamageCreature.getName()); } } } diff --git a/Mage.Sets/src/mage/cards/a/Acquire.java b/Mage.Sets/src/mage/cards/a/Acquire.java index 3eb0827a33..53895e0758 100644 --- a/Mage.Sets/src/mage/cards/a/Acquire.java +++ b/Mage.Sets/src/mage/cards/a/Acquire.java @@ -63,7 +63,7 @@ class AcquireEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (opponent != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - controller.searchLibrary(target, game, opponent.getId()); + controller.searchLibrary(target, source, game, opponent.getId()); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/a/ActiveVolcano.java b/Mage.Sets/src/mage/cards/a/ActiveVolcano.java index bd8c4eb432..4497ba90dc 100644 --- a/Mage.Sets/src/mage/cards/a/ActiveVolcano.java +++ b/Mage.Sets/src/mage/cards/a/ActiveVolcano.java @@ -38,8 +38,8 @@ public final class ActiveVolcano extends CardImpl { // or return target Island to its owner's hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetPermanent(filterIsland)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetPermanent(filterIsland)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AdamaroFirstToDesire.java b/Mage.Sets/src/mage/cards/a/AdamaroFirstToDesire.java index a4b80c6083..134eaaabf5 100644 --- a/Mage.Sets/src/mage/cards/a/AdamaroFirstToDesire.java +++ b/Mage.Sets/src/mage/cards/a/AdamaroFirstToDesire.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -14,14 +13,15 @@ import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AdamaroFirstToDesire extends CardImpl { public AdamaroFirstToDesire(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SPIRIT); @@ -46,7 +46,7 @@ class MostCardsInOpponentsHandCount implements DynamicValue { @Override public int calculate(Game game, Ability source, Effect effect) { int maxCards = 0; - for (UUID opponentId: game.getOpponents(source.getControllerId())) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { int cards = opponent.getHand().size(); @@ -60,7 +60,7 @@ class MostCardsInOpponentsHandCount implements DynamicValue { @Override public DynamicValue copy() { - return new mage.abilities.dynamicvalue.common.CardsInControllerHandCount(); + return new MostCardsInOpponentsHandCount(); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java index 1e1341a51e..7c23ced8eb 100644 --- a/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AdaptiveAutomaton.java @@ -20,7 +20,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class AdaptiveAutomaton extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index 5824191414..4c8c7bc6cc 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -34,7 +34,7 @@ public final class AdarkarValkyrie extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AdarkarValkyrie(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AdelizTheCinderWind.java b/Mage.Sets/src/mage/cards/a/AdelizTheCinderWind.java index fa86659658..c6eeeea5d5 100644 --- a/Mage.Sets/src/mage/cards/a/AdelizTheCinderWind.java +++ b/Mage.Sets/src/mage/cards/a/AdelizTheCinderWind.java @@ -1,26 +1,23 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostControlledEffect; -import mage.constants.*; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author JRHerlehy */ public final class AdelizTheCinderWind extends CardImpl { @@ -34,7 +31,7 @@ public final class AdelizTheCinderWind extends CardImpl { public AdelizTheCinderWind(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); - + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN, SubType.WIZARD); this.power = new MageInt(2); @@ -48,7 +45,7 @@ public final class AdelizTheCinderWind extends CardImpl { // Whenever you cast an instant or sorcery spell, Wizards you control get +1/+1 until end of turn. Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter); - Ability ability = new SpellCastControllerTriggeredAbility(effect, StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false); + Ability ability = new SpellCastControllerTriggeredAbility(effect, StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java index f03302bd76..8f3a011dcf 100644 --- a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java +++ b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java @@ -71,10 +71,10 @@ class DamagedByPiratesWatcher extends Watcher { private final Map> damageSourceIds = new HashMap<>(); public DamagedByPiratesWatcher() { - super(DamagedByPiratesWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public DamagedByPiratesWatcher(final DamagedByPiratesWatcher watcher) { + private DamagedByPiratesWatcher(final DamagedByPiratesWatcher watcher) { super(watcher); for (UUID playerId : watcher.damageSourceIds.keySet()) { Set creatures = new HashSet<>(); @@ -106,7 +106,7 @@ class DamagedByPiratesWatcher extends Watcher { } } - public boolean damagedByEnoughPirates(UUID sourceId, Game game) { + public boolean damagedByEnoughPirates(UUID sourceId) { return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2; } @@ -119,14 +119,11 @@ class DamagedByPiratesWatcher extends Watcher { class ControllerDealtDamageByPiratesPredicate implements Predicate { - public ControllerDealtDamageByPiratesPredicate() { - } - @Override public boolean apply(Permanent input, Game game) { - DamagedByPiratesWatcher watcher = (DamagedByPiratesWatcher) game.getState().getWatchers().get(DamagedByPiratesWatcher.class.getSimpleName()); + DamagedByPiratesWatcher watcher = game.getState().getWatcher(DamagedByPiratesWatcher.class); if (watcher != null) { - return watcher.damagedByEnoughPirates(input.getControllerId(), game); + return watcher.damagedByEnoughPirates(input.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java b/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java index a969bbc989..2490d280e4 100644 --- a/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java +++ b/Mage.Sets/src/mage/cards/a/AdmonitionAngel.java @@ -30,7 +30,7 @@ public final class AdmonitionAngel extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("nonland permanent other than Admonition Angel"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); } diff --git a/Mage.Sets/src/mage/cards/a/AdroitHateflayer.java b/Mage.Sets/src/mage/cards/a/AdroitHateflayer.java index e51f259f63..dcf0a7f023 100644 --- a/Mage.Sets/src/mage/cards/a/AdroitHateflayer.java +++ b/Mage.Sets/src/mage/cards/a/AdroitHateflayer.java @@ -1,10 +1,9 @@ - package mage.cards.a; import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; -import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.LoseLifeAllPlayersEffect; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,7 +17,7 @@ import mage.constants.SubType; public final class AdroitHateflayer extends CardImpl { public AdroitHateflayer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{B}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}{R}"); this.subtype.add(SubType.NAUTOLAN); this.subtype.add(SubType.SITH); this.power = new MageInt(3); @@ -26,9 +25,9 @@ public final class AdroitHateflayer extends CardImpl { // Menace this.addAbility(new MenaceAbility()); - - // Whenever Adroit Hateflayer attacks, each opponent loses 2 life. - this.addAbility(new AttacksTriggeredAbility(new LoseLifeOpponentsEffect(2), false)); + + // Whenever Adroit Hateflayer attacks, each player loses 2 life. + this.addAbility(new AttacksTriggeredAbility(new LoseLifeAllPlayersEffect(2), false)); } public AdroitHateflayer(final AdroitHateflayer card) { diff --git a/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java b/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java new file mode 100644 index 0000000000..f52a02aa30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AdventurersGuildhouse.java @@ -0,0 +1,47 @@ + +package mage.cards.a; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class AdventurersGuildhouse extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Green legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.GREEN)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public AdventurersGuildhouse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Green legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public AdventurersGuildhouse(final AdventurersGuildhouse card) { + super(card); + } + + @Override + public AdventurersGuildhouse copy() { + return new AdventurersGuildhouse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java b/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java index 49876ba87a..fcf6697af8 100644 --- a/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java +++ b/Mage.Sets/src/mage/cards/a/AdviceFromTheFae.java @@ -64,7 +64,7 @@ class AdviceFromTheFaeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getObject(source.getSourceId()); - if (controller != null) { + if (controller != null && mageObject != null) { Set topCards = controller.getLibrary().getTopCards(game, 5); Cards cardsFromLibrary = new CardsImpl(); for (Card card : topCards) { diff --git a/Mage.Sets/src/mage/cards/a/AegisAngel.java b/Mage.Sets/src/mage/cards/a/AegisAngel.java index 4750a5d59c..7222995d67 100644 --- a/Mage.Sets/src/mage/cards/a/AegisAngel.java +++ b/Mage.Sets/src/mage/cards/a/AegisAngel.java @@ -27,7 +27,7 @@ public final class AegisAngel extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AegisAngel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java index ae6e30725a..aca72950ae 100644 --- a/Mage.Sets/src/mage/cards/a/AegisAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/AegisAutomaton.java @@ -25,7 +25,7 @@ public final class AegisAutomaton extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AegisAutomaton(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AeonChronicler.java b/Mage.Sets/src/mage/cards/a/AeonChronicler.java index 4a6d8d4b4a..8b3f42378d 100644 --- a/Mage.Sets/src/mage/cards/a/AeonChronicler.java +++ b/Mage.Sets/src/mage/cards/a/AeonChronicler.java @@ -36,7 +36,7 @@ public final class AeonChronicler extends CardImpl { this.toughness = new MageInt(0); // Aeon Chronicler's power and toughness are each equal to the number of cards in your hand. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInControllerHandCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame))); // Suspend X-{X}{3}{U}. X can't be 0. this.addAbility(new SuspendAbility(Integer.MAX_VALUE, new ManaCostsImpl("{3}{U}"), this, true)); diff --git a/Mage.Sets/src/mage/cards/a/AerialGuide.java b/Mage.Sets/src/mage/cards/a/AerialGuide.java index c39dd4fa69..55ddd1a1a3 100644 --- a/Mage.Sets/src/mage/cards/a/AerialGuide.java +++ b/Mage.Sets/src/mage/cards/a/AerialGuide.java @@ -25,7 +25,7 @@ public final class AerialGuide extends CardImpl { static final FilterAttackingCreature filter = new FilterAttackingCreature("another target attacking creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AerialGuide(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Aeromunculus.java b/Mage.Sets/src/mage/cards/a/Aeromunculus.java new file mode 100644 index 0000000000..4f2d962f01 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Aeromunculus.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.keyword.FlyingAbility; +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 Aeromunculus extends CardImpl { + + public Aeromunculus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.subtype.add(SubType.HOMUNCULUS); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {2}{G}{U}: Adapt 1. + this.addAbility(new AdaptAbility(1, "{2}{G}{U}")); + } + + public Aeromunculus(final Aeromunculus card) { + super(card); + } + + @Override + public Aeromunculus copy() { + return new Aeromunculus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AeronautTinkerer.java b/Mage.Sets/src/mage/cards/a/AeronautTinkerer.java index a532d44cd6..769b373b33 100644 --- a/Mage.Sets/src/mage/cards/a/AeronautTinkerer.java +++ b/Mage.Sets/src/mage/cards/a/AeronautTinkerer.java @@ -22,7 +22,7 @@ import mage.filter.common.FilterControlledArtifactPermanent; */ public final class AeronautTinkerer extends CardImpl { - final static private String rule = "{this} has flying as long as you control an artifact"; + private static final String rule = "{this} has flying as long as you control an artifact"; public AeronautTinkerer(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); @@ -38,7 +38,7 @@ public final class AeronautTinkerer extends CardImpl { } - public AeronautTinkerer(final AeronautTinkerer card) { + private AeronautTinkerer(final AeronautTinkerer card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AetherBurst.java b/Mage.Sets/src/mage/cards/a/AetherBurst.java index 54355a980a..fdda9a8727 100644 --- a/Mage.Sets/src/mage/cards/a/AetherBurst.java +++ b/Mage.Sets/src/mage/cards/a/AetherBurst.java @@ -13,29 +13,42 @@ import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; import java.util.UUID; import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; /** - * * @author magenoxx_at_gmail.com */ public final class AetherBurst extends CardImpl { - - private static final FilterCard filter = new FilterCard("cards named Aether Burst"); - - static { - filter.add(new NamePredicate("Aether Burst")); - } - public AetherBurst(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return up to X target creatures to their owners' hands, where X is one plus the number of cards named Aether Burst in all graveyards as you cast Aether Burst. this.getSpellAbility().addEffect(new DynamicReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new DynamicTargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(AetherBurstAdjuster.instance); + } + + + public AetherBurst(final AetherBurst card) { + super(card); + } + + @Override + public AetherBurst copy() { + return new AetherBurst(this); + } +} + +enum AetherBurstAdjuster implements TargetAdjuster { + instance; + private static final FilterCard filter = new FilterCard("cards named Aether Burst"); + + static { + filter.add(new NamePredicate("Aether Burst")); } @Override @@ -55,15 +68,6 @@ public final class AetherBurst extends CardImpl { target.setMaxNumberOfTargets(amount + 1); } } - - public AetherBurst(final AetherBurst card) { - super(card); - } - - @Override - public AetherBurst copy() { - return new AetherBurst(this); - } } class DynamicTargetCreaturePermanent extends TargetPermanent { diff --git a/Mage.Sets/src/mage/cards/a/AetherMeltdown.java b/Mage.Sets/src/mage/cards/a/AetherMeltdown.java index c206ad09e5..999dfe2ab6 100644 --- a/Mage.Sets/src/mage/cards/a/AetherMeltdown.java +++ b/Mage.Sets/src/mage/cards/a/AetherMeltdown.java @@ -26,7 +26,7 @@ import mage.target.TargetPermanent; */ public final class AetherMeltdown extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("creature or vehicle"); + private static final FilterPermanent filter = new FilterPermanent("creature or vehicle"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new SubtypePredicate(SubType.VEHICLE))); @@ -53,7 +53,7 @@ public final class AetherMeltdown extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } - public AetherMeltdown(final AetherMeltdown card) { + private AetherMeltdown(final AetherMeltdown card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AetherMutation.java b/Mage.Sets/src/mage/cards/a/AetherMutation.java index 4f0fad54ba..c5b9b39587 100644 --- a/Mage.Sets/src/mage/cards/a/AetherMutation.java +++ b/Mage.Sets/src/mage/cards/a/AetherMutation.java @@ -25,7 +25,7 @@ public final class AetherMutation extends CardImpl { this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // create X 1/1 green Saproling creature tokens, where X is that creature's converted mana cost. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new TargetConvertedManaCost())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), TargetConvertedManaCost.instance)); } public AetherMutation(final AetherMutation card) { diff --git a/Mage.Sets/src/mage/cards/a/AetherShockwave.java b/Mage.Sets/src/mage/cards/a/AetherShockwave.java index 02e969ae58..d27f0a86a4 100644 --- a/Mage.Sets/src/mage/cards/a/AetherShockwave.java +++ b/Mage.Sets/src/mage/cards/a/AetherShockwave.java @@ -33,7 +33,7 @@ public final class AetherShockwave extends CardImpl { this.getSpellAbility().addEffect(new TapAllEffect(filterSpirit)); Mode mode = new Mode(); - mode.getEffects().add(new TapAllEffect(filterNonSpirit)); + mode.addEffect(new TapAllEffect(filterNonSpirit)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AetherStorm.java b/Mage.Sets/src/mage/cards/a/AetherStorm.java index caf533324a..a2298fa7be 100644 --- a/Mage.Sets/src/mage/cards/a/AetherStorm.java +++ b/Mage.Sets/src/mage/cards/a/AetherStorm.java @@ -36,7 +36,7 @@ public final class AetherStorm extends CardImpl { this.addAbility(ability); } - public AetherStorm(final AetherStorm card) { + private AetherStorm(final AetherStorm card) { super(card); } @@ -53,7 +53,7 @@ class AetherStormReplacementEffect extends ContinuousRuleModifyingEffectImpl { staticText = "Creature spells can't be cast."; } - public AetherStormReplacementEffect(final AetherStormReplacementEffect effect) { + private AetherStormReplacementEffect(final AetherStormReplacementEffect effect) { super(effect); } @@ -75,10 +75,7 @@ class AetherStormReplacementEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Card card = game.getCard(event.getSourceId()); - if (card != null && card.isCreature()) { - return true; - } - return false; + return card != null && card.isCreature(); } } diff --git a/Mage.Sets/src/mage/cards/a/AetherTide.java b/Mage.Sets/src/mage/cards/a/AetherTide.java new file mode 100644 index 0000000000..f368a6ff02 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AetherTide.java @@ -0,0 +1,76 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostAdjuster; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +/** + * + * @author jeffwadsworth + */ +public final class AetherTide extends CardImpl { + + public AetherTide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}"); + + // As an additional cost to cast Aether Tide, discard X creature cards. + Ability ability = new SimpleStaticAbility(Zone.ALL, new InfoEffect("As an additional cost to cast {this}, discard X creature cards")); + ability.setRuleAtTheTop(true); + this.addAbility(ability); + + // Return X target creatures to their owners' hands. + Effect effect = new ReturnToHandTargetEffect(true); + effect.setText("Return X target creatures to their owners' hands"); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(AetherTideTargetAdjuster.instance); + this.getSpellAbility().setCostAdjuster(AetherTideCostAdjuster.instance); + + } + + public AetherTide(final AetherTide card) { + super(card); + } + + @Override + public AetherTide copy() { + return new AetherTide(this); + } +} + +enum AetherTideTargetAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetCreaturePermanent(xValue, xValue, new FilterCreaturePermanent(), false)); + } +} + +enum AetherTideCostAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + if (xValue > 0) { + ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, new FilterCreatureCard("creature cards")))); + } + } +} diff --git a/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java b/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java index 2e25504f2f..927aa2b43a 100644 --- a/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java +++ b/Mage.Sets/src/mage/cards/a/AetherbornMarauder.java @@ -76,7 +76,7 @@ class AetherbornMarauderEffect extends OneShotEffect { Permanent sourceObject = game.getPermanent(source.getSourceId()); if (controller != null && sourceObject != null) { FilterControlledPermanent filter = new FilterControlledPermanent("permanent you control to remove +1/+1 counters from"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CounterPredicate(CounterType.P1P1)); boolean firstRun = true; while (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0) { diff --git a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java index 5b25220b99..871b4d90ac 100644 --- a/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java +++ b/Mage.Sets/src/mage/cards/a/AetherfluxReservoir.java @@ -50,8 +50,11 @@ class AetherfluxReservoirDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); - return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if(watcher != null) { + return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(sourceAbility.getControllerId()); + } + return 0; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AethersquallAncient.java b/Mage.Sets/src/mage/cards/a/AethersquallAncient.java index 7f2ef61310..fa62158339 100644 --- a/Mage.Sets/src/mage/cards/a/AethersquallAncient.java +++ b/Mage.Sets/src/mage/cards/a/AethersquallAncient.java @@ -27,7 +27,7 @@ public final class AethersquallAncient extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AethersquallAncient(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AetherstormRoc.java b/Mage.Sets/src/mage/cards/a/AetherstormRoc.java index 3424b95a3a..aff1bf10b0 100644 --- a/Mage.Sets/src/mage/cards/a/AetherstormRoc.java +++ b/Mage.Sets/src/mage/cards/a/AetherstormRoc.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -21,17 +20,17 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AetherstormRoc extends CardImpl { - private final UUID originalId; - public AetherstormRoc(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -47,30 +46,32 @@ public final class AetherstormRoc extends CardImpl { Ability ability = new AttacksTriggeredAbility(doIfCostPaidEffect, false, "Whenever {this} attacks you may pay {E}{E}. If you do, put a +1/+1 counter on it and tap up to one target creature defending player controls."); ability.addTarget(new TargetCreaturePermanent(0, 1, new FilterCreaturePermanent("creature defending player controls"), false)); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(AetherstormRocAdjuster.instance); this.addAbility(ability); } public AetherstormRoc(final AetherstormRoc card) { super(card); - this.originalId = card.originalId; } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); - filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); - ability.addTarget(target); - } - } @Override public AetherstormRoc copy() { return new AetherstormRoc(this); } } + +enum AetherstormRocAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); + UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); + filter.add(new ControllerIdPredicate(defenderId)); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); + ability.addTarget(target); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AetherwindBasker.java b/Mage.Sets/src/mage/cards/a/AetherwindBasker.java index c92b84d420..e2bc62492d 100644 --- a/Mage.Sets/src/mage/cards/a/AetherwindBasker.java +++ b/Mage.Sets/src/mage/cards/a/AetherwindBasker.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; /** @@ -35,13 +36,13 @@ public final class AetherwindBasker extends CardImpl { this.addAbility(TrampleAbility.getInstance()); // Whenever Aetherwind Basker enters the battlefield or attacks, you get {E} for each creature you control. - this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GetEnergyCountersControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creature you control"), null)))); + this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new GetEnergyCountersControllerEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, null)))); // Pay {E}: Aetherwind Basker gets +1/+1 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new PayEnergyCost(1))); } - public AetherwindBasker(final AetherwindBasker card) { + private AetherwindBasker(final AetherwindBasker card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java index 2cca7a8b91..9fdf02cfa5 100644 --- a/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java +++ b/Mage.Sets/src/mage/cards/a/AetherworksMarvel.java @@ -73,10 +73,7 @@ class AetherworksMarvelEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Set cardsSet = controller.getLibrary().getTopCards(game, 6); - Cards cards = new CardsImpl(); - for (Card card : cardsSet) { - cards.add(card); - } + Cards cards = new CardsImpl(cardsSet); TargetCard target = new TargetCardInLibrary(0, 1, new FilterNonlandCard("card to cast without paying its mana cost")); if (controller.choose(Outcome.PlayForFree, cards, target, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/a/Afterburn.java b/Mage.Sets/src/mage/cards/a/Afterburn.java index 8747051002..80f2aa3aac 100644 --- a/Mage.Sets/src/mage/cards/a/Afterburn.java +++ b/Mage.Sets/src/mage/cards/a/Afterburn.java @@ -31,8 +31,8 @@ public final class Afterburn extends CardImpl { // Remove target creature from combat. Mode mode = new Mode(); - mode.getEffects().add(new RemoveFromCombatTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new RemoveFromCombatTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AgentOfShauku.java b/Mage.Sets/src/mage/cards/a/AgentOfShauku.java index 974b9bda93..21093caee9 100644 --- a/Mage.Sets/src/mage/cards/a/AgentOfShauku.java +++ b/Mage.Sets/src/mage/cards/a/AgentOfShauku.java @@ -25,7 +25,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class AgentOfShauku extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledLandPermanent("a land"); + static final FilterControlledPermanent filter = new FilterControlledLandPermanent("a land"); public AgentOfShauku(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); diff --git a/Mage.Sets/src/mage/cards/a/Aggravate.java b/Mage.Sets/src/mage/cards/a/Aggravate.java index 6110f09d52..21d9585854 100644 --- a/Mage.Sets/src/mage/cards/a/Aggravate.java +++ b/Mage.Sets/src/mage/cards/a/Aggravate.java @@ -61,7 +61,7 @@ class AggravateRequirementEffect extends RequirementEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(permanent, game); } diff --git a/Mage.Sets/src/mage/cards/a/Aggression.java b/Mage.Sets/src/mage/cards/a/Aggression.java new file mode 100644 index 0000000000..78b9408748 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Aggression.java @@ -0,0 +1,104 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.MageObjectReference; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DestroyAttachedToEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.watchers.common.AttackedThisTurnWatcher; + +/** + * + * @author jeffwadsworth + */ +public final class Aggression extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); + } + + public Aggression(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant non-Wall creature + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has first strike and trample. + Ability ability2 = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), + AttachmentType.AURA)); + ability2.addEffect(new GainAbilityAttachedEffect( + TrampleAbility.getInstance(), + AttachmentType.AURA)); + this.addAbility(ability2); + + // At the beginning of the end step of enchanted creature's controller, destroy that creature if it didn't attack this turn. + this.addAbility(new ConditionalTriggeredAbility( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new DestroyAttachedToEffect("enchanted"), + TargetController.CONTROLLER_ATTACHED_TO), + DidNotAttackedThisTurnEnchantedCondition.instance, + "At the beginning of the end step of enchanted creature's controller, destroy that creature if it didn't attack this turn."), + new AttackedThisTurnWatcher()); + + } + + private Aggression(final Aggression card) { + super(card); + } + + @Override + public Aggression copy() { + return new Aggression(this); + } +} + +enum DidNotAttackedThisTurnEnchantedCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Permanent auraPermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (auraPermanent != null) { + Permanent enchantedPermanent = game.getPermanent(auraPermanent.getAttachedTo()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + return enchantedPermanent != null + && watcher != null + && !watcher.getAttackedThisTurnCreatures().contains( + new MageObjectReference(enchantedPermanent, game)); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AgonizingDemise.java b/Mage.Sets/src/mage/cards/a/AgonizingDemise.java index a183e73f73..dcaab97043 100644 --- a/Mage.Sets/src/mage/cards/a/AgonizingDemise.java +++ b/Mage.Sets/src/mage/cards/a/AgonizingDemise.java @@ -40,7 +40,7 @@ public final class AgonizingDemise extends CardImpl { //If Agonizing Demise was kicked, it deals damage equal to that creature's power to the creature's controller. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetControllerEffect(new TargetPermanentPowerCount()), + new DamageTargetControllerEffect(TargetPermanentPowerCount.instance), KickedCondition.instance, "if this spell was kicked, it deals damage equal to that creature's power to the creature's controller.")); diff --git a/Mage.Sets/src/mage/cards/a/AhnCropInvader.java b/Mage.Sets/src/mage/cards/a/AhnCropInvader.java new file mode 100644 index 0000000000..625089a4ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AhnCropInvader.java @@ -0,0 +1,77 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AhnCropInvader extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("another creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public AhnCropInvader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.MINOTAUR); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // As long as it's your turn, Ahn-Crop Invader has first strike. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, + "As long as it's your turn, " + + "{this} has first strike." + ) + )); + + // {1}, Sacrifice another creature: Ahn-Crop Invader gets +2/+0 until end of turn. + Ability ability = new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), new GenericManaCost(1) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private AhnCropInvader(final AhnCropInvader card) { + super(card); + } + + @Override + public AhnCropInvader copy() { + return new AhnCropInvader(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AidTheFallen.java b/Mage.Sets/src/mage/cards/a/AidTheFallen.java new file mode 100644 index 0000000000..5e676ec87b --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AidTheFallen.java @@ -0,0 +1,50 @@ +package mage.cards.a; + +import mage.abilities.Mode; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterPlaneswalkerCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AidTheFallen extends CardImpl { + + private static final FilterCard filter = new FilterPlaneswalkerCard("planeswalker card from your graveyard"); + + public AidTheFallen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Choose one or both— + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // • Return target creature card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard( + StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD + ).withChooseHint("returns a creature card to your hand")); + + // • Return target planeswalker card from your graveyard to your hand. + Mode mode = new Mode(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filter) + .withChooseHint("returns a planeswalker card to your hand")); + this.getSpellAbility().addMode(mode); + } + + private AidTheFallen(final AidTheFallen card) { + super(card); + } + + @Override + public AidTheFallen copy() { + return new AidTheFallen(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AinokGuide.java b/Mage.Sets/src/mage/cards/a/AinokGuide.java index d964db9bfe..2136d4f976 100644 --- a/Mage.Sets/src/mage/cards/a/AinokGuide.java +++ b/Mage.Sets/src/mage/cards/a/AinokGuide.java @@ -36,7 +36,7 @@ public final class AinokGuide extends CardImpl { // * Search your library for a basic land card, reveal it, then shuffle your library and put that card on top of it. Mode mode = new Mode(); - mode.getEffects().add(new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true)); + mode.addEffect(new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true, true)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AirdropCondor.java b/Mage.Sets/src/mage/cards/a/AirdropCondor.java index 447fbfae6c..824ef1f572 100644 --- a/Mage.Sets/src/mage/cards/a/AirdropCondor.java +++ b/Mage.Sets/src/mage/cards/a/AirdropCondor.java @@ -42,7 +42,7 @@ public final class AirdropCondor extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {1}{R}, Sacrifice a Goblin creature: Airdrop Condor deals damage equal to the sacrificed creature's power to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new SacrificeCostCreaturesPower()), new ManaCostsImpl("{1}{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(SacrificeCostCreaturesPower.instance), new ManaCostsImpl("{1}{R}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java b/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java index 0dfdd6a8bf..a3b0b04fc4 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java +++ b/Mage.Sets/src/mage/cards/a/AjaniCallerOfThePride.java @@ -49,7 +49,7 @@ public final class AjaniCallerOfThePride extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // -8: create X 2/2 white Cat creature tokens, where X is your life total. - this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new CatToken(), new ControllerLifeCount()), -8)); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new CatToken(), ControllerLifeCount.instance), -8)); } public AjaniCallerOfThePride(final AjaniCallerOfThePride card) { diff --git a/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java b/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java index 7d95193116..1d4a95c891 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java +++ b/Mage.Sets/src/mage/cards/a/AjaniSteadfast.java @@ -36,7 +36,7 @@ public final class AjaniSteadfast extends CardImpl { private static final FilterPlaneswalkerPermanent filter = new FilterPlaneswalkerPermanent("other planeswalker you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java b/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java new file mode 100644 index 0000000000..fe392e8e50 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AjaniTheGreathearted.java @@ -0,0 +1,71 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +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 mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AjaniTheGreathearted extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent(); + + static { + filter.add(AnotherPredicate.instance); + } + + public AjaniTheGreathearted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.AJANI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Creatures you control have vigilance. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), + Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); + + // +1: You gain 3 life. + this.addAbility(new LoyaltyAbility(new GainLifeEffect(3), 1)); + + // -2: Put a +1/+1 counter on each creature you control and a loyalty counter on each other planeswalker you control. + Ability ability = new LoyaltyAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURES + ), -2); + ability.addEffect(new AddCountersAllEffect( + CounterType.LOYALTY.createInstance(), filter + ).setText("and a loyalty counter on each other planeswalker you control")); + this.addAbility(ability); + } + + private AjaniTheGreathearted(final AjaniTheGreathearted card) { + super(card); + } + + @Override + public AjaniTheGreathearted copy() { + return new AjaniTheGreathearted(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java index f7ba38516c..ab5289a028 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java +++ b/Mage.Sets/src/mage/cards/a/AjaniUnyielding.java @@ -35,7 +35,7 @@ public final class AjaniUnyielding extends CardImpl { static { nonlandPermanentFilter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); planeswalkerFilter.add(new ControllerPredicate(TargetController.YOU)); - planeswalkerFilter.add(new AnotherPredicate()); + planeswalkerFilter.add(AnotherPredicate.instance); } public AjaniUnyielding(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java index 00f6ca6c98..7bec5ea3f3 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java +++ b/Mage.Sets/src/mage/cards/a/AjaniValiantProtector.java @@ -44,7 +44,7 @@ public final class AjaniValiantProtector extends CardImpl { this.addAbility(new LoyaltyAbility(new RevealCardsFromLibraryUntilEffect(new FilterCreatureCard(), Zone.HAND, Zone.LIBRARY), 1)); // -11: Put X +1/+1 counters on target creature, where X is your life total. That creature gains trample until end of turn. - Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), new ControllerLifeCount()); + Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), ControllerLifeCount.instance); effect.setText("Put X +1/+1 counters on target creature, where X is your life total."); ability = new LoyaltyAbility(effect, -11); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); diff --git a/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java b/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java index 8a28d2545e..b264f97b35 100644 --- a/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java +++ b/Mage.Sets/src/mage/cards/a/AjaniWiseCounselor.java @@ -1,25 +1,24 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.ControllerLifeCount; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; -import mage.constants.SubType; -import mage.constants.SuperType; 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.StaticFilters; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class AjaniWiseCounselor extends CardImpl { @@ -32,9 +31,8 @@ public final class AjaniWiseCounselor extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); // +2: You gain 1 life for each creature you control. - this.addAbility(new LoyaltyAbility(new GainLifeEffect( - new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE) - ).setText("you gain 1 life for each creature you control"), 2)); + this.addAbility(new LoyaltyAbility(new GainLifeEffect(CreaturesYouControlCount.instance) + .setText("you gain 1 life for each creature you control"), 2)); // −3: Creatures you control get +2/+2 until end of turn. this.addAbility(new LoyaltyAbility( @@ -44,7 +42,7 @@ public final class AjaniWiseCounselor extends CardImpl { // −9: Put X +1/+1 counters on target creature, where X is your life total. Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( CounterType.P1P1.createInstance(), - new ControllerLifeCount() + ControllerLifeCount.instance ).setText("put X +1/+1 counters on target creature, where X is your life total"), -9); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AjanisAid.java b/Mage.Sets/src/mage/cards/a/AjanisAid.java index 1bfe98285e..9728a402c3 100644 --- a/Mage.Sets/src/mage/cards/a/AjanisAid.java +++ b/Mage.Sets/src/mage/cards/a/AjanisAid.java @@ -23,7 +23,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class AjanisAid extends CardImpl { - private final static FilterCard filter = new FilterCard("Ajani, Valiant Protector"); + private static final FilterCard filter = new FilterCard("Ajani, Valiant Protector"); static { filter.add(new NamePredicate("Ajani, Valiant Protector")); @@ -42,7 +42,7 @@ public final class AjanisAid extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new SacrificeSourceCost())); } - public AjanisAid(final AjanisAid card) { + private AjanisAid(final AjanisAid card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AjanisLastStand.java b/Mage.Sets/src/mage/cards/a/AjanisLastStand.java index 8be2b128f1..7e6b59f641 100644 --- a/Mage.Sets/src/mage/cards/a/AjanisLastStand.java +++ b/Mage.Sets/src/mage/cards/a/AjanisLastStand.java @@ -83,8 +83,7 @@ class AjanisLastStandTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD - && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget().isControlledBy(controllerId) && (zEvent.getTarget().isCreature() || zEvent.getTarget().isPlaneswalker())) { diff --git a/Mage.Sets/src/mage/cards/a/AjanisPridemate.java b/Mage.Sets/src/mage/cards/a/AjanisPridemate.java index 124891d3c7..ad07f8d4e9 100644 --- a/Mage.Sets/src/mage/cards/a/AjanisPridemate.java +++ b/Mage.Sets/src/mage/cards/a/AjanisPridemate.java @@ -2,38 +2,37 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.GainLifeControllerTriggeredAbility; 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.constants.Zone; import mage.counters.CounterType; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class AjanisPridemate extends CardImpl { public AjanisPridemate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.CAT); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); this.toughness = new MageInt(2); - this.addAbility(new AjanisPridemateAbility()); + // Whenever you gain life, put a +1/+1 counter on Ajani's Pridemate. + this.addAbility(new GainLifeControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false + )); } - public AjanisPridemate(final AjanisPridemate card) { + private AjanisPridemate(final AjanisPridemate card) { super(card); } @@ -43,35 +42,3 @@ public final class AjanisPridemate extends CardImpl { } } - -class AjanisPridemateAbility extends TriggeredAbilityImpl { - - public AjanisPridemateAbility() { - super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true); - } - - public AjanisPridemateAbility(final AjanisPridemateAbility ability) { - super(ability); - } - - @Override - public AjanisPridemateAbility copy() { - return new AjanisPridemateAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.GAINED_LIFE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals(controllerId); - } - - @Override - public String getRule() { - return "Whenever you gain life, you may put a +1/+1 counter on {this}."; - } - -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AkoumFlameseeker.java b/Mage.Sets/src/mage/cards/a/AkoumFlameseeker.java index d076743f8c..5c1c67eea2 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumFlameseeker.java +++ b/Mage.Sets/src/mage/cards/a/AkoumFlameseeker.java @@ -30,7 +30,7 @@ public final class AkoumFlameseeker extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public AkoumFlameseeker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java b/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java index 0e443e10e2..67907265a0 100644 --- a/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java +++ b/Mage.Sets/src/mage/cards/a/AkroanConscriptor.java @@ -28,7 +28,7 @@ public final class AkroanConscriptor extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AkroanConscriptor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AkroanHoplite.java b/Mage.Sets/src/mage/cards/a/AkroanHoplite.java index 599a0dfa13..d19cdaf3b6 100644 --- a/Mage.Sets/src/mage/cards/a/AkroanHoplite.java +++ b/Mage.Sets/src/mage/cards/a/AkroanHoplite.java @@ -27,7 +27,7 @@ public final class AkroanHoplite extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public AkroanHoplite(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AlabasterPotion.java b/Mage.Sets/src/mage/cards/a/AlabasterPotion.java index 7e24a9bf8e..9a69608a6f 100644 --- a/Mage.Sets/src/mage/cards/a/AlabasterPotion.java +++ b/Mage.Sets/src/mage/cards/a/AlabasterPotion.java @@ -23,11 +23,11 @@ public final class AlabasterPotion extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}"); // Choose one - Target player gains X life; or prevent the next X damage that would be dealt to any target this turn. - this.getSpellAbility().addEffect(new GainLifeTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new GainLifeTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, new ManacostVariableValue())); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.instance)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/Alarum.java b/Mage.Sets/src/mage/cards/a/Alarum.java index 553c075fa3..ac526c698f 100644 --- a/Mage.Sets/src/mage/cards/a/Alarum.java +++ b/Mage.Sets/src/mage/cards/a/Alarum.java @@ -23,7 +23,7 @@ public final class Alarum extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonattacking creature"); static { - filter.add(Predicates.not(new AttackingPredicate())); + filter.add(Predicates.not(AttackingPredicate.instance)); } public Alarum(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Aleatory.java b/Mage.Sets/src/mage/cards/a/Aleatory.java index 71080e6298..eb33925b2b 100644 --- a/Mage.Sets/src/mage/cards/a/Aleatory.java +++ b/Mage.Sets/src/mage/cards/a/Aleatory.java @@ -67,7 +67,7 @@ class AleatoryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source); return true; } diff --git a/Mage.Sets/src/mage/cards/a/AlhammarretsArchive.java b/Mage.Sets/src/mage/cards/a/AlhammarretsArchive.java index 02b087e0ab..7934c8b858 100644 --- a/Mage.Sets/src/mage/cards/a/AlhammarretsArchive.java +++ b/Mage.Sets/src/mage/cards/a/AlhammarretsArchive.java @@ -113,7 +113,7 @@ class AlhammarretsArchiveReplacementEffect extends ReplacementEffectImpl { if (event.getPlayerId().equals(source.getControllerId())) { if (game.isActivePlayer(event.getPlayerId()) && game.getPhase().getStep().getType() == PhaseStep.DRAW) { - CardsDrawnDuringDrawStepWatcher watcher = (CardsDrawnDuringDrawStepWatcher) game.getState().getWatchers().get(CardsDrawnDuringDrawStepWatcher.class.getSimpleName()); + CardsDrawnDuringDrawStepWatcher watcher = game.getState().getWatcher(CardsDrawnDuringDrawStepWatcher.class); if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 0) { return true; } diff --git a/Mage.Sets/src/mage/cards/a/AliveWell.java b/Mage.Sets/src/mage/cards/a/AliveWell.java index 5994424691..523cf73a10 100644 --- a/Mage.Sets/src/mage/cards/a/AliveWell.java +++ b/Mage.Sets/src/mage/cards/a/AliveWell.java @@ -65,8 +65,8 @@ class WellEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - int life = 2 * game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); if (player != null) { + int life = 2 * game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); player.gainLife(life, game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/a/AllSunsDawn.java b/Mage.Sets/src/mage/cards/a/AllSunsDawn.java index 3278bd9a59..2a882a21f7 100644 --- a/Mage.Sets/src/mage/cards/a/AllSunsDawn.java +++ b/Mage.Sets/src/mage/cards/a/AllSunsDawn.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -17,17 +16,18 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AllSunsDawn extends CardImpl { - private final static FilterCard filterGreen = new FilterCard("green card from your graveyard"); - private final static FilterCard filterRed = new FilterCard("red card from your graveyard"); - private final static FilterCard filterBlue = new FilterCard("blue card from your graveyard"); - private final static FilterCard filterBlack = new FilterCard("black card from your graveyard"); - private final static FilterCard filterWhite = new FilterCard("white card from your graveyard"); + private static final FilterCard filterGreen = new FilterCard("green card from your graveyard"); + private static final FilterCard filterRed = new FilterCard("red card from your graveyard"); + private static final FilterCard filterBlue = new FilterCard("blue card from your graveyard"); + private static final FilterCard filterBlack = new FilterCard("black card from your graveyard"); + private static final FilterCard filterWhite = new FilterCard("white card from your graveyard"); static { filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); @@ -38,7 +38,7 @@ public final class AllSunsDawn extends CardImpl { } public AllSunsDawn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); // For each color, return up to one target card of that color from your graveyard to your hand. this.getSpellAbility().addEffect(new AllSunsDawnEffect()); @@ -51,7 +51,7 @@ public final class AllSunsDawn extends CardImpl { this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); } - public AllSunsDawn(final AllSunsDawn card) { + private AllSunsDawn(final AllSunsDawn card) { super(card); } @@ -68,7 +68,7 @@ class AllSunsDawnEffect extends OneShotEffect { this.staticText = "For each color, return up to one target card of that color from your graveyard to your hand"; } - public AllSunsDawnEffect(final AllSunsDawnEffect effect) { + private AllSunsDawnEffect(final AllSunsDawnEffect effect) { super(effect); } @@ -89,8 +89,7 @@ class AllSunsDawnEffect extends OneShotEffect { cardsToHand.add(card); } } - controller.moveCards(cardsToHand, Zone.HAND, source, game); - return true; + return controller.moveCards(cardsToHand, Zone.HAND, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AlleyEvasion.java b/Mage.Sets/src/mage/cards/a/AlleyEvasion.java index 04f7cb8de8..6c3e8b955a 100644 --- a/Mage.Sets/src/mage/cards/a/AlleyEvasion.java +++ b/Mage.Sets/src/mage/cards/a/AlleyEvasion.java @@ -27,8 +27,8 @@ public final class AlleyEvasion extends CardImpl { // Return target creature you control to its owner's hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetControlledCreaturePermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AllianceOfArms.java b/Mage.Sets/src/mage/cards/a/AllianceOfArms.java index 30533ffff2..3dcf8431e5 100644 --- a/Mage.Sets/src/mage/cards/a/AllianceOfArms.java +++ b/Mage.Sets/src/mage/cards/a/AllianceOfArms.java @@ -100,7 +100,7 @@ class AllianceOfArmsEffect extends OneShotEffect { payed = true; } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}."); return xValue; } } diff --git a/Mage.Sets/src/mage/cards/a/AlpineMoon.java b/Mage.Sets/src/mage/cards/a/AlpineMoon.java index a88fa999f8..364fb82893 100644 --- a/Mage.Sets/src/mage/cards/a/AlpineMoon.java +++ b/Mage.Sets/src/mage/cards/a/AlpineMoon.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -9,15 +8,7 @@ import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.mana.AnyColorManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; @@ -27,8 +18,9 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class AlpineMoon extends CardImpl { @@ -97,7 +89,7 @@ class AlpineMoonEffect extends ContinuousEffectImpl { // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects // So the ability removing has to be done before Layer 6 land.removeAllAbilities(source.getSourceId(), game); - land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + land.getSubtype(game).removeAll(SubType.getLandTypes()); break; case AbilityAddingRemovingEffects_6: land.addAbility(new AnyColorManaAbility(), source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/a/AltacBloodseeker.java b/Mage.Sets/src/mage/cards/a/AltacBloodseeker.java index 3f6e056f88..b9d6032bfa 100644 --- a/Mage.Sets/src/mage/cards/a/AltacBloodseeker.java +++ b/Mage.Sets/src/mage/cards/a/AltacBloodseeker.java @@ -25,7 +25,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class AltacBloodseeker extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/a/AltarGolem.java b/Mage.Sets/src/mage/cards/a/AltarGolem.java index 52501d4637..5b0dc5a367 100644 --- a/Mage.Sets/src/mage/cards/a/AltarGolem.java +++ b/Mage.Sets/src/mage/cards/a/AltarGolem.java @@ -34,7 +34,7 @@ public final class AltarGolem extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public AltarGolem(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheBrood.java b/Mage.Sets/src/mage/cards/a/AltarOfTheBrood.java index 0fbb0b78f9..9512286798 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheBrood.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheBrood.java @@ -21,7 +21,7 @@ public final class AltarOfTheBrood extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AltarOfTheBrood(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Aluren.java b/Mage.Sets/src/mage/cards/a/Aluren.java index 8397fa65c9..a0c485b682 100644 --- a/Mage.Sets/src/mage/cards/a/Aluren.java +++ b/Mage.Sets/src/mage/cards/a/Aluren.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.SourceIsSpellCondition; @@ -17,29 +15,31 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * 10/4/2004 The mana cost of the creatures being cast is still the stated cost on the card, - * even though you did not pay the cost. + * 10/4/2004 The mana cost of the creatures being cast is still the stated cost on the card, + * even though you did not pay the cost. * 10/4/2004 Aluren checks the actual printed cost on the creature card, and is not affected - * by things which allow you to cast the spell for less. - * 10/4/2004 You can't choose to cast a creature as though it had flash via Aluren and still pay the mana cost. - * You either cast the creature normally, or via Aluren without paying the mana cost. - * 10/4/2004 You can't use Aluren when casting a creature using another alternate means, - * such as the Morph ability. - * 8/1/2008 If creature with X in its cost is cast this way, X can only be 0. - * + * by things which allow you to cast the spell for less. + * 10/4/2004 You can't choose to cast a creature as though it had flash via Aluren and still pay the mana cost. + * You either cast the creature normally, or via Aluren without paying the mana cost. + * 10/4/2004 You can't use Aluren when casting a creature using another alternate means, + * such as the Morph ability. + * 8/1/2008 If creature with X in its cost is cast this way, X can only be 0. + * * @author emerald000 */ public final class Aluren extends CardImpl { - + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 3 or less"); - + static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } - + public Aluren(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); // Any player may play creature cards with converted mana cost 3 or less without paying their mana cost @@ -63,15 +63,15 @@ public final class Aluren extends CardImpl { } class AlurenRuleEffect extends ContinuousEffectImpl { - + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 3 or less"); - + static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } - - private static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, SourceIsSpellCondition.instance, null, filter, true); - + + private static AlternativeCostSourceAbility alternativeCastingCostAbility = new AlternativeCostSourceAbility(null, SourceIsSpellCondition.instance, null, filter, true); + public AlurenRuleEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); staticText = "Any player may cast creature cards with converted mana cost 3 or less without paying their mana cost"; @@ -90,12 +90,12 @@ class AlurenRuleEffect extends ContinuousEffectImpl { public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - for (UUID playerId: game.getState().getPlayersInRange(controller.getId(), game)){ + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { player.getAlternativeSourceCosts().add(alternativeCastingCostAbility); } - } + } return true; } return false; @@ -110,47 +110,4 @@ class AlurenRuleEffect extends ContinuousEffectImpl { public boolean hasLayer(Layer layer) { return layer == Layer.RulesEffects; } -} - -//class AlurenEffect extends CostModificationEffectImpl { -// -// AlurenEffect() { -// super(Duration.WhileOnBattlefield, Outcome.PlayForFree, CostModificationType.SET_COST); -// this.staticText = "Any player may play creature cards with converted mana cost 3 or less without paying their mana cost"; -// } -// -// AlurenEffect(final AlurenEffect effect) { -// super(effect); -// } -// -// @Override -// public boolean apply(Game game, Ability source, Ability abilityToModify) { -// SpellAbility spellAbility = (SpellAbility) abilityToModify; -// spellAbility.getManaCostsToPay().clear(); -// return true; -// } -// -// @Override -// public boolean applies(Ability abilityToModify, Ability source, Game game) { -// if (abilityToModify instanceof SpellAbility) { -// Card sourceCard = game.getCard(abilityToModify.getSourceId()); -// StackObject stackObject = game.getStack().getStackObject(abilityToModify.getSourceId()); -// if (stackObject != null && stackObject instanceof Spell) { -// if (sourceCard != null && sourceCard.isCreature() && sourceCard.getConvertedManaCost() <= 3) { -// Player player = game.getPlayer(stackObject.getControllerId()); -// String message = "Cast " + sourceCard.getName() + " without paying its mana costs?"; -// if (player != null && -// (CardUtil.isCheckPlayableMode(abilityToModify) || player.chooseUse(outcome, message, game))) { -// return true; -// } -// } -// } -// } -// return false; -// } -// -// @Override -// public AlurenEffect copy() { -// return new AlurenEffect(this); -// } -//} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AlwaysWatching.java b/Mage.Sets/src/mage/cards/a/AlwaysWatching.java index ecb7a7d350..a844009f12 100644 --- a/Mage.Sets/src/mage/cards/a/AlwaysWatching.java +++ b/Mage.Sets/src/mage/cards/a/AlwaysWatching.java @@ -26,7 +26,7 @@ public final class AlwaysWatching extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creatures"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public AlwaysWatching(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AmbushKrotiq.java b/Mage.Sets/src/mage/cards/a/AmbushKrotiq.java index 821128e1d7..18e0f9a150 100644 --- a/Mage.Sets/src/mage/cards/a/AmbushKrotiq.java +++ b/Mage.Sets/src/mage/cards/a/AmbushKrotiq.java @@ -22,7 +22,7 @@ public final class AmbushKrotiq extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AmbushKrotiq(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java b/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java index 8067fc0183..bdd8b1e1ed 100644 --- a/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java +++ b/Mage.Sets/src/mage/cards/a/AminatouTheFateShifter.java @@ -40,11 +40,11 @@ public class AminatouTheFateShifter extends CardImpl { static { filter.add(new OwnerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AminatouTheFateShifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{W}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{W}{U}{B}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AMINATOU); @@ -56,7 +56,7 @@ public class AminatouTheFateShifter extends CardImpl { // -1: Exile another target permanent you own, then return it to the battlefield under your control. ability = new LoyaltyAbility(new ExileTargetForSourceEffect(), -1); - ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect()); + ability.addEffect(new ReturnToBattlefieldUnderYourControlTargetEffect(true)); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); @@ -68,6 +68,7 @@ public class AminatouTheFateShifter extends CardImpl { // Aminatou, the Fateshifter can be your commander. this.addAbility(CanBeYourCommanderAbility.getInstance()); } + public AminatouTheFateShifter(final AminatouTheFateShifter card) { super(card); } @@ -79,6 +80,7 @@ public class AminatouTheFateShifter extends CardImpl { } class AminatouPlusEffect extends OneShotEffect { + public AminatouPlusEffect() { super(Outcome.DrawCard); staticText = "draw a card, then put a card from your hand on top of your library"; @@ -118,10 +120,11 @@ class AminatouPlusEffect extends OneShotEffect { } class AminatouUltimateEffect extends OneShotEffect { - public AminatouUltimateEffect (){ + + public AminatouUltimateEffect() { super(Outcome.Benefit); - staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou," + - " the Fateshifter controlled by the next player in the chosen direction."; + staticText = "Choose left or right. Each player gains control of all nonland permanents other than Aminatou," + + " the Fateshifter controlled by the next player in the chosen direction."; } public AminatouUltimateEffect(final AminatouUltimateEffect effect) { @@ -129,7 +132,9 @@ class AminatouUltimateEffect extends OneShotEffect { } @Override - public AminatouUltimateEffect copy(){return new AminatouUltimateEffect(this);} + public AminatouUltimateEffect copy() { + return new AminatouUltimateEffect(this); + } @Override public boolean apply(Game game, Ability source) { @@ -154,7 +159,7 @@ class AminatouUltimateEffect extends OneShotEffect { return false; } // skip players out of range - if (!game.getState().getPlayersInRange(controller.getId(), game).contains(nextPlayer)){ + if (!game.getState().getPlayersInRange(controller.getId(), game).contains(nextPlayer)) { continue; } // save first next player to check for iteration stop @@ -164,7 +169,7 @@ class AminatouUltimateEffect extends OneShotEffect { FilterNonlandPermanent nextPlayerNonlandPermanentsFilter = new FilterNonlandPermanent(); nextPlayerNonlandPermanentsFilter.add(new ControllerIdPredicate(nextPlayer)); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(nextPlayerNonlandPermanentsFilter, game)) { - if (permanent.getId().equals(source.getSourceId())){ + if (permanent.getId().equals(source.getSourceId())) { continue; } ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfGame, currentPlayer); @@ -188,4 +193,3 @@ class AminatouUltimateEffect extends OneShotEffect { return nextPlayerId; } } - diff --git a/Mage.Sets/src/mage/cards/a/AminatousAugury.java b/Mage.Sets/src/mage/cards/a/AminatousAugury.java index 303954e3aa..8741698be0 100644 --- a/Mage.Sets/src/mage/cards/a/AminatousAugury.java +++ b/Mage.Sets/src/mage/cards/a/AminatousAugury.java @@ -1,15 +1,11 @@ package mage.cards.a; +import java.util.EnumSet; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.costs.Cost; -import mage.abilities.costs.CostImpl; -import mage.abilities.costs.Costs; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.cards.*; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.*; import mage.filter.StaticFilters; import mage.game.ExileZone; @@ -18,11 +14,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; - -import java.util.Arrays; -import java.util.EnumSet; -import java.util.Optional; import java.util.UUID; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; /** * @@ -50,20 +44,19 @@ public class AminatousAugury extends CardImpl { } -class AminatousAuguryEffect extends OneShotEffect{ +class AminatousAuguryEffect extends OneShotEffect { public AminatousAuguryEffect() { super(Outcome.PlayForFree); - staticText = "Exile the top eight cards of your library. You may put a land card from among them onto the" + - " battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from" + - " among the exiled cards without paying its mana cost."; + staticText = "Exile the top eight cards of your library. You may put a land card from among them onto the" + + " battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from" + + " among the exiled cards without paying its mana cost."; } public AminatousAuguryEffect(final AminatousAuguryEffect effect) { super(effect); } - @Override public AminatousAuguryEffect copy() { return new AminatousAuguryEffect(this); @@ -97,9 +90,8 @@ class AminatousAuguryEffect extends OneShotEffect{ } } } - AminatousAuguryExileHandler exileHandler = new AminatousAuguryExileHandler(cardsToCast, source, game); - for (Card card:cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND,game)) { - AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(card.getCardType(), exileHandler); + for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) { + AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(); effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game))); game.addEffect(effect, source); } @@ -109,20 +101,14 @@ class AminatousAuguryEffect extends OneShotEffect{ } class AminatousAuguryCastFromExileEffect extends AsThoughEffectImpl { - private final AminatousAuguryExileHandler cardTypeHandler; - private final EnumSet cardType; - public AminatousAuguryCastFromExileEffect(EnumSet cardType, AminatousAuguryExileHandler cardTypeTracker) { + public AminatousAuguryCastFromExileEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.PlayForFree); - this.cardTypeHandler = cardTypeTracker; - this.cardType = cardType; staticText = "Cast this card without paying its mana cost"; } public AminatousAuguryCastFromExileEffect(final AminatousAuguryCastFromExileEffect effect) { super(effect); - this.cardTypeHandler = effect.cardTypeHandler; - this.cardType = effect.cardType; } @Override @@ -137,117 +123,33 @@ class AminatousAuguryCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - if (!cardTypeHandler.atLeastOneAvailable(cardType)){ - return false; + Player player = game.getPlayer(affectedControllerId); + EnumSet cardTypes = EnumSet.noneOf(CardType.class); + Boolean checkType = false; + if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") != null) { + cardTypes = (EnumSet) game.getState().getValue(source.getSourceId().toString() + "cardTypes"); } - if (sourceId != null && sourceId.equals(getTargetPointer().getFirst(game, source)) + //TODO add code for choosing from multiple card types and adding additional costs to the card + if (player != null + && sourceId != null + && sourceId.equals(getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(sourceId); - if (card != null && game.getState().getZone(sourceId) == Zone.EXILED) { - Player player = game.getPlayer(affectedControllerId); - Costs costs = card.getSpellAbility().getCosts().copy(); - costs.add(new ConsumeCardTypeCost(cardType, cardTypeHandler)); - player.setCastSourceIdWithAlternateMana(sourceId, null, costs); - return true; + if (card != null + && game.getState().getZone(sourceId) == Zone.EXILED) { + for (CardType cardT : cardTypes) { + if (card.getCardType().contains(cardT)) { + checkType = true; + } + } + if (!checkType) { + player.setCastSourceIdWithAlternateMana(sourceId, null, null); + cardTypes.addAll(card.getCardType()); + game.getState().setValue(source.getSourceId().toString() + "cardTypes", cardTypes); + return true; + } } } return false; } } - - - -/** - * Tracks which card types have already been cast, and provides utility functions for confirming used types. - * (one ExileHandler is shared between all cards from a single cast of Animatou's Augury) - */ -class AminatousAuguryExileHandler { - private final EnumSet usedCardTypes; - - public AminatousAuguryExileHandler(Cards cards, Ability source, Game game){ - usedCardTypes = EnumSet.noneOf(CardType.class); - } - - public EnumSet availableTypes(EnumSet types){ - EnumSet available = EnumSet.copyOf(types); - available.removeAll(usedCardTypes); - return available; - } - - public boolean atLeastOneAvailable(EnumSet types){ - EnumSet available = availableTypes(types); - return !available.isEmpty(); - } - - public boolean useCardType(CardType type){ - if (usedCardTypes.contains(type)){ - return false; - } - usedCardTypes.add(type); - return true; - } - -} - -/** - * Allows the user to choose one of the given card types - */ -class CardTypeChoice extends ChoiceImpl{ - - public CardTypeChoice (EnumSet types){ - super(false); - for (CardType type:types){ - this.choices.add(type+""); - } - this.message = "Choose card type to cast as"; - } -} - -class ConsumeCardTypeCost extends CostImpl{ - - final private AminatousAuguryExileHandler exileHandler; - final private EnumSet types; - - public ConsumeCardTypeCost (EnumSet types, AminatousAuguryExileHandler exileHandler){ - this.exileHandler = exileHandler; - this.types = types; - this.text = "Cast as "+types; - } - - @Override - public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - return exileHandler.atLeastOneAvailable(types); - } - - @Override - public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { - if (isPaid()){ - return true; - } - CardType choiceType; - EnumSet availableChoices = exileHandler.availableTypes(types); - if (availableChoices.size()==1){ - // if there is only one possibility, don't need to prompt for a choice - choiceType = availableChoices.iterator().next(); - }else { - Choice choice = new CardTypeChoice(availableChoices); - if (!game.getPlayer(controllerId).choose(Outcome.Neutral, choice, game)) { - return false; - } - Optional optionalChoice = Arrays.stream(CardType.values()).filter(type -> type.toString().equals(choice.getChoice())).findAny(); - if (optionalChoice.isPresent()){ - choiceType = optionalChoice.get(); - }else{ - return false; - } - } - paid = exileHandler.useCardType(choiceType); - return paid; - } - - @Override - public Cost copy() { - return new ConsumeCardTypeCost(types, exileHandler); - } -} - diff --git a/Mage.Sets/src/mage/cards/a/AmphibiousKavu.java b/Mage.Sets/src/mage/cards/a/AmphibiousKavu.java new file mode 100644 index 0000000000..9548016486 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AmphibiousKavu.java @@ -0,0 +1,48 @@ + +package mage.cards.a; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.common.BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; + +/** + * + * @author L_J + */ +public final class AmphibiousKavu extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blue and/or black creatures"); + + static { + filter.add(Predicates.or(new ColorPredicate(ObjectColor.BLUE), new ColorPredicate(ObjectColor.BLACK))); + } + + public AmphibiousKavu(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + this.subtype.add(SubType.KAVU); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever Amphibious Kavu blocks or becomes blocked by one or more blue and/or black creatures, Amphibious Kavu gets +3/+3 until end of turn. + this.addAbility(new BlocksOrBecomesBlockedByOneOrMoreTriggeredAbility(new BoostSourceEffect(3, 3, Duration.EndOfTurn), filter, false)); + } + + public AmphibiousKavu(final AmphibiousKavu card) { + super(card); + } + + @Override + public AmphibiousKavu copy() { + return new AmphibiousKavu(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/Amplifire.java b/Mage.Sets/src/mage/cards/a/Amplifire.java new file mode 100644 index 0000000000..a93e1f986f --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Amplifire.java @@ -0,0 +1,90 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Amplifire extends CardImpl { + + public Amplifire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // At the beginning of your upkeep, reveal cards from the top of your library until you reveal a creature card. Until your next turn, Amplifire's base power becomes twice that card's power and its base toughness becomes twice that card's toughness. Put the revealed cards on the bottom of your library in a random order. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new AmplifireEffect(), TargetController.YOU, false + )); + } + + private Amplifire(final Amplifire card) { + super(card); + } + + @Override + public Amplifire copy() { + return new Amplifire(this); + } +} + +class AmplifireEffect extends OneShotEffect { + + AmplifireEffect() { + super(Outcome.Benefit); + staticText = "reveal cards from the top of your library until you reveal a creature card. " + + "Until your next turn, {this}'s base power becomes twice that card's power " + + "and its base toughness becomes twice that card's toughness. " + + "Put the revealed cards on the bottom of your library in a random order."; + } + + private AmplifireEffect(final AmplifireEffect effect) { + super(effect); + } + + @Override + public AmplifireEffect copy() { + return new AmplifireEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Card lastCard = null; + for (Card card : player.getLibrary().getCards(game)) { + if (card != null) { + cards.add(card); + if (card.isCreature()) { + lastCard = card; + break; + } + } + } + player.revealCards(source, cards, game); + if (lastCard != null) { + game.addEffect(new SetPowerToughnessSourceEffect( + 2 * lastCard.getPower().getValue(), + 2 * lastCard.getToughness().getValue(), + Duration.UntilYourNextTurn, SubLayer.SetPT_7b + ), source); + } + player.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AmrouSeekers.java b/Mage.Sets/src/mage/cards/a/AmrouSeekers.java index 006a78032c..e9f0358e37 100644 --- a/Mage.Sets/src/mage/cards/a/AmrouSeekers.java +++ b/Mage.Sets/src/mage/cards/a/AmrouSeekers.java @@ -22,7 +22,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class AmrouSeekers extends CardImpl { - private final static FilterCreaturePermanent notArtificatOrWhite = new FilterCreaturePermanent("except by artifact creatures and/or white creatures"); + private static final FilterCreaturePermanent notArtificatOrWhite = new FilterCreaturePermanent("except by artifact creatures and/or white creatures"); static { notArtificatOrWhite.add(Predicates.not( diff --git a/Mage.Sets/src/mage/cards/a/AmuletOfUnmaking.java b/Mage.Sets/src/mage/cards/a/AmuletOfUnmaking.java index 70272a0b5a..79decffc5d 100644 --- a/Mage.Sets/src/mage/cards/a/AmuletOfUnmaking.java +++ b/Mage.Sets/src/mage/cards/a/AmuletOfUnmaking.java @@ -1,11 +1,11 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ColorlessManaCost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,27 +16,32 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class AmuletOfUnmaking extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or enchantment"); + private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or land"); static { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.ENCHANTMENT))); + new CardTypePredicate(CardType.LAND) + )); } public AmuletOfUnmaking(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // {5}, {tap}, Exile Amulet of Unmaking: Exile target artifact, creature, or land. Activate this ability only any time you could cast a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect("Exile target artifact, creature or land"), new ColorlessManaCost(5)); + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new ExileTargetEffect(), new GenericManaCost(5) + ); ability.addCost(new TapSourceCost()); + ability.addCost(new ExileSourceCost()); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java index f77efb80a8..dbf3e6a841 100644 --- a/Mage.Sets/src/mage/cards/a/AnaBattlemage.java +++ b/Mage.Sets/src/mage/cards/a/AnaBattlemage.java @@ -34,7 +34,7 @@ public final class AnaBattlemage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creature"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public AnaBattlemage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AnabaAncestor.java b/Mage.Sets/src/mage/cards/a/AnabaAncestor.java index 261ab7c1e7..65a6936cc4 100644 --- a/Mage.Sets/src/mage/cards/a/AnabaAncestor.java +++ b/Mage.Sets/src/mage/cards/a/AnabaAncestor.java @@ -28,7 +28,7 @@ public final class AnabaAncestor extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MINOTAUR)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AnabaAncestor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AnafenzaKinTreeSpirit.java b/Mage.Sets/src/mage/cards/a/AnafenzaKinTreeSpirit.java index 3e6aa23196..3c8407616c 100644 --- a/Mage.Sets/src/mage/cards/a/AnafenzaKinTreeSpirit.java +++ b/Mage.Sets/src/mage/cards/a/AnafenzaKinTreeSpirit.java @@ -25,8 +25,8 @@ public final class AnafenzaKinTreeSpirit extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); } public AnafenzaKinTreeSpirit(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java b/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java index 16fb5ec22a..96e8487a47 100644 --- a/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java +++ b/Mage.Sets/src/mage/cards/a/AnafenzaTheForemost.java @@ -32,8 +32,8 @@ public final class AnafenzaTheForemost extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target tapped creature you control"); static { - filter.add(new AnotherPredicate()); - filter.add(new TappedPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(TappedPredicate.instance); } public AnafenzaTheForemost(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AncestorDragon.java b/Mage.Sets/src/mage/cards/a/AncestorDragon.java index ffb6f54a8a..ed0fce2629 100644 --- a/Mage.Sets/src/mage/cards/a/AncestorDragon.java +++ b/Mage.Sets/src/mage/cards/a/AncestorDragon.java @@ -1,6 +1,7 @@ package mage.cards.a; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksWithCreaturesTriggeredAbility; @@ -15,7 +16,6 @@ import mage.game.Game; import mage.players.Player; /** - * * @author TheElk801 */ public final class AncestorDragon extends CardImpl { @@ -46,8 +46,6 @@ public final class AncestorDragon extends CardImpl { class AncestorDragonEffect extends OneShotEffect { - private int attackers; - public AncestorDragonEffect() { super(Outcome.GainLife); staticText = "you gain 1 life for each attacking creature"; @@ -65,10 +63,9 @@ class AncestorDragonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - attackers = game.getCombat().getAttackers().size(); if (you != null) { + int attackers = game.getCombat().getAttackers().size(); you.gainLife(attackers, game, source); - attackers = 0; return true; } return false; diff --git a/Mage.Sets/src/mage/cards/a/AncestorsProphet.java b/Mage.Sets/src/mage/cards/a/AncestorsProphet.java index 356f2cf096..a83a788e70 100644 --- a/Mage.Sets/src/mage/cards/a/AncestorsProphet.java +++ b/Mage.Sets/src/mage/cards/a/AncestorsProphet.java @@ -27,7 +27,7 @@ public final class AncestorsProphet extends CardImpl { static { filter.add(new SubtypePredicate(SubType.CLERIC)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public AncestorsProphet(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AncestralMask.java b/Mage.Sets/src/mage/cards/a/AncestralMask.java index 60e6948212..bbfa90a874 100644 --- a/Mage.Sets/src/mage/cards/a/AncestralMask.java +++ b/Mage.Sets/src/mage/cards/a/AncestralMask.java @@ -24,7 +24,7 @@ public final class AncestralMask extends CardImpl { private static final FilterEnchantmentPermanent filter = new FilterEnchantmentPermanent("each other enchantment on the battlefield"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AncestralMask(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AncientExcavation.java b/Mage.Sets/src/mage/cards/a/AncientExcavation.java index 4965f68132..c339ac270d 100644 --- a/Mage.Sets/src/mage/cards/a/AncientExcavation.java +++ b/Mage.Sets/src/mage/cards/a/AncientExcavation.java @@ -61,7 +61,7 @@ class AncientExcavationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - DynamicValue numCards = new CardsInControllerHandCount(); + DynamicValue numCards = CardsInControllerHandCount.instance; int amount = numCards.calculate(game, source, this); player.drawCards(amount, game); player.discard(amount, false, source, game); diff --git a/Mage.Sets/src/mage/cards/a/AncientHellkite.java b/Mage.Sets/src/mage/cards/a/AncientHellkite.java index a07bb7320e..527f9bec33 100644 --- a/Mage.Sets/src/mage/cards/a/AncientHellkite.java +++ b/Mage.Sets/src/mage/cards/a/AncientHellkite.java @@ -29,7 +29,7 @@ public final class AncientHellkite extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public AncientHellkite(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AncientHolocron.java b/Mage.Sets/src/mage/cards/a/AncientHolocron.java index 565a7f334b..37c27e4836 100644 --- a/Mage.Sets/src/mage/cards/a/AncientHolocron.java +++ b/Mage.Sets/src/mage/cards/a/AncientHolocron.java @@ -23,7 +23,7 @@ public final class AncientHolocron extends CardImpl { private static final FilterSpell filter = new FilterSpell("multicolored spells"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public AncientHolocron(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AncientStirrings.java b/Mage.Sets/src/mage/cards/a/AncientStirrings.java index e9408b81cd..490c2641f5 100644 --- a/Mage.Sets/src/mage/cards/a/AncientStirrings.java +++ b/Mage.Sets/src/mage/cards/a/AncientStirrings.java @@ -20,7 +20,7 @@ public final class AncientStirrings extends CardImpl { private static final FilterCard filter = new FilterCard("a colorless card"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java b/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java index c9935eb2c3..bc7ddf8dac 100644 --- a/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java +++ b/Mage.Sets/src/mage/cards/a/AncientStoneIdol.java @@ -65,7 +65,7 @@ class AncientStoneIdolCostReductionEffect extends CostModificationEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public AncientStoneIdolCostReductionEffect() { diff --git a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java index 19a9acf838..b407c9e41f 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfCondemnation.java @@ -39,7 +39,7 @@ public final class AngelOfCondemnation extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AngelOfCondemnation(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AngelOfDeliverance.java b/Mage.Sets/src/mage/cards/a/AngelOfDeliverance.java index 166342229b..ba03f1345a 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfDeliverance.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfDeliverance.java @@ -1,7 +1,7 @@ - package mage.cards.a; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -24,7 +25,6 @@ import mage.game.events.GameEvent.EventType; import mage.target.common.TargetCreaturePermanent; /** - * * @author fireshoes */ public final class AngelOfDeliverance extends CardImpl { @@ -36,7 +36,7 @@ public final class AngelOfDeliverance extends CardImpl { } public AngelOfDeliverance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{W}{W}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -52,6 +52,7 @@ public final class AngelOfDeliverance extends CardImpl { "Delirium — Whenever {this} deals damage, if there are four or more card types among cards in your graveyard, exile target creature an opponent controls" ); ability.addTarget(new TargetCreaturePermanent(filter)); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AngelOfGrace.java b/Mage.Sets/src/mage/cards/a/AngelOfGrace.java new file mode 100644 index 0000000000..be50c0fc04 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelOfGrace.java @@ -0,0 +1,100 @@ +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.ExileSourceFromGraveCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.SetPlayerLifeSourceEffect; +import mage.abilities.keyword.FlashAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngelOfGrace extends CardImpl { + + public AngelOfGrace(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Angel of Grace enters the battlefield, until end of turn, damage that would reduce your life total to less than 1 reduces it to 1 instead. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AngelOfGraceReplacementEffect())); + + // {4}{W}{W}, Exile Angel of Grace from your graveyard: Your life total becomes 10. + Ability ability = new SimpleActivatedAbility( + Zone.GRAVEYARD, new SetPlayerLifeSourceEffect(10), new ManaCostsImpl("{4}{W}{W}") + ); + ability.addCost(new ExileSourceFromGraveCost()); + this.addAbility(ability); + } + + private AngelOfGrace(final AngelOfGrace card) { + super(card); + } + + @Override + public AngelOfGrace copy() { + return new AngelOfGrace(this); + } +} + +class AngelOfGraceReplacementEffect extends ReplacementEffectImpl { + + AngelOfGraceReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "until end of turn, damage that would reduce your life total to less than 1 reduces it to 1 instead"; + } + + private AngelOfGraceReplacementEffect(final AngelOfGraceReplacementEffect effect) { + super(effect); + } + + @Override + public AngelOfGraceReplacementEffect copy() { + return new AngelOfGraceReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CAUSES_LIFE_LOSS; + } + + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getPlayerId().equals(source.getControllerId())) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && (controller.getLife() - event.getAmount()) < 1) { + event.setAmount(controller.getLife() - 1); + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/a/AngelOfJubilation.java b/Mage.Sets/src/mage/cards/a/AngelOfJubilation.java index cb7bd64713..85a34e8ae6 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfJubilation.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfJubilation.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -80,7 +79,8 @@ class AngelOfJubilationEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Player player : game.getPlayers().values()) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); player.setCanPayLifeCost(false); player.setCanPaySacrificeCostFilter(new FilterCreaturePermanent()); } @@ -113,8 +113,10 @@ class AngelOfJubilationSacrificeFilterEffect extends CostModificationEffectImpl @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - return abilityToModify.getAbilityType() == AbilityType.ACTIVATED - || abilityToModify instanceof SpellAbility; + + return (abilityToModify.getAbilityType() == AbilityType.ACTIVATED + || abilityToModify instanceof SpellAbility) + && game.getState().getPlayersInRange(source.getControllerId(), game).contains(abilityToModify.getControllerId()); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AngelOfRenewal.java b/Mage.Sets/src/mage/cards/a/AngelOfRenewal.java index 85b19cabf8..09c42722ee 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfRenewal.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfRenewal.java @@ -1,20 +1,18 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class AngelOfRenewal extends CardImpl { @@ -29,9 +27,7 @@ public final class AngelOfRenewal extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When Angel of Renewal enters the battlefield, you gain 1 life for each creature you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect( - new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE) - ))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(CreaturesYouControlCount.instance))); } public AngelOfRenewal(final AngelOfRenewal card) { diff --git a/Mage.Sets/src/mage/cards/a/AngelOfSanctions.java b/Mage.Sets/src/mage/cards/a/AngelOfSanctions.java index 2d61c57d49..c6ebd9d003 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfSanctions.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfSanctions.java @@ -26,7 +26,7 @@ import mage.target.TargetPermanent; */ public final class AngelOfSanctions extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java index b34df8718c..4dfb63bbc4 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java @@ -1,43 +1,34 @@ - package mage.cards.a; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; -import mage.abilities.common.ZoneChangeTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.AnotherPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardIdPredicate; import mage.target.Target; -import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetCreaturePermanent; -import mage.util.CardUtil; +import mage.target.common.TargetCardInGraveyardOrBattlefield; /** * * @author LevelX2 */ public final class AngelOfSerenity extends CardImpl { + + private static final String rule = "you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards."; public AngelOfSerenity(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}{W}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(5); @@ -47,7 +38,12 @@ public final class AngelOfSerenity extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Angel of Serenity enters the battlefield, you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards. - this.addAbility(new AngelOfSerenityTriggeredAbility()); + FilterCreatureCard filter = new FilterCreatureCard("creatures from the battlefield and/or a graveyard"); + filter.add(Predicates.not(new CardIdPredicate(this.getId()))); + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect().setText(rule), true); + Target target = new TargetCardInGraveyardOrBattlefield(0, 3, filter); + ability.addTarget(target); + this.addAbility(ability); // When Angel of Serenity leaves the battlefield, return the exiled cards to their owners' hands. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.HAND, false, true), false)); @@ -62,92 +58,3 @@ public final class AngelOfSerenity extends CardImpl { return new AngelOfSerenity(this); } } - -class AngelOfSerenityTriggeredAbility extends ZoneChangeTriggeredAbility { - - public AngelOfSerenityTriggeredAbility() { - super(Zone.BATTLEFIELD, new AngelOfSerenityEnterEffect(), "When {this} enters the battlefield, ", true); - } - - public AngelOfSerenityTriggeredAbility(AngelOfSerenityTriggeredAbility ability) { - super(ability); - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (super.checkTrigger(event, game)) { - getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("up to three other target creatures"); - filter.add(new AnotherPredicate()); - TargetCreaturePermanent target1 = new TargetCreaturePermanent(0, 3, filter, false); - game.getPlayer(getControllerId()).chooseTarget(Outcome.Exile, target1, this, game); - if (!target1.getTargets().isEmpty()) { - getTargets().add(target1); - - } - int leftTargets = 3 - target1.getTargets().size(); - if (leftTargets > 0) { - FilterCard filter2 = new FilterCreatureCard("up to " + leftTargets + " target creature card" + (leftTargets > 1 ? "s" : "") + " from graveyards"); - TargetCardInGraveyard target2 = new TargetCardInGraveyard(0, leftTargets, filter2); - game.getPlayer(getControllerId()).chooseTarget(Outcome.Exile, target2, this, game); - if (!target2.getTargets().isEmpty()) { - getTargets().add(target2); - } - } - return true; - } - return false; - } - - @Override - public AngelOfSerenityTriggeredAbility copy() { - return new AngelOfSerenityTriggeredAbility(this); - } - -} - -class AngelOfSerenityEnterEffect extends OneShotEffect { - - public AngelOfSerenityEnterEffect() { - super(Outcome.ReturnToHand); - this.staticText = "you may exile up to three other target creatures from the battlefield and/or creature cards from graveyards"; - } - - public AngelOfSerenityEnterEffect(final AngelOfSerenityEnterEffect effect) { - super(effect); - } - - @Override - public AngelOfSerenityEnterEffect copy() { - return new AngelOfSerenityEnterEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - boolean result = true; - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null && !source.getTargets().isEmpty()) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - for (Target target : source.getTargets()) { - if (target instanceof TargetCreaturePermanent) { - for (UUID permanentId : target.getTargets()) { - Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { - result |= controller.moveCardToExileWithInfo(permanent, exileZoneId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); - } - } - - } else if (target instanceof TargetCardInGraveyard) { - for (UUID cardId : target.getTargets()) { - Card card = game.getCard(cardId); - if (card != null) { - result |= controller.moveCardToExileWithInfo(card, exileZoneId, sourceObject.getIdName(), source.getSourceId(), game, Zone.GRAVEYARD, true); - } - } - } - } - } - return result; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AngelicArbiter.java b/Mage.Sets/src/mage/cards/a/AngelicArbiter.java index 75693f80c0..167a878e73 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicArbiter.java +++ b/Mage.Sets/src/mage/cards/a/AngelicArbiter.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -18,8 +16,9 @@ import mage.game.permanent.Permanent; import mage.watchers.common.CastSpellLastTurnWatcher; import mage.watchers.common.PlayerAttackedWatcher; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class AngelicArbiter extends CardImpl { @@ -66,16 +65,14 @@ class AngelicArbiterCantAttackTargetEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (game.isActivePlayer(permanent.getControllerId()) && game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(permanent.getControllerId()) > 0) { - return true; - } + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(permanent.getControllerId()) > 0; } return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @@ -114,10 +111,8 @@ class AngelicArbiterEffect2 extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.isActivePlayer(event.getPlayerId()) && game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { - PlayerAttackedWatcher watcher = (PlayerAttackedWatcher) game.getState().getWatchers().get(PlayerAttackedWatcher.class.getSimpleName()); - if (watcher != null && watcher.getNumberOfAttackersCurrentTurn(event.getPlayerId()) > 0) { - return true; - } + PlayerAttackedWatcher watcher = game.getState().getWatcher(PlayerAttackedWatcher.class); + return watcher != null && watcher.getNumberOfAttackersCurrentTurn(event.getPlayerId()) > 0; } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AngelicCaptain.java b/Mage.Sets/src/mage/cards/a/AngelicCaptain.java index 4f04176e98..3b16d8ebfb 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicCaptain.java +++ b/Mage.Sets/src/mage/cards/a/AngelicCaptain.java @@ -26,7 +26,7 @@ public final class AngelicCaptain extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AngelicCaptain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AngelicExaltation.java b/Mage.Sets/src/mage/cards/a/AngelicExaltation.java new file mode 100644 index 0000000000..df3b3f66f8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelicExaltation.java @@ -0,0 +1,81 @@ +package mage.cards.a; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngelicExaltation extends CardImpl { + + public AngelicExaltation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of creatures you control. + this.addAbility(new AngelicExaltationAbility().addHint(CreaturesYouControlHint.instance)); + } + + private AngelicExaltation(final AngelicExaltation card) { + super(card); + } + + @Override + public AngelicExaltation copy() { + return new AngelicExaltation(this); + } +} + +class AngelicExaltationAbility extends TriggeredAbilityImpl { + + public AngelicExaltationAbility() { + super(Zone.BATTLEFIELD, new BoostTargetEffect(CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, true), false); + } + + public AngelicExaltationAbility(final AngelicExaltationAbility ability) { + super(ability); + } + + @Override + public AngelicExaltationAbility copy() { + return new AngelicExaltationAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.isActivePlayer(this.controllerId)) { + if (game.getCombat().attacksAlone()) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackers().get(0))); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever a creature you control attacks alone, " + + "it gets +X/+X until end of turn, " + + "where X is the number of creatures you control."; + } + +} diff --git a/Mage.Sets/src/mage/cards/a/AngelicFavor.java b/Mage.Sets/src/mage/cards/a/AngelicFavor.java index 9ab91cae5d..0fb54f8153 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicFavor.java +++ b/Mage.Sets/src/mage/cards/a/AngelicFavor.java @@ -38,7 +38,7 @@ public final class AngelicFavor extends CardImpl { private static final FilterControlledCreaturePermanent untappedCreatureYouControl = new FilterControlledCreaturePermanent("untapped creature you control"); static { - untappedCreatureYouControl.add(Predicates.not(new TappedPredicate())); + untappedCreatureYouControl.add(Predicates.not(TappedPredicate.instance)); } public AngelicFavor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AngelicReward.java b/Mage.Sets/src/mage/cards/a/AngelicReward.java new file mode 100644 index 0000000000..dce1309e72 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngelicReward.java @@ -0,0 +1,53 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +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.FlyingAbility; +import mage.abilities.keyword.TotemArmorAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.abilities.mana.WhiteManaAbility; +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 JayDi85 + */ + +public final class AngelicReward extends CardImpl { + + public AngelicReward(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +3/+3 and has flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + } + + public AngelicReward(final AngelicReward card) { + super(card); + } + + @Override + public AngelicReward copy() { + return new AngelicReward(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AngelicVoices.java b/Mage.Sets/src/mage/cards/a/AngelicVoices.java index 4cfe3696d6..4a3dc8e834 100644 --- a/Mage.Sets/src/mage/cards/a/AngelicVoices.java +++ b/Mage.Sets/src/mage/cards/a/AngelicVoices.java @@ -1,9 +1,8 @@ - package mage.cards.a; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalContinuousEffect; @@ -13,20 +12,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ColorPredicate; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class AngelicVoices extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("nonartifact, nonwhite creatures"); + private static final FilterPermanent filter = new FilterCreaturePermanent("nonartifact, nonwhite creatures"); static { filter.add(Predicates.not( @@ -38,15 +38,15 @@ public final class AngelicVoices extends CardImpl { filter.add(new ControllerPredicate(TargetController.YOU)); } + private static final Condition condition = new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)); + public AngelicVoices(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures. this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new ConditionalContinuousEffect( - new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield), - new InvertCondition(new PermanentsOnTheBattlefieldCondition(filter)), + new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield), condition, "Creatures you control get +1/+1 as long as you control no nonartifact, nonwhite creatures." ) )); diff --git a/Mage.Sets/src/mage/cards/a/AngelsFeather.java b/Mage.Sets/src/mage/cards/a/AngelsFeather.java index 351a64d2bb..193eeeefb0 100644 --- a/Mage.Sets/src/mage/cards/a/AngelsFeather.java +++ b/Mage.Sets/src/mage/cards/a/AngelsFeather.java @@ -17,7 +17,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class AngelsFeather extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a white spell"); + private static final FilterSpell filter = new FilterSpell("a white spell"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); diff --git a/Mage.Sets/src/mage/cards/a/AngelsTomb.java b/Mage.Sets/src/mage/cards/a/AngelsTomb.java index 6cd8c0e5ad..9eec7a6286 100644 --- a/Mage.Sets/src/mage/cards/a/AngelsTomb.java +++ b/Mage.Sets/src/mage/cards/a/AngelsTomb.java @@ -1,10 +1,8 @@ package mage.cards.a; -import java.util.UUID; - -import mage.MageInt; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -12,10 +10,12 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.game.permanent.token.TokenImpl; -import mage.game.permanent.token.Token; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.game.permanent.token.custom.CreatureToken; +import java.util.UUID; + /** * @author Loki */ @@ -25,12 +25,18 @@ public final class AngelsTomb extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Whenever a creature enters the battlefield under your control, you may have Angel's Tomb become a 3/3 white Angel artifact creature with flying until end of turn. - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new BecomesCreatureSourceEffect( - new CreatureToken(3, 3, "3/3 white Angel artifact creature with flying") - .withColor("W") - .withSubType(SubType.ANGEL) - .withAbility(FlyingAbility.getInstance()), - "", Duration.EndOfTurn), true)); + Effect effect = new BecomesCreatureSourceEffect(new CreatureToken(3, 3, "3/3 white Angel artifact creature with flying") + .withColor("W") + .withSubType(SubType.ANGEL) + .withAbility(FlyingAbility.getInstance()), + "", Duration.EndOfTurn) + .setText("have {this} become a 3/3 white Angel artifact creature with flying until end of turn"); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + effect, + StaticFilters.FILTER_PERMANENT_CREATURE_A, + true) + ); } public AngelsTomb(final AngelsTomb card) { diff --git a/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java b/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java index 0f415cc405..5de5f29b03 100644 --- a/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java +++ b/Mage.Sets/src/mage/cards/a/AngelsTrumpet.java @@ -64,15 +64,15 @@ class AngelsTrumpetTapEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(game.getActivePlayerId()); - int count = 0; if (player != null) { + int count = 0; for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) { // Untapped creatures are safe. if (creature.isTapped()) { continue; } // Creatures that attacked are safe. - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(creature, game))) { continue; } diff --git a/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java b/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java new file mode 100644 index 0000000000..9827fa6684 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngrathCaptainOfChaos.java @@ -0,0 +1,49 @@ +package mage.cards.a; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.MenaceAbility; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngrathCaptainOfChaos extends CardImpl { + + public AngrathCaptainOfChaos(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B/R}{B/R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ANGRATH); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Creatures you control have menace. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new MenaceAbility(false), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); + + // -2: Amass 2. (Put two +1/+1 counters on an Army you control. If you don’t control one, create a 0/0 black Zombie Army creature token first.) + this.addAbility(new LoyaltyAbility(new AmassEffect(2), -2)); + } + + private AngrathCaptainOfChaos(final AngrathCaptainOfChaos card) { + super(card); + } + + @Override + public AngrathCaptainOfChaos copy() { + return new AngrathCaptainOfChaos(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AngrathsFury.java b/Mage.Sets/src/mage/cards/a/AngrathsFury.java index 40cfd16459..dcf0f829f4 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathsFury.java +++ b/Mage.Sets/src/mage/cards/a/AngrathsFury.java @@ -20,7 +20,7 @@ import mage.target.targetpointer.SecondTargetPointer; */ public final class AngrathsFury extends CardImpl { - private final static FilterCard filter = new FilterCard("Angrath, Minotaur Pirate"); + private static final FilterCard filter = new FilterCard("Angrath, Minotaur Pirate"); static { filter.add(new NamePredicate(filter.getMessage())); diff --git a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java index 665411c981..cd6f1f2366 100644 --- a/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java +++ b/Mage.Sets/src/mage/cards/a/AngrathsMarauders.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -15,6 +14,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; import mage.util.CardUtil; /** @@ -63,15 +63,9 @@ class AngrathsMaraudersEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch (event.getType()) { - case DAMAGE_PLAYER: - return true; - case DAMAGE_CREATURE: - return true; - case DAMAGE_PLANESWALKER: - return true; - } - return false; + return event.getType().equals(EventType.DAMAGE_PLAYER) + || event.getType().equals(EventType.DAMAGE_CREATURE) + || event.getType().equals(EventType.DAMAGE_PLANESWALKER); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AngrathsRampage.java b/Mage.Sets/src/mage/cards/a/AngrathsRampage.java new file mode 100644 index 0000000000..b97ee95945 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AngrathsRampage.java @@ -0,0 +1,54 @@ +package mage.cards.a; + +import mage.abilities.Mode; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AngrathsRampage extends CardImpl { + + public AngrathsRampage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{R}"); + + // Choose one: + // • Target player sacrifices an artifact. + this.getSpellAbility().addEffect(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_ARTIFACT, + 1, "Target player" + )); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // • Target player sacrifices a creature. + Mode mode = new Mode(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, + 1, "Target player" + )); + mode.addTarget(new TargetPlayer()); + this.getSpellAbility().addMode(mode); + + // • Target player sacrifices a planeswalker. + mode = new Mode(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_PLANESWALKER, + 1, "Target player" + )); + mode.addTarget(new TargetPlayer()); + this.getSpellAbility().addMode(mode); + } + + private AngrathsRampage(final AngrathsRampage card) { + super(card); + } + + @Override + public AngrathsRampage copy() { + return new AngrathsRampage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java b/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java index ee3bfbd111..c5a369e1a8 100644 --- a/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java +++ b/Mage.Sets/src/mage/cards/a/AnimalMagnetism.java @@ -60,8 +60,7 @@ class AnimalMagnetismEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); if (!cards.isEmpty()) { controller.revealCards(staticText, cards, game); Card cardToBattlefield; diff --git a/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java b/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java index f7291fa112..94e44b7c8e 100644 --- a/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java +++ b/Mage.Sets/src/mage/cards/a/AnimarSoulOfElements.java @@ -69,7 +69,7 @@ class AnimarCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - Ability spellAbility = (SpellAbility) abilityToModify; + Ability spellAbility = abilityToModify; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && spellAbility != null) { int amount = sourcePermanent.getCounters(game).getCount(CounterType.P1P1); diff --git a/Mage.Sets/src/mage/cards/a/AnimateDead.java b/Mage.Sets/src/mage/cards/a/AnimateDead.java index c74a187ef3..0f833cc16e 100644 --- a/Mage.Sets/src/mage/cards/a/AnimateDead.java +++ b/Mage.Sets/src/mage/cards/a/AnimateDead.java @@ -189,7 +189,7 @@ class AnimateDeadAttachEffect extends OneShotEffect { class AnimateDeadChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { - private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Animate Dead"); + private static final Ability newAbility = new EnchantAbility("creature put onto the battlefield with Animate Dead"); static { newAbility.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/cards/a/AnointerPriest.java b/Mage.Sets/src/mage/cards/a/AnointerPriest.java index 31784994a2..bc4f0e4e88 100644 --- a/Mage.Sets/src/mage/cards/a/AnointerPriest.java +++ b/Mage.Sets/src/mage/cards/a/AnointerPriest.java @@ -24,7 +24,7 @@ public final class AnointerPriest extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("a creature token"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public AnointerPriest(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Antagonism.java b/Mage.Sets/src/mage/cards/a/Antagonism.java new file mode 100644 index 0000000000..0ad3603e87 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/Antagonism.java @@ -0,0 +1,64 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.watchers.common.BloodthirstWatcher; + +/** + * + * @author jeffwadsworth + */ +public final class Antagonism extends CardImpl { + + private static final String rule = "{this} deals 2 damage to that player unless one of their opponents was dealt damage this turn"; + + public Antagonism(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); + + // At the beginning of each player's end step, Antagonism deals 2 damage to that player unless one of their opponents was dealt damage this turn. + this.addAbility(new BeginningOfEndStepTriggeredAbility(new ConditionalOneShotEffect(new DamageTargetEffect(2), + new OpponentWasNotDealtDamageCondition(), rule), TargetController.ANY, false)); + + } + + public Antagonism(final Antagonism card) { + super(card); + } + + @Override + public Antagonism copy() { + return new Antagonism(this); + } +} + +class OpponentWasNotDealtDamageCondition implements Condition { + + public OpponentWasNotDealtDamageCondition() { + } + + @Override + public boolean apply(Game game, Ability source) { + UUID activePlayer = game.getState().getActivePlayerId(); + if (activePlayer != null) { + BloodthirstWatcher watcher = game.getState().getWatcher(BloodthirstWatcher.class, activePlayer); + if (watcher != null) { + return !watcher.conditionMet(); + } + } + return false; + } + + @Override + public String toString() { + return "if an opponent was dealt damage this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ApexHawks.java b/Mage.Sets/src/mage/cards/a/ApexHawks.java index 796decca43..12d41455eb 100644 --- a/Mage.Sets/src/mage/cards/a/ApexHawks.java +++ b/Mage.Sets/src/mage/cards/a/ApexHawks.java @@ -35,7 +35,7 @@ public final class ApexHawks extends CardImpl { // Apex Hawks enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true) + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true) ,"with a +1/+1 counter on it for each time it was kicked")); } diff --git a/Mage.Sets/src/mage/cards/a/AphettoDredging.java b/Mage.Sets/src/mage/cards/a/AphettoDredging.java index 5dcd18c3df..9309b1bd80 100644 --- a/Mage.Sets/src/mage/cards/a/AphettoDredging.java +++ b/Mage.Sets/src/mage/cards/a/AphettoDredging.java @@ -1,9 +1,7 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; @@ -18,9 +16,11 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Quercitron */ public final class AphettoDredging extends CardImpl { @@ -32,20 +32,7 @@ public final class AphettoDredging extends CardImpl { Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return up to three target creature cards of the creature type of your choice from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player controller = game.getPlayer(ability.getControllerId()); - Choice typeChoice = new ChoiceCreatureType(game.getObject(ability.getSourceId())); - if (controller != null && controller.choose(Outcome.PutCreatureInPlay, typeChoice, game)) { - String chosenType = typeChoice.getChoice(); - FilterCreatureCard filter = new FilterCreatureCard(chosenType + " cards"); - filter.add(new SubtypePredicate(SubType.byDescription(chosenType))); - ability.addTarget(new TargetCardInYourGraveyard(0, 3, filter)); - } - } + this.getSpellAbility().setTargetAdjuster(AphettoDredgingAdjuster.instance); } public AphettoDredging(final AphettoDredging card) { @@ -57,3 +44,19 @@ public final class AphettoDredging extends CardImpl { return new AphettoDredging(this); } } + +enum AphettoDredgingAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + Choice typeChoice = new ChoiceCreatureType(game.getObject(ability.getSourceId())); + if (controller != null && controller.choose(Outcome.PutCreatureInPlay, typeChoice, game)) { + String chosenType = typeChoice.getChoice(); + FilterCreatureCard filter = new FilterCreatureCard(chosenType + " cards"); + filter.add(new SubtypePredicate(SubType.byDescription(chosenType))); + ability.addTarget(new TargetCardInYourGraveyard(0, 3, filter)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AphettoGrifter.java b/Mage.Sets/src/mage/cards/a/AphettoGrifter.java index a00ec7bb62..c1e7324741 100644 --- a/Mage.Sets/src/mage/cards/a/AphettoGrifter.java +++ b/Mage.Sets/src/mage/cards/a/AphettoGrifter.java @@ -28,7 +28,7 @@ public final class AphettoGrifter extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Wizards you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.WIZARD)); } diff --git a/Mage.Sets/src/mage/cards/a/ApocalypseChime.java b/Mage.Sets/src/mage/cards/a/ApocalypseChime.java index 18f862f153..178b6930de 100644 --- a/Mage.Sets/src/mage/cards/a/ApocalypseChime.java +++ b/Mage.Sets/src/mage/cards/a/ApocalypseChime.java @@ -27,7 +27,7 @@ public final class ApocalypseChime extends CardImpl { static { filter.add(Predicates.and( - Predicates.not(new TokenPredicate()), + Predicates.not(TokenPredicate.instance), new ExpansionSetPredicate("HML") )); } diff --git a/Mage.Sets/src/mage/cards/a/ApocalypseDemon.java b/Mage.Sets/src/mage/cards/a/ApocalypseDemon.java index db37a8a443..9a1882a6e7 100644 --- a/Mage.Sets/src/mage/cards/a/ApocalypseDemon.java +++ b/Mage.Sets/src/mage/cards/a/ApocalypseDemon.java @@ -25,7 +25,7 @@ public final class ApocalypseDemon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ApocalypseDemon(UUID ownerId, CardSetInfo cardSetInfo) { diff --git a/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java b/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java index aa93fa740d..d0d536f087 100644 --- a/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java +++ b/Mage.Sets/src/mage/cards/a/ApocalypseHydra.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -23,14 +22,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class ApocalypseHydra extends CardImpl { public ApocalypseHydra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{X}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{R}{G}"); this.subtype.add(SubType.HYDRA); this.power = new MageInt(0); @@ -46,7 +46,7 @@ public final class ApocalypseHydra extends CardImpl { this.addAbility(ability); } - public ApocalypseHydra(final ApocalypseHydra card) { + private ApocalypseHydra(final ApocalypseHydra card) { super(card); } @@ -63,28 +63,29 @@ class ApocalypseHydraEffect extends OneShotEffect { staticText = "with X +1/+1 counters on it. If X is 5 or more, it enters the battlefield with an additional X +1/+1 counters on it"; } - ApocalypseHydraEffect(final ApocalypseHydraEffect effect) { + private ApocalypseHydraEffect(final ApocalypseHydraEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if (permanent != null) { - SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); - if (spellAbility != null - && spellAbility.getSourceId().equals(source.getSourceId()) - && permanent.getZoneChangeCounter(game) == spellAbility.getSourceObjectZoneChangeCounter()) { - int amount = spellAbility.getManaCostsToPay().getX(); - if (amount > 0) { - if (amount < 5) { - permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game); - } else { - permanent.addCounters(CounterType.P1P1.createInstance(amount * 2), source, game); - } - } + if (permanent == null) { + return false; + } + SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); + if (spellAbility == null + || !spellAbility.getSourceId().equals(source.getSourceId()) + || permanent.getZoneChangeCounter(game) != spellAbility.getSourceObjectZoneChangeCounter()) { + return false; + } + int amount = spellAbility.getManaCostsToPay().getX(); + if (amount > 0) { + if (amount < 5) { + permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game); + } else { + permanent.addCounters(CounterType.P1P1.createInstance(amount * 2), source, game); } - return true; } return true; } diff --git a/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java b/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java index 97bf7f87a6..a4cbd66ee7 100644 --- a/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java +++ b/Mage.Sets/src/mage/cards/a/ApothecaryGeist.java @@ -27,7 +27,7 @@ public final class ApothecaryGeist extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Elf"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.SPIRIT)); } diff --git a/Mage.Sets/src/mage/cards/a/AppealAuthority.java b/Mage.Sets/src/mage/cards/a/AppealAuthority.java index 0405aca0f8..3fd64be5f6 100644 --- a/Mage.Sets/src/mage/cards/a/AppealAuthority.java +++ b/Mage.Sets/src/mage/cards/a/AppealAuthority.java @@ -1,17 +1,14 @@ - package mage.cards.a; -import java.util.UUID; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.AftermathAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; -import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.SplitCard; import mage.constants.CardType; @@ -23,8 +20,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AppealAuthority extends SplitCard { @@ -36,14 +34,14 @@ public final class AppealAuthority extends SplitCard { // Until end of turn, target creature gains trample and gets +X/+X, where X is the number of creatures you control. getLeftHalfCard().getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn) .setText("Until end of turn, target creature gains trample")); - DynamicValue controlledCreatures = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("the number of creatures you control")); - getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(controlledCreatures, controlledCreatures, Duration.EndOfTurn, true) + getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, true) .setText("and gets +X/+X, where X is the number of creatures you control")); getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + getLeftHalfCard().getSpellAbility().addHint(CreaturesYouControlHint.instance); // Authority // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Tap up to two target creatures your opponents control. Creatures you control gain vigilance until end of turn. getRightHalfCard().getSpellAbility().addEffect(new TapTargetEffect()); FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures your opponents control"); diff --git a/Mage.Sets/src/mage/cards/a/AppliedBiomancy.java b/Mage.Sets/src/mage/cards/a/AppliedBiomancy.java new file mode 100644 index 0000000000..9bdb39eab2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AppliedBiomancy.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.abilities.Mode; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AppliedBiomancy extends CardImpl { + + public AppliedBiomancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}"); + + // Choose one or both — + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // • Target creature gets +1/+1 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(1, 1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets +1/+1 until end of turn")); + + // • Return target creature to its owner's hand. + Mode mode = new Mode(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCreaturePermanent().withChooseHint("return to its owner's hand")); + this.getSpellAbility().addMode(mode); + } + + private AppliedBiomancy(final AppliedBiomancy card) { + super(card); + } + + @Override + public AppliedBiomancy copy() { + return new AppliedBiomancy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java index 1877fee325..76cf887d40 100644 --- a/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java +++ b/Mage.Sets/src/mage/cards/a/ApproachOfTheSecondSun.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.*; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -16,6 +15,10 @@ import mage.game.stack.Spell; import mage.players.Player; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * @author stravant */ @@ -62,9 +65,9 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { Spell spell = game.getStack().getSpell(source.getSourceId()); if (controller != null && spell != null) { ApproachOfTheSecondSunWatcher watcher - = (ApproachOfTheSecondSunWatcher) game.getState().getWatchers().get(ApproachOfTheSecondSunWatcher.class.getSimpleName()); + = game.getState().getWatcher(ApproachOfTheSecondSunWatcher.class); if (watcher != null - && !spell.isCopiedSpell() + && !spell.isCopy() && watcher.getApproachesCast(controller.getId()) > 1 && spell.getFromZone() == Zone.HAND) { // Win the game @@ -74,7 +77,7 @@ class ApproachOfTheSecondSunEffect extends OneShotEffect { controller.gainLife(7, game, source); // Put this into the library as the 7th from the top - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { return true; } Card spellCard = game.getStack().getSpell(source.getSourceId()).getCard(); @@ -93,7 +96,7 @@ class ApproachOfTheSecondSunWatcher extends Watcher { private Map approachesCast = new HashMap<>(); public ApproachOfTheSecondSunWatcher() { - super(ApproachOfTheSecondSunWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ApproachOfTheSecondSunWatcher(final ApproachOfTheSecondSunWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/a/AquamorphEntity.java b/Mage.Sets/src/mage/cards/a/AquamorphEntity.java index 1ab44d76a0..637577aca2 100644 --- a/Mage.Sets/src/mage/cards/a/AquamorphEntity.java +++ b/Mage.Sets/src/mage/cards/a/AquamorphEntity.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -21,8 +20,9 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AquamorphEntity extends CardImpl { @@ -42,7 +42,7 @@ public final class AquamorphEntity extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{U}"))); } - public AquamorphEntity(final AquamorphEntity card) { + private AquamorphEntity(final AquamorphEntity card) { super(card); } @@ -57,12 +57,12 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { private static final String choice51 = "a 5/1 creature"; private static final String choice15 = "a 1/5 creature"; - public AquamorphEntityReplacementEffect() { + AquamorphEntityReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); staticText = "as {this} enters the battlefield or is turned face up, it becomes your choice of 5/1 or 1/5"; } - public AquamorphEntityReplacementEffect(AquamorphEntityReplacementEffect effect) { + private AquamorphEntityReplacementEffect(AquamorphEntityReplacementEffect effect) { super(effect); } @@ -103,34 +103,32 @@ class AquamorphEntityReplacementEffect extends ReplacementEffectImpl { } else { permanent = game.getPermanent(event.getTargetId()); } - if (permanent != null) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Choose what the creature becomes to"); - choice.getChoices().add(choice51); - choice.getChoices().add(choice15); - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (!controller.choose(Outcome.Neutral, choice, game)) { - discard(); - return false; - } - } - int power = 0; - int toughness = 0; - switch (choice.getChoice()) { - case choice51: - power = 5; - toughness = 1; - break; - case choice15: - power = 1; - toughness = 5; - break; - } - game.addEffect(new SetPowerToughnessSourceEffect(power, toughness, Duration.Custom, SubLayer.SetPT_7b), source); + if (permanent == null) { + return false; } - return false; - + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose what the creature becomes to"); + choice.getChoices().add(choice51); + choice.getChoices().add(choice15); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && !controller.choose(Outcome.Neutral, choice, game)) { + discard(); + return false; + } + int power = 0; + int toughness = 0; + switch (choice.getChoice()) { + case choice51: + power = 5; + toughness = 1; + break; + case choice15: + power = 1; + toughness = 5; + break; + } + game.addEffect(new SetPowerToughnessSourceEffect(power, toughness, Duration.Custom, SubLayer.SetPT_7b), source); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AquitectsWill.java b/Mage.Sets/src/mage/cards/a/AquitectsWill.java index 29ee455491..b9b1d00d7f 100644 --- a/Mage.Sets/src/mage/cards/a/AquitectsWill.java +++ b/Mage.Sets/src/mage/cards/a/AquitectsWill.java @@ -25,7 +25,7 @@ import java.util.UUID; */ public final class AquitectsWill extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("Merfolk"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Merfolk"); static { filter.add(new SubtypePredicate(SubType.MERFOLK)); diff --git a/Mage.Sets/src/mage/cards/a/ArachnusSpinner.java b/Mage.Sets/src/mage/cards/a/ArachnusSpinner.java index 3d5fca4ea8..3c4d17cc49 100644 --- a/Mage.Sets/src/mage/cards/a/ArachnusSpinner.java +++ b/Mage.Sets/src/mage/cards/a/ArachnusSpinner.java @@ -39,7 +39,7 @@ public final class ArachnusSpinner extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SPIDER)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ArachnusSpinner(UUID ownerId, CardSetInfo setInfo) { @@ -106,7 +106,7 @@ class ArachnusSpinnerEffect extends OneShotEffect { } if (card == null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java b/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java index 9eb4e17736..c0b9086041 100644 --- a/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java +++ b/Mage.Sets/src/mage/cards/a/ArahboRoarOfTheWorld.java @@ -41,10 +41,10 @@ public final class ArahboRoarOfTheWorld extends CardImpl { static { filter.add(new SubtypePredicate(SubType.CAT)); filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter2.add(new SubtypePredicate(SubType.CAT)); filter2.add(new ControllerPredicate(TargetController.YOU)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public ArahboRoarOfTheWorld(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/ArashiTheSkyAsunder.java b/Mage.Sets/src/mage/cards/a/ArashiTheSkyAsunder.java index 7a91c68a67..e474a02af8 100644 --- a/Mage.Sets/src/mage/cards/a/ArashiTheSkyAsunder.java +++ b/Mage.Sets/src/mage/cards/a/ArashiTheSkyAsunder.java @@ -43,13 +43,13 @@ public final class ArashiTheSkyAsunder extends CardImpl { this.toughness = new MageInt(5); // {X}{G}, {tap}: Arashi, the Sky Asunder deals X damage to target creature with flying. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{G}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{G}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // Channel - {X}{G}{G}, Discard Arashi: Arashi deals X damage to each creature with flying. - this.addAbility(new ChannelAbility("{X}{G}{G}", new DamageAllEffect(new ManacostVariableValue(), filter))); + this.addAbility(new ChannelAbility("{X}{G}{G}", new DamageAllEffect(ManacostVariableValue.instance, filter))); } public ArashiTheSkyAsunder(final ArashiTheSkyAsunder card) { diff --git a/Mage.Sets/src/mage/cards/a/ArashinForemost.java b/Mage.Sets/src/mage/cards/a/ArashinForemost.java index fdee5a88fc..2fbb32c68a 100644 --- a/Mage.Sets/src/mage/cards/a/ArashinForemost.java +++ b/Mage.Sets/src/mage/cards/a/ArashinForemost.java @@ -27,7 +27,7 @@ public final class ArashinForemost extends CardImpl { static { filter.add(new SubtypePredicate(SubType.WARRIOR)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ArashinForemost(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java b/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java index a59ec01c4d..d6f18e479c 100644 --- a/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java +++ b/Mage.Sets/src/mage/cards/a/ArashinWarBeast.java @@ -51,7 +51,7 @@ class ArashinWarBeastTriggeredAbility extends TriggeredAbilityImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("one or more blockers"); static { - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } boolean usedForCombatDamageStep; diff --git a/Mage.Sets/src/mage/cards/a/ArborealGrazer.java b/Mage.Sets/src/mage/cards/a/ArborealGrazer.java new file mode 100644 index 0000000000..445bf3daac --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArborealGrazer.java @@ -0,0 +1,45 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArborealGrazer extends CardImpl { + + public ArborealGrazer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Arboreal Grazer enters the battlefield, you may put a land card from your hand onto the battlefield tapped. + this.addAbility(new EntersBattlefieldTriggeredAbility(new PutCardFromHandOntoBattlefieldEffect( + StaticFilters.FILTER_CARD_LAND_A, false, true + ), false)); + + } + + private ArborealGrazer(final ArborealGrazer card) { + super(card); + } + + @Override + public ArborealGrazer copy() { + return new ArborealGrazer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/Arboria.java b/Mage.Sets/src/mage/cards/a/Arboria.java index 0cb05c3628..e45fa65784 100644 --- a/Mage.Sets/src/mage/cards/a/Arboria.java +++ b/Mage.Sets/src/mage/cards/a/Arboria.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -17,8 +15,9 @@ import mage.game.permanent.PermanentToken; import mage.watchers.common.CastSpellYourLastTurnWatcher; import mage.watchers.common.PermanentsEnteredBattlefieldYourLastTurnWatcher; +import java.util.UUID; + /** - * * @author spjspj */ public final class Arboria extends CardImpl { @@ -59,14 +58,18 @@ class ArboriaEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { - CastSpellYourLastTurnWatcher watcher = (CastSpellYourLastTurnWatcher) game.getState().getWatchers().get(CastSpellYourLastTurnWatcher.class.getSimpleName()); + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + + CastSpellYourLastTurnWatcher watcher = game.getState().getWatcher(CastSpellYourLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsCastOnPlayersTurn(defenderId) > 0) { return true; } PermanentsEnteredBattlefieldYourLastTurnWatcher watcher2 - = (PermanentsEnteredBattlefieldYourLastTurnWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldYourLastTurnWatcher.class.getSimpleName()); + = game.getState().getWatcher(PermanentsEnteredBattlefieldYourLastTurnWatcher.class); if (watcher2 != null && watcher2.getPermanentsEnteringOnPlayersLastTurn(game, defenderId) != null) { for (Permanent permanent : watcher2.getPermanentsEnteringOnPlayersLastTurn(game, defenderId)) { diff --git a/Mage.Sets/src/mage/cards/a/ArcadesSabboth.java b/Mage.Sets/src/mage/cards/a/ArcadesSabboth.java index 2cc2901e87..2737870cee 100644 --- a/Mage.Sets/src/mage/cards/a/ArcadesSabboth.java +++ b/Mage.Sets/src/mage/cards/a/ArcadesSabboth.java @@ -29,8 +29,8 @@ public final class ArcadesSabboth extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); - filter.add(Predicates.not(new AttackingPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); + filter.add(Predicates.not(AttackingPredicate.instance)); } public ArcadesSabboth(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java b/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java index 028bc5bfca..0dbc363239 100644 --- a/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java +++ b/Mage.Sets/src/mage/cards/a/ArcadesTheStrategist.java @@ -1,43 +1,36 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderAllEffect; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; import mage.abilities.keyword.DefenderAbility; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ArcadesTheStrategist extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature with defender"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(); static { filter.add(new AbilityPredicate(DefenderAbility.class)); + filter2.add(new AbilityPredicate(DefenderAbility.class)); } public ArcadesTheStrategist(UUID ownerId, CardSetInfo setInfo) { @@ -61,14 +54,14 @@ public final class ArcadesTheStrategist extends CardImpl { )); // Each creature you control with defender assigns combat damage equal to its toughness rather than its power and can attack as though it didn't have defender. - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ArcadesTheStrategistCombatDamageRuleEffect()); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new CombatDamageByToughnessEffect(filter2, true).setText("Each creature you control with defender assigns combat damage equal to its toughness rather than its power")); ability.addEffect(new CanAttackAsThoughItDidntHaveDefenderAllEffect( Duration.WhileOnBattlefield, filter ).setText("and can attack as though it didn't have defender")); this.addAbility(ability); } - public ArcadesTheStrategist(final ArcadesTheStrategist card) { + private ArcadesTheStrategist(final ArcadesTheStrategist card) { super(card); } @@ -77,41 +70,3 @@ public final class ArcadesTheStrategist extends CardImpl { return new ArcadesTheStrategist(this); } } - -class ArcadesTheStrategistCombatDamageRuleEffect extends ContinuousEffectImpl { - - public ArcadesTheStrategistCombatDamageRuleEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Each creature you control with defender assigns combat damage equal to its toughness rather than its power"; - } - - public ArcadesTheStrategistCombatDamageRuleEffect(final ArcadesTheStrategistCombatDamageRuleEffect effect) { - super(effect); - } - - @Override - public ArcadesTheStrategistCombatDamageRuleEffect copy() { - return new ArcadesTheStrategistCombatDamageRuleEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - // Change the rule - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(source.getControllerId())); - filter.add(new AbilityPredicate(DefenderAbility.class)); - game.getCombat().setUseToughnessForDamage(true); - game.getCombat().addUseToughnessForDamageFilter(filter); - return true; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.RulesEffects; - } -} diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index ee192097ff..56674534e0 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -1,9 +1,5 @@ - package mage.cards.a; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -20,8 +16,11 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ArcaneAdaptation extends CardImpl { @@ -70,14 +69,14 @@ class ConspyEffect extends ContinuousEffectImpl { // in graveyard for (UUID cardId : controller.getGraveyard()) { Card card = game.getCard(cardId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } // on Hand for (UUID cardId : controller.getHand()) { Card card = game.getCard(cardId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } @@ -97,13 +96,13 @@ class ConspyEffect extends ContinuousEffectImpl { for (UUID commanderId : controller.getCommandersIds()) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); - if (card.isCreature() && !card.hasSubtype(subType, game)) { + if (card != null && card.isCreature() && !card.hasSubtype(subType, game)) { game.getState().getCreateCardAttribute(card, game).getSubtype().add(subType); } } } // creature spells you control - for (Iterator iterator = game.getStack().iterator(); iterator.hasNext();) { + for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); if (stackObject instanceof Spell && stackObject.isControlledBy(source.getControllerId()) diff --git a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java index 52fe2bd0c7..99cceae788 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneArtisan.java @@ -1,4 +1,3 @@ - package mage.cards.a; import mage.MageInt; @@ -97,26 +96,29 @@ class ArcaneArtisanCreateTokenEffect extends OneShotEffect { return false; } Card card = game.getCard(target.getFirstTarget()); - player.moveCards(card, Zone.EXILED, source, game); - if (!card.isCreature()) { + if (!player.moveCards(card, Zone.EXILED, source, game)) { return false; } - CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(player.getId()); - effect.setTargetPointer(new FixedTarget(card.getId(), game)); - effect.apply(game, source); - Object object = game.getState().getValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game)); - Set tokensCreated; - if (object != null) { - tokensCreated = (Set) object; - } else { - tokensCreated = new HashSet<>(); - } - for (Permanent perm : effect.getAddedPermanent()) { - if (perm != null) { - tokensCreated.add(perm.getId()); + + if (card.isCreature()) { + CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(player.getId()); + effect.setTargetPointer(new FixedTarget(card.getId(), game)); + effect.apply(game, source); + Object object = game.getState().getValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game)); + Set tokensCreated; + if (object != null) { + tokensCreated = (Set) object; + } else { + tokensCreated = new HashSet<>(); } + for (Permanent perm : effect.getAddedPermanent()) { + if (perm != null) { + tokensCreated.add(perm.getId()); + } + } + game.getState().setValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game), tokensCreated); } - game.getState().setValue(CardUtil.getCardZoneString("_tokensCreated", source.getSourceId(), game), tokensCreated); + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ArcboundCrusher.java b/Mage.Sets/src/mage/cards/a/ArcboundCrusher.java index 5e62cf8f8c..f4d125a554 100644 --- a/Mage.Sets/src/mage/cards/a/ArcboundCrusher.java +++ b/Mage.Sets/src/mage/cards/a/ArcboundCrusher.java @@ -25,7 +25,7 @@ public final class ArcboundCrusher extends CardImpl { private static final FilterPermanent filter = new FilterArtifactPermanent("another artifact"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ArcboundCrusher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java b/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java index e82387ae22..3ebbf6f70e 100644 --- a/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java +++ b/Mage.Sets/src/mage/cards/a/ArchOfOrazca.java @@ -1,13 +1,12 @@ - package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; @@ -15,8 +14,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ArchOfOrazca extends CardImpl { @@ -36,6 +36,7 @@ public final class ArchOfOrazca extends CardImpl { new GenericManaCost(5), CitysBlessingCondition.instance); ability.addCost(new TapSourceCost()); + ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/ArcheryTraining.java b/Mage.Sets/src/mage/cards/a/ArcheryTraining.java new file mode 100644 index 0000000000..f70caaa22c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArcheryTraining.java @@ -0,0 +1,67 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetAttackingOrBlockingCreature; + +/** + * + * @author jeffwadsworth + */ +public final class ArcheryTraining extends CardImpl { + + private static final String rule = "This creature deals X damage to target attacking or blocking creature, where X is the number of arrow counters on {this}."; + + public ArcheryTraining(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of your upkeep, you may put an arrow counter on Archery Training. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.ARROW.createInstance(), true), TargetController.YOU, true)); + + // Enchanted creature has "{tap}: This creature deals X damage to target attacking or blocking creature, where X is the number of arrow counters on Archery Training." + Ability gainedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new CountersSourceCount(CounterType.ARROW)).setText(rule), new TapSourceCost()); + gainedAbility.addTarget(new TargetAttackingOrBlockingCreature()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA))); + + } + + public ArcheryTraining(final ArcheryTraining card) { + super(card); + } + + @Override + public ArcheryTraining copy() { + return new ArcheryTraining(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArchfiendOfDespair.java b/Mage.Sets/src/mage/cards/a/ArchfiendOfDespair.java index 4d5bc436e4..e7f41f723f 100644 --- a/Mage.Sets/src/mage/cards/a/ArchfiendOfDespair.java +++ b/Mage.Sets/src/mage/cards/a/ArchfiendOfDespair.java @@ -79,12 +79,12 @@ class ArchfiendOfDespairEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (controller != null && watcher != null) { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - int lifeLost = watcher.getLiveLost(playerId); + int lifeLost = watcher.getLifeLost(playerId); if (lifeLost > 0) { opponent.loseLife(lifeLost, game, false); } diff --git a/Mage.Sets/src/mage/cards/a/ArchiveTrap.java b/Mage.Sets/src/mage/cards/a/ArchiveTrap.java index d0c3c88c15..ead89d87a5 100644 --- a/Mage.Sets/src/mage/cards/a/ArchiveTrap.java +++ b/Mage.Sets/src/mage/cards/a/ArchiveTrap.java @@ -51,13 +51,13 @@ public final class ArchiveTrap extends CardImpl { class ArchiveTrapWatcher extends Watcher { - Set playerIds = new HashSet<>(); + private Set playerIds = new HashSet<>(); public ArchiveTrapWatcher() { - super(ArchiveTrapWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public ArchiveTrapWatcher(final ArchiveTrapWatcher watcher) { + private ArchiveTrapWatcher(final ArchiveTrapWatcher watcher) { super(watcher); this.playerIds.addAll(watcher.playerIds); } @@ -92,7 +92,7 @@ enum OpponentSearchesLibCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - ArchiveTrapWatcher watcher = (ArchiveTrapWatcher) game.getState().getWatchers().get(ArchiveTrapWatcher.class.getSimpleName()); + ArchiveTrapWatcher watcher = game.getState().getWatcher(ArchiveTrapWatcher.class); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && watcher != null) { for (UUID playerId : watcher.getPlayersSearchedLibrary()) { diff --git a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java index 71f9e08a5d..e71f21b2b6 100644 --- a/Mage.Sets/src/mage/cards/a/ArchmageAscension.java +++ b/Mage.Sets/src/mage/cards/a/ArchmageAscension.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -22,8 +21,9 @@ import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.watchers.common.CardsAmountDrawnThisTurnWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ArchmageAscension extends CardImpl { @@ -74,7 +74,7 @@ class ArchmageAscensionTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent archmage = game.getPermanent(super.getSourceId()); CardsAmountDrawnThisTurnWatcher watcher - = (CardsAmountDrawnThisTurnWatcher) game.getState().getWatchers().get(CardsAmountDrawnThisTurnWatcher.class.getSimpleName()); + = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); return archmage != null && watcher != null && watcher.getAmountCardsDrawn(this.getControllerId()) >= 2; } @@ -111,7 +111,7 @@ class ArchmageAscensionReplacementEffect extends ReplacementEffectImpl { Player player = game.getPlayer(event.getPlayerId()); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java b/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java index ffc743472c..fd4d1baa2a 100644 --- a/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java +++ b/Mage.Sets/src/mage/cards/a/ArchonOfValorsReach.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -9,26 +8,23 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.constants.SubType; import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceImpl; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ArchonOfValorsReach extends CardImpl { @@ -56,7 +52,7 @@ public final class ArchonOfValorsReach extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ArchonOfValorsReachReplacementEffect())); } - public ArchonOfValorsReach(final ArchonOfValorsReach card) { + private ArchonOfValorsReach(final ArchonOfValorsReach card) { super(card); } @@ -68,14 +64,12 @@ public final class ArchonOfValorsReach extends CardImpl { class ArchonOfValorsReachChooseEffect extends OneShotEffect { - public static String VALUE_KEY = "_cardtype"; - - public ArchonOfValorsReachChooseEffect() { + ArchonOfValorsReachChooseEffect() { super(Outcome.Benefit); this.staticText = "choose artifact, enchantment, instant, sorcery, or planeswalker"; } - public ArchonOfValorsReachChooseEffect(final ArchonOfValorsReachChooseEffect effect) { + private ArchonOfValorsReachChooseEffect(final ArchonOfValorsReachChooseEffect effect) { super(effect); } @@ -96,7 +90,7 @@ class ArchonOfValorsReachChooseEffect extends OneShotEffect { if (controller.choose(Outcome.Neutral, choices, game)) { game.informPlayers(mageObject.getName() + ": Chosen card type is " + choices.getChoice()); System.out.println(mageObject.getId()); - game.getState().setValue(mageObject.getId().toString() + VALUE_KEY, choices.getChoice()); + game.getState().setValue(mageObject.getId().toString() + "_cardtype", choices.getChoice()); if (mageObject instanceof Permanent) { ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen card type: " + choices.getChoice()), game); } @@ -109,7 +103,7 @@ class ArchonOfValorsReachChooseEffect extends OneShotEffect { class ArchonOfValorsReachChoice extends ChoiceImpl { - public ArchonOfValorsReachChoice() { + ArchonOfValorsReachChoice() { super(true); this.choices.add("Artifact"); this.choices.add("Enchantment"); @@ -119,7 +113,7 @@ class ArchonOfValorsReachChoice extends ChoiceImpl { this.message = "Choose artifact, enchantment, instant, sorcery, or planeswalker"; } - public ArchonOfValorsReachChoice(final ArchonOfValorsReachChoice choice) { + private ArchonOfValorsReachChoice(final ArchonOfValorsReachChoice choice) { super(choice); } @@ -154,7 +148,7 @@ class ArchonOfValorsReachReplacementEffect extends ContinuousRuleModifyingEffect staticText = "Players can't cast spells of the chosen type"; } - ArchonOfValorsReachReplacementEffect(final ArchonOfValorsReachReplacementEffect effect) { + private ArchonOfValorsReachReplacementEffect(final ArchonOfValorsReachReplacementEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/a/ArchwayAngel.java b/Mage.Sets/src/mage/cards/a/ArchwayAngel.java new file mode 100644 index 0000000000..ebab4bd07d --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArchwayAngel.java @@ -0,0 +1,55 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.GateYouControlHint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ArchwayAngel extends CardImpl { + + + private static final FilterPermanent filter = new FilterControlledPermanent("Gate you control"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public ArchwayAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Archway Angel enters the battlefield, you gain 2 life for each Gate you control. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(new PermanentsOnBattlefieldCount(filter, 2))); + ability.addHint(GateYouControlHint.instance); + this.addAbility(ability); + } + + public ArchwayAngel(final ArchwayAngel card) { + super(card); + } + + @Override + public ArchwayAngel copy() { + return new ArchwayAngel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java index 89fe19f8ee..5cb55edbc2 100644 --- a/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java +++ b/Mage.Sets/src/mage/cards/a/ArclightPhoenix.java @@ -72,8 +72,8 @@ enum ArclightPhoenixCondition implements Condition { @Override public boolean apply(Game game, Ability source) { ArclightPhoenixWatcher watcher - = (ArclightPhoenixWatcher) game.getState().getWatchers().get( - ArclightPhoenixWatcher.class.getSimpleName() + = game.getState().getWatcher( + ArclightPhoenixWatcher.class ); return watcher != null && watcher.getInstantSorceryCount(source.getControllerId()) > 2; } @@ -81,10 +81,10 @@ enum ArclightPhoenixCondition implements Condition { class ArclightPhoenixWatcher extends Watcher { - private final Map instantSorceryCount = new HashMap(); + private final Map instantSorceryCount = new HashMap<>(); public ArclightPhoenixWatcher() { - super(ArclightPhoenixWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ArclightPhoenixWatcher(final ArclightPhoenixWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/a/ArcumDagsson.java b/Mage.Sets/src/mage/cards/a/ArcumDagsson.java index d07d474fe3..c86c8389d4 100644 --- a/Mage.Sets/src/mage/cards/a/ArcumDagsson.java +++ b/Mage.Sets/src/mage/cards/a/ArcumDagsson.java @@ -90,7 +90,7 @@ class ArcumDagssonEffect extends OneShotEffect { artifactCreature.sacrifice(source.getSourceId(), game); if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a noncreature artifact card?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { player.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/a/ArenaOfTheAncients.java b/Mage.Sets/src/mage/cards/a/ArenaOfTheAncients.java index 466dcdc9e2..60f5990d5a 100644 --- a/Mage.Sets/src/mage/cards/a/ArenaOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/a/ArenaOfTheAncients.java @@ -23,7 +23,7 @@ import mage.filter.predicate.mageobject.SupertypePredicate; */ public final class ArenaOfTheAncients extends CardImpl { - private final static FilterCreaturePermanent legendaryFilter = new FilterCreaturePermanent("legendary creatures"); + private static final FilterCreaturePermanent legendaryFilter = new FilterCreaturePermanent("legendary creatures"); static { legendaryFilter.add(new SupertypePredicate(SuperType.LEGENDARY)); } diff --git a/Mage.Sets/src/mage/cards/a/ArgothianEnchantress.java b/Mage.Sets/src/mage/cards/a/ArgothianEnchantress.java index 27cd7898b1..f6e8dd769a 100644 --- a/Mage.Sets/src/mage/cards/a/ArgothianEnchantress.java +++ b/Mage.Sets/src/mage/cards/a/ArgothianEnchantress.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,8 +11,9 @@ import mage.constants.SubType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.CardTypePredicate; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class ArgothianEnchantress extends CardImpl { @@ -26,16 +25,18 @@ public final class ArgothianEnchantress extends CardImpl { } public ArgothianEnchantress(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.DRUID); this.power = new MageInt(0); this.toughness = new MageInt(1); + // Shroud this.addAbility(ShroudAbility.getInstance()); + // Whenever you cast an Enchantment spell, you draw a card. - this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1), filter, false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), filter, false)); } public ArgothianEnchantress(final ArgothianEnchantress card) { diff --git a/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java index 3c6578b392..615f5d7e24 100644 --- a/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java +++ b/Mage.Sets/src/mage/cards/a/ArixmethesSlumberingIsle.java @@ -28,7 +28,6 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.counters.CounterType; -import mage.filter.FilterSpell; import mage.game.Game; import mage.game.permanent.Permanent; @@ -38,8 +37,6 @@ import mage.game.permanent.Permanent; */ public final class ArixmethesSlumberingIsle extends CardImpl { - private static final FilterSpell filter = new FilterSpell("a spell"); - public ArixmethesSlumberingIsle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); diff --git a/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java b/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java new file mode 100644 index 0000000000..705531fe94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArlinnVoiceOfThePack.java @@ -0,0 +1,89 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.WolfToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArlinnVoiceOfThePack extends CardImpl { + + public ArlinnVoiceOfThePack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ARLINN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + + // Each creature you control that's a Wolf or Werewolf enters the battlefield with an additional +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility(new ArlinnVoiceOfThePackReplacementEffect())); + + // -2: Create a 2/2 green Wolf creature token. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new WolfToken("WAR")), -2)); + } + + private ArlinnVoiceOfThePack(final ArlinnVoiceOfThePack card) { + super(card); + } + + @Override + public ArlinnVoiceOfThePack copy() { + return new ArlinnVoiceOfThePack(this); + } +} + +class ArlinnVoiceOfThePackReplacementEffect extends ReplacementEffectImpl { + + ArlinnVoiceOfThePackReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Each creature you control that's a Wolf or Werewolf " + + "enters the battlefield with an additional +1/+1 counter on it"; + } + + private ArlinnVoiceOfThePackReplacementEffect(final ArlinnVoiceOfThePackReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + return creature != null && creature.isControlledBy(source.getControllerId()) + && creature.isCreature() + && (creature.hasSubtype(SubType.WOLF, game) + || creature.hasSubtype(SubType.WEREWOLF, game)); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } + return false; + } + + @Override + public ArlinnVoiceOfThePackReplacementEffect copy() { + return new ArlinnVoiceOfThePackReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArlinnsWolf.java b/Mage.Sets/src/mage/cards/a/ArlinnsWolf.java new file mode 100644 index 0000000000..78fe947c22 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArlinnsWolf.java @@ -0,0 +1,50 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArlinnsWolf extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public ArlinnsWolf(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.WOLF); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Arlinn's Wolf can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect( + filter, Duration.WhileOnBattlefield + ))); + } + + private ArlinnsWolf(final ArlinnsWolf card) { + super(card); + } + + @Override + public ArlinnsWolf copy() { + return new ArlinnsWolf(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java b/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java index 1e442d5298..f4fe5b25bb 100644 --- a/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java +++ b/Mage.Sets/src/mage/cards/a/ArmoryAutomaton.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; @@ -11,16 +9,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.AttachedToPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author spjspj */ public final class ArmoryAutomaton extends CardImpl { @@ -73,9 +77,17 @@ class ArmoryAutomatonEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (player != null && sourcePermanent != null) { - int countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game).size() - sourcePermanent.getAttachments().size(); - while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Attach a target Equipment?", source, game)) { - Target targetEquipment = new TargetPermanent(filter); + + // dynamic filter (can't selects own attaches and can't selects twice) + FilterPermanent currentFilter = filter.copy(); + FilterPermanent filterSourceId = new FilterPermanent(); + filterSourceId.add(new CardIdPredicate(this.getId())); + currentFilter.add(Predicates.not(new AttachedToPredicate(filterSourceId))); + + int countBattlefield = game.getBattlefield().getAllActivePermanents(currentFilter, game).size(); + while (player.canRespond() && countBattlefield > 0 && player.chooseUse(Outcome.Benefit, "Select and attach a target Equipment?", source, game)) { + Target targetEquipment = new TargetPermanent(currentFilter); + targetEquipment.setRequired(false); if (player.choose(Outcome.Benefit, targetEquipment, source.getSourceId(), game)) { Permanent aura = game.getPermanent(targetEquipment.getFirstTarget()); if (aura != null) { @@ -84,9 +96,12 @@ class ArmoryAutomatonEffect extends OneShotEffect { attachedTo.removeAttachment(aura.getId(), game); } sourcePermanent.addAttachment(aura.getId(), game); + + // exclude selected + currentFilter.add(Predicates.not(new PermanentIdPredicate(aura.getId()))); } } - countBattlefield = game.getBattlefield().getAllActivePermanents(filter, game).size() - sourcePermanent.getAttachments().size(); + countBattlefield = game.getBattlefield().getAllActivePermanents(currentFilter, game).size(); } return true; } diff --git a/Mage.Sets/src/mage/cards/a/ArrestersAdmonition.java b/Mage.Sets/src/mage/cards/a/ArrestersAdmonition.java new file mode 100644 index 0000000000..27656402f5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArrestersAdmonition.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ArrestersAdmonition extends CardImpl { + + public ArrestersAdmonition(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Return target creature to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Addendum — If you cast this spell during your main phase, draw a card. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(1), AddendumCondition.instance, + "
    Addendum — If you cast this spell during your main phase, draw a card." + )); + } + + private ArrestersAdmonition(final ArrestersAdmonition card) { + super(card); + } + + @Override + public ArrestersAdmonition copy() { + return new ArrestersAdmonition(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArrestersZeal.java b/Mage.Sets/src/mage/cards/a/ArrestersZeal.java new file mode 100644 index 0000000000..9d488e442a --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/ArrestersZeal.java @@ -0,0 +1,70 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ArrestersZeal extends CardImpl { + + public ArrestersZeal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + + // Target creature gets +2/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Addendum — If you cast this spell during your main phase, that creature gains flying until end of turn. + this.getSpellAbility().addEffect(new ArrestersZealEffect()); + } + + public ArrestersZeal(final ArrestersZeal card) { + super(card); + } + + @Override + public ArrestersZeal copy() { + return new ArrestersZeal(this); + } +} + +class ArrestersZealEffect extends OneShotEffect { + + ArrestersZealEffect() { + super(Outcome.Benefit); + staticText = "
    Addendum — If you cast this spell during your main phase, that creature gains flying until end of turn."; + } + + private ArrestersZealEffect(final ArrestersZealEffect effect) { + super(effect); + } + + @Override + public ArrestersZealEffect copy() { + return new ArrestersZealEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!AddendumCondition.instance.apply(game, source)) { + return false; + } + game.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java b/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java index 076db17cd7..16fcdf16f2 100644 --- a/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java +++ b/Mage.Sets/src/mage/cards/a/ArtfulTakedown.java @@ -1,6 +1,5 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -11,8 +10,9 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ArtfulTakedown extends CardImpl { @@ -33,14 +33,14 @@ public final class ArtfulTakedown extends CardImpl { this.getSpellAbility().addEffect( new TapTargetEffect().setText("target creature") ); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1).withChooseHint("tap")); // • Target creature gets -2/-4 until end of turn. Mode mode = new Mode( new BoostTargetEffect(-2, -4, Duration.EndOfTurn) .setText("target creature gets -2/-4 until end of turn") ); - mode.addTarget(new TargetCreaturePermanent(filter2)); + mode.addTarget(new TargetCreaturePermanent(filter2).withChooseHint("gets -2/-4 until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/ArtifactMutation.java b/Mage.Sets/src/mage/cards/a/ArtifactMutation.java index 2aaa2ef027..43c0240f8e 100644 --- a/Mage.Sets/src/mage/cards/a/ArtifactMutation.java +++ b/Mage.Sets/src/mage/cards/a/ArtifactMutation.java @@ -25,7 +25,7 @@ public final class ArtifactMutation extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // create X 1/1 green Saproling creature tokens, where X is that artifact's converted mana cost. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new TargetConvertedManaCost())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), TargetConvertedManaCost.instance)); } public ArtifactMutation(final ArtifactMutation card) { diff --git a/Mage.Sets/src/mage/cards/a/ArtificersAssistant.java b/Mage.Sets/src/mage/cards/a/ArtificersAssistant.java index d8c5d76f4f..2a610e18b0 100644 --- a/Mage.Sets/src/mage/cards/a/ArtificersAssistant.java +++ b/Mage.Sets/src/mage/cards/a/ArtificersAssistant.java @@ -22,7 +22,7 @@ public final class ArtificersAssistant extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public ArtificersAssistant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java b/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java index 86ad83f7f4..b260e58011 100644 --- a/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java +++ b/Mage.Sets/src/mage/cards/a/AryelKnightOfWindgrace.java @@ -80,7 +80,7 @@ class AryelTapXTargetCost extends VariableCostImpl { static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Knights you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.KNIGHT)); } diff --git a/Mage.Sets/src/mage/cards/a/AsForetold.java b/Mage.Sets/src/mage/cards/a/AsForetold.java index fe2e8f8f0c..e5cf038407 100644 --- a/Mage.Sets/src/mage/cards/a/AsForetold.java +++ b/Mage.Sets/src/mage/cards/a/AsForetold.java @@ -1,4 +1,3 @@ - package mage.cards.a; import java.util.UUID; @@ -17,33 +16,34 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.counters.CounterType; import mage.game.Game; -import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.watchers.Watcher; /** * * @author stravant * - * Note, this card is pretty hacky in its implementation due to the fact that the alternative cost system doesn't - * really support "once each turn" alternative costs in an obvious way, but it should work in all scenarios as far - * as I can see. */ public final class AsForetold extends CardImpl { + public AsForetold(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); - // At the beginning of your upkeep, put a time counter on As Foretold. addAbility( new BeginningOfUpkeepTriggeredAbility( - new AddCountersSourceEffect(CounterType.TIME.createInstance(), new StaticValue(1), true), + new AddCountersSourceEffect( + CounterType.TIME.createInstance(), + new StaticValue(1), + true), TargetController.YOU, - /* optional = */false)); + false)); // Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast with converted mana cost X or less, where X is the number of time counters on As Foretold. - addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AsForetoldAddAltCostEffect()), new AsForetoldAltCostUsedWatcher()); + addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new AsForetoldAddAltCostEffect())); + } public AsForetold(final AsForetold card) { @@ -60,6 +60,7 @@ public final class AsForetold extends CardImpl { * Used to determine what cast objects to apply the alternative cost to */ class SpellWithManaCostLessThanOrEqualToCondition implements Condition { + private int counters; public SpellWithManaCostLessThanOrEqualToCondition(int counters) { @@ -69,26 +70,31 @@ class SpellWithManaCostLessThanOrEqualToCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); - return object != null && !object.isLand() && object.getConvertedManaCost() <= counters; + return object != null + && !object.isLand() + && object.getConvertedManaCost() <= counters; } } - /** - * Special AlternativeCostSourceAbility implementation. We wrap the call to askToActivateAlternativeCosts in order to - * tell when the alternative cost is used, and mark it as having been used this turn in the watcher + * Special AlternativeCostSourceAbility implementation. We wrap the call to + * askToActivateAlternativeCosts in order to tell when the alternative cost is + * used, and mark it as having been used this turn in the watcher */ class AsForetoldAlternativeCost extends AlternativeCostSourceAbility { + private UUID sourceAsForetold; + private boolean wasActivated; AsForetoldAlternativeCost(UUID sourceAsForetold, int timeCounters) { super(new ManaCostsImpl("{0}"), new SpellWithManaCostLessThanOrEqualToCondition(timeCounters)); this.sourceAsForetold = sourceAsForetold; } - AsForetoldAlternativeCost(final AsForetoldAlternativeCost ability) { + private AsForetoldAlternativeCost(final AsForetoldAlternativeCost ability) { super(ability); this.sourceAsForetold = ability.sourceAsForetold; + this.wasActivated = ability.wasActivated; } @Override @@ -98,24 +104,31 @@ class AsForetoldAlternativeCost extends AlternativeCostSourceAbility { @Override public boolean askToActivateAlternativeCosts(Ability ability, Game game) { - boolean activated = super.askToActivateAlternativeCosts(ability, game); - if (activated) { - // Get the watcher - AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher = - (AsForetoldAltCostUsedWatcher)game.getState().getWatchers() - .get("asForetoldAltCostUsedWatcher", sourceAsForetold); - - // Mark as used - asForetoldAltCostUsedWatcher.markUsedThisTurn(); + Player controller = game.getPlayer(ability.getControllerId()); + Permanent asForetold = game.getPermanent(sourceAsForetold); + if (controller != null + && asForetold != null) { + if (controller.chooseUse(Outcome.Neutral, "Do you wish to use " + + asForetold.getLogName() + " to pay the alternative cost ?", ability, game)) { + wasActivated = super.askToActivateAlternativeCosts(ability, game); + if (wasActivated) { + game.getState().setValue(asForetold.getId().toString() + + asForetold.getZoneChangeCounter(game) + + asForetold.getTurnsOnBattlefield(), true); + } + } } - return activated; + return wasActivated; } + } /** - * The continuous effect that adds the option to pay the alternative cost if we haven't used it yet this turn + * The continuous effect that adds the option to pay the alternative cost if we + * haven't used it yet this turn */ class AsForetoldAddAltCostEffect extends ContinuousEffectImpl { + public AsForetoldAddAltCostEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); staticText = "Once each turn, you may pay {0} rather than pay the mana cost for a spell you cast with converted mana cost X or less, where X is the number of time counters on {this}."; @@ -136,17 +149,16 @@ class AsForetoldAddAltCostEffect extends ContinuousEffectImpl { if (controller != null) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null) { - // Get the watcher - AsForetoldAltCostUsedWatcher asForetoldAltCostUsedWatcher = - (AsForetoldAltCostUsedWatcher)game.getState().getWatchers() - .get("asForetoldAltCostUsedWatcher", sourcePermanent.getId()); - + Boolean wasItUsed = (Boolean) game.getState().getValue( + sourcePermanent.getId().toString() + + sourcePermanent.getZoneChangeCounter(game) + + sourcePermanent.getTurnsOnBattlefield()); // If we haven't used it yet this turn, give the option of using the zero alternative cost - if (!asForetoldAltCostUsedWatcher.hasBeenUsedThisTurn()) { + if (wasItUsed == null) { int timeCounters = sourcePermanent.getCounters(game).getCount("time"); - controller.getAlternativeSourceCosts().add(new AsForetoldAlternativeCost(sourcePermanent.getId(), timeCounters)); + controller.getAlternativeSourceCosts().add( + new AsForetoldAlternativeCost(sourcePermanent.getId(), timeCounters)); } - // Return true even if we didn't add the alt cost. We still applied the effect return true; } @@ -164,38 +176,3 @@ class AsForetoldAddAltCostEffect extends ContinuousEffectImpl { return layer == Layer.RulesEffects; } } - -/** - * Watcher used as extra storage to record whether a given As Foretold has been used this turn. - * Technically speaking this watcher doesn't *watch* any GameEvents, but it does "watch" the - * alternative cost being used. That just isn't possible to watch through a game event. It's still - * helpfull to co-op the Watcher system for this since it automatically handles ZoneChangeCounter - * stuff and resetting the condition at the end of the turn. - */ -class AsForetoldAltCostUsedWatcher extends Watcher { - public AsForetoldAltCostUsedWatcher() { - super("asForetoldAltCostUsedWatcher", WatcherScope.CARD); - } - - public AsForetoldAltCostUsedWatcher(final AsForetoldAltCostUsedWatcher watcher) { - super(watcher); - } - - @Override - public void watch(GameEvent event, Game game) { - // Nothing to do, we explicitly mark used in the alternative cost - } - - public boolean hasBeenUsedThisTurn() { - return conditionMet(); - } - - public void markUsedThisTurn() { - condition = true; - } - - @Override - public AsForetoldAltCostUsedWatcher copy() { - return new AsForetoldAltCostUsedWatcher(this); - } -} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AshenSkinZubera.java b/Mage.Sets/src/mage/cards/a/AshenSkinZubera.java index 55f6c44791..050b2493a3 100644 --- a/Mage.Sets/src/mage/cards/a/AshenSkinZubera.java +++ b/Mage.Sets/src/mage/cards/a/AshenSkinZubera.java @@ -27,7 +27,7 @@ public final class AshenSkinZubera extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - Ability ability = new DiesTriggeredAbility(new DiscardTargetEffect(new ZuberasDiedDynamicValue())); + Ability ability = new DiesTriggeredAbility(new DiscardTargetEffect(ZuberasDiedDynamicValue.instance)); ability.addTarget(new TargetOpponent()); this.addAbility(ability, new ZuberasDiedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/a/AshenmoorCohort.java b/Mage.Sets/src/mage/cards/a/AshenmoorCohort.java index 8609bb3fa8..c791c25680 100644 --- a/Mage.Sets/src/mage/cards/a/AshenmoorCohort.java +++ b/Mage.Sets/src/mage/cards/a/AshenmoorCohort.java @@ -29,7 +29,7 @@ public final class AshenmoorCohort extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.BLACK)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Ashenmoor Cohort gets +1/+1 as long as you control another black creature"; diff --git a/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java b/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java new file mode 100644 index 0000000000..9b383b89f5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AshiokDreamRender.java @@ -0,0 +1,99 @@ +package mage.cards.a; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.target.TargetPlayer; + +/** + * @author TheElk801 + */ +public final class AshiokDreamRender extends CardImpl { + + public AshiokDreamRender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U/B}{U/B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ASHIOK); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Spells and abilities your opponents control can't cause their controller to search their library. + this.addAbility(new SimpleStaticAbility(new AshiokDreamRenderEffect())); + + // -1: Target player puts the top four cards of their library into their graveyard. Then exile each opponent's graveyard. + Ability ability = new LoyaltyAbility(new PutLibraryIntoGraveTargetEffect(4), -1); + ability.addTarget(new TargetPlayer()); + ability.addEffect(new ExileGraveyardAllPlayersEffect(StaticFilters.FILTER_CARD, TargetController.OPPONENT).setText("Then exile each opponent's graveyard.")); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private AshiokDreamRender(final AshiokDreamRender card) { + super(card); + } + + @Override + public AshiokDreamRender copy() { + return new AshiokDreamRender(this); + } +} + +class AshiokDreamRenderEffect extends ContinuousRuleModifyingEffectImpl { + + AshiokDreamRenderEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, true, false); + staticText = "Spells and abilities your opponents control can't cause their controller to search their library."; + } + + private AshiokDreamRenderEffect(final AshiokDreamRenderEffect effect) { + super(effect); + } + + @Override + public AshiokDreamRenderEffect copy() { + return new AshiokDreamRenderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't search libraries (" + mageObject.getLogName() + " in play)."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return GameEvent.EventType.SEARCH_LIBRARY == event.getType(); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + return controller != null + && event.getPlayerId().equals(game.getControllerId(event.getSourceId())) + && event.getTargetId().equals(game.getControllerId(event.getSourceId())) + && controller.hasOpponent(game.getControllerId(event.getSourceId()), game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java b/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java index 810e91e0aa..bc67e69a24 100644 --- a/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java +++ b/Mage.Sets/src/mage/cards/a/AshiokNightmareWeaver.java @@ -222,8 +222,7 @@ class AshiokNightmareWeaverExileAllEffect extends OneShotEffect { for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); if (opponent != null) { - Cards cards = new CardsImpl(); - cards.addAll(opponent.getHand()); + Cards cards = new CardsImpl(opponent.getHand()); for (UUID cardId : cards) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/a/AshioksSkulker.java b/Mage.Sets/src/mage/cards/a/AshioksSkulker.java new file mode 100644 index 0000000000..e67a4f5e3e --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AshioksSkulker.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +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 AshioksSkulker extends CardImpl { + + public AshioksSkulker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.NIGHTMARE); + this.power = new MageInt(3); + this.toughness = new MageInt(5); + + // {3}{U}: Ashiok's Skulker can't be blocked this turn. + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), new ManaCostsImpl("{3}{U}") + )); + } + + private AshioksSkulker(final AshioksSkulker card) { + super(card); + } + + @Override + public AshioksSkulker copy() { + return new AshioksSkulker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AsmiraHolyAvenger.java b/Mage.Sets/src/mage/cards/a/AsmiraHolyAvenger.java index 60cb57bd4f..ee45b419a1 100644 --- a/Mage.Sets/src/mage/cards/a/AsmiraHolyAvenger.java +++ b/Mage.Sets/src/mage/cards/a/AsmiraHolyAvenger.java @@ -56,7 +56,7 @@ class AsmiraHolyAvengerWatcher extends Watcher { private int creaturesCount = 0; public AsmiraHolyAvengerWatcher() { - super(AsmiraHolyAvengerWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); condition = true; } @@ -95,7 +95,7 @@ class AsmiraHolyAvengerDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - AsmiraHolyAvengerWatcher watcher = (AsmiraHolyAvengerWatcher) game.getState().getWatchers().get(AsmiraHolyAvengerWatcher.class.getSimpleName(), sourceAbility.getControllerId()); + AsmiraHolyAvengerWatcher watcher = game.getState().getWatcher(AsmiraHolyAvengerWatcher.class, sourceAbility.getControllerId()); if (watcher != null) { return watcher.getCreaturesCount(); } diff --git a/Mage.Sets/src/mage/cards/a/Asphyxiate.java b/Mage.Sets/src/mage/cards/a/Asphyxiate.java index 030206e579..d5275dc296 100644 --- a/Mage.Sets/src/mage/cards/a/Asphyxiate.java +++ b/Mage.Sets/src/mage/cards/a/Asphyxiate.java @@ -20,7 +20,7 @@ public final class Asphyxiate extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creature"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Asphyxiate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Assassinate.java b/Mage.Sets/src/mage/cards/a/Assassinate.java index 891a186397..47355573df 100644 --- a/Mage.Sets/src/mage/cards/a/Assassinate.java +++ b/Mage.Sets/src/mage/cards/a/Assassinate.java @@ -20,7 +20,7 @@ public final class Assassinate extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public Assassinate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AssassinsBlade.java b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java index fe2b98e641..6f530833e2 100644 --- a/Mage.Sets/src/mage/cards/a/AssassinsBlade.java +++ b/Mage.Sets/src/mage/cards/a/AssassinsBlade.java @@ -29,7 +29,7 @@ public final class AssassinsBlade extends CardImpl { static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public AssassinsBlade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AssassinsTrophy.java b/Mage.Sets/src/mage/cards/a/AssassinsTrophy.java index 0d3015285a..a973855cc4 100644 --- a/Mage.Sets/src/mage/cards/a/AssassinsTrophy.java +++ b/Mage.Sets/src/mage/cards/a/AssassinsTrophy.java @@ -1,6 +1,7 @@ package mage.cards.a; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -21,7 +22,6 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; /** - * * @author TheElk801 */ public final class AssassinsTrophy extends CardImpl { @@ -74,17 +74,19 @@ class AssassinsTrophyEffect extends OneShotEffect { Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (permanent != null) { Player controller = game.getPlayer(permanent.getControllerId()); - if (controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { - TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.BATTLEFIELD, source, game); + if (controller != null) { + if (controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); + if (controller.searchLibrary(target, source, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } } + controller.shuffleLibrary(source, game); } - controller.shuffleLibrary(source, game); + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/a/AssaultFormation.java b/Mage.Sets/src/mage/cards/a/AssaultFormation.java index 8895519cf3..645fec98a5 100644 --- a/Mage.Sets/src/mage/cards/a/AssaultFormation.java +++ b/Mage.Sets/src/mage/cards/a/AssaultFormation.java @@ -1,26 +1,27 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderTargetEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class AssaultFormation extends CardImpl { @@ -32,10 +33,10 @@ public final class AssaultFormation extends CardImpl { } public AssaultFormation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Each creature you control assigns combat damage equal to its toughness rather than its power. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AssaultFormationCombatDamageRuleEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CombatDamageByToughnessEffect(StaticFilters.FILTER_PERMANENT_CREATURE, true))); // {G}: Target creature with defender can attack this turn as though it didn't have defender. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanAttackAsThoughItDidntHaveDefenderTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{G}")); @@ -43,11 +44,11 @@ public final class AssaultFormation extends CardImpl { this.addAbility(ability); // {2}{G}: Creatures you control get +0/+1 until end of turn. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0,1,Duration.EndOfTurn), new ManaCostsImpl("{2}{G}"))); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl("{2}{G}"))); } - public AssaultFormation(final AssaultFormation card) { + private AssaultFormation(final AssaultFormation card) { super(card); } @@ -56,40 +57,3 @@ public final class AssaultFormation extends CardImpl { return new AssaultFormation(this); } } - -class AssaultFormationCombatDamageRuleEffect extends ContinuousEffectImpl { - - public AssaultFormationCombatDamageRuleEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Each creature you control assigns combat damage equal to its toughness rather than its power"; - } - - public AssaultFormationCombatDamageRuleEffect(final AssaultFormationCombatDamageRuleEffect effect) { - super(effect); - } - - @Override - public AssaultFormationCombatDamageRuleEffect copy() { - return new AssaultFormationCombatDamageRuleEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - // Change the rule - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(source.getControllerId())); - game.getCombat().setUseToughnessForDamage(true); - game.getCombat().addUseToughnessForDamageFilter(filter); - return true; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.RulesEffects; - } -} diff --git a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java index bf7ea122ec..d31eb4c570 100644 --- a/Mage.Sets/src/mage/cards/a/AsylumVisitor.java +++ b/Mage.Sets/src/mage/cards/a/AsylumVisitor.java @@ -1,7 +1,5 @@ - package mage.cards.a; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -19,8 +17,9 @@ import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class AsylumVisitor extends CardImpl { @@ -33,11 +32,11 @@ public final class AsylumVisitor extends CardImpl { this.toughness = new MageInt(1); // At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life. - Ability ability = new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.ANY, false), + Ability ability = new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), TargetController.ANY, false), new CardsInHandCondition(ComparisonType.EQUAL_TO, 0, null, TargetController.ACTIVE), "At the beginning of each player's upkeep, if that player has no cards in hand, you draw a card and you lose 1 life."); Effect effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java b/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java index 433d9bc8e7..38c00a82ce 100644 --- a/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java +++ b/Mage.Sets/src/mage/cards/a/AtalyaSamiteMaster.java @@ -41,7 +41,7 @@ public final class AtalyaSamiteMaster extends CardImpl { this.toughness = new MageInt(3); // {X}, {tap}: Choose one - Prevent the next X damage that would be dealt to target creature this turn; or you gain X life. Spend only white mana on X. - PreventDamageToTargetEffect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, new ManacostVariableValue()); + PreventDamageToTargetEffect effect = new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.instance); effect.setText("Prevent the next X damage that would be dealt to target creature this turn. Spend only white mana on X."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); @@ -55,7 +55,7 @@ public final class AtalyaSamiteMaster extends CardImpl { // or you gain X life Mode mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(new ManacostVariableValue()).setText("You gain X life. Spend only white mana on X.")); + mode.addEffect(new GainLifeEffect(ManacostVariableValue.instance).setText("You gain X life. Spend only white mana on X.")); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/a/AtarkasCommand.java b/Mage.Sets/src/mage/cards/a/AtarkasCommand.java index 8bd0376032..cb3175d052 100644 --- a/Mage.Sets/src/mage/cards/a/AtarkasCommand.java +++ b/Mage.Sets/src/mage/cards/a/AtarkasCommand.java @@ -35,22 +35,22 @@ public final class AtarkasCommand extends CardImpl { // or Atarka's Command deals 3 damage to each opponent; Mode mode = new Mode(); - mode.getEffects().add(new DamagePlayersEffect(3, TargetController.OPPONENT)); + mode.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT)); this.getSpellAbility().addMode(mode); // or You may put a land card from your hand onto the battlefield; mode = new Mode(); - mode.getEffects().add(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); + mode.addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); this.getSpellAbility().addMode(mode); // or Creatures you control get +1/+1 and gain reach until the end of turn. mode = new Mode(); Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn); effect.setText("Creatures you control get +1/+1"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityControlledEffect(ReachAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gain reach until the end of turn"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java b/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java index 53f6e575df..8bdca274c7 100644 --- a/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java +++ b/Mage.Sets/src/mage/cards/a/AthreosGodOfPassage.java @@ -36,7 +36,7 @@ public final class AthreosGodOfPassage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you own"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new OwnerPredicate(TargetController.YOU)); } @@ -99,7 +99,7 @@ class AthreosGodOfPassageReturnEffect extends OneShotEffect { if (opponent != null) { Cost cost = new PayLifeCost(3); if (cost.canPay(source, source.getSourceId(), opponent.getId(), game) - && opponent.chooseUse(outcome, new StringBuilder("Pay 3 live to prevent that ").append(creature.getLogName()).append(" returns to ").append(controller.getLogName()).append("'s hand?").toString(), source, game)) { + && opponent.chooseUse(outcome, "Pay 3 life to prevent that " + creature.getLogName() + " returns to " + controller.getLogName() + "'s hand?", source, game)) { if (cost.pay(source, game, source.getSourceId(), opponent.getId(), false, null)) { paid = true; } @@ -144,7 +144,7 @@ class AthreosDiesCreatureTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget() != null && filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { for (Effect effect : this.getEffects()) { effect.setValue("creatureId", event.getTargetId()); diff --git a/Mage.Sets/src/mage/cards/a/Atogatog.java b/Mage.Sets/src/mage/cards/a/Atogatog.java index 107f7ccbbe..0f17b1a8a0 100644 --- a/Mage.Sets/src/mage/cards/a/Atogatog.java +++ b/Mage.Sets/src/mage/cards/a/Atogatog.java @@ -37,7 +37,7 @@ public final class Atogatog extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(5); - DynamicValue xValue = new SacrificeCostCreaturesPower(); + DynamicValue xValue = SacrificeCostCreaturesPower.instance; // Sacrifice an Atog creature: Atogatog gets +X/+X until end of turn, where X is the sacrificed creature's power. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(xValue, xValue,Duration.EndOfTurn), diff --git a/Mage.Sets/src/mage/cards/a/AtzocanArcher.java b/Mage.Sets/src/mage/cards/a/AtzocanArcher.java index dfb3b1bbfd..c07989dd62 100644 --- a/Mage.Sets/src/mage/cards/a/AtzocanArcher.java +++ b/Mage.Sets/src/mage/cards/a/AtzocanArcher.java @@ -25,7 +25,7 @@ public final class AtzocanArcher extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AtzocanArcher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AuraGraft.java b/Mage.Sets/src/mage/cards/a/AuraGraft.java index 414c76e5b1..7e0293246c 100644 --- a/Mage.Sets/src/mage/cards/a/AuraGraft.java +++ b/Mage.Sets/src/mage/cards/a/AuraGraft.java @@ -120,7 +120,7 @@ class MoveTargetAuraEffect extends OneShotEffect { } FilterPermanent filter = new FilterPermanent("another permanent " + enchantment.getLogName() + " can enchant"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new PermanentCanBeAttachedToPredicate(enchantment)); Target target = new TargetPermanent(filter); target.setNotTarget(true); diff --git a/Mage.Sets/src/mage/cards/a/AuraMutation.java b/Mage.Sets/src/mage/cards/a/AuraMutation.java index 6586f22e63..7eaad0d970 100644 --- a/Mage.Sets/src/mage/cards/a/AuraMutation.java +++ b/Mage.Sets/src/mage/cards/a/AuraMutation.java @@ -25,7 +25,7 @@ public final class AuraMutation extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); // create X 1/1 green Saproling creature tokens, where X is that enchantment's converted mana cost. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new TargetConvertedManaCost())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), TargetConvertedManaCost.instance)); } public AuraMutation(final AuraMutation card) { diff --git a/Mage.Sets/src/mage/cards/a/AuraOfDominion.java b/Mage.Sets/src/mage/cards/a/AuraOfDominion.java index e0956632a6..2f7be843a0 100644 --- a/Mage.Sets/src/mage/cards/a/AuraOfDominion.java +++ b/Mage.Sets/src/mage/cards/a/AuraOfDominion.java @@ -31,7 +31,7 @@ public final class AuraOfDominion extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } diff --git a/Mage.Sets/src/mage/cards/a/AuratouchedMage.java b/Mage.Sets/src/mage/cards/a/AuratouchedMage.java index 5bd4e110db..7cb38b3de8 100644 --- a/Mage.Sets/src/mage/cards/a/AuratouchedMage.java +++ b/Mage.Sets/src/mage/cards/a/AuratouchedMage.java @@ -69,7 +69,7 @@ class AuratouchedMageEffect extends OneShotEffect { filter.add(new AuraCardCanAttachToLKIPermanentId(source.getSourceId())); TargetCardInLibrary target = new TargetCardInLibrary(filter); target.setNotTarget(true); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (target.getFirstTarget() != null) { Card aura = game.getCard(target.getFirstTarget()); Permanent auratouchedMage = source.getSourcePermanentIfItStillExists(game); diff --git a/Mage.Sets/src/mage/cards/a/AureliasFury.java b/Mage.Sets/src/mage/cards/a/AureliasFury.java index 30fd2f477b..634de83e29 100644 --- a/Mage.Sets/src/mage/cards/a/AureliasFury.java +++ b/Mage.Sets/src/mage/cards/a/AureliasFury.java @@ -1,7 +1,6 @@ package mage.cards.a; -import java.util.*; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; @@ -27,6 +26,10 @@ import mage.target.common.TargetAnyTargetAmount; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * GATECRASH FAQ 11.01.2013 *

    @@ -59,7 +62,7 @@ public final class AureliasFury extends CardImpl { // Aurelia's Fury deals X damage divided as you choose among any number of target creatures and/or players. // Tap each creature dealt damage this way. Players dealt damage this way can't cast noncreature spells this turn. - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new DamageMultiEffect(xValue)); this.getSpellAbility().addEffect(new AureliasFuryEffect()); this.getSpellAbility().addTarget(new TargetAnyTargetAmount(xValue)); @@ -67,7 +70,7 @@ public final class AureliasFury extends CardImpl { } - public AureliasFury(final AureliasFury card) { + private AureliasFury(final AureliasFury card) { super(card); } @@ -79,12 +82,12 @@ public final class AureliasFury extends CardImpl { class AureliasFuryEffect extends OneShotEffect { - public AureliasFuryEffect() { + AureliasFuryEffect() { super(Outcome.Benefit); this.staticText = "Tap each creature dealt damage this way. Players dealt damage this way can't cast noncreature spells this turn"; } - public AureliasFuryEffect(final AureliasFuryEffect effect) { + private AureliasFuryEffect(final AureliasFuryEffect effect) { super(effect); } @@ -95,15 +98,15 @@ class AureliasFuryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - AureliasFuryDamagedByWatcher watcher = (AureliasFuryDamagedByWatcher) game.getState().getWatchers().get(AureliasFuryDamagedByWatcher.class.getSimpleName(), source.getSourceId()); + AureliasFuryDamagedByWatcher watcher = game.getState().getWatcher(AureliasFuryDamagedByWatcher.class, source.getSourceId()); if (watcher != null) { - for (UUID creatureId : watcher.damagedCreatures) { + for (UUID creatureId : watcher.getDamagedCreatures()) { Permanent permanent = game.getPermanent(creatureId); if (permanent != null) { permanent.tap(game); } } - for (UUID playerId : watcher.damagedPlayers) { + for (UUID playerId : watcher.getDamagedPlayers()) { ContinuousEffect effect = new AureliasFuryCantCastEffect(); effect.setTargetPointer(new FixedTarget(playerId)); game.addEffect(effect, source); @@ -117,12 +120,12 @@ class AureliasFuryEffect extends OneShotEffect { class AureliasFuryCantCastEffect extends ContinuousRuleModifyingEffectImpl { - public AureliasFuryCantCastEffect() { + AureliasFuryCantCastEffect() { super(Duration.EndOfTurn, Outcome.Benefit); staticText = "Players dealt damage this way can't cast noncreature spells this turn"; } - public AureliasFuryCantCastEffect(final AureliasFuryCantCastEffect effect) { + private AureliasFuryCantCastEffect(final AureliasFuryCantCastEffect effect) { super(effect); } @@ -165,14 +168,14 @@ class AureliasFuryCantCastEffect extends ContinuousRuleModifyingEffectImpl { class AureliasFuryDamagedByWatcher extends Watcher { - public Set damagedCreatures = new HashSet<>(); - public Set damagedPlayers = new HashSet<>(); + private final Set damagedCreatures = new HashSet<>(); + private final Set damagedPlayers = new HashSet<>(); - public AureliasFuryDamagedByWatcher() { - super(AureliasFuryDamagedByWatcher.class.getSimpleName(), WatcherScope.CARD); + AureliasFuryDamagedByWatcher() { + super(WatcherScope.CARD); } - public AureliasFuryDamagedByWatcher(final AureliasFuryDamagedByWatcher watcher) { + private AureliasFuryDamagedByWatcher(final AureliasFuryDamagedByWatcher watcher) { super(watcher); this.damagedCreatures.addAll(watcher.damagedCreatures); this.damagedPlayers.addAll(watcher.damagedPlayers); @@ -210,4 +213,11 @@ class AureliasFuryDamagedByWatcher extends Watcher { damagedPlayers.clear(); } + Set getDamagedCreatures() { + return damagedCreatures; + } + + Set getDamagedPlayers() { + return damagedPlayers; + } } diff --git a/Mage.Sets/src/mage/cards/a/AuriokChampion.java b/Mage.Sets/src/mage/cards/a/AuriokChampion.java index 4b0fa72273..6bb9d6e8fe 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokChampion.java +++ b/Mage.Sets/src/mage/cards/a/AuriokChampion.java @@ -24,7 +24,7 @@ public final class AuriokChampion extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AuriokChampion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/Aurochs.java b/Mage.Sets/src/mage/cards/a/Aurochs.java index d1b68781a7..ddd1acbe40 100644 --- a/Mage.Sets/src/mage/cards/a/Aurochs.java +++ b/Mage.Sets/src/mage/cards/a/Aurochs.java @@ -27,7 +27,7 @@ public final class Aurochs extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.AUROCHS)); - filter1.add(new AnotherPredicate()); + filter1.add(AnotherPredicate.instance); } public Aurochs(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AurochsHerd.java b/Mage.Sets/src/mage/cards/a/AurochsHerd.java index ab0b6b6ef2..62223e8f2e 100644 --- a/Mage.Sets/src/mage/cards/a/AurochsHerd.java +++ b/Mage.Sets/src/mage/cards/a/AurochsHerd.java @@ -33,7 +33,7 @@ public final class AurochsHerd extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.AUROCHS)); filter2.add(new SubtypePredicate(SubType.AUROCHS)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public AurochsHerd(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AuroraChampion.java b/Mage.Sets/src/mage/cards/a/AuroraChampion.java index 365bb5f82e..b4932d81b2 100644 --- a/Mage.Sets/src/mage/cards/a/AuroraChampion.java +++ b/Mage.Sets/src/mage/cards/a/AuroraChampion.java @@ -25,7 +25,7 @@ public final class AuroraChampion extends CardImpl { private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "another Warrior"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AuroraChampion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java b/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java index b09ac13a39..074f1e164d 100644 --- a/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java +++ b/Mage.Sets/src/mage/cards/a/AurraSingBaneOfJedi.java @@ -1,8 +1,5 @@ - package mage.cards.a; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; @@ -18,6 +15,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.game.Game; @@ -27,29 +25,32 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.List; +import java.util.UUID; + /** - * * @author Styxo */ public final class AurraSingBaneOfJedi extends CardImpl { public AurraSingBaneOfJedi(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}{R}"); + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.AURRA); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); - // +1:You may have {this} deal 2 damage to target creature. If you don't, {this} deals 1 damage to you. + // +1: You may have {this} deal 2 damage to target creature. If you don't, {this} deals 1 damage to you. Ability ability = new LoyaltyAbility(new AurraSingBaneOfJediEffect(), +1); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - // -4:Target player gets an emblem wiht "Whenever a nontoken creature you control leave the battlefied, discard a card.". + // -4: Target player gets an emblem wiht "Whenever a nontoken creature you control leave the battlefied, discard a card.". ability = new LoyaltyAbility(new GetEmblemTargetPlayerEffect(new AurraSingBaneOfJediEmblem()), -4); ability.addTarget(new TargetPlayer()); this.addAbility(ability); - // -6:Each player discards their hand and sacrificies all creatures he or she controls. Each player's life total becomes 1." + // -6: Each player discards their hand and sacrificies all creatures he or she controls. Each player's life total becomes 1." ability = new LoyaltyAbility(new DiscardHandAllEffect(), -6); ability.addEffect(new SacrificeAllEffect()); Effect effect = new SetPlayerLifeAllEffect(1, TargetController.ANY); diff --git a/Mage.Sets/src/mage/cards/a/AustereCommand.java b/Mage.Sets/src/mage/cards/a/AustereCommand.java index 71339579e6..76503ff207 100644 --- a/Mage.Sets/src/mage/cards/a/AustereCommand.java +++ b/Mage.Sets/src/mage/cards/a/AustereCommand.java @@ -37,15 +37,15 @@ public final class AustereCommand extends CardImpl { this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterArtifactPermanent("artifacts"))); // or destroy all enchantments; Mode mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(new FilterEnchantmentPermanent("enchantments"))); + mode.addEffect(new DestroyAllEffect(new FilterEnchantmentPermanent("enchantments"))); this.getSpellAbility().getModes().addMode(mode); // or destroy all creatures with converted mana cost 3 or less; mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(filter3orLess)); + mode.addEffect(new DestroyAllEffect(filter3orLess)); this.getSpellAbility().getModes().addMode(mode); // or destroy all creatures with converted mana cost 4 or greater. mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(filter4orMore)); + mode.addEffect(new DestroyAllEffect(filter4orMore)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java index ca41a7b3d6..f9cbe9fe74 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnalGloom.java +++ b/Mage.Sets/src/mage/cards/a/AutumnalGloom.java @@ -1,7 +1,7 @@ - package mage.cards.a; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,13 +19,12 @@ import mage.constants.TargetController; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class AutumnalGloom extends CardImpl { public AutumnalGloom(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); this.transformable = true; this.secondSideCardClazz = AncientOfTheEquinox.class; @@ -35,6 +35,7 @@ public final class AutumnalGloom extends CardImpl { this.addAbility(new TransformAbility()); Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new TransformSourceEffect(true), TargetController.YOU, DeliriumCondition.instance, false); ability.setAbilityWord(AbilityWord.DELIRIUM); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java b/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java index ec6d5355c2..acc437a572 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java +++ b/Mage.Sets/src/mage/cards/a/AvacynGuardianAngel.java @@ -33,7 +33,7 @@ public final class AvacynGuardianAngel extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AvacynGuardianAngel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java b/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java index e3ff29da23..47dfa768b6 100644 --- a/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java +++ b/Mage.Sets/src/mage/cards/a/AvacynThePurifier.java @@ -107,7 +107,7 @@ class AvacynThePurifierEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { FilterCreaturePermanent filter = new FilterCreaturePermanent("each other creature"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game); for (Permanent permanent : permanents) { permanent.damage(3, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/a/Avalanche.java b/Mage.Sets/src/mage/cards/a/Avalanche.java index ed9bbbeb21..703bd8f95a 100644 --- a/Mage.Sets/src/mage/cards/a/Avalanche.java +++ b/Mage.Sets/src/mage/cards/a/Avalanche.java @@ -1,40 +1,32 @@ package mage.cards.a; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class Avalanche extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent("snow lands"); - public Avalanche(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{2}{R}{R}"); // Destroy X target snow lands. this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy X target snow lands")); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetPermanent(xValue, xValue, filter, false)); - } + this.getSpellAbility().setTargetAdjuster(AvalancheAdjuster.instance); } public Avalanche(final Avalanche card) { @@ -46,3 +38,19 @@ public final class Avalanche extends CardImpl { return new Avalanche(this); } } + +enum AvalancheAdjuster implements TargetAdjuster { + instance; + private static final FilterPermanent filter = new FilterLandPermanent("snow lands"); + + static { + filter.add(new SupertypePredicate(SuperType.SNOW)); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetPermanent(xValue, xValue, filter, false)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfFury.java b/Mage.Sets/src/mage/cards/a/AvatarOfFury.java index dbcc9e1e04..eed329a4e2 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfFury.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfFury.java @@ -85,55 +85,4 @@ class AvatarOfFuryAdjustingCostsAbility extends SimpleStaticAbility implements A } } } -} - -//class AvatarOfFuryAdjustingCostsEffect extends CostModificationEffectImpl { -// -// public AvatarOfFuryAdjustingCostsEffect() { -// super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); -// } -// -// public AvatarOfFuryAdjustingCostsEffect(final AvatarOfFuryAdjustingCostsEffect effect) { -// super(effect); -// } -// -// @Override -// public boolean apply(Game game, Ability source, Ability abilityToModify) { -// SpellAbility spellAbility = (SpellAbility)abilityToModify; -// Mana mana = spellAbility.getManaCostsToPay().getMana(); -// -// boolean condition = false; -// FilterPermanent filter = new FilterLandPermanent(); -// for (UUID playerId: game.getOpponents(source.getControllerId())) { -// if (game.getBattlefield().countAll(filter, playerId, game) > 6) { -// condition = true; -// break; -// } -// } -// -// if (mana.getColorless() > 0 && condition) { -// int newCount = mana.getColorless() - 6; -// if (newCount < 0) { -// newCount = 0; -// } -// mana.setColorless(newCount); -// spellAbility.getManaCostsToPay().load(mana.toString()); -// return true; -// } -// return false; -// } -// -// @Override -// public boolean applies(Ability abilityToModify, Ability source, Game game) { -// if ((abilityToModify instanceof SpellAbility || abilityToModify instanceof FlashbackAbility || abilityToModify instanceof RetraceAbility) -// && abilityToModify.getSourceId().equals(source.getSourceId())) { -// return true; -// } -// return false; -// } -// -// @Override -// public AvatarOfFuryAdjustingCostsEffect copy() { -// return new AvatarOfFuryAdjustingCostsEffect(this); -// } -//} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfGrowth.java b/Mage.Sets/src/mage/cards/a/AvatarOfGrowth.java new file mode 100644 index 0000000000..cd41b415dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvatarOfGrowth.java @@ -0,0 +1,93 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceForOpponentsEffect; +import mage.abilities.keyword.TrampleAbility; +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.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class AvatarOfGrowth extends CardImpl { + + public AvatarOfGrowth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.AVATAR); + + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // This spell costs {1} less to cast for each opponent you have. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceForOpponentsEffect("This spell costs {1} less to cast for each opponent you have"))); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Avatar of Growth enters the battlefield, each player searches their library for up to two basic land cards, puts them onto the battlefield, then shuffles their library. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AvatarOfGrowthSearchEffect())); + } + + public AvatarOfGrowth(final AvatarOfGrowth card) { + super(card); + } + + @Override + public AvatarOfGrowth copy() { + return new AvatarOfGrowth(this); + } +} + +class AvatarOfGrowthSearchEffect extends OneShotEffect { + + public AvatarOfGrowthSearchEffect() { + super(Outcome.Detriment); + this.staticText = "each player searches their library for up to two basic land cards, puts them onto the battlefield, then shuffles their libarary"; + } + + public AvatarOfGrowthSearchEffect(final AvatarOfGrowthSearchEffect effect) { + super(effect); + } + + @Override + public AvatarOfGrowthSearchEffect copy() { + return new AvatarOfGrowthSearchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); + if (player.searchLibrary(target, source, game)) { + if (!target.getTargets().isEmpty()) { + player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); + } + } + player.shuffleLibrary(source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfTheResolute.java b/Mage.Sets/src/mage/cards/a/AvatarOfTheResolute.java index 1265256eb7..987d7a0122 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfTheResolute.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfTheResolute.java @@ -28,7 +28,7 @@ public final class AvatarOfTheResolute extends CardImpl { static { filter.add(new CounterPredicate(CounterType.P1P1)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AvatarOfTheResolute(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AvenEternal.java b/Mage.Sets/src/mage/cards/a/AvenEternal.java new file mode 100644 index 0000000000..fa0afe4db3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AvenEternal.java @@ -0,0 +1,43 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.FlyingAbility; +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 AvenEternal extends CardImpl { + + public AvenEternal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Aven Eternal enters the battlefield, amass 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(1))); + } + + private AvenEternal(final AvenEternal card) { + super(card); + } + + @Override + public AvenEternal copy() { + return new AvenEternal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AvenMimeomancer.java b/Mage.Sets/src/mage/cards/a/AvenMimeomancer.java index 64ccbf893f..dcb30c301d 100644 --- a/Mage.Sets/src/mage/cards/a/AvenMimeomancer.java +++ b/Mage.Sets/src/mage/cards/a/AvenMimeomancer.java @@ -91,9 +91,7 @@ class AvenEffect extends ContinuousEffectImpl { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append("If you do, that creature has base power and toughness 3/1 and has flying for as long as it has a feather counter on it"); - return sb.toString(); + return "If you do, that creature has base power and toughness 3/1 and has flying for as long as it has a feather counter on it"; } } diff --git a/Mage.Sets/src/mage/cards/a/AvenShrine.java b/Mage.Sets/src/mage/cards/a/AvenShrine.java index d949acb21f..7bf7b50760 100644 --- a/Mage.Sets/src/mage/cards/a/AvenShrine.java +++ b/Mage.Sets/src/mage/cards/a/AvenShrine.java @@ -67,7 +67,7 @@ class AvenShrineTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); MageObject mageObject = game.getObject(sourceId); - if (spell != null) { + if (spell != null && mageObject != null) { game.getState().setValue("avenShrine" + mageObject, spell); return true; } @@ -91,21 +91,23 @@ class AvenShrineEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int count = 0; MageObject mageObject = game.getObject(source.getSourceId()); - Spell spell = (Spell) game.getState().getValue("avenShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); + if(mageObject != null) { + Spell spell = (Spell) game.getState().getValue("avenShrine" + mageObject); + if (spell != null) { + Player controller = game.getPlayer(spell.getControllerId()); + if (controller != null) { + String name = spell.getName(); + FilterCard filterCardName = new FilterCard(); + filterCardName.add(new NamePredicate(name)); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + count += player.getGraveyard().count(filterCardName, game); + } } + controller.gainLife(count, game, source); + return true; } - controller.gainLife(count, game, source); - return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java index 52e9da2dc8..9c0d5ed7e9 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java +++ b/Mage.Sets/src/mage/cards/a/AvenSoulgazer.java @@ -33,7 +33,7 @@ public final class AvenSoulgazer extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public AvenSoulgazer(UUID ownerId, CardSetInfo setInfo) { @@ -89,8 +89,7 @@ class AvenSoulgazerLookFaceDownEffect extends OneShotEffect { if (faceDownCreature != null) { Permanent copyFaceDown = faceDownCreature.copy(); copyFaceDown.setFaceDown(false, game); - Cards cards = new CardsImpl(); - cards.add(copyFaceDown); + Cards cards = new CardsImpl(copyFaceDown); player.lookAtCards("face down card - " + mageObject.getName(), cards, game); } else { return false; diff --git a/Mage.Sets/src/mage/cards/a/AvenSurveyor.java b/Mage.Sets/src/mage/cards/a/AvenSurveyor.java index 2153c5f1b3..9104c32feb 100644 --- a/Mage.Sets/src/mage/cards/a/AvenSurveyor.java +++ b/Mage.Sets/src/mage/cards/a/AvenSurveyor.java @@ -38,8 +38,8 @@ public final class AvenSurveyor extends CardImpl { // * Return target creature to its owner's hand Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/a/AvengingArrow.java b/Mage.Sets/src/mage/cards/a/AvengingArrow.java index eb277e62ce..e04ff459b6 100644 --- a/Mage.Sets/src/mage/cards/a/AvengingArrow.java +++ b/Mage.Sets/src/mage/cards/a/AvengingArrow.java @@ -53,7 +53,7 @@ class AvengingArrowTarget extends TargetPermanent { @Override public boolean canTarget(UUID id, Ability source, Game game) { - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); if (watcher != null) { if (watcher.damageSources.contains(id)) { return super.canTarget(id, source, game); @@ -66,7 +66,7 @@ class AvengingArrowTarget extends TargetPermanent { public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); if (watcher != null) { for (UUID targetId : availablePossibleTargets) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/a/AviaryMechanic.java b/Mage.Sets/src/mage/cards/a/AviaryMechanic.java index 37acc4e67e..59a64bd234 100644 --- a/Mage.Sets/src/mage/cards/a/AviaryMechanic.java +++ b/Mage.Sets/src/mage/cards/a/AviaryMechanic.java @@ -21,7 +21,7 @@ public final class AviaryMechanic extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public AviaryMechanic(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AvoidFate.java b/Mage.Sets/src/mage/cards/a/AvoidFate.java index c5d9a4834a..2e8bd46831 100644 --- a/Mage.Sets/src/mage/cards/a/AvoidFate.java +++ b/Mage.Sets/src/mage/cards/a/AvoidFate.java @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class AvoidFate extends CardImpl { - private final static FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); + private static final FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new SubtypePredicate(SubType.AURA))); diff --git a/Mage.Sets/src/mage/cards/a/AwakenTheErstwhile.java b/Mage.Sets/src/mage/cards/a/AwakenTheErstwhile.java new file mode 100644 index 0000000000..13a4d8ad62 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AwakenTheErstwhile.java @@ -0,0 +1,85 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +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.ZombieToken; +import mage.players.Player; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class AwakenTheErstwhile extends CardImpl { + + public AwakenTheErstwhile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); + + // Each player discards all the cards in their hand, then creates that many 2/2 black Zombie creature tokens. + this.getSpellAbility().addEffect(new AwakenTheErstwhileEffect()); + } + + public AwakenTheErstwhile(final AwakenTheErstwhile card) { + super(card); + } + + @Override + public AwakenTheErstwhile copy() { + return new AwakenTheErstwhile(this); + } +} + +class AwakenTheErstwhileEffect extends OneShotEffect { + + public AwakenTheErstwhileEffect() { + super(Outcome.Detriment); + this.staticText = "each player discards all the cards in their hand, then creates that many 2/2 black Zombie creature tokens"; + } + + public AwakenTheErstwhileEffect(final AwakenTheErstwhileEffect effect) { + super(effect); + } + + @Override + public AwakenTheErstwhileEffect copy() { + return new AwakenTheErstwhileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + // discard hands + Map cardsAmount = new HashMap<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + int cardsInHand = player.getHand().size(); + if (cardsInHand > 0) { + player.discard(cardsInHand, false, source, game); + cardsAmount.put(playerId, cardsInHand); + } + } + } + + // create tokens + cardsAmount.entrySet().forEach(discardedHand -> { + Player player = game.getPlayer(discardedHand.getKey()); + int tokensCount = discardedHand.getValue(); + if (player != null && tokensCount > 0) { + new ZombieToken().putOntoBattlefield(tokensCount, game, source.getSourceId(), player.getId()); + } + }); + + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/a/AwakeningOfVituGhazi.java b/Mage.Sets/src/mage/cards/a/AwakeningOfVituGhazi.java new file mode 100644 index 0000000000..b7b2b87c67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AwakeningOfVituGhazi.java @@ -0,0 +1,66 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +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.StaticFilters; +import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AwakeningOfVituGhazi extends CardImpl { + + public AwakeningOfVituGhazi(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{G}"); + + // Put nine +1/+1 counters on target land you control. It becomes a legendary 0/0 Elemental creature with haste named Vitu-Ghazi. It's still a land. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(9))); + this.getSpellAbility().addEffect(new BecomesCreatureTargetEffect( + new AwakeningOfVituGhaziToken(), false, true, Duration.Custom, true + ).setText("It becomes a legendary 0/0 Elemental creature with haste named Vitu-Ghazi. It's still a land.")); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND)); + } + + private AwakeningOfVituGhazi(final AwakeningOfVituGhazi card) { + super(card); + } + + @Override + public AwakeningOfVituGhazi copy() { + return new AwakeningOfVituGhazi(this); + } +} + +class AwakeningOfVituGhaziToken extends TokenImpl { + + AwakeningOfVituGhaziToken() { + super("Vitu-Ghazi", "legendary 0/0 Elemental creature with haste named Vitu-Ghazi"); + this.supertype.add(SuperType.LEGENDARY); + this.cardType.add(CardType.CREATURE); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + this.addAbility(HasteAbility.getInstance()); + } + + private AwakeningOfVituGhaziToken(final AwakeningOfVituGhaziToken token) { + super(token); + } + + public AwakeningOfVituGhaziToken copy() { + return new AwakeningOfVituGhaziToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AweForTheGuilds.java b/Mage.Sets/src/mage/cards/a/AweForTheGuilds.java index f1569e4915..4a0ee0ad5f 100644 --- a/Mage.Sets/src/mage/cards/a/AweForTheGuilds.java +++ b/Mage.Sets/src/mage/cards/a/AweForTheGuilds.java @@ -22,7 +22,7 @@ public final class AweForTheGuilds extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Monocolored creatures"); static { - filter.add(Predicates.not(new MulticoloredPredicate())); + filter.add(Predicates.not(MulticoloredPredicate.instance)); } public AweForTheGuilds(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/a/AwesomePresence.java b/Mage.Sets/src/mage/cards/a/AwesomePresence.java new file mode 100644 index 0000000000..604d293a3c --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AwesomePresence.java @@ -0,0 +1,96 @@ +package mage.cards.a; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCosts; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.PayCostToAttackBlockEffectImpl; +import mage.abilities.effects.PayCostToAttackBlockEffectImpl.RestrictType; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class AwesomePresence extends CardImpl { + + public AwesomePresence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature can't be blocked unless defending player pays {3} for each creature he or she controls that's blocking it. + this.addAbility(new SimpleStaticAbility(new AwesomePresenceRestrictionEffect(new ManaCostsImpl("{3}")))); + + } + + private AwesomePresence(final AwesomePresence card) { + super(card); + } + + @Override + public AwesomePresence copy() { + return new AwesomePresence(this); + } +} + +class AwesomePresenceRestrictionEffect extends PayCostToAttackBlockEffectImpl { + + public AwesomePresenceRestrictionEffect(ManaCosts manaCosts) { + super(Duration.WhileOnBattlefield, Outcome.Neutral, RestrictType.BLOCK, manaCosts); + staticText = "Enchanted creature" + + " can't be blocked " + + "unless defending player pays " + + (manaCosts == null ? "" : manaCosts.getText() + + " for each creature he or she controls that's blocking it"); + } + + public AwesomePresenceRestrictionEffect(AwesomePresenceRestrictionEffect effect) { + super(effect); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent blockingCreature = game.getPermanent(event.getSourceId()); + Permanent enchantedAttackingCreature = game.getPermanent(event.getTargetId()); + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (blockingCreature != null + && enchantedAttackingCreature != null + && enchantment.isAttachedTo(enchantedAttackingCreature.getId())) { + Player defendingPlayer = game.getPlayer(blockingCreature.getControllerId()); + if (defendingPlayer != null) { + if (manaCosts.canPay(source, source.getSourceId(), defendingPlayer.getId(), game) + && manaCosts.pay(source, game, source.getSourceId(), defendingPlayer.getId(), false)) { + return false; + } + } + } + return true; + } + + @Override + public AwesomePresenceRestrictionEffect copy() { + return new AwesomePresenceRestrictionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AxebaneBeast.java b/Mage.Sets/src/mage/cards/a/AxebaneBeast.java new file mode 100644 index 0000000000..f620a5ff30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AxebaneBeast.java @@ -0,0 +1,32 @@ +package mage.cards.a; + +import java.util.UUID; + +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * @author TheElk801 + */ +public final class AxebaneBeast extends CardImpl { + + public AxebaneBeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + } + + private AxebaneBeast(final AxebaneBeast card) { + super(card); + } + + @Override + public AxebaneBeast copy() { + return new AxebaneBeast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java b/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java index cf8165cc37..a0aa295210 100644 --- a/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java +++ b/Mage.Sets/src/mage/cards/a/AyeshaTanaka.java @@ -26,7 +26,7 @@ import mage.target.common.TargetActivatedAbility; */ public final class AyeshaTanaka extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private static final FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); diff --git a/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java b/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java index dd52b588a1..4e6c3c3282 100644 --- a/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java +++ b/Mage.Sets/src/mage/cards/a/AyliEternalPilgrim.java @@ -45,7 +45,7 @@ public final class AyliEternalPilgrim extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // {1}, Sacrifice another creature: You gain life equal to the sacrificed creature's toughness. - Effect effect = new GainLifeEffect(new SacrificeCostCreaturesToughness()); + Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance); effect.setText("You gain life equal to the sacrificed creature's toughness"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1)); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); @@ -78,6 +78,9 @@ class AyliEternalPilgrimCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - return player.getLife() >= game.getLife() + 10; + if(player != null) { + return player.getLife() >= game.getLife() + 10; + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/a/AzamiLadyOfScrolls.java b/Mage.Sets/src/mage/cards/a/AzamiLadyOfScrolls.java index 456b3bd39b..0c3d861582 100644 --- a/Mage.Sets/src/mage/cards/a/AzamiLadyOfScrolls.java +++ b/Mage.Sets/src/mage/cards/a/AzamiLadyOfScrolls.java @@ -27,7 +27,7 @@ public final class AzamiLadyOfScrolls extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Wizard you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.WIZARD)); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusCharm.java b/Mage.Sets/src/mage/cards/a/AzoriusCharm.java index 611f935937..e749a8ddfb 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusCharm.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusCharm.java @@ -29,13 +29,13 @@ public final class AzoriusCharm extends CardImpl { // or draw a card; Mode mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(1)); + mode.addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().addMode(mode); // or put target attacking or blocking creature on top of its owner's library. mode = new Mode(); - mode.getTargets().add(new TargetAttackingOrBlockingCreature()); - mode.getEffects().add(new PutOnLibraryTargetEffect(true)); + mode.addTarget(new TargetAttackingOrBlockingCreature()); + mode.addEffect(new PutOnLibraryTargetEffect(true)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusKnightArbiter.java b/Mage.Sets/src/mage/cards/a/AzoriusKnightArbiter.java new file mode 100644 index 0000000000..11f763bf98 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzoriusKnightArbiter.java @@ -0,0 +1,41 @@ +package mage.cards.a; + +import mage.MageInt; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AzoriusKnightArbiter extends CardImpl { + + public AzoriusKnightArbiter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Azorius Knight-Arbiter can't be blocked. + this.addAbility(new CantBeBlockedSourceAbility()); + } + + private AzoriusKnightArbiter(final AzoriusKnightArbiter card) { + super(card); + } + + @Override + public AzoriusKnightArbiter copy() { + return new AzoriusKnightArbiter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzoriusLocket.java b/Mage.Sets/src/mage/cards/a/AzoriusLocket.java new file mode 100644 index 0000000000..8f78a48347 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzoriusLocket.java @@ -0,0 +1,45 @@ +package mage.cards.a; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class AzoriusLocket extends CardImpl { + + public AzoriusLocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add {W} or {U}. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlueManaAbility()); + + // {W/U}{W/U}{W/U}{W/U}, {T}, Sacrifice Azorius Locket: Draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{W/U}{W/U}{W/U}{W/U}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public AzoriusLocket(final AzoriusLocket card) { + super(card); + } + + @Override + public AzoriusLocket copy() { + return new AzoriusLocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/a/AzoriusPloy.java b/Mage.Sets/src/mage/cards/a/AzoriusPloy.java index c7e1c996d5..0a2586584a 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusPloy.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusPloy.java @@ -2,14 +2,9 @@ package mage.cards.a; import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.AbilityImpl; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.PreventCombatDamageBySourceEffect; import mage.abilities.effects.common.PreventDamageByTargetEffect; import mage.abilities.effects.common.PreventDamageToTargetEffect; -import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -46,7 +41,7 @@ public final class AzoriusPloy extends CardImpl { } - public AzoriusPloy(final AzoriusPloy card) { + private AzoriusPloy(final AzoriusPloy card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusSkyguard.java b/Mage.Sets/src/mage/cards/a/AzoriusSkyguard.java new file mode 100644 index 0000000000..58cb054d70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/a/AzoriusSkyguard.java @@ -0,0 +1,47 @@ +package mage.cards.a; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostOpponentsEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class AzoriusSkyguard extends CardImpl { + + public AzoriusSkyguard(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Creatures your opponents control get -1/-0. + this.addAbility(new SimpleStaticAbility(new BoostOpponentsEffect(-1, 0, Duration.WhileOnBattlefield))); + } + + private AzoriusSkyguard(final AzoriusSkyguard card) { + super(card); + } + + @Override + public AzoriusSkyguard copy() { + return new AzoriusSkyguard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Backlash.java b/Mage.Sets/src/mage/cards/b/Backlash.java index 274ab60416..b054f340c3 100644 --- a/Mage.Sets/src/mage/cards/b/Backlash.java +++ b/Mage.Sets/src/mage/cards/b/Backlash.java @@ -24,7 +24,7 @@ public final class Backlash extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creature"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Backlash(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BackwoodsSurvivalists.java b/Mage.Sets/src/mage/cards/b/BackwoodsSurvivalists.java index f6da0d428d..7a8e9af331 100644 --- a/Mage.Sets/src/mage/cards/b/BackwoodsSurvivalists.java +++ b/Mage.Sets/src/mage/cards/b/BackwoodsSurvivalists.java @@ -1,7 +1,7 @@ - package mage.cards.b; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,13 +19,12 @@ import mage.constants.SubType; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class BackwoodsSurvivalists extends CardImpl { public BackwoodsSurvivalists(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.HUMAN, SubType.WARRIOR); this.power = new MageInt(4); this.toughness = new MageInt(3); @@ -33,6 +33,7 @@ public final class BackwoodsSurvivalists extends CardImpl { ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} gets +1/+1"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance()), DeliriumCondition.instance, "and has trample as long as there are four or more card types among cards in your graveyard.")); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BalaGedThief.java b/Mage.Sets/src/mage/cards/b/BalaGedThief.java index 50f18dede1..1ab4059d2c 100644 --- a/Mage.Sets/src/mage/cards/b/BalaGedThief.java +++ b/Mage.Sets/src/mage/cards/b/BalaGedThief.java @@ -106,7 +106,7 @@ class BalaGedThiefEffect extends OneShotEffect { Card card = revealedCards.get(targetInHand.getFirstTarget(), game); if (card != null) { targetPlayer.discard(card, source, game); - game.informPlayers(new StringBuilder("Bala Ged Thief: ").append(targetPlayer.getLogName()).append(" discarded ").append(card.getName()).toString()); + game.informPlayers("Bala Ged Thief: " + targetPlayer.getLogName() + " discarded " + card.getName()); } } return true; diff --git a/Mage.Sets/src/mage/cards/b/BalduvianConjurer.java b/Mage.Sets/src/mage/cards/b/BalduvianConjurer.java index c9797864b5..e2a00d7149 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianConjurer.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianConjurer.java @@ -11,8 +11,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SupertypePredicate; -import mage.game.permanent.token.TokenImpl; -import mage.game.permanent.token.Token; import mage.game.permanent.token.custom.CreatureToken; import mage.target.TargetPermanent; @@ -43,7 +41,7 @@ public final class BalduvianConjurer extends CardImpl { this.addAbility(ability); } - public BalduvianConjurer(final BalduvianConjurer card) { + private BalduvianConjurer(final BalduvianConjurer card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BalduvianFallen.java b/Mage.Sets/src/mage/cards/b/BalduvianFallen.java index 6191b9cf44..7d8565f997 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianFallen.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianFallen.java @@ -3,8 +3,6 @@ package mage.cards.b; import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.constants.Duration; import mage.constants.SubType; @@ -38,7 +36,7 @@ public final class BalduvianFallen extends CardImpl { this.addAbility(new BalduvianFallenAbility()); } - public BalduvianFallen(final BalduvianFallen card) { + private BalduvianFallen(final BalduvianFallen card) { super(card); } @@ -54,7 +52,7 @@ class BalduvianFallenAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, null, false); } - public BalduvianFallenAbility(final BalduvianFallenAbility ability) { + private BalduvianFallenAbility(final BalduvianFallenAbility ability) { super(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java b/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java index dfe26e4d7d..2dfa74a2a6 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianFrostwaker.java @@ -15,7 +15,6 @@ import mage.constants.*; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.permanent.token.TokenImpl; -import mage.game.permanent.token.Token; import mage.target.TargetPermanent; /** @@ -44,7 +43,7 @@ public final class BalduvianFrostwaker extends CardImpl { this.addAbility(ability); } - public BalduvianFrostwaker(final BalduvianFrostwaker card) { + private BalduvianFrostwaker(final BalduvianFrostwaker card) { super(card); } @@ -65,7 +64,7 @@ class BalduvianFrostwakerToken extends TokenImpl { this.toughness = new MageInt(2); this.addAbility(FlyingAbility.getInstance()); } - public BalduvianFrostwakerToken(final BalduvianFrostwakerToken token) { + private BalduvianFrostwakerToken(final BalduvianFrostwakerToken token) { super(token); } diff --git a/Mage.Sets/src/mage/cards/b/BalduvianRage.java b/Mage.Sets/src/mage/cards/b/BalduvianRage.java index 832c748b7c..9f3e910722 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianRage.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianRage.java @@ -25,7 +25,7 @@ public final class BalduvianRage extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{R}"); // Target attacking creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterAttackingCreature())); // Draw a card at the beginning of the next turn's upkeep. diff --git a/Mage.Sets/src/mage/cards/b/BalduvianTradingPost.java b/Mage.Sets/src/mage/cards/b/BalduvianTradingPost.java index 9c4c948a5a..d133e2483a 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianTradingPost.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianTradingPost.java @@ -34,7 +34,7 @@ public final class BalduvianTradingPost extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MOUNTAIN)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public BalduvianTradingPost(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java index 1adf661c5c..7cc9356024 100644 --- a/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java +++ b/Mage.Sets/src/mage/cards/b/BalduvianWarlord.java @@ -51,7 +51,7 @@ public final class BalduvianWarlord extends CardImpl { this.addAbility(ability, new BlockedByOnlyOneCreatureThisCombatWatcher()); } - public BalduvianWarlord(final BalduvianWarlord card) { + private BalduvianWarlord(final BalduvianWarlord card) { super(card); } @@ -69,7 +69,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { this.staticText = " Remove target blocking creature from combat. Creatures it was blocking that hadn't become blocked by another creature this combat become unblocked, then it blocks an attacking creature of your choice"; } - public BalduvianWarlordUnblockEffect(final BalduvianWarlordUnblockEffect effect) { + private BalduvianWarlordUnblockEffect(final BalduvianWarlordUnblockEffect effect) { super(effect); } @@ -89,7 +89,7 @@ class BalduvianWarlordUnblockEffect extends OneShotEffect { effect.apply(game, source); // Make blocked creatures unblocked - BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName()); + BlockedByOnlyOneCreatureThisCombatWatcher watcher = game.getState().getWatcher(BlockedByOnlyOneCreatureThisCombatWatcher.class); if (watcher != null) { Set combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId()); if (combatGroups != null) { diff --git a/Mage.Sets/src/mage/cards/b/BalefulForce.java b/Mage.Sets/src/mage/cards/b/BalefulForce.java index 09b09a0e70..4107df5840 100644 --- a/Mage.Sets/src/mage/cards/b/BalefulForce.java +++ b/Mage.Sets/src/mage/cards/b/BalefulForce.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -14,24 +12,24 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BalefulForce extends CardImpl { public BalefulForce(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}{B}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(7); this.toughness = new MageInt(7); // At the beginning of each upkeep, you draw a card and you lose 1 life. - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1), TargetController.ANY, false); + Ability ability = new BeginningOfUpkeepTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), TargetController.ANY, false); Effect effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability.addEffect(effect); + ability.addEffect(effect.concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BallistaSquad.java b/Mage.Sets/src/mage/cards/b/BallistaSquad.java index 232a7b75f1..b52ad56e1d 100644 --- a/Mage.Sets/src/mage/cards/b/BallistaSquad.java +++ b/Mage.Sets/src/mage/cards/b/BallistaSquad.java @@ -30,7 +30,7 @@ public final class BallistaSquad extends CardImpl { this.toughness = new MageInt(2); // {X}{W}, {T}: Ballista Squad deals X damage to target attacking or blocking creature. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{W}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{W}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetAttackingOrBlockingCreature()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BallynockCohort.java b/Mage.Sets/src/mage/cards/b/BallynockCohort.java index 564920405b..e241fcec13 100644 --- a/Mage.Sets/src/mage/cards/b/BallynockCohort.java +++ b/Mage.Sets/src/mage/cards/b/BallynockCohort.java @@ -32,7 +32,7 @@ public final class BallynockCohort extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private String rule = "{this} gets +1/+1 as long as you control another white creature"; diff --git a/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java b/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java index ad1a669e75..8ee894caa0 100644 --- a/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java +++ b/Mage.Sets/src/mage/cards/b/BalmOfRestoration.java @@ -33,8 +33,8 @@ public final class BalmOfRestoration extends CardImpl { // or prevent the next 2 damage that would be dealt to any target this turn. Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 2)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 2)); + mode.addTarget(new TargetAnyTarget()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BalothCageTrap.java b/Mage.Sets/src/mage/cards/b/BalothCageTrap.java index 9d419b7921..4c86becb5b 100644 --- a/Mage.Sets/src/mage/cards/b/BalothCageTrap.java +++ b/Mage.Sets/src/mage/cards/b/BalothCageTrap.java @@ -50,7 +50,7 @@ enum BalothCageTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List permanents = watcher.getThisTurnEnteringPermanents(opponentId); diff --git a/Mage.Sets/src/mage/cards/b/BalthorTheStout.java b/Mage.Sets/src/mage/cards/b/BalthorTheStout.java index ef768145d4..1e280dd027 100644 --- a/Mage.Sets/src/mage/cards/b/BalthorTheStout.java +++ b/Mage.Sets/src/mage/cards/b/BalthorTheStout.java @@ -28,7 +28,7 @@ public final class BalthorTheStout extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.BARBARIAN)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); filter2.add(new SubtypePredicate(SubType.BARBARIAN)); } diff --git a/Mage.Sets/src/mage/cards/b/BandTogether.java b/Mage.Sets/src/mage/cards/b/BandTogether.java new file mode 100644 index 0000000000..ec4b774035 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BandTogether.java @@ -0,0 +1,99 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BandTogether extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("creatures you control"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("another target creature"); + + static { + filter.add(new AnotherTargetPredicate(1)); + filter2.add(new AnotherTargetPredicate(2)); + } + + public BandTogether(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Up to two target creatures you control each deal damage equal to their power to another target creature. + this.getSpellAbility().addEffect(new BandTogetherEffect()); + Target target = new TargetPermanent(0, 2, filter, false); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + target = new TargetPermanent(1, 1, filter2, false); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + } + + private BandTogether(final BandTogether card) { + super(card); + } + + @Override + public BandTogether copy() { + return new BandTogether(this); + } +} + +class BandTogetherEffect extends OneShotEffect { + + BandTogetherEffect() { + super(Outcome.Benefit); + this.staticText = "Up to two target creatures you control each deal damage equal to their power to another target creature."; + } + + private BandTogetherEffect(final BandTogetherEffect effect) { + super(effect); + } + + @Override + public BandTogetherEffect copy() { + return new BandTogetherEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getTargets().size() < 2) { + return false; + } + + Target damageTarget = source.getTargets().get(0); + Target destTarget = source.getTargets().get(1); + if (damageTarget.getTargets().isEmpty() || destTarget.getTargets().isEmpty()) { + return false; + } + + Permanent permanentDamage1 = damageTarget.getTargets().size() < 1 ? null : game.getPermanent(damageTarget.getTargets().get(0)); + Permanent permanentDamage2 = damageTarget.getTargets().size() < 2 ? null : game.getPermanent(damageTarget.getTargets().get(1)); + Permanent permanentDest = game.getPermanent(destTarget.getTargets().get(0)); + if (permanentDest == null) { + return false; + } + + if (permanentDamage1 != null) { + permanentDest.damage(permanentDamage1.getPower().getValue(), permanentDamage1.getId(), game, false, true); + } + if (permanentDamage2 != null) { + permanentDest.damage(permanentDamage2.getPower().getValue(), permanentDamage2.getId(), game, false, true); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java index 4527e5460a..6c7e3f8b9b 100644 --- a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java +++ b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java @@ -112,7 +112,7 @@ class BaneAlleyBrokerDrawExileEffect extends OneShotEffect { Card card = game.getCard(target.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); if (card != null && sourceObject != null) { - if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), new StringBuilder(sourceObject.getName()).toString(), source.getSourceId(), game)) { + if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceObject.getName(), source.getSourceId(), game)) { card.setFaceDown(true, game); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BaneOfBalaGed.java b/Mage.Sets/src/mage/cards/b/BaneOfBalaGed.java index 34c6ee3db4..7df9d2b0a3 100644 --- a/Mage.Sets/src/mage/cards/b/BaneOfBalaGed.java +++ b/Mage.Sets/src/mage/cards/b/BaneOfBalaGed.java @@ -2,8 +2,11 @@ package mage.cards.b; import java.util.HashSet; +import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.stream.Collectors; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -65,13 +68,10 @@ class BaneOfBalaGedEffect extends OneShotEffect { if (defendingPlayer != null) { Target target = new TargetControlledPermanent(2); defendingPlayer.chooseTarget(outcome, target, source, game); - Set toExile = new HashSet<>(); - target.getTargets().stream().map((targetId) - -> game.getPermanent(targetId)).filter((permanent) - -> (permanent != null)).forEach((permanent) - -> { - toExile.add(permanent); - }); + Set toExile = target.getTargets().stream() + .map(game::getPermanent) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); defendingPlayer.moveCards(toExile, Zone.EXILED, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java b/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java index e37a695bc9..a68033931f 100644 --- a/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java +++ b/Mage.Sets/src/mage/cards/b/BaneOfTheLiving.java @@ -32,7 +32,7 @@ public final class BaneOfTheLiving extends CardImpl { // Morph {X}{B}{B} this.addAbility(new MorphAbility(this, new ManaCostsImpl("{X}{B}{B}"))); // When Bane of the Living is turned face up, all creatures get -X/-X until end of turn. - DynamicValue morphX = new SignInversionDynamicValue(new MorphManacostVariableValue()); + DynamicValue morphX = new SignInversionDynamicValue(MorphManacostVariableValue.instance); this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new BoostAllEffect(morphX, morphX, Duration.EndOfTurn, new FilterCreaturePermanent("all creatures"), false, "", true))); } diff --git a/Mage.Sets/src/mage/cards/b/Banefire.java b/Mage.Sets/src/mage/cards/b/Banefire.java index 29d3a6a2fc..b74cddb4a9 100644 --- a/Mage.Sets/src/mage/cards/b/Banefire.java +++ b/Mage.Sets/src/mage/cards/b/Banefire.java @@ -106,7 +106,7 @@ class BaneFireEffect extends OneShotEffect { class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl { - Condition condition = new testCondition(new ManacostVariableValue(), 5); + Condition condition = new testCondition(ManacostVariableValue.instance, 5); public BanefireCantCounterEffect() { super(Duration.WhileOnStack, Outcome.Benefit); diff --git a/Mage.Sets/src/mage/cards/b/BanefulOmen.java b/Mage.Sets/src/mage/cards/b/BanefulOmen.java index 9643aacd05..7fc1edbecf 100644 --- a/Mage.Sets/src/mage/cards/b/BanefulOmen.java +++ b/Mage.Sets/src/mage/cards/b/BanefulOmen.java @@ -1,8 +1,6 @@ package mage.cards.b; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; @@ -15,15 +13,16 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; +import java.util.Set; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class BanefulOmen extends CardImpl { public BanefulOmen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{B}{B}"); // At the beginning of your end step, you may reveal the top card of your library. If you do, each opponent loses life equal to that card's converted mana cost. this.addAbility(new BanefulOmenTriggeredAbility()); @@ -40,11 +39,11 @@ public final class BanefulOmen extends CardImpl { class BanefulOmenTriggeredAbility extends TriggeredAbilityImpl { - public BanefulOmenTriggeredAbility() { + BanefulOmenTriggeredAbility() { super(Zone.BATTLEFIELD, new BanefulOmenEffect(), true); } - public BanefulOmenTriggeredAbility(BanefulOmenTriggeredAbility ability) { + private BanefulOmenTriggeredAbility(BanefulOmenTriggeredAbility ability) { super(ability); } @@ -71,11 +70,11 @@ public final class BanefulOmen extends CardImpl { static class BanefulOmenEffect extends OneShotEffect { - public BanefulOmenEffect() { + BanefulOmenEffect() { super(Outcome.Benefit); } - public BanefulOmenEffect(final BanefulOmenEffect effect) { + private BanefulOmenEffect(final BanefulOmenEffect effect) { super(effect); } @@ -85,24 +84,26 @@ public final class BanefulOmen extends CardImpl { if (player == null) { return false; } - if (player.getLibrary().hasCards()) { - Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Baneful Omen", cards, game); + if (!player.getLibrary().hasCards()) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + Cards cards = new CardsImpl(card); + player.revealCards("Baneful Omen", cards, game); - if (card != null) { - int loseLife = card.getConvertedManaCost(); - Set opponents = game.getOpponents(source.getControllerId()); - for (UUID opponentUuid : opponents) { - Player opponent = game.getPlayer(opponentUuid); - if (opponent != null) { - opponent.loseLife(loseLife, game, false); - } - } + + int loseLife = card.getConvertedManaCost(); + Set opponents = game.getOpponents(source.getControllerId()); + for (UUID opponentUuid : opponents) { + Player opponent = game.getPlayer(opponentUuid); + if (opponent != null) { + opponent.loseLife(loseLife, game, false); } } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/Banehound.java b/Mage.Sets/src/mage/cards/b/Banehound.java new file mode 100644 index 0000000000..493e33caa6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Banehound.java @@ -0,0 +1,41 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.keyword.HasteAbility; +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 Banehound extends CardImpl { + + public Banehound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.HOUND); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + } + + private Banehound(final Banehound card) { + super(card); + } + + @Override + public Banehound copy() { + return new Banehound(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BanisherPriest.java b/Mage.Sets/src/mage/cards/b/BanisherPriest.java index 8767e9754d..83b8c0fa0f 100644 --- a/Mage.Sets/src/mage/cards/b/BanisherPriest.java +++ b/Mage.Sets/src/mage/cards/b/BanisherPriest.java @@ -28,7 +28,7 @@ import mage.util.CardUtil; */ public final class BanisherPriest extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/b/BanishingLight.java b/Mage.Sets/src/mage/cards/b/BanishingLight.java index 56a3eed0ce..5383a01ccc 100644 --- a/Mage.Sets/src/mage/cards/b/BanishingLight.java +++ b/Mage.Sets/src/mage/cards/b/BanishingLight.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class BanishingLight extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/b/BankruptInBlood.java b/Mage.Sets/src/mage/cards/b/BankruptInBlood.java new file mode 100644 index 0000000000..f858051b67 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BankruptInBlood.java @@ -0,0 +1,35 @@ +package mage.cards.b; + +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BankruptInBlood extends CardImpl { + + public BankruptInBlood(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // As an additional cost to cast this spell, sacrifice two creatures. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(2))); + + // Draw three cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(3)); + } + + private BankruptInBlood(final BankruptInBlood card) { + super(card); + } + + @Override + public BankruptInBlood copy() { + return new BankruptInBlood(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Banshee.java b/Mage.Sets/src/mage/cards/b/Banshee.java index b2392191ad..3d0b460a5d 100644 --- a/Mage.Sets/src/mage/cards/b/Banshee.java +++ b/Mage.Sets/src/mage/cards/b/Banshee.java @@ -32,9 +32,9 @@ public final class Banshee extends CardImpl { this.toughness = new MageInt(1); // {X}, {T}: Banshee deals half X damage, rounded down, to any target, and half X damage, rounded up, to you. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new HalfValue(new ManacostVariableValue(), false)).setText("Banshee deals half X damage, rounded down, to any target,"), new ManaCostsImpl("{X}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new HalfValue(ManacostVariableValue.instance, false)).setText("Banshee deals half X damage, rounded down, to any target,"), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new DamageControllerEffect(new HalfValue(new ManacostVariableValue(), true)).setText(" and half X damage, rounded up, to you")); + ability.addEffect(new DamageControllerEffect(new HalfValue(ManacostVariableValue.instance, true)).setText(" and half X damage, rounded up, to you")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BantCharm.java b/Mage.Sets/src/mage/cards/b/BantCharm.java index ba94c016a8..5948547aa9 100644 --- a/Mage.Sets/src/mage/cards/b/BantCharm.java +++ b/Mage.Sets/src/mage/cards/b/BantCharm.java @@ -36,13 +36,13 @@ public final class BantCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // or put target creature on the bottom of its owner's library; Mode mode = new Mode(); - mode.getEffects().add(new PutOnLibraryTargetEffect(false)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new PutOnLibraryTargetEffect(false)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or counter target instant spell. mode = new Mode(); - mode.getEffects().add(new CounterTargetEffect()); - mode.getTargets().add(new TargetSpell(filter)); + mode.addEffect(new CounterTargetEffect()); + mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BantSureblade.java b/Mage.Sets/src/mage/cards/b/BantSureblade.java index 15c2410d1a..e39241c04e 100644 --- a/Mage.Sets/src/mage/cards/b/BantSureblade.java +++ b/Mage.Sets/src/mage/cards/b/BantSureblade.java @@ -29,8 +29,8 @@ public final class BantSureblade extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another multicolor permanent"); static { - filter.add(new MulticoloredPredicate()); - filter.add(new AnotherPredicate()); + filter.add(MulticoloredPredicate.instance); + filter.add(AnotherPredicate.instance); } public BantSureblade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BarbedLightning.java b/Mage.Sets/src/mage/cards/b/BarbedLightning.java index 53f94f504d..34bfa6646f 100644 --- a/Mage.Sets/src/mage/cards/b/BarbedLightning.java +++ b/Mage.Sets/src/mage/cards/b/BarbedLightning.java @@ -26,8 +26,8 @@ public final class BarbedLightning extends CardImpl { // or Barbed Lightning deals 3 damage to target player. Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(3)); - mode.getTargets().add(new TargetPlayerOrPlaneswalker()); + mode.addEffect(new DamageTargetEffect(3)); + mode.addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/b/Barishi.java b/Mage.Sets/src/mage/cards/b/Barishi.java index 41500213b9..41c85f15c7 100644 --- a/Mage.Sets/src/mage/cards/b/Barishi.java +++ b/Mage.Sets/src/mage/cards/b/Barishi.java @@ -67,8 +67,7 @@ class BarishiEffect extends OneShotEffect { if (controller == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + Cards cards = new CardsImpl(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); controller.putCardsOnTopOfLibrary(cards, game, source, false); controller.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/b/BaronSengir.java b/Mage.Sets/src/mage/cards/b/BaronSengir.java index f69bada8d5..41375fb1ce 100644 --- a/Mage.Sets/src/mage/cards/b/BaronSengir.java +++ b/Mage.Sets/src/mage/cards/b/BaronSengir.java @@ -32,7 +32,7 @@ public final class BaronSengir extends CardImpl { static { filter.add(new SubtypePredicate(SubType.VAMPIRE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BaronSengir(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BarrageOfBoulders.java b/Mage.Sets/src/mage/cards/b/BarrageOfBoulders.java index ccb1ae6068..df45e9b8d4 100644 --- a/Mage.Sets/src/mage/cards/b/BarrageOfBoulders.java +++ b/Mage.Sets/src/mage/cards/b/BarrageOfBoulders.java @@ -1,24 +1,25 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalRestrictionEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; + /** - * * @author LevelX2 */ public final class BarrageOfBoulders extends CardImpl { @@ -41,6 +42,7 @@ public final class BarrageOfBoulders extends CardImpl { new LockedInCondition(FerociousCondition.instance), null); effect.setText("
    Ferocious — If you control a creature with power 4 or greater, creatures can't block this turn"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addHint(FerociousHint.instance); } public BarrageOfBoulders(final BarrageOfBoulders card) { diff --git a/Mage.Sets/src/mage/cards/b/BarrageTyrant.java b/Mage.Sets/src/mage/cards/b/BarrageTyrant.java index 1c95a11f61..8f4b20d127 100644 --- a/Mage.Sets/src/mage/cards/b/BarrageTyrant.java +++ b/Mage.Sets/src/mage/cards/b/BarrageTyrant.java @@ -31,8 +31,8 @@ public final class BarrageTyrant extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public BarrageTyrant(UUID ownerId, CardSetInfo setInfo) { @@ -45,7 +45,7 @@ public final class BarrageTyrant extends CardImpl { this.addAbility(new DevoidAbility(this.color)); // {2}{R}, Sacrifice another colorless creature: Barrage Tyrant deals damage equal to the sacrificed creature's power to any target. - Effect effect = new DamageTargetEffect(new SacrificeCostCreaturesPower()); + Effect effect = new DamageTargetEffect(SacrificeCostCreaturesPower.instance); effect.setText("{this} deals damage equal to the sacrificed creature's power to any target"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{R}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); diff --git a/Mage.Sets/src/mage/cards/b/BarrenGlory.java b/Mage.Sets/src/mage/cards/b/BarrenGlory.java index 78113c6343..29ae7eb666 100644 --- a/Mage.Sets/src/mage/cards/b/BarrenGlory.java +++ b/Mage.Sets/src/mage/cards/b/BarrenGlory.java @@ -24,7 +24,7 @@ public final class BarrenGlory extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BarrenGlory(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BarrinsSpite.java b/Mage.Sets/src/mage/cards/b/BarrinsSpite.java index f1a97ff4d0..5eb3a9baf8 100644 --- a/Mage.Sets/src/mage/cards/b/BarrinsSpite.java +++ b/Mage.Sets/src/mage/cards/b/BarrinsSpite.java @@ -67,16 +67,18 @@ class BarrinsSpiteEffect extends OneShotEffect { Permanent creature = game.getPermanent(targetId); if (creature != null) { Player controllerOfCreature = game.getPlayer(creature.getControllerId()); - if ((count == 0 - && controllerOfCreature.chooseUse(Outcome.Sacrifice, "Sacrifice " + creature.getLogName() + '?', source, game)) - || (count == 1 - && !sacrificeDone)) { - creature.sacrifice(source.getId(), game); - sacrificeDone = true; - } else { - creature.moveToZone(Zone.HAND, source.getId(), game, false); + if(controllerOfCreature != null) { + if ((count == 0 + && controllerOfCreature.chooseUse(Outcome.Sacrifice, "Sacrifice " + creature.getLogName() + '?', source, game)) + || (count == 1 + && !sacrificeDone)) { + creature.sacrifice(source.getId(), game); + sacrificeDone = true; + } else { + creature.moveToZone(Zone.HAND, source.getId(), game, false); + } + count++; } - count++; } } return true; diff --git a/Mage.Sets/src/mage/cards/b/BartelRuneaxe.java b/Mage.Sets/src/mage/cards/b/BartelRuneaxe.java index a5ca949ea8..8c020d57cc 100644 --- a/Mage.Sets/src/mage/cards/b/BartelRuneaxe.java +++ b/Mage.Sets/src/mage/cards/b/BartelRuneaxe.java @@ -81,7 +81,7 @@ class BartelRuneaxeEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId()); + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (stackObject != null && event.getTargetId().equals(source.getSourceId())) { if (stackObject.hasSubtype(SubType.AURA, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/b/BaruFistOfKrosa.java b/Mage.Sets/src/mage/cards/b/BaruFistOfKrosa.java index 4ea8d13461..7cd9d78dcb 100644 --- a/Mage.Sets/src/mage/cards/b/BaruFistOfKrosa.java +++ b/Mage.Sets/src/mage/cards/b/BaruFistOfKrosa.java @@ -70,7 +70,7 @@ public final class BaruFistOfKrosa extends CardImpl { class BaruFistOfKrosaEffect extends OneShotEffect { - final static FilterControlledPermanent filter = new FilterControlledLandPermanent("lands you control"); + static final FilterControlledPermanent filter = new FilterControlledLandPermanent("lands you control"); BaruFistOfKrosaEffect() { super(Outcome.PutCreatureInPlay); diff --git a/Mage.Sets/src/mage/cards/b/BasilicaBellHaunt.java b/Mage.Sets/src/mage/cards/b/BasilicaBellHaunt.java new file mode 100644 index 0000000000..1fd9355939 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BasilicaBellHaunt.java @@ -0,0 +1,42 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BasilicaBellHaunt extends CardImpl { + + public BasilicaBellHaunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{B}{B}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When Basilica Bell-Haunt enters the battlefield, each opponent discards a card and you gain 3 life. + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect(TargetController.OPPONENT)); + ability.addEffect(new GainLifeEffect(3).setText("and you gain 3 life")); + this.addAbility(ability); + } + + private BasilicaBellHaunt(final BasilicaBellHaunt card) { + super(card); + } + + @Override + public BasilicaBellHaunt copy() { + return new BasilicaBellHaunt(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BastionProtector.java b/Mage.Sets/src/mage/cards/b/BastionProtector.java index 14844a9c4d..fa5054b1d9 100644 --- a/Mage.Sets/src/mage/cards/b/BastionProtector.java +++ b/Mage.Sets/src/mage/cards/b/BastionProtector.java @@ -24,10 +24,10 @@ import mage.filter.predicate.permanent.CommanderPredicate; */ public final class BastionProtector extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Commander creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Commander creatures"); static { - filter.add(new CommanderPredicate()); + filter.add(CommanderPredicate.instance); } public BastionProtector(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BattleAtTheBridge.java b/Mage.Sets/src/mage/cards/b/BattleAtTheBridge.java index b7d906149e..6aced560b8 100644 --- a/Mage.Sets/src/mage/cards/b/BattleAtTheBridge.java +++ b/Mage.Sets/src/mage/cards/b/BattleAtTheBridge.java @@ -27,10 +27,10 @@ public final class BattleAtTheBridge extends CardImpl { addAbility(new ImproviseAbility()); // Target creature gets -X/-X until end of turn. You gain X life. - DynamicValue x = new SignInversionDynamicValue(new ManacostVariableValue()); + DynamicValue x = new SignInversionDynamicValue(ManacostVariableValue.instance); this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new GainLifeEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance)); } public BattleAtTheBridge(final BattleAtTheBridge card) { diff --git a/Mage.Sets/src/mage/cards/b/BattleHymn.java b/Mage.Sets/src/mage/cards/b/BattleHymn.java index acb098f955..d1693a5748 100644 --- a/Mage.Sets/src/mage/cards/b/BattleHymn.java +++ b/Mage.Sets/src/mage/cards/b/BattleHymn.java @@ -1,17 +1,15 @@ - package mage.cards.b; -import java.util.UUID; import mage.Mana; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.mana.DynamicManaEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author North */ public final class BattleHymn extends CardImpl { @@ -20,7 +18,7 @@ public final class BattleHymn extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Add {R} for each creature you control. - this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE))); + this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CreaturesYouControlCount.instance)); } public BattleHymn(final BattleHymn card) { diff --git a/Mage.Sets/src/mage/cards/b/BattleScreech.java b/Mage.Sets/src/mage/cards/b/BattleScreech.java index 2fc92e6c6b..2a9f3d72cd 100644 --- a/Mage.Sets/src/mage/cards/b/BattleScreech.java +++ b/Mage.Sets/src/mage/cards/b/BattleScreech.java @@ -27,7 +27,7 @@ public final class BattleScreech extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public BattleScreech(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BattleSquadron.java b/Mage.Sets/src/mage/cards/b/BattleSquadron.java index 92964174fa..d5f534705d 100644 --- a/Mage.Sets/src/mage/cards/b/BattleSquadron.java +++ b/Mage.Sets/src/mage/cards/b/BattleSquadron.java @@ -1,11 +1,10 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,26 +12,26 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author fireshoes */ public final class BattleSquadron extends CardImpl { public BattleSquadron(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(0); this.toughness = new MageInt(0); // Flying this.addAbility(FlyingAbility.getInstance()); - + // Battle Squadron's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect( - new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); } public BattleSquadron(final BattleSquadron card) { diff --git a/Mage.Sets/src/mage/cards/b/BattlefieldPromotion.java b/Mage.Sets/src/mage/cards/b/BattlefieldPromotion.java new file mode 100644 index 0000000000..c86972f4c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BattlefieldPromotion.java @@ -0,0 +1,41 @@ +package mage.cards.b; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BattlefieldPromotion extends CardImpl { + + public BattlefieldPromotion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Put a +1/+1 counter on target creature. That creature gains first strike until end of turn. You gain 2 life. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("That creature gains first strike until end of turn.")); + this.getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private BattlefieldPromotion(final BattlefieldPromotion card) { + super(card); + } + + @Override + public BattlefieldPromotion copy() { + return new BattlefieldPromotion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java b/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java index 5b7a4e94bf..345086c7df 100644 --- a/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java +++ b/Mage.Sets/src/mage/cards/b/BattletideAlchemist.java @@ -2,6 +2,7 @@ package mage.cards.b; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -17,13 +18,12 @@ import mage.game.events.GameEvent.EventType; import mage.players.Player; /** - * * @author emerald000 */ public final class BattletideAlchemist extends CardImpl { public BattletideAlchemist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.KITHKIN, SubType.CLERIC); this.power = new MageInt(3); this.toughness = new MageInt(4); @@ -63,7 +63,7 @@ class BattletideAlchemistEffect extends PreventionEffectImpl { boolean result = false; Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(event.getTargetId()); - if (controller != null) { + if (controller != null && targetPlayer != null) { int numberOfClericsControlled = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent(SubType.CLERIC, "Clerics")).calculate(game, source, this); int toPrevent = Math.min(numberOfClericsControlled, event.getAmount()); if (toPrevent > 0 && controller.chooseUse(Outcome.PreventDamage, "Prevent " + toPrevent + " damage to " + targetPlayer.getName() + '?', source, game)) { @@ -71,20 +71,18 @@ class BattletideAlchemistEffect extends PreventionEffectImpl { if (!game.replaceEvent(preventEvent)) { if (event.getAmount() >= toPrevent) { event.setAmount(event.getAmount() - toPrevent); - } - else { + } else { event.setAmount(0); result = true; } - if (toPrevent > 0) { - game.informPlayers("Battletide Alchemist prevented " + toPrevent + " damage to " + targetPlayer.getName()); - game.fireEvent(GameEvent.getEvent( - GameEvent.EventType.PREVENTED_DAMAGE, - targetPlayer.getId(), - source.getSourceId(), - source.getControllerId(), - toPrevent)); - } + game.informPlayers("Battletide Alchemist prevented " + toPrevent + " damage to " + targetPlayer.getName()); + game.fireEvent(GameEvent.getEvent( + GameEvent.EventType.PREVENTED_DAMAGE, + targetPlayer.getId(), + source.getSourceId(), + source.getControllerId(), + toPrevent)); + } } } @@ -96,8 +94,4 @@ class BattletideAlchemistEffect extends PreventionEffectImpl { return event.getType() == EventType.DAMAGE_PLAYER; } - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - return super.applies(event, source, game); - } } diff --git a/Mage.Sets/src/mage/cards/b/BazaarKrovod.java b/Mage.Sets/src/mage/cards/b/BazaarKrovod.java index 672dcfb1ec..858ae9db6a 100644 --- a/Mage.Sets/src/mage/cards/b/BazaarKrovod.java +++ b/Mage.Sets/src/mage/cards/b/BazaarKrovod.java @@ -28,7 +28,7 @@ public final class BazaarKrovod extends CardImpl { static final FilterAttackingCreature filter = new FilterAttackingCreature("another target attacking creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BazaarKrovod(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java b/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java index f63d0ebc8a..542403fb70 100644 --- a/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java +++ b/Mage.Sets/src/mage/cards/b/BazaarOfWonders.java @@ -76,7 +76,7 @@ class BazaarOfWondersEffect extends OneShotEffect { String spellName = spell.getName(); FilterPermanent filter1 = new FilterPermanent(); filter1.add(new NamePredicate(spellName)); - filter1.add(Predicates.not(new TokenPredicate())); + filter1.add(Predicates.not(TokenPredicate.instance)); if (!game.getBattlefield().getActivePermanents(filter1, source.getControllerId(), game).isEmpty()) { spell.counter(source.getControllerId(), game); return true; diff --git a/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java b/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java index 0cd6c16ea0..30853e7e8b 100644 --- a/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java +++ b/Mage.Sets/src/mage/cards/b/BeamsplitterMage.java @@ -1,19 +1,19 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.OneShotEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -23,8 +23,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class BeamsplitterMage extends CardImpl { @@ -156,7 +157,7 @@ class BeamsplitterMageEffect extends OneShotEffect { if (usedTarget == null) { return false; } - FilterPermanent filter = new BeamsplitterMageFilter(usedTarget, source.getSourceId()); + FilterPermanent filter = new BeamsplitterMageFilter(usedTarget, source.getSourceId(), source.getControllerId()); Target target1 = new TargetPermanent(filter); target1.setNotTarget(true); if (controller.choose(outcome, target1, source.getSourceId(), game)) { @@ -199,10 +200,11 @@ class BeamsplitterMageFilter extends FilterControlledPermanent { private final Target target; private final UUID notId; - public BeamsplitterMageFilter(Target target, UUID notId) { + public BeamsplitterMageFilter(Target target, UUID notId, UUID controllerId) { super("creature this spell could target"); this.target = target; this.notId = notId; + this.add(new ControllerIdPredicate(controllerId)); } public BeamsplitterMageFilter(final BeamsplitterMageFilter filter) { diff --git a/Mage.Sets/src/mage/cards/b/BeastmastersMagemark.java b/Mage.Sets/src/mage/cards/b/BeastmastersMagemark.java index 98fd1d3bef..418c6e671a 100644 --- a/Mage.Sets/src/mage/cards/b/BeastmastersMagemark.java +++ b/Mage.Sets/src/mage/cards/b/BeastmastersMagemark.java @@ -29,7 +29,7 @@ public final class BeastmastersMagemark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control that are enchanted"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/b/BeastsOfBogardan.java b/Mage.Sets/src/mage/cards/b/BeastsOfBogardan.java index b9035891f6..0564015c88 100644 --- a/Mage.Sets/src/mage/cards/b/BeastsOfBogardan.java +++ b/Mage.Sets/src/mage/cards/b/BeastsOfBogardan.java @@ -30,7 +30,7 @@ public final class BeastsOfBogardan extends CardImpl { static { controlFilter.add(new ColorPredicate(ObjectColor.WHITE)); - controlFilter.add(Predicates.not(new TokenPredicate())); + controlFilter.add(Predicates.not(TokenPredicate.instance)); } public BeastsOfBogardan(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BeckonApparition.java b/Mage.Sets/src/mage/cards/b/BeckonApparition.java index 9df22c5d0b..0f22b77c30 100644 --- a/Mage.Sets/src/mage/cards/b/BeckonApparition.java +++ b/Mage.Sets/src/mage/cards/b/BeckonApparition.java @@ -1,15 +1,16 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.permanent.token.BeckonApparitionToken; +import mage.game.permanent.token.WhiteBlackSpiritToken; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** * @author Loki */ @@ -18,9 +19,10 @@ public final class BeckonApparition extends CardImpl { public BeckonApparition(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W/B}"); + // Exile target card from a graveyard. Create a 1/1 white and black Spirit creature token with flying. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); - this.getSpellAbility().addEffect(new CreateTokenEffect(new BeckonApparitionToken(), 1)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new WhiteBlackSpiritToken(), 1)); } public BeckonApparition(final BeckonApparition card) { diff --git a/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java b/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java new file mode 100644 index 0000000000..514dd6b598 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BedeckBedazzle.java @@ -0,0 +1,83 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetLandPermanent; +import mage.target.common.TargetOpponentOrPlaneswalker; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BedeckBedazzle extends SplitCard { + + public BedeckBedazzle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B/R}{B/R}", "{4}{B}{R}", SpellAbilityType.SPLIT); + + // Bedeck + // Target creature gets +3/-3 until end of turn. + this.getLeftHalfCard().getSpellAbility().addEffect( + new BoostTargetEffect(3, -3, Duration.EndOfTurn) + ); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Bedazzle + // Destroy target nonbasic land. Bedazzle deals 2 damage to target opponent or planeswalker. + this.getRightHalfCard().getSpellAbility().addEffect(new BedazzleEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetLandPermanent()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetOpponentOrPlaneswalker()); + } + + private BedeckBedazzle(final BedeckBedazzle card) { + super(card); + } + + @Override + public BedeckBedazzle copy() { + return new BedeckBedazzle(this); + } +} + +class BedazzleEffect extends OneShotEffect { + + BedazzleEffect() { + super(Outcome.Benefit); + staticText = "Destroy target nonbasic land. {this} deals 2 damage to target opponent or planeswalker."; + } + + private BedazzleEffect(final BedazzleEffect effect) { + super(effect); + } + + @Override + public BedazzleEffect copy() { + return new BedazzleEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } + Effect effect = new DamageTargetEffect(new StaticValue(2), true, "", true); + effect.setTargetPointer(new FixedTarget(source.getTargets().get(1).getFirstTarget(), game)); + effect.apply(game, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/Bedevil.java b/Mage.Sets/src/mage/cards/b/Bedevil.java new file mode 100644 index 0000000000..83e9390810 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Bedevil.java @@ -0,0 +1,45 @@ +package mage.cards.b; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Bedevil extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("artifact, creature, or planeswalker"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public Bedevil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}{R}"); + + // Destroy target artifact, creature, or planeswalker. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + public Bedevil(final Bedevil card) { + super(card); + } + + @Override + public Bedevil copy() { + return new Bedevil(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Bedlam.java b/Mage.Sets/src/mage/cards/b/Bedlam.java index 2e76947e5a..f305f65a97 100644 --- a/Mage.Sets/src/mage/cards/b/Bedlam.java +++ b/Mage.Sets/src/mage/cards/b/Bedlam.java @@ -2,9 +2,7 @@ package mage.cards.b; import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.combat.CantBlockAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -12,8 +10,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; -import mage.game.permanent.Permanent; /** * @@ -28,7 +24,7 @@ public final class Bedlam extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES, Duration.WhileOnBattlefield))); } - public Bedlam(final Bedlam card) { + private Bedlam(final Bedlam card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BeguilerOfWills.java b/Mage.Sets/src/mage/cards/b/BeguilerOfWills.java index ca8fd468ce..bda675f792 100644 --- a/Mage.Sets/src/mage/cards/b/BeguilerOfWills.java +++ b/Mage.Sets/src/mage/cards/b/BeguilerOfWills.java @@ -1,12 +1,11 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,14 +17,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author North */ public final class BeguilerOfWills extends CardImpl { public BeguilerOfWills(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.HUMAN, SubType.WIZARD); this.power = new MageInt(1); @@ -36,6 +36,7 @@ public final class BeguilerOfWills extends CardImpl { new GainControlTargetEffect(Duration.Custom), new TapSourceCost()); ability.addTarget(new BeguilerOfWillsTarget()); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BelbesArmor.java b/Mage.Sets/src/mage/cards/b/BelbesArmor.java index e1e54a3e32..d9cc57f6a2 100644 --- a/Mage.Sets/src/mage/cards/b/BelbesArmor.java +++ b/Mage.Sets/src/mage/cards/b/BelbesArmor.java @@ -29,8 +29,8 @@ public final class BelbesArmor extends CardImpl { Ability ability = new SimpleActivatedAbility( Zone.BATTLEFIELD, new BoostTargetEffect( - new MultipliedValue(new ManacostVariableValue(), -1), - new ManacostVariableValue(), + new MultipliedValue(ManacostVariableValue.instance, -1), + ManacostVariableValue.instance, Duration.EndOfTurn ), new ManaCostsImpl("{X}")); diff --git a/Mage.Sets/src/mage/cards/b/BelligerentBrontodon.java b/Mage.Sets/src/mage/cards/b/BelligerentBrontodon.java index a5de154190..e6243b73c8 100644 --- a/Mage.Sets/src/mage/cards/b/BelligerentBrontodon.java +++ b/Mage.Sets/src/mage/cards/b/BelligerentBrontodon.java @@ -1,21 +1,19 @@ package mage.cards.b; -import java.util.UUID; - import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class BelligerentBrontodon extends CardImpl { @@ -28,10 +26,10 @@ public final class BelligerentBrontodon extends CardImpl { this.toughness = new MageInt(6); // Each creature you control assigns combat damage equal to its toughness rather than its power. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BelligerentBrontodonCombatDamageRuleEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CombatDamageByToughnessEffect(StaticFilters.FILTER_PERMANENT_CREATURE, true))); } - public BelligerentBrontodon(final BelligerentBrontodon card) { + private BelligerentBrontodon(final BelligerentBrontodon card) { super(card); } @@ -40,40 +38,3 @@ public final class BelligerentBrontodon extends CardImpl { return new BelligerentBrontodon(this); } } - -class BelligerentBrontodonCombatDamageRuleEffect extends ContinuousEffectImpl { - - public BelligerentBrontodonCombatDamageRuleEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Each creature you control assigns combat damage equal to its toughness rather than its power"; - } - - public BelligerentBrontodonCombatDamageRuleEffect(final BelligerentBrontodonCombatDamageRuleEffect effect) { - super(effect); - } - - @Override - public BelligerentBrontodonCombatDamageRuleEffect copy() { - return new BelligerentBrontodonCombatDamageRuleEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - // Change the rule - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new ControllerIdPredicate(source.getControllerId())); - game.getCombat().setUseToughnessForDamage(true); - game.getCombat().addUseToughnessForDamageFilter(filter); - return true; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.RulesEffects; - } -} diff --git a/Mage.Sets/src/mage/cards/b/BellowingAegisaur.java b/Mage.Sets/src/mage/cards/b/BellowingAegisaur.java index e5942e94a5..e12a62d4bb 100644 --- a/Mage.Sets/src/mage/cards/b/BellowingAegisaur.java +++ b/Mage.Sets/src/mage/cards/b/BellowingAegisaur.java @@ -27,7 +27,7 @@ public final class BellowingAegisaur extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BellowingAegisaur(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BelltollDragon.java b/Mage.Sets/src/mage/cards/b/BelltollDragon.java index f2f6f73f80..1a0407c5ce 100644 --- a/Mage.Sets/src/mage/cards/b/BelltollDragon.java +++ b/Mage.Sets/src/mage/cards/b/BelltollDragon.java @@ -27,7 +27,7 @@ public final class BelltollDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other Dragon creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/b/BelltowerSphinx.java b/Mage.Sets/src/mage/cards/b/BelltowerSphinx.java index 5835f6115c..832d83f0d6 100644 --- a/Mage.Sets/src/mage/cards/b/BelltowerSphinx.java +++ b/Mage.Sets/src/mage/cards/b/BelltowerSphinx.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.dynamicvalue.common.StaticValue; @@ -18,19 +16,23 @@ import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * @author nantuko */ public final class BelltowerSphinx extends CardImpl { public BelltowerSphinx(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.SPHINX); this.power = new MageInt(2); this.toughness = new MageInt(5); + // Flying this.addAbility(FlyingAbility.getInstance()); + // Whenever a source deals damage to Belltower Sphinx, that source's controller puts that many cards from the top of their library into their graveyard. this.addAbility(new BelltowerSphinxEffect()); } diff --git a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java index c8b93e3272..a32d8b03f0 100644 --- a/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java +++ b/Mage.Sets/src/mage/cards/b/BenBenAkkiHermit.java @@ -30,7 +30,7 @@ public final class BenBenAkkiHermit extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("untapped Mountain you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.MOUNTAIN)); } diff --git a/Mage.Sets/src/mage/cards/b/BenalishMissionary.java b/Mage.Sets/src/mage/cards/b/BenalishMissionary.java index d0d4b011fe..952a930598 100644 --- a/Mage.Sets/src/mage/cards/b/BenalishMissionary.java +++ b/Mage.Sets/src/mage/cards/b/BenalishMissionary.java @@ -27,7 +27,7 @@ public final class BenalishMissionary extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocked creature"); static { - filter.add(new BlockedPredicate()); + filter.add(BlockedPredicate.instance); } public BenalishMissionary(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BendOrBreak.java b/Mage.Sets/src/mage/cards/b/BendOrBreak.java new file mode 100644 index 0000000000..19cd360d8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BendOrBreak.java @@ -0,0 +1,199 @@ + +package mage.cards.b; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPlayer; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.PlayerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.players.PlayerList; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author LevelX2 & L_J + */ +public final class BendOrBreak extends CardImpl { + + public BendOrBreak(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + + // Each player separates all nontoken lands they control into two piles. For each player, one of their piles is chosen by one of their opponents of their choice. Destroy all lands in the chosen piles. Tap all lands in the other piles. + this.getSpellAbility().addEffect(new BendOrBreakEffect()); + } + + public BendOrBreak(final BendOrBreak card) { + super(card); + } + + @Override + public BendOrBreak copy() { + return new BendOrBreak(this); + } +} + +class BendOrBreakEffect extends OneShotEffect { + + + public BendOrBreakEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Each player separates all nontoken lands they control into two piles. For each player, one of their piles is chosen by one of their opponents of their choice. Destroy all lands in the chosen piles. Tap all lands in the other piles"; + } + + public BendOrBreakEffect(final BendOrBreakEffect effect) { + super(effect); + } + + @Override + public BendOrBreakEffect copy() { + return new BendOrBreakEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + + // Map of players and their piles + Map>> playerPermanents = new LinkedHashMap<>(); + + PlayerList playerList = game.getState().getPlayerList().copy(); + while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) { + playerList.getNext(); + } + Player currentPlayer = game.getPlayer(playerList.get()); + Player nextPlayer; + UUID firstNextPlayer = null; + + while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) { + nextPlayer = game.getPlayer(playerList.get()); + if (nextPlayer == null) { + return false; + } + if (firstNextPlayer == null) { + firstNextPlayer = nextPlayer.getId(); + } + if (!nextPlayer.canRespond()) { + continue; + } + // Each player separates all nontoken lands they control into two piles + if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { + List firstPile = new ArrayList<>(); + List secondPile = new ArrayList<>(); + FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)"); + TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); + if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { + if (currentPlayer.chooseTarget(Outcome.Neutral, target, source, game)) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) { + if (target.getTargets().contains(permanent.getId())) { + firstPile.add(permanent); + } else { + secondPile.add(permanent); + } + } + } + + StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + } + List> playerPiles = new ArrayList<>(); + playerPiles.add(firstPile); + playerPiles.add(secondPile); + playerPermanents.put(currentPlayer.getId(), playerPiles); + } + currentPlayer = nextPlayer; + } + + // For each player, one of their piles is chosen by one of their opponents of their choice + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player != null) { + FilterPlayer filter = new FilterPlayer("opponent"); + List opponentPredicates = new ArrayList<>(); + for (UUID opponentId : game.getOpponents(player.getId())) { + opponentPredicates.add(new PlayerIdPredicate(opponentId)); + } + filter.add(Predicates.or(opponentPredicates)); + Target target = new TargetPlayer(1, 1, true, filter); + target.setTargetController(player.getId()); + target.setAbilityController(source.getControllerId()); + if (player.chooseTarget(outcome, target, source, game)) { + Player chosenOpponent = game.getPlayer(target.getFirstTarget()); + if (chosenOpponent != null) { + List firstPile = playerPiles.getValue().get(0); + List secondPile = playerPiles.getValue().get(1); + game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose his pile"); + if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(firstPile); + lists.add(secondPile); + game.informPlayers(player.getLogName() + " will have their first pile destroyed"); + } else { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(secondPile); + lists.add(firstPile); + game.informPlayers(player.getLogName() + " will have their second pile destroyed"); + } + } + } + } + } + // Destroy all lands in the chosen piles. Tap all lands in the other piles + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player != null) { + List pileToSac = playerPiles.getValue().get(0); + List pileToTap = playerPiles.getValue().get(1); + for (Permanent permanent : pileToSac) { + if (permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } + } + for (Permanent permanent : pileToTap) { + if (permanent != null) { + permanent.tap(game); + } + } + } + } + return true; + } + return false; + } + + private UUID getNextPlayerInDirection(boolean left, PlayerList playerList) { + UUID nextPlayerId; + if (left) { + nextPlayerId = playerList.getNext(); + } else { + nextPlayerId = playerList.getPrevious(); + } + return nextPlayerId; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java b/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java index c0a55c2a66..39cab57d3c 100644 --- a/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java +++ b/Mage.Sets/src/mage/cards/b/BenefactionOfRhonas.java @@ -63,8 +63,7 @@ class BenefactionOfRhonasEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); boolean creatureCardFound = false; boolean enchantmentCardFound = false; for (UUID cardId : cards) { diff --git a/Mage.Sets/src/mage/cards/b/BenevolentUnicorn.java b/Mage.Sets/src/mage/cards/b/BenevolentUnicorn.java new file mode 100644 index 0000000000..c2297b646c --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BenevolentUnicorn.java @@ -0,0 +1,91 @@ + +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.game.stack.StackObject; + +/** + * + * @author LoneFox, Ketsuban + + */ +public final class BenevolentUnicorn extends CardImpl { + + public BenevolentUnicorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + this.subtype.add(SubType.UNICORN); + + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // If a spell would deal damage to a permanent or player, it deals that much damage minus 1 to that permanent or player instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BenevolentUnicornEffect())); + } + + public BenevolentUnicorn(final BenevolentUnicorn card) { + super(card); + } + + @Override + public BenevolentUnicorn copy() { + return new BenevolentUnicorn(this); + } +} + +class BenevolentUnicornEffect extends ReplacementEffectImpl { + + public BenevolentUnicornEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a spell would deal damage to a permanent or player, it deals that much damage minus 1 to that permanent or player instead."; + } + + public BenevolentUnicornEffect(final BenevolentUnicornEffect effect) { + super(effect); + } + + @Override + public BenevolentUnicornEffect copy() { + return new BenevolentUnicornEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(event.getAmount() - 1); + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.DAMAGE_CREATURE || event.getType() == EventType.DAMAGE_PLANESWALKER || event.getType() == EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + if (stackObject == null) { + stackObject = (StackObject) game.getLastKnownInformation(event.getSourceId(), Zone.STACK); + } + return stackObject instanceof Spell; + } + +} diff --git a/Mage.Sets/src/mage/cards/b/BenthicBiomancer.java b/Mage.Sets/src/mage/cards/b/BenthicBiomancer.java new file mode 100644 index 0000000000..54e0b622c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BenthicBiomancer.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.OneOrMoreCountersAddedTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.keyword.AdaptAbility; +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 BenthicBiomancer extends CardImpl { + + public BenthicBiomancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{U}: Adapt 1. + this.addAbility(new AdaptAbility(1, "{1}{U}")); + + // Whenever one or more +1/+1 counters are put on Benthic Biomancer, draw a card, then discard a card. + Ability ability = new OneOrMoreCountersAddedTriggeredAbility(new DrawCardSourceControllerEffect(1)); + ability.addEffect(new DiscardControllerEffect(1).setText(", then discard a card")); + this.addAbility(ability); + } + + private BenthicBiomancer(final BenthicBiomancer card) { + super(card); + } + + @Override + public BenthicBiomancer copy() { + return new BenthicBiomancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BenthicExplorers.java b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java new file mode 100644 index 0000000000..0760baeed8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java @@ -0,0 +1,262 @@ +package mage.cards.b; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.Mana; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetLandPermanent; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public final class BenthicExplorers extends CardImpl { + + private static final FilterLandPermanent filter = new FilterLandPermanent("tapped land an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + filter.add(TappedPredicate.instance); + } + + public BenthicExplorers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {tap}, Untap a tapped land an opponent controls: Add one mana of any type that land could produce. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BenthicExplorersManaEffect(), new TapSourceCost()); + ability.addCost(new BenthicExplorersCost(new TargetLandPermanent(filter))); + this.addAbility(ability); + + } + + private BenthicExplorers(final BenthicExplorers card) { + super(card); + } + + @Override + public BenthicExplorers copy() { + return new BenthicExplorers(this); + } +} + +class BenthicExplorersCost extends CostImpl { + + TargetLandPermanent target; + + public BenthicExplorersCost(TargetLandPermanent target) { + this.target = target; + this.text = "Untap " + CardUtil.numberToText(target.getMaxNumberOfTargets(), "") + ' ' + target.getTargetName(); + } + + public BenthicExplorersCost(final BenthicExplorersCost cost) { + super(cost); + this.target = cost.target.copy(); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + if (target.choose(Outcome.Untap, controllerId, sourceId, game)) { + for (UUID targetId : (List) target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + return false; + } + paid |= permanent.untap(game); + if (paid) { + game.getState().setValue("UntapTargetCost" + ability.getSourceId().toString(), permanent); // remember the untapped permanent + } + } + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return target.canChoose(controllerId, game); + } + + @Override + public BenthicExplorersCost copy() { + return new BenthicExplorersCost(this); + } + +} + +class BenthicExplorersManaEffect extends ManaEffect { + + public BenthicExplorersManaEffect() { + staticText = "Add one mana of any type that land could produce"; + } + + private BenthicExplorersManaEffect(final BenthicExplorersManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + //List mana = getNetMana(game, source); + Mana manaToProduce = produceMana(true, game, source); + controller.getManaPool().addMana(manaToProduce, game, source); + return true; + } + return false; + } + + @Override + public Mana produceMana(boolean netMana, Game game, Ability source) { + Mana mana = new Mana(); + Mana types = getManaTypes(game, source); + Choice choice = new ChoiceColor(true); + choice.getChoices().clear(); + choice.setMessage("Pick a mana color"); + if (types.getBlack() > 0) { + choice.getChoices().add("Black"); + } + if (types.getRed() > 0) { + choice.getChoices().add("Red"); + } + if (types.getBlue() > 0) { + choice.getChoices().add("Blue"); + } + if (types.getGreen() > 0) { + choice.getChoices().add("Green"); + } + if (types.getWhite() > 0) { + choice.getChoices().add("White"); + } + if (types.getColorless() > 0) { + choice.getChoices().add("Colorless"); + } + if (types.getAny() > 0) { + choice.getChoices().add("Black"); + choice.getChoices().add("Red"); + choice.getChoices().add("Blue"); + choice.getChoices().add("Green"); + choice.getChoices().add("White"); + choice.getChoices().add("Colorless"); + + } + if (!choice.getChoices().isEmpty()) { + Player player = game.getPlayer(source.getControllerId()); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else { + if (player == null + || !player.choose(Outcome.Neutral, choice, game)) { + return null; + } + } + if (choice.getChoice() != null) { + switch (choice.getChoice()) { + case "Black": + mana.setBlack(1); + break; + case "Blue": + mana.setBlue(1); + break; + case "Red": + mana.setRed(1); + break; + case "Green": + mana.setGreen(1); + break; + case "White": + mana.setWhite(1); + break; + case "Colorless": + mana.setColorless(1); + break; + } + } + } + return mana; + } + + private Mana getManaTypes(Game game, Ability source) { + Mana types = new Mana(); + if (game == null + || game.getPhase() == null) { + return types; + } + Permanent land = (Permanent) game.getState().getValue("UntapTargetCost" + source.getSourceId().toString()); + if (land != null) { + System.out.println("The land is " + land.getName()); + Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); + for (ActivatedManaAbilityImpl ability : mana) { + if (ability.definesMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { + types.add(netMana); + } + } + } + } + System.out.println("The types : " + types.toString()); + return types; + } + + @Override + public List getNetMana(Game game, Ability source) { + List netManas = new ArrayList<>(); + Mana types = getManaTypes(game, source); + if (types.getBlack() > 0) { + netManas.add(new Mana(ColoredManaSymbol.B)); + } + if (types.getRed() > 0) { + netManas.add(new Mana(ColoredManaSymbol.R)); + } + if (types.getBlue() > 0) { + netManas.add(new Mana(ColoredManaSymbol.U)); + } + if (types.getGreen() > 0) { + netManas.add(new Mana(ColoredManaSymbol.G)); + } + if (types.getWhite() > 0) { + netManas.add(new Mana(ColoredManaSymbol.W)); + } + if (types.getColorless() > 0) { + netManas.add(Mana.ColorlessMana(1)); + } + if (types.getAny() > 0) { + netManas.add(Mana.AnyMana(1)); + } + return netManas; + } + + @Override + public BenthicExplorersManaEffect copy() { + return new BenthicExplorersManaEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Benthicore.java b/Mage.Sets/src/mage/cards/b/Benthicore.java index 9ca093b861..48424e9d86 100644 --- a/Mage.Sets/src/mage/cards/b/Benthicore.java +++ b/Mage.Sets/src/mage/cards/b/Benthicore.java @@ -33,7 +33,7 @@ public final class Benthicore extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Merfolk you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.MERFOLK)); } diff --git a/Mage.Sets/src/mage/cards/b/Berserk.java b/Mage.Sets/src/mage/cards/b/Berserk.java index 3d38da94d8..4a5cbc6440 100644 --- a/Mage.Sets/src/mage/cards/b/Berserk.java +++ b/Mage.Sets/src/mage/cards/b/Berserk.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -26,8 +25,9 @@ import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; import mage.watchers.common.AttackedThisTurnWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Berserk extends CardImpl { @@ -43,7 +43,7 @@ public final class Berserk extends CardImpl { Effect effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains trample"); this.getSpellAbility().addEffect(effect); - effect = new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true); + effect = new BoostTargetEffect(TargetPermanentPowerCount.instance, new StaticValue(0), Duration.EndOfTurn, true); effect.setText("and gets +X/+0 until end of turn, where X is its power"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new BerserkDestroyEffect()); @@ -76,7 +76,7 @@ class BerserkReplacementEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getSourceId().equals(source.getSourceId())) { - CombatDamageStepStartedWatcher watcher = (CombatDamageStepStartedWatcher) game.getState().getWatchers().get(CombatDamageStepStartedWatcher.class.getSimpleName()); + CombatDamageStepStartedWatcher watcher = game.getState().getWatcher(CombatDamageStepStartedWatcher.class); return watcher == null || watcher.conditionMet(); } return false; @@ -96,7 +96,7 @@ class BerserkReplacementEffect extends ContinuousRuleModifyingEffectImpl { class CombatDamageStepStartedWatcher extends Watcher { public CombatDamageStepStartedWatcher() { - super(CombatDamageStepStartedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CombatDamageStepStartedWatcher(final CombatDamageStepStartedWatcher watcher) { @@ -170,11 +170,9 @@ class BerserkDelayedDestroyEffect extends OneShotEffect { if (controller != null) { Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (permanent != null) { - Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher instanceof AttackedThisTurnWatcher) { - if (((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { - return permanent.destroy(source.getSourceId(), game, false); - } + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + if (watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { + return permanent.destroy(source.getSourceId(), game, false); } } } diff --git a/Mage.Sets/src/mage/cards/b/Betrayal.java b/Mage.Sets/src/mage/cards/b/Betrayal.java index 46d61656e4..89f60dd1d1 100644 --- a/Mage.Sets/src/mage/cards/b/Betrayal.java +++ b/Mage.Sets/src/mage/cards/b/Betrayal.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BecomesTappedAttachedTriggeredAbility; import mage.abilities.effects.common.AttachEffect; @@ -18,8 +16,9 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class Betrayal extends CardImpl { @@ -31,7 +30,7 @@ public final class Betrayal extends CardImpl { } public Betrayal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); this.subtype.add(SubType.AURA); // Enchant creature an opponent controls @@ -40,8 +39,9 @@ public final class Betrayal extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Whenever enchanted creature becomes tapped, you draw a card. - this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DrawCardSourceControllerEffect(1), "enchanted creature")); + this.addAbility(new BecomesTappedAttachedTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), "enchanted creature")); } public Betrayal(final Betrayal card) { diff --git a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java index b2c9ae65ab..960d4b9018 100644 --- a/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java +++ b/Mage.Sets/src/mage/cards/b/BetrayalOfFlesh.java @@ -34,8 +34,8 @@ public final class BetrayalOfFlesh extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or return target creature card from your graveyard to the battlefield. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + mode.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); // Entwine-Sacrifice three lands. this.addAbility(new EntwineAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, new FilterControlledLandPermanent("three lands"), true)))); diff --git a/Mage.Sets/src/mage/cards/b/BetrothedOfFire.java b/Mage.Sets/src/mage/cards/b/BetrothedOfFire.java new file mode 100644 index 0000000000..bb4ac7ecfb --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BetrothedOfFire.java @@ -0,0 +1,71 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeAttachedCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BetrothedOfFire extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("an untapped creature"); + + static { + filter.add(Predicates.not(TappedPredicate.instance)); + } + + public BetrothedOfFire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Sacrifice an untapped creature: Enchanted creature gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostEnchantedEffect(2, 0, Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + )); + + // Sacrifice enchanted creature: Creatures you control get +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostControlledEffect(2, 0, Duration.EndOfTurn), + new SacrificeAttachedCost() + )); + } + + public BetrothedOfFire(final BetrothedOfFire card) { + super(card); + } + + @Override + public BetrothedOfFire copy() { + return new BetrothedOfFire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Bifurcate.java b/Mage.Sets/src/mage/cards/b/Bifurcate.java index 4faba2a260..397ab59792 100644 --- a/Mage.Sets/src/mage/cards/b/Bifurcate.java +++ b/Mage.Sets/src/mage/cards/b/Bifurcate.java @@ -29,7 +29,7 @@ public final class Bifurcate extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creatures"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public Bifurcate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BileBlight.java b/Mage.Sets/src/mage/cards/b/BileBlight.java index 64440f8042..0b23756190 100644 --- a/Mage.Sets/src/mage/cards/b/BileBlight.java +++ b/Mage.Sets/src/mage/cards/b/BileBlight.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -12,15 +10,17 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron */ public final class BileBlight extends CardImpl { public BileBlight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); // Target creature and all creatures with the same name as that creature get -3/-3 until end of turn. @@ -56,12 +56,12 @@ class BileBlightEffect extends BoostAllEffect { if (this.affectedObjectsSet) { Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); if (target != null) { - if (target.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(target)) { // face down creature affectedObjectList.add(new MageObjectReference(target, game)); } else { String name = target.getName(); for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (perm.getName().equals(name)) { + if (CardUtil.haveSameNames(perm.getName(), name)) { affectedObjectList.add(new MageObjectReference(perm, game)); } } diff --git a/Mage.Sets/src/mage/cards/b/BindingMummy.java b/Mage.Sets/src/mage/cards/b/BindingMummy.java index 7ebaf19338..69217bf9a9 100644 --- a/Mage.Sets/src/mage/cards/b/BindingMummy.java +++ b/Mage.Sets/src/mage/cards/b/BindingMummy.java @@ -26,7 +26,7 @@ public final class BindingMummy extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Zombie"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ZOMBIE)); } diff --git a/Mage.Sets/src/mage/cards/b/BioessenceHydra.java b/Mage.Sets/src/mage/cards/b/BioessenceHydra.java new file mode 100644 index 0000000000..2d591b829f --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BioessenceHydra.java @@ -0,0 +1,130 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BioessenceHydra extends CardImpl { + + public BioessenceHydra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{U}"); + + this.subtype.add(SubType.HYDRA); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Bioessence Hydra enters the battlefield with a +1/+1 counter on it for each loyalty counter on planeswalkers you control. + this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance(), BioessenceHydraDynamicValue.instance, true + ), "with a +1/+1 counter on it for each loyalty counter on planeswalkers you control." + )); + + // Whenever one or more loyalty counters are put on planeswalkers you control, put that many +1/+1 counters on Bioessence Hydra. + this.addAbility(new BioessenceHydraTriggeredAbility()); + } + + private BioessenceHydra(final BioessenceHydra card) { + super(card); + } + + @Override + public BioessenceHydra copy() { + return new BioessenceHydra(this); + } +} + +enum BioessenceHydraDynamicValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int counter = 0; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_PLANESWALKER, sourceAbility.getControllerId(), game + )) { + if (permanent != null) { + counter += permanent.getCounters(game).getCount(CounterType.LOYALTY); + } + } + return counter; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} + +class BioessenceHydraTriggeredAbility extends TriggeredAbilityImpl { + + BioessenceHydraTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); + } + + private BioessenceHydraTriggeredAbility(final BioessenceHydraTriggeredAbility ability) { + super(ability); + } + + @Override + public BioessenceHydraTriggeredAbility copy() { + return new BioessenceHydraTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COUNTERS_ADDED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getData().equals(CounterType.LOYALTY.getName()) && event.getAmount() > 0) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null + && !event.getTargetId().equals(this.getSourceId()) + && permanent.isPlaneswalker() + && permanent.isControlledBy(this.getControllerId())) { + this.getEffects().clear(); + this.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(event.getAmount()))); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever one or more loyalty counters are put on a planeswalker you control, put that many +1/+1 counters on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BiogenicOoze.java b/Mage.Sets/src/mage/cards/b/BiogenicOoze.java new file mode 100644 index 0000000000..7f6d1b87f4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BiogenicOoze.java @@ -0,0 +1,67 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.permanent.token.BiogenicOozeToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BiogenicOoze extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent("Ooze you control"); + + static { + filter.add(new SubtypePredicate(SubType.OOZE)); + } + + public BiogenicOoze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.subtype.add(SubType.OOZE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Biogenic Ooze enters the battlefield, create a 2/2 green Ooze creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new BiogenicOozeToken()) + )); + + // At the beginning if your end step, put a +1/+1 counter on each Ooze you control. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), + TargetController.YOU, false + )); + + // {1}{G}{G}{G}: Create a 2/2 green Ooze creature token. + this.addAbility(new SimpleActivatedAbility( + new CreateTokenEffect(new BiogenicOozeToken()), + new ManaCostsImpl("{1}{G}{G}{G}") + )); + } + + private BiogenicOoze(final BiogenicOoze card) { + super(card); + } + + @Override + public BiogenicOoze copy() { + return new BiogenicOoze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BiogenicUpgrade.java b/Mage.Sets/src/mage/cards/b/BiogenicUpgrade.java new file mode 100644 index 0000000000..8d0622f6e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BiogenicUpgrade.java @@ -0,0 +1,78 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.DistributeCountersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanentAmount; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BiogenicUpgrade extends CardImpl { + + public BiogenicUpgrade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); + + // Distribute three +1/+1 counters among one, two, or three target creatures, then double the number of +1/+1 counters on each of those creatures. + this.getSpellAbility().addEffect(new DistributeCountersEffect( + CounterType.P1P1, 3, false, + "one, two, or three target creatures" + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(3)); + this.getSpellAbility().addEffect(new BiogenicUpgradeEffect()); + } + + private BiogenicUpgrade(final BiogenicUpgrade card) { + super(card); + } + + @Override + public BiogenicUpgrade copy() { + return new BiogenicUpgrade(this); + } +} + +class BiogenicUpgradeEffect extends OneShotEffect { + + BiogenicUpgradeEffect() { + super(Outcome.Benefit); + staticText = ", then double the number of +1/+1 counters on each of those creatures."; + } + + private BiogenicUpgradeEffect(final BiogenicUpgradeEffect effect) { + super(effect); + } + + @Override + public BiogenicUpgradeEffect copy() { + return new BiogenicUpgradeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID permanentId : source.getTargets().get(0).getTargets()) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent == null) { + continue; + } + Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance( + permanent.getCounters(game).getCount(CounterType.P1P1) + )); + effect.setTargetPointer(new FixedTarget(permanent, game)); + effect.apply(game, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java b/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java new file mode 100644 index 0000000000..99f4667c1a --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BiomancersFamiliar.java @@ -0,0 +1,159 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BiomancersFamiliar extends CardImpl { + + public BiomancersFamiliar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Activated abilities of creatures you control cost {2} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BiomancersFamiliarCostReductionEffect())); + + // {T}: The next time target creature adapts this turn, it adapts as though it had no +1/+1 counters on it. + Ability ability = new SimpleActivatedAbility( + new BiomancersFamiliarReplacementEffect(), new TapSourceCost() + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private BiomancersFamiliar(final BiomancersFamiliar card) { + super(card); + } + + @Override + public BiomancersFamiliar copy() { + return new BiomancersFamiliar(this); + } +} + +class BiomancersFamiliarCostReductionEffect extends CostModificationEffectImpl { + + private static final String effectText = "Activated abilities of creatures you control cost {2} less to activate. " + + "This effect can't reduce the amount of mana an ability costs to activate to less than one mana"; + + BiomancersFamiliarCostReductionEffect() { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = effectText; + } + + private BiomancersFamiliarCostReductionEffect(final BiomancersFamiliarCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player controller = game.getPlayer(abilityToModify.getControllerId()); + if (controller != null) { + Mana mana = abilityToModify.getManaCostsToPay().getMana(); + int reduceMax = mana.getGeneric(); + if (reduceMax > 0 && mana.count() == mana.getGeneric()) { + reduceMax--; + } + if (reduceMax > 2) { + reduceMax = 2; + } + if (reduceMax > 0) { + ChoiceImpl choice = new ChoiceImpl(true); + Set set = new LinkedHashSet<>(); + + for (int i = 0; i <= reduceMax; i++) { + set.add(String.valueOf(i)); + } + choice.setChoices(set); + choice.setMessage("Reduce ability cost"); + if (!controller.choose(Outcome.Benefit, choice, game)) { + return false; + } + int reduce = Integer.parseInt(choice.getChoice()); + CardUtil.reduceCost(abilityToModify, reduce); + } + return true; + } + + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED + || (abilityToModify.getAbilityType() == AbilityType.MANA && abilityToModify instanceof ActivatedAbility)) { + //Activated abilities of creatures you control + Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); + if (permanent != null && permanent.isCreature() && permanent.isControlledBy(source.getControllerId())) { + return true; + } + } + return false; + } + + @Override + public BiomancersFamiliarCostReductionEffect copy() { + return new BiomancersFamiliarCostReductionEffect(this); + } +} + +class BiomancersFamiliarReplacementEffect extends ReplacementEffectImpl { + + BiomancersFamiliarReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Benefit); + staticText = "The next time target creature adapts this turn, " + + "it adapts as though it had no +1/+1 counters on it."; + } + + private BiomancersFamiliarReplacementEffect(final BiomancersFamiliarReplacementEffect effect) { + super(effect); + } + + @Override + public BiomancersFamiliarReplacementEffect copy() { + return new BiomancersFamiliarReplacementEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ADAPT; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(targetPointer.getFirst(game, source)); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setFlag(true); + discard(); + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BiomassMutation.java b/Mage.Sets/src/mage/cards/b/BiomassMutation.java index eaf5268466..cbd6af3407 100644 --- a/Mage.Sets/src/mage/cards/b/BiomassMutation.java +++ b/Mage.Sets/src/mage/cards/b/BiomassMutation.java @@ -22,7 +22,7 @@ public final class BiomassMutation extends CardImpl { // Creatures you control have base power and toughness X/X until end of turn. - DynamicValue variableMana = new ManacostVariableValue(); + DynamicValue variableMana = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new SetPowerToughnessAllEffect(variableMana, variableMana, Duration.EndOfTurn, new FilterControlledCreaturePermanent("Creatures you control"), true)); } diff --git a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java index c6ff1dbc10..749f216e29 100644 --- a/Mage.Sets/src/mage/cards/b/BirchloreRangers.java +++ b/Mage.Sets/src/mage/cards/b/BirchloreRangers.java @@ -26,7 +26,7 @@ public final class BirchloreRangers extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Elves you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/b/BirthingPod.java b/Mage.Sets/src/mage/cards/b/BirthingPod.java index 2242e3886d..76a8df1d7d 100644 --- a/Mage.Sets/src/mage/cards/b/BirthingPod.java +++ b/Mage.Sets/src/mage/cards/b/BirthingPod.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.Cost; @@ -17,7 +16,7 @@ import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; +import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; @@ -26,6 +25,8 @@ import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** * @author Loki */ @@ -36,9 +37,13 @@ public final class BirthingPod extends CardImpl { // {1}{G/P}, {tap}, Sacrifice a creature: Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, // put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. - Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new BirthingPodEffect(), new ManaCostsImpl("{1}{G/P}")); + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new BirthingPodEffect(), new ManaCostsImpl("{1}{G/P}") + ); ability.addCost(new TapSourceCost()); - ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent( + StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT + ))); this.addAbility(ability); } @@ -56,11 +61,12 @@ class BirthingPodEffect extends OneShotEffect { BirthingPodEffect() { super(Outcome.Benefit); - staticText = "Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card " - + "onto the battlefield, then shuffle your library"; + staticText = "Search your library for a creature card with converted mana cost equal to 1 " + + "plus the sacrificed creature's converted mana cost, put that card " + + "onto the battlefield, then shuffle your library"; } - BirthingPodEffect(final BirthingPodEffect effect) { + private BirthingPodEffect(final BirthingPodEffect effect) { super(effect); } @@ -77,20 +83,20 @@ class BirthingPodEffect extends OneShotEffect { } } Player controller = game.getPlayer(source.getControllerId()); - if (sacrificedPermanent != null && controller != null) { - int newConvertedCost = sacrificedPermanent.getConvertedManaCost() + 1; - FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, newConvertedCost)); - filter.add(new CardTypePredicate(CardType.CREATURE)); - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { - Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - } - controller.shuffleLibrary(source, game); - return true; + if (sacrificedPermanent == null || controller == null) { + return false; } - return false; + int newConvertedCost = sacrificedPermanent.getConvertedManaCost() + 1; + FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, newConvertedCost)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + if (controller.searchLibrary(target, source, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + controller.shuffleLibrary(source, game); + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java index ac53b0111a..9b1fccfe48 100644 --- a/Mage.Sets/src/mage/cards/b/BishopOfBinding.java +++ b/Mage.Sets/src/mage/cards/b/BishopOfBinding.java @@ -35,7 +35,7 @@ import mage.util.CardUtil; */ public final class BishopOfBinding extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/b/BitterOrdeal.java b/Mage.Sets/src/mage/cards/b/BitterOrdeal.java index 1611148bff..7a0fd7d729 100644 --- a/Mage.Sets/src/mage/cards/b/BitterOrdeal.java +++ b/Mage.Sets/src/mage/cards/b/BitterOrdeal.java @@ -66,7 +66,7 @@ class BitterOrdealEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && targetPlayer != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (controller.searchLibrary(target, game, targetPlayer.getId())) { + if (controller.searchLibrary(target, source, game, targetPlayer.getId())) { Card card = targetPlayer.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, Zone.LIBRARY, true); diff --git a/Mage.Sets/src/mage/cards/b/BitterheartWitch.java b/Mage.Sets/src/mage/cards/b/BitterheartWitch.java index b3158adf6e..c010a92f29 100644 --- a/Mage.Sets/src/mage/cards/b/BitterheartWitch.java +++ b/Mage.Sets/src/mage/cards/b/BitterheartWitch.java @@ -76,7 +76,7 @@ class BitterheartWitchEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(source.getFirstTarget()); if (controller != null && targetPlayer != null) { TargetCardInLibrary targetCard = new TargetCardInLibrary(filter); - if (controller.searchLibrary(targetCard, game)) { + if (controller.searchLibrary(targetCard, source, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { game.getState().setValue("attachTo:" + card.getId(), targetPlayer.getId()); diff --git a/Mage.Sets/src/mage/cards/b/BlackManaBattery.java b/Mage.Sets/src/mage/cards/b/BlackManaBattery.java index 2423fc449b..0aa099282e 100644 --- a/Mage.Sets/src/mage/cards/b/BlackManaBattery.java +++ b/Mage.Sets/src/mage/cards/b/BlackManaBattery.java @@ -36,7 +36,7 @@ public final class BlackManaBattery extends CardImpl { // {tap}, Remove any number of charge counters from Black Mana Battery: Add {B}, then add an additional {B} for each charge counter removed this way. ability = new DynamicManaAbility( Mana.BlackMana(1), - new IntPlusDynamicValue(1, new RemovedCountersForCostValue()), + new IntPlusDynamicValue(1, RemovedCountersForCostValue.instance), new TapSourceCost(), "Add {B}, then add {B} for each charge counter removed this way", true, new CountersSourceCount(CounterType.CHARGE)); diff --git a/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java b/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java index c27c99be18..22ef04c463 100644 --- a/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java +++ b/Mage.Sets/src/mage/cards/b/BlackOakOfOdunos.java @@ -30,8 +30,8 @@ public final class BlackOakOfOdunos extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another untapped creature you control"); static { - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TappedPredicate.instance)); } public BlackOakOfOdunos(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BladeJuggler.java b/Mage.Sets/src/mage/cards/b/BladeJuggler.java new file mode 100644 index 0000000000..a9c5e82aee --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BladeJuggler.java @@ -0,0 +1,49 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.SpectacleAbility; +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 BladeJuggler extends CardImpl { + + public BladeJuggler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Spectacle {2}{B} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{2}{B}"))); + + // When Blade Juggler enters the battlefield, it deals 1 damage to you and you draw a card. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageControllerEffect(1, "it") + ); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and you draw a card")); + this.addAbility(ability); + } + + private BladeJuggler(final BladeJuggler card) { + super(card); + } + + @Override + public BladeJuggler copy() { + return new BladeJuggler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/Bladebrand.java b/Mage.Sets/src/mage/cards/b/Bladebrand.java new file mode 100644 index 0000000000..472d4cc809 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Bladebrand.java @@ -0,0 +1,40 @@ +package mage.cards.b; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +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 Bladebrand extends CardImpl { + + public Bladebrand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Target creature gains deathtouch until end of turn. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private Bladebrand(final Bladebrand card) { + super(card); + } + + @Override + public Bladebrand copy() { + return new Bladebrand(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BladewingsThrall.java b/Mage.Sets/src/mage/cards/b/BladewingsThrall.java index f9de91df98..bac7f52f71 100644 --- a/Mage.Sets/src/mage/cards/b/BladewingsThrall.java +++ b/Mage.Sets/src/mage/cards/b/BladewingsThrall.java @@ -25,7 +25,7 @@ import mage.filter.common.FilterCreaturePermanent; */ public final class BladewingsThrall extends CardImpl { - final static private String RULE = "{this} has flying as long as you control a Dragon"; + static final private String RULE = "{this} has flying as long as you control a Dragon"; public BladewingsThrall(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); diff --git a/Mage.Sets/src/mage/cards/b/BlaringCaptain.java b/Mage.Sets/src/mage/cards/b/BlaringCaptain.java index ab76349078..3a4c55c65c 100644 --- a/Mage.Sets/src/mage/cards/b/BlaringCaptain.java +++ b/Mage.Sets/src/mage/cards/b/BlaringCaptain.java @@ -23,7 +23,7 @@ public final class BlaringCaptain extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.WARRIOR, "attacking Warriors"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public BlaringCaptain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BlastZone.java b/Mage.Sets/src/mage/cards/b/BlastZone.java new file mode 100644 index 0000000000..982b139f1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlastZone.java @@ -0,0 +1,95 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BlastZone extends CardImpl { + + public BlastZone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + + // Blast Zone enters the battlefield with a charge counter on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.CHARGE.createInstance(1)) + )); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {X}{X}, {T}: Put X charge counters on Blast Zone. + Ability ability = new SimpleActivatedAbility(new AddCountersSourceEffect( + CounterType.CHARGE.createInstance(), ManacostVariableValue.instance, true + ), new ManaCostsImpl("{X}{X}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {3}, {T}, Sacrifice Blast Zone: Destroy each nonland permanent with converted mana cost equal to the number of charge counters on Blast Zone. + ability = new SimpleActivatedAbility(new BlastZoneEffect(), new GenericManaCost(3)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private BlastZone(final BlastZone card) { + super(card); + } + + @Override + public BlastZone copy() { + return new BlastZone(this); + } +} + +class BlastZoneEffect extends OneShotEffect { + + BlastZoneEffect() { + super(Outcome.Benefit); + staticText = "Destroy each nonland permanent with converted mana cost " + + "equal to the number of charge counters on {this}"; + } + + private BlastZoneEffect(final BlastZoneEffect effect) { + super(effect); + } + + @Override + public BlastZoneEffect copy() { + return new BlastZoneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + int xValue = permanent.getCounters(game).getCount(CounterType.CHARGE); + FilterPermanent filter = new FilterNonlandPermanent(); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + return new DestroyAllEffect(filter).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BlastfireBolt.java b/Mage.Sets/src/mage/cards/b/BlastfireBolt.java index b83dcb3e74..681b81191f 100644 --- a/Mage.Sets/src/mage/cards/b/BlastfireBolt.java +++ b/Mage.Sets/src/mage/cards/b/BlastfireBolt.java @@ -1,22 +1,13 @@ package mage.cards.b; -import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DestroyAllAttachedEquipmentEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCreaturePermanent; -import java.util.ArrayList; -import java.util.List; import java.util.UUID; /** @@ -35,7 +26,7 @@ public final class BlastfireBolt extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } - public BlastfireBolt(final BlastfireBolt card) { + private BlastfireBolt(final BlastfireBolt card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BlatantThievery.java b/Mage.Sets/src/mage/cards/b/BlatantThievery.java index 39bfb83a74..3a65bbec7d 100644 --- a/Mage.Sets/src/mage/cards/b/BlatantThievery.java +++ b/Mage.Sets/src/mage/cards/b/BlatantThievery.java @@ -1,9 +1,7 @@ - package mage.cards.b; import java.util.*; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; @@ -18,6 +16,7 @@ import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; /** @@ -31,34 +30,37 @@ public final class BlatantThievery extends CardImpl { // For each opponent, gain control of target permanent that player controls. this.getSpellAbility().addEffect(new BlatantThieveryEffect()); + this.getSpellAbility().setTargetAdjuster(BlatantThieveryAdjuster.instance); } public BlatantThievery(final BlatantThievery card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterPermanent filter = new FilterPermanent("Permanent of player " + opponent.getName()); - filter.add(new ControllerIdPredicate(opponentId)); - TargetPermanent targetPermanent = new TargetPermanent(filter); - ability.addTarget(targetPermanent); - } - } - } - } - @Override public BlatantThievery copy() { return new BlatantThievery(this); } } +enum BlatantThieveryAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterPermanent filter = new FilterPermanent("Permanent of player " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetPermanent targetPermanent = new TargetPermanent(filter); + ability.addTarget(targetPermanent); + } + } + } +} + class BlatantThieveryEffect extends OneShotEffect { BlatantThieveryEffect() { diff --git a/Mage.Sets/src/mage/cards/b/Blaze.java b/Mage.Sets/src/mage/cards/b/Blaze.java index bbeead8481..d2b4c01921 100644 --- a/Mage.Sets/src/mage/cards/b/Blaze.java +++ b/Mage.Sets/src/mage/cards/b/Blaze.java @@ -20,7 +20,7 @@ public final class Blaze extends CardImpl { // Blaze deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/b/BlazeCommando.java b/Mage.Sets/src/mage/cards/b/BlazeCommando.java index 07376a338c..64d8c84bf5 100644 --- a/Mage.Sets/src/mage/cards/b/BlazeCommando.java +++ b/Mage.Sets/src/mage/cards/b/BlazeCommando.java @@ -105,6 +105,6 @@ class BlazeCommandoTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever an instant or sorcery spell you control deals damage, ").append(super.getRule()).toString(); + return "Whenever an instant or sorcery spell you control deals damage, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java new file mode 100644 index 0000000000..b61c69b42c --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java @@ -0,0 +1,124 @@ + +package mage.cards.b; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; +import mage.watchers.Watcher; + +/** + * + * @author TheElk801 & L_J + */ +public final class BlazingEffigy extends CardImpl { + + public BlazingEffigy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // When Blazing Effigy dies, it deals X damage to target creature, where X is 3 plus the amount of damage dealt to Blazing Effigy this turn by other sources named Blazing Effigy. + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(BlazingEffigyCount.instance), false); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability, new BlazingEffigyWatcher()); + } + + public BlazingEffigy(final BlazingEffigy card) { + super(card); + } + + @Override + public BlazingEffigy copy() { + return new BlazingEffigy(this); + } +} + +enum BlazingEffigyCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + BlazingEffigyWatcher watcher = game.getState().getWatcher(BlazingEffigyWatcher.class); + if (watcher == null) { + return 3; + } + int effigyDamage = watcher.damageDoneTo(sourceAbility.getSourceId(), sourceAbility.getSourceObjectZoneChangeCounter() - 1, game); + return CardUtil.addWithOverflowCheck(3, effigyDamage); + } + + @Override + public BlazingEffigyCount copy() { + return BlazingEffigyCount.instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "3 plus the amount of damage dealt to {this} this turn by other sources named Blazing Effigy"; + } +} + +class BlazingEffigyWatcher extends Watcher { + + private final Map damagedObjects = new HashMap<>(); + + public BlazingEffigyWatcher() { + super(WatcherScope.GAME); + } + + public BlazingEffigyWatcher(final BlazingEffigyWatcher watcher) { + super(watcher); + this.damagedObjects.putAll(watcher.damagedObjects); + } + + @Override + public BlazingEffigyWatcher copy() { + return new BlazingEffigyWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGED_CREATURE) { + if (!event.getSourceId().equals(event.getTargetId())) { + MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); + MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); + if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { + damagedObjects.putIfAbsent(damageTargetRef, 0); + damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); + } + } + } + } + + @Override + public void reset() { + super.reset(); + damagedObjects.clear(); + } + + public int damageDoneTo(UUID objectId, int zoneChangeCounter, Game game) { + MageObjectReference mor = new MageObjectReference(objectId, zoneChangeCounter, game); + return damagedObjects.getOrDefault(mor, 0); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlazingHope.java b/Mage.Sets/src/mage/cards/b/BlazingHope.java index 4708a0241e..3ca5a50c30 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingHope.java +++ b/Mage.Sets/src/mage/cards/b/BlazingHope.java @@ -75,13 +75,15 @@ class BlazingHopeTarget extends TargetCreaturePermanent { int count = 0; Player controller = game.getPlayer(sourceControllerId); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId())) { - if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if (controller != null && permanent.getPower().getValue() >= controller.getLife()) { - count++; - if (count >= remainingTargets) { - return true; + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId())) { + if (notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (controller != null && permanent.getPower().getValue() >= controller.getLife()) { + count++; + if (count >= remainingTargets) { + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/b/BlazingShoal.java b/Mage.Sets/src/mage/cards/b/BlazingShoal.java index 79e19d154d..9f6238b97e 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingShoal.java +++ b/Mage.Sets/src/mage/cards/b/BlazingShoal.java @@ -38,7 +38,7 @@ public final class BlazingShoal extends CardImpl { this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter),true))); // Target creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(new ExileFromHandCostCardConvertedMana(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ExileFromHandCostCardConvertedMana.instance, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/b/BleedingEdge.java b/Mage.Sets/src/mage/cards/b/BleedingEdge.java new file mode 100644 index 0000000000..d3c4ffae6b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BleedingEdge.java @@ -0,0 +1,36 @@ +package mage.cards.b; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.keyword.AmassEffect; +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 BleedingEdge extends CardImpl { + + public BleedingEdge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // Up to one target creature gets -2/-2 until end of turn. Amass 2. + this.getSpellAbility().addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + this.getSpellAbility().addEffect(new AmassEffect(2)); + } + + private BleedingEdge(final BleedingEdge card) { + super(card); + } + + @Override + public BleedingEdge copy() { + return new BleedingEdge(this); + } +} +// It's nanotech, you like it? \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java index cc5d01b8f2..e2db331f7e 100644 --- a/Mage.Sets/src/mage/cards/b/BlessedAlliance.java +++ b/Mage.Sets/src/mage/cards/b/BlessedAlliance.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -20,8 +18,9 @@ import mage.filter.predicate.other.PlayerPredicate; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class BlessedAlliance extends CardImpl { @@ -35,7 +34,7 @@ public final class BlessedAlliance extends CardImpl { } public BlessedAlliance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Escalate {2} this.addAbility(new EscalateAbility(new GenericManaCost(2))); @@ -48,20 +47,20 @@ public final class BlessedAlliance extends CardImpl { Effect effect = new GainLifeTargetEffect(4); effect.setText("Target player gains 4 life"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife)); + this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterGainLife).withChooseHint("player gains 4 life")); // Untap up to two target creatures. Mode mode = new Mode(); effect = new UntapTargetEffect(); effect.setText("Untap up to two target creatures"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(0, 2, filterCreature, false)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(0, 2, filterCreature, false).withChooseHint("untap")); this.getSpellAbility().addMode(mode); // Target opponent sacrifices an attacking creature. mode = new Mode(); - mode.getEffects().add(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent")); - mode.getTargets().add(new TargetPlayer(1, 1, false, filterSacrifice)); + mode.addEffect(new SacrificeEffect(new FilterAttackingCreature(), 1, "Target opponent")); + mode.addTarget(new TargetPlayer(1, 1, false, filterSacrifice).withChooseHint("sacrifices an attacking creature")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BlightHerder.java b/Mage.Sets/src/mage/cards/b/BlightHerder.java index 12c4977360..598dc52a20 100644 --- a/Mage.Sets/src/mage/cards/b/BlightHerder.java +++ b/Mage.Sets/src/mage/cards/b/BlightHerder.java @@ -48,7 +48,7 @@ public final class BlightHerder extends CardImpl { class BlightHerderEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("cards your opponents own from exile"); + private static final FilterCard filter = new FilterCard("cards your opponents own from exile"); static { filter.add(new OwnerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/b/BlightedSteppe.java b/Mage.Sets/src/mage/cards/b/BlightedSteppe.java index b792bab0c2..b334ebce8f 100644 --- a/Mage.Sets/src/mage/cards/b/BlightedSteppe.java +++ b/Mage.Sets/src/mage/cards/b/BlightedSteppe.java @@ -14,6 +14,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; /** @@ -30,14 +31,14 @@ public final class BlightedSteppe extends CardImpl { // {3}{W}, {T}, Sacrifice Blighted Steppe: You gain 2 life for each creature you control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new GainLifeEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creature you control"), 2)), + new GainLifeEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, 2)), new ManaCostsImpl<>("{3}{W}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); } - public BlightedSteppe(final BlightedSteppe card) { + private BlightedSteppe(final BlightedSteppe card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BlindSpotGiant.java b/Mage.Sets/src/mage/cards/b/BlindSpotGiant.java index 52688ab0cf..bb9a88fe7f 100644 --- a/Mage.Sets/src/mage/cards/b/BlindSpotGiant.java +++ b/Mage.Sets/src/mage/cards/b/BlindSpotGiant.java @@ -25,7 +25,7 @@ public final class BlindSpotGiant extends CardImpl { static { filter.add(new SubtypePredicate(SubType.GIANT)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BlindSpotGiant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/Blindblast.java b/Mage.Sets/src/mage/cards/b/Blindblast.java new file mode 100644 index 0000000000..4d6abe5a47 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/Blindblast.java @@ -0,0 +1,40 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author TheElk801 + */ +public final class Blindblast extends CardImpl { + + public Blindblast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Blindblast deals 1 damage to target creature. That creature can't block this turn. + this.getSpellAbility().addEffect(new DamageTargetEffect(1)); + this.getSpellAbility().addEffect(new CantBlockTargetEffect( + Duration.EndOfTurn + ).setText("That creature can't block this turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private Blindblast(final Blindblast card) { + super(card); + } + + @Override + public Blindblast copy() { + return new Blindblast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlindingAngel.java b/Mage.Sets/src/mage/cards/b/BlindingAngel.java index c75b26c07e..f7f25c29ab 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingAngel.java +++ b/Mage.Sets/src/mage/cards/b/BlindingAngel.java @@ -1,14 +1,14 @@ - package mage.cards.b; import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; 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; /** @@ -16,26 +16,28 @@ import mage.constants.SubType; * @author Plopman */ public final class BlindingAngel extends CardImpl { - + public BlindingAngel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.ANGEL); - + this.power = new MageInt(2); this.toughness = new MageInt(4); // Flying this.addAbility(FlyingAbility.getInstance()); - // Whenever Blinding Angel deals combat damage to a player, that player skips their next combat phase. - this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SkipNextCombatEffect(), false, true)); - } + // Whenever Blinding Angel deals combat damage to a player, that player skips their next combat phase. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("that player skips their next combat phase."), false, true)); + + } + public BlindingAngel(final BlindingAngel card) { super(card); } - + @Override public BlindingAngel copy() { return new BlindingAngel(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/b/BlindingBeam.java b/Mage.Sets/src/mage/cards/b/BlindingBeam.java index 3ce3042afd..92ab1a8627 100644 --- a/Mage.Sets/src/mage/cards/b/BlindingBeam.java +++ b/Mage.Sets/src/mage/cards/b/BlindingBeam.java @@ -42,8 +42,8 @@ public final class BlindingBeam extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(2,2)); // or creatures don't untap during target player's next untap step. Mode mode = new Mode(); - mode.getEffects().add(new BlindingBeamEffect()); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new BlindingBeamEffect()); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // Entwine {1} diff --git a/Mage.Sets/src/mage/cards/b/BlindingRadiance.java b/Mage.Sets/src/mage/cards/b/BlindingRadiance.java new file mode 100644 index 0000000000..2ef6ef3039 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BlindingRadiance.java @@ -0,0 +1,40 @@ +package mage.cards.b; + +import mage.abilities.effects.common.TapAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessPredicate; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class BlindingRadiance extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterOpponentsCreaturePermanent("creatures your opponents control with toughness 2 or less"); + static { + filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public BlindingRadiance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + // Tap all creatures your opponents control with toughness 2 or less. + TapAllEffect effect = new TapAllEffect(filter); + this.getSpellAbility().addEffect(effect); + } + + public BlindingRadiance(final BlindingRadiance card) { + super(card); + } + + @Override + public BlindingRadiance copy() { + return new BlindingRadiance(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java b/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java index 1c9f837951..172b43b805 100644 --- a/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java +++ b/Mage.Sets/src/mage/cards/b/BlinkmothNexus.java @@ -4,7 +4,6 @@ package mage.cards.b; import java.util.UUID; -import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -21,8 +20,6 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.permanent.token.TokenImpl; -import mage.game.permanent.token.Token; import mage.game.permanent.token.custom.CreatureToken; import mage.target.TargetPermanent; @@ -59,7 +56,7 @@ public final class BlinkmothNexus extends CardImpl { } - public BlinkmothNexus(final BlinkmothNexus card) { + private BlinkmothNexus(final BlinkmothNexus card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BlistercoilWeird.java b/Mage.Sets/src/mage/cards/b/BlistercoilWeird.java index e454c0342d..8321019952 100644 --- a/Mage.Sets/src/mage/cards/b/BlistercoilWeird.java +++ b/Mage.Sets/src/mage/cards/b/BlistercoilWeird.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -14,22 +12,23 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** * @author LevelX2 */ public final class BlistercoilWeird extends CardImpl { - - public BlistercoilWeird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U/R}"); - this.subtype.add(SubType.WEIRD); + public BlistercoilWeird(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U/R}"); + this.subtype.add(SubType.WEIRD); this.power = new MageInt(1); this.toughness = new MageInt(1); // Whenever you cast an instant or sorcery spell, Blistercoil Weird gets +1/+1 until end of turn. Untap it. - Ability ability = new SpellCastControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false); + Ability ability = new SpellCastControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); ability.addEffect(new UntapSourceEffect()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java b/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java index 0b8fc235a6..1fb2a4c3a2 100644 --- a/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java +++ b/Mage.Sets/src/mage/cards/b/BlizzardSpecter.java @@ -41,7 +41,7 @@ public final class BlizzardSpecter extends CardImpl { // or that player discards a card. Mode mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(1, false)); + mode.addEffect(new DiscardTargetEffect(1, false)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/Blockbuster.java b/Mage.Sets/src/mage/cards/b/Blockbuster.java index 3dbb960768..174ebca05f 100644 --- a/Mage.Sets/src/mage/cards/b/Blockbuster.java +++ b/Mage.Sets/src/mage/cards/b/Blockbuster.java @@ -23,7 +23,7 @@ public final class Blockbuster extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public Blockbuster(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BloodArtist.java b/Mage.Sets/src/mage/cards/b/BloodArtist.java index 866650d418..66a09bd835 100644 --- a/Mage.Sets/src/mage/cards/b/BloodArtist.java +++ b/Mage.Sets/src/mage/cards/b/BloodArtist.java @@ -29,7 +29,7 @@ public final class BloodArtist extends CardImpl { // Whenever Blood Artist or another creature dies, target player loses 1 life and you gain 1 life. Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new LoseLifeTargetEffect(1), false); - ability.addEffect(new GainLifeEffect(1)); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); Target target = new TargetPlayer(); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BloodChinFanatic.java b/Mage.Sets/src/mage/cards/b/BloodChinFanatic.java index 5ad22400d9..a05a7f2857 100644 --- a/Mage.Sets/src/mage/cards/b/BloodChinFanatic.java +++ b/Mage.Sets/src/mage/cards/b/BloodChinFanatic.java @@ -31,7 +31,7 @@ public final class BloodChinFanatic extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Warrior creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.WARRIOR)); } @@ -42,9 +42,9 @@ public final class BloodChinFanatic extends CardImpl { this.toughness = new MageInt(3); // {1}{B}, Sacrifice another Warrior creature: Target player loses X life and you gain X life, where X is the sacrificed creature's power. - Effect effect = new LoseLifeTargetEffect(new SacrificeCostCreaturesPower()); + Effect effect = new LoseLifeTargetEffect(SacrificeCostCreaturesPower.instance); effect.setText("Target player loses X life"); - Effect effect2 = new GainLifeEffect(new SacrificeCostCreaturesPower()); + Effect effect2 = new GainLifeEffect(SacrificeCostCreaturesPower.instance); effect2.setText("and you gain X life, where X is the sacrificed creature's power"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{B}")); ability.addEffect(effect2); diff --git a/Mage.Sets/src/mage/cards/b/BloodCursedKnight.java b/Mage.Sets/src/mage/cards/b/BloodCursedKnight.java index b80b2c8cd7..71adc8a30a 100644 --- a/Mage.Sets/src/mage/cards/b/BloodCursedKnight.java +++ b/Mage.Sets/src/mage/cards/b/BloodCursedKnight.java @@ -24,8 +24,8 @@ import mage.filter.common.FilterControlledEnchantmentPermanent; */ public final class BloodCursedKnight extends CardImpl { - final static private String rule1 = "As long as you control an enchantment, {this} gets +1/+1"; - final static private String rule2 = "and has lifelink"; + static final private String rule1 = "As long as you control an enchantment, {this} gets +1/+1"; + static final private String rule2 = "and has lifelink"; public BloodCursedKnight(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{B}"); diff --git a/Mage.Sets/src/mage/cards/b/BloodHound.java b/Mage.Sets/src/mage/cards/b/BloodHound.java index 7a438904db..f182a4b5e3 100644 --- a/Mage.Sets/src/mage/cards/b/BloodHound.java +++ b/Mage.Sets/src/mage/cards/b/BloodHound.java @@ -1,23 +1,24 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class BloodHound extends CardImpl { @@ -33,10 +34,12 @@ public final class BloodHound extends CardImpl { this.addAbility(new BloodHoundTriggeredAbility()); // At the beginning of your end step, remove all +1/+1 counters from Blood Hound. - this.addAbility(new BeginningOfEndStepTriggeredAbility(new RemoveAllCountersSourceEffect(CounterType.P1P1), TargetController.YOU, false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new RemoveAllCountersSourceEffect(CounterType.P1P1), TargetController.YOU, false + )); } - public BloodHound(final BloodHound card) { + private BloodHound(final BloodHound card) { super(card); } @@ -48,11 +51,11 @@ public final class BloodHound extends CardImpl { class BloodHoundTriggeredAbility extends TriggeredAbilityImpl { - public BloodHoundTriggeredAbility() { - super(Zone.BATTLEFIELD, new BloodHoundEffect(), true); + BloodHoundTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), true); } - public BloodHoundTriggeredAbility(final BloodHoundTriggeredAbility ability) { + private BloodHoundTriggeredAbility(final BloodHoundTriggeredAbility ability) { super(ability); } @@ -68,8 +71,9 @@ class BloodHoundTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getTargetId().equals(this.getControllerId())) { - this.getEffects().get(0).setValue("damageAmount", event.getAmount()); + if (event.getTargetId().equals(this.getControllerId()) && event.getAmount() > 0) { + this.getEffects().clear(); + this.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance(event.getAmount()))); return true; } return false; @@ -77,31 +81,6 @@ class BloodHoundTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever you are dealt damage, you may put that many +1/+1 counters on {this}."; - } -} - -class BloodHoundEffect extends OneShotEffect { - - public BloodHoundEffect() { - super(Outcome.Benefit); - } - - public BloodHoundEffect(final BloodHoundEffect effect) { - super(effect); - } - - @Override - public BloodHoundEffect copy() { - return new BloodHoundEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.addCounters(CounterType.P1P1.createInstance((Integer) this.getValue("damageAmount")), source, game); - } - return true; + return "Whenever you're dealt damage, you may put that many +1/+1 counters on {this}."; } } diff --git a/Mage.Sets/src/mage/cards/b/BloodMoon.java b/Mage.Sets/src/mage/cards/b/BloodMoon.java index ca52c9989c..1eef0357ac 100644 --- a/Mage.Sets/src/mage/cards/b/BloodMoon.java +++ b/Mage.Sets/src/mage/cards/b/BloodMoon.java @@ -1,11 +1,14 @@ - package mage.cards.b; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -22,7 +25,7 @@ import mage.game.permanent.Permanent; public final class BloodMoon extends CardImpl { public BloodMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); // Nonbasic lands are Mountains. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodMoonEffect())); @@ -72,12 +75,28 @@ class BloodMoonEffect extends ContinuousEffectImpl { case TypeChangingEffects_4: // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects // So the ability removing has to be done before Layer 6 - land.removeAllAbilities(source.getSourceId(), game); - land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + //land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + land.getSubtype(game).clear(); land.getSubtype(game).add(SubType.MOUNTAIN); + land.removeAllAbilities(source.getSourceId(), game); break; case AbilityAddingRemovingEffects_6: - land.addAbility(new RedManaAbility(), source.getSourceId(), game); + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } break; } } @@ -86,6 +105,7 @@ class BloodMoonEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/b/BloodScrivener.java b/Mage.Sets/src/mage/cards/b/BloodScrivener.java index 9eb861cc9a..ee24474fbd 100644 --- a/Mage.Sets/src/mage/cards/b/BloodScrivener.java +++ b/Mage.Sets/src/mage/cards/b/BloodScrivener.java @@ -85,8 +85,10 @@ class BloodScrivenerReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getPlayerId().equals(source.getControllerId())) { Player player = game.getPlayer(event.getPlayerId()); - if (player.getHand().isEmpty()) { - return true; + if(player != null) { + if (player.getHand().isEmpty()) { + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/b/BloodSun.java b/Mage.Sets/src/mage/cards/b/BloodSun.java index efa84ba2eb..227b656eaf 100644 --- a/Mage.Sets/src/mage/cards/b/BloodSun.java +++ b/Mage.Sets/src/mage/cards/b/BloodSun.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.Iterator; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -14,7 +13,6 @@ import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Layer; -import static mage.constants.Layer.AbilityAddingRemovingEffects_6; import mage.constants.Outcome; import mage.constants.SubLayer; import mage.constants.Zone; @@ -39,7 +37,7 @@ public final class BloodSun extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodSunEffect(Duration.WhileOnBattlefield))); } - public BloodSun(final BloodSun card) { + private BloodSun(final BloodSun card) { super(card); } @@ -56,7 +54,7 @@ class BloodSunEffect extends ContinuousEffectImpl { staticText = "all lands lose all abilities except mana abilities"; } - public BloodSunEffect(final BloodSunEffect effect) { + private BloodSunEffect(final BloodSunEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/b/BloodTithe.java b/Mage.Sets/src/mage/cards/b/BloodTithe.java index 86832f3bbc..02355d98cd 100644 --- a/Mage.Sets/src/mage/cards/b/BloodTithe.java +++ b/Mage.Sets/src/mage/cards/b/BloodTithe.java @@ -37,7 +37,7 @@ public final class BloodTithe extends CardImpl { class BloodTitheEffect extends OneShotEffect { public BloodTitheEffect() { - super(Outcome.Damage); + super(Outcome.GainLife); staticText = "Each opponent loses 3 life. You gain life equal to the life lost this way"; } @@ -47,11 +47,11 @@ class BloodTitheEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int damage = 0; + int lifeLost = 0; for (UUID opponentId: game.getOpponents(source.getControllerId())) { - damage += game.getPlayer(opponentId).damage(3, source.getSourceId(), game, false, true); + lifeLost += game.getPlayer(opponentId).loseLife(3, game, false); } - game.getPlayer(source.getControllerId()).gainLife(damage, game, source); + game.getPlayer(source.getControllerId()).gainLife(lifeLost, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BloodTribute.java b/Mage.Sets/src/mage/cards/b/BloodTribute.java index cd9587f409..694c16ac06 100644 --- a/Mage.Sets/src/mage/cards/b/BloodTribute.java +++ b/Mage.Sets/src/mage/cards/b/BloodTribute.java @@ -37,7 +37,7 @@ public final class BloodTribute extends CardImpl { TextPartSubType textPartVampire = (TextPartSubType) addTextPart(new TextPartSubType(SubType.VAMPIRE)); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped Vampire you control"); filter.add(new TextPartSubtypePredicate(textPartVampire)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); this.addAbility(new KickerAbility(new TapTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, true)))); // Target opponent loses half their life, rounded up. diff --git a/Mage.Sets/src/mage/cards/b/Bloodbriar.java b/Mage.Sets/src/mage/cards/b/Bloodbriar.java index f7920debb3..6db0ffa898 100644 --- a/Mage.Sets/src/mage/cards/b/Bloodbriar.java +++ b/Mage.Sets/src/mage/cards/b/Bloodbriar.java @@ -21,11 +21,11 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class Bloodbriar extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("another permanent"); + private static final FilterPermanent filter = new FilterPermanent("another permanent"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Bloodbriar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BloodcrazedGoblin.java b/Mage.Sets/src/mage/cards/b/BloodcrazedGoblin.java index a67946442b..8ebb4b39b4 100644 --- a/Mage.Sets/src/mage/cards/b/BloodcrazedGoblin.java +++ b/Mage.Sets/src/mage/cards/b/BloodcrazedGoblin.java @@ -1,8 +1,5 @@ - - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -17,15 +14,16 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.BloodthirstWatcher; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com * @author North */ public final class BloodcrazedGoblin extends CardImpl { public BloodcrazedGoblin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.GOBLIN, SubType.BERSERKER); this.power = new MageInt(2); @@ -62,15 +60,15 @@ class BloodcrazedGoblinEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get(BloodthirstWatcher.class.getSimpleName(), source.getControllerId()); // BloodthirstWatcher - return !watcher.conditionMet(); + BloodthirstWatcher watcher = game.getState().getWatcher(BloodthirstWatcher.class, source.getControllerId()); // BloodthirstWatcher + return watcher != null && !watcher.conditionMet(); } return false; } diff --git a/Mage.Sets/src/mage/cards/b/BloodcrazedPaladin.java b/Mage.Sets/src/mage/cards/b/BloodcrazedPaladin.java index 979494a69d..85cfe792f6 100644 --- a/Mage.Sets/src/mage/cards/b/BloodcrazedPaladin.java +++ b/Mage.Sets/src/mage/cards/b/BloodcrazedPaladin.java @@ -34,7 +34,7 @@ public final class BloodcrazedPaladin extends CardImpl { // Bloodcrazed Paladin enters the battlefield with a +1/+1 counter on it for each creature that died this turn. Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), - new CreaturesDiedThisTurnCount(), true); + CreaturesDiedThisTurnCount.instance, true); effect.setText("with a +1/+1 counter on it for each creature that died this turn."); this.addAbility(new EntersBattlefieldAbility(effect), new CreaturesDiedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/b/BloodcurdlingScream.java b/Mage.Sets/src/mage/cards/b/BloodcurdlingScream.java index 405349caa7..50d803fc36 100644 --- a/Mage.Sets/src/mage/cards/b/BloodcurdlingScream.java +++ b/Mage.Sets/src/mage/cards/b/BloodcurdlingScream.java @@ -21,7 +21,7 @@ public final class BloodcurdlingScream extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}"); // Target creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(new ExileFromHandCostCardConvertedMana(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ExileFromHandCostCardConvertedMana.instance, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/b/BloodhuskRitualist.java b/Mage.Sets/src/mage/cards/b/BloodhuskRitualist.java index 4fb929dd9f..d3cc620816 100644 --- a/Mage.Sets/src/mage/cards/b/BloodhuskRitualist.java +++ b/Mage.Sets/src/mage/cards/b/BloodhuskRitualist.java @@ -32,7 +32,7 @@ public final class BloodhuskRitualist extends CardImpl { this.addAbility(new MultikickerAbility("{B}")); // When Bloodhusk Ritualist enters the battlefield, target opponent discards a card for each time it was kicked. - Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(new MultikickerCount())); + Ability ability = new EntersBattlefieldTriggeredAbility(new DiscardTargetEffect(MultikickerCount.instance)); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java index d658ab2bbf..9cae143784 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java @@ -70,7 +70,7 @@ class BloodlineShamanEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (controller != null && controller.choose(outcome, typeChoice, game)) { + if (controller != null && sourceObject != null && controller.choose(outcome, typeChoice, game)) { game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); FilterCard filterSubtype = new FilterCard(); filterSubtype.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); diff --git a/Mage.Sets/src/mage/cards/b/BloodlordOfVaasgoth.java b/Mage.Sets/src/mage/cards/b/BloodlordOfVaasgoth.java index adad0809f7..5e951498c3 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlordOfVaasgoth.java +++ b/Mage.Sets/src/mage/cards/b/BloodlordOfVaasgoth.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -18,6 +17,8 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; +import java.util.UUID; + /** * @author nantuko */ @@ -31,7 +32,7 @@ public final class BloodlordOfVaasgoth extends CardImpl { } public BloodlordOfVaasgoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.VAMPIRE, SubType.WARRIOR); this.power = new MageInt(3); @@ -47,7 +48,7 @@ public final class BloodlordOfVaasgoth extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility(new BloodlordOfVaasgothEffect(), filter, false, true)); } - public BloodlordOfVaasgoth(final BloodlordOfVaasgoth card) { + private BloodlordOfVaasgoth(final BloodlordOfVaasgoth card) { super(card); } @@ -63,12 +64,12 @@ class BloodlordOfVaasgothEffect extends ContinuousEffectImpl { private int zoneChangeCounter; private UUID permanentId; - public BloodlordOfVaasgothEffect() { + BloodlordOfVaasgothEffect() { super(Duration.OneUse, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); staticText = "it gains bloodthirst 3"; } - public BloodlordOfVaasgothEffect(final BloodlordOfVaasgothEffect effect) { + private BloodlordOfVaasgothEffect(final BloodlordOfVaasgothEffect effect) { super(effect); this.ability = effect.ability.copy(); this.zoneChangeCounter = effect.zoneChangeCounter; @@ -95,7 +96,6 @@ class BloodlordOfVaasgothEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(permanentId); if (permanent != null && permanent.getZoneChangeCounter(game) <= zoneChangeCounter) { permanent.addAbility(ability, source.getSourceId(), game); - return true; } else { if (game.getState().getZoneChangeCounter(permanentId) >= zoneChangeCounter) { discard(); diff --git a/Mage.Sets/src/mage/cards/b/BloodmistInfiltrator.java b/Mage.Sets/src/mage/cards/b/BloodmistInfiltrator.java new file mode 100644 index 0000000000..1a523bb739 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BloodmistInfiltrator.java @@ -0,0 +1,54 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BloodmistInfiltrator extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("another creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public BloodmistInfiltrator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Whenever Bloodmist Infiltrator attacks, you may sacrifice another creature. If you do, Bloodmist Infiltrator can't be blocked this turn. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + ), false)); + } + + private BloodmistInfiltrator(final BloodmistInfiltrator card) { + super(card); + } + + @Override + public BloodmistInfiltrator copy() { + return new BloodmistInfiltrator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BloodshotCyclops.java b/Mage.Sets/src/mage/cards/b/BloodshotCyclops.java index 80aa19dbbb..7cbe947de4 100644 --- a/Mage.Sets/src/mage/cards/b/BloodshotCyclops.java +++ b/Mage.Sets/src/mage/cards/b/BloodshotCyclops.java @@ -33,7 +33,7 @@ public final class BloodshotCyclops extends CardImpl { // {T}, Sacrifice a creature: Bloodshot Cyclops deals damage equal to the sacrificed // creature's power to any target. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new DamageTargetEffect(new SacrificeCostCreaturesPower()), + new DamageTargetEffect(SacrificeCostCreaturesPower.instance), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/b/BloodswornSteward.java b/Mage.Sets/src/mage/cards/b/BloodswornSteward.java index e9070d6d06..10dcbe7f9f 100644 --- a/Mage.Sets/src/mage/cards/b/BloodswornSteward.java +++ b/Mage.Sets/src/mage/cards/b/BloodswornSteward.java @@ -25,9 +25,9 @@ import mage.filter.predicate.permanent.CommanderPredicate; */ public final class BloodswornSteward extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Commander creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Commander creatures"); static { - filter.add(new CommanderPredicate()); + filter.add(CommanderPredicate.instance); } public BloodswornSteward(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BloodtallowCandle.java b/Mage.Sets/src/mage/cards/b/BloodtallowCandle.java index fe875013e2..5cc30915a8 100644 --- a/Mage.Sets/src/mage/cards/b/BloodtallowCandle.java +++ b/Mage.Sets/src/mage/cards/b/BloodtallowCandle.java @@ -6,13 +6,9 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.StaticFilters; -import mage.target.common.TargetCardInLibrary; import java.util.UUID; import mage.abilities.effects.common.continuous.BoostTargetEffect; @@ -39,7 +35,7 @@ public final class BloodtallowCandle extends CardImpl { this.addAbility(ability); } - public BloodtallowCandle(final BloodtallowCandle card) { + private BloodtallowCandle(final BloodtallowCandle card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/b/BloomHulk.java b/Mage.Sets/src/mage/cards/b/BloomHulk.java new file mode 100644 index 0000000000..c5631c3dc1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BloomHulk.java @@ -0,0 +1,38 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +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 BloomHulk extends CardImpl { + + public BloomHulk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.PLANT); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Bloom Hulk enters the battlefield, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new EntersBattlefieldTriggeredAbility(new ProliferateEffect())); + } + + private BloomHulk(final BloomHulk card) { + super(card); + } + + @Override + public BloomHulk copy() { + return new BloomHulk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java b/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java index f4c139b882..5bf9a75465 100644 --- a/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java +++ b/Mage.Sets/src/mage/cards/b/BlueElementalBlast.java @@ -38,8 +38,8 @@ public final class BlueElementalBlast extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(filterSpell)); Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filterPermanent)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filterPermanent)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BlueManaBattery.java b/Mage.Sets/src/mage/cards/b/BlueManaBattery.java index 9283e18893..05ad3bfc87 100644 --- a/Mage.Sets/src/mage/cards/b/BlueManaBattery.java +++ b/Mage.Sets/src/mage/cards/b/BlueManaBattery.java @@ -36,7 +36,7 @@ public final class BlueManaBattery extends CardImpl { // {tap}, Remove any number of charge counters from Blue Mana Battery: Add {U}, then add an additional {U} for each charge counter removed this way. ability = new DynamicManaAbility( Mana.BlueMana(1), - new IntPlusDynamicValue(1, new RemovedCountersForCostValue()), + new IntPlusDynamicValue(1, RemovedCountersForCostValue.instance), new TapSourceCost(), "Add {U}, then add {U} for each charge counter removed this way", true, new CountersSourceCount(CounterType.CHARGE)); diff --git a/Mage.Sets/src/mage/cards/b/BlueSunsZenith.java b/Mage.Sets/src/mage/cards/b/BlueSunsZenith.java index 72d74af31f..2e94941db5 100644 --- a/Mage.Sets/src/mage/cards/b/BlueSunsZenith.java +++ b/Mage.Sets/src/mage/cards/b/BlueSunsZenith.java @@ -21,7 +21,7 @@ public final class BlueSunsZenith extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}{U}{U}"); // Target player draws X cards. Shuffle Blue Sun's Zenith into its owner's library. - this.getSpellAbility().addEffect(new DrawCardTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addEffect(ShuffleSpellEffect.getInstance()); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/b/BoarUmbra.java b/Mage.Sets/src/mage/cards/b/BoarUmbra.java index c161a7a1ca..5e40bb1e6a 100644 --- a/Mage.Sets/src/mage/cards/b/BoarUmbra.java +++ b/Mage.Sets/src/mage/cards/b/BoarUmbra.java @@ -31,8 +31,11 @@ public final class BoarUmbra extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature gets +3/+3. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java b/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java index 7b23221999..cebfdf8ec6 100644 --- a/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java +++ b/Mage.Sets/src/mage/cards/b/BoardTheWeatherlight.java @@ -19,7 +19,7 @@ public final class BoardTheWeatherlight extends CardImpl { private static final FilterCard filter = new FilterCard("a historic card"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public BoardTheWeatherlight(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BogGlider.java b/Mage.Sets/src/mage/cards/b/BogGlider.java index ed773d4f40..d00ee5c13b 100644 --- a/Mage.Sets/src/mage/cards/b/BogGlider.java +++ b/Mage.Sets/src/mage/cards/b/BogGlider.java @@ -29,7 +29,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class BogGlider extends CardImpl { - final static FilterControlledPermanent landFilter = new FilterControlledLandPermanent("a land"); + static final FilterControlledPermanent landFilter = new FilterControlledLandPermanent("a land"); private static final FilterPermanentCard filter = new FilterPermanentCard("Mercenary permanent card with converted mana cost 2 or less"); static { diff --git a/Mage.Sets/src/mage/cards/b/BoilingEarth.java b/Mage.Sets/src/mage/cards/b/BoilingEarth.java index a6d410a08f..bb72e70568 100644 --- a/Mage.Sets/src/mage/cards/b/BoilingEarth.java +++ b/Mage.Sets/src/mage/cards/b/BoilingEarth.java @@ -17,7 +17,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class BoilingEarth extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature your opponents control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature your opponents control"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/b/BolassCitadel.java b/Mage.Sets/src/mage/cards/b/BolassCitadel.java new file mode 100644 index 0000000000..f7f617045d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BolassCitadel.java @@ -0,0 +1,110 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Costs; +import mage.abilities.costs.CostsImpl; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author jeffwadsworth + */ +public final class BolassCitadel extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("nonland permanents"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + } + + public BolassCitadel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{B}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + + // You may look at the top card of your library any time. + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); + + // You may play the top card of your library. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost. + this.addAbility(new SimpleStaticAbility(new BolassCitadelPlayTheTopCardEffect())); + + // {T}, Sacrifice ten nonland permanents: Each opponent loses 10 life. + Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( + 10, 10, filter, true + ))); + this.addAbility(ability); + } + + private BolassCitadel(final BolassCitadel card) { + super(card); + } + + @Override + public BolassCitadel copy() { + return new BolassCitadel(this); + } +} + +class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl { + + BolassCitadelPlayTheTopCardEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, + Duration.WhileOnBattlefield, Outcome.AIDontUseIt); // AI will need help with this + staticText = "You may play the top card of your library. If you cast a spell this way, " + + "pay life equal to its converted mana cost rather than pay its mana cost."; + } + + private BolassCitadelPlayTheTopCardEffect(final BolassCitadelPlayTheTopCardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public BolassCitadelPlayTheTopCardEffect copy() { + return new BolassCitadelPlayTheTopCardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Card cardOnTop = game.getCard(objectId); + if (cardOnTop == null) { + return false; + } + if (affectedControllerId.equals(source.getControllerId()) + && cardOnTop.isOwnedBy(source.getControllerId())) { + Player controller = game.getPlayer(cardOnTop.getOwnerId()); + if (controller != null + && cardOnTop.equals(controller.getLibrary().getFromTop(game))) { + PayLifeCost cost = new PayLifeCost(cardOnTop.getManaCost().convertedManaCost()); + Costs costs = new CostsImpl(); + costs.add(cost); + controller.setCastSourceIdWithAlternateMana(cardOnTop.getId(), null, costs); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoldwyrHeavyweights.java b/Mage.Sets/src/mage/cards/b/BoldwyrHeavyweights.java index 02789e13b3..f86567ffc2 100644 --- a/Mage.Sets/src/mage/cards/b/BoldwyrHeavyweights.java +++ b/Mage.Sets/src/mage/cards/b/BoldwyrHeavyweights.java @@ -73,7 +73,7 @@ class BoldwyrHeavyweightsEffect extends OneShotEffect { Player opponent = game.getPlayer(opponentId); if (opponent != null && opponent.chooseUse(Outcome.PutCreatureInPlay, "Search your library for a creature card and put it onto the battlefield?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterCreatureCard()); - if (opponent.searchLibrary(target, game)) { + if (opponent.searchLibrary(target, source, game)) { Card targetCard = opponent.getLibrary().getCard(target.getFirstTarget(), game); if (targetCard != null) { opponent.moveCards(targetCard, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BoldwyrIntimidator.java b/Mage.Sets/src/mage/cards/b/BoldwyrIntimidator.java index 19e439b762..c44b6d4c5a 100644 --- a/Mage.Sets/src/mage/cards/b/BoldwyrIntimidator.java +++ b/Mage.Sets/src/mage/cards/b/BoldwyrIntimidator.java @@ -1,4 +1,3 @@ - package mage.cards.b; import mage.MageInt; @@ -22,27 +21,26 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author fireshoes */ public final class BoldwyrIntimidator extends CardImpl { public BoldwyrIntimidator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); this.subtype.add(SubType.GIANT, SubType.WARRIOR); this.power = new MageInt(5); this.toughness = new MageInt(5); // Cowards can't block Warriors. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoldwyrIntimidatorEffect())); - + // {R}: Target creature becomes a Coward until end of turn. Effect effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.COWARD); effect.setText("Target creature becomes a Coward until end of turn"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{R}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - + // {2}{R}: Target creature becomes a Warrior until end of turn. effect = new BecomesCreatureTypeTargetEffect(Duration.EndOfTurn, SubType.WARRIOR); effect.setText("Target creature becomes a Warrior until end of turn"); @@ -75,14 +73,11 @@ class BoldwyrIntimidatorEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - return true; - } - return false; + return sourcePermanent != null; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { if (attacker != null && blocker != null) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null && attacker.hasSubtype(SubType.WARRIOR, game)) { diff --git a/Mage.Sets/src/mage/cards/b/BolracClanCrusher.java b/Mage.Sets/src/mage/cards/b/BolracClanCrusher.java new file mode 100644 index 0000000000..5b41bafcf1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BolracClanCrusher.java @@ -0,0 +1,47 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCounterCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BolracClanCrusher extends CardImpl { + + public BolracClanCrusher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {T}, Remove a +1/+1 counter from a creature you control: Bolrac-Clan Crusher deals 2 damage to any target. + Ability ability = new SimpleActivatedAbility(new DamageTargetEffect(2), new TapSourceCost()); + ability.addCost(new RemoveCounterCost(new TargetControlledCreaturePermanent(), CounterType.P1P1)); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private BolracClanCrusher(final BolracClanCrusher card) { + super(card); + } + + @Override + public BolracClanCrusher copy() { + return new BolracClanCrusher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoltBend.java b/Mage.Sets/src/mage/cards/b/BoltBend.java new file mode 100644 index 0000000000..69dcc08aa9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoltBend.java @@ -0,0 +1,49 @@ +package mage.cards.b; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.effects.common.ChooseNewTargetsTargetEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.NumberOfTargetsPredicate; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BoltBend extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("spell with a single target"); + + static { + filter.add(new NumberOfTargetsPredicate(1)); + } + + public BoltBend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); + + // This spell costs {3} less to cast if you control a creature with power 4 or greater. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(3, FerociousCondition.instance) + ).setRuleAtTheTop(true)); + + // Change the target of target spell or ability with a single target. + this.getSpellAbility().addEffect(new ChooseNewTargetsTargetEffect(true, true)); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + private BoltBend(final BoltBend card) { + super(card); + } + + @Override + public BoltBend copy() { + return new BoltBend(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoltwingMarauder.java b/Mage.Sets/src/mage/cards/b/BoltwingMarauder.java index 58c3574144..230401b197 100644 --- a/Mage.Sets/src/mage/cards/b/BoltwingMarauder.java +++ b/Mage.Sets/src/mage/cards/b/BoltwingMarauder.java @@ -26,7 +26,7 @@ public final class BoltwingMarauder extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature under your control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BoltwingMarauder(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BombSquad.java b/Mage.Sets/src/mage/cards/b/BombSquad.java index 154cdb4d63..fdfb32772f 100644 --- a/Mage.Sets/src/mage/cards/b/BombSquad.java +++ b/Mage.Sets/src/mage/cards/b/BombSquad.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -26,20 +24,22 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * 10/4/2004: If the creature regenerates, the fuse counters are still removed and - * the four damage is still dealt. - * 10/4/2004: If there are two Bomb Squads on the battlefield when a creature ends - * up with 4 or more fuse counters, both Bomb Squad abilities will trigger - * causing 4 damage each even though the first to resolve will destroy the - * creature. + * 10/4/2004: If the creature regenerates, the fuse counters are still removed and + * the four damage is still dealt. + * 10/4/2004: If there are two Bomb Squads on the battlefield when a creature ends + * up with 4 or more fuse counters, both Bomb Squad abilities will trigger + * causing 4 damage each even though the first to resolve will destroy the + * creature. * * @author LevelX2 */ public final class BombSquad extends CardImpl { public BombSquad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.DWARF); this.power = new MageInt(1); @@ -150,6 +150,7 @@ class BombSquadDamgeEffect extends OneShotEffect { class BombSquadBeginningEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with a fuse counter on it"); + static { filter.add(new CounterPredicate(CounterType.FUSE)); } @@ -171,10 +172,13 @@ class BombSquadBeginningEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); + if (card == null) { + return false; + } for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { permanent.addCounters(CounterType.FUSE.createInstance(), source, game); - game.informPlayers(new StringBuilder(card.getName()).append(" puts a fuse counter on ").append(permanent.getName()).toString()); + game.informPlayers(card.getName() + " puts a fuse counter on " + permanent.getName()); } return true; } diff --git a/Mage.Sets/src/mage/cards/b/BondOfAgony.java b/Mage.Sets/src/mage/cards/b/BondOfAgony.java index 761c1ad988..a6da60f30e 100644 --- a/Mage.Sets/src/mage/cards/b/BondOfAgony.java +++ b/Mage.Sets/src/mage/cards/b/BondOfAgony.java @@ -18,7 +18,7 @@ public final class BondOfAgony extends CardImpl { public BondOfAgony(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}"); - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; // As an additional cost to cast Bond of Agony, pay X life. // magenoxx: here we don't use PayVariableLifeCost as {X} shouldn't actually be announced diff --git a/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java b/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java new file mode 100644 index 0000000000..d5980c6ca7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BondOfDiscipline.java @@ -0,0 +1,43 @@ +package mage.cards.b; + +import mage.abilities.effects.common.TapAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BondOfDiscipline extends CardImpl { + + private static final FilterPermanent filter + = new FilterOpponentsCreaturePermanent("creatures your opponents control."); + + public BondOfDiscipline(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + // Tap all creatures your opponents control. Creatures you control gain lifelink until end of turn. + this.getSpellAbility().addEffect(new TapAllEffect(filter)); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES + )); + } + + private BondOfDiscipline(final BondOfDiscipline card) { + super(card); + } + + @Override + public BondOfDiscipline copy() { + return new BondOfDiscipline(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java b/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java new file mode 100644 index 0000000000..bba9076cfe --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BondOfFlourishing.java @@ -0,0 +1,40 @@ +package mage.cards.b; + +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BondOfFlourishing extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard(); + + public BondOfFlourishing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // Look at the top three card of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. You gain 3 life. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(3), false, + new StaticValue(1), filter, false + )); + this.getSpellAbility().addEffect(new GainLifeEffect(3).setText("You gain 3 life.")); + } + + private BondOfFlourishing(final BondOfFlourishing card) { + super(card); + } + + @Override + public BondOfFlourishing copy() { + return new BondOfFlourishing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BondOfInsight.java b/Mage.Sets/src/mage/cards/b/BondOfInsight.java new file mode 100644 index 0000000000..fcd7cdda7e --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BondOfInsight.java @@ -0,0 +1,83 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BondOfInsight extends CardImpl { + + public BondOfInsight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); + + // Each player puts the top four cards of their library into their graveyard. Return up to two instant and/or sorcery cards from your graveyard to your hand. Exile Bond of Insight. + this.getSpellAbility().addEffect(new BondOfInsightEffect()); + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + private BondOfInsight(final BondOfInsight card) { + super(card); + } + + @Override + public BondOfInsight copy() { + return new BondOfInsight(this); + } +} + +class BondOfInsightEffect extends OneShotEffect { + + BondOfInsightEffect() { + super(Outcome.Benefit); + staticText = "Each player puts the top four cards of their library into their graveyard. " + + "Return up to two instant and/or sorcery cards from your graveyard to your hand."; + } + + private BondOfInsightEffect(final BondOfInsightEffect effect) { + super(effect); + } + + @Override + public BondOfInsightEffect copy() { + return new BondOfInsightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + player.moveCards(player.getLibrary().getTopCards(game, 4), Zone.GRAVEYARD, source, game); + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInYourGraveyard( + 0, 2, StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, true + ); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Cards cards = new CardsImpl(target.getTargets()); + return player.moveCards(cards, Zone.HAND, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BondOfPassion.java b/Mage.Sets/src/mage/cards/b/BondOfPassion.java new file mode 100644 index 0000000000..a68664370b --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BondOfPassion.java @@ -0,0 +1,108 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterCreaturePlayerOrPlaneswalker; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetAnyTarget; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BondOfPassion extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent(); + private static final FilterCreaturePlayerOrPlaneswalker filter2 + = new FilterCreaturePlayerOrPlaneswalker("any other target"); + + static { + filter.add(new AnotherTargetPredicate(1)); + filter2.getCreatureFilter().add(new AnotherTargetPredicate(2)); + filter2.getPlaneswalkerFilter().add(new AnotherTargetPredicate(2)); + filter2.getPlayerFilter().add(new AnotherTargetPredicate(2)); + } + + public BondOfPassion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}"); + + // Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Bond of Passion deals 2 damage to any other target. + this.getSpellAbility().addEffect(new BondOfPassionEffect()); + Target target = new TargetPermanent(filter); + target.setTargetTag(1); + this.getSpellAbility().addTarget(target); + target = new TargetAnyTarget(filter2); + target.setTargetTag(2); + this.getSpellAbility().addTarget(target); + } + + private BondOfPassion(final BondOfPassion card) { + super(card); + } + + @Override + public BondOfPassion copy() { + return new BondOfPassion(this); + } +} + +class BondOfPassionEffect extends OneShotEffect { + + BondOfPassionEffect() { + super(Outcome.Benefit); + staticText = "Gain control of target creature until end of turn. Untap that creature. " + + "It gains haste until end of turn. {this} deals 2 damage to any other target."; + } + + private BondOfPassionEffect(final BondOfPassionEffect effect) { + super(effect); + } + + @Override + public BondOfPassionEffect copy() { + return new BondOfPassionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + ContinuousEffect effect = new GainControlTargetEffect(Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + permanent.untap(game); + effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + Permanent permanent2 = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (permanent2 != null) { + permanent2.damage(2, source.getSourceId(), game); + return true; + } + Player player = game.getPlayer(source.getTargets().get(1).getFirstTarget()); + if (player != null) { + player.damage(2, source.getSourceId(), game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BondOfRevival.java b/Mage.Sets/src/mage/cards/b/BondOfRevival.java new file mode 100644 index 0000000000..e10a10f214 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BondOfRevival.java @@ -0,0 +1,81 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BondOfRevival extends CardImpl { + + public BondOfRevival(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + + // Return target creature card from your graveyard to the battlefield. It gains haste until your next turn. + this.getSpellAbility().addEffect(new BondOfRevivalEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard( + StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD + )); + } + + private BondOfRevival(final BondOfRevival card) { + super(card); + } + + @Override + public BondOfRevival copy() { + return new BondOfRevival(this); + } +} + +class BondOfRevivalEffect extends OneShotEffect { + + BondOfRevivalEffect() { + super(Outcome.Benefit); + staticText = "Return target creature card from your graveyard to the battlefield. " + + "It gains haste until your next turn."; + } + + private BondOfRevivalEffect(final BondOfRevivalEffect effect) { + super(effect); + } + + @Override + public BondOfRevivalEffect copy() { + return new BondOfRevivalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.UntilYourNextTurn); + effect.setTargetPointer(new FixedTarget(card.getId(), card.getZoneChangeCounter(game) + 1)); + if (player.moveCards(card, Zone.BATTLEFIELD, source, game)) { + game.addEffect(effect, source); + } + return true; + } +} + + diff --git a/Mage.Sets/src/mage/cards/b/BoneMask.java b/Mage.Sets/src/mage/cards/b/BoneMask.java new file mode 100644 index 0000000000..77707ff083 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BoneMask.java @@ -0,0 +1,94 @@ +package mage.cards.b; + +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetSource; + +/** + * + * @author jeffwadsworth + */ +public final class BoneMask extends CardImpl { + + public BoneMask(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {2}, {tap}: The next time a source of your choice would deal damage to you this turn, prevent that damage. Exile cards from the top of your library equal to the damage prevented this way. + Ability ability = new SimpleActivatedAbility(new BoneMaskEffect(), new ManaCostsImpl("{2}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetSource()); + this.addAbility(ability); + + } + + private BoneMask(final BoneMask card) { + super(card); + } + + @Override + public BoneMask copy() { + return new BoneMask(this); + } +} + +class BoneMaskEffect extends PreventionEffectImpl { + + public BoneMaskEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + this.staticText = "The next time a source of your choice would deal damage to you this turn, prevent that damage. " + + "Exile cards from the top of your library equal to the damage prevented this way."; + } + + public BoneMaskEffect(final BoneMaskEffect effect) { + super(effect); + } + + @Override + public BoneMaskEffect copy() { + return new BoneMaskEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used + && super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getControllerId()) + && event.getSourceId().equals(source.getFirstTarget())) { + PreventionEffectData preventionData = preventDamageAction(event, source, game); + this.used = true; + this.discard(); + if (preventionData.getPreventedDamage() > 0) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cardsToMoveToExileFromTopOfLibrary = controller.getLibrary().getTopCards( + game, + preventionData.getPreventedDamage()); + controller.moveCards(cardsToMoveToExileFromTopOfLibrary, Zone.EXILED, source, game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java index 4b61d29348..a604ccf7ae 100644 --- a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java +++ b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java @@ -96,7 +96,7 @@ class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl { return false; } } - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { return true; } diff --git a/Mage.Sets/src/mage/cards/b/BontuTheGlorified.java b/Mage.Sets/src/mage/cards/b/BontuTheGlorified.java index 57662b4c40..79e561b86e 100644 --- a/Mage.Sets/src/mage/cards/b/BontuTheGlorified.java +++ b/Mage.Sets/src/mage/cards/b/BontuTheGlorified.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -25,8 +23,9 @@ import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.watchers.common.CreaturesDiedWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class BontuTheGlorified extends CardImpl { @@ -85,12 +84,12 @@ class BontuTheGlorifiedRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @@ -98,7 +97,7 @@ class BontuTheGlorifiedRestrictionEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { Player controller = game.getPlayer(source.getControllerId()); - CreaturesDiedWatcher watcher = (CreaturesDiedWatcher) game.getState().getWatchers().get(CreaturesDiedWatcher.class.getSimpleName()); + CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class); if (controller != null && watcher != null) { return (watcher.getAmountOfCreaturesDiedThisTurnByController(controller.getId()) == 0); diff --git a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java index 4a7619452c..944c751ba4 100644 --- a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java +++ b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java @@ -101,7 +101,7 @@ class BoonweaverGiantEffect extends OneShotEffect { } if (card == null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); if (card != null) { zone = Zone.LIBRARY; diff --git a/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java index b74b8f771c..d4a61d6b65 100644 --- a/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java +++ b/Mage.Sets/src/mage/cards/b/BorderlandExplorer.java @@ -1,9 +1,5 @@ - package mage.cards.b; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -22,8 +18,11 @@ import mage.target.Target; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetDiscard; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BorderlandExplorer extends CardImpl { @@ -81,10 +80,9 @@ class BorderlandExplorerEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - Cards cards = new CardsImpl(); - Target target = new TargetDiscard(0, 1, new FilterCard(), playerId); + Target target = new TargetDiscard(0, 1, new FilterCard(), playerId); player.chooseTarget(outcome, target, source, game); - cards.addAll(target.getTargets()); + Cards cards = new CardsImpl(target.getTargets()); cardsToDiscard.put(playerId, cards); } } @@ -110,7 +108,7 @@ class BorderlandExplorerEffect extends OneShotEffect { Cards cardsPlayer = cardsToDiscard.get(playerId); if (cardsPlayer != null && !cardsPlayer.isEmpty()) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(target.getTargets()); cards.addAll(target.getTargets()); @@ -127,11 +125,13 @@ class BorderlandExplorerEffect extends OneShotEffect { Cards cardsPlayer = cardsToReveal.get(playerId); if (cardsPlayer != null) { for (UUID cardId : cardsPlayer) { - Cards cards = new CardsImpl(game.getCard(cardId)); Card card = game.getCard(cardId); - player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game); - player.moveCards(card, Zone.HAND, source, game); - player.shuffleLibrary(source, game); + Cards cards = new CardsImpl(game.getCard(cardId)); + if (card != null && !cards.isEmpty()) { + player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game); + player.moveCards(card, Zone.HAND, source, game); + player.shuffleLibrary(source, game); + } } } } diff --git a/Mage.Sets/src/mage/cards/b/BoreasCharger.java b/Mage.Sets/src/mage/cards/b/BoreasCharger.java index 151cdfab2f..4050b02399 100644 --- a/Mage.Sets/src/mage/cards/b/BoreasCharger.java +++ b/Mage.Sets/src/mage/cards/b/BoreasCharger.java @@ -114,7 +114,7 @@ class BoreasChargerEffect extends OneShotEffect { TargetCardInLibrary target2 = new TargetCardInLibrary(0, landDifference, filter2); Cards cardsToHand = new CardsImpl(); - if (controller.searchLibrary(target2, game)) { + if (controller.searchLibrary(target2, source, game)) { for (UUID cardId : target2.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/b/BorosCharm.java b/Mage.Sets/src/mage/cards/b/BorosCharm.java index 9264ea0620..b43d9a32a3 100644 --- a/Mage.Sets/src/mage/cards/b/BorosCharm.java +++ b/Mage.Sets/src/mage/cards/b/BorosCharm.java @@ -33,12 +33,12 @@ public final class BorosCharm extends CardImpl { Mode mode = new Mode(); Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledPermanent(), false); effect.setText("permanents you control are indestructible this turn"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); //or target creature gains double strike until end of turn. Mode mode2 = new Mode(); - mode2.getEffects().add(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); - mode2.getTargets().add(new TargetCreaturePermanent()); + mode2.addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); + mode2.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedGrace.java b/Mage.Sets/src/mage/cards/b/BorrowedGrace.java index 7029a62249..b9b9fa7bcd 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedGrace.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedGrace.java @@ -32,7 +32,7 @@ public final class BorrowedGrace extends CardImpl { // Creatures you control get +0/+2 until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); + mode.addEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java index bdcf746f21..dca3762339 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedHostility.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedHostility.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; @@ -16,8 +14,9 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BorrowedHostility extends CardImpl { @@ -26,7 +25,7 @@ public final class BorrowedHostility extends CardImpl { private static final FilterCreaturePermanent filterFirstStrike = new FilterCreaturePermanent("creature to gain first strike"); public BorrowedHostility(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Escalate {3} this.addAbility(new EscalateAbility(new ManaCostsImpl<>("{3}"))); @@ -38,15 +37,15 @@ public final class BorrowedHostility extends CardImpl { // Target creature gets +3/+0 until end of turn.; Effect effect = new BoostTargetEffect(3, 0, Duration.EndOfTurn); effect.setText("Target creature gets +3/+0 until end of turn"); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost)); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterBoost).withChooseHint("gets +3/+0 until end of turn")); // Target creature gains first strike until end of turn. Mode mode = new Mode(); effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains first strike until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterFirstStrike)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterFirstStrike).withChooseHint("gains first strike until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java index 3b985e8e6d..9c31246c70 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java +++ b/Mage.Sets/src/mage/cards/b/BorrowedMalevolence.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -14,8 +12,9 @@ import mage.constants.Duration; import mage.filter.common.FilterCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class BorrowedMalevolence extends CardImpl { @@ -24,7 +23,7 @@ public final class BorrowedMalevolence extends CardImpl { private static final FilterCreaturePermanent filterCreatureMinus = new FilterCreaturePermanent("creature to get -1/-1"); public BorrowedMalevolence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Escalate {2} this.addAbility(new EscalateAbility(new GenericManaCost(2))); @@ -37,14 +36,14 @@ public final class BorrowedMalevolence extends CardImpl { Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("Target creature gets +1/+1 until end of turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterCreaturePlus).withChooseHint("gets +1/+1 until end of turn")); // Target creature gets -1/-1 until end of turn. Mode mode = new Mode(); effect = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); effect.setText("Target creature gets -1/-1 until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterCreatureMinus)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -1/-1 until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java b/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java index 2d6bd827ee..47ba5f1cd4 100644 --- a/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java +++ b/Mage.Sets/src/mage/cards/b/Borrowing100000Arrows.java @@ -62,7 +62,7 @@ class Borrowing100000ArrowsEffect extends OneShotEffect { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (opponent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerIdPredicate(opponent.getId())); return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game)).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/b/BorrowingTheEastWind.java b/Mage.Sets/src/mage/cards/b/BorrowingTheEastWind.java index 9d5ab407c5..53f13e39be 100644 --- a/Mage.Sets/src/mage/cards/b/BorrowingTheEastWind.java +++ b/Mage.Sets/src/mage/cards/b/BorrowingTheEastWind.java @@ -27,7 +27,7 @@ public final class BorrowingTheEastWind extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G}{G}"); // Borrowing the East Wind deals X damage to each creature with horsemanship and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new ManacostVariableValue(), filter)); } + this.getSpellAbility().addEffect(new DamageEverythingEffect(ManacostVariableValue.instance, filter)); } public BorrowingTheEastWind(final BorrowingTheEastWind card) { super(card); diff --git a/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java b/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java index 9e19d3430a..5a8195beb8 100644 --- a/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java +++ b/Mage.Sets/src/mage/cards/b/BoseijuWhoSheltersAll.java @@ -62,7 +62,7 @@ class BoseijuWhoSheltersAllWatcher extends Watcher { private final String originalId; public BoseijuWhoSheltersAllWatcher(UUID originalId) { - super(BoseijuWhoSheltersAllWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); this.originalId = originalId.toString(); } @@ -137,7 +137,7 @@ class BoseijuWhoSheltersAllCantCounterEffect extends ContinuousRuleModifyingEffe @Override public boolean applies(GameEvent event, Ability source, Game game) { - BoseijuWhoSheltersAllWatcher watcher = (BoseijuWhoSheltersAllWatcher) game.getState().getWatchers().get(BoseijuWhoSheltersAllWatcher.class.getSimpleName(), source.getSourceId()); + BoseijuWhoSheltersAllWatcher watcher = game.getState().getWatcher(BoseijuWhoSheltersAllWatcher.class, source.getSourceId()); Spell spell = game.getStack().getSpell(event.getTargetId()); return spell != null && watcher != null && watcher.spellCantBeCountered(spell.getId()); } diff --git a/Mage.Sets/src/mage/cards/b/BottleOfSuleiman.java b/Mage.Sets/src/mage/cards/b/BottleOfSuleiman.java index efc5271eff..9d82fd071f 100644 --- a/Mage.Sets/src/mage/cards/b/BottleOfSuleiman.java +++ b/Mage.Sets/src/mage/cards/b/BottleOfSuleiman.java @@ -61,7 +61,7 @@ class BottleOfSuleimanEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); if (you != null) { - if (you.flipCoin(game)) { + if (you.flipCoin(source, game, true)) { DjinnToken token = new DjinnToken(); token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); return true; diff --git a/Mage.Sets/src/mage/cards/b/BottomlessVault.java b/Mage.Sets/src/mage/cards/b/BottomlessVault.java index 8bd5f7fa13..caad3bf15c 100644 --- a/Mage.Sets/src/mage/cards/b/BottomlessVault.java +++ b/Mage.Sets/src/mage/cards/b/BottomlessVault.java @@ -44,7 +44,7 @@ public final class BottomlessVault extends CardImpl { // {tap}, Remove any number of storage counters from Bottomless Vault: Add {B} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.BlackMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {B} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/b/BoundByMoonsilver.java b/Mage.Sets/src/mage/cards/b/BoundByMoonsilver.java index 58c5928fdb..6edd91e6fe 100644 --- a/Mage.Sets/src/mage/cards/b/BoundByMoonsilver.java +++ b/Mage.Sets/src/mage/cards/b/BoundByMoonsilver.java @@ -26,10 +26,10 @@ import java.util.UUID; */ public final class BoundByMoonsilver extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BoundByMoonsilver(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BoundlessRealms.java b/Mage.Sets/src/mage/cards/b/BoundlessRealms.java index bb84c4a6e0..6d8c76a0e6 100644 --- a/Mage.Sets/src/mage/cards/b/BoundlessRealms.java +++ b/Mage.Sets/src/mage/cards/b/BoundlessRealms.java @@ -70,7 +70,7 @@ class BoundlessRealmsEffect extends OneShotEffect { int amount = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); TargetCardInLibrary target = new TargetCardInLibrary(0, amount, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/b/BowOfNylea.java b/Mage.Sets/src/mage/cards/b/BowOfNylea.java index 015d08a910..f1897c10e6 100644 --- a/Mage.Sets/src/mage/cards/b/BowOfNylea.java +++ b/Mage.Sets/src/mage/cards/b/BowOfNylea.java @@ -56,18 +56,18 @@ public final class BowOfNylea extends CardImpl { ability.addCost(new TapSourceCost()); // or Bow of Nylea deals 2 damage to target creature with flying; Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(2)); + mode.addEffect(new DamageTargetEffect(2)); Target target = new TargetCreaturePermanent(filterFlying); - mode.getTargets().add(target); + mode.addTarget(target); ability.addMode(mode); // or you gain 3 life; mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(3)); + mode.addEffect(new GainLifeEffect(3)); ability.addMode(mode); // or put up to four target cards from your graveyard on the bottom of your library in any order. mode = new Mode(); - mode.getEffects().add(new PutCardsFromGraveyardToLibraryEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(0,4, new FilterCard())); + mode.addEffect(new PutCardsFromGraveyardToLibraryEffect()); + mode.addTarget(new TargetCardInYourGraveyard(0,4, new FilterCard())); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/b/BowerPassage.java b/Mage.Sets/src/mage/cards/b/BowerPassage.java index 2051063fd9..d1ae1ac1d8 100644 --- a/Mage.Sets/src/mage/cards/b/BowerPassage.java +++ b/Mage.Sets/src/mage/cards/b/BowerPassage.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -14,13 +12,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * @author noxx */ public final class BowerPassage extends CardImpl { public BowerPassage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Creatures with flying can't block creatures you control. @@ -59,11 +59,8 @@ class BowerPassageEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (attacker != null && attacker.isControlledBy(source.getControllerId()) && blocker.getAbilities().contains(FlyingAbility.getInstance())) { - return false; - } - return true; + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return attacker == null || !attacker.isControlledBy(source.getControllerId()) || !blocker.getAbilities().contains(FlyingAbility.getInstance()); } } diff --git a/Mage.Sets/src/mage/cards/b/BraceForImpact.java b/Mage.Sets/src/mage/cards/b/BraceForImpact.java index 9d45dbaedd..6b5a458592 100644 --- a/Mage.Sets/src/mage/cards/b/BraceForImpact.java +++ b/Mage.Sets/src/mage/cards/b/BraceForImpact.java @@ -25,7 +25,7 @@ public final class BraceForImpact extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("multicolored creature"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public BraceForImpact(UUID ownerId, CardSetInfo setInfo) { @@ -82,7 +82,7 @@ class BraceForImpactPreventDamageTargetEffect extends PreventionEffectImpl { Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); if (targetPermanent != null) { targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source, game); - game.informPlayers(new StringBuilder("Brace for Impact: Prevented ").append(prevented).append(" damage ").toString()); + game.informPlayers("Brace for Impact: Prevented " + prevented + " damage "); game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); } } diff --git a/Mage.Sets/src/mage/cards/b/BraidOfFire.java b/Mage.Sets/src/mage/cards/b/BraidOfFire.java index 40a2ba2f88..b211a5b7e6 100644 --- a/Mage.Sets/src/mage/cards/b/BraidOfFire.java +++ b/Mage.Sets/src/mage/cards/b/BraidOfFire.java @@ -49,9 +49,12 @@ class BraidOfFireCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player player = game.getPlayer(controllerId); - player.getManaPool().addMana(Mana.RedMana(1), game, ability); - paid = true; - return true; + if(player != null) { + player.getManaPool().addMana(Mana.RedMana(1), game, ability); + paid = true; + return true; + } + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BrainGorgers.java b/Mage.Sets/src/mage/cards/b/BrainGorgers.java index b704ffe496..056e52aa17 100644 --- a/Mage.Sets/src/mage/cards/b/BrainGorgers.java +++ b/Mage.Sets/src/mage/cards/b/BrainGorgers.java @@ -74,7 +74,7 @@ class BrainGorgersCounterSourceEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { cost.clearPaid(); Player player = game.getPlayer(playerId); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) + if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(outcome, "Sacrifice a creature to counter " + sourceObject.getIdName() + '?', source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { game.informPlayers(player.getLogName() + " sacrifices a creature to counter " + sourceObject.getIdName() + '.'); diff --git a/Mage.Sets/src/mage/cards/b/BrainInAJar.java b/Mage.Sets/src/mage/cards/b/BrainInAJar.java index 161a5c9fcc..7896994188 100644 --- a/Mage.Sets/src/mage/cards/b/BrainInAJar.java +++ b/Mage.Sets/src/mage/cards/b/BrainInAJar.java @@ -118,7 +118,7 @@ class BrainInAJarScryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int x = new RemovedCountersForCostValue().calculate(game, source, this); + int x = RemovedCountersForCostValue.instance.calculate(game, source, this); if (x > 0) { return controller.scry(x, source, game); } diff --git a/Mage.Sets/src/mage/cards/b/BrainPry.java b/Mage.Sets/src/mage/cards/b/BrainPry.java index 2bebd65d8d..4628af7111 100644 --- a/Mage.Sets/src/mage/cards/b/BrainPry.java +++ b/Mage.Sets/src/mage/cards/b/BrainPry.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -14,15 +12,17 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class BrainPry extends CardImpl { public BrainPry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); //Name a nonland card. Target player reveals their hand. That player discards a card with that name. If he or she can't, you draw a card. this.getSpellAbility().addEffect((new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.NON_LAND_NAME))); @@ -60,7 +60,7 @@ class BrainPryEffect extends OneShotEffect { if (targetPlayer != null && controller != null && sourceObject != null && cardName != null) { boolean hasDiscarded = false; for (Card card : targetPlayer.getHand().getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { targetPlayer.discard(card, source, game); hasDiscarded = true; break; diff --git a/Mage.Sets/src/mage/cards/b/Braingeyser.java b/Mage.Sets/src/mage/cards/b/Braingeyser.java index f3bd4083b0..75dad9a4f6 100644 --- a/Mage.Sets/src/mage/cards/b/Braingeyser.java +++ b/Mage.Sets/src/mage/cards/b/Braingeyser.java @@ -21,7 +21,7 @@ public final class Braingeyser extends CardImpl { // Target player draws X cards. - this.getSpellAbility().addEffect(new DrawCardTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/b/Brainspoil.java b/Mage.Sets/src/mage/cards/b/Brainspoil.java index d7422bbba5..f49bcc4a40 100644 --- a/Mage.Sets/src/mage/cards/b/Brainspoil.java +++ b/Mage.Sets/src/mage/cards/b/Brainspoil.java @@ -21,7 +21,7 @@ public final class Brainspoil extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that isn't enchanted"); static { - filter.add(Predicates.not(new EnchantedPredicate())); + filter.add(Predicates.not(EnchantedPredicate.instance)); } public Brainspoil(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BrambleSovereign.java b/Mage.Sets/src/mage/cards/b/BrambleSovereign.java index ab9ad76b56..caa98f8bf6 100644 --- a/Mage.Sets/src/mage/cards/b/BrambleSovereign.java +++ b/Mage.Sets/src/mage/cards/b/BrambleSovereign.java @@ -32,8 +32,8 @@ public final class BrambleSovereign extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); } public BrambleSovereign(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BranchingBolt.java b/Mage.Sets/src/mage/cards/b/BranchingBolt.java index dafaf25238..3e22522510 100644 --- a/Mage.Sets/src/mage/cards/b/BranchingBolt.java +++ b/Mage.Sets/src/mage/cards/b/BranchingBolt.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -18,8 +16,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class BranchingBolt extends CardImpl { @@ -33,19 +32,18 @@ public final class BranchingBolt extends CardImpl { } public BranchingBolt(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{G}"); // Choose one or both - this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); // Branching Bolt deals 3 damage to target creature with flying; this.getSpellAbility().addEffect(new DamageTargetEffect(3)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals 3 damage, without flying")); // or Branching Bolt deals 3 damage to target creature without flying. Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(3)); - mode.getTargets().add(new TargetCreaturePermanent(filterNotFlying)); + mode.addEffect(new DamageTargetEffect(3)); + mode.addTarget(new TargetCreaturePermanent(filterNotFlying).withChooseHint("deals 3 damage, without flying")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java b/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java index dd1acafed7..ddaaeedf9d 100644 --- a/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java +++ b/Mage.Sets/src/mage/cards/b/BrandedBrawlers.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,8 +8,8 @@ import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanen import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; @@ -21,17 +19,20 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * @author L_J */ public final class BrandedBrawlers extends CardImpl { static final private FilterLandPermanent filter = new FilterLandPermanent("an untapped land"); + static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } - - final static private String rule = "{this} can't block if you control an untapped land"; + + static final private String rule = "{this} can't block if you control an untapped land"; public BrandedBrawlers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); @@ -64,7 +65,7 @@ class BrandedBrawlersCantBlockEffect extends RestrictionEffect { public BrandedBrawlersCantBlockEffect(FilterPermanent filter) { super(Duration.WhileOnBattlefield); this.filter = filter; - staticText = new StringBuilder("{this} can't attack if you control ").append(filter.getMessage()).toString(); + staticText = "{this} can't attack if you control " + filter.getMessage(); } public BrandedBrawlersCantBlockEffect(final BrandedBrawlersCantBlockEffect effect) { @@ -78,12 +79,10 @@ class BrandedBrawlersCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { Player player = game.getPlayer(blocker.getControllerId()); if (player != null) { - if (game.getBattlefield().countAll(filter, player.getId(), game) > 0) { - return false; - } + return game.getBattlefield().countAll(filter, player.getId(), game) <= 0; } return true; } diff --git a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java index 4012646d0c..6d80495ed5 100644 --- a/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java +++ b/Mage.Sets/src/mage/cards/b/BrassTalonChimera.java @@ -1,4 +1,3 @@ - package mage.cards.b; import mage.MageInt; @@ -22,7 +21,6 @@ import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author TheElk801 */ public final class BrassTalonChimera extends CardImpl { @@ -43,9 +41,9 @@ public final class BrassTalonChimera extends CardImpl { // First strike this.addAbility(FirstStrikeAbility.getInstance()); - // Sacrifice Brass-Talon Chimera: Put a +2/+2 counter on target Chimera creature. It gains first strike. + // Sacrifice Brass-Talon Chimera: Put a +2/+2 counter on target Chimera creature. It gains first strike. (This effect lasts indefinitely.) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P2P2.createInstance()), new SacrificeSourceCost()); - ability.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield)); + ability.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield).setText("It gains first strike. (This effect lasts indefinitely.)")); ability.addTarget(new TargetCreaturePermanent(filter)); addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java b/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java index dd74b144c3..3d19290224 100644 --- a/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java +++ b/Mage.Sets/src/mage/cards/b/BreachingHippocamp.java @@ -23,7 +23,7 @@ public final class BreachingHippocamp extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BreachingHippocamp(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BreakOpen.java b/Mage.Sets/src/mage/cards/b/BreakOpen.java index fcfc4f81e1..275c9fc7fb 100644 --- a/Mage.Sets/src/mage/cards/b/BreakOpen.java +++ b/Mage.Sets/src/mage/cards/b/BreakOpen.java @@ -21,7 +21,7 @@ public final class BreakOpen extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Face-down creature an opponent controls"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/b/BreathstealersCrypt.java b/Mage.Sets/src/mage/cards/b/BreathstealersCrypt.java index 503f832836..aaeb5b471e 100644 --- a/Mage.Sets/src/mage/cards/b/BreathstealersCrypt.java +++ b/Mage.Sets/src/mage/cards/b/BreathstealersCrypt.java @@ -46,7 +46,7 @@ class BreathstealersCryptEffect extends ReplacementEffectImpl { public BreathstealersCryptEffect() { super(Duration.WhileOnBattlefield, Outcome.LoseLife); - staticText = "If a player would draw a card, instead he or she draws a card and reveals it. If it's a creature card, that player discards it unless he or she pays 3 life"; + staticText = "If a player would draw a card, instead they draw a card and reveal it. If it's a creature card, that player discards it unless they pay 3 life"; } public BreathstealersCryptEffect(final BreathstealersCryptEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java b/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java index 3f0c1e2985..ba36808b69 100644 --- a/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java +++ b/Mage.Sets/src/mage/cards/b/BreyaEtheriumShaper.java @@ -49,13 +49,13 @@ public final class BreyaEtheriumShaper extends CardImpl { // Target creature gets -4/-4 until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // or You gain 5 life. mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(5)); + mode.addEffect(new GainLifeEffect(5)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BriarberryCohort.java b/Mage.Sets/src/mage/cards/b/BriarberryCohort.java index ea7b0b7649..888f21eede 100644 --- a/Mage.Sets/src/mage/cards/b/BriarberryCohort.java +++ b/Mage.Sets/src/mage/cards/b/BriarberryCohort.java @@ -32,7 +32,7 @@ public final class BriarberryCohort extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private String rule = "{this} gets +1/+1 as long as you control another blue creature"; diff --git a/Mage.Sets/src/mage/cards/b/BriarbridgePatrol.java b/Mage.Sets/src/mage/cards/b/BriarbridgePatrol.java index 9995cf93e4..594613056f 100644 --- a/Mage.Sets/src/mage/cards/b/BriarbridgePatrol.java +++ b/Mage.Sets/src/mage/cards/b/BriarbridgePatrol.java @@ -56,7 +56,7 @@ enum BriarbridgePatrolCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PermanentsSacrificedWatcher watcher = (PermanentsSacrificedWatcher) game.getState().getWatchers().get(PermanentsSacrificedWatcher.class.getSimpleName()); + PermanentsSacrificedWatcher watcher = game.getState().getWatcher(PermanentsSacrificedWatcher.class); if (watcher != null) { List sacrificedPermanents = watcher.getThisTurnSacrificedPermanents(source.getControllerId()); if (sacrificedPermanents != null && !sacrificedPermanents.isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/b/Bribery.java b/Mage.Sets/src/mage/cards/b/Bribery.java index 86e930dfbe..ba5979ca67 100644 --- a/Mage.Sets/src/mage/cards/b/Bribery.java +++ b/Mage.Sets/src/mage/cards/b/Bribery.java @@ -62,7 +62,7 @@ class BriberyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && opponent != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, new FilterCreatureCard("creature card")); - if (controller.searchLibrary(target, game, opponent.getId())) { + if (controller.searchLibrary(target, source, game, opponent.getId())) { Card card = opponent.getLibrary().getCard(target.getFirstTarget(), game); controller.moveCards(card, Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java index fb1f645ac0..21da232f16 100644 --- a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java +++ b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java @@ -34,7 +34,7 @@ public final class BridgeFromBelow extends CardImpl { static{ filter1.add(new ControllerPredicate(TargetController.YOU)); - filter1.add(Predicates.not(new TokenPredicate())); + filter1.add(Predicates.not(TokenPredicate.instance)); filter2.add(new ControllerPredicate(TargetController.OPPONENT)); } @@ -84,7 +84,7 @@ class BridgeFromBelowAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/b/Brightflame.java b/Mage.Sets/src/mage/cards/b/Brightflame.java index 8e70b4a364..54f8ab2edf 100644 --- a/Mage.Sets/src/mage/cards/b/Brightflame.java +++ b/Mage.Sets/src/mage/cards/b/Brightflame.java @@ -29,7 +29,7 @@ public final class Brightflame extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}{R}{W}{W}"); // Radiance - Brightflame deals X damage to target creature and each other creature that shares a color with it. You gain life equal to the damage dealt this way. - this.getSpellAbility().addEffect(new BrightflameEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new BrightflameEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().setAbilityWord(AbilityWord.RADIANCE); } diff --git a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java index c9bad9c5c7..4dc433e7c1 100644 --- a/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java +++ b/Mage.Sets/src/mage/cards/b/BrilliantUltimatum.java @@ -1,4 +1,3 @@ - package mage.cards.b; import java.util.ArrayList; @@ -111,6 +110,7 @@ class BrilliantUltimatumEffect extends OneShotEffect { TargetCard targetExiledCard = new TargetCard(Zone.EXILED, new FilterCard()); if (controller.chooseTarget(Outcome.PlayForFree, selectedPile, targetExiledCard, source, game)) { Card card = selectedPile.get(targetExiledCard.getFirstTarget(), game); + controller.canPlayLand(); if (controller.playCard(card, game, true, true, new MageObjectReference(source.getSourceObject(game), game))) { selectedPileCards.remove(card); selectedPile.remove(card); diff --git a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java index dd37a947c6..d0fca03525 100644 --- a/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java +++ b/Mage.Sets/src/mage/cards/b/BrimstoneVolley.java @@ -53,8 +53,8 @@ class BrimstoneVolleyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int damage = 3; - Watcher watcher = game.getState().getWatchers().get(MorbidWatcher.class.getSimpleName()); - if (watcher.conditionMet()) { + MorbidWatcher watcher = game.getState().getWatcher(MorbidWatcher.class); + if (watcher != null && watcher.conditionMet()) { damage = 5; } Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/b/BrineHag.java b/Mage.Sets/src/mage/cards/b/BrineHag.java new file mode 100644 index 0000000000..5050409b69 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BrineHag.java @@ -0,0 +1,93 @@ + +package mage.cards.b; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.PermanentInListPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public final class BrineHag extends CardImpl { + + public BrineHag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + this.subtype.add(SubType.HAG); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Brine Hag dies, change the base power and toughness of all creatures that dealt damage to it this turn to 0/2. + this.addAbility(new DiesTriggeredAbility(new BrineHagEffect())); + } + + public BrineHag(final BrineHag card) { + super(card); + } + + @Override + public BrineHag copy() { + return new BrineHag(this); + } +} + +class BrineHagEffect extends OneShotEffect { + + public BrineHagEffect() { + super(Outcome.Detriment); + this.staticText = "change the base power and toughness of all creatures that dealt damage to it this turn to 0/2"; + } + + public BrineHagEffect(final BrineHagEffect effect) { + super(effect); + } + + @Override + public BrineHagEffect copy() { + return new BrineHagEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourcePermanent != null) { + List list = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { + if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { + list.add(creature); + } + } + } + } + if (!list.isEmpty()) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new PermanentInListPredicate(list)); + game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrineShaman.java b/Mage.Sets/src/mage/cards/b/BrineShaman.java index 2a2d0398ca..a19445b707 100644 --- a/Mage.Sets/src/mage/cards/b/BrineShaman.java +++ b/Mage.Sets/src/mage/cards/b/BrineShaman.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,31 +12,21 @@ import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterSpell; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; - import mage.filter.StaticFilters; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetSpell; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author TheElk801 */ public final class BrineShaman extends CardImpl { - private static final FilterSpell filter = new FilterSpell("creature spell"); - - static { - filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); - } - public BrineShaman(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); @@ -46,16 +35,14 @@ public final class BrineShaman extends CardImpl { this.toughness = new MageInt(1); // {tap}, Sacrifice a creature: Target creature gets +2/+2 until end of turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(2, 2, Duration.EndOfTurn), - new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); - ability.addCost(new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new BoostTargetEffect(2, 2), new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); // {1}{U}{U}, Sacrifice a creature: Counter target creature spell. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CounterTargetEffect(), - new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); - ability.addCost(new ManaCostsImpl("{1}{U}{U}")); + ability = new SimpleActivatedAbility(new CounterTargetEffect(), new ManaCostsImpl("{1}{U}{U}")); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BringToLight.java b/Mage.Sets/src/mage/cards/b/BringToLight.java index 45971d1cd1..1f10c21b5c 100644 --- a/Mage.Sets/src/mage/cards/b/BringToLight.java +++ b/Mage.Sets/src/mage/cards/b/BringToLight.java @@ -74,7 +74,7 @@ class BringToLightEffect extends OneShotEffect { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, numberColors + 1)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - controller.searchLibrary(target, game); + controller.searchLibrary(target, source, game); Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.EXILED, source, game); diff --git a/Mage.Sets/src/mage/cards/b/BringToTrial.java b/Mage.Sets/src/mage/cards/b/BringToTrial.java new file mode 100644 index 0000000000..bf7b058150 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BringToTrial.java @@ -0,0 +1,42 @@ +package mage.cards.b; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class BringToTrial extends CardImpl { + + static private final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public BringToTrial(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}"); + + + // Exile target creature with power 4 or greater. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public BringToTrial(final BringToTrial card) { + super(card); + } + + @Override + public BringToTrial copy() { + return new BringToTrial(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BrionStoutarm.java b/Mage.Sets/src/mage/cards/b/BrionStoutarm.java index f6939807c7..a39a9e1060 100644 --- a/Mage.Sets/src/mage/cards/b/BrionStoutarm.java +++ b/Mage.Sets/src/mage/cards/b/BrionStoutarm.java @@ -30,7 +30,7 @@ public final class BrionStoutarm extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature other than Brion Stoutarm"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BrionStoutarm(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BrokenAmbitions.java b/Mage.Sets/src/mage/cards/b/BrokenAmbitions.java index 484e49a210..b9d4be4d1a 100644 --- a/Mage.Sets/src/mage/cards/b/BrokenAmbitions.java +++ b/Mage.Sets/src/mage/cards/b/BrokenAmbitions.java @@ -30,7 +30,7 @@ public final class BrokenAmbitions extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); // Counter target spell unless its controller pays {X}. Clash with an opponent. If you win, that spell's controller puts the top four cards of their library into their graveyard. - this.getSpellAbility().addEffect(new BrokenAmbitionsEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new BrokenAmbitionsEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetSpell()); } diff --git a/Mage.Sets/src/mage/cards/b/BrokenVisage.java b/Mage.Sets/src/mage/cards/b/BrokenVisage.java index e250769885..495b05ec36 100644 --- a/Mage.Sets/src/mage/cards/b/BrokenVisage.java +++ b/Mage.Sets/src/mage/cards/b/BrokenVisage.java @@ -31,7 +31,7 @@ public final class BrokenVisage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonartifact attacking creature"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public BrokenVisage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BronzeHorse.java b/Mage.Sets/src/mage/cards/b/BronzeHorse.java new file mode 100644 index 0000000000..bcd1ed3166 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BronzeHorse.java @@ -0,0 +1,91 @@ + +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalReplacementEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.Target; + +/** + * + * @author L_J + */ +public final class BronzeHorse extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + } + + public BronzeHorse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{7}"); + this.subtype.add(SubType.HORSE); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // As long as you control another creature, prevent all damage that would be dealt to Bronze Horse by spells that target it. + Effect effect = new ConditionalReplacementEffect(new PreventDamageToSourceBySpellsThatTargetIt(), new PermanentsOnTheBattlefieldCondition(filter)); + effect.setText("As long as you control another creature, prevent all damage that would be dealt to {this} by spells that target it."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public BronzeHorse(final BronzeHorse card) { + super(card); + } + + @Override + public BronzeHorse copy() { + return new BronzeHorse(this); + } +} + +class PreventDamageToSourceBySpellsThatTargetIt extends PreventAllDamageToSourceEffect { + + public PreventDamageToSourceBySpellsThatTargetIt() { + super(Duration.WhileOnBattlefield); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getSourceId())) { + Spell spell = game.getStack().getSpell(event.getSourceId()); + if (spell != null) { + for (UUID modeId : spell.getStackAbility().getModes().getSelectedModes()) { + Mode mode = spell.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetId : target.getTargets()) { + if (targetId.equals(source.getSourceId())) { + return true; + } + } + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/b/BronzebeakMoa.java b/Mage.Sets/src/mage/cards/b/BronzebeakMoa.java index b8d9f77917..949498cd93 100644 --- a/Mage.Sets/src/mage/cards/b/BronzebeakMoa.java +++ b/Mage.Sets/src/mage/cards/b/BronzebeakMoa.java @@ -25,7 +25,7 @@ public final class BronzebeakMoa extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature under your control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BronzebeakMoa (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{W}"); diff --git a/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java index cb7d25fffe..cd838bcfd0 100644 --- a/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java +++ b/Mage.Sets/src/mage/cards/b/BroodOfCockroaches.java @@ -1,34 +1,33 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.game.Game; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + import static mage.constants.Outcome.Benefit; /** - * * @author mpouedras */ public final class BroodOfCockroaches extends CardImpl { public BroodOfCockroaches(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); - + this.subtype.add(SubType.INSECT); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -37,7 +36,7 @@ public final class BroodOfCockroaches extends CardImpl { // at the beginning of the next end step, // you lose 1 life // and return Brood of Cockroaches to your hand. - this.addAbility(new DiesTriggeredAbility(new BroodOfCockroachesEffect())); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new BroodOfCockroachesEffect(), false, true)); } public BroodOfCockroaches(final BroodOfCockroaches card) { @@ -51,7 +50,7 @@ public final class BroodOfCockroaches extends CardImpl { } class BroodOfCockroachesEffect extends OneShotEffect { - private static final String effectText = "at the beginning of the next end step, you lose 1 life and return Brood of Cockroaches to your hand."; + private static final String effectText = "at the beginning of the next end step, you lose 1 life and return {this} to your hand."; BroodOfCockroachesEffect() { super(Benefit); diff --git a/Mage.Sets/src/mage/cards/b/BroodingSaurian.java b/Mage.Sets/src/mage/cards/b/BroodingSaurian.java index 9b71bf2e91..221feab710 100644 --- a/Mage.Sets/src/mage/cards/b/BroodingSaurian.java +++ b/Mage.Sets/src/mage/cards/b/BroodingSaurian.java @@ -50,7 +50,7 @@ class BroodingSaurianControlEffect extends ContinuousEffectImpl { private static final FilterPermanent filter = new FilterPermanent(); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public BroodingSaurianControlEffect() { diff --git a/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java b/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java index 1cfb85d324..bacf632163 100644 --- a/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java +++ b/Mage.Sets/src/mage/cards/b/BrothersYamazaki.java @@ -31,7 +31,7 @@ public final class BrothersYamazaki extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new NamePredicate("Brothers Yamazaki")); } diff --git a/Mage.Sets/src/mage/cards/b/Browbeat.java b/Mage.Sets/src/mage/cards/b/Browbeat.java index ac5df5f4fa..4bc1a4a7e5 100644 --- a/Mage.Sets/src/mage/cards/b/Browbeat.java +++ b/Mage.Sets/src/mage/cards/b/Browbeat.java @@ -2,6 +2,7 @@ package mage.cards.b; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -15,13 +16,12 @@ import mage.players.Player; import mage.target.TargetPlayer; /** - * * @author dustinconrad */ public final class Browbeat extends CardImpl { public Browbeat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); // Any player may have Browbeat deal 5 damage to him or her. If no one does, target player draws three cards. this.getSpellAbility().addEffect(new BrowbeatDrawEffect()); @@ -61,16 +61,16 @@ class BrowbeatDrawEffect extends OneShotEffect { return false; } StackObject spell = null; - for(StackObject object : game.getStack()){ - if(object instanceof Spell && object.getSourceId().equals(source.getSourceId())){ + for (StackObject object : game.getStack()) { + if (object instanceof Spell && object.getSourceId().equals(source.getSourceId())) { spell = object; } } - if(spell != null){ + if (spell != null) { boolean drawCards = true; - for(UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)){ + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getLogName() + " deal 5 damage to you?", source, game)){ + if (player != null && player.chooseUse(Outcome.Detriment, "Have " + spell.getLogName() + " deal 5 damage to you?", source, game)) { drawCards = false; player.damage(5, source.getSourceId(), game, false, true); game.informPlayers(player.getLogName() + " has " + spell.getLogName() + " deal 5 to him or her"); @@ -80,7 +80,9 @@ class BrowbeatDrawEffect extends OneShotEffect { UUID targetPlayer = getTargetPointer().getFirst(game, source); if (targetPlayer != null) { Player player = game.getPlayer(targetPlayer); - player.drawCards(3, game); + if (player != null) { + player.drawCards(3, game); + } } } return drawCards; diff --git a/Mage.Sets/src/mage/cards/b/BrownOuphe.java b/Mage.Sets/src/mage/cards/b/BrownOuphe.java index b7ba3b157a..d41d846a2d 100644 --- a/Mage.Sets/src/mage/cards/b/BrownOuphe.java +++ b/Mage.Sets/src/mage/cards/b/BrownOuphe.java @@ -24,7 +24,7 @@ import mage.target.common.TargetActivatedAbility; */ public final class BrownOuphe extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private static final FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); diff --git a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java index 52e0b75f3c..ef8d9f5b94 100644 --- a/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java +++ b/Mage.Sets/src/mage/cards/b/BrudicladTelchorEngineer.java @@ -31,7 +31,7 @@ public final class BrudicladTelchorEngineer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature tokens you control"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public BrudicladTelchorEngineer(UUID ownerId, CardSetInfo setInfo) { @@ -64,7 +64,7 @@ class BrudicladTelchorEngineerEffect extends OneShotEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("token you control"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public BrudicladTelchorEngineerEffect() { @@ -84,6 +84,9 @@ class BrudicladTelchorEngineerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if(controller == null){ + return false; + } CreateTokenEffect effect = new CreateTokenEffect(new BrudicladTelchorMyrToken(), 1); if (effect.apply(game, source)) { diff --git a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java index 51d2776146..da36417d90 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java +++ b/Mage.Sets/src/mage/cards/b/BrutalExpulsion.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; @@ -18,13 +16,15 @@ import mage.target.common.TargetCreatureOrPlaneswalker; import mage.target.common.TargetSpellOrPermanent; import mage.watchers.common.DamagedByWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BrutalExpulsion extends CardImpl { private static final FilterSpellOrPermanent filter = new FilterSpellOrPermanent("spell or creature"); + static { filter.setPermanentFilter(new FilterCreaturePermanent()); } @@ -39,15 +39,15 @@ public final class BrutalExpulsion extends CardImpl { this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); // - Return target spell or creature to its owner's hand; - this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false)); this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpellOrPermanent(1, 1, filter, false).withChooseHint("return to its owner's hand")); // or Brutal Expulsion deals 2 damage to target creature or planeswalker. If that permanent would be put into a graveyard this turn, exile it instead. Mode mode = new Mode(); - mode.getTargets().add(new TargetCreatureOrPlaneswalker()); - mode.getEffects().add(new DamageTargetEffect(2)); + mode.addEffect(new DamageTargetEffect(2)); Effect effect = new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn); effect.setText("If that permanent would be put into a graveyard this turn, exile it instead"); - mode.getEffects().add(effect); + mode.addEffect(effect); + mode.addTarget(new TargetCreatureOrPlaneswalker().withChooseHint("deals 2 damage and exile instead")); this.getSpellAbility().addMode(mode); this.getSpellAbility().addWatcher(new DamagedByWatcher(true)); } diff --git a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java index e3b37d6800..c6e43f6dc7 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalHordechief.java +++ b/Mage.Sets/src/mage/cards/b/BrutalHordechief.java @@ -74,7 +74,7 @@ public final class BrutalHordechief extends CardImpl { @Override public boolean apply(Game game, Ability source) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); if (watcher != null) { watcher.increment(); return true; @@ -155,7 +155,10 @@ class BrutalHordechiefChooseBlockersEffect extends ContinuousRuleModifyingEffect @Override public boolean applies(GameEvent event, Ability source, Game game) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); + if(watcher == null){ + return false; + } watcher.decrement(); if (watcher.copyCountApply > 0) { game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); diff --git a/Mage.Sets/src/mage/cards/b/BrutalSuppression.java b/Mage.Sets/src/mage/cards/b/BrutalSuppression.java index e45580406e..0d33236877 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalSuppression.java +++ b/Mage.Sets/src/mage/cards/b/BrutalSuppression.java @@ -58,7 +58,7 @@ class BrutalSuppressionAdditionalCostEffect extends CostModificationEffectImpl { private static final FilterPermanent filter2 = new FilterPermanent("nontoken Rebels"); static{ filter2.add(new SubtypePredicate(SubType.REBEL)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } BrutalSuppressionAdditionalCostEffect() { diff --git a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java index 7b5168057f..39e2f957b2 100644 --- a/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java +++ b/Mage.Sets/src/mage/cards/b/BrutalizerExarch.java @@ -49,8 +49,8 @@ public final class BrutalizerExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new SearchLibraryPutOnLibraryEffect(target, true, true), false); // or put target noncreature permanent on the bottom of its owner's library. Mode mode = new Mode(); - mode.getEffects().add(new BrutalizerExarchEffect2()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new BrutalizerExarchEffect2()); + mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/b/BubblingCauldron.java b/Mage.Sets/src/mage/cards/b/BubblingCauldron.java index 01dd111c02..92e311577f 100644 --- a/Mage.Sets/src/mage/cards/b/BubblingCauldron.java +++ b/Mage.Sets/src/mage/cards/b/BubblingCauldron.java @@ -1,4 +1,3 @@ - package mage.cards.b; import java.util.UUID; @@ -61,7 +60,7 @@ public final class BubblingCauldron extends CardImpl { class BubblingCauldronEffect extends OneShotEffect { public BubblingCauldronEffect() { - super(Outcome.Damage); + super(Outcome.GainLife); staticText = "Each opponent loses 4 life. You gain life equal to the life lost this way"; } @@ -71,12 +70,17 @@ class BubblingCauldronEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int damage = 0; + int lostLife = 0; + Player controller = game.getPlayer(source.getControllerId()); for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); - damage += opponent.loseLife(4, game, false); + if (opponent != null) { + lostLife += opponent.loseLife(4, game, false); + } + } + if (controller != null) { + controller.gainLife(lostLife, game, source); } - game.getPlayer(source.getControllerId()).gainLife(damage, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java b/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java index 45f1695281..f20894e3e9 100644 --- a/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java +++ b/Mage.Sets/src/mage/cards/b/BuccaneersBravado.java @@ -39,9 +39,9 @@ public final class BuccaneersBravado extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains first strike until end of turn")); // Target Pirate gets +1/+1 and gains double strike until end of turn. Mode mode = new Mode(); - mode.getTargets().add(new TargetPermanent(filter)); - mode.getEffects().add(new BoostTargetEffect(1, 1, Duration.EndOfTurn).setText("Target Pirate gets +1/+1")); - mode.getEffects().add(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains double strike until end of turn")); + mode.addTarget(new TargetPermanent(filter)); + mode.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn).setText("Target Pirate gets +1/+1")); + mode.addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn).setText("and gains double strike until end of turn")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/b/BudokaGardener.java b/Mage.Sets/src/mage/cards/b/BudokaGardener.java index 6bf5ead6b2..309f398046 100644 --- a/Mage.Sets/src/mage/cards/b/BudokaGardener.java +++ b/Mage.Sets/src/mage/cards/b/BudokaGardener.java @@ -56,7 +56,7 @@ public final class BudokaGardener extends CardImpl { class BudokaGardenerEffect extends OneShotEffect { - final static FilterControlledPermanent filterLands = new FilterControlledLandPermanent("lands you control"); + static final FilterControlledPermanent filterLands = new FilterControlledLandPermanent("lands you control"); BudokaGardenerEffect() { super(Outcome.PutLandInPlay); diff --git a/Mage.Sets/src/mage/cards/b/BuildersBane.java b/Mage.Sets/src/mage/cards/b/BuildersBane.java index 094a17f47e..7ee8821d2e 100644 --- a/Mage.Sets/src/mage/cards/b/BuildersBane.java +++ b/Mage.Sets/src/mage/cards/b/BuildersBane.java @@ -1,11 +1,7 @@ package mage.cards.b; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,9 +12,13 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetArtifactPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** - * * @author sinsedrix */ public final class BuildersBane extends CardImpl { @@ -29,15 +29,7 @@ public final class BuildersBane extends CardImpl { // Destroy X target artifacts. Builder's Bane deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way. this.getSpellAbility().addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addEffect(new BuildersBaneEffect()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); - } + this.getSpellAbility().setTargetAdjuster(BuildersBaneAdjuster.instance); } public BuildersBane(final BuildersBane card) { @@ -50,11 +42,22 @@ public final class BuildersBane extends CardImpl { } } +enum BuildersBaneAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); + } +} + class BuildersBaneEffect extends OneShotEffect { public BuildersBaneEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy X target artifacts. {this} deals damage to each player equal to the number of artifacts he or she controlled put into a graveyard this way"; + this.staticText = "Destroy X target artifacts. {this} deals damage to each player equal to the number of artifacts they controlled that were put into a graveyard this way"; } public BuildersBaneEffect(final BuildersBaneEffect effect) { diff --git a/Mage.Sets/src/mage/cards/b/BullAurochs.java b/Mage.Sets/src/mage/cards/b/BullAurochs.java index 7f4e83734d..7da88699f1 100644 --- a/Mage.Sets/src/mage/cards/b/BullAurochs.java +++ b/Mage.Sets/src/mage/cards/b/BullAurochs.java @@ -27,7 +27,7 @@ public final class BullAurochs extends CardImpl { static { filter.add(new SubtypePredicate(SubType.AUROCHS)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BullAurochs(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BullRancor.java b/Mage.Sets/src/mage/cards/b/BullRancor.java index 00a101067b..00ed2000ab 100644 --- a/Mage.Sets/src/mage/cards/b/BullRancor.java +++ b/Mage.Sets/src/mage/cards/b/BullRancor.java @@ -9,6 +9,7 @@ import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.MonstrosityAbility; +import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -28,6 +29,9 @@ public final class BullRancor extends CardImpl { this.power = new MageInt(7); this.toughness = new MageInt(7); + // Trample + this.addAbility(TrampleAbility.getInstance()); + // {3}{R}{G}{G}{W}: Monstrosity 3. this.addAbility(new MonstrosityAbility("{3}{R}{G}{G}{W}", 3)); diff --git a/Mage.Sets/src/mage/cards/b/BullRushBruiser.java b/Mage.Sets/src/mage/cards/b/BullRushBruiser.java index ac0cfeaab9..b89ace249d 100644 --- a/Mage.Sets/src/mage/cards/b/BullRushBruiser.java +++ b/Mage.Sets/src/mage/cards/b/BullRushBruiser.java @@ -24,7 +24,7 @@ public final class BullRushBruiser extends CardImpl { private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "another Warrior"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public BullRushBruiser(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/b/BulwarkGiant.java b/Mage.Sets/src/mage/cards/b/BulwarkGiant.java new file mode 100644 index 0000000000..95b8bc793d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BulwarkGiant.java @@ -0,0 +1,38 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +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 BulwarkGiant extends CardImpl { + + public BulwarkGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // When Bulwark Giant enters the battlefield, you gain 5 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(5))); + } + + private BulwarkGiant(final BulwarkGiant card) { + super(card); + } + + @Override + public BulwarkGiant copy() { + return new BulwarkGiant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java b/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java index 124aac6ceb..2f8ad795d0 100644 --- a/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java +++ b/Mage.Sets/src/mage/cards/b/BurdenOfGreed.java @@ -48,7 +48,7 @@ class BurdenOfGreedCount implements DynamicValue { return 0; } FilterArtifactPermanent filter = new FilterArtifactPermanent(); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerIdPredicate(sourceAbility.getFirstTarget())); return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); } diff --git a/Mage.Sets/src/mage/cards/b/BuriedAlive.java b/Mage.Sets/src/mage/cards/b/BuriedAlive.java index fab3129c81..ca43d18192 100644 --- a/Mage.Sets/src/mage/cards/b/BuriedAlive.java +++ b/Mage.Sets/src/mage/cards/b/BuriedAlive.java @@ -61,7 +61,7 @@ class BuriedAliveEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/b/BurnAtTheStake.java b/Mage.Sets/src/mage/cards/b/BurnAtTheStake.java index b804747d35..7707490f2d 100644 --- a/Mage.Sets/src/mage/cards/b/BurnAtTheStake.java +++ b/Mage.Sets/src/mage/cards/b/BurnAtTheStake.java @@ -27,7 +27,7 @@ public final class BurnAtTheStake extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public BurnAtTheStake(UUID ownerId, CardSetInfo setInfo) { @@ -69,7 +69,7 @@ class BurnAtTheStakeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = (new GetXValue()).calculate(game, source, this) * 3; + int amount = (GetXValue.instance).calculate(game, source, this) * 3; Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/b/BurnBright.java b/Mage.Sets/src/mage/cards/b/BurnBright.java new file mode 100644 index 0000000000..bfc8e02a9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurnBright.java @@ -0,0 +1,31 @@ +package mage.cards.b; + +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class BurnBright extends CardImpl { + + public BurnBright(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); + + // Creatures you control get +2/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn)); + } + + private BurnBright(final BurnBright card) { + super(card); + } + + @Override + public BurnBright copy() { + return new BurnBright(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java index 1585222ed7..6cda9d99ce 100644 --- a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java +++ b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java @@ -184,7 +184,7 @@ class BurningCinderFuryOfCrimsonChaosFireCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - BurningCinderFuryOfCrimsonChaosFireWatcher watcher = (BurningCinderFuryOfCrimsonChaosFireWatcher) game.getState().getWatchers().get(BurningCinderFuryOfCrimsonChaosFireWatcher.class.getSimpleName()); + BurningCinderFuryOfCrimsonChaosFireWatcher watcher = game.getState().getWatcher(BurningCinderFuryOfCrimsonChaosFireWatcher.class); if (watcher != null) { return !watcher.tappedNonlandThisTurn(game.getActivePlayerId()); } @@ -201,7 +201,7 @@ class BurningCinderFuryOfCrimsonChaosFireWatcher extends Watcher { private final Set tappedActivePlayerIds = new HashSet<>(); public BurningCinderFuryOfCrimsonChaosFireWatcher() { - super(BurningCinderFuryOfCrimsonChaosFireWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public BurningCinderFuryOfCrimsonChaosFireWatcher(final BurningCinderFuryOfCrimsonChaosFireWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/b/BurningEarth.java b/Mage.Sets/src/mage/cards/b/BurningEarth.java index 885b551720..901829dc53 100644 --- a/Mage.Sets/src/mage/cards/b/BurningEarth.java +++ b/Mage.Sets/src/mage/cards/b/BurningEarth.java @@ -19,7 +19,7 @@ import mage.filter.predicate.mageobject.SupertypePredicate; */ public final class BurningEarth extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent("a player taps a nonbasic land"); + private static final FilterLandPermanent filter = new FilterLandPermanent("a player taps a nonbasic land"); static { filter.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); diff --git a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java index 1d7ff56bc7..16a159d914 100644 --- a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java +++ b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java @@ -89,7 +89,7 @@ class BurningOfXinyeEffect extends OneShotEffect{ } for ( int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent((UUID)target.getTargets().get(idx)); + Permanent permanent = game.getPermanent(target.getTargets().get(idx)); if ( permanent != null ) { abilityApplied |= permanent.destroy(source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/b/BurningProphet.java b/Mage.Sets/src/mage/cards/b/BurningProphet.java new file mode 100644 index 0000000000..1fd95238a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurningProphet.java @@ -0,0 +1,48 @@ +package mage.cards.b; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +/** + * @author TheElk801 + */ +public final class BurningProphet extends CardImpl { + + public BurningProphet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever you cast a noncreature spell, Burning Prophet gets +1/+0 until end of turn, then scry 1. + Ability ability = new SpellCastControllerTriggeredAbility( + new BoostSourceEffect( + 1, 0, Duration.EndOfTurn + ).setText("{this} gets +1/+0 until end of turn, then"), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + ); + ability.addEffect(new ScryEffect(1)); + this.addAbility(ability); + } + + private BurningProphet(final BurningProphet card) { + super(card); + } + + @Override + public BurningProphet copy() { + return new BurningProphet(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/BurningSands.java b/Mage.Sets/src/mage/cards/b/BurningSands.java index a8c0af943b..01f30e5a5d 100644 --- a/Mage.Sets/src/mage/cards/b/BurningSands.java +++ b/Mage.Sets/src/mage/cards/b/BurningSands.java @@ -1,7 +1,6 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.common.SacrificeEffect; @@ -12,39 +11,29 @@ import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class BurningSands extends CardImpl { - private final UUID originalId; - public BurningSands(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); // Whenever a creature dies, that creature's controller sacrifices a land. - Ability ability = new DiesCreatureTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_LAND, 1, "that creature's controller"), false, false, true); - originalId = ability.getOriginalId(); + Ability ability = new DiesCreatureTriggeredAbility(new SacrificeEffect( + StaticFilters.FILTER_LAND, 1, "that creature's controller" + ), false, false, true); + ability.setTargetAdjuster(BurningSandsAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - UUID creatureId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); - Permanent creature = (Permanent) game.getLastKnownInformation(creatureId, Zone.BATTLEFIELD); - if (creature != null) { - ability.getEffects().get(0).setTargetPointer(new FixedTarget(creature.getControllerId())); - } - } - } - public BurningSands(final BurningSands card) { super(card); - this.originalId = card.originalId; } @Override @@ -52,3 +41,16 @@ public final class BurningSands extends CardImpl { return new BurningSands(this); } } + +enum BurningSandsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + UUID creatureId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + Permanent creature = game.getPermanentOrLKIBattlefield(creatureId); + if (creature != null) { + ability.getEffects().get(0).setTargetPointer(new FixedTarget(creature.getControllerId())); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java index 52fd5e5c25..18b29ddd9b 100644 --- a/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java +++ b/Mage.Sets/src/mage/cards/b/BurningTreeShaman.java @@ -1,7 +1,5 @@ - package mage.cards.b; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.dynamicvalue.common.StaticValue; @@ -19,14 +17,15 @@ import mage.game.events.GameEvent.EventType; import mage.game.stack.StackAbility; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class BurningTreeShaman extends CardImpl { public BurningTreeShaman(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); this.subtype.add(SubType.CENTAUR, SubType.SHAMAN); this.power = new MageInt(3); @@ -49,7 +48,7 @@ public final class BurningTreeShaman extends CardImpl { class BurningTreeShamanTriggeredAbility extends TriggeredAbilityImpl { BurningTreeShamanTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(1), false, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(1), true, "that player", true)); } BurningTreeShamanTriggeredAbility(final BurningTreeShamanTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/b/BurningTreeVandal.java b/Mage.Sets/src/mage/cards/b/BurningTreeVandal.java new file mode 100644 index 0000000000..fe6ea62ee9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BurningTreeVandal.java @@ -0,0 +1,46 @@ +package mage.cards.b; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.RiotAbility; +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 BurningTreeVandal extends CardImpl { + + public BurningTreeVandal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Riot + this.addAbility(new RiotAbility()); + + // Whenever Burning-Tree Vandal attacks, you may discard a card. If you do, draw a card. + this.addAbility(new AttacksTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(1), new DiscardCardCost() + ), false)); + } + + private BurningTreeVandal(final BurningTreeVandal card) { + super(card); + } + + @Override + public BurningTreeVandal copy() { + return new BurningTreeVandal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/b/ByForce.java b/Mage.Sets/src/mage/cards/b/ByForce.java index 2263b8fc36..5c42282251 100644 --- a/Mage.Sets/src/mage/cards/b/ByForce.java +++ b/Mage.Sets/src/mage/cards/b/ByForce.java @@ -1,18 +1,18 @@ package mage.cards.b; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.Game; import mage.target.common.TargetArtifactPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author spjspj */ public final class ByForce extends CardImpl { @@ -23,15 +23,7 @@ public final class ByForce extends CardImpl { // Destroy X target artifacts. this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy X target artifacts")); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); - } + this.getSpellAbility().setTargetAdjuster(ByForceAdjuster.instance); } public ByForce(final ByForce card) { @@ -43,3 +35,14 @@ public final class ByForce extends CardImpl { return new ByForce(this); } } + +enum ByForceAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CabalInterrogator.java b/Mage.Sets/src/mage/cards/c/CabalInterrogator.java index 7e8862fdb9..4fd7e496e3 100644 --- a/Mage.Sets/src/mage/cards/c/CabalInterrogator.java +++ b/Mage.Sets/src/mage/cards/c/CabalInterrogator.java @@ -78,7 +78,7 @@ class CabalInterrogatorEffect extends OneShotEffect { return false; } - int amountToReveal = (new ManacostVariableValue()).calculate(game, source, this); + int amountToReveal = (ManacostVariableValue.instance).calculate(game, source, this); Cards revealedCards = new CardsImpl(); if (amountToReveal > 0 && targetPlayer.getHand().size() > amountToReveal) { diff --git a/Mage.Sets/src/mage/cards/c/CabalShrine.java b/Mage.Sets/src/mage/cards/c/CabalShrine.java index e58672dbfe..fe994ad773 100644 --- a/Mage.Sets/src/mage/cards/c/CabalShrine.java +++ b/Mage.Sets/src/mage/cards/c/CabalShrine.java @@ -67,7 +67,7 @@ class CabalShrineTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); MageObject mageObject = game.getObject(sourceId); - if (spell != null) { + if (spell != null && mageObject != null) { game.getState().setValue("cabalShrine" + mageObject, spell); return true; } @@ -91,21 +91,23 @@ class CabalShrineEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int count = 0; MageObject mageObject = game.getObject(source.getSourceId()); - Spell spell = (Spell) game.getState().getValue("cabalShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); + if(mageObject != null) { + Spell spell = (Spell) game.getState().getValue("cabalShrine" + mageObject); + if (spell != null) { + Player controller = game.getPlayer(spell.getControllerId()); + if (controller != null) { + String name = spell.getName(); + FilterCard filterCardName = new FilterCard(); + filterCardName.add(new NamePredicate(name)); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + count += player.getGraveyard().count(filterCardName, game); + } } + controller.discard(count, false, source, game); + return true; } - controller.discard(count, false, source, game); - return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapist.java b/Mage.Sets/src/mage/cards/c/CabalTherapist.java new file mode 100644 index 0000000000..96978c84ee --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CabalTherapist.java @@ -0,0 +1,164 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.SendOptionUsedEventEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CabalTherapist extends CardImpl { + + public CabalTherapist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.HORROR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. + this.addAbility(new BeginningOfPreCombatMainTriggeredAbility( + new DoIfCostPaid( + new CabalTherapistCreateReflexiveTriggerEffect(), + new SacrificeTargetCost(new TargetControlledPermanent( + StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT + )), "Sacrifice a creature?" + ).setText("you may sacrifice a creature. When you do, " + + "choose a nonland card name, then target player reveals their hand " + + "and discards all cards with that name."), + TargetController.YOU, false + )); + } + + private CabalTherapist(final CabalTherapist card) { + super(card); + } + + @Override + public CabalTherapist copy() { + return new CabalTherapist(this); + } +} + +class CabalTherapistCreateReflexiveTriggerEffect extends OneShotEffect { + + CabalTherapistCreateReflexiveTriggerEffect() { + super(Outcome.Benefit); + } + + private CabalTherapistCreateReflexiveTriggerEffect(final CabalTherapistCreateReflexiveTriggerEffect effect) { + super(effect); + } + + @Override + public CabalTherapistCreateReflexiveTriggerEffect copy() { + return new CabalTherapistCreateReflexiveTriggerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.addDelayedTriggeredAbility(new CabalTherapistReflexiveTriggeredAbility(), source); + return new SendOptionUsedEventEffect().apply(game, source); + } +} + +class CabalTherapistReflexiveTriggeredAbility extends DelayedTriggeredAbility { + + CabalTherapistReflexiveTriggeredAbility() { + super(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.NON_LAND_NAME), Duration.OneUse, true); + this.addEffect(new CabalTherapistDiscardEffect()); + this.addTarget(new TargetPlayer()); + } + + private CabalTherapistReflexiveTriggeredAbility(final CabalTherapistReflexiveTriggeredAbility ability) { + super(ability); + } + + @Override + public CabalTherapistReflexiveTriggeredAbility copy() { + return new CabalTherapistReflexiveTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.OPTION_USED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()) + && event.getSourceId().equals(this.getSourceId()); + } + + @Override + public String getRule() { + return "Choose a nonland card name, then target player reveals their hand and discards all cards with that name."; + } +} + +class CabalTherapistDiscardEffect extends OneShotEffect { + + CabalTherapistDiscardEffect() { + super(Outcome.Discard); + } + + private CabalTherapistDiscardEffect(final CabalTherapistDiscardEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (targetPlayer == null || controller == null || sourceObject == null) { + return false; + } + String cardName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + Cards hand = targetPlayer.getHand(); + + for (Card card : hand.getCards(game)) { + if (card.isSplitCard()) { + SplitCard splitCard = (SplitCard) card; + if (CardUtil.haveSameNames(splitCard.getLeftHalfCard().getName(), cardName)) { + targetPlayer.discard(card, source, game); + } else if (CardUtil.haveSameNames(splitCard.getRightHalfCard().getName(), cardName)) { + targetPlayer.discard(card, source, game); + } + } + if (CardUtil.haveSameNames(card.getName(), cardName)) { + targetPlayer.discard(card, source, game); + } + } + targetPlayer.revealCards("Cabal Therapist", hand, game); + return true; + } + + @Override + public CabalTherapistDiscardEffect copy() { + return new CabalTherapistDiscardEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CabalTherapy.java b/Mage.Sets/src/mage/cards/c/CabalTherapy.java index 70d7f7863c..ba03643b0a 100644 --- a/Mage.Sets/src/mage/cards/c/CabalTherapy.java +++ b/Mage.Sets/src/mage/cards/c/CabalTherapy.java @@ -15,11 +15,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetControlledCreaturePermanent; +import mage.util.CardUtil; import java.util.UUID; /** - * * @author jonubuu */ public final class CabalTherapy extends CardImpl { @@ -71,13 +71,13 @@ class CabalTherapyEffect extends OneShotEffect { for (Card card : hand.getCards(game)) { if (card.isSplitCard()) { SplitCard splitCard = (SplitCard) card; - if (splitCard.getLeftHalfCard().getName().equals(cardName)) { + if (CardUtil.haveSameNames(splitCard.getLeftHalfCard().getName(), cardName)) { targetPlayer.discard(card, source, game); - } else if (splitCard.getRightHalfCard().getName().equals(cardName)) { + } else if (CardUtil.haveSameNames(splitCard.getRightHalfCard().getName(), cardName)) { targetPlayer.discard(card, source, game); } } - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { targetPlayer.discard(card, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CacklingWitch.java b/Mage.Sets/src/mage/cards/c/CacklingWitch.java index ec76eecd38..37f93e1542 100644 --- a/Mage.Sets/src/mage/cards/c/CacklingWitch.java +++ b/Mage.Sets/src/mage/cards/c/CacklingWitch.java @@ -33,7 +33,7 @@ public final class CacklingWitch extends CardImpl { this.toughness = new MageInt(1); // {X}{B}, {tap}, Discard a card: Target creature gets +X/+0 until end of turn. - ManacostVariableValue manaX = new ManacostVariableValue(); + ManacostVariableValue manaX = ManacostVariableValue.instance; Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(manaX, new StaticValue(0), Duration.EndOfTurn), new ManaCostsImpl("{X}{B}")); diff --git a/Mage.Sets/src/mage/cards/c/CageOfHands.java b/Mage.Sets/src/mage/cards/c/CageOfHands.java index 32199c393a..4130d96835 100644 --- a/Mage.Sets/src/mage/cards/c/CageOfHands.java +++ b/Mage.Sets/src/mage/cards/c/CageOfHands.java @@ -1,8 +1,5 @@ - - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -13,27 +10,24 @@ import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class CageOfHands extends CardImpl { - public CageOfHands (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + public CageOfHands(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.subtype.add(SubType.AURA); - + // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -48,7 +42,7 @@ public final class CageOfHands extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandSourceEffect(true), new ManaCostsImpl("{1}{W}"))); } - public CageOfHands (final CageOfHands card) { + public CageOfHands(final CageOfHands card) { super(card); } @@ -71,19 +65,16 @@ class CageOfHandsEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getAttachments().contains((source.getSourceId()))) { - return true; - } + return permanent.getAttachments().contains((source.getSourceId())); + } + + @Override + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { - return false; - } - - @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CalciformPools.java b/Mage.Sets/src/mage/cards/c/CalciformPools.java index 72702e77fd..9d12369191 100644 --- a/Mage.Sets/src/mage/cards/c/CalciformPools.java +++ b/Mage.Sets/src/mage/cards/c/CalciformPools.java @@ -36,7 +36,7 @@ public final class CalciformPools extends CardImpl { this.addAbility(ability); // {1}, Remove X storage counters from Calciform Pools: Add X mana in any combination of {W} and/or {U}. ability = new SimpleManaAbility(Zone.BATTLEFIELD, - new AddManaInAnyCombinationEffect(new RemovedCountersForCostValue(), ColoredManaSymbol.W, ColoredManaSymbol.U), + new AddManaInAnyCombinationEffect(RemovedCountersForCostValue.instance, ColoredManaSymbol.W, ColoredManaSymbol.U), new GenericManaCost(1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/c/CallToTheKindred.java b/Mage.Sets/src/mage/cards/c/CallToTheKindred.java index 91f10556c6..3b6bf2e502 100644 --- a/Mage.Sets/src/mage/cards/c/CallToTheKindred.java +++ b/Mage.Sets/src/mage/cards/c/CallToTheKindred.java @@ -90,8 +90,7 @@ class CallToTheKindredEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.lookAtCards(enchantment.getIdName(), cards, game); FilterCreatureCard filter = new FilterCreatureCard(); diff --git a/Mage.Sets/src/mage/cards/c/CallerOfTheClaw.java b/Mage.Sets/src/mage/cards/c/CallerOfTheClaw.java index e5607074fe..fc0c0aee3f 100644 --- a/Mage.Sets/src/mage/cards/c/CallerOfTheClaw.java +++ b/Mage.Sets/src/mage/cards/c/CallerOfTheClaw.java @@ -60,7 +60,7 @@ class CallerOfTheClawWatcher extends Watcher { private int creaturesCount = 0; public CallerOfTheClawWatcher() { - super(CallerOfTheClawWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); condition = true; } @@ -114,7 +114,7 @@ class CallerOfTheClawDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CallerOfTheClawWatcher watcher = (CallerOfTheClawWatcher) game.getState().getWatchers().get(CallerOfTheClawWatcher.class.getSimpleName(), sourceAbility.getControllerId()); + CallerOfTheClawWatcher watcher = game.getState().getWatcher(CallerOfTheClawWatcher.class, sourceAbility.getControllerId()); if (watcher != null) { return watcher.getCreaturesCount(); } diff --git a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java index f05249eeac..37eb08abbe 100644 --- a/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/c/CallerOfTheHunt.java @@ -1,14 +1,15 @@ package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostAdjuster; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; import mage.abilities.effects.common.continuous.SetToughnessSourceEffect; import mage.cards.CardImpl; @@ -21,8 +22,9 @@ import mage.filter.predicate.mageobject.ChosenSubtypePredicate; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CallerOfTheHunt extends CardImpl { @@ -34,14 +36,24 @@ public final class CallerOfTheHunt extends CardImpl { // As an additional cost to cast Caller of the Hunt, choose a creature type. // Caller of the Hunt's power and toughness are each equal to the number of creatures of the chosen type on the battlefield. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new CallerOfTheHuntAdditionalCostEffect())); - + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("as an additional cost to cast this spell, choose a creature type. \r" + + "{this}'s power and toughness are each equal to the number of creatures of the chosen type on the battlefield"))); + this.getSpellAbility().setCostAdjuster(CallerOfTheHuntAdjuster.instance); } public CallerOfTheHunt(final CallerOfTheHunt card) { super(card); } + @Override + public CallerOfTheHunt copy() { + return new CallerOfTheHunt(this); + } +} + +enum CallerOfTheHuntAdjuster implements CostAdjuster { + instance; + @Override public void adjustCosts(Ability ability, Game game) { MageObject mageObject = game.getObject(ability.getSourceId()); @@ -56,34 +68,6 @@ public final class CallerOfTheHunt extends CardImpl { game.addEffect(effectToughness, ability); } } - - @Override - public CallerOfTheHunt copy() { - return new CallerOfTheHunt(this); - } -} - -class CallerOfTheHuntAdditionalCostEffect extends OneShotEffect { - - public CallerOfTheHuntAdditionalCostEffect() { - super(Outcome.Benefit); - this.staticText = "as an additional cost to cast this spell, choose a creature type. \r" - + "{this}'s power and toughness are each equal to the number of creatures of the chosen type on the battlefield"; - } - - public CallerOfTheHuntAdditionalCostEffect(final CallerOfTheHuntAdditionalCostEffect effect) { - super(effect); - } - - @Override - public CallerOfTheHuntAdditionalCostEffect copy() { - return new CallerOfTheHuntAdditionalCostEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } } class ChooseCreatureTypeEffect extends OneShotEffect { // code by LevelX2, but that other version is not compatible with this card @@ -116,5 +100,4 @@ class ChooseCreatureTypeEffect extends OneShotEffect { // code by LevelX2, but t public ChooseCreatureTypeEffect copy() { return new ChooseCreatureTypeEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/c/CallousDismissal.java b/Mage.Sets/src/mage/cards/c/CallousDismissal.java new file mode 100644 index 0000000000..db2440421f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CallousDismissal.java @@ -0,0 +1,36 @@ +package mage.cards.c; + +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CallousDismissal extends CardImpl { + + public CallousDismissal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + + // Return target nonland permanent to its owner's hand. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + + // Amass 1. + this.getSpellAbility().addEffect(new AmassEffect(1).concatBy("
    ")); + } + + private CallousDismissal(final CallousDismissal card) { + super(card); + } + + @Override + public CallousDismissal copy() { + return new CallousDismissal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CalmingVerse.java b/Mage.Sets/src/mage/cards/c/CalmingVerse.java index 8d94a2f0d8..08a66a28ef 100644 --- a/Mage.Sets/src/mage/cards/c/CalmingVerse.java +++ b/Mage.Sets/src/mage/cards/c/CalmingVerse.java @@ -50,7 +50,7 @@ class CalmingVerseEffect extends OneShotEffect { static { untappedLandFilter.add(new CardTypePredicate(CardType.LAND)); - untappedLandFilter.add(Predicates.not(new TappedPredicate())); + untappedLandFilter.add(Predicates.not(TappedPredicate.instance)); } private static final FilterEnchantmentPermanent opponentEnchantmentsFilter = new FilterEnchantmentPermanent("enchantments you don't control"); diff --git a/Mage.Sets/src/mage/cards/c/Camaraderie.java b/Mage.Sets/src/mage/cards/c/Camaraderie.java index 9baba360db..1e0880911b 100644 --- a/Mage.Sets/src/mage/cards/c/Camaraderie.java +++ b/Mage.Sets/src/mage/cards/c/Camaraderie.java @@ -1,9 +1,9 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -13,8 +13,9 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Camaraderie extends CardImpl { @@ -24,6 +25,7 @@ public final class Camaraderie extends CardImpl { // You gain X life and draw X cards, where X is the number of creatures you control. Creatures you control get +1/+1 until end of turn. this.getSpellAbility().addEffect(new CamaraderieEffect()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); } public Camaraderie(final Camaraderie card) { diff --git a/Mage.Sets/src/mage/cards/c/CanalDredger.java b/Mage.Sets/src/mage/cards/c/CanalDredger.java new file mode 100644 index 0000000000..d1a8d2b7bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CanalDredger.java @@ -0,0 +1,52 @@ + +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.common.TargetCardInYourGraveyard; + +/** + * + * @author L_J + */ +public final class CanalDredger extends CardImpl { + + public CanalDredger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // TODO: Draft specific abilities not implemented + // Draft Canal Dredger face up. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Canal Dredger face up."))); + + // Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Each player passes the last card from each booster pack to a player who drafted a card named Canal Dredger."))); + + // {T}: Put target card from your graveyard on the bottom of your library. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutOnLibraryTargetEffect(false), new TapSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard()); + this.addAbility(ability); + } + + public CanalDredger(final CanalDredger card) { + super(card); + } + + @Override + public CanalDredger copy() { + return new CanalDredger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CandlesGlow.java b/Mage.Sets/src/mage/cards/c/CandlesGlow.java index 158da85435..7bf8e711e2 100644 --- a/Mage.Sets/src/mage/cards/c/CandlesGlow.java +++ b/Mage.Sets/src/mage/cards/c/CandlesGlow.java @@ -92,8 +92,8 @@ class CandlesGlowPreventDamageTargetEffect extends PreventionEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.gainLife(prevented, game, source); - game.informPlayers(new StringBuilder("Candles' Glow: Prevented ").append(prevented).append(" damage ").toString()); - game.informPlayers(new StringBuilder("Candles' Glow: ").append(controller.getLogName()).append(" gained ").append(prevented).append("life").toString()); + game.informPlayers("Candles' Glow: Prevented " + prevented + " damage "); + game.informPlayers("Candles' Glow: " + controller.getLogName() + " gained " + prevented + "life"); } } } diff --git a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java index a6a8de33be..71a2e65349 100644 --- a/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java +++ b/Mage.Sets/src/mage/cards/c/CandlesOfLeng.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,9 +15,11 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class CandlesOfLeng extends CardImpl { @@ -63,6 +63,9 @@ class CandlesOfLengEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); + if(controller == null || sourceObject == null){ + return false; + } if (controller.getLibrary().hasCards()) { CardsImpl cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); @@ -73,7 +76,7 @@ class CandlesOfLengEffect extends OneShotEffect { controller.revealCards(sourceObject.getName(), cards, game); boolean hasTheSameName = false; for (UUID uuid : controller.getGraveyard()) { - if (card.getName().equals(game.getCard(uuid).getName())) { + if (CardUtil.haveSameNames(card, game.getCard(uuid))) { hasTheSameName = true; } } diff --git a/Mage.Sets/src/mage/cards/c/CanopyCover.java b/Mage.Sets/src/mage/cards/c/CanopyCover.java index 4fa4768cc2..ff82a8bc79 100644 --- a/Mage.Sets/src/mage/cards/c/CanopyCover.java +++ b/Mage.Sets/src/mage/cards/c/CanopyCover.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -20,6 +18,8 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author noxx */ @@ -71,15 +71,13 @@ class CanopyCoverEffect extends RestrictionEffect { Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { Permanent equipped = game.getPermanent(equipment.getAttachedTo()); - if (equipped != null && permanent.getId().equals(equipped.getId())) { - return true; - } + return equipped != null && permanent.getId().equals(equipped.getId()); } return false; } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().contains(FlyingAbility.getInstance()) || blocker.getAbilities().contains(ReachAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/c/CantonicaCasino.java b/Mage.Sets/src/mage/cards/c/CantonicaCasino.java index 4c528b303d..f91d45b698 100644 --- a/Mage.Sets/src/mage/cards/c/CantonicaCasino.java +++ b/Mage.Sets/src/mage/cards/c/CantonicaCasino.java @@ -1,13 +1,9 @@ package mage.cards.c; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.RollDiceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,21 +11,21 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author NinthWorld */ public final class CantonicaCasino extends CardImpl { public CantonicaCasino(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - // {T}: Roll two six-sided dice. If you roll doubles, gain 10 life. Otherwise, lose 1 life. this.addAbility(new SimpleActivatedAbility(new CantonicaCasinoEffect(), new TapSourceCost())); } - public CantonicaCasino(final CantonicaCasino card) { + private CantonicaCasino(final CantonicaCasino card) { super(card); } @@ -41,33 +37,31 @@ public final class CantonicaCasino extends CardImpl { class CantonicaCasinoEffect extends OneShotEffect { - public CantonicaCasinoEffect() { + CantonicaCasinoEffect() { super(Outcome.Neutral); - staticText = "Roll two six-sided dice. If you roll doubles, gain 10 life. Otherwise, lose 1 life"; + staticText = "Roll two six-sided dice. If you roll doubles, gain 10 life. Otherwise, you lose 1 life"; } - public CantonicaCasinoEffect(final CantonicaCasinoEffect effect) { + private CantonicaCasinoEffect(final CantonicaCasinoEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - if(you != null) { + if (you != null) { // Roll two six-sided dice int dice1 = you.rollDice(game, 6); int dice2 = you.rollDice(game, 6); - if(dice1 == dice2) { + if (dice1 == dice2) { // If you roll doubles, gain 10 life you.gainLife(10, game, source); - return false; - } - else { + } else { // Otherwise, lose 1 life you.loseLife(1, game, false); - return false; } + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CaptainOfTheMists.java b/Mage.Sets/src/mage/cards/c/CaptainOfTheMists.java index 2a1470958c..b936bb82bf 100644 --- a/Mage.Sets/src/mage/cards/c/CaptainOfTheMists.java +++ b/Mage.Sets/src/mage/cards/c/CaptainOfTheMists.java @@ -31,7 +31,7 @@ public final class CaptainOfTheMists extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another Human"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.HUMAN)); } diff --git a/Mage.Sets/src/mage/cards/c/CaptainPhasma.java b/Mage.Sets/src/mage/cards/c/CaptainPhasma.java index 829342d2b6..d37a042cd1 100644 --- a/Mage.Sets/src/mage/cards/c/CaptainPhasma.java +++ b/Mage.Sets/src/mage/cards/c/CaptainPhasma.java @@ -32,7 +32,7 @@ public final class CaptainPhasma extends CardImpl { static { filter.add(new SubtypePredicate(SubType.TROOPER)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filterCard.add(new SubtypePredicate(SubType.TROOPER)); } diff --git a/Mage.Sets/src/mage/cards/c/CaptivatingVampire.java b/Mage.Sets/src/mage/cards/c/CaptivatingVampire.java index 7262d6bc79..7ae2146618 100644 --- a/Mage.Sets/src/mage/cards/c/CaptivatingVampire.java +++ b/Mage.Sets/src/mage/cards/c/CaptivatingVampire.java @@ -34,7 +34,7 @@ public final class CaptivatingVampire extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.VAMPIRE)); filter2.add(new SubtypePredicate(SubType.VAMPIRE)); - filter2.add(Predicates.not(new TappedPredicate())); + filter2.add(Predicates.not(TappedPredicate.instance)); } public CaptivatingVampire(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CaptiveAudience.java b/Mage.Sets/src/mage/cards/c/CaptiveAudience.java new file mode 100644 index 0000000000..342849027d --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CaptiveAudience.java @@ -0,0 +1,140 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.effects.common.SetPlayerLifeSourceEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.effects.common.discard.DiscardHandControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class CaptiveAudience extends CardImpl { + + public CaptiveAudience(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{B}{R}"); + + // Captive Audience enters the battlefield under the control of an opponent of your choice. + this.addAbility(new EntersBattlefieldAbility(new CaptiveAudienceETBEffect())); + + // At the beginning of your upkeep, choose one that hasn't been chosen — + // • Your life total becomes 4. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new SetPlayerLifeSourceEffect(4), TargetController.YOU, false + ); + ability.getModes().setEachModeOnlyOnce(true); + + // • Discard your hand. + ability.addMode(new Mode(new DiscardHandControllerEffect())); + + // • Each opponent creates five 2/2 black Zombie creature tokens. + ability.addMode(new Mode(new CaptiveAudienceCreateTokensEffect())); + this.addAbility(ability); + } + + private CaptiveAudience(final CaptiveAudience card) { + super(card); + } + + @Override + public CaptiveAudience copy() { + return new CaptiveAudience(this); + } +} + +class CaptiveAudienceETBEffect extends OneShotEffect { + + CaptiveAudienceETBEffect() { + super(Benefit); + staticText = "under the control of an opponent of your choice"; + } + + private CaptiveAudienceETBEffect(final CaptiveAudienceETBEffect effect) { + super(effect); + } + + @Override + public CaptiveAudienceETBEffect copy() { + return new CaptiveAudienceETBEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Target target = new TargetOpponent(); + target.setNotTarget(true); + if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + return false; + } + Player player = game.getPlayer(target.getFirstTarget()); + if (player == null) { + return false; + } + ContinuousEffect continuousEffect = new GainControlTargetEffect( + Duration.WhileOnBattlefield, true, player.getId() + ); + continuousEffect.setTargetPointer(new FixedTarget( + source.getSourceId(), source.getSourceObjectZoneChangeCounter() + )); + game.addEffect(continuousEffect, source); + return true; + } +} + +class CaptiveAudienceCreateTokensEffect extends OneShotEffect { + + CaptiveAudienceCreateTokensEffect() { + super(Benefit); + staticText = "Each opponent creates five 2/2 black Zombie creature tokens."; + } + + private CaptiveAudienceCreateTokensEffect(final CaptiveAudienceCreateTokensEffect effect) { + super(effect); + } + + @Override + public CaptiveAudienceCreateTokensEffect copy() { + return new CaptiveAudienceCreateTokensEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (Player player : game.getPlayers().values()) { + if (player != null && controller.hasOpponent(player.getId(), game)) { + Effect effect = new CreateTokenTargetEffect(new ZombieToken(), 5); + effect.setTargetPointer(new FixedTarget(player.getId(), game)); + effect.apply(game, source); + } + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java b/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java index ea9e913770..66dedbd9d5 100644 --- a/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java +++ b/Mage.Sets/src/mage/cards/c/CapturedByTheConsulate.java @@ -33,7 +33,7 @@ import mage.target.targetpointer.FixedTarget; */ public final class CapturedByTheConsulate extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); diff --git a/Mage.Sets/src/mage/cards/c/CarapaceForger.java b/Mage.Sets/src/mage/cards/c/CarapaceForger.java index 03ce8bd225..01d92bba75 100644 --- a/Mage.Sets/src/mage/cards/c/CarapaceForger.java +++ b/Mage.Sets/src/mage/cards/c/CarapaceForger.java @@ -2,40 +2,44 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author Loki */ public final class CarapaceForger extends CardImpl { - private static final String text = "Metalcraft — Carapace Forger gets +2/+2 as long as you control three or more artifacts"; - public CarapaceForger (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + public CarapaceForger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(2); this.toughness = new MageInt(2); - ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, text); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + MetalcraftCondition.instance, "Metalcraft — {this} gets " + + "+2/+2 as long as you control three or more artifacts" + ) + )); } - public CarapaceForger (final CarapaceForger card) { + public CarapaceForger(final CarapaceForger card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CaravanVigil.java b/Mage.Sets/src/mage/cards/c/CaravanVigil.java index 963e149db3..d915675c4a 100644 --- a/Mage.Sets/src/mage/cards/c/CaravanVigil.java +++ b/Mage.Sets/src/mage/cards/c/CaravanVigil.java @@ -11,7 +11,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterBasicLandCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; @@ -63,7 +62,7 @@ class CaravanVigilEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { Cards cards = new CardsImpl(card); diff --git a/Mage.Sets/src/mage/cards/c/CarefulConsideration.java b/Mage.Sets/src/mage/cards/c/CarefulConsideration.java index 17f41df187..f23ff03b5c 100644 --- a/Mage.Sets/src/mage/cards/c/CarefulConsideration.java +++ b/Mage.Sets/src/mage/cards/c/CarefulConsideration.java @@ -2,7 +2,7 @@ package mage.cards.c; import java.util.UUID; -import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.condition.common.AddendumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawDiscardTargetEffect; import mage.cards.CardImpl; @@ -24,7 +24,7 @@ public final class CarefulConsideration extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DrawDiscardTargetEffect(4,2), new DrawDiscardTargetEffect(4,3), - MyMainPhaseCondition.instance, + AddendumCondition.instance, "Target player draws four cards, then discards three cards. If you cast this spell during your main phase, instead that player draws four cards, then discards two cards")); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/c/CaribouRange.java b/Mage.Sets/src/mage/cards/c/CaribouRange.java index f2ae348ca7..4599b610ce 100644 --- a/Mage.Sets/src/mage/cards/c/CaribouRange.java +++ b/Mage.Sets/src/mage/cards/c/CaribouRange.java @@ -34,7 +34,7 @@ public final class CaribouRange extends CardImpl { static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a Caribou token"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new SubtypePredicate(SubType.CARIBOU)); } diff --git a/Mage.Sets/src/mage/cards/c/CarnifexDemon.java b/Mage.Sets/src/mage/cards/c/CarnifexDemon.java index 9d2bb438dd..72a8bdb868 100644 --- a/Mage.Sets/src/mage/cards/c/CarnifexDemon.java +++ b/Mage.Sets/src/mage/cards/c/CarnifexDemon.java @@ -28,7 +28,7 @@ public final class CarnifexDemon extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each other creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CarnifexDemon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java new file mode 100644 index 0000000000..e5cdc2a443 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CarnivalCarnage.java @@ -0,0 +1,82 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CarnivalCarnage extends SplitCard { + + public CarnivalCarnage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{B/R}", "{2}{B}{R}", SpellAbilityType.SPLIT); + + // Carnival + // Carnival deals 1 damage to target creature or planeswalker and 1 damage to that permanent's controller. + this.getLeftHalfCard().getSpellAbility().addEffect(new CarnivalEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + + // Carnage + // Carnage deals 3 damage to target opponent. That player discards two cards. + this.getRightHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getRightHalfCard().getSpellAbility().addEffect( + new DiscardTargetEffect(2).setText("That player discards two cards.") + ); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetOpponent()); + } + + private CarnivalCarnage(final CarnivalCarnage card) { + super(card); + } + + @Override + public CarnivalCarnage copy() { + return new CarnivalCarnage(this); + } +} + +class CarnivalEffect extends OneShotEffect { + + CarnivalEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to target creature or planeswalker " + + "and 1 damage to that permanent's controller"; + } + + private CarnivalEffect(final CarnivalEffect effect) { + super(effect); + } + + @Override + public CarnivalEffect copy() { + return new CarnivalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.damage(1, source.getSourceId(), game); + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + player.damage(1, source.getSourceId(), game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java b/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java index 64f3dc27f9..947525af65 100644 --- a/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java +++ b/Mage.Sets/src/mage/cards/c/CarpetOfFlowers.java @@ -98,8 +98,7 @@ class CarpetOfFlowersTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - StringBuilder sb = new StringBuilder("At the beginning of each of your main phases, if you haven't added mana with this ability this turn, "); - return sb.append(super.getRule()).toString(); + return "At the beginning of each of your main phases, if you haven't added mana with this ability this turn, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/c/Carrion.java b/Mage.Sets/src/mage/cards/c/Carrion.java index 335d1c595a..befed330ea 100644 --- a/Mage.Sets/src/mage/cards/c/Carrion.java +++ b/Mage.Sets/src/mage/cards/c/Carrion.java @@ -25,7 +25,7 @@ public final class Carrion extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); // Put X 0/1 black Insect creature tokens onto the battlefield, where X is the sacrificed creature's power. - this.getSpellAbility().addEffect(new CreateTokenEffect(new CarrionBlackInsectToken(), new SacrificeCostCreaturesPower())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new CarrionBlackInsectToken(), SacrificeCostCreaturesPower.instance)); } public Carrion(final Carrion card) { diff --git a/Mage.Sets/src/mage/cards/c/CarrionImp.java b/Mage.Sets/src/mage/cards/c/CarrionImp.java new file mode 100644 index 0000000000..0804414d36 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CarrionImp.java @@ -0,0 +1,51 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CarrionImp extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card from a graveyard"); + + public CarrionImp(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.IMP); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Carrion Imp enters the battlefield, you may exile target creature card from a graveyard. If you do, you gain 2 life. + Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(), true); + ability.addEffect(new GainLifeEffect(2).concatBy("If you do,")); + ability.addTarget(new TargetCardInGraveyard(filter)); + this.addAbility(ability); + } + + private CarrionImp(final CarrionImp card) { + super(card); + } + + @Override + public CarrionImp copy() { + return new CarrionImp(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CastOut.java b/Mage.Sets/src/mage/cards/c/CastOut.java index ea4dd6d953..80465f8c2b 100644 --- a/Mage.Sets/src/mage/cards/c/CastOut.java +++ b/Mage.Sets/src/mage/cards/c/CastOut.java @@ -24,7 +24,7 @@ import mage.target.TargetPermanent; */ public final class CastOut extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/c/CasualtiesOfWar.java b/Mage.Sets/src/mage/cards/c/CasualtiesOfWar.java new file mode 100644 index 0000000000..f6bc983359 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CasualtiesOfWar.java @@ -0,0 +1,62 @@ +package mage.cards.c; + +import mage.abilities.Mode; +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.TargetArtifactPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetEnchantmentPermanent; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CasualtiesOfWar extends CardImpl { + + public CasualtiesOfWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}{G}{G}"); + + // Choose one or more — + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(5); + + // • Destroy target artifact. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + + // • Destroy target creature. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addMode(mode); + + // • Destroy target enchantment. + mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); + this.getSpellAbility().addMode(mode); + + // • Destroy target land. + mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetLandPermanent()); + this.getSpellAbility().addMode(mode); + + // • Destroy target planeswalker. + mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_PLANESWALKER)); + this.getSpellAbility().addMode(mode); + } + + private CasualtiesOfWar(final CasualtiesOfWar card) { + super(card); + } + + @Override + public CasualtiesOfWar copy() { + return new CasualtiesOfWar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CatacombCrocodile.java b/Mage.Sets/src/mage/cards/c/CatacombCrocodile.java new file mode 100644 index 0000000000..d6beb926a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CatacombCrocodile.java @@ -0,0 +1,32 @@ +package mage.cards.c; + +import mage.MageInt; +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 CatacombCrocodile extends CardImpl { + + public CatacombCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(3); + this.toughness = new MageInt(7); + } + + private CatacombCrocodile(final CatacombCrocodile card) { + super(card); + } + + @Override + public CatacombCrocodile copy() { + return new CatacombCrocodile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CatacombDragon.java b/Mage.Sets/src/mage/cards/c/CatacombDragon.java new file mode 100644 index 0000000000..c76e5deda0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CatacombDragon.java @@ -0,0 +1,86 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedByCreatureTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CatacombDragon extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("a nonartifact, non-Dragon creature"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); + filter.add(Predicates.not(new SubtypePredicate(SubType.DRAGON))); + } + + public CatacombDragon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Catacomb Dragon becomes blocked by a nonartifact, non-Dragon creature, that creature gets -X/-0 until end of turn, where X is half the creature's power, rounded down. + this.addAbility(new BecomesBlockedByCreatureTriggeredAbility(new CatacombDragonEffect(), filter, false)); + } + + private CatacombDragon(final CatacombDragon card) { + super(card); + } + + @Override + public CatacombDragon copy() { + return new CatacombDragon(this); + } +} + +class CatacombDragonEffect extends OneShotEffect { + + CatacombDragonEffect() { + super(Outcome.Benefit); + staticText = "that creature gets -X/-0 until end of turn, where X is half the creature's power, rounded down."; + } + + private CatacombDragonEffect(final CatacombDragonEffect effect) { + super(effect); + } + + @Override + public CatacombDragonEffect copy() { + return new CatacombDragonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent == null || !permanent.isCreature()) { + return false; + } + int unBoost = -1 * Math.floorDiv(permanent.getPower().getValue(), 2); + game.addEffect(new BoostTargetEffect(unBoost, 0), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CatacombSifter.java b/Mage.Sets/src/mage/cards/c/CatacombSifter.java index 43f3e15b98..1ea063803c 100644 --- a/Mage.Sets/src/mage/cards/c/CatacombSifter.java +++ b/Mage.Sets/src/mage/cards/c/CatacombSifter.java @@ -24,9 +24,9 @@ import mage.game.permanent.token.EldraziScionToken; */ public final class CatacombSifter extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/c/CatapultMaster.java b/Mage.Sets/src/mage/cards/c/CatapultMaster.java index 0664a36eb6..ea9a17d070 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultMaster.java +++ b/Mage.Sets/src/mage/cards/c/CatapultMaster.java @@ -28,7 +28,7 @@ public final class CatapultMaster extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Soldiers you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.SOLDIER)); } public CatapultMaster(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CatapultSquad.java b/Mage.Sets/src/mage/cards/c/CatapultSquad.java index db703b595e..b8b9bd3af7 100644 --- a/Mage.Sets/src/mage/cards/c/CatapultSquad.java +++ b/Mage.Sets/src/mage/cards/c/CatapultSquad.java @@ -29,7 +29,7 @@ public final class CatapultSquad extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Soldiers you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.SOLDIER)); } diff --git a/Mage.Sets/src/mage/cards/c/CatharsCrusade.java b/Mage.Sets/src/mage/cards/c/CatharsCrusade.java index bfb4f678fb..59a6ce427e 100644 --- a/Mage.Sets/src/mage/cards/c/CatharsCrusade.java +++ b/Mage.Sets/src/mage/cards/c/CatharsCrusade.java @@ -1,27 +1,34 @@ package mage.cards.c; -import java.util.UUID; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class CatharsCrusade extends CardImpl { public CatharsCrusade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{W}"); // Whenever a creature enters the battlefield under your control, put a +1/+1 counter on each creature you control. - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()))); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()), + StaticFilters.FILTER_PERMANENT_CREATURE_A, + false) + ); } public CatharsCrusade(final CatharsCrusade card) { diff --git a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java index 01c4248f3f..80ce89d1f8 100644 --- a/Mage.Sets/src/mage/cards/c/CathedralMembrane.java +++ b/Mage.Sets/src/mage/cards/c/CathedralMembrane.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.*; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.ZoneChangeTriggeredAbility; @@ -15,6 +14,10 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** * @author BetaSteward */ @@ -35,7 +38,7 @@ public final class CathedralMembrane extends CardImpl { } - public CathedralMembrane(final CathedralMembrane card) { + private CathedralMembrane(final CathedralMembrane card) { super(card); } @@ -47,11 +50,11 @@ public final class CathedralMembrane extends CardImpl { class CathedralMembraneAbility extends ZoneChangeTriggeredAbility { - public CathedralMembraneAbility() { + CathedralMembraneAbility() { super(Zone.BATTLEFIELD, Zone.GRAVEYARD, new CathedralMembraneEffect(), "When {this} dies during combat, ", false); } - public CathedralMembraneAbility(CathedralMembraneAbility ability) { + private CathedralMembraneAbility(CathedralMembraneAbility ability) { super(ability); } @@ -74,12 +77,12 @@ class CathedralMembraneAbility extends ZoneChangeTriggeredAbility { class CathedralMembraneEffect extends OneShotEffect { - public CathedralMembraneEffect() { + CathedralMembraneEffect() { super(Outcome.Damage); staticText = "it deals 6 damage to each creature it blocked this combat"; } - public CathedralMembraneEffect(final CathedralMembraneEffect effect) { + private CathedralMembraneEffect(final CathedralMembraneEffect effect) { super(effect); } @@ -90,9 +93,9 @@ class CathedralMembraneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CathedralMembraneWatcher watcher = (CathedralMembraneWatcher) game.getState().getWatchers().get(CathedralMembraneWatcher.class.getSimpleName(), source.getSourceId()); + CathedralMembraneWatcher watcher = game.getState().getWatcher(CathedralMembraneWatcher.class, source.getSourceId()); if (watcher != null) { - for (UUID uuid : watcher.blockedCreatures) { + for (UUID uuid : watcher.getBlockedCreatures()) { Permanent permanent = game.getPermanent(uuid); if (permanent != null) { permanent.damage(6, source.getSourceId(), game, false, true); @@ -105,13 +108,13 @@ class CathedralMembraneEffect extends OneShotEffect { class CathedralMembraneWatcher extends Watcher { - public Set blockedCreatures = new HashSet<>(); + private final Set blockedCreatures = new HashSet<>(); - public CathedralMembraneWatcher() { - super(CathedralMembraneWatcher.class.getSimpleName(), WatcherScope.CARD); + CathedralMembraneWatcher() { + super(WatcherScope.CARD); } - public CathedralMembraneWatcher(final CathedralMembraneWatcher watcher) { + private CathedralMembraneWatcher(final CathedralMembraneWatcher watcher) { super(watcher); this.blockedCreatures.addAll(watcher.blockedCreatures); } @@ -134,4 +137,7 @@ class CathedralMembraneWatcher extends Watcher { blockedCreatures.clear(); } + Set getBlockedCreatures() { + return blockedCreatures; + } } diff --git a/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java b/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java new file mode 100644 index 0000000000..b570289989 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CathedralOfSerra.java @@ -0,0 +1,47 @@ + +package mage.cards.c; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class CathedralOfSerra extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("White legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.WHITE)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public CathedralOfSerra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // White legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public CathedralOfSerra(final CathedralOfSerra card) { + super(card); + } + + @Override + public CathedralOfSerra copy() { + return new CathedralOfSerra(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CauldronHaze.java b/Mage.Sets/src/mage/cards/c/CauldronHaze.java index db95a2d1e1..28f0e6d9c7 100644 --- a/Mage.Sets/src/mage/cards/c/CauldronHaze.java +++ b/Mage.Sets/src/mage/cards/c/CauldronHaze.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.PersistAbility; import mage.cards.CardImpl; @@ -10,13 +9,14 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CauldronHaze extends CardImpl { - private final String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn"; + private static final String rule = "Choose any number of target creatures. Each of those creatures gains persist until end of turn"; public CauldronHaze(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W/B}"); @@ -24,7 +24,6 @@ public final class CauldronHaze extends CardImpl { // Choose any number of target creatures. Each of those creatures gains persist until end of turn. this.getSpellAbility().addEffect(new GainAbilityTargetEffect(new PersistAbility(), Duration.EndOfTurn, rule)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); - } public CauldronHaze(final CauldronHaze card) { diff --git a/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java b/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java new file mode 100644 index 0000000000..7c7f863bad --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CavalcadeOfCalamity.java @@ -0,0 +1,72 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CavalcadeOfCalamity extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creaure you control with power 1 or less"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 2)); + } + + public CavalcadeOfCalamity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking. + this.addAbility(new AttacksAllTriggeredAbility( + new CavalcadeOfCalamityEffect(), false, filter, + SetTargetPointer.PERMANENT, false, false + )); + } + + private CavalcadeOfCalamity(final CavalcadeOfCalamity card) { + super(card); + } + + @Override + public CavalcadeOfCalamity copy() { + return new CavalcadeOfCalamity(this); + } +} + +class CavalcadeOfCalamityEffect extends OneShotEffect { + + CavalcadeOfCalamityEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to the player or planeswalker that creature is attacking."; + } + + private CavalcadeOfCalamityEffect(final CavalcadeOfCalamityEffect effect) { + super(effect); + } + + @Override + public CavalcadeOfCalamityEffect copy() { + return new CavalcadeOfCalamityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return game.damagePlayerOrPlaneswalker( + game.getCombat().getDefenderId(targetPointer.getFirst(game, source)), 1, + source.getSourceId(), game, false, true + ) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CavalryPegasus.java b/Mage.Sets/src/mage/cards/c/CavalryPegasus.java index 023e566e08..6d46fa8c7c 100644 --- a/Mage.Sets/src/mage/cards/c/CavalryPegasus.java +++ b/Mage.Sets/src/mage/cards/c/CavalryPegasus.java @@ -25,7 +25,7 @@ public final class CavalryPegasus extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("each attacking Human"); static { filter.add(new SubtypePredicate(SubType.HUMAN)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public CavalryPegasus(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CavernOfSouls.java b/Mage.Sets/src/mage/cards/c/CavernOfSouls.java index e1a5f5a2a1..0cb6fdf728 100644 --- a/Mage.Sets/src/mage/cards/c/CavernOfSouls.java +++ b/Mage.Sets/src/mage/cards/c/CavernOfSouls.java @@ -111,7 +111,7 @@ class CavernOfSoulsManaCondition extends CreatureCastManaCondition { if (super.apply(game, source)) { // check: ... of the chosen type MageObject object = game.getObject(source.getSourceId()); - if (creatureType != null && object.hasSubtype(creatureType, game)) { + if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } } @@ -125,7 +125,7 @@ class CavernOfSoulsWatcher extends Watcher { private final String originalId; public CavernOfSoulsWatcher(UUID originalId) { - super(CavernOfSoulsWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); this.originalId = originalId.toString(); } @@ -197,7 +197,7 @@ class CavernOfSoulsCantCounterEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - CavernOfSoulsWatcher watcher = (CavernOfSoulsWatcher) game.getState().getWatchers().get(CavernOfSoulsWatcher.class.getSimpleName(), source.getSourceId()); + CavernOfSoulsWatcher watcher = game.getState().getWatcher(CavernOfSoulsWatcher.class, source.getSourceId()); Spell spell = game.getStack().getSpell(event.getTargetId()); return spell != null && watcher != null && watcher.spellCantBeCountered(spell.getId()); } diff --git a/Mage.Sets/src/mage/cards/c/CavernsOfDespair.java b/Mage.Sets/src/mage/cards/c/CavernsOfDespair.java index 392fb6dd27..6b7f873e4b 100644 --- a/Mage.Sets/src/mage/cards/c/CavernsOfDespair.java +++ b/Mage.Sets/src/mage/cards/c/CavernsOfDespair.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -10,12 +8,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SuperType; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.constants.Zone; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CavernsOfDespair extends CardImpl { @@ -64,7 +63,7 @@ class CavernsOfDespairAttackRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getAttackers().size() < 2; } } @@ -91,7 +90,7 @@ class CavernsOfDespairBlockRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getBlockers().size() < 2; } } diff --git a/Mage.Sets/src/mage/cards/c/CelestialDawn.java b/Mage.Sets/src/mage/cards/c/CelestialDawn.java index 787eaf39cc..babf9c8d24 100644 --- a/Mage.Sets/src/mage/cards/c/CelestialDawn.java +++ b/Mage.Sets/src/mage/cards/c/CelestialDawn.java @@ -135,7 +135,7 @@ class CelestialDawnToWhiteEffect extends ContinuousEffectImpl { // Command for (CommandObject commandObject : game.getState().getCommand()) { if (commandObject instanceof Commander) { - if (commandObject.getControllerId().equals(controller.getId())) { + if (commandObject.isControlledBy(controller.getId())) { setColor(commandObject.getColor(game), game); } } diff --git a/Mage.Sets/src/mage/cards/c/CennsHeir.java b/Mage.Sets/src/mage/cards/c/CennsHeir.java index ed5c3645f2..c5dc2acad2 100644 --- a/Mage.Sets/src/mage/cards/c/CennsHeir.java +++ b/Mage.Sets/src/mage/cards/c/CennsHeir.java @@ -25,7 +25,7 @@ public final class CennsHeir extends CardImpl { static { filter.add(new SubtypePredicate(SubType.KITHKIN)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CennsHeir(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CentaurNurturer.java b/Mage.Sets/src/mage/cards/c/CentaurNurturer.java new file mode 100644 index 0000000000..e71e56131b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CentaurNurturer.java @@ -0,0 +1,44 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.mana.AnyColorManaAbility; + + +/** + * + * @author antoni-g + */ +public final class CentaurNurturer extends CardImpl { + + public CentaurNurturer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.CENTAUR); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // When Centaur Nurturer enters the battlefield, you gain 3 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3))); + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private CentaurNurturer(final CentaurNurturer card) { + super(card); + } + + @Override + public CentaurNurturer copy() { + return new CentaurNurturer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java index d99c19d977..ebd089f421 100644 --- a/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java +++ b/Mage.Sets/src/mage/cards/c/CentaurPeacemaker.java @@ -1,5 +1,6 @@ package mage.cards.c; +import java.util.Objects; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; @@ -61,12 +62,11 @@ class CentaurMediatorEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { game.getState().getPlayersInRange( - source.getControllerId(), game - ).stream().map((playerId) -> game.getPlayer(playerId)).filter( - (player) -> (player != null) - ).forEachOrdered((player) -> { - player.gainLife(4, game, source); - }); + source.getControllerId(), game) + .stream() + .map(game::getPlayer) + .filter(Objects::nonNull) + .forEachOrdered(player -> player.gainLife(4, game, source)); return true; } diff --git a/Mage.Sets/src/mage/cards/c/CephalidInkshrouder.java b/Mage.Sets/src/mage/cards/c/CephalidInkshrouder.java index e1c1f54fe6..e01b5375fd 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidInkshrouder.java +++ b/Mage.Sets/src/mage/cards/c/CephalidInkshrouder.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,30 +11,35 @@ import mage.abilities.keyword.ShroudAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CephalidInkshrouder extends CardImpl { public CephalidInkshrouder(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); - + this.subtype.add(SubType.CEPHALID); this.power = new MageInt(2); this.toughness = new MageInt(1); // Discard a card: Cephalid Inkshrouder gains shroud until end of turn and is unblockable this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilitySourceEffect(ShroudAbility.getInstance(),Duration.EndOfTurn), new DiscardCardCost()); - ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility( + new GainAbilitySourceEffect( + ShroudAbility.getInstance(), + Duration.EndOfTurn + ), new DiscardCardCost() + ); + ability.addEffect(new CantBeBlockedSourceEffect(Duration.EndOfTurn).setText("and can't be blocked this turn")); this.addAbility(ability); } - public CephalidInkshrouder(final CephalidInkshrouder card) { + private CephalidInkshrouder(final CephalidInkshrouder card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CephalidPathmage.java b/Mage.Sets/src/mage/cards/c/CephalidPathmage.java index 1d87ab2e72..ccd3c1c47a 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidPathmage.java +++ b/Mage.Sets/src/mage/cards/c/CephalidPathmage.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,12 +11,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CephalidPathmage extends CardImpl { @@ -35,8 +32,8 @@ public final class CephalidPathmage extends CardImpl { this.addAbility(new CantBeBlockedSourceAbility()); // {tap}, Sacrifice Cephalid Pathmage: Target creature is unblockable this turn. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBeBlockedTargetEffect(Duration.EndOfTurn), new SacrificeSourceCost()); - ability.addCost(new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new CantBeBlockedTargetEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CephalidShrine.java b/Mage.Sets/src/mage/cards/c/CephalidShrine.java index b8cc075cc5..63121de89d 100644 --- a/Mage.Sets/src/mage/cards/c/CephalidShrine.java +++ b/Mage.Sets/src/mage/cards/c/CephalidShrine.java @@ -69,7 +69,7 @@ class CephalidShrineTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); MageObject mageObject = game.getObject(sourceId); - if (spell != null) { + if (spell != null && mageObject != null) { game.getState().setValue("cephalidShrine" + mageObject, spell); return true; } @@ -93,31 +93,33 @@ class CephalidShrineEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int count = 0; MageObject mageObject = game.getObject(source.getSourceId()); - Spell spell = (Spell) game.getState().getValue("cephalidShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); + if(mageObject != null) { + Spell spell = (Spell) game.getState().getValue("cephalidShrine" + mageObject); + if (spell != null) { + Player controller = game.getPlayer(spell.getControllerId()); + if (controller != null) { + String name = spell.getName(); + FilterCard filterCardName = new FilterCard(); + filterCardName.add(new NamePredicate(name)); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + count += player.getGraveyard().count(filterCardName, game); + } + } + // even if the cost is 0, we still offer + Cost cost = new GenericManaCost(count); + if (game.getStack().contains(spell) + && cost.canPay(source, source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Pay " + cost.getText() + " to prevent countering " + spell.getName() + "?", source, game) + && cost.pay(source, game, source.getSourceId(), controller.getId(), false) + && cost.isPaid()) { + return false; + } else { + spell.counter(source.getId(), game); + game.informPlayers(spell.getName() + " has been countered due to " + controller.getName() + " not paying " + cost.getText()); + return true; } - } - // even if the cost is 0, we still offer - Cost cost = new GenericManaCost(count); - if (game.getStack().contains((StackObject) spell) - && cost.canPay(source, source.getSourceId(), controller.getId(), game) - && controller.chooseUse(outcome, "Pay " + cost.getText() + " to prevent countering " + spell.getName() + "?", source, game) - && cost.pay(source, game, source.getSourceId(), controller.getId(), false) - && cost.isPaid()) { - return false; - } else { - spell.counter(source.getId(), game); - game.informPlayers(spell.getName() + " has been countered due to " + controller.getName() + " not paying " + cost.getText()); - return true; } } } diff --git a/Mage.Sets/src/mage/cards/c/CerebralVortex.java b/Mage.Sets/src/mage/cards/c/CerebralVortex.java index 8421720254..1329470ef8 100644 --- a/Mage.Sets/src/mage/cards/c/CerebralVortex.java +++ b/Mage.Sets/src/mage/cards/c/CerebralVortex.java @@ -66,7 +66,7 @@ class CerebralVortexEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (targetPlayer != null) { - CerebralVortexWatcher watcher = (CerebralVortexWatcher) game.getState().getWatchers().get(CerebralVortexWatcher.class.getSimpleName()); + CerebralVortexWatcher watcher = game.getState().getWatcher(CerebralVortexWatcher.class); if (watcher != null) { targetPlayer.damage(watcher.getDraws(targetPlayer.getId()), source.getSourceId(), game, false, true); return true; @@ -81,7 +81,7 @@ class CerebralVortexWatcher extends Watcher { private final Map draws = new HashMap<>(); CerebralVortexWatcher() { - super(CerebralVortexWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } CerebralVortexWatcher(final CerebralVortexWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/c/CeremoniousRejection.java b/Mage.Sets/src/mage/cards/c/CeremoniousRejection.java index c3aed499b7..e8ef317b00 100644 --- a/Mage.Sets/src/mage/cards/c/CeremoniousRejection.java +++ b/Mage.Sets/src/mage/cards/c/CeremoniousRejection.java @@ -19,7 +19,7 @@ public final class CeremoniousRejection extends CardImpl { private static final FilterSpell filter = new FilterSpell("colorless spell"); static{ - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public CeremoniousRejection(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/Cessation.java b/Mage.Sets/src/mage/cards/c/Cessation.java index 1407222dcf..c06f089f7c 100644 --- a/Mage.Sets/src/mage/cards/c/Cessation.java +++ b/Mage.Sets/src/mage/cards/c/Cessation.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,33 +9,31 @@ import mage.abilities.effects.common.combat.CantAttackAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class Cessation extends CardImpl { public Cessation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.subtype.add(SubType.AURA); - //Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); - this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + //Enchanted creature can't attack. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackAttachedEffect(AttachmentType.AURA))); + //When Cessation is put into a graveyard from the battlefield, return Cessation to its owner's hand. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect())); } diff --git a/Mage.Sets/src/mage/cards/c/ChainOfSilence.java b/Mage.Sets/src/mage/cards/c/ChainOfSilence.java index b9848d13ba..68833dbeb1 100644 --- a/Mage.Sets/src/mage/cards/c/ChainOfSilence.java +++ b/Mage.Sets/src/mage/cards/c/ChainOfSilence.java @@ -74,7 +74,7 @@ class ChainOfSilenceEffect extends OneShotEffect { game.addEffect(effect, source); Player player = game.getPlayer(permanent.getControllerId()); TargetControlledPermanent target = new TargetControlledPermanent(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'), true); - if (player.chooseTarget(Outcome.Sacrifice, target, source, game)) { + if (player != null && player.chooseTarget(Outcome.Sacrifice, target, source, game)) { Permanent land = game.getPermanent(target.getFirstTarget()); if (land != null && land.sacrifice(source.getSourceId(), game)) { if (player.chooseUse(outcome, "Copy the spell?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/c/ChainOfVapor.java b/Mage.Sets/src/mage/cards/c/ChainOfVapor.java index d6b94d8838..cfcb94afc3 100644 --- a/Mage.Sets/src/mage/cards/c/ChainOfVapor.java +++ b/Mage.Sets/src/mage/cards/c/ChainOfVapor.java @@ -71,7 +71,7 @@ class ChainOfVaporEffect extends OneShotEffect { controller.moveCards(permanent, Zone.HAND, source, game); Player player = game.getPlayer(permanent.getControllerId()); TargetControlledPermanent target = new TargetControlledPermanent(0, 1, new FilterControlledLandPermanent("a land to sacrifice (to be able to copy " + sourceObject.getName() + ')'), true); - if (player.chooseTarget(Outcome.Sacrifice, target, source, game)) { + if (player != null && player.chooseTarget(Outcome.Sacrifice, target, source, game)) { Permanent land = game.getPermanent(target.getFirstTarget()); if (land != null && land.sacrifice(source.getSourceId(), game)) { if (player.chooseUse(outcome, "Copy the spell?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/c/ChainStasis.java b/Mage.Sets/src/mage/cards/c/ChainStasis.java index 295f1bffa1..4724a14be8 100644 --- a/Mage.Sets/src/mage/cards/c/ChainStasis.java +++ b/Mage.Sets/src/mage/cards/c/ChainStasis.java @@ -74,6 +74,9 @@ class ChainStasisEffect extends OneShotEffect { effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); effect.apply(game, source); Player player = game.getPlayer(permanent.getControllerId()); + if(player == null){ + return false; + } Cost cost = new ManaCostsImpl("{2}{U}"); if (cost.pay(source, game, player.getId(), controller.getId(), false)) { if (player.chooseUse(outcome, "Copy the spell?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java index 69e12ec700..f9ac5ba327 100644 --- a/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java +++ b/Mage.Sets/src/mage/cards/c/ChainedThroatseeker.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,22 +8,23 @@ import mage.abilities.keyword.InfectAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author North */ public final class ChainedThroatseeker extends CardImpl { public ChainedThroatseeker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(5); @@ -65,12 +64,10 @@ class ChainedThroatseekerCantAttackEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { Player targetPlayer = game.getPlayer(defenderId); if (targetPlayer != null) { - if (targetPlayer.getCounters().containsKey(CounterType.POISON)) { - return true; - } + return targetPlayer.getCounters().containsKey(CounterType.POISON); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/ChainsOfMephistopheles.java b/Mage.Sets/src/mage/cards/c/ChainsOfMephistopheles.java index 04f12fe4cf..4cba73bcdc 100644 --- a/Mage.Sets/src/mage/cards/c/ChainsOfMephistopheles.java +++ b/Mage.Sets/src/mage/cards/c/ChainsOfMephistopheles.java @@ -86,7 +86,7 @@ class ChainsOfMephistophelesReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (game.isActivePlayer(event.getPlayerId()) && game.getPhase().getStep().getType() == PhaseStep.DRAW) { - CardsDrawnDuringDrawStepWatcher watcher = (CardsDrawnDuringDrawStepWatcher) game.getState().getWatchers().get(CardsDrawnDuringDrawStepWatcher.class.getSimpleName()); + CardsDrawnDuringDrawStepWatcher watcher = game.getState().getWatcher(CardsDrawnDuringDrawStepWatcher.class); if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 0) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/ChainwhipCyclops.java b/Mage.Sets/src/mage/cards/c/ChainwhipCyclops.java new file mode 100644 index 0000000000..28551b8860 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChainwhipCyclops.java @@ -0,0 +1,46 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChainwhipCyclops extends CardImpl { + + public ChainwhipCyclops(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.CYCLOPS); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {3}{R}: Target creature can't block this turn. + Ability ability = new SimpleActivatedAbility( + new CantBlockTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{3}{R}") + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ChainwhipCyclops(final ChainwhipCyclops card) { + super(card); + } + + @Override + public ChainwhipCyclops copy() { + return new ChainwhipCyclops(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java index 64428785ba..038aae4141 100644 --- a/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java +++ b/Mage.Sets/src/mage/cards/c/ChaliceOfLife.java @@ -60,13 +60,15 @@ class ChaliceOfLifeEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { Player player = game.getPlayer(source.getControllerId()); - //gain 1 life - player.gainLife(1, game, source); + if(player != null) { + //gain 1 life + player.gainLife(1, game, source); - // if you have at least 10 life more than your starting life total, transform Chalice of Life. - if (player.getLife() >= game.getLife() + 10) { - permanent.transform(game); - game.informPlayers(new StringBuilder(permanent.getName()).append(" transforms into ").append(permanent.getSecondCardFace().getName()).toString()); + // if you have at least 10 life more than your starting life total, transform Chalice of Life. + if (player.getLife() >= game.getLife() + 10) { + permanent.transform(game); + game.informPlayers(permanent.getName() + " transforms into " + permanent.getSecondCardFace().getName()); + } } } return false; diff --git a/Mage.Sets/src/mage/cards/c/ChallengerTroll.java b/Mage.Sets/src/mage/cards/c/ChallengerTroll.java new file mode 100644 index 0000000000..65a3055c7a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChallengerTroll.java @@ -0,0 +1,80 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChallengerTroll extends CardImpl { + + public ChallengerTroll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.TROLL); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Each creature you control with power 4 or greater can't be blocked by more than one creature. + this.addAbility(new SimpleStaticAbility(new ChallengerTrollEffect())); + } + + private ChallengerTroll(final ChallengerTroll card) { + super(card); + } + + @Override + public ChallengerTroll copy() { + return new ChallengerTroll(this); + } +} + +class ChallengerTrollEffect extends ContinuousEffectImpl { + + ChallengerTrollEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Each creature you control with power 4 or greater can't be blocked by more than one creature."; + } + + private ChallengerTrollEffect(final ChallengerTrollEffect effect) { + super(effect); + } + + @Override + public ChallengerTrollEffect copy() { + return new ChallengerTrollEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + if (layer != Layer.RulesEffects) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (permanent != null && permanent.isControlledBy(source.getControllerId()) + && permanent.isCreature() && permanent.getPower().getValue() >= 4) { + permanent.setMaxBlockedBy(1); + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.RulesEffects; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChamberSentry.java b/Mage.Sets/src/mage/cards/c/ChamberSentry.java index 60c1182502..7e8969db2a 100644 --- a/Mage.Sets/src/mage/cards/c/ChamberSentry.java +++ b/Mage.Sets/src/mage/cards/c/ChamberSentry.java @@ -44,7 +44,7 @@ public final class ChamberSentry extends CardImpl { "with a +1/+1 counter on it for each color of mana spent to cast it")); // {X}, {T}, Remove X +1/+1 counters from Chamber Sentry: It deals X damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()) + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance) .setText("It deals X damage to any target"), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfDusk.java b/Mage.Sets/src/mage/cards/c/ChampionOfDusk.java index e5c218c007..dedfdaa9de 100644 --- a/Mage.Sets/src/mage/cards/c/ChampionOfDusk.java +++ b/Mage.Sets/src/mage/cards/c/ChampionOfDusk.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class ChampionOfDusk extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("Vampires you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Vampires you control"); static { filter.add(new SubtypePredicate(SubType.VAMPIRE)); diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfLambholt.java b/Mage.Sets/src/mage/cards/c/ChampionOfLambholt.java index de10a0845e..8040e0c037 100644 --- a/Mage.Sets/src/mage/cards/c/ChampionOfLambholt.java +++ b/Mage.Sets/src/mage/cards/c/ChampionOfLambholt.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; @@ -10,11 +8,7 @@ import mage.abilities.effects.RestrictionEffect; 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.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -22,15 +16,17 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * @author noxx */ public final class ChampionOfLambholt extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } @@ -77,9 +73,9 @@ class ChampionOfLambholtEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null && attacker.isControlledBy(sourcePermanent.getControllerId())) { + if (sourcePermanent != null && attacker != null && attacker.isControlledBy(sourcePermanent.getControllerId())) { return blocker.getPower().getValue() >= sourcePermanent.getPower().getValue(); } return true; diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfStraySouls.java b/Mage.Sets/src/mage/cards/c/ChampionOfStraySouls.java index 24434b01b7..f8e2745365 100644 --- a/Mage.Sets/src/mage/cards/c/ChampionOfStraySouls.java +++ b/Mage.Sets/src/mage/cards/c/ChampionOfStraySouls.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -22,22 +21,23 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ChampionOfStraySouls extends CardImpl { - private final UUID originalId; private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ChampionOfStraySouls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); this.subtype.add(SubType.SKELETON); this.subtype.add(SubType.WARRIOR); @@ -49,7 +49,6 @@ public final class ChampionOfStraySouls extends CardImpl { * ability, before you pay any costs. You can't target any of the * creatures you sacrifice. */ - //TODO: Make ability properly copiable // {3}{B}{B}, {T}, Sacrifice X other creatures: Return X target creatures from your graveyard to the battlefield. Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setText("Return X target creatures from your graveyard to the battlefield"); @@ -57,32 +56,17 @@ public final class ChampionOfStraySouls extends CardImpl { ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeXTargetCost(filter)); ability.addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard"))); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(ChampionOfStraySoulsAdjuster.instance); this.addAbility(ability); // {5}{B}{B}: Put Champion of Stray Souls on top of your library from your graveyard. this.addAbility(new SimpleActivatedAbility(Zone.GRAVEYARD, new PutOnLibrarySourceEffect(true, "Put {this} on top of your library from your graveyard"), new ManaCostsImpl("{5}{B}{B}"))); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - for (Effect effect : ability.getEffects()) { - if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) { - int xValue = new GetXValue().calculate(game, ability, null); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(xValue, xValue, new FilterCreatureCard("creature cards from your graveyard"))); - } - } - } } public ChampionOfStraySouls(final ChampionOfStraySouls card) { super(card); - this.originalId = card.originalId; } @Override @@ -90,3 +74,18 @@ public final class ChampionOfStraySouls extends CardImpl { return new ChampionOfStraySouls(this); } } + +enum ChampionOfStraySoulsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + for (Effect effect : ability.getEffects()) { + if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) { + int xValue = GetXValue.instance.calculate(game, ability, null); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(xValue, xValue, new FilterCreatureCard("creature cards from your graveyard"))); + } + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ChampionOfTheParish.java b/Mage.Sets/src/mage/cards/c/ChampionOfTheParish.java index 8e57197839..617487fb23 100644 --- a/Mage.Sets/src/mage/cards/c/ChampionOfTheParish.java +++ b/Mage.Sets/src/mage/cards/c/ChampionOfTheParish.java @@ -24,7 +24,7 @@ public final class ChampionOfTheParish extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another Human"); static { filter.add(new SubtypePredicate(SubType.HUMAN)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ChampionOfTheParish(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ChanceEncounter.java b/Mage.Sets/src/mage/cards/c/ChanceEncounter.java index 84d4fbbac8..20801608a8 100644 --- a/Mage.Sets/src/mage/cards/c/ChanceEncounter.java +++ b/Mage.Sets/src/mage/cards/c/ChanceEncounter.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -16,27 +15,29 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; +import mage.game.events.CoinFlippedEvent; import mage.game.events.GameEvent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ChanceEncounter extends CardImpl { public ChanceEncounter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}{R}"); // Whenever you win a coin flip, put a luck counter on Chance Encounter. this.addAbility(new ChanceEncounterTriggeredAbility()); - + // At the beginning of your upkeep, if Chance Encounter has ten or more luck counters on it, you win the game. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new WinGameSourceControllerEffect(), TargetController.YOU, false); + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new WinGameSourceControllerEffect(), TargetController.YOU, false); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceHasCounterCondition(CounterType.LUCK, 10, Integer.MAX_VALUE), "At the beginning of your upkeep, if {this} has ten or more luck counters on it, you win the game")); } - public ChanceEncounter(final ChanceEncounter card) { + private ChanceEncounter(final ChanceEncounter card) { super(card); } @@ -47,30 +48,33 @@ public final class ChanceEncounter extends CardImpl { } class ChanceEncounterTriggeredAbility extends TriggeredAbilityImpl { - - public ChanceEncounterTriggeredAbility() { + + ChanceEncounterTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.LUCK.createInstance()), false); } - - public ChanceEncounterTriggeredAbility(final ChanceEncounterTriggeredAbility ability) { + + private ChanceEncounterTriggeredAbility(final ChanceEncounterTriggeredAbility ability) { super(ability); } - + @Override public ChanceEncounterTriggeredAbility copy() { return new ChanceEncounterTriggeredAbility(this); } - + @Override public boolean checkEventType(GameEvent event, Game game) { return event.getType() == GameEvent.EventType.COIN_FLIPPED; } - + @Override public boolean checkTrigger(GameEvent event, Game game) { - return this.isControlledBy(event.getPlayerId()) && event.getFlag(); + CoinFlippedEvent flipEvent = (CoinFlippedEvent) event; + return flipEvent.getPlayerId().equals(controllerId) + && flipEvent.isWinnable() + && (flipEvent.getChosen() == flipEvent.getResult()); } - + @Override public String getRule() { return "Whenever you win a coin flip, " + super.getRule(); diff --git a/Mage.Sets/src/mage/cards/c/ChanceForGlory.java b/Mage.Sets/src/mage/cards/c/ChanceForGlory.java index ab8c37fb8a..dff4e834e2 100644 --- a/Mage.Sets/src/mage/cards/c/ChanceForGlory.java +++ b/Mage.Sets/src/mage/cards/c/ChanceForGlory.java @@ -1,16 +1,17 @@ package mage.cards.c; -import java.util.UUID; -import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ChanceForGlory extends CardImpl { @@ -19,9 +20,10 @@ public final class ChanceForGlory extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); // Creatures you control gain indestructible. Take an extra turn after this one. At the beginning of that turn's end step, you lose the game. - this.getSpellAbility().addEffect(new GainAbilityControlledEffect( - IndestructibleAbility.getInstance(), Duration.EndOfGame - ).setText("Creatures you control gain indestructible")); + this.getSpellAbility().addEffect(new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.EndOfGame, + StaticFilters.FILTER_CONTROLLED_CREATURES + ).setText("Creatures you control gain indestructible.")); this.getSpellAbility().addEffect(new AddExtraTurnControllerEffect(true)); } diff --git a/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java b/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java index 9118e1f5d6..70285f2e54 100644 --- a/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java +++ b/Mage.Sets/src/mage/cards/c/ChancellorOfTheForge.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.ChancellorAbility; @@ -9,6 +7,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,8 +20,9 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.token.GoblinToken; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class ChancellorOfTheForge extends CardImpl { @@ -46,7 +46,8 @@ public final class ChancellorOfTheForge extends CardImpl { // When Chancellor of the Forge enters the battlefield, create X 1/1 red Goblin creature tokens with haste, where X is the number of creatures you control. DynamicValue value = new PermanentsOnBattlefieldCount(filter); - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken(true), value), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken(true), value), false) + .addHint(CreaturesYouControlHint.instance)); } public ChancellorOfTheForge(final ChancellorOfTheForge card) { diff --git a/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java b/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java new file mode 100644 index 0000000000..052ed7c91f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChandraFireArtisan.java @@ -0,0 +1,136 @@ +package mage.cards.c; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetOpponentOrPlaneswalker; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChandraFireArtisan extends CardImpl { + + public ChandraFireArtisan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CHANDRA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Whenever one or more loyalty counters are removed from Chandra, Fire Artisan, she deals that much damage to target opponent or planeswalker. + this.addAbility(new ChandraFireArtisanTriggeredAbility()); + + // +1: Exile the top card of your library. You may play it this turn. + this.addAbility(new LoyaltyAbility(new ChandraFireArtisanEffect(false), 1)); + + // -7: Exile the top seven cards of your library. You may play them this turn. + this.addAbility(new LoyaltyAbility(new ChandraFireArtisanEffect(true), -7)); + } + + private ChandraFireArtisan(final ChandraFireArtisan card) { + super(card); + } + + @Override + public ChandraFireArtisan copy() { + return new ChandraFireArtisan(this); + } +} + +class ChandraFireArtisanTriggeredAbility extends TriggeredAbilityImpl { + + ChandraFireArtisanTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + this.addTarget(new TargetOpponentOrPlaneswalker()); + } + + private ChandraFireArtisanTriggeredAbility(final ChandraFireArtisanTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COUNTERS_REMOVED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getAmount() == 0 || !event.getData().equals("loyalty") + || !event.getTargetId().equals(getSourceId())) { + return false; + } + this.getEffects().clear(); + this.addEffect(new DamageTargetEffect(event.getAmount())); + return true; + } + + @Override + public ChandraFireArtisanTriggeredAbility copy() { + return new ChandraFireArtisanTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever one or more loyalty counters are removed from {this}, " + + "she deals that much damage to target opponent or planeswalker."; + } +} + +class ChandraFireArtisanEffect extends OneShotEffect { + + private final boolean exileSeven; + + ChandraFireArtisanEffect(boolean exileSeven) { + super(Outcome.Detriment); + this.exileSeven = exileSeven; + if (exileSeven) { + staticText = "Exile the top seven cards of your library. You may play them this turn."; + } else { + staticText = "Exile the top card of your library. You may play it this turn"; + } + } + + private ChandraFireArtisanEffect(final ChandraFireArtisanEffect effect) { + super(effect); + this.exileSeven = effect.exileSeven; + } + + @Override + public ChandraFireArtisanEffect copy() { + return new ChandraFireArtisanEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller == null || sourceObject == null) { + return false; + } + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, (exileSeven ? 7 : 1))); + controller.moveCards(cards, Zone.EXILED, source, game); + for (Card card : cards.getCards(game)) { + if (card == null) { + continue; + } + ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(effect, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java b/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java new file mode 100644 index 0000000000..d17dea561b --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChandraGremlinWrangler.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.permanent.token.GremlinToken; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChandraGremlinWrangler extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GREMLIN)); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + public ChandraGremlinWrangler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CHANDRA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // +1: Create a 2/2 red Gremlin creature token. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new GremlinToken()), 1)); + + // -2: Chandra, Gremlin Wrangler deals X damage to any target, where X is the number of Gremlins you control. + Ability ability = new LoyaltyAbility(new DamageTargetEffect(xValue).setText("{this} deals X damage to any target, where X is the number of Gremlins you control."), -2); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private ChandraGremlinWrangler(final ChandraGremlinWrangler card) { + super(card); + } + + @Override + public ChandraGremlinWrangler copy() { + return new ChandraGremlinWrangler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java index 027213fdb3..57a53d3191 100644 --- a/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java +++ b/Mage.Sets/src/mage/cards/c/ChandraPyromaster.java @@ -212,8 +212,7 @@ class ChandraPyromasterEffect3 extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 10)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 10)); controller.moveCardsToExile(cards.getCards(game), source, game, true, source.getSourceId(), sourceObject.getIdName()); if (!cards.getCards(new FilterInstantOrSorceryCard(), game).isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/c/ChandrasDefeat.java b/Mage.Sets/src/mage/cards/c/ChandrasDefeat.java index 23f2a0ca92..0da144b19c 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasDefeat.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasDefeat.java @@ -26,7 +26,7 @@ import mage.target.TargetPermanent; */ public final class ChandrasDefeat extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("creature or planeswalker"); + private static final FilterPermanent filter = new FilterPermanent("creature or planeswalker"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/c/ChandrasOutburst.java b/Mage.Sets/src/mage/cards/c/ChandrasOutburst.java index 6d682588f9..5d70eb1fb4 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasOutburst.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasOutburst.java @@ -17,7 +17,7 @@ import mage.target.common.TargetPlayerOrPlaneswalker; */ public final class ChandrasOutburst extends CardImpl { - private final static FilterCard filter = new FilterCard("Chandra, Bold Pyromancer"); + private static final FilterCard filter = new FilterCard("Chandra, Bold Pyromancer"); static { filter.add(new NamePredicate("Chandra, Bold Pyromancer")); diff --git a/Mage.Sets/src/mage/cards/c/ChandrasPyrohelix.java b/Mage.Sets/src/mage/cards/c/ChandrasPyrohelix.java index 7e31f1a07c..f2520c040c 100644 --- a/Mage.Sets/src/mage/cards/c/ChandrasPyrohelix.java +++ b/Mage.Sets/src/mage/cards/c/ChandrasPyrohelix.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -16,11 +15,11 @@ import mage.target.common.TargetAnyTargetAmount; public final class ChandrasPyrohelix extends CardImpl { public ChandrasPyrohelix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); - // Chandra's Pyrohelix deals 2 damage divided as you choose among one or two target creatures and/or players. + // Chandra's Pyrohelix deals 2 damage divided as you choose among one or two targets. Effect effect = new DamageMultiEffect(2); - effect.setText("{this} deals 2 damage divided as you choose among one or two target creatures and/or players"); + effect.setText("{this} deals 2 damage divided as you choose among one or two targets"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTargetAmount(2)); } diff --git a/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java b/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java new file mode 100644 index 0000000000..9ce80e45f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChandrasTriumph.java @@ -0,0 +1,84 @@ +package mage.cards.c; + +import mage.abilities.Ability; +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.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChandrasTriumph extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public ChandrasTriumph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Chandra's Triumph deals 3 damage to target creature or planeswalker an opponent controls. Chandra's Triumph deals 5 damage to that permanent instead + // if you control a Chandra planeswalker. + this.getSpellAbility().addEffect(new ChandrasTriumphEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private ChandrasTriumph(final ChandrasTriumph card) { + super(card); + } + + @Override + public ChandrasTriumph copy() { + return new ChandrasTriumph(this); + } +} + +class ChandrasTriumphEffect extends OneShotEffect { + + private static final FilterControlledPlaneswalkerPermanent filter + = new FilterControlledPlaneswalkerPermanent(SubType.CHANDRA); + + ChandrasTriumphEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 3 damage to target creature or planeswalker an opponent controls. " + + "{this} deals 5 damage to that permanent instead if you control a Chandra planeswalker."; + } + + private ChandrasTriumphEffect(final ChandrasTriumphEffect effect) { + super(effect); + } + + @Override + public ChandrasTriumphEffect copy() { + return new ChandrasTriumphEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + int damage = 3; + if (!game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game).isEmpty()) { + damage = 5; + } + return permanent.damage(damage, source.getSourceId(), game) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ChaosCharm.java b/Mage.Sets/src/mage/cards/c/ChaosCharm.java index 78ae9a01ec..e90b303b79 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosCharm.java +++ b/Mage.Sets/src/mage/cards/c/ChaosCharm.java @@ -37,13 +37,13 @@ public final class ChaosCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter)); // or Chaos Charm deals 1 damage to target creature Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(1)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new DamageTargetEffect(1)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target creature gains haste until end of turn. mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ChaosLord.java b/Mage.Sets/src/mage/cards/c/ChaosLord.java new file mode 100644 index 0000000000..b7f2cca6ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChaosLord.java @@ -0,0 +1,163 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.ControlsPermanentsComparedToOpponentsCondition; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.SubType; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author jeffwadsworth + */ +public final class ChaosLord extends CardImpl { + + public ChaosLord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}{R}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // At the beginning of your upkeep, target opponent gains control of Chaos Lord if the number of permanents is even. + Ability ability = new ChaosLordTriggeredAbility(); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + // Chaos Lord can attack as though it had haste unless it entered the battlefield this turn. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ChaosLordEffect())); + + } + + private ChaosLord(final ChaosLord card) { + super(card); + } + + @Override + public ChaosLord copy() { + return new ChaosLord(this); + } +} + +class ChaosLordTriggeredAbility extends BeginningOfUpkeepTriggeredAbility { + + public ChaosLordTriggeredAbility() { + super(Zone.BATTLEFIELD, + new GainControlSourceEffect(), + TargetController.YOU, + false); + } + + public ChaosLordTriggeredAbility(ChaosLordTriggeredAbility ability) { + super(ability); + } + + @Override + public BeginningOfUpkeepTriggeredAbility copy() { + return new ChaosLordTriggeredAbility(this); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + Condition condition = new ControlsPermanentsComparedToOpponentsCondition( + ComparisonType.EQUAL_TO, + new FilterPermanent()); + Player controller = game.getPlayer(controllerId); + if (controller != null + && condition.apply(game, this)) { + return super.checkInterveningIfClause(game); + } + return false; + } + + @Override + public String getRule() { + return "At the beginning of your upkeep, target opponent gains control of {this} if the number of permanents is even."; + } + +} + +class GainControlSourceEffect extends ContinuousEffectImpl { + + public GainControlSourceEffect() { + super(Duration.Custom, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + staticText = "target opponent gains control of {this}"; + } + + public GainControlSourceEffect(final GainControlSourceEffect effect) { + super(effect); + } + + @Override + public GainControlSourceEffect copy() { + return new GainControlSourceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); + if (permanent != null) { + return permanent.changeControllerId(source.getFirstTarget(), game); + } else { + discard(); + } + return false; + } +} + +class ChaosLordEffect extends AsThoughEffectImpl { + + public ChaosLordEffect() { + super(AsThoughEffectType.ATTACK_AS_HASTE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "Chaos Lord can attack as though it had haste unless it entered the battlefield this turn"; + } + + public ChaosLordEffect(final ChaosLordEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public ChaosLordEffect copy() { + return new ChaosLordEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + Permanent chaosLord = game.getPermanent(objectId); + return chaosLord != null + && objectId == source.getSourceId() + && chaosLord.getTurnsOnBattlefield() > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChaosMaw.java b/Mage.Sets/src/mage/cards/c/ChaosMaw.java index 7916f847db..c53c0263ea 100644 --- a/Mage.Sets/src/mage/cards/c/ChaosMaw.java +++ b/Mage.Sets/src/mage/cards/c/ChaosMaw.java @@ -14,7 +14,7 @@ import mage.filter.predicate.permanent.AnotherPredicate; public final class ChaosMaw extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ChaosMaw(UUID ownerId, CardSetInfo cardSetInfo){ super(ownerId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); diff --git a/Mage.Sets/src/mage/cards/c/Chaosphere.java b/Mage.Sets/src/mage/cards/c/Chaosphere.java index c7b2180bf4..12511380fc 100644 --- a/Mage.Sets/src/mage/cards/c/Chaosphere.java +++ b/Mage.Sets/src/mage/cards/c/Chaosphere.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -20,8 +18,9 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Chaosphere extends CardImpl { @@ -79,7 +78,10 @@ class ChaosphereEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.hasAbility(FlyingAbility.getInstance().getId(), game); } diff --git a/Mage.Sets/src/mage/cards/c/ChaoticGoo.java b/Mage.Sets/src/mage/cards/c/ChaoticGoo.java index 9e80008f07..d66c6778fe 100644 --- a/Mage.Sets/src/mage/cards/c/ChaoticGoo.java +++ b/Mage.Sets/src/mage/cards/c/ChaoticGoo.java @@ -67,7 +67,7 @@ class ChaoticGooEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.informPlayers("Chaotic Goo: Won flip. Put a +1/+1 counter on Chaotic Goo."); new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)).apply(game, source); return true; diff --git a/Mage.Sets/src/mage/cards/c/ChaoticStrike.java b/Mage.Sets/src/mage/cards/c/ChaoticStrike.java index 49424f1723..2c97e2a415 100644 --- a/Mage.Sets/src/mage/cards/c/ChaoticStrike.java +++ b/Mage.Sets/src/mage/cards/c/ChaoticStrike.java @@ -65,7 +65,7 @@ class ChaoticStrikeEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.addEffect(new BoostTargetEffect(1, 1, Duration.EndOfTurn), source); return true; } diff --git a/Mage.Sets/src/mage/cards/c/ChargingCinderhorn.java b/Mage.Sets/src/mage/cards/c/ChargingCinderhorn.java index 52d71ff766..28603c5d0f 100644 --- a/Mage.Sets/src/mage/cards/c/ChargingCinderhorn.java +++ b/Mage.Sets/src/mage/cards/c/ChargingCinderhorn.java @@ -62,7 +62,7 @@ class ChargingCinderhornCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null) { return watcher.getAttackedThisTurnCreatures().isEmpty(); } diff --git a/Mage.Sets/src/mage/cards/c/ChargingWarBoar.java b/Mage.Sets/src/mage/cards/c/ChargingWarBoar.java new file mode 100644 index 0000000000..58c8cdd961 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ChargingWarBoar.java @@ -0,0 +1,68 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ChargingWarBoar extends CardImpl { + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(new FilterControlledPlaneswalkerPermanent(SubType.DOMRI)); + private static final ConditionHint hint = new ConditionHint(condition, "You control Domri planeswalker"); + + public ChargingWarBoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.subtype.add(SubType.BOAR); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // As long as you control a Domri planeswalker, Charging War Boar gets +1/+1 and has trample. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield), + condition, "As long as you control a Domri planeswalker, {this} gets +1/+1" + ) + ); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield + ), condition, "and has trample" + )); + ability.addHint(hint); + this.addAbility(ability); + } + + private ChargingWarBoar(final ChargingWarBoar card) { + super(card); + } + + @Override + public ChargingWarBoar copy() { + return new ChargingWarBoar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CharityExtractor.java b/Mage.Sets/src/mage/cards/c/CharityExtractor.java new file mode 100644 index 0000000000..d815a3230f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CharityExtractor.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import mage.MageInt; +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 CharityExtractor extends CardImpl { + + public CharityExtractor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(5); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + } + + private CharityExtractor(final CharityExtractor card) { + super(card); + } + + @Override + public CharityExtractor copy() { + return new CharityExtractor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java b/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java index 2d4f308185..2158bd95f8 100644 --- a/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java +++ b/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java @@ -90,7 +90,7 @@ class CharmbreakerDevilsEffect extends OneShotEffect { if (cards.length > 0) { Card card = cards[RandomUtil.nextInt(cards.length)]; card.moveToZone(Zone.HAND, source.getSourceId(), game, true); - game.informPlayers(new StringBuilder("Charmbreaker Devils: ").append(card.getName()).append(" returned to the hand of ").append(player.getLogName()).toString()); + game.informPlayers("Charmbreaker Devils: " + card.getName() + " returned to the hand of " + player.getLogName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CharmedStray.java b/Mage.Sets/src/mage/cards/c/CharmedStray.java new file mode 100644 index 0000000000..a684da4063 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CharmedStray.java @@ -0,0 +1,56 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +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 mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CharmedStray extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("other creature you control named Charmed Stray"); + + static { + filter.add(new NamePredicate("Charmed Stray")); + filter.add(AnotherPredicate.instance); + } + + public CharmedStray(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever Charmed Stray enters the battlefield, put a +1/+1 counter on each other creature you control named Charmed Stray. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter) + )); + } + + private CharmedStray(final CharmedStray card) { + super(card); + } + + @Override + public CharmedStray copy() { + return new CharmedStray(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CherishedHatchling.java b/Mage.Sets/src/mage/cards/c/CherishedHatchling.java index 46363fd917..a4bfcdfa48 100644 --- a/Mage.Sets/src/mage/cards/c/CherishedHatchling.java +++ b/Mage.Sets/src/mage/cards/c/CherishedHatchling.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -27,8 +25,9 @@ import mage.game.stack.Spell; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CherishedHatchling extends CardImpl { @@ -67,7 +66,7 @@ class CherishedHatchlingTriggeredAbility extends DelayedTriggeredAbility { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CherishedHatchlingTriggeredAbility() { @@ -113,48 +112,3 @@ class CherishedHatchlingTriggeredAbility extends DelayedTriggeredAbility { return "and whenever you cast a Dinosaur spell this turn, " + super.getRule(); } } - -//class CherishedHatchlingGainAbilityEffect extends ContinuousEffectImpl { -// -// private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); -// -// static { -// filter.add(new AnotherPredicate()); -// } -// private Ability abilityToAdd = null; -// private Card relatedCard = null; -// -// public CherishedHatchlingGainAbilityEffect() { -// super(Duration.EndOfTurn, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); -// staticText = "it gains \"When this creature enters the battlefield, you may have it fight another target creature.\""; -// } -// -// public CherishedHatchlingGainAbilityEffect(final CherishedHatchlingGainAbilityEffect effect) { -// super(effect); -// this.abilityToAdd = effect.abilityToAdd; -// this.relatedCard = effect.relatedCard; -// } -// -// @Override -// public CherishedHatchlingGainAbilityEffect copy() { -// return new CherishedHatchlingGainAbilityEffect(this); -// } -// -// @Override -// public boolean apply(Game game, Ability source) { -// if (relatedCard == null) { -// Spell spell = game.getStack().getSpell(getTargetPointer().getFirst(game, source)); -// if (spell != null) { -// relatedCard = game.getCard(spell.getSourceId()); -// Effect effect = new FightTargetSourceEffect(); -// effect.setText("you may have it fight another target creature"); -// abilityToAdd = new EntersBattlefieldTriggeredAbility(effect, true); -// abilityToAdd.addTarget(new TargetCreaturePermanent(filter)); -// } -// } -// if (relatedCard != null) { -// game.getState().addOtherAbility(relatedCard, abilityToAdd, false); -// } -// return true; -// } -//} diff --git a/Mage.Sets/src/mage/cards/c/Chewbacca.java b/Mage.Sets/src/mage/cards/c/Chewbacca.java index 66f13c8ea0..be15218f89 100644 --- a/Mage.Sets/src/mage/cards/c/Chewbacca.java +++ b/Mage.Sets/src/mage/cards/c/Chewbacca.java @@ -26,7 +26,7 @@ public final class Chewbacca extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Chewbacca(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java b/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java index d206feff7e..f7ffe1d408 100644 --- a/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java +++ b/Mage.Sets/src/mage/cards/c/ChewbaccaTheBeast.java @@ -27,8 +27,8 @@ public final class ChewbaccaTheBeast extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); - filter.add(new AttackingPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(AttackingPredicate.instance); } public ChewbaccaTheBeast(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ChickenALaKing.java b/Mage.Sets/src/mage/cards/c/ChickenALaKing.java index 54fc631a3b..db786af300 100644 --- a/Mage.Sets/src/mage/cards/c/ChickenALaKing.java +++ b/Mage.Sets/src/mage/cards/c/ChickenALaKing.java @@ -33,7 +33,7 @@ public final class ChickenALaKing extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Chicken you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.CHICKEN)); } diff --git a/Mage.Sets/src/mage/cards/c/ChiefChirpa.java b/Mage.Sets/src/mage/cards/c/ChiefChirpa.java index 4751f53f00..5cd547a440 100644 --- a/Mage.Sets/src/mage/cards/c/ChiefChirpa.java +++ b/Mage.Sets/src/mage/cards/c/ChiefChirpa.java @@ -40,7 +40,7 @@ public final class ChiefChirpa extends CardImpl { diedFilter.add(new ControllerPredicate(TargetController.YOU)); ewokFilter.add(new SubtypePredicate(SubType.EWOK)); - ewokFilter.add(new AnotherPredicate()); + ewokFilter.add(AnotherPredicate.instance); } public ChiefChirpa(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ChieftainEnDal.java b/Mage.Sets/src/mage/cards/c/ChieftainEnDal.java index 94468b8b24..2cddae6857 100644 --- a/Mage.Sets/src/mage/cards/c/ChieftainEnDal.java +++ b/Mage.Sets/src/mage/cards/c/ChieftainEnDal.java @@ -1,21 +1,20 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; -import mage.filter.common.FilterAttackingCreature; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ChieftainEnDal extends CardImpl { @@ -29,11 +28,12 @@ public final class ChieftainEnDal extends CardImpl { this.toughness = new MageInt(2); // Whenever Chieftain en-Dal attacks, attacking creatures gain first strike until end of turn. - Ability ability = new AttacksTriggeredAbility(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, new FilterAttackingCreature()), false); - this.addAbility(ability); + this.addAbility(new AttacksTriggeredAbility(new GainAbilityAllEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_ATTACKING_CREATURES + ), false)); } - public ChieftainEnDal(final ChieftainEnDal card) { + private ChieftainEnDal(final ChieftainEnDal card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/ChildrenOfKorlis.java b/Mage.Sets/src/mage/cards/c/ChildrenOfKorlis.java index c38f2ec2f4..6275d1f0f3 100644 --- a/Mage.Sets/src/mage/cards/c/ChildrenOfKorlis.java +++ b/Mage.Sets/src/mage/cards/c/ChildrenOfKorlis.java @@ -52,9 +52,9 @@ class SourceControllerLostLifeCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { - return watcher.getLiveLost(sourceAbility.getControllerId()); + return watcher.getLifeLost(sourceAbility.getControllerId()); } return 0; } diff --git a/Mage.Sets/src/mage/cards/c/ChillHaunting.java b/Mage.Sets/src/mage/cards/c/ChillHaunting.java index 2730c08155..c35832ceb8 100644 --- a/Mage.Sets/src/mage/cards/c/ChillHaunting.java +++ b/Mage.Sets/src/mage/cards/c/ChillHaunting.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.costs.common.ExileXFromYourGraveCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.GetXValue; @@ -11,28 +10,30 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreatureCard; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ChillHaunting extends CardImpl { + private static final DynamicValue xval = new SignInversionDynamicValue(GetXValue.instance); + public ChillHaunting(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // As an additional cost to cast Chill Haunting, exile X creature cards from your graveyard. - this.getSpellAbility().addCost(new ExileXFromYourGraveCost(new FilterCreatureCard("creature cards from your graveyard"), true)); + this.getSpellAbility().addCost(new ExileXFromYourGraveCost(StaticFilters.FILTER_CARD_CREATURES_YOUR_GRAVEYARD, true)); // Target creature gets -X/-X until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - DynamicValue xval = new SignInversionDynamicValue(new GetXValue()); this.getSpellAbility().addEffect(new BoostTargetEffect(xval, xval, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } - public ChillHaunting(final ChillHaunting card) { + private ChillHaunting(final ChillHaunting card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/Chillbringer.java b/Mage.Sets/src/mage/cards/c/Chillbringer.java new file mode 100644 index 0000000000..bd03de10b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Chillbringer.java @@ -0,0 +1,47 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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 Chillbringer extends CardImpl { + + public Chillbringer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Chillbringer enters the battlefield, tap target creature an opponent controls. It doesn't untap during its controller's next untap step. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("It")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private Chillbringer(final Chillbringer card) { + super(card); + } + + @Override + public Chillbringer copy() { + return new Chillbringer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ChimeOfNight.java b/Mage.Sets/src/mage/cards/c/ChimeOfNight.java index 5f3a207f0b..60ae0c6148 100644 --- a/Mage.Sets/src/mage/cards/c/ChimeOfNight.java +++ b/Mage.Sets/src/mage/cards/c/ChimeOfNight.java @@ -1,25 +1,25 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; -import mage.target.common.TargetCreaturePermanent; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.constants.Outcome; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ChimeOfNight extends CardImpl { @@ -43,7 +43,7 @@ public final class ChimeOfNight extends CardImpl { this.addAbility(ability); // When Chime of Night is put into a graveyard from the battlefield, destroy target nonblack creature. - ability = new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DestroyTargetEffect(), false); + ability = new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DestroyTargetEffect()); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/ChimericEgg.java b/Mage.Sets/src/mage/cards/c/ChimericEgg.java index 88816bba41..5508713638 100644 --- a/Mage.Sets/src/mage/cards/c/ChimericEgg.java +++ b/Mage.Sets/src/mage/cards/c/ChimericEgg.java @@ -31,7 +31,7 @@ import mage.game.permanent.token.custom.CreatureToken; */ public final class ChimericEgg extends CardImpl { - private final static FilterSpell nonArtifactFilter = new FilterSpell("a nonartifact spell"); + private static final FilterSpell nonArtifactFilter = new FilterSpell("a nonartifact spell"); static { nonArtifactFilter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); diff --git a/Mage.Sets/src/mage/cards/c/ChiseiHeartOfOceans.java b/Mage.Sets/src/mage/cards/c/ChiseiHeartOfOceans.java index 207982df3b..916b686a1c 100644 --- a/Mage.Sets/src/mage/cards/c/ChiseiHeartOfOceans.java +++ b/Mage.Sets/src/mage/cards/c/ChiseiHeartOfOceans.java @@ -29,7 +29,7 @@ public final class ChiseiHeartOfOceans extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new CounterAnyPredicate()); + filter.add(CounterAnyPredicate.instance); } public ChiseiHeartOfOceans(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ChorusOfMight.java b/Mage.Sets/src/mage/cards/c/ChorusOfMight.java index 4480ae2717..04a33b7f04 100644 --- a/Mage.Sets/src/mage/cards/c/ChorusOfMight.java +++ b/Mage.Sets/src/mage/cards/c/ChorusOfMight.java @@ -1,8 +1,5 @@ - - package mage.cards.c; -import java.util.UUID; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -11,21 +8,22 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ChorusOfMight extends CardImpl { public ChorusOfMight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); + - // Until end of turn, target creature gets +1/+1 for each creature you control and gains trample. - PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); + PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new BoostTargetEffect(value, value, Duration.EndOfTurn, true)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java index 5a31f0d5b8..e4771fc0e7 100644 --- a/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java +++ b/Mage.Sets/src/mage/cards/c/ChosenOfMarkov.java @@ -28,7 +28,7 @@ public final class ChosenOfMarkov extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Vampire you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/c/ChromeMox.java b/Mage.Sets/src/mage/cards/c/ChromeMox.java index b3b414ee19..75fd118e48 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeMox.java +++ b/Mage.Sets/src/mage/cards/c/ChromeMox.java @@ -1,8 +1,5 @@ package mage.cards.c; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.Mana; import mage.ObjectColor; @@ -30,8 +27,11 @@ import mage.target.TargetCard; import mage.util.CardUtil; import mage.util.GameLog; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author Plopman */ public final class ChromeMox extends CardImpl { @@ -141,7 +141,7 @@ class ChromeMoxManaEffect extends ManaEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { List imprinted = permanent.getImprinted(); - if (!imprinted.isEmpty()) { + if (imprinted != null && !imprinted.isEmpty()) { Card imprintedCard = game.getCard(imprinted.get(0)); if (imprintedCard != null) { ObjectColor color = imprintedCard.getColor(game); @@ -172,7 +172,7 @@ class ChromeMoxManaEffect extends ManaEffect { Player player = game.getPlayer(source.getControllerId()); if (permanent != null && player != null) { List imprinted = permanent.getImprinted(); - if (!imprinted.isEmpty()) { + if (imprinted != null && !imprinted.isEmpty()) { Card imprintedCard = game.getCard(imprinted.get(0)); if (imprintedCard != null) { Choice choice = new ChoiceColor(true); diff --git a/Mage.Sets/src/mage/cards/c/ChromeSteed.java b/Mage.Sets/src/mage/cards/c/ChromeSteed.java index b0e34f7e10..87b468f3c2 100644 --- a/Mage.Sets/src/mage/cards/c/ChromeSteed.java +++ b/Mage.Sets/src/mage/cards/c/ChromeSteed.java @@ -2,38 +2,42 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author Loki */ public final class ChromeSteed extends CardImpl { - private static final String text = "Metalcraft — Chrome Steed gets +2/+2 as long as you control three or more artifacts"; - public ChromeSteed (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + public ChromeSteed(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.HORSE); this.power = new MageInt(2); this.toughness = new MageInt(2); - ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, text); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + MetalcraftCondition.instance, "Metalcraft — {this} gets " + + "+2/+2 as long as you control three or more artifacts" + ) + )); } - public ChromeSteed (final ChromeSteed card) { + public ChromeSteed(final ChromeSteed card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CinderCloud.java b/Mage.Sets/src/mage/cards/c/CinderCloud.java index 24d02c18e8..9cdc408293 100644 --- a/Mage.Sets/src/mage/cards/c/CinderCloud.java +++ b/Mage.Sets/src/mage/cards/c/CinderCloud.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -15,8 +14,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author ciaccona007 */ public final class CinderCloud extends CardImpl { @@ -43,7 +43,8 @@ class CinderCloudEffect extends OneShotEffect { public CinderCloudEffect() { super(Outcome.Benefit); - this.staticText = "Destroy target creature. If a white creature dies this way, {this} deals damage to that creature's controller equal to the creature's power"; + this.staticText = "Destroy target creature. If a white creature dies this way, " + + "{this} deals damage to that creature's controller equal to the creature's power"; } public CinderCloudEffect(final CinderCloudEffect effect) { @@ -71,6 +72,6 @@ class CinderCloudEffect extends OneShotEffect { permanentController.damage(damage, source.getSourceId(), game, false, true); } } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/c/CinderElemental.java b/Mage.Sets/src/mage/cards/c/CinderElemental.java index 8adeae708e..16a0dfcae5 100644 --- a/Mage.Sets/src/mage/cards/c/CinderElemental.java +++ b/Mage.Sets/src/mage/cards/c/CinderElemental.java @@ -31,7 +31,7 @@ public final class CinderElemental extends CardImpl { this.toughness = new MageInt(2); // {X}{R}, {tap}, Sacrifice Cinder Elemental: Cinder Elemental deals X damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{R}")); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/c/CinderGiant.java b/Mage.Sets/src/mage/cards/c/CinderGiant.java index bce7205df5..24cfbac228 100644 --- a/Mage.Sets/src/mage/cards/c/CinderGiant.java +++ b/Mage.Sets/src/mage/cards/c/CinderGiant.java @@ -21,7 +21,7 @@ public final class CinderGiant extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("each other creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CinderGiant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/Cindervines.java b/Mage.Sets/src/mage/cards/c/Cindervines.java new file mode 100644 index 0000000000..80233fc945 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cindervines.java @@ -0,0 +1,88 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Cindervines extends CardImpl { + + public Cindervines(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{G}"); + + // Whenever an opponent casts a noncreature spell, Cindervines deals 1 damage to that player. + this.addAbility(new SpellCastOpponentTriggeredAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(1, true, "that player"), + StaticFilters.FILTER_SPELL_NON_CREATURE, false, SetTargetPointer.PLAYER + )); + + // {1}, Sacrifice Cindervines: Destroy target artifact or enchantment. Cindervines deals 2 damage to that permanent's controller. + Ability ability = new SimpleActivatedAbility( + new CindervinesEffect(), new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + this.addAbility(ability); + } + + private Cindervines(final Cindervines card) { + super(card); + } + + @Override + public Cindervines copy() { + return new Cindervines(this); + } +} + +class CindervinesEffect extends OneShotEffect { + + CindervinesEffect() { + super(Outcome.Benefit); + staticText = "Destroy target artifact or enchantment. " + + "{this} deals 2 damage to that permanent's controller."; + } + + private CindervinesEffect(final CindervinesEffect effect) { + super(effect); + } + + @Override + public CindervinesEffect copy() { + return new CindervinesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + permanent.destroy(source.getSourceId(), game, false); + player.damage(2, source.getSourceId(), game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CircleOfAffliction.java b/Mage.Sets/src/mage/cards/c/CircleOfAffliction.java index cc3962342f..4091fb8bf0 100644 --- a/Mage.Sets/src/mage/cards/c/CircleOfAffliction.java +++ b/Mage.Sets/src/mage/cards/c/CircleOfAffliction.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.UUID; @@ -29,7 +28,7 @@ import mage.target.TargetPlayer; public final class CircleOfAffliction extends CardImpl { public CircleOfAffliction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // As Circle of Affliction enters the battlefield, choose a color. this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); @@ -69,12 +68,12 @@ class CircleOfAfflictionTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent circleOfAffliction = game.getPermanentOrLKIBattlefield(getSourceId()); - if (circleOfAffliction != null) { + if (circleOfAffliction != null && event.getTargetId().equals(getControllerId())) { ObjectColor chosenColor = (ObjectColor) game.getState().getValue(circleOfAffliction.getId() + "_color"); if (chosenColor != null) { MageObject damageSource = game.getObject(event.getSourceId()); if (damageSource != null) { - if ( damageSource.getColor(game).shares(chosenColor) ) { + if (damageSource.getColor(game).shares(chosenColor)) { return true; } } @@ -92,4 +91,4 @@ class CircleOfAfflictionTriggeredAbility extends TriggeredAbilityImpl { public String getRule() { return "Whenever a source of the chosen color deals damage to you, you may pay {1}. If you do, target player loses 1 life and you gain 1 life."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java index 84ec986fd2..8d8972b26a 100644 --- a/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java +++ b/Mage.Sets/src/mage/cards/c/CircuDimirLobotomist.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageInt; @@ -136,7 +135,7 @@ class CircuDimirLobotomistRuleModifyingEffect extends ContinuousRuleModifyingEff ExileZone exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if ((exileZone != null)) { for (Card card : exileZone.getCards(game)) { - if ((card.getName().equals(object.getName()))) { + if (CardUtil.haveSameNames(card, object)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CitadelOfPain.java b/Mage.Sets/src/mage/cards/c/CitadelOfPain.java index 40973164a4..1cf2bbde90 100644 --- a/Mage.Sets/src/mage/cards/c/CitadelOfPain.java +++ b/Mage.Sets/src/mage/cards/c/CitadelOfPain.java @@ -56,7 +56,7 @@ class CitadelOfPainEffect extends OneShotEffect { } static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public CitadelOfPainEffect() { diff --git a/Mage.Sets/src/mage/cards/c/CitadelSiege.java b/Mage.Sets/src/mage/cards/c/CitadelSiege.java index 86093720e5..84764fb93d 100644 --- a/Mage.Sets/src/mage/cards/c/CitadelSiege.java +++ b/Mage.Sets/src/mage/cards/c/CitadelSiege.java @@ -15,28 +15,33 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.Predicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; /** - * * @author LevelX2 */ public final class CitadelSiege extends CardImpl { - private final static String ruleTrigger1 = "&bull Khans — At the beginning of combat on your turn, put two +1/+1 counters on target creature you control."; - private final static String ruleTrigger2 = "&bull Dragons — At the beginning of combat on each opponent's turn, tap target creature that player controls."; + private static final String ruleTrigger1 = "&bull Khans — At the beginning of combat on your turn, put two +1/+1 counters on target creature you control."; + private static final String ruleTrigger2 = "&bull Dragons — At the beginning of combat on each opponent's turn, tap target creature that player controls."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by the active player"); + + static { + filter.add(CitadelSiegePredicate.instance); + } public CitadelSiege(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // As Citadel Siege enters the battlefield, choose Khans or Dragons. - this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?","Khans", "Dragons"),null, - "As {this} enters the battlefield, choose Khans or Dragons.","")); + this.addAbility(new EntersBattlefieldAbility(new ChooseModeEffect("Khans or Dragons?", "Khans", "Dragons"), null, + "As {this} enters the battlefield, choose Khans or Dragons.", "")); // * Khans - At the beginning of combat on your turn, put two +1/+1 counters on target creature you control. Ability ability = new ConditionalTriggeredAbility( @@ -51,21 +56,10 @@ public final class CitadelSiege extends CardImpl { new BeginningOfCombatTriggeredAbility(new TapTargetEffect(), TargetController.OPPONENT, false), new ModeChoiceSourceCondition("Dragons"), ruleTrigger2); - ability.addTarget(new TargetCreaturePermanent()); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (this.getAbilities().contains(ability) && ability.getRule().startsWith("&bull Dragons")) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that player controls"); - filter.add(new ControllerIdPredicate(game.getCombat().getAttackingPlayerId())); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } - - public CitadelSiege(final CitadelSiege card) { super(card); } @@ -75,3 +69,12 @@ public final class CitadelSiege extends CardImpl { return new CitadelSiege(this); } } + +enum CitadelSiegePredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + return input.getControllerId().equals(game.getActivePlayerId()); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CitanulFlute.java b/Mage.Sets/src/mage/cards/c/CitanulFlute.java index 1af7222872..de2556d10b 100644 --- a/Mage.Sets/src/mage/cards/c/CitanulFlute.java +++ b/Mage.Sets/src/mage/cards/c/CitanulFlute.java @@ -74,7 +74,7 @@ class CitanulFluteSearchEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); Cards cards = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/c/CityInABottle.java b/Mage.Sets/src/mage/cards/c/CityInABottle.java index 00a469b756..547ba0933e 100644 --- a/Mage.Sets/src/mage/cards/c/CityInABottle.java +++ b/Mage.Sets/src/mage/cards/c/CityInABottle.java @@ -139,7 +139,7 @@ class CityInABottleStateTriggeredAbility extends StateTriggeredAbility { private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent originally printed in the Arabian Nights expansion other than City in a Bottle"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(Predicates.or(getArabianNightsNamePredicates())); } @@ -173,7 +173,7 @@ class CityInABottleSacrificeEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent originally printed in the Arabian Nights expansion other than City in a Bottle"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(Predicates.or(getArabianNightsNamePredicates())); } diff --git a/Mage.Sets/src/mage/cards/c/CivicStalwart.java b/Mage.Sets/src/mage/cards/c/CivicStalwart.java new file mode 100644 index 0000000000..b9f6fecc0e --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CivicStalwart.java @@ -0,0 +1,40 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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.SubType; +import mage.filter.common.FilterCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class CivicStalwart extends CardImpl { + + public CivicStalwart(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Civic Stalwart enters the battlefield, creatures you control get +1/+1 until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new BoostControlledEffect(1, 1, Duration.EndOfTurn, new FilterCreaturePermanent("creatures")))); + } + + public CivicStalwart(final CivicStalwart card) { + super(card); + } + + @Override + public CivicStalwart copy() { + return new CivicStalwart(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java index 775632b928..0f3f1eb7d2 100644 --- a/Mage.Sets/src/mage/cards/c/CivilizedScholar.java +++ b/Mage.Sets/src/mage/cards/c/CivilizedScholar.java @@ -12,6 +12,7 @@ import mage.abilities.keyword.TransformAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.h.HomicidalBruteWatcher; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; @@ -54,31 +55,7 @@ public final class CivilizedScholar extends CardImpl { } } -class HomicidalBruteWatcher extends Watcher { - public HomicidalBruteWatcher() { - super(HomicidalBruteWatcher.class.getSimpleName(), WatcherScope.CARD); - } - - public HomicidalBruteWatcher(final HomicidalBruteWatcher watcher) { - super(watcher); - } - - @Override - public HomicidalBruteWatcher copy() { - return new HomicidalBruteWatcher(this); - } - - @Override - public void watch(GameEvent event, Game game) { - if (condition == true) { - return; - } - if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(sourceId)) { - condition = true; - } - } -} class CivilizedScholarEffect extends OneShotEffect { @@ -87,7 +64,7 @@ class CivilizedScholarEffect extends OneShotEffect { staticText = "Draw a card, then discard a card. If a creature card is discarded this way, untap {this}, then transform it"; } - public CivilizedScholarEffect(final CivilizedScholarEffect effect) { + private CivilizedScholarEffect(final CivilizedScholarEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/c/ClaimFame.java b/Mage.Sets/src/mage/cards/c/ClaimFame.java index f0444ad01a..5ebf4cfa89 100644 --- a/Mage.Sets/src/mage/cards/c/ClaimFame.java +++ b/Mage.Sets/src/mage/cards/c/ClaimFame.java @@ -42,7 +42,7 @@ public final class ClaimFame extends SplitCard { // Fame // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Target creature gets +2/+0 and gains haste until end of turn. getRightHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); getRightHalfCard().getSpellAbility().addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn) diff --git a/Mage.Sets/src/mage/cards/c/ClamorShaman.java b/Mage.Sets/src/mage/cards/c/ClamorShaman.java new file mode 100644 index 0000000000..3d8e5b0fea --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClamorShaman.java @@ -0,0 +1,49 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClamorShaman extends CardImpl { + + public ClamorShaman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Riot + this.addAbility(new RiotAbility()); + + // Whenever Clamor Shaman attacks, target creature an opponent controls can't block this turn. + Ability ability = new AttacksTriggeredAbility( + new CantBlockTargetEffect(Duration.EndOfTurn), false + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private ClamorShaman(final ClamorShaman card) { + super(card); + } + + @Override + public ClamorShaman copy() { + return new ClamorShaman(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClanDefiance.java b/Mage.Sets/src/mage/cards/c/ClanDefiance.java index c1e0243d4e..cd3a2dc270 100644 --- a/Mage.Sets/src/mage/cards/c/ClanDefiance.java +++ b/Mage.Sets/src/mage/cards/c/ClanDefiance.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.DamageTargetEffect; @@ -15,18 +13,19 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class ClanDefiance extends CardImpl { - static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); - static final private FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature without flying"); + static final private FilterCreaturePermanent filterFlying = new FilterCreaturePermanent("creature with flying"); + static final private FilterCreaturePermanent filterWithoutFlying = new FilterCreaturePermanent("creature without flying"); static { - filter.add(new AbilityPredicate(FlyingAbility.class)); - filter2.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + filterFlying.add(new AbilityPredicate(FlyingAbility.class)); + filterWithoutFlying.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } public ClanDefiance(UUID ownerId, CardSetInfo setInfo) { @@ -36,17 +35,17 @@ public final class ClanDefiance extends CardImpl { this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(3); // Clan Defiance deals X damage to target creature with flying; - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterFlying).withChooseHint("deals X damage, with flying")); // Clan Defiance deals X damage to target creature without flying; Mode mode1 = new Mode(); - mode1.getEffects().add(new DamageTargetEffect(new ManacostVariableValue())); - mode1.getTargets().add(new TargetCreaturePermanent(filter2)); + mode1.addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + mode1.addTarget(new TargetCreaturePermanent(filterWithoutFlying).withChooseHint("deals X damage, without flying")); this.getSpellAbility().addMode(mode1); // and/or Clan Defiance deals X damage to target player. Mode mode2 = new Mode(); - mode2.getEffects().add(new DamageTargetEffect(new ManacostVariableValue())); - mode2.getTargets().add(new TargetPlayerOrPlaneswalker()); + mode2.addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + mode2.addTarget(new TargetPlayerOrPlaneswalker().withChooseHint("deals X damage")); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/c/ClanGuildmage.java b/Mage.Sets/src/mage/cards/c/ClanGuildmage.java new file mode 100644 index 0000000000..85ba5ee568 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClanGuildmage.java @@ -0,0 +1,85 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClanGuildmage extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledLandPermanent(); + + public ClanGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{R}, {T}: Target creature can't block this turn. + Ability ability = new SimpleActivatedAbility( + new CantBlockTargetEffect(Duration.EndOfTurn), new ManaCostsImpl("{1}{R}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // {2}{G}, {T}: Target land you control becomes a 4/4 Elemental creature with haste until end of turn. It's still a land. + ability = new SimpleActivatedAbility(new BecomesCreatureTargetEffect( + new ClanGuildmageToken(), false, true, Duration.EndOfTurn + ), new ManaCostsImpl("{2}{G}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private ClanGuildmage(final ClanGuildmage card) { + super(card); + } + + @Override + public ClanGuildmage copy() { + return new ClanGuildmage(this); + } +} + +class ClanGuildmageToken extends TokenImpl { + + public ClanGuildmageToken() { + super("", "4/4 Elemental creature with haste"); + this.cardType.add(CardType.CREATURE); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + this.addAbility(HasteAbility.getInstance()); + } + + public ClanGuildmageToken(final ClanGuildmageToken token) { + super(token); + } + + public ClanGuildmageToken copy() { + return new ClanGuildmageToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java index c1528dfa3a..460d287979 100644 --- a/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/ClarionUltimatum.java @@ -80,7 +80,7 @@ class ClarionUltimatumEffect extends OneShotEffect { FilterCard filter = new FilterCard("card named " + cardName); filter.add(new NamePredicate(cardName)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { chosenCards.add(card); diff --git a/Mage.Sets/src/mage/cards/c/ClashOfWills.java b/Mage.Sets/src/mage/cards/c/ClashOfWills.java index 0108bc2691..a16fe93da3 100644 --- a/Mage.Sets/src/mage/cards/c/ClashOfWills.java +++ b/Mage.Sets/src/mage/cards/c/ClashOfWills.java @@ -19,7 +19,7 @@ public final class ClashOfWills extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); // Counter target spell unless its controller pays {X}. - this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetSpell()); } diff --git a/Mage.Sets/src/mage/cards/c/Cleansing.java b/Mage.Sets/src/mage/cards/c/Cleansing.java index 29f62f0d3d..457e84620b 100644 --- a/Mage.Sets/src/mage/cards/c/Cleansing.java +++ b/Mage.Sets/src/mage/cards/c/Cleansing.java @@ -55,17 +55,18 @@ class CleansingEffect extends OneShotEffect { boolean paidLife = false; Permanent p = permanents.next(); if (p.isLand()) { - paidLife = false; game.informPlayers("Any player may pay 1 life to prevent the destruction of " + p.getLogName() + " controlled by " + game.getPlayer(p.getControllerId()).getLogName() + "."); PayLifeCost cost = new PayLifeCost(1); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); - cost.clearPaid(); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Pay 1 life to prevent this?", source, game)) { - if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { - game.informPlayers(player.getLogName() + " pays 1 life to prevent the destruction of " + p.getLogName()); - paidLife = true; + if(player != null) { + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Pay 1 life to prevent this?", source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + game.informPlayers(player.getLogName() + " pays 1 life to prevent the destruction of " + p.getLogName()); + paidLife = true; + } } } } diff --git a/Mage.Sets/src/mage/cards/c/CleansingNova.java b/Mage.Sets/src/mage/cards/c/CleansingNova.java index c3b1237329..457c54e923 100644 --- a/Mage.Sets/src/mage/cards/c/CleansingNova.java +++ b/Mage.Sets/src/mage/cards/c/CleansingNova.java @@ -27,7 +27,7 @@ public final class CleansingNova extends CardImpl { // • Destroy all artifacts and enchantments. Mode mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(filter)); + mode.addEffect(new DestroyAllEffect(filter)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CleansingRay.java b/Mage.Sets/src/mage/cards/c/CleansingRay.java index 62dbb482ae..52bc1eb902 100644 --- a/Mage.Sets/src/mage/cards/c/CleansingRay.java +++ b/Mage.Sets/src/mage/cards/c/CleansingRay.java @@ -31,8 +31,8 @@ public final class CleansingRay extends CardImpl { // - Destroy target enchantment. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetEnchantmentPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ClearTheLand.java b/Mage.Sets/src/mage/cards/c/ClearTheLand.java new file mode 100644 index 0000000000..5f1a55058a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClearTheLand.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Library; +import mage.players.Player; + +/** + * + * @author davidmfritz + */ +public final class ClearTheLand extends CardImpl { + + public ClearTheLand(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + + // Each player reveals the top five cards of their library, puts all land cards revealed this way onto the battlefield tapped, and exiles the rest. + getSpellAbility().addEffect(new ClearTheLandEffect()); + } + + public ClearTheLand(final ClearTheLand card) { + super(card); + } + + @Override + public ClearTheLand copy() { + return new ClearTheLand(this); + } +} + +class ClearTheLandEffect extends OneShotEffect { + + public ClearTheLandEffect() { + super(Outcome.Benefit); + this.staticText = "Each player reveals the top five cards of their library, puts all land cards revealed this way onto the battlefield tapped, and exiles the rest."; + } + + public ClearTheLandEffect(final ClearTheLandEffect effect) { + super(effect); + } + + @Override + public ClearTheLandEffect copy() { + return new ClearTheLandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + + boolean tapped = true; + + Player controller = game.getPlayer(source.getControllerId()); + + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Library library = player.getLibrary(); + Cards cardsToReveal = new CardsImpl(); + cardsToReveal.addAll(library.getTopCards(game, 5)); + if (!cardsToReveal.isEmpty()) { + player.revealCards(source, "Revealed cards for " + player.getName(), cardsToReveal, game); + Cards cardsToPutOnBattlefield = new CardsImpl(); + Cards cardsToExile = new CardsImpl(); + for (Card card : cardsToReveal.getCards(game)) { + if (card.isLand()) { + cardsToPutOnBattlefield.add(card); + } else { + cardsToExile.add(card); + } + } + player.moveCards(cardsToPutOnBattlefield.getCards(game), Zone.BATTLEFIELD, source, game, tapped, false, true, null); + player.moveCards(cardsToExile.getCards(game), Zone.EXILED, source, game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClearTheMind.java b/Mage.Sets/src/mage/cards/c/ClearTheMind.java new file mode 100644 index 0000000000..b92b0ae932 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClearTheMind.java @@ -0,0 +1,72 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClearTheMind extends CardImpl { + + public ClearTheMind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); + + // Target player shuffles their graveyard into their library. + this.getSpellAbility().addEffect(new ClearTheMindEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private ClearTheMind(final ClearTheMind card) { + super(card); + } + + @Override + public ClearTheMind copy() { + return new ClearTheMind(this); + } +} + +class ClearTheMindEffect extends OneShotEffect { + + ClearTheMindEffect() { + super(Outcome.Benefit); + staticText = "Target player shuffles their graveyard into their library."; + } + + private ClearTheMindEffect(final ClearTheMindEffect effect) { + super(effect); + } + + @Override + public ClearTheMindEffect copy() { + return new ClearTheMindEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + player.putCardsOnBottomOfLibrary( + new CardsImpl(player.getGraveyard().getCards(game)), + game, source, false + ); + player.shuffleLibrary(source, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ClearTheStage.java b/Mage.Sets/src/mage/cards/c/ClearTheStage.java new file mode 100644 index 0000000000..b642591b6f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ClearTheStage.java @@ -0,0 +1,83 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.FerociousHint; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ClearTheStage extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature card from your graveyard"); + + public ClearTheStage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); + + // Target creature gets -3/-3 until end of turn. If you control a creature with power 4 or greater, you may return up to one target creature card from your graveyard to your hand. + this.getSpellAbility().addEffect(new ClearTheStageEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 1, filter)); + this.getSpellAbility().addHint(FerociousHint.instance); + } + + private ClearTheStage(final ClearTheStage card) { + super(card); + } + + @Override + public ClearTheStage copy() { + return new ClearTheStage(this); + } +} + +class ClearTheStageEffect extends OneShotEffect { + + ClearTheStageEffect() { + super(Outcome.Benefit); + staticText = "Target creature gets -3/-3 until end of turn. If you control a creature with power 4 or greater, " + + "you may return up to one target creature card from your graveyard to your hand."; + } + + private ClearTheStageEffect(final ClearTheStageEffect effect) { + super(effect); + } + + @Override + public ClearTheStageEffect copy() { + return new ClearTheStageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.addEffect(new BoostTargetEffect(-3, -3), source); + if (!FerociousCondition.instance.apply(game, source)) { + return true; + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.chooseUse(Outcome.Benefit, "Return a creature card from your graveyard to your hand?", source, game)) { + return false; + } + Card card = game.getCard(source.getTargets().get(1).getFirstTarget()); + if (card == null) { + return false; + } + return player.moveCards(card, Zone.HAND, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java b/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java new file mode 100644 index 0000000000..477ddbbc72 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CloakOfConfusion.java @@ -0,0 +1,186 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author jeffwadsworth + */ +public final class CloakOfConfusion extends CardImpl { + + public CloakOfConfusion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature attacks and isn't blocked, you may have it assign no combat damage this turn. + // If you do, defending player discards a card at random. + this.addAbility(new CloakOfConfusionTriggeredAbility()); + + } + + public CloakOfConfusion(final CloakOfConfusion card) { + super(card); + } + + @Override + public CloakOfConfusion copy() { + return new CloakOfConfusion(this); + } +} + +class CloakOfConfusionTriggeredAbility extends TriggeredAbilityImpl { + + public CloakOfConfusionTriggeredAbility() { + super(Zone.BATTLEFIELD, new CloakOfConfusionEffect(), true); + } + + public CloakOfConfusionTriggeredAbility(final CloakOfConfusionTriggeredAbility ability) { + super(ability); + } + + @Override + public CloakOfConfusionTriggeredAbility copy() { + return new CloakOfConfusionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DECLARE_BLOCKERS_STEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent aura = game.getPermanentOrLKIBattlefield(getSourceId()); + if (aura != null) { + Permanent enchantedCreature = game.getPermanent(aura.getAttachedTo()); + if (enchantedCreature != null + && enchantedCreature.isAttacking()) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().isEmpty() + && combatGroup.getAttackers().contains(enchantedCreature.getId())) { + this.getEffects().setTargetPointer( + new FixedTarget(game.getCombat().getDefendingPlayerId( + enchantedCreature.getId(), game))); + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature attacks and isn't blocked, " + super.getRule(); + } +} + +class CloakOfConfusionEffect extends OneShotEffect { + + public CloakOfConfusionEffect() { + super(Outcome.Neutral); + this.staticText = "you may have it assign no combat damage this turn. " + + "If you do, defending player discards a card at random"; + } + + public CloakOfConfusionEffect(final CloakOfConfusionEffect effect) { + super(effect); + } + + @Override + public CloakOfConfusionEffect copy() { + return new CloakOfConfusionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent enchantedCreature = game.getPermanent(game.getPermanent(source.getSourceId()).getAttachedTo()); + if (controller != null && controller.chooseUse(outcome, "Do you wish to not assign combat damage from " + + enchantedCreature.getName() + " and have the defending player discard a card at random?", source, game)) { + ContinuousEffect effect = new AssignNoCombatDamageTargetEffect(); + effect.setTargetPointer(new FixedTarget(enchantedCreature.getId())); + game.addEffect(effect, source); + Player defendingPlayer = game.getPlayer(targetPointer.getFirst(game, source)); + if (defendingPlayer != null) { + defendingPlayer.discard(1, true, source, game); + } + return true; + } + + return false; + } +} + +class AssignNoCombatDamageTargetEffect extends ReplacementEffectImpl { + + public AssignNoCombatDamageTargetEffect() { + super(Duration.EndOfTurn, Outcome.Neutral); + } + + public AssignNoCombatDamageTargetEffect(final AssignNoCombatDamageTargetEffect effect) { + super(effect); + } + + @Override + public AssignNoCombatDamageTargetEffect copy() { + return new AssignNoCombatDamageTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + return event.getSourceId().equals(targetPointer.getFirst(game, source)) + && damageEvent.isCombatDamage(); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ClockOfOmens.java b/Mage.Sets/src/mage/cards/c/ClockOfOmens.java index 3708f17477..9b85270125 100644 --- a/Mage.Sets/src/mage/cards/c/ClockOfOmens.java +++ b/Mage.Sets/src/mage/cards/c/ClockOfOmens.java @@ -26,7 +26,7 @@ public final class ClockOfOmens extends CardImpl { static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ClockOfOmens(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/Clockspinning.java b/Mage.Sets/src/mage/cards/c/Clockspinning.java index 0c76c6572c..2bb9c92c71 100644 --- a/Mage.Sets/src/mage/cards/c/Clockspinning.java +++ b/Mage.Sets/src/mage/cards/c/Clockspinning.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -23,8 +19,11 @@ import mage.players.Player; import mage.target.common.TargetPermanentOrSuspendedCard; import mage.target.targetpointer.FixedTarget; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author spjspj */ public final class Clockspinning extends CardImpl { @@ -133,7 +132,6 @@ class ClockspinningAddOrRemoveCounterEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getFirstTarget()); - Card card = game.getCard(source.getFirstTarget()); if (player != null && permanent != null) { if (player.chooseUse(Outcome.Neutral, "Do you want to to remove a counter?", source, game)) { @@ -151,6 +149,8 @@ class ClockspinningAddOrRemoveCounterEffect extends OneShotEffect { } return true; } + + Card card = game.getCard(source.getFirstTarget()); if (player != null && card != null) { if (player.chooseUse(Outcome.Neutral, "Do you want to to remove a counter?", source, game)) { Counter counter = selectCounterType(game, source, card); diff --git a/Mage.Sets/src/mage/cards/c/ClockworkAvian.java b/Mage.Sets/src/mage/cards/c/ClockworkAvian.java index 7eabddb97f..696fca568a 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkAvian.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkAvian.java @@ -63,7 +63,7 @@ public final class ClockworkAvian extends CardImpl { Zone.BATTLEFIELD, new AvianAddCountersSourceEffect( CounterType.P1P0.createInstance(), - new ManacostVariableValue(), + ManacostVariableValue.instance, true, true ), new ManaCostsImpl("{X}"), diff --git a/Mage.Sets/src/mage/cards/c/ClockworkBeast.java b/Mage.Sets/src/mage/cards/c/ClockworkBeast.java index e02f4434b4..9fa1356e13 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkBeast.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkBeast.java @@ -59,7 +59,7 @@ public final class ClockworkBeast extends CardImpl { Zone.BATTLEFIELD, new BeastAddCountersSourceEffect( CounterType.P1P0.createInstance(), - new ManacostVariableValue(), + ManacostVariableValue.instance, true, true ), new ManaCostsImpl("{X}"), diff --git a/Mage.Sets/src/mage/cards/c/ClockworkSteed.java b/Mage.Sets/src/mage/cards/c/ClockworkSteed.java index fe4557ef8d..c2975f53d2 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkSteed.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkSteed.java @@ -70,7 +70,7 @@ public final class ClockworkSteed extends CardImpl { Zone.BATTLEFIELD, new ClockworkSteedAddCountersSourceEffect( CounterType.P1P0.createInstance(), - new ManacostVariableValue(), + ManacostVariableValue.instance, true, true ), new ManaCostsImpl("{X}"), diff --git a/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java b/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java index 4480d844ce..0cd0288d2e 100644 --- a/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java +++ b/Mage.Sets/src/mage/cards/c/ClockworkSwarm.java @@ -73,7 +73,7 @@ public final class ClockworkSwarm extends CardImpl { Zone.BATTLEFIELD, new SwarmAddCountersSourceEffect( CounterType.P1P0.createInstance(), - new ManacostVariableValue(), + ManacostVariableValue.instance, true, true ), new ManaCostsImpl("{X}"), diff --git a/Mage.Sets/src/mage/cards/c/CloneShell.java b/Mage.Sets/src/mage/cards/c/CloneShell.java index 4007df8bcd..84171a085b 100644 --- a/Mage.Sets/src/mage/cards/c/CloneShell.java +++ b/Mage.Sets/src/mage/cards/c/CloneShell.java @@ -1,8 +1,5 @@ - package mage.cards.c; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; @@ -20,6 +17,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.util.CardUtil; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -115,11 +115,13 @@ class CloneShellDiesEffect extends OneShotEffect { Permanent permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); if (permanent != null) { List imprinted = permanent.getImprinted(); - if (!imprinted.isEmpty()) { + if (imprinted != null && !imprinted.isEmpty()) { Card imprintedCard = game.getCard(imprinted.get(0)); - imprintedCard.setFaceDown(false, game); - if (imprintedCard.isCreature()) { - controller.moveCards(imprintedCard, Zone.BATTLEFIELD, source, game); + if (imprintedCard != null) { + imprintedCard.setFaceDown(false, game); + if (imprintedCard.isCreature()) { + controller.moveCards(imprintedCard, Zone.BATTLEFIELD, source, game); + } } } } diff --git a/Mage.Sets/src/mage/cards/c/CloseQuarters.java b/Mage.Sets/src/mage/cards/c/CloseQuarters.java index 17cbd66ffd..1d0fa5519c 100644 --- a/Mage.Sets/src/mage/cards/c/CloseQuarters.java +++ b/Mage.Sets/src/mage/cards/c/CloseQuarters.java @@ -19,7 +19,7 @@ import mage.target.common.TargetAnyTarget; */ public final class CloseQuarters extends CardImpl { - final static private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); + static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/c/CloudgoatRanger.java b/Mage.Sets/src/mage/cards/c/CloudgoatRanger.java index 368b1c1914..1172299866 100644 --- a/Mage.Sets/src/mage/cards/c/CloudgoatRanger.java +++ b/Mage.Sets/src/mage/cards/c/CloudgoatRanger.java @@ -34,7 +34,7 @@ public final class CloudgoatRanger extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Kithkin you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.KITHKIN)); } diff --git a/Mage.Sets/src/mage/cards/c/ClovenCasting.java b/Mage.Sets/src/mage/cards/c/ClovenCasting.java index 91c8961b96..389fc161c1 100644 --- a/Mage.Sets/src/mage/cards/c/ClovenCasting.java +++ b/Mage.Sets/src/mage/cards/c/ClovenCasting.java @@ -27,7 +27,7 @@ public final class ClovenCasting extends CardImpl { filter.add(Predicates.or( new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public ClovenCasting(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CoalitionFlag.java b/Mage.Sets/src/mage/cards/c/CoalitionFlag.java index 9ee5821e9d..a0816c88f8 100644 --- a/Mage.Sets/src/mage/cards/c/CoalitionFlag.java +++ b/Mage.Sets/src/mage/cards/c/CoalitionFlag.java @@ -1,8 +1,6 @@ package mage.cards.c; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -11,18 +9,13 @@ import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentI import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; +import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CoalitionFlag extends CardImpl { @@ -40,10 +33,12 @@ public final class CoalitionFlag extends CardImpl { this.addAbility(ability); // Enchanted creature is a Flagbearer. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetCardSubtypeAttachedEffect(Duration.WhileOnBattlefield, AttachmentType.AURA, SubType.FLAGBEARER))); + this.addAbility(new SimpleStaticAbility(new SetCardSubtypeAttachedEffect( + Duration.WhileOnBattlefield, AttachmentType.AURA, SubType.FLAGBEARER + ))); // While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer")))); + this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect())); } public CoalitionFlag(final CoalitionFlag card) { diff --git a/Mage.Sets/src/mage/cards/c/CoalitionHonorGuard.java b/Mage.Sets/src/mage/cards/c/CoalitionHonorGuard.java index bae309cbc2..e421744e28 100644 --- a/Mage.Sets/src/mage/cards/c/CoalitionHonorGuard.java +++ b/Mage.Sets/src/mage/cards/c/CoalitionHonorGuard.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentIfAbleEffect; @@ -9,8 +8,8 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; + +import java.util.UUID; /** * Cardname: Coalition Honor Guard @@ -28,7 +27,7 @@ public final class CoalitionHonorGuard extends CardImpl { this.toughness = new MageInt(4); // While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer")))); + this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect())); } public CoalitionHonorGuard(final CoalitionHonorGuard card) { diff --git a/Mage.Sets/src/mage/cards/c/CoastalPiracy.java b/Mage.Sets/src/mage/cards/c/CoastalPiracy.java index f3a94fc0a6..6eef0cd9d1 100644 --- a/Mage.Sets/src/mage/cards/c/CoastalPiracy.java +++ b/Mage.Sets/src/mage/cards/c/CoastalPiracy.java @@ -61,7 +61,7 @@ class CoastalPiracyTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (((DamagedPlayerEvent) event).isCombatDamage() - && game.getOpponents(this.controllerId).contains(((DamagedPlayerEvent) event).getPlayerId())) { + && game.getOpponents(this.controllerId).contains(event.getPlayerId())) { Permanent creature = game.getPermanent(event.getSourceId()); if (creature != null && creature.isControlledBy(controllerId)) { return true; diff --git a/Mage.Sets/src/mage/cards/c/CoastalWizard.java b/Mage.Sets/src/mage/cards/c/CoastalWizard.java index 54bb6b7b24..1ed09be149 100644 --- a/Mage.Sets/src/mage/cards/c/CoastalWizard.java +++ b/Mage.Sets/src/mage/cards/c/CoastalWizard.java @@ -27,7 +27,7 @@ public final class CoastalWizard extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CoastalWizard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CobraTrap.java b/Mage.Sets/src/mage/cards/c/CobraTrap.java index a84de7815d..69b1011f58 100644 --- a/Mage.Sets/src/mage/cards/c/CobraTrap.java +++ b/Mage.Sets/src/mage/cards/c/CobraTrap.java @@ -55,7 +55,7 @@ enum CobraTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CobraTrapWatcher watcher = (CobraTrapWatcher) game.getState().getWatchers().get(CobraTrapWatcher.class.getSimpleName()); + CobraTrapWatcher watcher = game.getState().getWatcher(CobraTrapWatcher.class); return watcher != null && watcher.conditionMet(source.getControllerId()); } @@ -68,10 +68,10 @@ enum CobraTrapCondition implements Condition { class CobraTrapWatcher extends Watcher { - Set players = new HashSet<>(); + private Set players = new HashSet<>(); public CobraTrapWatcher() { - super(CobraTrapWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CobraTrapWatcher(final CobraTrapWatcher watcher) { @@ -86,7 +86,7 @@ class CobraTrapWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() == EventType.DESTROYED_PERMANENT) { - Permanent perm = (Permanent) game.getPermanentOrLKIBattlefield(event.getTargetId()); // can regenerate or be indestructible + Permanent perm = game.getPermanentOrLKIBattlefield(event.getTargetId()); // can regenerate or be indestructible if (perm != null && !perm.isCreature()) { if (!game.getStack().isEmpty()) { StackObject spell = game.getStack().getStackObject(event.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/c/Cocoon.java b/Mage.Sets/src/mage/cards/c/Cocoon.java new file mode 100644 index 0000000000..ce5d8be5c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cocoon.java @@ -0,0 +1,115 @@ + +package mage.cards.c; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * @author L_J + */ +public final class Cocoon extends CardImpl { + + public Cocoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // When Cocoon enters the battlefield, tap enchanted creature and put three pupa counters on Cocoon. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new AddCountersSourceEffect(CounterType.PUPA.createInstance(3))); + this.addAbility(ability); + + // Enchanted creature doesn’t untap during your untap step if Cocoon has a pupa counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), + new SourceHasCounterCondition(CounterType.PUPA)).setText("Enchanted creature doesn't untap during its controller's untap step if Cocoon has a pupa counter on it"))); + + // At the beginning of your upkeep, remove a pupa counter from Cocoon. If you can’t, sacrifice it, put a +1/+1 counter on enchanted creature, and that creature gains flying. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new CocoonEffect(), TargetController.YOU, false)); + + } + + public Cocoon(final Cocoon card) { + super(card); + } + + @Override + public Cocoon copy() { + return new Cocoon(this); + } +} + +class CocoonEffect extends OneShotEffect { + + CocoonEffect() { + super(Outcome.Sacrifice); + staticText = "remove a pupa counter from {this}. If you can’t, sacrifice it, put a +1/+1 counter on enchanted creature, and that creature gains flying"; + } + + CocoonEffect(final CocoonEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (permanent != null) { + int amount = permanent.getCounters(game).getCount(CounterType.PUPA); + if (amount > 0) { + permanent.removeCounters(CounterType.PUPA.createInstance(), game); + } else { + Permanent enchantedPermanent = game.getPermanent(permanent.getAttachedTo()); + permanent.sacrifice(source.getSourceId(), game); + if (enchantedPermanent != null) { + Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); + effect.setTargetPointer(new FixedTarget(enchantedPermanent, game)); + effect.apply(game, source); + ContinuousEffect effect2 = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.Custom); + effect2.setTargetPointer(new FixedTarget(enchantedPermanent, game)); + game.addEffect(effect2, source); + } + } + return true; + } + return false; + } + + @Override + public CocoonEffect copy() { + return new CocoonEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CodeOfConstraint.java b/Mage.Sets/src/mage/cards/c/CodeOfConstraint.java new file mode 100644 index 0000000000..f548ade278 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CodeOfConstraint.java @@ -0,0 +1,73 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CodeOfConstraint extends CardImpl { + + public CodeOfConstraint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Target creature gets -4/-0 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(-4, 0)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + + // Addendum — If you cast this spell during your main phase, tap that creature and it doesn't untap during its controller's next untap step. + this.getSpellAbility().addEffect(new CodeOfConstraintEffect()); + } + + private CodeOfConstraint(final CodeOfConstraint card) { + super(card); + } + + @Override + public CodeOfConstraint copy() { + return new CodeOfConstraint(this); + } +} + +class CodeOfConstraintEffect extends OneShotEffect { + + CodeOfConstraintEffect() { + super(Outcome.Benefit); + staticText = "
    Addendum — If you cast this spell during your main phase, " + + "tap that creature and it doesn't untap during its controller's next untap step."; + } + + private CodeOfConstraintEffect(final CodeOfConstraintEffect effect) { + super(effect); + } + + @Override + public CodeOfConstraintEffect copy() { + return new CodeOfConstraintEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (AddendumCondition.instance.apply(game, source)) { + new TapTargetEffect().apply(game, source); + game.addEffect(new DontUntapInControllersNextUntapStepTargetEffect(), source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CoffinPuppets.java b/Mage.Sets/src/mage/cards/c/CoffinPuppets.java index abd123b793..621ce06321 100644 --- a/Mage.Sets/src/mage/cards/c/CoffinPuppets.java +++ b/Mage.Sets/src/mage/cards/c/CoffinPuppets.java @@ -1,9 +1,7 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.condition.CompoundCondition; import mage.abilities.condition.Condition; @@ -22,18 +20,28 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CoffinPuppets extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control a Swamp"); + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("you control a Swamp"); + private static final FilterControlledPermanent filter2 + = new FilterControlledLandPermanent("two lands"); static { filter.add(new SubtypePredicate(SubType.SWAMP)); } + private static final Condition condition = new CompoundCondition( + "during your upkeep and only if you control a Swamp", + new PermanentsOnTheBattlefieldCondition(filter), + new IsStepCondition(PhaseStep.UPKEEP) + ); + public CoffinPuppets(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); @@ -42,12 +50,13 @@ public final class CoffinPuppets extends CardImpl { this.toughness = new MageInt(3); // Sacrifice two lands: Return Coffin Puppets from your graveyard to the battlefield. Activate this ability only during your upkeep and only if you control a Swamp. - Condition condition = new CompoundCondition("during your upkeep and only if you control a Swamp",new PermanentsOnTheBattlefieldCondition(filter), new IsStepCondition(PhaseStep.UPKEEP)); - Ability ability = new ActivateIfConditionActivatedAbility(Zone.GRAVEYARD, + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToBattlefieldEffect(), - new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("two lands"), true)), - condition); - this.addAbility(ability); + new SacrificeTargetCost( + new TargetControlledPermanent(2, 2, filter2, true) + ), condition + )); } public CoffinPuppets(final CoffinPuppets card) { diff --git a/Mage.Sets/src/mage/cards/c/CoffinPurge.java b/Mage.Sets/src/mage/cards/c/CoffinPurge.java index 34d26d9c91..200d6a4a9c 100644 --- a/Mage.Sets/src/mage/cards/c/CoffinPurge.java +++ b/Mage.Sets/src/mage/cards/c/CoffinPurge.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.FlashbackAbility; @@ -11,21 +10,21 @@ import mage.constants.CardType; import mage.constants.TimingRule; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author cbt33, jonubuu (Withered Wretch) */ public final class CoffinPurge extends CardImpl { public CoffinPurge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Exile target card from a graveyard. - this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); + // Flashback {B} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{B}"), TimingRule.INSTANT)); } diff --git a/Mage.Sets/src/mage/cards/c/CoilingWoodworm.java b/Mage.Sets/src/mage/cards/c/CoilingWoodworm.java index 489ce9d8c6..b56c057680 100644 --- a/Mage.Sets/src/mage/cards/c/CoilingWoodworm.java +++ b/Mage.Sets/src/mage/cards/c/CoilingWoodworm.java @@ -1,9 +1,9 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; import mage.cards.CardImpl; @@ -13,19 +13,17 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CoilingWoodworm extends CardImpl { - final static FilterPermanent filterLands = new FilterPermanent("Forests you control"); - - static { - filterLands.add(new SubtypePredicate(SubType.FOREST)); - } + private static final DynamicValue count = new PermanentsOnBattlefieldCount( + new FilterPermanent(SubType.FOREST, "Forests on the battlefield") + ); public CoilingWoodworm(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); @@ -36,10 +34,10 @@ public final class CoilingWoodworm extends CardImpl { this.toughness = new MageInt(1); // Coiling Woodworm's power is equal to the number of Forests on the battlefield. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerSourceEffect(new PermanentsOnBattlefieldCount(filterLands), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerSourceEffect(count, Duration.EndOfGame))); } - public CoilingWoodworm(final CoilingWoodworm card) { + private CoilingWoodworm(final CoilingWoodworm card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java b/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java index 26133075d3..09f2b669a0 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveBrutality.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.costs.Cost; import mage.abilities.costs.common.DiscardCardCost; @@ -25,8 +23,9 @@ import mage.filter.predicate.other.PlayerPredicate; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CollectiveBrutality extends CardImpl { @@ -44,7 +43,7 @@ public final class CollectiveBrutality extends CardImpl { } public CollectiveBrutality(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Escalate - Discard a card. Cost cost = new DiscardCardCost(); @@ -59,25 +58,24 @@ public final class CollectiveBrutality extends CardImpl { Effect effect = new DiscardCardYouChooseTargetEffect(filter, TargetController.ANY); effect.setText("Target opponent reveals their hand. You choose an instant or sorcery card from it. That player discards that card"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard)); + this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard).withChooseHint("reveals hand, you choose to discard")); // Target creature gets -2/-2 until end of turn.; Mode mode = new Mode(); effect = new BoostTargetEffect(-2, -2, Duration.EndOfTurn); effect.setText("Target creature gets -2/-2 until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterCreatureMinus)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterCreatureMinus).withChooseHint("gets -2/-2 until end of turn")); this.getSpellAbility().addMode(mode); // Target opponent loses 2 life and you gain 2 life. mode = new Mode(); effect = new LoseLifeTargetEffect(2); effect.setText("Target opponent loses 2 life"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetPlayer(1, 1, false, filterLoseLife)); + mode.addEffect(effect); + mode.addTarget(new TargetPlayer(1, 1, false, filterLoseLife).withChooseHint("loses 2 life")); effect = new GainLifeEffect(2); - effect.setText("and you gain 2 life"); - mode.getEffects().add(effect); + mode.addEffect(effect.concatBy("and")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java index 13e9dd8303..ae5c57bb19 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveDefiance.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; @@ -22,8 +20,9 @@ import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CollectiveDefiance extends CardImpl { @@ -43,22 +42,22 @@ public final class CollectiveDefiance extends CardImpl { // Target player discards all cards in their hand, then draws that many cards.; this.getSpellAbility().addEffect(new CollectiveDefianceEffect()); - this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard)); + this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterDiscard).withChooseHint("discards all cards and draws")); // Collective Defiance deals 4 damage to target creature.; Mode mode = new Mode(); Effect effect = new DamageTargetEffect(4); effect.setText("{this} deals 4 damage to target creature"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 4 damage to")); this.getSpellAbility().addMode(mode); // Collective Defiance deals 3 damage to target opponent or planeswalker. mode = new Mode(); effect = new DamageTargetEffect(3); effect.setText("{this} deals 3 damage to target opponent or planeswalker"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetOpponentOrPlaneswalker()); + mode.addEffect(effect); + mode.addTarget(new TargetOpponentOrPlaneswalker().withChooseHint("deals 3 damage to")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java index 26d03a9d4e..da4e80f4e1 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveEffort.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveEffort.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.Cost; @@ -32,8 +30,9 @@ import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CollectiveEffort extends CardImpl { @@ -44,7 +43,7 @@ public final class CollectiveEffort extends CardImpl { private static final FilterPlayer filterPlayer = new FilterPlayer("player whose creatures get +1/+1 counters"); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); filterDestroyCreature.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); } @@ -62,22 +61,22 @@ public final class CollectiveEffort extends CardImpl { // Destroy target creature with power 4 or greater.; this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filterDestroyCreature).withChooseHint("destroy")); // Destroy target enchantment.; Mode mode = new Mode(); Effect effect = new DestroyTargetEffect(); effect.setText("Destroy target enchantment"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetEnchantmentPermanent(filterDestroyEnchantment)); + mode.addEffect(effect); + mode.addTarget(new TargetEnchantmentPermanent(filterDestroyEnchantment).withChooseHint("destroy")); this.getSpellAbility().addMode(mode); // Put a +1/+1 counter on each creature target player controls. mode = new Mode(); effect = new CollectiveEffortEffect(); effect.setText("Put a +1/+1 counter on each creature target player controls"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetPlayer(1, 1, false, filterPlayer)); + mode.addEffect(effect); + mode.addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("put +1/+1 counter on each creature")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CollectiveUnconscious.java b/Mage.Sets/src/mage/cards/c/CollectiveUnconscious.java index 9e9df9e93a..e3de225ee5 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveUnconscious.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveUnconscious.java @@ -1,26 +1,25 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author Plopman */ public final class CollectiveUnconscious extends CardImpl { public CollectiveUnconscious(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); // Draw a card for each creature you control. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()))); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE))); } public CollectiveUnconscious(final CollectiveUnconscious card) { diff --git a/Mage.Sets/src/mage/cards/c/CollectiveVoyage.java b/Mage.Sets/src/mage/cards/c/CollectiveVoyage.java index bcdcda9492..e027b6eb8b 100644 --- a/Mage.Sets/src/mage/cards/c/CollectiveVoyage.java +++ b/Mage.Sets/src/mage/cards/c/CollectiveVoyage.java @@ -76,7 +76,7 @@ class CollectiveVoyageEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, xSum, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); player.shuffleLibrary(source, game); } @@ -110,7 +110,7 @@ class CollectiveVoyageEffect extends OneShotEffect { game.removeBookmark(bookmark); } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}."); return xValue; } } diff --git a/Mage.Sets/src/mage/cards/c/CollisionColossus.java b/Mage.Sets/src/mage/cards/c/CollisionColossus.java new file mode 100644 index 0000000000..74a9473184 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CollisionColossus.java @@ -0,0 +1,60 @@ +package mage.cards.c; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SpellAbilityType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CollisionColossus extends SplitCard { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public CollisionColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R/G}", "{R}{G}", SpellAbilityType.SPLIT); + + // Collision + // Collision deals 6 damage to target creature with flying. + this.getLeftHalfCard().getSpellAbility().addEffect(new DamageTargetEffect(6)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Colossus + // Target creature gets +4/+2 and gains trample until end of turn. + this.getRightHalfCard().getSpellAbility().addEffect( + new BoostTargetEffect(4, 2, Duration.EndOfTurn) + .setText("target creature gets +4/+2") + ); + this.getRightHalfCard().getSpellAbility().addEffect(new GainAbilityTargetEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains trample until end of turn")); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private CollisionColossus(final CollisionColossus card) { + super(card); + } + + @Override + public CollisionColossus copy() { + return new CollisionColossus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ColossalMajesty.java b/Mage.Sets/src/mage/cards/c/ColossalMajesty.java index abd4bd9d6f..b82fb0a92b 100644 --- a/Mage.Sets/src/mage/cards/c/ColossalMajesty.java +++ b/Mage.Sets/src/mage/cards/c/ColossalMajesty.java @@ -1,17 +1,18 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ColossalMajesty extends CardImpl { @@ -27,9 +28,9 @@ public final class ColossalMajesty extends CardImpl { ), FerociousCondition.instance, "At the beginning of your upkeep, " - + "if you control a creature with power 4 or greater, " - + "draw a card." - )); + + "if you control a creature with power 4 or greater, " + + "draw a card." + ).addHint(FerociousHint.instance)); } public ColossalMajesty(final ColossalMajesty card) { diff --git a/Mage.Sets/src/mage/cards/c/ColossalWhale.java b/Mage.Sets/src/mage/cards/c/ColossalWhale.java index b1d47d77ed..8a4ac9a8d2 100644 --- a/Mage.Sets/src/mage/cards/c/ColossalWhale.java +++ b/Mage.Sets/src/mage/cards/c/ColossalWhale.java @@ -89,7 +89,7 @@ class ColossalWhaleAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever {this} attacks, ").append(super.getRule()).toString(); + return "Whenever {this} attacks, " + super.getRule(); } @Override diff --git a/Mage.Sets/src/mage/cards/c/CombineGuildmage.java b/Mage.Sets/src/mage/cards/c/CombineGuildmage.java new file mode 100644 index 0000000000..82d0b72cd7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CombineGuildmage.java @@ -0,0 +1,143 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CombineGuildmage extends CardImpl { + + private static final FilterPermanent filter1 + = new FilterControlledCreaturePermanent("creature you control (to remove a counter from)"); + private static final FilterPermanent filter2 + = new FilterControlledCreaturePermanent("creature you control (to move a counter to)"); + + public CombineGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{G}, {T}: This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it. + Ability ability = new SimpleActivatedAbility( + new CombineGuildmageReplacementEffect(), new ManaCostsImpl("{1}{G}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {1}{U}, {T}: Move a +1/+1 counter from target creature you control onto another target creature you control. + ability = new SimpleActivatedAbility( + new CombineGuildmageCounterEffect(), new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter1)); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private CombineGuildmage(final CombineGuildmage card) { + super(card); + } + + @Override + public CombineGuildmage copy() { + return new CombineGuildmage(this); + } +} + +class CombineGuildmageReplacementEffect extends ReplacementEffectImpl { + + CombineGuildmageReplacementEffect() { + super(Duration.EndOfTurn, Outcome.BoostCreature); + this.staticText = "This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it"; + } + + private CombineGuildmageReplacementEffect(CombineGuildmageReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + return permanent != null && permanent.isControlledBy(source.getControllerId()) && permanent.isCreature(); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); + if (target != null) { + target.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } + return false; + } + + @Override + public CombineGuildmageReplacementEffect copy() { + return new CombineGuildmageReplacementEffect(this); + } +} + +class CombineGuildmageCounterEffect extends OneShotEffect { + + CombineGuildmageCounterEffect() { + super(Outcome.Benefit); + staticText = "Move a +1/+1 counter from target creature you control onto another target creature you control."; + } + + private CombineGuildmageCounterEffect(final CombineGuildmageCounterEffect effect) { + super(effect); + } + + @Override + public CombineGuildmageCounterEffect copy() { + return new CombineGuildmageCounterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent fromPermanent = game.getPermanent(source.getFirstTarget()); + Permanent toPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (fromPermanent == null || toPermanent == null) { + return false; + } + if (fromPermanent.getCounters(game).getCount(CounterType.P1P1) > 0) { + fromPermanent.removeCounters(CounterType.P1P1.createInstance(), game); + toPermanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CombustibleGearhulk.java b/Mage.Sets/src/mage/cards/c/CombustibleGearhulk.java index a78c0eadb6..4b3cc8e09f 100644 --- a/Mage.Sets/src/mage/cards/c/CombustibleGearhulk.java +++ b/Mage.Sets/src/mage/cards/c/CombustibleGearhulk.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.Set; @@ -19,7 +18,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetOpponent; /** @@ -29,7 +27,7 @@ import mage.target.common.TargetOpponent; public final class CombustibleGearhulk extends CardImpl { public CombustibleGearhulk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}{R}{R}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -75,29 +73,19 @@ class CombustibleGearhulkEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && sourcePermanent != null) { - UUID opponentId; - if (game.getOpponents(controller.getId()).size() == 1) { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } else { - Target target = new TargetOpponent(); - controller.choose(outcome, target, source.getSourceId(), game); - opponentId = target.getFirstTarget(); - } - if (opponentId != null) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - StringBuilder sb = new StringBuilder("Have " + controller.getLogName() + " draw three cards?"); - if (opponent.chooseUse(outcome, sb.toString(), source, game)) { - if (!game.isSimulation()) { - game.informPlayers(opponent.getLogName() + " lets " + controller.getLogName() + " draw three cards"); - } - return new DrawCardSourceControllerEffect(3).apply(game, source); - } else { - if (!game.isSimulation()) { - game.informPlayers(opponent.getLogName() + " does not let " + controller.getLogName() + " draw three cards"); - } - return new CombustibleGearhulkMillAndDamageEffect().apply(game, source); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent != null) { + String questionDrawThree = "Have " + controller.getLogName() + " draw three cards?"; + if (opponent.chooseUse(outcome, questionDrawThree, source, game)) { + if (!game.isSimulation()) { + game.informPlayers(opponent.getLogName() + " lets " + controller.getLogName() + " draw three cards"); } + return new DrawCardSourceControllerEffect(3).apply(game, source); + } else { + if (!game.isSimulation()) { + game.informPlayers(opponent.getLogName() + " does not let " + controller.getLogName() + " draw three cards"); + } + return new CombustibleGearhulkMillAndDamageEffect().apply(game, source); } } } diff --git a/Mage.Sets/src/mage/cards/c/CometStorm.java b/Mage.Sets/src/mage/cards/c/CometStorm.java index c88df06c34..41c3de1510 100644 --- a/Mage.Sets/src/mage/cards/c/CometStorm.java +++ b/Mage.Sets/src/mage/cards/c/CometStorm.java @@ -1,9 +1,7 @@ - package mage.cards.c; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.MultikickerAbility; @@ -15,6 +13,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -31,27 +30,30 @@ public final class CometStorm extends CardImpl { // Choose any target, then choose another any target for each time Comet Storm was kicked. Comet Storm deals X damage to each of them. this.getSpellAbility().addEffect(new CometStormEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget(1)); + this.getSpellAbility().setTargetAdjuster(CometStormAdjuster.instance); } public CometStorm(final CometStorm card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numbTargets = new MultikickerCount().calculate(game, ability, null) + 1; - ability.addTarget(new TargetAnyTarget(numbTargets)); - } - } - @Override public CometStorm copy() { return new CometStorm(this); } } +enum CometStormAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = MultikickerCount.instance.calculate(game, ability, null) + 1; + ability.addTarget(new TargetAnyTarget(numbTargets)); + } +} + class CometStormEffect extends OneShotEffect { public CometStormEffect() { diff --git a/Mage.Sets/src/mage/cards/c/CommandTheDreadhorde.java b/Mage.Sets/src/mage/cards/c/CommandTheDreadhorde.java new file mode 100644 index 0000000000..0858ff2698 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CommandTheDreadhorde.java @@ -0,0 +1,79 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CommandTheDreadhorde extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature and/or planeswalker cards in graveyards"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.CREATURE) + )); + } + + public CommandTheDreadhorde(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); + + // Choose any number of target creature and/or planeswalker cards in graveyards. Command the Dreadhorde deals damage to you equal to the total converted mana cost of those cards. Put them onto the battlefield under your control. + this.getSpellAbility().addEffect(new CommandTheDreadhordeEffect()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(0, Integer.MAX_VALUE, filter)); + } + + private CommandTheDreadhorde(final CommandTheDreadhorde card) { + super(card); + } + + @Override + public CommandTheDreadhorde copy() { + return new CommandTheDreadhorde(this); + } +} + +class CommandTheDreadhordeEffect extends OneShotEffect { + + CommandTheDreadhordeEffect() { + super(Outcome.Benefit); + staticText = "Choose any number of target creature and/or planeswalker cards in graveyards. " + + "{this} deals damage to you equal to the total converted mana cost of those cards. " + + "Put them onto the battlefield under your control."; + } + + private CommandTheDreadhordeEffect(final CommandTheDreadhordeEffect effect) { + super(effect); + } + + @Override + public CommandTheDreadhordeEffect copy() { + return new CommandTheDreadhordeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(source.getTargets().get(0).getTargets()); + int damage = cards.getCards(game).stream().mapToInt(Card::getConvertedManaCost).sum(); + player.damage(damage, source.getSourceId(), game); + return player.moveCards(cards, Zone.BATTLEFIELD, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CommanderCody.java b/Mage.Sets/src/mage/cards/c/CommanderCody.java index 94867b369d..2b20b390fa 100644 --- a/Mage.Sets/src/mage/cards/c/CommanderCody.java +++ b/Mage.Sets/src/mage/cards/c/CommanderCody.java @@ -25,7 +25,7 @@ public final class CommanderCody extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-token Trooper creatures"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(new SubtypePredicate(SubType.TROOPER)); } diff --git a/Mage.Sets/src/mage/cards/c/CommenceTheEndgame.java b/Mage.Sets/src/mage/cards/c/CommenceTheEndgame.java new file mode 100644 index 0000000000..45eaf89629 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CommenceTheEndgame.java @@ -0,0 +1,66 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.CantBeCounteredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CommenceTheEndgame extends CardImpl { + + public CommenceTheEndgame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); + + // This spell can't be countered. + this.addAbility(new CantBeCounteredAbility()); + + // Draw two cards, then amass X, where X is the number of cards in your hand. + this.getSpellAbility().addEffect(new CommenceTheEndgameEffect()); + } + + private CommenceTheEndgame(final CommenceTheEndgame card) { + super(card); + } + + @Override + public CommenceTheEndgame copy() { + return new CommenceTheEndgame(this); + } +} + +class CommenceTheEndgameEffect extends OneShotEffect { + + CommenceTheEndgameEffect() { + super(Outcome.Benefit); + staticText = "Draw two cards, then amass X, where X is the number of cards in your hand."; + } + + private CommenceTheEndgameEffect(final CommenceTheEndgameEffect effect) { + super(effect); + } + + @Override + public CommenceTheEndgameEffect copy() { + return new CommenceTheEndgameEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(2, game); + return new AmassEffect(player.getHand().size()).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CommitMemory.java b/Mage.Sets/src/mage/cards/c/CommitMemory.java index eaebaa461e..a0fb02b1e5 100644 --- a/Mage.Sets/src/mage/cards/c/CommitMemory.java +++ b/Mage.Sets/src/mage/cards/c/CommitMemory.java @@ -45,7 +45,7 @@ public final class CommitMemory extends SplitCard { // Memory // Aftermath // Each player shuffles their hand and graveyard into their library, then draws seven cards. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new ShuffleHandGraveyardAllEffect()); Effect effect = new DrawCardAllEffect(7); effect.setText(", then draws seven cards"); @@ -82,7 +82,7 @@ class CommitEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent permanent = game.getPermanent(source.getFirstTarget()); if (permanent != null) { return controller.putCardOnTopXOfLibrary(permanent, game, source, 2); } diff --git a/Mage.Sets/src/mage/cards/c/CommonCause.java b/Mage.Sets/src/mage/cards/c/CommonCause.java index 3fd5e226bb..bfcff613fe 100644 --- a/Mage.Sets/src/mage/cards/c/CommonCause.java +++ b/Mage.Sets/src/mage/cards/c/CommonCause.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -12,15 +11,15 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CommonCause extends CardImpl { @@ -35,9 +34,11 @@ public final class CommonCause extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // Nonartifact creatures get +2/+2 as long as they all share a color. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, false), - new AllColorCondition(), - "nonartifact creatures get +2/+2 as long as they all share a color."))); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, false), + AllColorCondition.instance, + "nonartifact creatures get +2/+2 as long as they all share a color.") + )); } public CommonCause(final CommonCause card) { @@ -50,7 +51,8 @@ public final class CommonCause extends CardImpl { } } -class AllColorCondition implements Condition { +enum AllColorCondition implements Condition { + instance; @Override public boolean apply(Game game, Ability source) { @@ -58,7 +60,7 @@ class AllColorCondition implements Condition { filter.add(Predicates.not(new CardTypePredicate(CardType.ARTIFACT))); ObjectColor allColor = new ObjectColor("WUBRG"); for (Permanent thing : game.getBattlefield().getAllActivePermanents(filter, game)) { - allColor = allColor.intersection(thing.getColor(game)); + allColor = allColor.intersection(thing.getColor(game)); } return !allColor.isColorless(); } diff --git a/Mage.Sets/src/mage/cards/c/CommuneWithLava.java b/Mage.Sets/src/mage/cards/c/CommuneWithLava.java index 08cf2112e7..30392efead 100644 --- a/Mage.Sets/src/mage/cards/c/CommuneWithLava.java +++ b/Mage.Sets/src/mage/cards/c/CommuneWithLava.java @@ -1,7 +1,5 @@ package mage.cards.c; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -15,8 +13,10 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.Set; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CommuneWithLava extends CardImpl { @@ -59,7 +59,7 @@ class CommuneWithLavaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Card sourceCard = game.getCard(source.getSourceId()); - if (controller != null) { + if (controller != null && sourceCard != null) { int amount = source.getManaCostsToPay().getX(); Set cards = controller.getLibrary().getTopCards(game, amount); controller.moveCardsToExile(cards, source, game, true, CardUtil.getCardExileZoneId(game, source), sourceCard.getIdName()); @@ -78,7 +78,7 @@ class CommuneWithLavaEffect extends OneShotEffect { class CommuneWithLavaMayPlayEffect extends AsThoughEffectImpl { - int castOnTurn = 0; + private int castOnTurn = 0; public CommuneWithLavaMayPlayEffect() { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); @@ -104,9 +104,7 @@ class CommuneWithLavaMayPlayEffect extends AsThoughEffectImpl { @Override public boolean isInactive(Ability source, Game game) { if (castOnTurn != game.getTurnNum() && game.getPhase().getStep().getType() == PhaseStep.END_TURN) { - if (game.isActivePlayer(source.getControllerId())) { - return true; - } + return game.isActivePlayer(source.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CompellingDeterrence.java b/Mage.Sets/src/mage/cards/c/CompellingDeterrence.java index d456459d5b..4be944df32 100644 --- a/Mage.Sets/src/mage/cards/c/CompellingDeterrence.java +++ b/Mage.Sets/src/mage/cards/c/CompellingDeterrence.java @@ -65,9 +65,9 @@ class CompellingDeterrenceEffect extends OneShotEffect { if (controller != null && player != null) { player.moveCards(target, Zone.HAND, source, game); game.applyEffects(); - FilterPermanent FILTER = new FilterPermanent(); - FILTER.add(new SubtypePredicate(SubType.ZOMBIE)); - if (game.getState().getBattlefield().countAll(FILTER, controller.getId(), game) > 0) { + FilterPermanent zombieFilter = new FilterPermanent(); + zombieFilter.add(new SubtypePredicate(SubType.ZOMBIE)); + if (game.getState().getBattlefield().countAll(zombieFilter, controller.getId(), game) > 0) { player.discard(1, false, source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java b/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java index 3697c4ab9f..012152970d 100644 --- a/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java +++ b/Mage.Sets/src/mage/cards/c/ComplexAutomaton.java @@ -1,27 +1,31 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; -import mage.abilities.TriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ComparisonType; +import mage.constants.SubType; import mage.constants.TargetController; -import mage.filter.common.FilterControlledPermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ComplexAutomaton extends CardImpl { + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + StaticFilters.FILTER_CONTROLLED_PERMANENT, ComparisonType.MORE_THAN, 6 + ); + public ComplexAutomaton(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); @@ -30,12 +34,16 @@ public final class ComplexAutomaton extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, if you control seven or more permanents, return Complex Automaton to its owner's hand. - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new ReturnToHandSourceEffect(true), TargetController.YOU, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new PermanentsOnTheBattlefieldCondition(new FilterControlledPermanent(), ComparisonType.MORE_THAN, 6), - "At the beginning of your upkeep, if you control seven or more permanents, return Complex Automaton to its owner's hand.")); + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + new ReturnToHandSourceEffect(true), + TargetController.YOU, false + ), condition, "At the beginning of your upkeep, " + + "if you control seven or more permanents, return {this} to its owner's hand." + )); } - public ComplexAutomaton(final ComplexAutomaton card) { + private ComplexAutomaton(final ComplexAutomaton card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/ConclavePhalanx.java b/Mage.Sets/src/mage/cards/c/ConclavePhalanx.java index b8efd50953..41257a501d 100644 --- a/Mage.Sets/src/mage/cards/c/ConclavePhalanx.java +++ b/Mage.Sets/src/mage/cards/c/ConclavePhalanx.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -11,16 +9,17 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author jonubuu */ public final class ConclavePhalanx extends CardImpl { public ConclavePhalanx(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -31,7 +30,7 @@ public final class ConclavePhalanx extends CardImpl { this.addAbility(new ConvokeAbility()); // When Conclave Phalanx enters the battlefield, you gain 1 life for each creature you control. this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect( - new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent())))); + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE)))); } public ConclavePhalanx(final ConclavePhalanx card) { diff --git a/Mage.Sets/src/mage/cards/c/ConclaveTribunal.java b/Mage.Sets/src/mage/cards/c/ConclaveTribunal.java index d06e3d72f8..ca5fec4701 100644 --- a/Mage.Sets/src/mage/cards/c/ConclaveTribunal.java +++ b/Mage.Sets/src/mage/cards/c/ConclaveTribunal.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class ConclaveTribunal extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java b/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java index 50103876f9..23c5c0e79d 100644 --- a/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java +++ b/Mage.Sets/src/mage/cards/c/ConcussiveBolt.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.MetalcraftCondition; import mage.abilities.effects.OneShotEffect; @@ -17,8 +15,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author North */ public final class ConcussiveBolt extends CardImpl { @@ -89,14 +88,11 @@ class ConcussiveBoltRestrictionEffect extends RestrictionEffect { if (player == null) { return false; } - if (metalcraft && permanent.isControlledBy(player.getId())) { - return true; - } - return false; + return metalcraft && permanent.isControlledBy(player.getId()); } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } } diff --git a/Mage.Sets/src/mage/cards/c/Condescend.java b/Mage.Sets/src/mage/cards/c/Condescend.java index 05ce5af84c..26c8ceb6f9 100644 --- a/Mage.Sets/src/mage/cards/c/Condescend.java +++ b/Mage.Sets/src/mage/cards/c/Condescend.java @@ -21,7 +21,7 @@ public final class Condescend extends CardImpl { // Counter target spell unless its controller pays {X}. - this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetSpell()); // Scry 2. this.getSpellAbility().addEffect(new ScryEffect(2)); diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java b/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java index 3dc843647f..b5f0b3842a 100644 --- a/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java +++ b/Mage.Sets/src/mage/cards/c/ConduitOfRuin.java @@ -38,7 +38,7 @@ public final class ConduitOfRuin extends CardImpl { private static final FilterCreatureCard filterCost = new FilterCreatureCard("The first creature spell"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 6)); filterCost.add(new FirstCastCreatureSpellPredicate()); } @@ -71,11 +71,10 @@ public final class ConduitOfRuin extends CardImpl { class ConduitOfRuinWatcher extends Watcher { - Map playerCreatureSpells; - int spellCount = 0; + private Map playerCreatureSpells; public ConduitOfRuinWatcher() { - super(ConduitOfRuinWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); playerCreatureSpells = new HashMap<>(); } @@ -117,7 +116,7 @@ class FirstCastCreatureSpellPredicate implements ObjectPlayerPredicate input, Game game) { if (input.getObject() instanceof Spell && ((Spell) input.getObject()).isCreature()) { - ConduitOfRuinWatcher watcher = (ConduitOfRuinWatcher) game.getState().getWatchers().get(ConduitOfRuinWatcher.class.getSimpleName()); + ConduitOfRuinWatcher watcher = game.getState().getWatcher(ConduitOfRuinWatcher.class); return watcher != null && watcher.creatureSpellsCastThisTurn(input.getPlayerId()) == 0; } return false; diff --git a/Mage.Sets/src/mage/cards/c/ConfiscationCoup.java b/Mage.Sets/src/mage/cards/c/ConfiscationCoup.java index ff2bc46367..7d3d959125 100644 --- a/Mage.Sets/src/mage/cards/c/ConfiscationCoup.java +++ b/Mage.Sets/src/mage/cards/c/ConfiscationCoup.java @@ -29,7 +29,7 @@ import mage.target.targetpointer.FixedTarget; */ public final class ConfiscationCoup extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("creature or artifact"); + private static final FilterPermanent filter = new FilterPermanent("creature or artifact"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.ARTIFACT))); diff --git a/Mage.Sets/src/mage/cards/c/Conflux.java b/Mage.Sets/src/mage/cards/c/Conflux.java index 555530b266..a0de7fd3dc 100644 --- a/Mage.Sets/src/mage/cards/c/Conflux.java +++ b/Mage.Sets/src/mage/cards/c/Conflux.java @@ -77,7 +77,7 @@ class ConfluxEffect extends OneShotEffect { TargetCardInLibrary targetGreen = new TargetCardInLibrary(filterGreen); if (you != null && you.getLibrary().hasCards()) { - if (you.searchLibrary(targetWhite, game)) { + if (you.searchLibrary(targetWhite, source, game)) { if (!targetWhite.getTargets().isEmpty()) { for (UUID cardId : targetWhite.getTargets()) { Card card = you.getLibrary().remove(cardId, game); @@ -89,7 +89,7 @@ class ConfluxEffect extends OneShotEffect { } } if (you != null && you.getLibrary().hasCards()) { - if (you.searchLibrary(targetBlue, game)) { + if (you.searchLibrary(targetBlue, source, game)) { if (!targetBlue.getTargets().isEmpty()) { for (UUID cardId : targetBlue.getTargets()) { Card card = you.getLibrary().remove(cardId, game); @@ -101,7 +101,7 @@ class ConfluxEffect extends OneShotEffect { } } if (you != null && you.getLibrary().hasCards()) { - if (you.searchLibrary(targetBlack, game)) { + if (you.searchLibrary(targetBlack, source, game)) { if (!targetBlack.getTargets().isEmpty()) { for (UUID cardId : targetBlack.getTargets()) { Card card = you.getLibrary().remove(cardId, game); @@ -113,7 +113,7 @@ class ConfluxEffect extends OneShotEffect { } } if (you != null && you.getLibrary().hasCards()) { - if (you.searchLibrary(targetRed, game)) { + if (you.searchLibrary(targetRed, source, game)) { if (!targetRed.getTargets().isEmpty()) { for (UUID cardId : targetRed.getTargets()) { Card card = you.getLibrary().remove(cardId, game); @@ -125,7 +125,7 @@ class ConfluxEffect extends OneShotEffect { } } if (you != null && you.getLibrary().hasCards()) { - if (you.searchLibrary(targetGreen, game)) { + if (you.searchLibrary(targetGreen, source, game)) { if (!targetGreen.getTargets().isEmpty()) { for (UUID cardId : targetGreen.getTargets()) { Card card = you.getLibrary().remove(cardId, game); diff --git a/Mage.Sets/src/mage/cards/c/Confound.java b/Mage.Sets/src/mage/cards/c/Confound.java index 6a04ca4571..1a46edb59c 100644 --- a/Mage.Sets/src/mage/cards/c/Confound.java +++ b/Mage.Sets/src/mage/cards/c/Confound.java @@ -18,7 +18,7 @@ import mage.target.TargetSpell; */ public final class Confound extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a creature"); + private static final FilterSpell filter = new FilterSpell("spell that targets a creature"); static { filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/c/ConfrontTheAssault.java b/Mage.Sets/src/mage/cards/c/ConfrontTheAssault.java new file mode 100644 index 0000000000..985bc5f919 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConfrontTheAssault.java @@ -0,0 +1,45 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.AttackedThisStepCondition; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.TurnPhase; +import mage.game.permanent.token.SpiritWhiteToken; +import mage.watchers.common.PlayerAttackedStepWatcher; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ConfrontTheAssault extends CardImpl { + + public ConfrontTheAssault(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); + + // Cast this spell only if a creature is attacking you. + Ability ability = new CastOnlyDuringPhaseStepSourceAbility( + TurnPhase.COMBAT, PhaseStep.DECLARE_ATTACKERS, AttackedThisStepCondition.instance, + "Cast this spell only if a creature is attacking you." + ); + ability.addWatcher(new PlayerAttackedStepWatcher()); + this.addAbility(ability); + + // Create three 1/1 white Spirit creature tokens with flying. + this.getSpellAbility().addEffect(new CreateTokenEffect(new SpiritWhiteToken("ANA"), 3)); + } + + public ConfrontTheAssault(final ConfrontTheAssault card) { + super(card); + } + + @Override + public ConfrontTheAssault copy() { + return new ConfrontTheAssault(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java b/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java index 388e46d2bc..fe65023e65 100644 --- a/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java +++ b/Mage.Sets/src/mage/cards/c/ConfusionInTheRanks.java @@ -1,10 +1,6 @@ package mage.cards.c; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.Effect; @@ -22,9 +18,14 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; +import java.util.UUID; /** - * * @author anonymous */ public final class ConfusionInTheRanks extends CardImpl { @@ -38,7 +39,6 @@ public final class ConfusionInTheRanks extends CardImpl { new CardTypePredicate(CardType.ENCHANTMENT) )); } - private final UUID originalId; public ConfusionInTheRanks(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}{R}"); @@ -49,54 +49,18 @@ public final class ConfusionInTheRanks extends CardImpl { new ExchangeControlTargetEffect( Duration.EndOfGame, "its controller chooses target permanent " - + "another player controls that shares a card type with it. " - + "Exchange control of those permanents" + + "another player controls that shares a card type with it. " + + "Exchange control of those permanents" ), filter, false, SetTargetPointer.PERMANENT, null ); ability.addTarget(new TargetPermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(ConfusionInTheRanksAdjuster.instance); this.addAbility(ability); } public ConfusionInTheRanks(final ConfusionInTheRanks card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - UUID enteringPermanentId = null; - for (Effect effect : ability.getEffects()) { - enteringPermanentId = effect.getTargetPointer().getFirst(game, ability); - } - if (enteringPermanentId == null) { - return; - } - Permanent enteringPermanent = game.getPermanent(enteringPermanentId); - if (enteringPermanent == null) { - return; - } - ability.getTargets().clear(); - FilterPermanent filterTarget = new FilterPermanent(); - String message = ""; - filterTarget.add(Predicates.not(new ControllerIdPredicate(enteringPermanent.getControllerId()))); - Set cardTypesPredicates = new HashSet<>(1); - for (CardType cardTypeEntering : enteringPermanent.getCardType()) { - cardTypesPredicates.add(new CardTypePredicate(cardTypeEntering)); - if (!message.isEmpty()) { - message += "or "; - } - message += cardTypeEntering.toString().toLowerCase(Locale.ENGLISH) + ' '; - } - filterTarget.add(Predicates.or(cardTypesPredicates)); - message += "you don't control"; - filterTarget.setMessage(message); - TargetPermanent target = new TargetPermanent(filterTarget); - target.setTargetController(enteringPermanent.getControllerId()); - ability.getTargets().add(target); - } } @Override @@ -104,3 +68,40 @@ public final class ConfusionInTheRanks extends CardImpl { return new ConfusionInTheRanks(this); } } + +enum ConfusionInTheRanksAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + UUID enteringPermanentId = null; + for (Effect effect : ability.getEffects()) { + enteringPermanentId = effect.getTargetPointer().getFirst(game, ability); + } + if (enteringPermanentId == null) { + return; + } + Permanent enteringPermanent = game.getPermanent(enteringPermanentId); + if (enteringPermanent == null) { + return; + } + ability.getTargets().clear(); + FilterPermanent filterTarget = new FilterPermanent(); + String message = ""; + filterTarget.add(Predicates.not(new ControllerIdPredicate(enteringPermanent.getControllerId()))); + Set cardTypesPredicates = new HashSet<>(1); + for (CardType cardTypeEntering : enteringPermanent.getCardType()) { + cardTypesPredicates.add(new CardTypePredicate(cardTypeEntering)); + if (!message.isEmpty()) { + message += "or "; + } + message += cardTypeEntering.toString().toLowerCase(Locale.ENGLISH) + ' '; + } + filterTarget.add(Predicates.or(cardTypesPredicates)); + message += "you don't control"; + filterTarget.setMessage(message); + TargetPermanent target = new TargetPermanent(filterTarget); + target.setTargetController(enteringPermanent.getControllerId()); + ability.getTargets().add(target); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java b/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java index 822d0addf2..6e60b5d15a 100644 --- a/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java +++ b/Mage.Sets/src/mage/cards/c/CongregationAtDawn.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.List; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -64,10 +63,10 @@ class CongregationAtDawnEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCreatureCard("creature cards")); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); - for (UUID cardId : (List) target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().remove(cardId, game); revealed.add(card); } diff --git a/Mage.Sets/src/mage/cards/c/ConquerorsFlail.java b/Mage.Sets/src/mage/cards/c/ConquerorsFlail.java index 477cd898b8..6e1ed21d91 100644 --- a/Mage.Sets/src/mage/cards/c/ConquerorsFlail.java +++ b/Mage.Sets/src/mage/cards/c/ConquerorsFlail.java @@ -90,9 +90,8 @@ class ConquerorsFlailColorCount implements DynamicValue { count++; } } - return count; } - return 0; + return count; } @Override diff --git a/Mage.Sets/src/mage/cards/c/ConsecrateConsume.java b/Mage.Sets/src/mage/cards/c/ConsecrateConsume.java new file mode 100644 index 0000000000..72fc2b36a9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConsecrateConsume.java @@ -0,0 +1,94 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ConsecrateConsume extends SplitCard { + + public ConsecrateConsume(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{1}{W/B}", "{2}{W}{B}", SpellAbilityType.SPLIT); + + // Consecrate + // Exile target card from a graveyard. + this.getLeftHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCardInGraveyard()); + + // Draw a card. + this.getLeftHalfCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + + // Consume + // Target player sacrifices a creature with the greatest power among creatures they control. You gain life equal to its power. + this.getRightHalfCard().getSpellAbility().addEffect(new ConsumeEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer()); + } + + private ConsecrateConsume(final ConsecrateConsume card) { + super(card); + } + + @Override + public ConsecrateConsume copy() { + return new ConsecrateConsume(this); + } +} + +class ConsumeEffect extends OneShotEffect { + + ConsumeEffect() { + super(Outcome.Benefit); + staticText = "Target player sacrifices a creature " + + "with the greatest power among creatures they control. " + + "You gain life equal to its power."; + } + + private ConsumeEffect(final ConsumeEffect effect) { + super(effect); + } + + @Override + public ConsumeEffect copy() { + return new ConsumeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null || controller == null) { + return false; + } + int greatestPower = 0; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(player.getId())) { + if (permanent != null && permanent.isCreature()) { + greatestPower = Math.max(permanent.getPower().getValue(), greatestPower); + } + } + FilterPermanent filter = new FilterCreaturePermanent("creature with power " + greatestPower); + filter.add(new PowerPredicate(ComparisonType.EQUAL_TO, greatestPower)); + new SacrificeEffect(filter, 1, "").apply(game, source); + controller.gainLife(greatestPower, game, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/ConsecratedByBlood.java b/Mage.Sets/src/mage/cards/c/ConsecratedByBlood.java index 6b03575c2a..cc1b5456e1 100644 --- a/Mage.Sets/src/mage/cards/c/ConsecratedByBlood.java +++ b/Mage.Sets/src/mage/cards/c/ConsecratedByBlood.java @@ -32,7 +32,7 @@ public final class ConsecratedByBlood extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("two other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ConsecratedByBlood(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ConsignOblivion.java b/Mage.Sets/src/mage/cards/c/ConsignOblivion.java index 8a46e4a0d3..f54697f3d1 100644 --- a/Mage.Sets/src/mage/cards/c/ConsignOblivion.java +++ b/Mage.Sets/src/mage/cards/c/ConsignOblivion.java @@ -29,7 +29,7 @@ public final class ConsignOblivion extends SplitCard { // Oblivion {4}{B} // Sorcery // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Target opponent discards two cards. getRightHalfCard().getSpellAbility().addEffect(new DiscardTargetEffect(2)); getRightHalfCard().getSpellAbility().addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/cards/c/ConsignToThePit.java b/Mage.Sets/src/mage/cards/c/ConsignToThePit.java new file mode 100644 index 0000000000..18a9df9d95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConsignToThePit.java @@ -0,0 +1,69 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ConsignToThePit extends CardImpl { + + public ConsignToThePit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{B}"); + + // Destroy target creature. Consign to the Pit deals 2 damage to that creature's controller. + this.getSpellAbility().addEffect(new ConsignToThePitEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private ConsignToThePit(final ConsignToThePit card) { + super(card); + } + + @Override + public ConsignToThePit copy() { + return new ConsignToThePit(this); + } +} + +class ConsignToThePitEffect extends OneShotEffect { + + ConsignToThePitEffect() { + super(Outcome.Benefit); + staticText = "Destroy target creature. {this} deals 2 damage to that creature's controller."; + } + + private ConsignToThePitEffect(final ConsignToThePitEffect effect) { + super(effect); + } + + @Override + public ConsignToThePitEffect copy() { + return new ConsignToThePitEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + permanent.destroy(source.getSourceId(), game, false); + player.damage(2, source.getSourceId(), game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/Conspiracy.java b/Mage.Sets/src/mage/cards/c/Conspiracy.java index dcac9387fb..934ebd7db9 100644 --- a/Mage.Sets/src/mage/cards/c/Conspiracy.java +++ b/Mage.Sets/src/mage/cards/c/Conspiracy.java @@ -1,9 +1,5 @@ - package mage.cards.c; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -22,8 +18,11 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.util.SubTypeList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + /** - * * @author anonymous */ public final class Conspiracy extends CardImpl { @@ -72,14 +71,14 @@ class ConspiracyEffect extends ContinuousEffectImpl { // in graveyard for (UUID cardId : controller.getGraveyard()) { Card card = game.getCard(cardId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { setCreatureSubtype(card, subType, game); } } // on Hand for (UUID cardId : controller.getHand()) { Card card = game.getCard(cardId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { setCreatureSubtype(card, subType, game); } } @@ -99,13 +98,13 @@ class ConspiracyEffect extends ContinuousEffectImpl { for (UUID commanderId : controller.getCommandersIds()) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { setCreatureSubtype(card, subType, game); } } } // creature spells you control - for (Iterator iterator = game.getStack().iterator(); iterator.hasNext();) { + for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); if (stackObject instanceof Spell && stackObject.isControlledBy(source.getControllerId()) @@ -140,7 +139,7 @@ class ConspiracyEffect extends ContinuousEffectImpl { private void setChosenSubtype(SubTypeList subtype, SubType choice) { if (subtype.size() != 1 || !subtype.contains(choice)) { - subtype.removeAll(SubType.getCreatureTypes(false)); + subtype.clear(); subtype.add(choice); } } diff --git a/Mage.Sets/src/mage/cards/c/ConsulateCrackdown.java b/Mage.Sets/src/mage/cards/c/ConsulateCrackdown.java index c43791b438..164a7c77f3 100644 --- a/Mage.Sets/src/mage/cards/c/ConsulateCrackdown.java +++ b/Mage.Sets/src/mage/cards/c/ConsulateCrackdown.java @@ -64,19 +64,19 @@ class ConsulateCracksownExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player contoller = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); //If the permanent leaves the battlefield before the ability resolves, artifacts won't be exiled. - if (permanent == null || contoller == null) return false; + if (permanent == null || controller == null) return false; Set toExile = new LinkedHashSet<>(); - for (Permanent artifact : game.getBattlefield().getActivePermanents(filter, contoller.getId(), game)) { + for (Permanent artifact : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) { toExile.add(artifact); } if (!toExile.isEmpty()) { - contoller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); + controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java b/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java index a2a81ff2a7..29fe70cdc5 100644 --- a/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java +++ b/Mage.Sets/src/mage/cards/c/ConsulsShieldguard.java @@ -26,10 +26,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class ConsulsShieldguard extends CardImpl { - private final static FilterAttackingCreature filter = new FilterAttackingCreature(); + private static final FilterAttackingCreature filter = new FilterAttackingCreature(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ConsulsShieldguard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java b/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java index 54c4ab2113..87498d73ce 100644 --- a/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java +++ b/Mage.Sets/src/mage/cards/c/ConsultTheNecrosages.java @@ -24,8 +24,8 @@ public final class ConsultTheNecrosages extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new DrawCardTargetEffect(2)); Mode mode = new Mode(); - mode.getTargets().add(new TargetPlayer()); - mode.getEffects().add(new DiscardTargetEffect(2)); + mode.addTarget(new TargetPlayer()); + mode.addEffect(new DiscardTargetEffect(2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumeSpirit.java b/Mage.Sets/src/mage/cards/c/ConsumeSpirit.java index ad2aced6af..21a451a872 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumeSpirit.java +++ b/Mage.Sets/src/mage/cards/c/ConsumeSpirit.java @@ -1,49 +1,52 @@ package mage.cards.c; -import java.util.UUID; -import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.VariableManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.FilterMana; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetAnyTarget; - +import java.util.UUID; /** * @author nantuko */ public final class ConsumeSpirit extends CardImpl { - static final FilterMana filterBlack = new FilterMana(); + private static final FilterMana filterBlack = new FilterMana(); static { filterBlack.setBlack(true); } public ConsumeSpirit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{1}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}"); // Spend only black mana on X. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("Spend only black mana on X")).setRuleAtTheTop(true) + ); + // Consume Spirit deals X damage to any target and you gain X life. this.getSpellAbility().addTarget(new TargetAnyTarget()); - this.getSpellAbility().addEffect(new ConsumeSpiritEffect()); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance).concatBy("and")); VariableCost variableCost = this.getSpellAbility().getManaCostsToPay().getVariableCosts().get(0); if (variableCost instanceof VariableManaCost) { ((VariableManaCost) variableCost).setFilter(filterBlack); } } - public ConsumeSpirit(final ConsumeSpirit card) { + private ConsumeSpirit(final ConsumeSpirit card) { super(card); } @@ -52,46 +55,3 @@ public final class ConsumeSpirit extends CardImpl { return new ConsumeSpirit(this); } } - -class ConsumeSpiritEffect extends OneShotEffect { - - public ConsumeSpiritEffect() { - super(Outcome.Damage); - staticText = "Consume Spirit deals X damage to any target and you gain X life. Spend only black mana on X"; - } - - public ConsumeSpiritEffect(final ConsumeSpiritEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int amount = source.getManaCostsToPay().getX(); - if (amount > 0) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - permanent.damage(amount, source.getSourceId(), game, false, true); - } else { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null) { - player.damage(amount, source.getSourceId(), game, false, true); - } else { - return false; - } - } - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.gainLife(amount, game, source); - } else { - return false; - } - } - return true; - } - - @Override - public ConsumeSpiritEffect copy() { - return new ConsumeSpiritEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/c/ConsumeTheMeek.java b/Mage.Sets/src/mage/cards/c/ConsumeTheMeek.java index cde6962f31..44a67c1570 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumeTheMeek.java +++ b/Mage.Sets/src/mage/cards/c/ConsumeTheMeek.java @@ -27,7 +27,7 @@ public final class ConsumeTheMeek extends CardImpl { // Destroy each creature with converted mana cost 3 or less. They can't be regenerated. - this.getSpellAbility().addEffect(new DestroyAllEffect(filter, false)); + this.getSpellAbility().addEffect(new DestroyAllEffect(filter, true)); } public ConsumeTheMeek(final ConsumeTheMeek card) { diff --git a/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java b/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java index 97287b6037..9546725a19 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingBonfire.java @@ -41,8 +41,8 @@ public final class ConsumingBonfire extends CardImpl { //or Consuming Bonfire deals 7 damage to target Treefolk creature. Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(7)); - mode.getTargets().add(new TargetPermanent(filter2)); + mode.addEffect(new DamageTargetEffect(7)); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java index 744fca6f32..116a5ac642 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingSinkhole.java @@ -41,8 +41,8 @@ public final class ConsumingSinkhole extends CardImpl { // Consuming Sinkhole deals 4 damage to target player. Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(4)); - mode.getTargets().add(new TargetPlayerOrPlaneswalker()); + mode.addEffect(new DamageTargetEffect(4)); + mode.addTarget(new TargetPlayerOrPlaneswalker()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/ConsumingVapors.java b/Mage.Sets/src/mage/cards/c/ConsumingVapors.java index f31246100a..adbf64bb32 100644 --- a/Mage.Sets/src/mage/cards/c/ConsumingVapors.java +++ b/Mage.Sets/src/mage/cards/c/ConsumingVapors.java @@ -72,7 +72,7 @@ class ConsumingVaporsEffect extends OneShotEffect { //A spell or ability could have removed the only legal target this player //had, if thats the case this ability should fizzle. - if (target.canChoose(player.getId(), game)) { + if (player != null && target.canChoose(player.getId(), game)) { player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/c/ContagionEngine.java b/Mage.Sets/src/mage/cards/c/ContagionEngine.java index 9a21e1df5f..96c31fe3e6 100644 --- a/Mage.Sets/src/mage/cards/c/ContagionEngine.java +++ b/Mage.Sets/src/mage/cards/c/ContagionEngine.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -21,8 +19,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author Loki */ public final class ContagionEngine extends CardImpl { @@ -36,13 +35,13 @@ public final class ContagionEngine extends CardImpl { this.addAbility(ability); // {4}, {T}: Proliferate, then proliferate again. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there. Then do it again.) - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ProliferateEffect(), new GenericManaCost(4)); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ProliferateEffect("", false), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); - ability.addEffect(new ProliferateEffect()); + ability.addEffect(new ProliferateEffect(" again", true).concatBy(", then")); this.addAbility(ability); } - public ContagionEngine(final ContagionEngine card) { + private ContagionEngine(final ContagionEngine card) { super(card); } @@ -60,7 +59,7 @@ class ContagionEngineEffect extends OneShotEffect { staticText = "put a -1/-1 counter on each creature target player controls"; } - ContagionEngineEffect(final ContagionEngineEffect effect) { + private ContagionEngineEffect(final ContagionEngineEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/c/ContainmentPriest.java b/Mage.Sets/src/mage/cards/c/ContainmentPriest.java index e3cffabc67..701eb3aa4a 100644 --- a/Mage.Sets/src/mage/cards/c/ContainmentPriest.java +++ b/Mage.Sets/src/mage/cards/c/ContainmentPriest.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,19 +9,16 @@ import mage.abilities.keyword.TransformAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; import mage.watchers.common.CreatureWasCastWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ContainmentPriest extends CardImpl { @@ -94,16 +90,14 @@ class ContainmentPriestReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD) { - Card card = game.getCard(event.getTargetId()); Object entersTransformed = game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + event.getTargetId()); - if (entersTransformed instanceof Boolean && (Boolean) entersTransformed && card.getSecondCardFace() != null) { + Card card = game.getCard(event.getTargetId()); + if (card != null && entersTransformed instanceof Boolean && (Boolean) entersTransformed && card.getSecondCardFace() != null) { card = card.getSecondCardFace(); } - if (card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly - CreatureWasCastWatcher watcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName()); - if (watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId())) { - return true; - } + if (card != null && card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly + CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class); + return watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId()); } } return false; diff --git a/Mage.Sets/src/mage/cards/c/Contempt.java b/Mage.Sets/src/mage/cards/c/Contempt.java new file mode 100644 index 0000000000..1aa4800d05 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Contempt.java @@ -0,0 +1,93 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.AttacksAttachedTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class Contempt extends CardImpl { + + public Contempt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature attacks, return it and Contempt to their owners' hands at end of combat. + this.addAbility(new AttacksAttachedTriggeredAbility(new ContemptEffect())); + + } + + public Contempt(final Contempt card) { + super(card); + } + + @Override + public Contempt copy() { + return new Contempt(this); + } +} + +class ContemptEffect extends OneShotEffect { + + ContemptEffect() { + super(Outcome.Detriment); + this.staticText = "return it and {this} to their owners' hands at end of combat."; + } + + ContemptEffect(final ContemptEffect effect) { + super(effect); + } + + @Override + public ContemptEffect copy() { + return new ContemptEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent contempt = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (contempt != null) { + Permanent attachedToPermanent = game.getPermanent(contempt.getAttachedTo()); + if (attachedToPermanent != null) { + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget( + attachedToPermanent.getId())).setText("return " + + attachedToPermanent.getName() + " to owner's hand."); + AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(ability, source); + } + Effect effect = new ReturnToHandSourceEffect(); + AtTheEndOfCombatDelayedTriggeredAbility ability = new AtTheEndOfCombatDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(ability, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/ContentiousPlan.java b/Mage.Sets/src/mage/cards/c/ContentiousPlan.java new file mode 100644 index 0000000000..dc9573d558 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ContentiousPlan.java @@ -0,0 +1,33 @@ +package mage.cards.c; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author antoni-g + */ +public final class ContentiousPlan extends CardImpl { + + public ContentiousPlan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + + // Proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.getSpellAbility().addEffect(new ProliferateEffect()); + // Draw a card. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + } + + private ContentiousPlan(final ContentiousPlan card) { + super(card); + } + + @Override + public ContentiousPlan copy() { + return new ContentiousPlan(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java index dc03cb3c69..ae2ce4eaaf 100644 --- a/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java +++ b/Mage.Sets/src/mage/cards/c/ConundrumSphinx.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -18,9 +16,11 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class ConundrumSphinx extends CardImpl { @@ -85,7 +85,7 @@ class ConundrumSphinxEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(source, player.getName(), cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.putCardsOnBottomOfLibrary(cards, game, source, false); diff --git a/Mage.Sets/src/mage/cards/c/Convalescence.java b/Mage.Sets/src/mage/cards/c/Convalescence.java index 104ba5007f..fa3476e5a4 100644 --- a/Mage.Sets/src/mage/cards/c/Convalescence.java +++ b/Mage.Sets/src/mage/cards/c/Convalescence.java @@ -51,7 +51,7 @@ class ConvalescenceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player.getLife() <= 10) { + if (player != null && player.getLife() <= 10) { player.gainLife(1, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/c/Conversion.java b/Mage.Sets/src/mage/cards/c/Conversion.java index 24f0ef8d1f..8731aaba76 100644 --- a/Mage.Sets/src/mage/cards/c/Conversion.java +++ b/Mage.Sets/src/mage/cards/c/Conversion.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.List; @@ -13,11 +12,14 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; import mage.abilities.mana.WhiteManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -27,13 +29,15 @@ import mage.game.permanent.Permanent; */ public final class Conversion extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(SubType.MOUNTAIN, "Mountains"); - public Conversion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // At the beginning of your upkeep, sacrifice Conversion unless you pay {W}{W}. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{W}{W}")), TargetController.YOU, false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new SacrificeSourceUnlessPaysEffect( + new ManaCostsImpl("{W}{W}")), + TargetController.YOU, + false)); // All Mountains are Plains. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConversionEffect())); @@ -72,15 +76,45 @@ public final class Conversion extends CardImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - for (Permanent land : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND)) { switch (layer) { - case AbilityAddingRemovingEffects_6: - land.removeAllAbilities(source.getSourceId(), game); - land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); - break; case TypeChangingEffects_4: - land.getSubtype(game).clear(); - land.getSubtype(game).add(SubType.PLAINS); + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.getSubtype(game).clear(); + land.getSubtype(game).add(SubType.PLAINS); + game.getState().setValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), + "true"); + } + break; + case AbilityAddingRemovingEffects_6: + if (game.getState().getValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("conversion" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } + } break; } } @@ -89,20 +123,17 @@ public final class Conversion extends CardImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } @Override public Set isDependentTo(List allEffectsInLayer) { - // the dependent classes needs to be an enclosed class for dependent check of continuous effects return allEffectsInLayer .stream() - .filter(effect->effect.getDependencyTypes().contains(DependencyType.BecomeMountain)) + .filter(effect -> effect.getDependencyTypes().contains(DependencyType.BecomePlains)) .map(Effect::getId) .collect(Collectors.toSet()); - } - } - } diff --git a/Mage.Sets/src/mage/cards/c/CopperLeafAngel.java b/Mage.Sets/src/mage/cards/c/CopperLeafAngel.java index 8fe61fdfd9..a894eec248 100644 --- a/Mage.Sets/src/mage/cards/c/CopperLeafAngel.java +++ b/Mage.Sets/src/mage/cards/c/CopperLeafAngel.java @@ -35,7 +35,7 @@ public final class CopperLeafAngel extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // {tap}, Sacrifice X lands: Put X +1/+1 counters on Copper-Leaf Angel. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(),new GetXValue(), false), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(),GetXValue.instance, false), new TapSourceCost()); ability.addCost(new SacrificeXTargetCost(new FilterControlledLandPermanent("lands"), false)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CopperhoofVorrac.java b/Mage.Sets/src/mage/cards/c/CopperhoofVorrac.java index ea42ffd4a0..0a48307d1f 100644 --- a/Mage.Sets/src/mage/cards/c/CopperhoofVorrac.java +++ b/Mage.Sets/src/mage/cards/c/CopperhoofVorrac.java @@ -28,7 +28,7 @@ public final class CopperhoofVorrac extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("untapped permanent your opponents control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java index f84ee371dd..a17d5da526 100644 --- a/Mage.Sets/src/mage/cards/c/CopyEnchantment.java +++ b/Mage.Sets/src/mage/cards/c/CopyEnchantment.java @@ -2,6 +2,8 @@ package mage.cards.c; import java.util.UUID; + +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -17,6 +19,7 @@ import mage.filter.FilterPermanent; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentCard; import mage.players.Player; import mage.target.Target; import mage.util.functions.EmptyApplyToPermanent; @@ -44,63 +47,3 @@ public final class CopyEnchantment extends CardImpl { return new CopyEnchantment(this); } } - -class CopyEnchantmentEffect extends CopyPermanentEffect { - - public CopyEnchantmentEffect(FilterPermanent filter) { - super(filter, new EmptyApplyToPermanent()); - } - - public CopyEnchantmentEffect(final CopyEnchantmentEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); - if (controller != null && sourcePermanent != null) { - if (super.apply(game, source)) { - Permanent permanentToCopy = getBluePrintPermanent(); - if (permanentToCopy != null) { - if (permanentToCopy.hasSubtype(SubType.AURA, game)) { - Target target = getBluePrintPermanent().getSpellAbility().getTargets().get(0); - Outcome auraOutcome = Outcome.BoostCreature; - Ability: - for (Ability ability : getBluePrintPermanent().getAbilities()) { - if (ability instanceof SpellAbility) { - for (Effect effect : ability.getEffects()) { - if (effect instanceof AttachEffect) { - auraOutcome = effect.getOutcome(); - break Ability; - } - } - } - } - target.setNotTarget(true); - if (controller.choose(auraOutcome, target, source.getSourceId(), game)) { - UUID targetId = target.getFirstTarget(); - Permanent targetPermanent = game.getPermanent(targetId); - Player targetPlayer = game.getPlayer(targetId); - if (targetPermanent != null) { - targetPermanent.addAttachment(sourcePermanent.getId(), game); - } else if (targetPlayer != null) { - targetPlayer.addAttachment(sourcePermanent.getId(), game); - } else { - return false; - } - } - } - return true; - } - } - } - return false; - } - - @Override - public CopyEnchantmentEffect copy() { - return new CopyEnchantmentEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/c/CoralAtoll.java b/Mage.Sets/src/mage/cards/c/CoralAtoll.java index 0fc9f41693..92a7ab94cf 100644 --- a/Mage.Sets/src/mage/cards/c/CoralAtoll.java +++ b/Mage.Sets/src/mage/cards/c/CoralAtoll.java @@ -30,7 +30,7 @@ public final class CoralAtoll extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ISLAND)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public CoralAtoll(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CoralCommando.java b/Mage.Sets/src/mage/cards/c/CoralCommando.java new file mode 100644 index 0000000000..16b2ed9439 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CoralCommando.java @@ -0,0 +1,33 @@ +package mage.cards.c; + +import mage.MageInt; +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 CoralCommando extends CardImpl { + + public CoralCommando(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + } + + private CoralCommando(final CoralCommando card) { + super(card); + } + + @Override + public CoralCommando copy() { + return new CoralCommando(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CoralFighters.java b/Mage.Sets/src/mage/cards/c/CoralFighters.java index 2737c523a6..eaee988286 100644 --- a/Mage.Sets/src/mage/cards/c/CoralFighters.java +++ b/Mage.Sets/src/mage/cards/c/CoralFighters.java @@ -64,8 +64,7 @@ class CoralFightersEffect extends OneShotEffect { if(controller != null && defendingPlayer != null) { Card card = defendingPlayer.getLibrary().getFromTop(game); if(card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("Coral Fighters", cards, game); if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", source, game)) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); diff --git a/Mage.Sets/src/mage/cards/c/CoralReef.java b/Mage.Sets/src/mage/cards/c/CoralReef.java index a15a7c6afc..24093ec4c5 100644 --- a/Mage.Sets/src/mage/cards/c/CoralReef.java +++ b/Mage.Sets/src/mage/cards/c/CoralReef.java @@ -40,7 +40,7 @@ public final class CoralReef extends CardImpl { static { islandFilter.add(new SubtypePredicate(SubType.ISLAND)); - untappedBlueCreatureFilter.add(Predicates.not(new TappedPredicate())); + untappedBlueCreatureFilter.add(Predicates.not(TappedPredicate.instance)); untappedBlueCreatureFilter.add(new ColorPredicate(ObjectColor.BLUE)); } diff --git a/Mage.Sets/src/mage/cards/c/CoreProwler.java b/Mage.Sets/src/mage/cards/c/CoreProwler.java index 0354d8b176..963b642bbe 100644 --- a/Mage.Sets/src/mage/cards/c/CoreProwler.java +++ b/Mage.Sets/src/mage/cards/c/CoreProwler.java @@ -1,8 +1,5 @@ - - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesTriggeredAbility; import mage.abilities.effects.common.counter.ProliferateEffect; @@ -12,22 +9,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author Loki */ public final class CoreProwler extends CardImpl { - public CoreProwler (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + public CoreProwler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(2); + + // Infect (This creature deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.) this.addAbility(InfectAbility.getInstance()); + + // When Core Prowler dies, proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.addAbility(new DiesTriggeredAbility(new ProliferateEffect())); } - public CoreProwler (final CoreProwler card) { + public CoreProwler(final CoreProwler card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CorpseConnoisseur.java b/Mage.Sets/src/mage/cards/c/CorpseConnoisseur.java index bde105b0f7..d134fd60ac 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseConnoisseur.java +++ b/Mage.Sets/src/mage/cards/c/CorpseConnoisseur.java @@ -70,7 +70,7 @@ class SearchLibraryPutInGraveyard extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/c/CorpseHarvester.java b/Mage.Sets/src/mage/cards/c/CorpseHarvester.java index 9c7efc62df..0735a84c4a 100644 --- a/Mage.Sets/src/mage/cards/c/CorpseHarvester.java +++ b/Mage.Sets/src/mage/cards/c/CorpseHarvester.java @@ -82,7 +82,7 @@ class CorpseHarvesterEffect extends OneShotEffect { FilterCard filter = new FilterCard(subtype); filter.add(new SubtypePredicate(SubType.byDescription(subtype))); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/c/CorrosiveGale.java b/Mage.Sets/src/mage/cards/c/CorrosiveGale.java index 3a4ca7d234..e5a5ccb8e4 100644 --- a/Mage.Sets/src/mage/cards/c/CorrosiveGale.java +++ b/Mage.Sets/src/mage/cards/c/CorrosiveGale.java @@ -27,7 +27,7 @@ public final class CorrosiveGale extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G/P}"); - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filter)); } public CorrosiveGale(final CorrosiveGale card) { diff --git a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java index ac19501f19..c1965a1d60 100644 --- a/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java +++ b/Mage.Sets/src/mage/cards/c/CorrosiveOoze.java @@ -1,13 +1,5 @@ - package mage.cards.c; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -18,12 +10,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TurnPhase; -import mage.constants.WatcherScope; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.EquippedPredicate; import mage.game.Game; @@ -31,10 +18,12 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; import mage.watchers.Watcher; +import java.util.*; + /** - * * @author rscoates */ public final class CorrosiveOoze extends CardImpl { @@ -42,7 +31,7 @@ public final class CorrosiveOoze extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("equipped creature"); static { - filter.add(new EquippedPredicate()); + filter.add(EquippedPredicate.instance); } public CorrosiveOoze(UUID ownerId, CardSetInfo setInfo) { @@ -87,7 +76,7 @@ class CorrosiveOozeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - CorrosiveOozeCombatWatcher watcher = (CorrosiveOozeCombatWatcher) game.getState().getWatchers().get(CorrosiveOozeCombatWatcher.class.getSimpleName()); + CorrosiveOozeCombatWatcher watcher = game.getState().getWatcher(CorrosiveOozeCombatWatcher.class); if (controller != null && watcher != null) { MageObjectReference sourceMor = new MageObjectReference(source.getSourceObject(game), game); // get equipmentsToDestroy of creatres already left the battlefield @@ -129,21 +118,21 @@ class CorrosiveOozeEffect extends OneShotEffect { class CorrosiveOozeCombatWatcher extends Watcher { - public final HashMap> oozeBlocksOrBlocked = new HashMap<>(); - public final HashMap> oozeEquipmentsToDestroy = new HashMap<>(); + private final Map> oozeBlocksOrBlocked = new HashMap<>(); + private final Map> oozeEquipmentsToDestroy = new HashMap<>(); public CorrosiveOozeCombatWatcher() { - super(CorrosiveOozeCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CorrosiveOozeCombatWatcher(final CorrosiveOozeCombatWatcher watcher) { super(watcher); - for (Map.Entry> entry : watcher.oozeBlocksOrBlocked.entrySet()) { - HashSet newSet = new HashSet<>(entry.getValue()); + for (Map.Entry> entry : watcher.oozeBlocksOrBlocked.entrySet()) { + Set newSet = new HashSet<>(entry.getValue()); oozeBlocksOrBlocked.put(entry.getKey(), newSet); } - for (Map.Entry> entry : watcher.oozeEquipmentsToDestroy.entrySet()) { - HashSet newSet = new HashSet<>(entry.getValue()); + for (Map.Entry> entry : watcher.oozeEquipmentsToDestroy.entrySet()) { + Set newSet = new HashSet<>(entry.getValue()); oozeEquipmentsToDestroy.put(entry.getKey(), newSet); } } @@ -156,18 +145,18 @@ class CorrosiveOozeCombatWatcher extends Watcher { if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { Permanent attacker = game.getPermanent(event.getTargetId()); Permanent blocker = game.getPermanent(event.getSourceId()); - if (attacker != null && attacker.getName().equals("Corrosive Ooze")) { // To check for name is not working if Ooze is copied but name changed + if (attacker != null && CardUtil.haveSameNames(attacker.getName(), "Corrosive Ooze")) { // To check for name is not working if Ooze is copied but name changed if (blocker != null && hasAttachedEquipment(game, blocker)) { MageObjectReference oozeMor = new MageObjectReference(attacker, game); - HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); + Set relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); relatedCreatures.add(new MageObjectReference(event.getSourceId(), game)); oozeBlocksOrBlocked.put(oozeMor, relatedCreatures); } } - if (blocker != null && blocker.getName().equals("Corrosive Ooze")) { + if (blocker != null && CardUtil.haveSameNames(blocker.getName(), "Corrosive Ooze")) { if (attacker != null && hasAttachedEquipment(game, attacker)) { MageObjectReference oozeMor = new MageObjectReference(blocker, game); - HashSet relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); + Set relatedCreatures = oozeBlocksOrBlocked.getOrDefault(oozeMor, new HashSet<>()); relatedCreatures.add(new MageObjectReference(event.getTargetId(), game)); oozeBlocksOrBlocked.put(oozeMor, relatedCreatures); } @@ -178,14 +167,14 @@ class CorrosiveOozeCombatWatcher extends Watcher { if (((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { if (game.getTurn() != null && TurnPhase.COMBAT == game.getTurn().getPhaseType()) { // Check if a previous blocked or blocked by creatures is leaving the battlefield - for (Map.Entry> entry : oozeBlocksOrBlocked.entrySet()) { + for (Map.Entry> entry : oozeBlocksOrBlocked.entrySet()) { for (MageObjectReference mor : entry.getValue()) { if (mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { // check for equipments and remember for (UUID attachmentId : ((ZoneChangeEvent) event).getTarget().getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); if (attachment != null && attachment.hasSubtype(SubType.EQUIPMENT, game)) { - HashSet toDestroy = oozeEquipmentsToDestroy.getOrDefault(entry.getKey(), new HashSet<>()); + Set toDestroy = oozeEquipmentsToDestroy.getOrDefault(entry.getKey(), new HashSet<>()); toDestroy.add(new MageObjectReference(attachment, game)); oozeEquipmentsToDestroy.put(entry.getKey(), toDestroy); } diff --git a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java index b9b2f943eb..a6e289d8f4 100644 --- a/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java +++ b/Mage.Sets/src/mage/cards/c/CouncilOfTheAbsolute.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -19,8 +18,9 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CouncilOfTheAbsolute extends CardImpl { @@ -92,9 +92,8 @@ class CouncilOfTheAbsoluteReplacementEffect extends ContinuousRuleModifyingEffec public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); - if (object != null && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY))) { - return true; - } + String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + return object != null && CardUtil.haveSameNames(object.getName(), needName); } return false; } @@ -122,7 +121,10 @@ class CouncilOfTheAbsoluteCostReductionEffect extends CostModificationEffectImpl if ((abilityToModify instanceof SpellAbility) && abilityToModify.isControlledBy(source.getControllerId())) { Card card = game.getCard(abilityToModify.getSourceId()); - return card.getName().equals(game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY)); + if (card != null) { + String needName = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + return CardUtil.haveSameNames(card.getName(), needName); + } } return false; } diff --git a/Mage.Sets/src/mage/cards/c/CourageInCrisis.java b/Mage.Sets/src/mage/cards/c/CourageInCrisis.java new file mode 100644 index 0000000000..9b10852d11 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CourageInCrisis.java @@ -0,0 +1,35 @@ +package mage.cards.c; + +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CourageInCrisis extends CardImpl { + + public CourageInCrisis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); + + // Put a +1/+1 counter on target creature, then proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy(", then")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private CourageInCrisis(final CourageInCrisis card) { + super(card); + } + + @Override + public CourageInCrisis copy() { + return new CourageInCrisis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java b/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java index 4706b03adb..6c4fad4bf0 100644 --- a/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java +++ b/Mage.Sets/src/mage/cards/c/CourtStreetDenizen.java @@ -29,7 +29,7 @@ public final class CourtStreetDenizen extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another white creature"); private static final FilterCreaturePermanent filterOpponentCreature = new FilterCreaturePermanent("creature an opponent controls"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ColorPredicate(ObjectColor.WHITE)); filter.add(new ControllerPredicate(TargetController.YOU)); filterOpponentCreature.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/c/CoverOfWinter.java b/Mage.Sets/src/mage/cards/c/CoverOfWinter.java index 5497f041bb..7d9fdfa426 100644 --- a/Mage.Sets/src/mage/cards/c/CoverOfWinter.java +++ b/Mage.Sets/src/mage/cards/c/CoverOfWinter.java @@ -88,7 +88,7 @@ class CoverOfWinterEffect extends PreventionEffectImpl { if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null && permanent.getControllerId().equals(source.getControllerId())) { + if (permanent != null && permanent.isControlledBy(source.getControllerId())) { return super.applies(event, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CovetedJewel.java b/Mage.Sets/src/mage/cards/c/CovetedJewel.java index 01cf2199b5..0e068ed2a5 100644 --- a/Mage.Sets/src/mage/cards/c/CovetedJewel.java +++ b/Mage.Sets/src/mage/cards/c/CovetedJewel.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,20 +12,16 @@ import mage.abilities.effects.mana.AddManaOfAnyColorEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CovetedJewel extends CardImpl { @@ -130,7 +125,7 @@ class CovetedJewelControlEffect extends ContinuousEffectImpl { Player newControllingPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); if (permanent == null || newControllingPlayer == null || !newControllingPlayer.isInGame()) { this.discard(); - return true; + return false; } permanent.changeControllerId(getTargetPointer().getFirst(game, source), game); return true; diff --git a/Mage.Sets/src/mage/cards/c/CovetedPeacock.java b/Mage.Sets/src/mage/cards/c/CovetedPeacock.java index 9b748f4068..dbe7642a59 100644 --- a/Mage.Sets/src/mage/cards/c/CovetedPeacock.java +++ b/Mage.Sets/src/mage/cards/c/CovetedPeacock.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -11,18 +10,23 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.target.common.TargetCreaturePermanent; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class CovetedPeacock extends CardImpl { - private final UUID originalId; + public static final FilterPermanent filter = new FilterCreaturePermanent("creature defending player controls"); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } public CovetedPeacock(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); @@ -36,26 +40,12 @@ public final class CovetedPeacock extends CardImpl { // Whenever Coveted Peacock attacks, you may goad target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new GoadTargetEffect(), true, "Whenever {this} attacks, you may goad target creature defending player controls."); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); - originalId = ability.getOriginalId(); + ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } public CovetedPeacock(final CovetedPeacock card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); - filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - ability.addTarget(target); - } } @Override diff --git a/Mage.Sets/src/mage/cards/c/CrabUmbra.java b/Mage.Sets/src/mage/cards/c/CrabUmbra.java index 86f5d56cf7..da173d8340 100644 --- a/Mage.Sets/src/mage/cards/c/CrabUmbra.java +++ b/Mage.Sets/src/mage/cards/c/CrabUmbra.java @@ -2,6 +2,7 @@ package mage.cards.c; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -19,13 +20,12 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author Loki */ public final class CrabUmbra extends CardImpl { public CrabUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); this.subtype.add(SubType.AURA); @@ -35,8 +35,11 @@ public final class CrabUmbra extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // {2}{U}: Untap enchanted creature. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new UntapEnchantedEffect(), new ManaCostsImpl("{2}{U}"))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/c/CrabappleCohort.java b/Mage.Sets/src/mage/cards/c/CrabappleCohort.java index 3cc760d109..aa536b9724 100644 --- a/Mage.Sets/src/mage/cards/c/CrabappleCohort.java +++ b/Mage.Sets/src/mage/cards/c/CrabappleCohort.java @@ -33,7 +33,7 @@ public final class CrabappleCohort extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CrabappleCohort(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/Crackleburr.java b/Mage.Sets/src/mage/cards/c/Crackleburr.java index b958d20061..d970807b97 100644 --- a/Mage.Sets/src/mage/cards/c/Crackleburr.java +++ b/Mage.Sets/src/mage/cards/c/Crackleburr.java @@ -38,10 +38,10 @@ public final class Crackleburr extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter2.add(new ColorPredicate(ObjectColor.BLUE)); - filter2.add(new TappedPredicate()); + filter2.add(TappedPredicate.instance); } public Crackleburr(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CracklingPerimeter.java b/Mage.Sets/src/mage/cards/c/CracklingPerimeter.java index b2a49d8229..0c1e9fc08f 100644 --- a/Mage.Sets/src/mage/cards/c/CracklingPerimeter.java +++ b/Mage.Sets/src/mage/cards/c/CracklingPerimeter.java @@ -27,7 +27,7 @@ public final class CracklingPerimeter extends CardImpl { static { filter.add(new SubtypePredicate(SubType.GATE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public CracklingPerimeter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CrashingBoars.java b/Mage.Sets/src/mage/cards/c/CrashingBoars.java index 9e47943bd4..26678b713c 100644 --- a/Mage.Sets/src/mage/cards/c/CrashingBoars.java +++ b/Mage.Sets/src/mage/cards/c/CrashingBoars.java @@ -53,7 +53,7 @@ class CrashingBoarsEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } CrashingBoarsEffect() { diff --git a/Mage.Sets/src/mage/cards/c/CraterhoofBehemoth.java b/Mage.Sets/src/mage/cards/c/CraterhoofBehemoth.java index 516570b6a7..68aade0911 100644 --- a/Mage.Sets/src/mage/cards/c/CraterhoofBehemoth.java +++ b/Mage.Sets/src/mage/cards/c/CraterhoofBehemoth.java @@ -1,27 +1,26 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TargetController; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author North */ public final class CraterhoofBehemoth extends CardImpl { @@ -33,7 +32,7 @@ public final class CraterhoofBehemoth extends CardImpl { } public CraterhoofBehemoth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}{G}"); this.subtype.add(SubType.BEAST); this.power = new MageInt(5); @@ -43,8 +42,8 @@ public final class CraterhoofBehemoth extends CardImpl { // When Craterhoof Behemoth enters the battlefield, creatures you control gain trample and get +X/+X until end of turn, where X is the number of creatures you control. Ability ability = new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter)); - PermanentsOnBattlefieldCount controlledCreatures = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("the number of creatures you control"), null); - ability.addEffect(new BoostControlledEffect(controlledCreatures, controlledCreatures, Duration.EndOfTurn, filter, false, true)); + ability.addEffect(new BoostControlledEffect(CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, filter, false, true)); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CratersClaws.java b/Mage.Sets/src/mage/cards/c/CratersClaws.java index 7d212220f1..a4b2b4dbfb 100644 --- a/Mage.Sets/src/mage/cards/c/CratersClaws.java +++ b/Mage.Sets/src/mage/cards/c/CratersClaws.java @@ -1,19 +1,19 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class CratersClaws extends CardImpl { @@ -24,12 +24,13 @@ public final class CratersClaws extends CardImpl { // Crater's Claws deals X damage to any target. // Ferocious — Crater's Claws deals X plus 2 damage to that creature or player instead if you control a creature with power 4 or greater. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(new IntPlusDynamicValue(2, new ManacostVariableValue())), - new DamageTargetEffect(new ManacostVariableValue()), + new DamageTargetEffect(new IntPlusDynamicValue(2, ManacostVariableValue.instance)), + new DamageTargetEffect(ManacostVariableValue.instance), FerociousCondition.instance, "{this} deals X damage to any target." - + "
    Ferocious — {this} deals X plus 2 damage to that permanent or player instead if you control a creature with power 4 or greater")); + + "
    Ferocious — {this} deals X plus 2 damage to that permanent or player instead if you control a creature with power 4 or greater")); this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().addHint(FerociousHint.instance); } public CratersClaws(final CratersClaws card) { diff --git a/Mage.Sets/src/mage/cards/c/CrazedFirecat.java b/Mage.Sets/src/mage/cards/c/CrazedFirecat.java index fdc96f3f9a..a19b1e8233 100644 --- a/Mage.Sets/src/mage/cards/c/CrazedFirecat.java +++ b/Mage.Sets/src/mage/cards/c/CrazedFirecat.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -9,15 +8,16 @@ 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.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CrazedFirecat extends CardImpl { @@ -34,7 +34,7 @@ public final class CrazedFirecat extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new CrazedFirecatEffect(), false)); } - public CrazedFirecat(final CrazedFirecat card) { + private CrazedFirecat(final CrazedFirecat card) { super(card); } @@ -46,12 +46,12 @@ public final class CrazedFirecat extends CardImpl { class CrazedFirecatEffect extends OneShotEffect { - public CrazedFirecatEffect() { + CrazedFirecatEffect() { super(Outcome.Benefit); - this.staticText = "flip a coin until you lose a flip. Put a +1/+1 counter on {this} for each flip you win."; + this.staticText = "flip a coin until you lose a flip. Put a +1/+1 counter on {this} for each flip you won."; } - public CrazedFirecatEffect(final CrazedFirecatEffect effect) { + private CrazedFirecatEffect(final CrazedFirecatEffect effect) { super(effect); } @@ -66,7 +66,7 @@ class CrazedFirecatEffect extends OneShotEffect { Permanent sourceObject = game.getPermanent(source.getSourceId()); if (controller != null && sourceObject != null) { int flipsWon = 0; - while (controller.flipCoin(game)) { + while (controller.flipCoin(source, game, true)) { flipsWon++; } sourceObject.addCounters(CounterType.P1P1.createInstance(flipsWon), source, game); diff --git a/Mage.Sets/src/mage/cards/c/CreatureBond.java b/Mage.Sets/src/mage/cards/c/CreatureBond.java index a1a8463073..7a6fff4437 100644 --- a/Mage.Sets/src/mage/cards/c/CreatureBond.java +++ b/Mage.Sets/src/mage/cards/c/CreatureBond.java @@ -35,7 +35,7 @@ public final class CreatureBond extends CardImpl { this.addAbility(ability); // When enchanted creature dies, Creature Bond deals damage equal to that creature's toughness to the creature's controller. - this.addAbility( new DiesAttachedTriggeredAbility(new DamageAttachedControllerEffect(new AttachedPermanentToughnessValue()), "enchanted creature")); + this.addAbility( new DiesAttachedTriggeredAbility(new DamageAttachedControllerEffect(AttachedPermanentToughnessValue.instance), "enchanted creature")); } public CreatureBond(final CreatureBond card) { diff --git a/Mage.Sets/src/mage/cards/c/CreepingDread.java b/Mage.Sets/src/mage/cards/c/CreepingDread.java index 509cf4176d..c2b0e0e8a0 100644 --- a/Mage.Sets/src/mage/cards/c/CreepingDread.java +++ b/Mage.Sets/src/mage/cards/c/CreepingDread.java @@ -89,7 +89,7 @@ class CreepingDreadEffect extends OneShotEffect { for (UUID playerId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(playerId); // opponent discards a card - if it is same card type as controller, add to opponentsAffected - if(!opponent.getHand().isEmpty()) { + if(opponent != null && !opponent.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, new FilterCard()); if(opponent.choose(Outcome.Discard, opponent.getHand(), target, game)) { Card card = opponent.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/c/CreepyDoll.java b/Mage.Sets/src/mage/cards/c/CreepyDoll.java index ad0b08e099..71c3056523 100644 --- a/Mage.Sets/src/mage/cards/c/CreepyDoll.java +++ b/Mage.Sets/src/mage/cards/c/CreepyDoll.java @@ -100,7 +100,7 @@ class CreepyDollEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (player.flipCoin(game)) { + if (player.flipCoin(source, game, true)) { UUID targetId = getTargetPointer().getFirst(game, source); Permanent permanent = game.getPermanent(targetId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/c/Cremate.java b/Mage.Sets/src/mage/cards/c/Cremate.java index a5e061094a..62c465e34f 100644 --- a/Mage.Sets/src/mage/cards/c/Cremate.java +++ b/Mage.Sets/src/mage/cards/c/Cremate.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; @@ -9,17 +8,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class Cremate extends CardImpl { public Cremate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); + // Exile target card from a graveyard. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); + + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } diff --git a/Mage.Sets/src/mage/cards/c/CrimsonHellkite.java b/Mage.Sets/src/mage/cards/c/CrimsonHellkite.java index a929af7dfd..f9f867142d 100644 --- a/Mage.Sets/src/mage/cards/c/CrimsonHellkite.java +++ b/Mage.Sets/src/mage/cards/c/CrimsonHellkite.java @@ -43,7 +43,7 @@ public final class CrimsonHellkite extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // {X}, {tap}: Crimson Hellkite deals X damage to target creature. Spend only red mana on X. - Effect effect = new DamageTargetEffect(new ManacostVariableValue()); + Effect effect = new DamageTargetEffect(ManacostVariableValue.instance); effect.setText("{this} deals X damage to target creature. Spend only red mana on X"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/CrimsonHonorGuard.java b/Mage.Sets/src/mage/cards/c/CrimsonHonorGuard.java index 341e4494f5..4d8f96c8ab 100644 --- a/Mage.Sets/src/mage/cards/c/CrimsonHonorGuard.java +++ b/Mage.Sets/src/mage/cards/c/CrimsonHonorGuard.java @@ -53,10 +53,10 @@ public final class CrimsonHonorGuard extends CardImpl { class CrimsonHonorGuardEffect extends OneShotEffect { - private final static FilterPermanent filter = new FilterPermanent("Commander"); + private static final FilterPermanent filter = new FilterPermanent("Commander"); static { - filter.add(new CommanderPredicate()); + filter.add(CommanderPredicate.instance); } public CrimsonHonorGuardEffect() { diff --git a/Mage.Sets/src/mage/cards/c/CrookOfCondemnation.java b/Mage.Sets/src/mage/cards/c/CrookOfCondemnation.java index 71016541e7..8770fff76c 100644 --- a/Mage.Sets/src/mage/cards/c/CrookOfCondemnation.java +++ b/Mage.Sets/src/mage/cards/c/CrookOfCondemnation.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileSourceCost; @@ -15,29 +14,28 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CrookOfCondemnation extends CardImpl { - - private UUID exileId = UUID.randomUUID(); public CrookOfCondemnation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - + // {1}, {t}: Exile target card from a graveyard. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new ManaCostsImpl("{1}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCardInGraveyard()); this.addAbility(ability); - + // {1}, Exile Crook of Condemnation: Exile all cards from all graveyards. Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileGraveyardAllPlayersEffect(), new ManaCostsImpl("{1}")); ability2.addCost(new ExileSourceCost()); this.addAbility(ability2); - + } public CrookOfCondemnation(final CrookOfCondemnation card) { diff --git a/Mage.Sets/src/mage/cards/c/CrookclawElder.java b/Mage.Sets/src/mage/cards/c/CrookclawElder.java index a570f6c7f9..6b2a76e853 100644 --- a/Mage.Sets/src/mage/cards/c/CrookclawElder.java +++ b/Mage.Sets/src/mage/cards/c/CrookclawElder.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,28 +13,29 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class CrookclawElder extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Bird you control"); - private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("untapped Wizards you control"); + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent(SubType.BIRD, "untapped Birds you control"); + private static final FilterControlledCreaturePermanent filter2 + = new FilterControlledCreaturePermanent(SubType.WIZARD, "untapped Wizards you control"); + private static final Predicate pred = Predicates.not(TappedPredicate.instance); static { - filter.add(new SubtypePredicate(SubType.BIRD)); - filter.add(Predicates.not(new TappedPredicate())); - filter2.add(new SubtypePredicate(SubType.WIZARD)); - filter2.add(Predicates.not(new TappedPredicate())); + filter.add(pred); + filter2.add(pred); } public CrookclawElder(UUID ownerId, CardSetInfo setInfo) { @@ -50,16 +50,26 @@ public final class CrookclawElder extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Tap two untapped Birds you control: Draw a card. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter, true))); + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), + new TapTargetCost(new TargetControlledCreaturePermanent( + 2, 2, filter, true + )) + ); this.addAbility(ability); // Tap two untapped Wizards you control: Target creature gains flying until end of turn. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new TapTargetCost(new TargetControlledCreaturePermanent(2, 2, filter2, true))); + ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), + new TapTargetCost(new TargetControlledCreaturePermanent( + 2, 2, filter2, true + )) + ); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } - public CrookclawElder(final CrookclawElder card) { + private CrookclawElder(final CrookclawElder card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/c/CrookedScales.java b/Mage.Sets/src/mage/cards/c/CrookedScales.java index 6a0e880cf7..0b19ce0bc4 100644 --- a/Mage.Sets/src/mage/cards/c/CrookedScales.java +++ b/Mage.Sets/src/mage/cards/c/CrookedScales.java @@ -72,7 +72,7 @@ class CrookedScalesEffect extends OneShotEffect { Cost cost; String message = "You lost the flip. Pay {3} to prevent your creature from being destroyed?"; do { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { if (theirGuy != null) { theirGuy.destroy(controller.getId(), game, false); } diff --git a/Mage.Sets/src/mage/cards/c/CropSigil.java b/Mage.Sets/src/mage/cards/c/CropSigil.java index 134273c25d..4c95be8935 100644 --- a/Mage.Sets/src/mage/cards/c/CropSigil.java +++ b/Mage.Sets/src/mage/cards/c/CropSigil.java @@ -1,7 +1,7 @@ - package mage.cards.c; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.OnEventTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; @@ -10,6 +10,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -20,7 +21,6 @@ import mage.game.events.GameEvent; import mage.target.common.TargetCardInYourGraveyard; /** - * * @author fireshoes */ public final class CropSigil extends CardImpl { @@ -34,7 +34,7 @@ public final class CropSigil extends CardImpl { } public CropSigil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); // At the beginning of your upkeep, you may put the top card of your library into your graveyard. this.addAbility(new OnEventTriggeredAbility(GameEvent.EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new PutTopCardOfLibraryIntoGraveControllerEffect(1), true)); @@ -44,10 +44,11 @@ public final class CropSigil extends CardImpl { Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(true), new ManaCostsImpl<>("{2}{G}"), DeliriumCondition.instance, "Delirium — {2}{G}, Sacrifice {this}: Return up to one target creature card and up to one target land card from your graveyard to your hand. " - + "Activate this ability only if there are four or more card types among cards in your graveyard"); + + "Activate this ability only if there are four or more card types among cards in your graveyard"); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterCreature)); ability.addTarget(new TargetCardInYourGraveyard(0, 1, filterLand)); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CrosisThePurger.java b/Mage.Sets/src/mage/cards/c/CrosisThePurger.java index 7bd601aaa2..b2f87e2d6a 100644 --- a/Mage.Sets/src/mage/cards/c/CrosisThePurger.java +++ b/Mage.Sets/src/mage/cards/c/CrosisThePurger.java @@ -78,22 +78,24 @@ class CrosisThePurgerEffect extends OneShotEffect { ChoiceColor choice = new ChoiceColor(); player.choose(outcome, choice, game); if (choice.isChosen()) { - game.informPlayers(new StringBuilder(player.getLogName()).append(" chooses ").append(choice.getColor()).toString()); + game.informPlayers(player.getLogName() + " chooses " + choice.getColor()); Player damagedPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - damagedPlayer.revealCards("hand of " + damagedPlayer.getName(), damagedPlayer.getHand(), game); - FilterCard filter = new FilterCard(); - filter.add(new ColorPredicate(choice.getColor())); - List toDiscard = new ArrayList<>(); - for (UUID cardId : damagedPlayer.getHand()) { - Card card = game.getCard(cardId); - if (filter.match(card, game)) { - toDiscard.add(card); + if(damagedPlayer != null) { + damagedPlayer.revealCards("hand of " + damagedPlayer.getName(), damagedPlayer.getHand(), game); + FilterCard filter = new FilterCard(); + filter.add(new ColorPredicate(choice.getColor())); + List toDiscard = new ArrayList<>(); + for (UUID cardId : damagedPlayer.getHand()) { + Card card = game.getCard(cardId); + if (filter.match(card, game)) { + toDiscard.add(card); + } } + for (Card card : toDiscard) { + damagedPlayer.discard(card, source, game); + } + return true; } - for (Card card : toDiscard) { - damagedPlayer.discard(card, source, game); - } - return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/c/CrosissCharm.java b/Mage.Sets/src/mage/cards/c/CrosissCharm.java index 74d7286209..62734db832 100644 --- a/Mage.Sets/src/mage/cards/c/CrosissCharm.java +++ b/Mage.Sets/src/mage/cards/c/CrosissCharm.java @@ -37,14 +37,14 @@ public final class CrosissCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent()); // or destroy target nonblack creature, and it can't be regenerated; Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect(true)); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DestroyTargetEffect(true)); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); // or destroy target artifact. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); + mode.addEffect(new DestroyTargetEffect()); Target target = new TargetArtifactPermanent(); - mode.getTargets().add(target); + mode.addTarget(target); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CrossroadsConsecrator.java b/Mage.Sets/src/mage/cards/c/CrossroadsConsecrator.java index 0cfc1cde78..91088cacf8 100644 --- a/Mage.Sets/src/mage/cards/c/CrossroadsConsecrator.java +++ b/Mage.Sets/src/mage/cards/c/CrossroadsConsecrator.java @@ -24,7 +24,7 @@ import mage.target.common.TargetAttackingCreature; */ public final class CrossroadsConsecrator extends CardImpl { - private final static FilterAttackingCreature filter = new FilterAttackingCreature("attacking Human"); + private static final FilterAttackingCreature filter = new FilterAttackingCreature("attacking Human"); static { filter.add(new SubtypePredicate(SubType.HUMAN)); diff --git a/Mage.Sets/src/mage/cards/c/CrownHunterHireling.java b/Mage.Sets/src/mage/cards/c/CrownHunterHireling.java index 59dbb7d432..0c479bcf50 100644 --- a/Mage.Sets/src/mage/cards/c/CrownHunterHireling.java +++ b/Mage.Sets/src/mage/cards/c/CrownHunterHireling.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,14 +9,15 @@ import mage.abilities.effects.common.BecomesMonarchSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CrownHunterHireling extends CardImpl { @@ -65,7 +64,10 @@ class CrownHunterHirelingCantAttackEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } return defenderId.equals(game.getMonarchId()); } diff --git a/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java b/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java index 0aa256d117..c23faefedb 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfConvergence.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -20,11 +19,12 @@ import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * @author jeffwadsworth */ @@ -46,7 +46,7 @@ public final class CrownOfConvergence extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrownOfConvergenceEffect(), new ManaCostsImpl("{G}{W}"))); } - public CrownOfConvergence(final CrownOfConvergence card) { + private CrownOfConvergence(final CrownOfConvergence card) { super(card); } @@ -58,8 +58,6 @@ public final class CrownOfConvergence extends CardImpl { class CrownOfConvergenceColorBoostEffect extends BoostAllEffect { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); - private static final String effectText = "creatures you control that share a color with that card get +1/+1"; CrownOfConvergenceColorBoostEffect() { @@ -67,7 +65,7 @@ class CrownOfConvergenceColorBoostEffect extends BoostAllEffect { staticText = effectText; } - CrownOfConvergenceColorBoostEffect(CrownOfConvergenceColorBoostEffect effect) { + private CrownOfConvergenceColorBoostEffect(CrownOfConvergenceColorBoostEffect effect) { super(effect); } @@ -77,7 +75,7 @@ class CrownOfConvergenceColorBoostEffect extends BoostAllEffect { if (you != null) { Card topCard = you.getLibrary().getFromTop(game); if (topCard != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_CREATURE, source.getControllerId(), source.getSourceId(), game)) { if (permanent.getColor(game).shares(topCard.getColor(game)) && !permanent.getColor(game).isColorless()) { permanent.addPower(power.calculate(game, source, this)); permanent.addToughness(toughness.calculate(game, source, this)); @@ -97,12 +95,12 @@ class CrownOfConvergenceColorBoostEffect extends BoostAllEffect { class CrownOfConvergenceEffect extends OneShotEffect { - public CrownOfConvergenceEffect() { + CrownOfConvergenceEffect() { super(Outcome.Neutral); staticText = "Put the top card of your library on the bottom of your library"; } - public CrownOfConvergenceEffect(final CrownOfConvergenceEffect effect) { + private CrownOfConvergenceEffect(final CrownOfConvergenceEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java index c5765ad727..6adeceba04 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfDoom.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfDoom.java @@ -1,4 +1,3 @@ - package mage.cards.c; import java.util.Objects; @@ -44,11 +43,20 @@ public final class CrownOfDoom extends CardImpl { // Whenever a creature attacks you or a planeswalker you control, it gets +2/+0 until end of turn. Effect effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); effect.setText("it gets +2/+0 until end of turn"); - this.addAbility(new AttacksAllTriggeredAbility(effect, false, StaticFilters.FILTER_PERMANENT_CREATURE, SetTargetPointer.PERMANENT, true)); + this.addAbility(new AttacksAllTriggeredAbility( + effect, + false, + StaticFilters.FILTER_PERMANENT_CREATURE, + SetTargetPointer.PERMANENT, + true)); //TODO: Make ability properly copiable // {2}: Target player other than Crown of Doom's owner gains control of it. Activate this ability only during your turn. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new CrownOfDoomEffect(), new ManaCostsImpl("{2}"), MyTurnCondition.instance); + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, + new CrownOfDoomEffect(), + new ManaCostsImpl("{2}"), + MyTurnCondition.instance); ability.addTarget(new TargetPlayer(1, 1, false, filter)); this.addAbility(ability); } @@ -104,8 +112,9 @@ class CrownOfDoomEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player newController = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (controller != null && newController != null && !Objects.equals(controller.getId(), newController.getId())) { - // Duration.Custom = effect ends if Artifact leaves the current zone (battlefield) + if (controller != null + && newController != null + && !Objects.equals(controller.getId(), newController.getId())) { ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, newController.getId()); effect.setTargetPointer(new FixedTarget(source.getSourceId())); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java index 91c4c727e5..f5bfddfe29 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfEmpires.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.SimpleActivatedAbility; @@ -17,6 +15,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author nantuko @@ -24,7 +25,7 @@ import mage.target.targetpointer.FixedTarget; public final class CrownOfEmpires extends CardImpl { public CrownOfEmpires(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // {3}, {tap}: Tap target creature. Gain control of that creature instead if you control artifacts named Scepter of Empires and Throne of Empires. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CrownOfEmpiresEffect(), new GenericManaCost(3)); @@ -60,9 +61,9 @@ class CrownOfEmpiresEffect extends OneShotEffect { boolean scepter = false; boolean throne = false; for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.getName().equals("Scepter of Empires")) { + if (CardUtil.haveSameNames(permanent.getName(), "Scepter of Empires")) { scepter = true; - } else if (permanent.getName().equals("Throne of Empires")) { + } else if (CardUtil.haveSameNames(permanent.getName(), "Throne of Empires")) { throne = true; } if (scepter && throne) break; diff --git a/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java index 29fb1beecf..1fbe8b43e2 100644 --- a/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java +++ b/Mage.Sets/src/mage/cards/c/CrownOfTheAges.java @@ -2,6 +2,7 @@ package mage.cards.c; import java.util.UUID; + import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -27,7 +28,6 @@ import mage.target.Target; import mage.target.TargetPermanent; /** - * * @author spjspj */ public final class CrownOfTheAges extends CardImpl { @@ -107,7 +107,7 @@ class CrownOfTheAgesEffect extends OneShotEffect { } // Check for protection MageObject auraObject = game.getObject(aura.getId()); - if (creatureToAttachAura.cantBeAttachedBy(auraObject, game)) { + if (auraObject != null && creatureToAttachAura.cantBeAttachedBy(auraObject, game)) { passed = false; } } diff --git a/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java b/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java index 1eb974792d..0b8fe29b22 100644 --- a/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/c/CrucibleOfTheSpiritDragon.java @@ -44,7 +44,7 @@ public final class CrucibleOfTheSpiritDragon extends CardImpl { // {T}, Remove X storage counters from Crucible of the Spirit Dragon: Add X mana in any combination of colors. Spend this mana only to cast Dragon spells or activate abilities of Dragons. ability = new ConditionalAnyColorManaAbility( new TapSourceCost(), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new CrucibleOfTheSpiritDragonManaBuilder(), false ); diff --git a/Mage.Sets/src/mage/cards/c/CruelCelebrant.java b/Mage.Sets/src/mage/cards/c/CruelCelebrant.java new file mode 100644 index 0000000000..03d9815abf --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CruelCelebrant.java @@ -0,0 +1,52 @@ + +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author Ketsuban + */ +public final class CruelCelebrant extends CardImpl { + + private static final FilterCreatureOrPlaneswalkerPermanent filter = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public CruelCelebrant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever Cruel Celebrant or another creature or planeswalker you control dies, each opponent loses 1 life and you gain 1 life. + Ability ability = new DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(new LoseLifeOpponentsEffect(1), false, filter); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + + } + + public CruelCelebrant(final CruelCelebrant card) { + super(card); + } + + @Override + public CruelCelebrant copy() { + return new CruelCelebrant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CruelCut.java b/Mage.Sets/src/mage/cards/c/CruelCut.java new file mode 100644 index 0000000000..267732f89f --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CruelCut.java @@ -0,0 +1,42 @@ +package mage.cards.c; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ + +public final class CruelCut extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public CruelCut(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Destroy target creature with power 2 or less. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public CruelCut(final CruelCut card) { + super(card); + } + + @Override + public CruelCut copy() { + return new CruelCut(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CruelRevival.java b/Mage.Sets/src/mage/cards/c/CruelRevival.java index cfc5ba9049..47a862248d 100644 --- a/Mage.Sets/src/mage/cards/c/CruelRevival.java +++ b/Mage.Sets/src/mage/cards/c/CruelRevival.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -21,14 +19,15 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class CruelRevival extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Zombie creature"); - private final static FilterCard filter2 = new FilterCard("Zombie card from your graveyard"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Zombie creature"); + private static final FilterCard filter2 = new FilterCard("Zombie card from your graveyard"); static { filter.add(new CardTypePredicate(CardType.CREATURE)); @@ -37,7 +36,7 @@ public final class CruelRevival extends CardImpl { } public CruelRevival(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); // Destroy target non-Zombie creature. It can't be regenerated. Return up to one target Zombie card from your graveyard to your hand. @@ -70,10 +69,11 @@ class CruelRevivalEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent targetDestroy = game.getPermanent(source.getFirstTarget()); - Card targetRetrieve = game.getCard(source.getTargets().get(1).getFirstTarget()); if (targetDestroy != null) { targetDestroy.destroy(source.getSourceId(), game, true); } + + Card targetRetrieve = game.getCard(source.getTargets().get(1).getFirstTarget()); if (targetRetrieve != null) { targetRetrieve.moveToZone(Zone.HAND, source.getSourceId(), game, true); } diff --git a/Mage.Sets/src/mage/cards/c/CruelSadist.java b/Mage.Sets/src/mage/cards/c/CruelSadist.java index 3be03cd96e..63e7c85fac 100644 --- a/Mage.Sets/src/mage/cards/c/CruelSadist.java +++ b/Mage.Sets/src/mage/cards/c/CruelSadist.java @@ -44,7 +44,7 @@ public final class CruelSadist extends CardImpl { this.addAbility(ability); // {2}{B}, {T}, Remove X +1/+1 counters from Cruel Sadist: Cruel Sadist deals X damage to target creature. - Effect effect = new DamageTargetEffect(new RemovedCountersForCostValue()); + Effect effect = new DamageTargetEffect(RemovedCountersForCostValue.instance); effect.setText("{this} deals X damage to target creature"); ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{B}")); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java index f4df0d4223..490c2d4d4f 100644 --- a/Mage.Sets/src/mage/cards/c/CruelUltimatum.java +++ b/Mage.Sets/src/mage/cards/c/CruelUltimatum.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -21,8 +19,9 @@ import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author North */ public final class CruelUltimatum extends CardImpl { @@ -80,7 +79,8 @@ class CruelUltimatumEffect extends OneShotEffect { if (card == null) { return false; } - controller.moveCards(card, Zone.HAND, source, game); + + return controller.moveCards(card, Zone.HAND, source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java b/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java index aef90bc19d..178cef7c56 100644 --- a/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java +++ b/Mage.Sets/src/mage/cards/c/CrueltyOfTheSith.java @@ -38,15 +38,15 @@ public final class CrueltyOfTheSith extends CardImpl { // Target player sacrifices a creture. Mode mode = new Mode(); - mode.getEffects().add(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "Target player")); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "Target player")); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); // Cruelty of the Sith deals 3 damage to target player. That player discards a card. mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(3)); - mode.getEffects().add(new DiscardTargetEffect(1)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new DamageTargetEffect(3)); + mode.addEffect(new DiscardTargetEffect(1)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CrusaderOfOdric.java b/Mage.Sets/src/mage/cards/c/CrusaderOfOdric.java index 50aa3f3735..bab744a9a5 100644 --- a/Mage.Sets/src/mage/cards/c/CrusaderOfOdric.java +++ b/Mage.Sets/src/mage/cards/c/CrusaderOfOdric.java @@ -1,27 +1,26 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author Loki */ public final class CrusaderOfOdric extends CardImpl { public CrusaderOfOdric(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -29,7 +28,8 @@ public final class CrusaderOfOdric extends CardImpl { this.toughness = new MageInt(0); // Crusader of Odric's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); } public CrusaderOfOdric(final CrusaderOfOdric card) { diff --git a/Mage.Sets/src/mage/cards/c/CrushContraband.java b/Mage.Sets/src/mage/cards/c/CrushContraband.java index 6cbe26f8db..d24044a83c 100644 --- a/Mage.Sets/src/mage/cards/c/CrushContraband.java +++ b/Mage.Sets/src/mage/cards/c/CrushContraband.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; @@ -10,28 +8,28 @@ import mage.constants.CardType; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author Ryan-Saklad */ public final class CrushContraband extends CardImpl { public CrushContraband(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); // Choose one or both - Destroy target artifact; or Destroy target land. this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); Mode mode1 = new Mode(); - mode1.getTargets().add(new TargetEnchantmentPermanent()); - mode1.getEffects().add(new ExileTargetEffect()); + mode1.addEffect(new ExileTargetEffect()); + mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); - } public CrushContraband(final CrushContraband card) { diff --git a/Mage.Sets/src/mage/cards/c/CrushDissent.java b/Mage.Sets/src/mage/cards/c/CrushDissent.java new file mode 100644 index 0000000000..74afddc6bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CrushDissent.java @@ -0,0 +1,37 @@ +package mage.cards.c; + +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CrushDissent extends CardImpl { + + public CrushDissent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Counter target spell unless its controller pays {2}. + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); + this.getSpellAbility().addTarget(new TargetSpell()); + + // Amass 2. + this.getSpellAbility().addEffect(new AmassEffect(2)); + } + + private CrushDissent(final CrushDissent card) { + super(card); + } + + @Override + public CrushDissent copy() { + return new CrushDissent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java index 623d5007af..692f43ca97 100644 --- a/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java +++ b/Mage.Sets/src/mage/cards/c/CrushUnderfoot.java @@ -77,7 +77,7 @@ class CrushUnderfootEffect extends OneShotEffect { && controller.chooseTarget(outcome, target, source, game)) { Permanent giant = game.getPermanent(target.getFirstTarget()); if (giant != null) { - game.informPlayers(new StringBuilder("Crush Underfoot: Choosen Giant is").append(giant.getName()).toString()); + game.informPlayers("Crush Underfoot: Chosen Giant is " + giant.getName()); Permanent targetCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (targetCreature != null) { targetCreature.damage(giant.getPower().getValue(), source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java index 949a2f17bc..7038a6ef5c 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingCanopy.java +++ b/Mage.Sets/src/mage/cards/c/CrushingCanopy.java @@ -34,8 +34,8 @@ public final class CrushingCanopy extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect()); // * Destroy target enchantment. Mode mode = new Mode(); - mode.getTargets().add(new TargetEnchantmentPermanent()); - mode.getEffects().add(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); + mode.addEffect(new DestroyTargetEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CrushingVines.java b/Mage.Sets/src/mage/cards/c/CrushingVines.java index 1d8a37dc26..4401947c32 100644 --- a/Mage.Sets/src/mage/cards/c/CrushingVines.java +++ b/Mage.Sets/src/mage/cards/c/CrushingVines.java @@ -33,8 +33,8 @@ public final class CrushingVines extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addEffect(new DestroyTargetEffect()); Mode mode = new Mode(); - mode.getTargets().add(new TargetArtifactPermanent()); - mode.getEffects().add(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CruxOfFate.java b/Mage.Sets/src/mage/cards/c/CruxOfFate.java index 495f8fdb04..ff9fe2802f 100644 --- a/Mage.Sets/src/mage/cards/c/CruxOfFate.java +++ b/Mage.Sets/src/mage/cards/c/CruxOfFate.java @@ -32,7 +32,7 @@ public final class CruxOfFate extends CardImpl { this.getSpellAbility().addEffect(new DestroyAllEffect(new FilterCreaturePermanent(SubType.DRAGON, "Dragon creatures"))); // * Destroy all non-Dragon creatures. Mode mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(new FilterCreaturePermanent(filterNonDragon))); + mode.addEffect(new DestroyAllEffect(new FilterCreaturePermanent(filterNonDragon))); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java b/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java new file mode 100644 index 0000000000..f8a451c4f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CryOfTheCarnarium.java @@ -0,0 +1,125 @@ +package mage.cards.c; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.CardsPutIntoGraveyardWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CryOfTheCarnarium extends CardImpl { + + public CryOfTheCarnarium(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // All creatures get -2/-2 until end of turn. Exile all creature cards in all graveyards that were put there from the battlefield this turn. If a creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new BoostAllEffect(-2, -2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new CryOfTheCarnariumExileEffect()); + this.getSpellAbility().addEffect(new CryOfTheCarnariumReplacementEffect()); + this.getSpellAbility().addWatcher(new CardsPutIntoGraveyardWatcher()); + } + + private CryOfTheCarnarium(final CryOfTheCarnarium card) { + super(card); + } + + @Override + public CryOfTheCarnarium copy() { + return new CryOfTheCarnarium(this); + } +} + +class CryOfTheCarnariumExileEffect extends OneShotEffect { + + CryOfTheCarnariumExileEffect() { + super(Outcome.Benefit); + staticText = "Exile all creature cards in all graveyards that were put there from the battlefield this turn."; + } + + private CryOfTheCarnariumExileEffect(final CryOfTheCarnariumExileEffect effect) { + super(effect); + } + + @Override + public CryOfTheCarnariumExileEffect copy() { + return new CryOfTheCarnariumExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); + if (player == null || watcher == null) { + return false; + } + Cards cards = new CardsImpl(); + for (MageObjectReference mor : watcher.getCardsPutToGraveyardFromBattlefield()) { + if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { + Card card = mor.getCard(game); + if (card != null && card.isCreature()) { + cards.add(card); + } + } + } + player.moveCards(cards, Zone.EXILED, source, game); + return true; + } +} + +class CryOfTheCarnariumReplacementEffect extends ReplacementEffectImpl { + + CryOfTheCarnariumReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Exile); + staticText = " If a creature would die this turn, exile it instead."; + } + + private CryOfTheCarnariumReplacementEffect(final CryOfTheCarnariumReplacementEffect effect) { + super(effect); + } + + @Override + public CryOfTheCarnariumReplacementEffect copy() { + return new CryOfTheCarnariumReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + return player.moveCards(permanent, Zone.EXILED, source, game); + } + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getTarget() != null + && zEvent.getTarget().isCreature() + && zEvent.isDiesEvent(); + } + +} diff --git a/Mage.Sets/src/mage/cards/c/CryptOfTheEternals.java b/Mage.Sets/src/mage/cards/c/CryptOfTheEternals.java index 05433c0e5f..6c49acb28b 100644 --- a/Mage.Sets/src/mage/cards/c/CryptOfTheEternals.java +++ b/Mage.Sets/src/mage/cards/c/CryptOfTheEternals.java @@ -13,6 +13,7 @@ import mage.constants.CardType; import mage.constants.Zone; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.UUID; @@ -23,18 +24,15 @@ public final class CryptOfTheEternals extends CardImpl { // When Crypt of the Eternals enters the battlefield, you gain 1 life. this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(1))); - + // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); // {1}, {T}: Add {U}, {B}, or {R}. - List list = new ArrayList() {{ - add(Mana.BlueMana(1)); - add(Mana.BlackMana(1)); - add(Mana.RedMana(1)); - }}; - - for(Mana m: list) { + List list = new ArrayList<>(Arrays.asList(Mana.BlueMana(1), Mana.BlackMana(1), Mana.RedMana(1))); + + + for (Mana m : list) { SimpleManaAbility uAbility = new SimpleManaAbility(Zone.BATTLEFIELD, m, new ManaCostsImpl("{1}")); uAbility.addCost(new TapSourceCost()); this.addAbility(uAbility); diff --git a/Mage.Sets/src/mage/cards/c/CryptRats.java b/Mage.Sets/src/mage/cards/c/CryptRats.java index f19332295b..d5dfc11893 100644 --- a/Mage.Sets/src/mage/cards/c/CryptRats.java +++ b/Mage.Sets/src/mage/cards/c/CryptRats.java @@ -38,7 +38,7 @@ public final class CryptRats extends CardImpl { this.toughness = new MageInt(1); // {X}: Crypt Rats deals X damage to each creature and each player. Spend only black mana on X. - Effect effect = new DamageEverythingEffect(new ManacostVariableValue()); + Effect effect = new DamageEverythingEffect(ManacostVariableValue.instance); effect.setText("{this} deals X damage to each creature and each player. Spend only black mana on X"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect,new ManaCostsImpl("{X}")); VariableCost variableCost = ability.getManaCostsToPay().getVariableCosts().get(0); diff --git a/Mage.Sets/src/mage/cards/c/CryptbornHorror.java b/Mage.Sets/src/mage/cards/c/CryptbornHorror.java index 9328ab0493..16d72c1098 100644 --- a/Mage.Sets/src/mage/cards/c/CryptbornHorror.java +++ b/Mage.Sets/src/mage/cards/c/CryptbornHorror.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -11,14 +9,15 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class CryptbornHorror extends CardImpl { @@ -26,7 +25,7 @@ public final class CryptbornHorror extends CardImpl { private static final String rule = "with X +1/+1 counters on it, where X is the total life lost by your opponents this turn"; public CryptbornHorror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B/R}{B/R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B/R}{B/R}"); this.subtype.add(SubType.HORROR); this.color.setBlack(true); this.color.setRed(true); @@ -64,7 +63,7 @@ class CryptbornHorrorEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { - int oll = new OpponentsLostLifeCount().calculate(game, source, this); + int oll = OpponentsLostLifeCount.instance.calculate(game, source, this); if (oll > 0) { permanent.addCounters(CounterType.P1P1.createInstance(oll), source, game); } diff --git a/Mage.Sets/src/mage/cards/c/Cryptbreaker.java b/Mage.Sets/src/mage/cards/c/Cryptbreaker.java index 446fe224f6..71255d8709 100644 --- a/Mage.Sets/src/mage/cards/c/Cryptbreaker.java +++ b/Mage.Sets/src/mage/cards/c/Cryptbreaker.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -25,8 +23,9 @@ import mage.filter.predicate.permanent.TappedPredicate; import mage.game.permanent.token.ZombieToken; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Cryptbreaker extends CardImpl { @@ -34,12 +33,12 @@ public final class Cryptbreaker extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Zombies you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.ZOMBIE)); } public Cryptbreaker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -51,12 +50,10 @@ public final class Cryptbreaker extends CardImpl { this.addAbility(ability); // Tap three untapped Zombies you control: You draw a card and you lose 1 life. - Effect effect = new DrawCardSourceControllerEffect(1); - effect.setText("You draw a card"); + Effect effect = new DrawCardSourceControllerEffect(1, "you"); ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapTargetCost(new TargetControlledCreaturePermanent(3, 3, filter, true))); effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability.addEffect(effect); + ability.addEffect(effect.concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/c/CrypticCommand.java b/Mage.Sets/src/mage/cards/c/CrypticCommand.java index 1d8ee21d14..445a6cfbe8 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticCommand.java +++ b/Mage.Sets/src/mage/cards/c/CrypticCommand.java @@ -39,16 +39,16 @@ public final class CrypticCommand extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); // or return target permanent to its owner's hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetPermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetPermanent()); this.getSpellAbility().getModes().addMode(mode); // or tap all creatures your opponents control; mode = new Mode(); - mode.getEffects().add(new CrypticCommandEffect()); + mode.addEffect(new CrypticCommandEffect()); this.getSpellAbility().getModes().addMode(mode); // or draw a card. mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(1)); + mode.addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/c/CrypticGateway.java b/Mage.Sets/src/mage/cards/c/CrypticGateway.java index def2b7f770..ea840305cf 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticGateway.java +++ b/Mage.Sets/src/mage/cards/c/CrypticGateway.java @@ -39,7 +39,7 @@ public final class CrypticGateway extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } TargetControlledPermanent target; @@ -70,7 +70,7 @@ class CrypticGatewayCost extends CostImpl { TargetControlledPermanent target; static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public CrypticGatewayCost(TargetControlledPermanent target) { @@ -87,7 +87,7 @@ class CrypticGatewayCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int numTargets = 0; while (numTargets < 2 && target.choose(Outcome.Tap, controllerId, sourceId, game)) { - for (UUID targetId : (List) target.getTargets()) { + for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) { return false; @@ -146,7 +146,6 @@ class CrypticGatewayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); if (source.getCosts() == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CrypticSerpent.java b/Mage.Sets/src/mage/cards/c/CrypticSerpent.java index c7e91127ba..fb28357301 100644 --- a/Mage.Sets/src/mage/cards/c/CrypticSerpent.java +++ b/Mage.Sets/src/mage/cards/c/CrypticSerpent.java @@ -1,23 +1,28 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGraveyardEffect; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterInstantOrSorceryCard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class CrypticSerpent extends CardImpl { + private static final DynamicValue cardsCount = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); + public CrypticSerpent(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); @@ -26,7 +31,8 @@ public final class CrypticSerpent extends CardImpl { this.toughness = new MageInt(5); // Cryptic Serpent costs {1} less to cast for each instant and sorcery card in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(new FilterInstantOrSorceryCard()))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SourceCostReductionForEachCardInGraveyardEffect(new FilterInstantOrSorceryCard())) + .addHint(new ValueHint("Instant and sorcery card in your graveyard", cardsCount))); } public CrypticSerpent(final CrypticSerpent card) { diff --git a/Mage.Sets/src/mage/cards/c/Cryptoplasm.java b/Mage.Sets/src/mage/cards/c/Cryptoplasm.java index ac76c4b339..3b159867ea 100644 --- a/Mage.Sets/src/mage/cards/c/Cryptoplasm.java +++ b/Mage.Sets/src/mage/cards/c/Cryptoplasm.java @@ -25,10 +25,10 @@ import mage.util.functions.ApplyToPermanent; */ public final class Cryptoplasm extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Cryptoplasm(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CultGuildmage.java b/Mage.Sets/src/mage/cards/c/CultGuildmage.java new file mode 100644 index 0000000000..7fa8895aae --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CultGuildmage.java @@ -0,0 +1,54 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.TargetPlayer; +import mage.target.common.TargetOpponentOrPlaneswalker; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class CultGuildmage extends CardImpl { + + public CultGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {3}{B}, {T}: Target player discards a card. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new ManaCostsImpl("{3}{B}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // {R}, {T}: Cult Guildmage deals 1 damage to target opponent or planeswalker. + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + public CultGuildmage(final CultGuildmage card) { + super(card); + } + + @Override + public CultGuildmage copy() { + return new CultGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java b/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java index eb94342220..da9dab039a 100644 --- a/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java +++ b/Mage.Sets/src/mage/cards/c/CultOfTheWaxingMoon.java @@ -47,7 +47,7 @@ public final class CultOfTheWaxingMoon extends CardImpl { class CultOfTheWaxingMoonAbility extends TriggeredAbilityImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { filter.add(Predicates.not(new SubtypePredicate(SubType.HUMAN))); diff --git a/Mage.Sets/src/mage/cards/c/Cultivate.java b/Mage.Sets/src/mage/cards/c/Cultivate.java index 1905336011..26e42118d3 100644 --- a/Mage.Sets/src/mage/cards/c/Cultivate.java +++ b/Mage.Sets/src/mage/cards/c/Cultivate.java @@ -67,7 +67,7 @@ class CultivateEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), revealed, game); diff --git a/Mage.Sets/src/mage/cards/c/CultivatorDrone.java b/Mage.Sets/src/mage/cards/c/CultivatorDrone.java index 6c86c44454..9dc80b5310 100644 --- a/Mage.Sets/src/mage/cards/c/CultivatorDrone.java +++ b/Mage.Sets/src/mage/cards/c/CultivatorDrone.java @@ -92,7 +92,7 @@ class CultivatorDroneManaCondition extends ManaCondition implements Condition { } } if (costToPay instanceof ManaCost) { - return ((ManaCost) costToPay).getText().contains("{C}"); + return costToPay.getText().contains("{C}"); } return false; } diff --git a/Mage.Sets/src/mage/cards/c/Cunning.java b/Mage.Sets/src/mage/cards/c/Cunning.java new file mode 100644 index 0000000000..505c10898a --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/Cunning.java @@ -0,0 +1,89 @@ +package mage.cards.c; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.AttacksOrBlocksEnchantedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextCleanupDelayedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public final class Cunning extends CardImpl { + + public Cunning(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +3/+3. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3))); + + // When enchanted creature attacks or blocks, sacrifice Cunning at the beginning of the next cleanup step. + this.addAbility(new AttacksOrBlocksEnchantedTriggeredAbility(Zone.BATTLEFIELD, + new SacrificeSourceBeginningCleanupStepEffect())); + } + + public Cunning(final Cunning card) { + super(card); + } + + @Override + public Cunning copy() { + return new Cunning(this); + } +} + +class SacrificeSourceBeginningCleanupStepEffect extends OneShotEffect { + + public SacrificeSourceBeginningCleanupStepEffect() { + super(Outcome.Sacrifice); + this.staticText = "sacrifice {this} at the beginning of the next cleanup step"; + } + + public SacrificeSourceBeginningCleanupStepEffect(final SacrificeSourceBeginningCleanupStepEffect effect) { + super(effect); + } + + @Override + public SacrificeSourceBeginningCleanupStepEffect copy() { + return new SacrificeSourceBeginningCleanupStepEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent cunning = game.getPermanent(source.getSourceId()); + if (cunning != null) { + DelayedTriggeredAbility delayedAbility + = new AtTheBeginOfNextCleanupDelayedTriggeredAbility( + new SacrificeSourceEffect()); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/c/CunningAbduction.java b/Mage.Sets/src/mage/cards/c/CunningAbduction.java index f34a14e72c..48553cd2ea 100644 --- a/Mage.Sets/src/mage/cards/c/CunningAbduction.java +++ b/Mage.Sets/src/mage/cards/c/CunningAbduction.java @@ -122,16 +122,15 @@ class CunningAbductionSpendAnyManaEffect extends AsThoughEffectImpl implements A @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted this.discard(); diff --git a/Mage.Sets/src/mage/cards/c/CuombajjWitches.java b/Mage.Sets/src/mage/cards/c/CuombajjWitches.java index 2bb7d7a777..5d58744bdb 100644 --- a/Mage.Sets/src/mage/cards/c/CuombajjWitches.java +++ b/Mage.Sets/src/mage/cards/c/CuombajjWitches.java @@ -1,7 +1,6 @@ package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,68 +10,42 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetOpponent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox - */ public final class CuombajjWitches extends CardImpl { - private final UUID originalId; - public CuombajjWitches(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(3); - //TODO: Make ability properly copiable // {T}: Cuombajj Witches deals 1 damage to any target and 1 damage to any target of an opponent's choice. Effect effect = new DamageTargetEffect(1); effect.setText("{this} deals 1 damage to any target and 1 damage to any target of an opponent's choice"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); ability.addTarget(new TargetAnyTarget()); + ability.setTargetAdjuster(CuombajjWitchesAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - Player controller = game.getPlayer(ability.getControllerId()); - if(controller != null) { - UUID opponentId = null; - if(game.getOpponents(controller.getId()).size() > 1) { - Target target = new TargetOpponent(true); - if(controller.chooseTarget(Outcome.Neutral, target, ability, game)) { - opponentId = target.getFirstTarget(); - } - } - else { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } - - if(opponentId != null) { - ability.getTargets().get(1).setTargetController(opponentId); - } - } - } } public CuombajjWitches(final CuombajjWitches card) { super(card); - this.originalId = card.originalId; } @Override @@ -80,3 +53,26 @@ public final class CuombajjWitches extends CardImpl { return new CuombajjWitches(this); } } + +enum CuombajjWitchesAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + UUID opponentId = null; + if (game.getOpponents(controller.getId()).size() > 1) { + Target target = new TargetOpponent(true); + if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) { + opponentId = target.getFirstTarget(); + } + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + if (opponentId != null) { + ability.getTargets().get(1).setTargetController(opponentId); + } + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/c/CurseOfBounty.java b/Mage.Sets/src/mage/cards/c/CurseOfBounty.java index 8e9695f276..4c853ed281 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfBounty.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfBounty.java @@ -75,7 +75,7 @@ class CurseOfBountyEffect extends OneShotEffect { if (enchantment != null) { Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); if (enchantedPlayer != null) { - Set players = new HashSet(); + Set players = new HashSet<>(); for (UUID attacker : game.getCombat().getAttackers()) { UUID defender = game.getCombat().getDefenderId(attacker); if (defender.equals(enchantedPlayer.getId()) diff --git a/Mage.Sets/src/mage/cards/c/CurseOfChaos.java b/Mage.Sets/src/mage/cards/c/CurseOfChaos.java index 4b5e917876..53b0c265ac 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfChaos.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfChaos.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.abilities.Ability; @@ -24,13 +23,12 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author LevelX2 */ public final class CurseOfChaos extends CardImpl { public CurseOfChaos(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); this.subtype.add(SubType.AURA, SubType.CURSE); @@ -74,9 +72,9 @@ class CurseOfChaosTriggeredAbility extends TriggeredAbilityImpl { Permanent enchantment = game.getPermanent(this.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null - && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { - for (Effect effect: this.getEffects()) { - effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId())); + && game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId())); } return true; } @@ -85,7 +83,7 @@ class CurseOfChaosTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever a player attacks enchanted player with one or more creatures, ").append(super.getRule()).toString(); + return "Whenever a player attacks enchanted player with one or more creatures, " + super.getRule(); } @Override @@ -115,7 +113,7 @@ class CurseOfChaosEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player attacker = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (attacker != null) { - if (!attacker.getHand().isEmpty() && attacker.chooseUse(outcome, "Discard a card and draw a card?", source, game)){ + if (!attacker.getHand().isEmpty() && attacker.chooseUse(outcome, "Discard a card and draw a card?", source, game)) { attacker.discard(1, false, source, game); attacker.drawCards(1, game); } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfDisturbance.java b/Mage.Sets/src/mage/cards/c/CurseOfDisturbance.java index 6d5a725461..27ec138424 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfDisturbance.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfDisturbance.java @@ -76,7 +76,7 @@ class CurseOfDisturbanceEffect extends OneShotEffect { if (enchantment != null) { Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); if (enchantedPlayer != null) { - Set players = new HashSet(); + Set players = new HashSet<>(); for (UUID attacker : game.getCombat().getAttackers()) { UUID defender = game.getCombat().getDefenderId(attacker); if (defender.equals(enchantedPlayer.getId()) diff --git a/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java b/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java index fc85728ff2..ff670fab1a 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfEchoes.java @@ -121,9 +121,9 @@ class CurseOfEchoesEffect extends OneShotEffect { if (spell != null) { String chooseMessage = "Copy target spell? You may choose new targets for the copy."; for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { - if (!playerId.equals(spell.getControllerId())) { + if (!spell.isControlledBy(playerId)) { Player player = game.getPlayer(playerId); - if (player.chooseUse(Outcome.Copy, chooseMessage, source, game)) { + if (player != null && player.chooseUse(Outcome.Copy, chooseMessage, source, game)) { spell.createCopyOnStack(game, source, player.getId(), true); } } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfExhaustion.java b/Mage.Sets/src/mage/cards/c/CurseOfExhaustion.java index d08a2bb66f..ea636fef2a 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfExhaustion.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfExhaustion.java @@ -77,7 +77,7 @@ class CurseOfExhaustionEffect extends ContinuousRuleModifyingEffectImpl { if (enchantment != null && enchantment.getAttachedTo() != null) { Player player = game.getPlayer(enchantment.getAttachedTo()); if (player != null && event.getPlayerId().equals(player.getId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0) { return true; } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfInertia.java b/Mage.Sets/src/mage/cards/c/CurseOfInertia.java index 57923e5031..06ccfc4813 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfInertia.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfInertia.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.abilities.Ability; @@ -23,13 +22,12 @@ import mage.target.TargetPlayer; import java.util.UUID; /** - * * @author LevelX2 */ public final class CurseOfInertia extends CardImpl { public CurseOfInertia(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.subtype.add(SubType.AURA, SubType.CURSE); @@ -59,7 +57,7 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl { public CurseOfInertiaTriggeredAbility() { super(Zone.BATTLEFIELD, new CurseOfInertiaTapOrUntapTargetEffect(), false); } - + public CurseOfInertiaTriggeredAbility(final CurseOfInertiaTriggeredAbility ability) { super(ability); } @@ -74,7 +72,7 @@ class CurseOfInertiaTriggeredAbility extends TriggeredAbilityImpl { Permanent enchantment = game.getPermanent(this.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null - && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { + && game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) { TargetPermanent target = new TargetPermanent(); target.setTargetController(game.getCombat().getAttackingPlayerId()); addTarget(target); diff --git a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java index 2e781e9c55..1fa8220d2f 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfMisfortunes.java @@ -87,7 +87,7 @@ class CurseOfMisfortunesEffect extends OneShotEffect { } } TargetCardInLibrary targetCard = new TargetCardInLibrary(filter); - if (player.searchLibrary(targetCard, game)) { + if (player.searchLibrary(targetCard, source, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { this.setTargetPointer(new FixedTarget(targetPlayer.getId())); diff --git a/Mage.Sets/src/mage/cards/c/CurseOfShallowGraves.java b/Mage.Sets/src/mage/cards/c/CurseOfShallowGraves.java index a12717fa74..d83d76ef44 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfShallowGraves.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfShallowGraves.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.abilities.Ability; @@ -27,7 +26,6 @@ import mage.target.targetpointer.FixedTarget; import java.util.UUID; /** - * * @author LevelX2 */ public final class CurseOfShallowGraves extends CardImpl { @@ -80,7 +78,7 @@ class CurseOfShallowTriggeredAbility extends TriggeredAbilityImpl { Permanent enchantment = game.getPermanent(this.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null - && game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo())) { + && game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo())) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(game.getCombat().getAttackingPlayerId())); } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheSwine.java b/Mage.Sets/src/mage/cards/c/CurseOfTheSwine.java index cc40d56084..6332c7987e 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheSwine.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheSwine.java @@ -1,15 +1,10 @@ package mage.cards.c; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -18,9 +13,13 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.CurseOfTheSwineBoarToken; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; /** - * * @author LevelX2 */ public final class CurseOfTheSwine extends CardImpl { @@ -31,15 +30,7 @@ public final class CurseOfTheSwine extends CardImpl { // Exile X target creatures. For each creature exiled this way, its controller creates a 2/2 green Boar creature token. this.getSpellAbility().addEffect(new CurseOfTheSwineEffect()); // Correct number of targets will be set in adjustTargets - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility && ability.getAbilityType() == AbilityType.SPELL) { - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); - } + this.getSpellAbility().setTargetAdjuster(CurseOfTheSwineAdjuster.instance); } public CurseOfTheSwine(final CurseOfTheSwine card) { @@ -52,6 +43,16 @@ public final class CurseOfTheSwine extends CardImpl { } } +enum CurseOfTheSwineAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} + class CurseOfTheSwineEffect extends OneShotEffect { public CurseOfTheSwineEffect() { @@ -82,8 +83,8 @@ class CurseOfTheSwineEffect extends OneShotEffect { } } CurseOfTheSwineBoarToken swineToken = new CurseOfTheSwineBoarToken(); - for (UUID playerId : playersWithTargets.keySet()) { - swineToken.putOntoBattlefield(playersWithTargets.get(playerId), game, source.getSourceId(), playerId); + for (Map.Entry exiledByController : playersWithTargets.entrySet()) { + swineToken.putOntoBattlefield(exiledByController.getValue(), game, source.getSourceId(), exiledByController.getKey()); } return true; } diff --git a/Mage.Sets/src/mage/cards/c/CurseOfVengeance.java b/Mage.Sets/src/mage/cards/c/CurseOfVengeance.java index 3fb01a3559..318a99d37e 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfVengeance.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfVengeance.java @@ -153,7 +153,7 @@ class CurseOfVengeanceDrawLifeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Permanent sourceObject = (Permanent) game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourceObject != null && controller != null) { if (sourceObject.getCounters(game).containsKey(CounterType.SPITE)) { controller.drawCards(sourceObject.getCounters(game).getCount(CounterType.SPITE), game); diff --git a/Mage.Sets/src/mage/cards/c/CurseOfVerbosity.java b/Mage.Sets/src/mage/cards/c/CurseOfVerbosity.java index 7363a7eef2..3b073b8073 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfVerbosity.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfVerbosity.java @@ -74,7 +74,7 @@ class CurseOfVerbosityEffect extends OneShotEffect { if (enchantment != null) { Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); if (enchantedPlayer != null) { - Set players = new HashSet(); + Set players = new HashSet<>(); for (UUID attacker : game.getCombat().getAttackers()) { UUID defender = game.getCombat().getDefenderId(attacker); if (defender.equals(enchantedPlayer.getId()) diff --git a/Mage.Sets/src/mage/cards/c/CurseOfVitality.java b/Mage.Sets/src/mage/cards/c/CurseOfVitality.java index 63768fe867..2e81c314ac 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfVitality.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfVitality.java @@ -74,7 +74,7 @@ class CurseOfVitalityEffect extends OneShotEffect { if (enchantment != null) { Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); if (enchantedPlayer != null) { - Set players = new HashSet(); + Set players = new HashSet<>(); for (UUID attacker : game.getCombat().getAttackers()) { UUID defender = game.getCombat().getDefenderId(attacker); if (defender.equals(enchantedPlayer.getId()) diff --git a/Mage.Sets/src/mage/cards/c/CursedScroll.java b/Mage.Sets/src/mage/cards/c/CursedScroll.java index 0278616567..e0ec2592d7 100644 --- a/Mage.Sets/src/mage/cards/c/CursedScroll.java +++ b/Mage.Sets/src/mage/cards/c/CursedScroll.java @@ -1,6 +1,5 @@ package mage.cards.c; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -16,11 +15,12 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth - * */ public final class CursedScroll extends CardImpl { @@ -70,7 +70,7 @@ class CursedScrollEffect extends OneShotEffect { } revealed.add(card); controller.revealCards(sourceObject.getIdName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null) { creature.damage(2, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/c/CursedTotem.java b/Mage.Sets/src/mage/cards/c/CursedTotem.java index 5237df02a0..b10fec6e2c 100644 --- a/Mage.Sets/src/mage/cards/c/CursedTotem.java +++ b/Mage.Sets/src/mage/cards/c/CursedTotem.java @@ -1,7 +1,5 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -13,14 +11,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class CursedTotem extends CardImpl { public CursedTotem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Activated abilities of creatures can't be activated. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CursedTotemCantActivateEffect())); @@ -53,7 +52,7 @@ class CursedTotemCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/c/CurtainOfLight.java b/Mage.Sets/src/mage/cards/c/CurtainOfLight.java index c96889ff7a..5f1e7056ef 100644 --- a/Mage.Sets/src/mage/cards/c/CurtainOfLight.java +++ b/Mage.Sets/src/mage/cards/c/CurtainOfLight.java @@ -31,8 +31,8 @@ public final class CurtainOfLight extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature"); static { - filter.add(new AttackingPredicate()); - filter.add(Predicates.not(new BlockedPredicate())); + filter.add(AttackingPredicate.instance); + filter.add(Predicates.not(BlockedPredicate.instance)); } public CurtainOfLight(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CustodiSoulbinders.java b/Mage.Sets/src/mage/cards/c/CustodiSoulbinders.java index 2653f5d1f3..ab23d88f7d 100644 --- a/Mage.Sets/src/mage/cards/c/CustodiSoulbinders.java +++ b/Mage.Sets/src/mage/cards/c/CustodiSoulbinders.java @@ -29,7 +29,7 @@ public final class CustodiSoulbinders extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public CustodiSoulbinders(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java b/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java index ae27d4bdda..b8950d773c 100644 --- a/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java +++ b/Mage.Sets/src/mage/cards/c/CustodiSoulcaller.java @@ -1,10 +1,6 @@ package mage.cards.c; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -12,7 +8,10 @@ import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffec import mage.abilities.keyword.MeleeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.WatcherScope; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.Predicates; @@ -23,16 +22,18 @@ import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.watchers.Watcher; +import java.util.*; + /** - * * @author L_J */ public final class CustodiSoulcaller extends CardImpl { public CustodiSoulcaller(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); @@ -45,25 +46,10 @@ public final class CustodiSoulcaller extends CardImpl { Ability ability = new AttacksTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false); ability.addWatcher(new CustodiSoulcallerWatcher()); ability.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard, where X is the number of players you attacked with a creature this combat"))); + ability.setTargetAdjuster(CustodiSoulcallerAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getClass().equals(AttacksTriggeredAbility.class)) { - ability.getTargets().clear(); - CustodiSoulcallerWatcher watcher = (CustodiSoulcallerWatcher) game.getState().getWatchers().get(CustodiSoulcallerWatcher.class.getSimpleName()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); - if (watcher != null && watcher.playersAttacked != null) { - int xValue = watcher.getNumberOfAttackedPlayers(sourcePermanent.getControllerId()); - FilterCard filter = new FilterCard("creature card with converted mana cost " + xValue + " or less"); - filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(Predicates.or(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue), new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue))); - ability.getTargets().add(new TargetCardInYourGraveyard(filter)); - } - } - } - public CustodiSoulcaller(final CustodiSoulcaller card) { super(card); } @@ -74,12 +60,30 @@ public final class CustodiSoulcaller extends CardImpl { } } +enum CustodiSoulcallerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + CustodiSoulcallerWatcher watcher = game.getState().getWatcher(CustodiSoulcallerWatcher.class); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); + if (watcher != null) { + int xValue = watcher.getNumberOfAttackedPlayers(sourcePermanent.getControllerId()); + FilterCard filter = new FilterCard("creature card with converted mana cost " + xValue + " or less"); + filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(Predicates.or(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue), new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue))); + ability.getTargets().add(new TargetCardInYourGraveyard(filter)); + } + } +} + class CustodiSoulcallerWatcher extends Watcher { - protected final HashMap> playersAttacked = new HashMap<>(0); + private final Map> playersAttacked = new HashMap<>(0); CustodiSoulcallerWatcher() { - super("CustodiSoulcallerWatcher", WatcherScope.GAME); + super(WatcherScope.GAME); } CustodiSoulcallerWatcher(final CustodiSoulcallerWatcher watcher) { @@ -91,8 +95,7 @@ class CustodiSoulcallerWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == EventType.BEGIN_COMBAT_STEP_PRE) { this.playersAttacked.clear(); - } - else if (event.getType() == EventType.ATTACKER_DECLARED) { + } else if (event.getType() == EventType.ATTACKER_DECLARED) { Set attackedPlayers = this.playersAttacked.getOrDefault(event.getPlayerId(), new HashSet<>(1)); attackedPlayers.add(event.getTargetId()); this.playersAttacked.put(event.getPlayerId(), attackedPlayers); diff --git a/Mage.Sets/src/mage/cards/c/CutRibbons.java b/Mage.Sets/src/mage/cards/c/CutRibbons.java index 4378f21ff6..b29a27ae09 100644 --- a/Mage.Sets/src/mage/cards/c/CutRibbons.java +++ b/Mage.Sets/src/mage/cards/c/CutRibbons.java @@ -28,8 +28,8 @@ public final class CutRibbons extends SplitCard { // to // Ribbons // Each opponent loses X life. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); - getRightHalfCard().getSpellAbility().addEffect(new LoseLifeOpponentsEffect(new ManacostVariableValue())); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().getSpellAbility().addEffect(new LoseLifeOpponentsEffect(ManacostVariableValue.instance)); } diff --git a/Mage.Sets/src/mage/cards/c/CutTheEarthlyBond.java b/Mage.Sets/src/mage/cards/c/CutTheEarthlyBond.java index 2eb73ac3d3..a3f122cd61 100644 --- a/Mage.Sets/src/mage/cards/c/CutTheEarthlyBond.java +++ b/Mage.Sets/src/mage/cards/c/CutTheEarthlyBond.java @@ -21,7 +21,7 @@ public final class CutTheEarthlyBond extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("enchanted permanent"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); } public CutTheEarthlyBond(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CutTheTethers.java b/Mage.Sets/src/mage/cards/c/CutTheTethers.java index 3536c265b7..3d2d7d499d 100644 --- a/Mage.Sets/src/mage/cards/c/CutTheTethers.java +++ b/Mage.Sets/src/mage/cards/c/CutTheTethers.java @@ -69,7 +69,7 @@ class CutTheTethersEffect extends OneShotEffect { Player player = game.getPlayer(creature.getControllerId()); if (player != null) { boolean paid = false; - if (player.chooseUse(outcome, new StringBuilder("Pay {3} to keep ").append(creature.getName()).append(" on the battlefield?").toString(), source, game)) { + if (player.chooseUse(outcome, "Pay {3} to keep " + creature.getName() + " on the battlefield?", source, game)) { Cost cost = new GenericManaCost(3); if (!cost.pay(source, game, source.getSourceId(), creature.getControllerId(), false, null)) { paid = true; diff --git a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java index 77e7787f93..d572a307b3 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java +++ b/Mage.Sets/src/mage/cards/c/CyclopeanTomb.java @@ -1,4 +1,3 @@ - package mage.cards.c; import mage.MageObjectReference; @@ -31,13 +30,9 @@ import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; /** - * * @author MTGfan */ public final class CyclopeanTomb extends CardImpl { @@ -57,11 +52,12 @@ public final class CyclopeanTomb extends CardImpl { ability.addTarget(new TargetLandPermanent(filter)); ability.addEffect(new BecomeSwampEffect(Duration.Custom, false, true, SubType.SWAMP)); this.addAbility(ability, new CyclopeanTombCounterWatcher()); + // When Cyclopean Tomb is put into a graveyard from the battlefield, at the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with Cyclopean Tomb but that a mire counter has not been removed from with Cyclopean Tomb. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new CyclopeanTombCreateTriggeredEffect())); } - public CyclopeanTomb(final CyclopeanTomb card) { + private CyclopeanTomb(final CyclopeanTomb card) { super(card); } @@ -73,12 +69,12 @@ public final class CyclopeanTomb extends CardImpl { class BecomeSwampEffect extends BecomesBasicLandTargetEffect { - public BecomeSwampEffect(Duration duration, boolean chooseLandType, boolean loseOther, SubType... landNames) { + BecomeSwampEffect(Duration duration, boolean chooseLandType, boolean loseOther, SubType... landNames) { super(duration, chooseLandType, loseOther, landNames); staticText = "That land is a Swamp for as long as it has a mire counter on it"; } - public BecomeSwampEffect(final BecomeSwampEffect effect) { + private BecomeSwampEffect(final BecomeSwampEffect effect) { super(effect); } @@ -103,12 +99,12 @@ class BecomeSwampEffect extends BecomesBasicLandTargetEffect { class CyclopeanTombCreateTriggeredEffect extends OneShotEffect { - public CyclopeanTombCreateTriggeredEffect() { + CyclopeanTombCreateTriggeredEffect() { super(Outcome.Benefit); this.staticText = "at the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with {this} but that a mire counter has not been removed from with {this}"; } - public CyclopeanTombCreateTriggeredEffect(final CyclopeanTombCreateTriggeredEffect effect) { + private CyclopeanTombCreateTriggeredEffect(final CyclopeanTombCreateTriggeredEffect effect) { super(effect); } @@ -123,7 +119,6 @@ class CyclopeanTombCreateTriggeredEffect extends OneShotEffect { if (controller != null) { Permanent tomb = game.getPermanentOrLKIBattlefield(source.getSourceId()); // we need to set the correct source object DelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new CyclopeanTombEffect(), Duration.EndOfGame, false); - ability.setSourceObject(tomb, game); ability.setControllerId(source.getControllerId()); ability.setSourceId(source.getSourceId()); game.addDelayedTriggeredAbility(ability); @@ -135,12 +130,12 @@ class CyclopeanTombCreateTriggeredEffect extends OneShotEffect { class CyclopeanTombEffect extends OneShotEffect { - public CyclopeanTombEffect() { + CyclopeanTombEffect() { super(Outcome.Benefit); this.staticText = "At the beginning of each of your upkeeps for the rest of the game, remove all mire counters from a land that a mire counter was put onto with {this} but that a mire counter has not been removed from with {this}"; } - public CyclopeanTombEffect(final CyclopeanTombEffect effect) { + private CyclopeanTombEffect(final CyclopeanTombEffect effect) { super(effect); } @@ -153,7 +148,7 @@ class CyclopeanTombEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObjectReference mor = new MageObjectReference(source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game); - CyclopeanTombCounterWatcher watcher = (CyclopeanTombCounterWatcher) game.getState().getWatchers().get(CyclopeanTombCounterWatcher.class.getSimpleName()); + CyclopeanTombCounterWatcher watcher = game.getState().getWatcher(CyclopeanTombCounterWatcher.class); if (controller != null && watcher != null) { Set landRef = watcher.landMiredByCyclopeanTombInstance(mor, game); @@ -171,8 +166,8 @@ class CyclopeanTombEffect extends OneShotEffect { filter.add(Predicates.or(idPref)); TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, true); /*Player must choose a land each upkeep. Using the message are above the player hand where frequent interactions - * take place is the most logical way to prompt for this scenario. A new constructor added to provide a not optional - * option for any cards like this where the player must choose a target in such the way this card requires. + * take place is the most logical way to prompt for this scenario. A new constructor added to provide a not optional + * option for any cards like this where the player must choose a target in such the way this card requires. */ if (controller.chooseTarget(Outcome.Neutral, target, source, game)) { Permanent chosenLand = game.getPermanent(target.getFirstTarget()); @@ -192,13 +187,13 @@ class CyclopeanTombEffect extends OneShotEffect { class CyclopeanTombCounterWatcher extends Watcher { - public HashMap> counterData = new HashMap<>(); + private final Map> counterData = new HashMap<>(); - public CyclopeanTombCounterWatcher() { - super(CyclopeanTombCounterWatcher.class.getSimpleName(), WatcherScope.GAME); + CyclopeanTombCounterWatcher() { + super(WatcherScope.GAME); } - public CyclopeanTombCounterWatcher(final CyclopeanTombCounterWatcher watcher) { + private CyclopeanTombCounterWatcher(final CyclopeanTombCounterWatcher watcher) { super(watcher); for (MageObjectReference mageObjectReference : watcher.counterData.keySet()) { Set miredLands = new HashSet<>(); @@ -231,11 +226,6 @@ class CyclopeanTombCounterWatcher extends Watcher { } } - @Override - public void reset() { - super.reset(); - } - public Set landMiredByCyclopeanTombInstance(MageObjectReference mor, Game game) { if (counterData.containsKey(mor)) { return counterData.get(mor); diff --git a/Mage.Sets/src/mage/cards/c/CyclopsElectromancer.java b/Mage.Sets/src/mage/cards/c/CyclopsElectromancer.java new file mode 100644 index 0000000000..3031fc6245 --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CyclopsElectromancer.java @@ -0,0 +1,51 @@ +package mage.cards.c; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CyclopsElectromancer extends CardImpl { + + private static final DynamicValue xValue + = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); + + public CyclopsElectromancer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.CYCLOPS); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // When Cyclops Electromancer enters the battlefield, it deals X damage to target creature an opponent controls, where X is the number of instant and sorcery cards in your graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DamageTargetEffect(xValue).setText("it deals X damage to target creature an opponent controls, " + + "where X is the number of instant and sorcery cards in your graveyard.") + ); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private CyclopsElectromancer(final CyclopsElectromancer card) { + super(card); + } + + @Override + public CyclopsElectromancer copy() { + return new CyclopsElectromancer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java index 95877d5cb9..638e886454 100644 --- a/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java +++ b/Mage.Sets/src/mage/cards/c/CyclopsGladiator.java @@ -70,7 +70,7 @@ class CyclopsGladiatorEffect extends OneShotEffect { TargetCreaturePermanent target = new TargetCreaturePermanent(filter); Player player = game.getPlayer(source.getControllerId()); if (target.canChoose(source.getSourceId(), source.getControllerId(), game)) { - if (player.chooseTarget(Outcome.Detriment, target, source, game)) { + if (player != null && player.chooseTarget(Outcome.Detriment, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); Permanent cyclops = game.getPermanent(source.getSourceId()); if (permanent != null && cyclops != null) { diff --git a/Mage.Sets/src/mage/cards/c/CytoplastRootKin.java b/Mage.Sets/src/mage/cards/c/CytoplastRootKin.java index 427e58c798..56b2902961 100644 --- a/Mage.Sets/src/mage/cards/c/CytoplastRootKin.java +++ b/Mage.Sets/src/mage/cards/c/CytoplastRootKin.java @@ -32,7 +32,7 @@ public final class CytoplastRootKin extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creature you control that has a +1/+1 counter on it"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CounterPredicate(CounterType.P1P1)); } diff --git a/Mage.Sets/src/mage/cards/d/DAvenantTrapper.java b/Mage.Sets/src/mage/cards/d/DAvenantTrapper.java index d763b44edb..313cb11594 100644 --- a/Mage.Sets/src/mage/cards/d/DAvenantTrapper.java +++ b/Mage.Sets/src/mage/cards/d/DAvenantTrapper.java @@ -23,7 +23,7 @@ public final class DAvenantTrapper extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public DAvenantTrapper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DaggerCaster.java b/Mage.Sets/src/mage/cards/d/DaggerCaster.java new file mode 100644 index 0000000000..b505371fee --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DaggerCaster.java @@ -0,0 +1,49 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DaggerCaster extends CardImpl { + + public DaggerCaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // When Dagger Caster enters the battlefield, it deals 1 damage to each opponent and 1 damage to each creature your opponents control. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect( + 1, TargetController.OPPONENT, "it" + )); + ability.addEffect( + new DamageAllEffect(1, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE) + .setText("and 1 damage to each creature your opponents control") + ); + this.addAbility(ability); + } + + private DaggerCaster(final DaggerCaster card) { + super(card); + } + + @Override + public DaggerCaster copy() { + return new DaggerCaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DamiaSageOfStone.java b/Mage.Sets/src/mage/cards/d/DamiaSageOfStone.java index 2ca4be3381..4b75082585 100644 --- a/Mage.Sets/src/mage/cards/d/DamiaSageOfStone.java +++ b/Mage.Sets/src/mage/cards/d/DamiaSageOfStone.java @@ -59,7 +59,7 @@ public final class DamiaSageOfStone extends CardImpl { class DamiaSageOfStoneTriggeredAbility extends BeginningOfUpkeepTriggeredAbility { DamiaSageOfStoneTriggeredAbility() { - super(new DrawCardSourceControllerEffect(new IntPlusDynamicValue(7, new MultipliedValue(new CardsInControllerHandCount(), -1))), TargetController.YOU, false); + super(new DrawCardSourceControllerEffect(new IntPlusDynamicValue(7, new MultipliedValue(CardsInControllerHandCount.instance, -1))), TargetController.YOU, false); } DamiaSageOfStoneTriggeredAbility(final DamiaSageOfStoneTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/d/DampeningPulse.java b/Mage.Sets/src/mage/cards/d/DampeningPulse.java index 48d1ab9fa3..54998b8e2c 100644 --- a/Mage.Sets/src/mage/cards/d/DampeningPulse.java +++ b/Mage.Sets/src/mage/cards/d/DampeningPulse.java @@ -19,7 +19,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class DampeningPulse extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/d/DampingEngine.java b/Mage.Sets/src/mage/cards/d/DampingEngine.java index 2884c643d0..573f507d55 100644 --- a/Mage.Sets/src/mage/cards/d/DampingEngine.java +++ b/Mage.Sets/src/mage/cards/d/DampingEngine.java @@ -27,7 +27,6 @@ */ package mage.cards.d; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpecialAction; @@ -39,11 +38,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -51,8 +46,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public class DampingEngine extends CardImpl { @@ -119,8 +115,7 @@ class DampingEngineEffect extends ContinuousRuleModifyingEffectImpl { Player player = game.getPlayer(event.getPlayerId()); Permanent dampingEngine = game.getPermanent(source.getSourceId()); final Card card = game.getCard(event.getSourceId()); - if (player != null - || card != null) { + if (player != null || card != null) { // check type of spell if (card.isCreature() || card.isArtifact() @@ -129,13 +124,10 @@ class DampingEngineEffect extends ContinuousRuleModifyingEffectImpl { // check to see if the player has more permanents if (new ControlsMorePermanentsThanEachOtherPlayer(player).apply(game, source)) { // check to see if the player choose to ignore the effect - if (game.getState().getValue("ignoreEffect") != null - && dampingEngine != null - && game.getState().getValue("ignoreEffect").equals - (dampingEngine.getId() + "ignoreEffect" + game.getState().getPriorityPlayerId() + game.getState().getTurnNum())) { - return false; - } - return true; + return game.getState().getValue("ignoreEffect") == null + || dampingEngine == null + || !game.getState().getValue("ignoreEffect").equals + (dampingEngine.getId() + "ignoreEffect" + game.getState().getPriorityPlayerId() + game.getState().getTurnNum()); } } } diff --git a/Mage.Sets/src/mage/cards/d/DampingSphere.java b/Mage.Sets/src/mage/cards/d/DampingSphere.java index 8447bc0aed..b4780d80d7 100644 --- a/Mage.Sets/src/mage/cards/d/DampingSphere.java +++ b/Mage.Sets/src/mage/cards/d/DampingSphere.java @@ -103,7 +103,7 @@ class DampingSphereIncreasementAllEffect extends SpellsCostIncreasementAllEffect @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { int additionalCost = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(abilityToModify.getControllerId()); CardUtil.increaseCost(abilityToModify, additionalCost); diff --git a/Mage.Sets/src/mage/cards/d/DanceOfMany.java b/Mage.Sets/src/mage/cards/d/DanceOfMany.java index e99a8ca72e..6b58f60fe4 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfMany.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfMany.java @@ -39,7 +39,7 @@ public final class DanceOfMany extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public DanceOfMany(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java b/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java index 40b8b5a6f3..01eccf7833 100644 --- a/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java +++ b/Mage.Sets/src/mage/cards/d/DanceOfTheDead.java @@ -204,7 +204,7 @@ class DanceOfTheDeadAttachEffect extends OneShotEffect { class DanceOfTheDeadChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { - private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Dance of the Dead"); + private static final Ability newAbility = new EnchantAbility("creature put onto the battlefield with Dance of the Dead"); static { newAbility.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java b/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java index 8abf13e932..713cded956 100644 --- a/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java +++ b/Mage.Sets/src/mage/cards/d/DarettiIngeniousIconoclast.java @@ -1,12 +1,10 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -14,32 +12,36 @@ import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.SuperType; +import mage.filter.FilterCard; import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; -import mage.filter.common.FilterControlledArtifactPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.game.Game; import mage.game.permanent.token.DarettiConstructToken; import mage.target.TargetPermanent; import mage.target.common.TargetCardInGraveyardOrBattlefield; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DarettiIngeniousIconoclast extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifact or creature"); + private static final FilterPermanent filter + = new FilterPermanent("artifact or creature (to destroy)"); + private static final FilterCard filter2 + = new FilterArtifactCard("artifact card in a graveyard or artifact on the battlefield"); static { filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.CREATURE))); + new CardTypePredicate(CardType.CREATURE) + )); } public DarettiIngeniousIconoclast(UUID ownerId, CardSetInfo setInfo) { @@ -50,27 +52,31 @@ public final class DarettiIngeniousIconoclast extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); // +1: Create a 1/1 colorless Construct artifact creature token with defender. - LoyaltyAbility ability = new LoyaltyAbility(new CreateTokenEffect(new DarettiConstructToken()), 1); - this.addAbility(ability); + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DarettiConstructToken()), 1)); // -1: You may sacrifice an artifact. If you do, destroy target artifact or creature. - ability = new LoyaltyAbility( - new DoIfCostPaid(new DestroyTargetEffect(""), new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledArtifactPermanent("an artifact")))), - -1); + Ability ability = new LoyaltyAbility( + new DoIfCostPaid( + new DestroyTargetEffect("destroy target artifact or creature"), + new SacrificeTargetCost(new TargetControlledPermanent( + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN + )) + ), -1 + ); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); // -6: Choose target artifact card in a graveyard or artifact on the battlefield. Create three tokens that are copies of it. ability = new LoyaltyAbility( new CreateTokenCopyTargetEffect(null, null, false, 3) - .setText("Choose target artifact card in a graveyard or artifact on the battlefield. Create three tokens that are copies of it"), - -6); - ability.addTarget(new TargetCardInGraveyardOrBattlefield(new FilterArtifactCard("artifact card in a graveyard or artifact on the battlefield"))); + .setText("Choose target artifact card in a graveyard or artifact on the battlefield. " + + "Create three tokens that are copies of it"), -6 + ); + ability.addTarget(new TargetCardInGraveyardOrBattlefield(filter2)); this.addAbility(ability); - } - public DarettiIngeniousIconoclast(final DarettiIngeniousIconoclast card) { + private DarettiIngeniousIconoclast(final DarettiIngeniousIconoclast card) { super(card); } @@ -79,25 +85,3 @@ public final class DarettiIngeniousIconoclast extends CardImpl { return new DarettiIngeniousIconoclast(this); } } - -class DarettiIngeniousIconoclastEffect extends OneShotEffect { - - public DarettiIngeniousIconoclastEffect() { - super(Outcome.Benefit); - this.staticText = "Choose target artifact card in a graveyard or artifact on the battlefield. Create three tokens that are copies of it"; - } - - public DarettiIngeniousIconoclastEffect(final DarettiIngeniousIconoclastEffect effect) { - super(effect); - } - - @Override - public DarettiIngeniousIconoclastEffect copy() { - return new DarettiIngeniousIconoclastEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java b/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java index 4afedcd472..68bc745628 100644 --- a/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java +++ b/Mage.Sets/src/mage/cards/d/DarigaazsCharm.java @@ -33,14 +33,14 @@ public final class DarigaazsCharm extends CardImpl { // or Darigaaz's Charm deals 3 damage to any target; Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(3)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new DamageTargetEffect(3)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); // or target creature gets +3/+3 until end of turn. mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(3, 3, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java b/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java index 9ee2191281..133b878468 100644 --- a/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java +++ b/Mage.Sets/src/mage/cards/d/DaringArchaeologist.java @@ -27,7 +27,7 @@ public final class DaringArchaeologist extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public DaringArchaeologist(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DaringDemolition.java b/Mage.Sets/src/mage/cards/d/DaringDemolition.java index 176dedf496..3bc03353c9 100644 --- a/Mage.Sets/src/mage/cards/d/DaringDemolition.java +++ b/Mage.Sets/src/mage/cards/d/DaringDemolition.java @@ -19,7 +19,7 @@ import mage.target.TargetPermanent; */ public final class DaringDemolition extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("creature or Vehicle"); + private static final FilterPermanent filter = new FilterPermanent("creature or Vehicle"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new SubtypePredicate(SubType.VEHICLE))); diff --git a/Mage.Sets/src/mage/cards/d/DaringThief.java b/Mage.Sets/src/mage/cards/d/DaringThief.java index 6c78419114..f61519a5df 100644 --- a/Mage.Sets/src/mage/cards/d/DaringThief.java +++ b/Mage.Sets/src/mage/cards/d/DaringThief.java @@ -5,6 +5,7 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Set; import java.util.UUID; + import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -27,13 +28,12 @@ import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; /** - * * @author LevelX2 */ public final class DaringThief extends CardImpl { public DaringThief(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); @@ -41,7 +41,7 @@ public final class DaringThief extends CardImpl { this.toughness = new MageInt(3); // Inspired - Whenever Daring Thief becomes untapped, you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it. - Ability ability = new InspiredAbility(new ExchangeControlTargetEffect(Duration.EndOfGame, + Ability ability = new InspiredAbility(new ExchangeControlTargetEffect(Duration.EndOfGame, "you may exchange control of target nonland permanent you control and target permanent an opponent controls that shares a card type with it", false, true), true); ability.addTarget(new TargetControlledPermanentSharingOpponentPermanentCardType()); ability.addTarget(new DaringThiefSecondTarget()); @@ -59,23 +59,23 @@ public final class DaringThief extends CardImpl { } class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetControlledPermanent { - + public TargetControlledPermanentSharingOpponentPermanentCardType() { super(); this.filter = this.filter.copy(); filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); setTargetName("nonland permanent you control"); - } - + } + public TargetControlledPermanentSharingOpponentPermanentCardType(final TargetControlledPermanentSharingOpponentPermanentCardType target) { super(target); } - + @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { if (super.canTarget(controllerId, id, source, game)) { Set cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), controllerId, game); - Permanent permanent = game.getPermanent(id); + Permanent permanent = game.getPermanent(id); for (CardType type : permanent.getCardType()) { if (cardTypes.contains(type)) { return true; @@ -84,36 +84,38 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo } return false; } - + @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { // get all cardtypes from opponents permanents Set cardTypes = getOpponentPermanentCardTypes(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - for (CardType type : permanent.getCardType()) { - if (cardTypes.contains(type)) { - possibleTargets.add(permanent.getId()); - break; - } + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + for (CardType type : permanent.getCardType()) { + if (cardTypes.contains(type)) { + possibleTargets.add(permanent.getId()); + break; + } + } } } } - return possibleTargets; + return possibleTargets; } - + @Override public TargetControlledPermanentSharingOpponentPermanentCardType copy() { return new TargetControlledPermanentSharingOpponentPermanentCardType(this); } - + private EnumSet getOpponentPermanentCardTypes(UUID sourceId, UUID sourceControllerId, Game game) { Player controller = game.getPlayer(sourceControllerId); - EnumSet cardTypes =EnumSet.noneOf(CardType.class); + EnumSet cardTypes = EnumSet.noneOf(CardType.class); if (controller != null) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(sourceControllerId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(sourceControllerId, game)) { if (controller.hasOpponent(permanent.getControllerId(), game)) { cardTypes.addAll(permanent.getCardType()); } @@ -127,20 +129,20 @@ class TargetControlledPermanentSharingOpponentPermanentCardType extends TargetCo class DaringThiefSecondTarget extends TargetPermanent { private Permanent firstTarget = null; - + public DaringThiefSecondTarget() { super(); this.filter = this.filter.copy(); filter.add(new ControllerPredicate(TargetController.OPPONENT)); setTargetName("permanent an opponent controls that shares a card type with it"); - } + } public DaringThiefSecondTarget(final DaringThiefSecondTarget target) { super(target); this.firstTarget = target.firstTarget; } - + @Override public boolean canTarget(UUID id, Ability source, Game game) { if (super.canTarget(id, source, game)) { @@ -152,29 +154,31 @@ class DaringThiefSecondTarget extends TargetPermanent { } return false; } - + @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if (permanent.shareTypes(firstTarget)) { - possibleTargets.add(permanent.getId()); + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (permanent.shareTypes(firstTarget)) { + possibleTargets.add(permanent.getId()); + } } } } } return possibleTargets; } - + @Override public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { firstTarget = game.getPermanent(source.getFirstTarget()); return super.chooseTarget(Outcome.Damage, playerId, source, game); - } - + } + @Override public DaringThiefSecondTarget copy() { return new DaringThiefSecondTarget(this); diff --git a/Mage.Sets/src/mage/cards/d/DarkDeal.java b/Mage.Sets/src/mage/cards/d/DarkDeal.java index 0509a07c3d..1c81482bc1 100644 --- a/Mage.Sets/src/mage/cards/d/DarkDeal.java +++ b/Mage.Sets/src/mage/cards/d/DarkDeal.java @@ -4,6 +4,8 @@ package mage.cards.d; import java.util.LinkedHashMap; import java.util.Map; import java.util.UUID; + +import com.j256.ormlite.stmt.query.In; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -67,10 +69,10 @@ class DarkDealEffect extends OneShotEffect { } } } - for (UUID playerId : cardsToDraw.keySet()) { - Player player = game.getPlayer(playerId); + for (Map.Entry toDrawByPlayer : cardsToDraw.entrySet()) { + Player player = game.getPlayer(toDrawByPlayer.getKey()); if (player != null) { - player.drawCards(cardsToDraw.get(playerId), game); + player.drawCards(toDrawByPlayer.getValue(), game); } } return true; diff --git a/Mage.Sets/src/mage/cards/d/DarkDecision.java b/Mage.Sets/src/mage/cards/d/DarkDecision.java index f89c73413b..cd96221c60 100644 --- a/Mage.Sets/src/mage/cards/d/DarkDecision.java +++ b/Mage.Sets/src/mage/cards/d/DarkDecision.java @@ -69,7 +69,7 @@ class DarkDecisionEffect extends OneShotEffect { if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard()); target.setCardLimit(10); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { UUID targetId = target.getFirstTarget(); Card card = game.getCard(targetId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/d/DarkDepths.java b/Mage.Sets/src/mage/cards/d/DarkDepths.java index 61b87fc341..763a32c0de 100644 --- a/Mage.Sets/src/mage/cards/d/DarkDepths.java +++ b/Mage.Sets/src/mage/cards/d/DarkDepths.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.StateTriggeredAbility; import mage.abilities.common.EntersBattlefieldAbility; @@ -22,8 +21,9 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.permanent.token.MaritLageToken; +import java.util.UUID; + /** - * * @author Plopman */ public final class DarkDepths extends CardImpl { @@ -106,7 +106,8 @@ class DarkDepthsAbility extends StateTriggeredAbility { @Override public String getRule() { - return "When {this} has no ice counters on it, sacrifice it. If you do, create a legendary 20/20 black Avatar creature token with flying and indestructible named Marit Lage."; + return "When {this} has no ice counters on it, sacrifice it. If you do, " + + "create Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible."; } } diff --git a/Mage.Sets/src/mage/cards/d/DarkProphecy.java b/Mage.Sets/src/mage/cards/d/DarkProphecy.java index 91c3f34f59..4881da9516 100644 --- a/Mage.Sets/src/mage/cards/d/DarkProphecy.java +++ b/Mage.Sets/src/mage/cards/d/DarkProphecy.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.effects.Effect; @@ -14,28 +12,27 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DarkProphecy extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); + static { filter.add(new ControllerPredicate(TargetController.YOU)); } public DarkProphecy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}{B}{B}"); // Whenever a creature you control dies, you draw a card and you lose 1 life. - Effect effect = new DrawCardSourceControllerEffect(1); - effect.setText("you draw a card"); + Effect effect = new DrawCardSourceControllerEffect(1, "you"); Ability ability = new DiesCreatureTriggeredAbility(effect, false, filter); effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability.addEffect(effect); + ability.addEffect(effect.concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DarkRevenant.java b/Mage.Sets/src/mage/cards/d/DarkRevenant.java index cb0fc5a2da..6741b40a2b 100644 --- a/Mage.Sets/src/mage/cards/d/DarkRevenant.java +++ b/Mage.Sets/src/mage/cards/d/DarkRevenant.java @@ -68,8 +68,10 @@ class DarkRevenantEffect extends OneShotEffect { Card card = game.getCard(source.getSourceId()); if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { Player owner = game.getPlayer(card.getOwnerId()); - owner.getGraveyard().remove(card); - return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + if(owner != null) { + owner.getGraveyard().remove(card); + return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/d/DarkSalvation.java b/Mage.Sets/src/mage/cards/d/DarkSalvation.java index 30100994ac..ca82c4e59e 100644 --- a/Mage.Sets/src/mage/cards/d/DarkSalvation.java +++ b/Mage.Sets/src/mage/cards/d/DarkSalvation.java @@ -34,7 +34,7 @@ public final class DarkSalvation extends CardImpl { // Target player creates X 2/2 black Zombie creature tokens, then up to one target creature gets -1/-1 until end of turn for each Zombie that player controls. this.getSpellAbility().addTarget(new TargetPlayer()); - Effect effect = new CreateTokenTargetEffect(new ZombieToken(), new ManacostVariableValue()); + Effect effect = new CreateTokenTargetEffect(new ZombieToken(), ManacostVariableValue.instance); effect.setText("Target player creates X 2/2 black Zombie creature tokens"); this.getSpellAbility().addEffect(effect); DynamicValue value = new ZombiesControlledByTargetPlayerCount(); @@ -58,7 +58,7 @@ public final class DarkSalvation extends CardImpl { class ZombiesControlledByTargetPlayerCount implements DynamicValue { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombies"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Zombies"); static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); diff --git a/Mage.Sets/src/mage/cards/d/DarkSupplicant.java b/Mage.Sets/src/mage/cards/d/DarkSupplicant.java index f733d39b2f..387bc27557 100644 --- a/Mage.Sets/src/mage/cards/d/DarkSupplicant.java +++ b/Mage.Sets/src/mage/cards/d/DarkSupplicant.java @@ -110,7 +110,7 @@ class DarkSupplicantEffect extends OneShotEffect { && controller.chooseUse(Outcome.Benefit, "Do you want to search your library for Scion of Darkness?", source, game)) { librarySearched = true; TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { selectedCard = game.getCard(target.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/d/DarkTriumph.java b/Mage.Sets/src/mage/cards/d/DarkTriumph.java index d2c98f3027..4af43095ae 100644 --- a/Mage.Sets/src/mage/cards/d/DarkTriumph.java +++ b/Mage.Sets/src/mage/cards/d/DarkTriumph.java @@ -1,7 +1,7 @@ package mage.cards.d; -import java.util.UUID; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.costs.AlternativeCostSourceAbility; import mage.abilities.costs.common.SacrificeTargetCost; @@ -11,30 +11,30 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; -import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.FilterPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author TheElk801 */ public final class DarkTriumph extends CardImpl { - private static final FilterLandPermanent filterSwamp = new FilterLandPermanent("If you control a Swamp"); - - static { - filterSwamp.add(new SubtypePredicate(SubType.SWAMP)); - } + private static final Condition condition = new PermanentsOnTheBattlefieldCondition( + new FilterPermanent(SubType.SWAMP, "If you control a Swamp") + ); public DarkTriumph(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); // If you control a Swamp, you may sacrifice a creature rather than pay Dark Triumph's mana cost. this.addAbility(new AlternativeCostSourceAbility( - new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)), - new PermanentsOnTheBattlefieldCondition(filterSwamp), null + new SacrificeTargetCost( + new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT) + ), condition )); // Creatures you control get +2/+0 until end of turn. diff --git a/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java b/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java index 85a91830aa..8af32ccef8 100644 --- a/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java +++ b/Mage.Sets/src/mage/cards/d/DarkbladeAgent.java @@ -1,8 +1,5 @@ package mage.cards.d; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -12,19 +9,18 @@ import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.keyword.DeathtouchAbility; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.WatcherScope; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DarkbladeAgent extends CardImpl { @@ -46,7 +42,7 @@ public final class DarkbladeAgent extends CardImpl { Duration.WhileOnBattlefield ), DarkbladeAgentCondition.instance, "As long as you've surveilled this turn, " - + "{this} has deathtouch" + + "{this} has deathtouch" ) ); ability.addEffect(new ConditionalContinuousEffect( @@ -56,7 +52,7 @@ public final class DarkbladeAgent extends CardImpl { ), Duration.WhileOnBattlefield ), DarkbladeAgentCondition.instance, "and \"Whenever this creature deals " - + "combat damage to a player, draw a card.\"" + + "combat damage to a player, draw a card.\"" )); this.addAbility(ability, new DarkbladeAgentWatcher()); } @@ -77,9 +73,8 @@ enum DarkbladeAgentCondition implements Condition { @Override public boolean apply(Game game, Ability source) { DarkbladeAgentWatcher watcher - = (DarkbladeAgentWatcher) game.getState().getWatchers().get( - DarkbladeAgentWatcher.class.getSimpleName() - ); + = game.getState().getWatcher( + DarkbladeAgentWatcher.class); return watcher != null && watcher.getSurveiledThisTurn(source.getControllerId()); } @@ -87,10 +82,10 @@ enum DarkbladeAgentCondition implements Condition { class DarkbladeAgentWatcher extends Watcher { - private final Set surveiledThisTurn = new HashSet(); + private final Set surveiledThisTurn = new HashSet<>(); public DarkbladeAgentWatcher() { - super(DarkbladeAgentWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public DarkbladeAgentWatcher(final DarkbladeAgentWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/d/DarkslickShores.java b/Mage.Sets/src/mage/cards/d/DarkslickShores.java index 1739e63087..82b941846a 100644 --- a/Mage.Sets/src/mage/cards/d/DarkslickShores.java +++ b/Mage.Sets/src/mage/cards/d/DarkslickShores.java @@ -23,10 +23,10 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class DarkslickShores extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterLandPermanent filter = new FilterLandPermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DarkslickShores(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java b/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java index 27fe59e672..59cc034dfa 100644 --- a/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java +++ b/Mage.Sets/src/mage/cards/d/DarthSidiousSithLord.java @@ -14,6 +14,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Duration; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; @@ -36,6 +37,7 @@ public final class DarthSidiousSithLord extends CardImpl { public DarthSidiousSithLord(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{4}{U}{B}{B}{R}"); + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SIDIOUS); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); diff --git a/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java b/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java index 92b3e495ab..6fc58b4f82 100644 --- a/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java +++ b/Mage.Sets/src/mage/cards/d/DarthTyranusCountOfSerenno.java @@ -14,6 +14,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; @@ -35,6 +36,7 @@ public final class DarthTyranusCountOfSerenno extends CardImpl { public DarthTyranusCountOfSerenno(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{1}{W}{U}{B}"); + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.DOOKU); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); @@ -122,7 +124,7 @@ class TransmuteArtifactEffect extends SearchEffect { sacrifice = permanent.sacrifice(source.getSourceId(), game); } } - if (sacrifice && controller.searchLibrary(target, game)) { + if (sacrifice && controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); diff --git a/Mage.Sets/src/mage/cards/d/DaruSpiritualist.java b/Mage.Sets/src/mage/cards/d/DaruSpiritualist.java index 1e684d94f6..dbf5f6a79d 100644 --- a/Mage.Sets/src/mage/cards/d/DaruSpiritualist.java +++ b/Mage.Sets/src/mage/cards/d/DaruSpiritualist.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -12,8 +11,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -50,12 +47,6 @@ public final class DaruSpiritualist extends CardImpl { class DaruSpiritualistTriggeredAbility extends TriggeredAbilityImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Cleric creature you control"); - - static { - filter.add(new SubtypePredicate(SubType.CLERIC)); - } - public DaruSpiritualistTriggeredAbility(Effect effect) { super(Zone.BATTLEFIELD, effect); } @@ -77,7 +68,7 @@ class DaruSpiritualistTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent creature = game.getPermanent(event.getTargetId()); - if (creature != null && filter.match(creature, getSourceId(), getControllerId(), game)) { + if (creature != null && creature.hasSubtype(SubType.CLERIC, game) && creature.getControllerId().equals(getControllerId()) && creature.isCreature()) { this.getEffects().setTargetPointer(new FixedTarget(creature, game)); return true; } diff --git a/Mage.Sets/src/mage/cards/d/DashHopes.java b/Mage.Sets/src/mage/cards/d/DashHopes.java index c3a0336f7a..a8edaeace7 100644 --- a/Mage.Sets/src/mage/cards/d/DashHopes.java +++ b/Mage.Sets/src/mage/cards/d/DashHopes.java @@ -67,14 +67,16 @@ class DashHopesCounterSourceEffect extends OneShotEffect { PayLifeCost cost = new PayLifeCost(5); for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); - cost.clearPaid(); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Pay 5 life to counter " + sourceObject.getIdName() + '?', source, game)) { - if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { - game.informPlayers(player.getLogName() + " pays 5 life to counter " + sourceObject.getIdName() + '.'); - Spell spell = game.getStack().getSpell(source.getSourceId()); - if (spell != null) { - game.getStack().counter(spell.getId(), source.getSourceId(), game); + if(player != null) { + cost.clearPaid(); + if (cost.canPay(source, source.getSourceId(), player.getId(), game) + && player.chooseUse(outcome, "Pay 5 life to counter " + sourceObject.getIdName() + '?', source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + game.informPlayers(player.getLogName() + " pays 5 life to counter " + sourceObject.getIdName() + '.'); + Spell spell = game.getStack().getSpell(source.getSourceId()); + if (spell != null) { + game.getStack().counter(spell.getId(), source.getSourceId(), game); + } } } } diff --git a/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java b/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java index e88ad33e38..6b28ec08fc 100644 --- a/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java +++ b/Mage.Sets/src/mage/cards/d/DauntlessBodyguard.java @@ -65,7 +65,7 @@ class DauntlessBodyguardChooseCreatureEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DauntlessBodyguardChooseCreatureEffect() { @@ -85,16 +85,14 @@ class DauntlessBodyguardChooseCreatureEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + Permanent mageObject = game.getPermanentEntering(source.getSourceId()); if (controller != null && mageObject != null) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(1, 1, filter, true); if (controller.choose(this.outcome, target, source.getSourceId(), game)) { Permanent chosenCreature = game.getPermanent(target.getFirstTarget()); if (chosenCreature != null) { game.getState().setValue(mageObject.getId() + "_chosenCreature", new MageObjectReference(chosenCreature, game)); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen creature", CardUtil.addToolTipMarkTags("Chosen creature: " + chosenCreature.getIdName()), game); - } + mageObject.addInfo("chosen creature", CardUtil.addToolTipMarkTags("Chosen creature: " + chosenCreature.getIdName()), game); } } return true; diff --git a/Mage.Sets/src/mage/cards/d/DauntlessDourbark.java b/Mage.Sets/src/mage/cards/d/DauntlessDourbark.java index 15fb9b4582..2f82085d8c 100644 --- a/Mage.Sets/src/mage/cards/d/DauntlessDourbark.java +++ b/Mage.Sets/src/mage/cards/d/DauntlessDourbark.java @@ -29,17 +29,17 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class DauntlessDourbark extends CardImpl { - final static private FilterControlledPermanent filter = new FilterControlledPermanent("Forests you control plus the number of Treefolk you control"); - final static private FilterControlledPermanent filter2 = new FilterControlledPermanent(); + static final private FilterControlledPermanent filter = new FilterControlledPermanent("Forests you control plus the number of Treefolk you control"); + static final private FilterControlledPermanent filter2 = new FilterControlledPermanent(); static { filter.add(Predicates.or(new SubtypePredicate(SubType.FOREST), new SubtypePredicate(SubType.TREEFOLK))); filter2.add(new SubtypePredicate(SubType.TREEFOLK)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } - final static private String rule = "{this} has trample as long as you control another Treefolk"; + static final private String rule = "{this} has trample as long as you control another Treefolk"; public DauntlessDourbark(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); diff --git a/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java new file mode 100644 index 0000000000..7209a03555 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DavrielRogueShadowmage.java @@ -0,0 +1,65 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DavrielRogueShadowmage extends CardImpl { + + public DavrielRogueShadowmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DAVRIEL); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, Davriel, Rogue Shadowmage deals 2 damage to them. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new DamageTargetEffect(2), + TargetController.OPPONENT, false, true + ), DavrielRogueShadowmageCondition.instance, "At the beginning of each opponent's upkeep, " + + "if that player has one or fewer cards in hand, {this} deals 2 damage to them." + )); + + // -1: Target player discards a card. + Ability ability = new LoyaltyAbility(new DiscardTargetEffect(1), -1); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private DavrielRogueShadowmage(final DavrielRogueShadowmage card) { + super(card); + } + + @Override + public DavrielRogueShadowmage copy() { + return new DavrielRogueShadowmage(this); + } +} + +enum DavrielRogueShadowmageCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + return player != null && player.getHand().size() < 2; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DavrielsShadowfugue.java b/Mage.Sets/src/mage/cards/d/DavrielsShadowfugue.java new file mode 100644 index 0000000000..728f93b6c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DavrielsShadowfugue.java @@ -0,0 +1,34 @@ +package mage.cards.d; + +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DavrielsShadowfugue extends CardImpl { + + public DavrielsShadowfugue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Target player discards two cards and loses 2 life. + this.getSpellAbility().addEffect(new DiscardTargetEffect(2)); + this.getSpellAbility().addEffect(new LoseLifeTargetEffect(2).setText("and loses 2 life")); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private DavrielsShadowfugue(final DavrielsShadowfugue card) { + super(card); + } + + @Override + public DavrielsShadowfugue copy() { + return new DavrielsShadowfugue(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DawnCharm.java b/Mage.Sets/src/mage/cards/d/DawnCharm.java index c35c1d6e93..7c2f878657 100644 --- a/Mage.Sets/src/mage/cards/d/DawnCharm.java +++ b/Mage.Sets/src/mage/cards/d/DawnCharm.java @@ -39,13 +39,13 @@ public final class DawnCharm extends CardImpl { this.getSpellAbility().addEffect(new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); // or regenerate target creature; Mode mode = new Mode(); - mode.getEffects().add(new RegenerateTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new RegenerateTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or counter target spell that targets you. mode = new Mode(); - mode.getEffects().add(new CounterTargetEffect()); - mode.getTargets().add(new TargetSpell(filter)); + mode.addEffect(new CounterTargetEffect()); + mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DawnToDusk.java b/Mage.Sets/src/mage/cards/d/DawnToDusk.java index 91cdf0c196..beb9a5d6f3 100644 --- a/Mage.Sets/src/mage/cards/d/DawnToDusk.java +++ b/Mage.Sets/src/mage/cards/d/DawnToDusk.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; @@ -13,19 +11,21 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetEnchantmentPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DawnToDusk extends CardImpl { private static final FilterCard filterCard = new FilterCard("enchantment card from your graveyard"); + static { filterCard.add(new CardTypePredicate(CardType.ENCHANTMENT)); } public DawnToDusk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Choose one or both - @@ -33,11 +33,11 @@ public final class DawnToDusk extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // Return target enchantment card from your graveyard to your hand; this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCard)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return from graveyard to hand")); // and/or destroy target enchantment. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetEnchantmentPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java b/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java index b3f06e02e7..1f45bb9d57 100644 --- a/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java +++ b/Mage.Sets/src/mage/cards/d/DawnbreakReclaimer.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.HashSet; @@ -20,10 +19,11 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.other.OwnerIdPredicate; +import mage.filter.predicate.other.OwnerPredicate; import mage.game.Game; import mage.players.Player; +import mage.target.TargetCard; import mage.target.common.TargetCardInGraveyard; -import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.common.TargetOpponent; /** @@ -33,7 +33,7 @@ import mage.target.common.TargetOpponent; public final class DawnbreakReclaimer extends CardImpl { public DawnbreakReclaimer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(5); this.toughness = new MageInt(5); @@ -74,11 +74,10 @@ class DawnbreakReclaimerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { /** - * 04.11.2015 If any opponent has a creature card in their - * graveyard as Dawnbreak Reclaimer's ability resolves, then you must - * choose one of those cards. You can't choose a different opponent with - * no creature cards in their graveyard to avoid returning one of - * those cards. + * 04.11.2015 If any opponent has a creature card in their graveyard as + * Dawnbreak Reclaimer's ability resolves, then you must choose one of + * those cards. You can't choose a different opponent with no creature + * cards in their graveyard to avoid returning one of those cards. * * 04.11.2015 If there are no creature cards in any opponent's graveyard * as Dawnbreak Reclaimer's ability resolves, you'll still have the @@ -88,16 +87,24 @@ class DawnbreakReclaimerEffect extends OneShotEffect { */ Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - TargetCardInOpponentsGraveyard targetOpponentGraveyard = new TargetCardInOpponentsGraveyard(new FilterCreatureCard("a creature card in an opponent's graveyard")); + if (controller != null + && sourceObject != null) { + FilterCreatureCard filter = new FilterCreatureCard("a creature card in an opponent's graveyard"); + filter.add(new OwnerPredicate(TargetController.OPPONENT)); + TargetCard chosenCreatureOpponentGraveyard = new TargetCard(Zone.GRAVEYARD, filter); Player opponent = null; Card cardOpponentGraveyard = null; - if (targetOpponentGraveyard.canChoose(source.getSourceId(), source.getControllerId(), game)) { - controller.choose(Outcome.Detriment, targetOpponentGraveyard, source.getSourceId(), game); - cardOpponentGraveyard = game.getCard(targetOpponentGraveyard.getFirstTarget()); + chosenCreatureOpponentGraveyard.setNotTarget(true); + if (chosenCreatureOpponentGraveyard.canChoose(source.getSourceId(), source.getControllerId(), game)) { + controller.choose(Outcome.Detriment, chosenCreatureOpponentGraveyard, source.getSourceId(), game); + cardOpponentGraveyard = game.getCard(chosenCreatureOpponentGraveyard.getFirstTarget()); if (cardOpponentGraveyard != null) { opponent = game.getPlayer(cardOpponentGraveyard.getOwnerId()); - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen " + cardOpponentGraveyard.getIdName() + " of " + opponent.getLogName()); + game.informPlayers(sourceObject.getLogName() + + ": " + controller.getLogName() + + " has chosen " + + cardOpponentGraveyard.getIdName() + + " of " + opponent.getLogName()); } } if (opponent == null) { @@ -106,20 +113,29 @@ class DawnbreakReclaimerEffect extends OneShotEffect { controller.choose(outcome, targetOpponent, source.getSourceId(), game); opponent = game.getPlayer(targetOpponent.getFirstTarget()); if (opponent != null) { - game.informPlayers(sourceObject.getLogName() + ": " + controller.getLogName() + " has chosen " + opponent.getLogName() + " to select a creature card from their graveyard"); + game.informPlayers(sourceObject.getLogName() + + ": " + controller.getLogName() + + " has chosen " + + opponent.getLogName() + + " to select a creature card from their graveyard"); } } if (opponent != null) { - FilterCreatureCard filter = new FilterCreatureCard("a creature card in " + controller.getName() + "'s the graveyard"); - filter.add(new OwnerIdPredicate(controller.getId())); - TargetCardInGraveyard targetControllerGaveyard = new TargetCardInGraveyard(filter); + FilterCreatureCard filterCreatureCard = + new FilterCreatureCard("a creature card in " + controller.getName() + "'s the graveyard"); + filterCreatureCard.add(new OwnerIdPredicate(controller.getId())); + TargetCardInGraveyard targetControllerGaveyard = new TargetCardInGraveyard(filterCreatureCard); targetControllerGaveyard.setNotTarget(true); Card controllerCreatureCard = null; if (targetControllerGaveyard.canChoose(source.getSourceId(), opponent.getId(), game) && opponent.choose(outcome, targetControllerGaveyard, source.getSourceId(), game)) { controllerCreatureCard = game.getCard(targetControllerGaveyard.getFirstTarget()); if (controllerCreatureCard != null) { - game.informPlayers(sourceObject.getLogName() + ": " + opponent.getLogName() + " has chosen " + controllerCreatureCard.getIdName() + " of " + controller.getLogName()); + game.informPlayers(sourceObject.getLogName() + + ": " + opponent.getLogName() + + " has chosen " + + controllerCreatureCard.getIdName() + + " of " + controller.getLogName()); } } Set cards = new HashSet<>(); @@ -133,7 +149,11 @@ class DawnbreakReclaimerEffect extends OneShotEffect { if (controller.chooseUse( outcome, "Return those cards to the battlefield under their owners' control?", - "Opponent's creature card: " + (cardOpponentGraveyard == null ? "none" : cardOpponentGraveyard.getLogName()) + ", your creature card: " + (controllerCreatureCard == null ? "none" : controllerCreatureCard.getLogName()), + "Opponent's creature card: " + + (cardOpponentGraveyard == null + ? "none" : cardOpponentGraveyard.getLogName()) + + ", your creature card: " + (controllerCreatureCard == null + ? "none" : controllerCreatureCard.getLogName()), null, null, source, diff --git a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java index a6527a52fe..7faec30b05 100644 --- a/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java +++ b/Mage.Sets/src/mage/cards/d/DawnglowInfusion.java @@ -25,7 +25,7 @@ public final class DawnglowInfusion extends CardImpl { // You gain X life if {G} was spent to cast Dawnglow Infusion and X life if {W} was spent to cast it. - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new GainLifeEffect(xValue), new ManaWasSpentCondition(ColoredManaSymbol.G), "You gain X life if {G} was spent to cast {this}")); diff --git a/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java b/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java index 87131ba9ba..e9cc591624 100644 --- a/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java +++ b/Mage.Sets/src/mage/cards/d/DaxosOfMeletis.java @@ -89,7 +89,7 @@ class DaxosOfMeletisEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); - if (card != null) { + if (card != null && sourceObject != null) { // move card to exile controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getIdName()); // player gains life @@ -177,6 +177,7 @@ class DaxosOfMeletisSpendAnyManaEffect extends AsThoughEffectImpl implements AsT @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards return source.isControlledBy(affectedControllerId) && Objects.equals(objectId, ((FixedTarget) getTargetPointer()).getTarget()) && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) diff --git a/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java index 4e6416c9e5..88bb01666e 100644 --- a/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java +++ b/Mage.Sets/src/mage/cards/d/DazzlingBeauty.java @@ -32,8 +32,8 @@ public final class DazzlingBeauty extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature"); static { - filter.add(new AttackingPredicate()); - filter.add(Predicates.not(new BlockedPredicate())); + filter.add(AttackingPredicate.instance); + filter.add(Predicates.not(BlockedPredicate.instance)); } public DazzlingBeauty(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DeadMansChest.java b/Mage.Sets/src/mage/cards/d/DeadMansChest.java index 76a659af21..284ec871fb 100644 --- a/Mage.Sets/src/mage/cards/d/DeadMansChest.java +++ b/Mage.Sets/src/mage/cards/d/DeadMansChest.java @@ -178,16 +178,15 @@ class DeadMansChestSpendManaEffect extends AsThoughEffectImpl implements AsThoug @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else { if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted diff --git a/Mage.Sets/src/mage/cards/d/DeadRevels.java b/Mage.Sets/src/mage/cards/d/DeadRevels.java new file mode 100644 index 0000000000..b0c8368e77 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeadRevels.java @@ -0,0 +1,41 @@ +package mage.cards.d; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeadRevels extends CardImpl { + + private static final FilterCard filter = new FilterCreatureCard("creature cards from your graveyard"); + + public DeadRevels(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); + + // Return up to two target creature cards from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, filter)); + + // Spectacle {1}{B} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{1}{B}"))); + } + + private DeadRevels(final DeadRevels card) { + super(card); + } + + @Override + public DeadRevels copy() { + return new DeadRevels(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeadbridgeChant.java b/Mage.Sets/src/mage/cards/d/DeadbridgeChant.java index 9857b7b602..a7624a76ce 100644 --- a/Mage.Sets/src/mage/cards/d/DeadbridgeChant.java +++ b/Mage.Sets/src/mage/cards/d/DeadbridgeChant.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -21,13 +20,10 @@ import mage.players.Player; * * @author LevelX2 */ - - public final class DeadbridgeChant extends CardImpl { public DeadbridgeChant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{B}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{B}{G}"); // When Deadbridge Chant enters the battlefield, put the top ten cards of your library into your graveyard. this.addAbility(new EntersBattlefieldTriggeredAbility(new PutTopCardOfLibraryIntoGraveControllerEffect(10))); @@ -64,9 +60,10 @@ class DeadbridgeChantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null && !player.getGraveyard().isEmpty()) { - Card card = player.getGraveyard().getRandom(game); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && !controller.getGraveyard().isEmpty()) { + Card card = controller.getGraveyard().getRandom(game); if (card != null) { Zone targetZone = Zone.HAND; String text = " put into hand of "; @@ -74,8 +71,8 @@ class DeadbridgeChantEffect extends OneShotEffect { targetZone = Zone.BATTLEFIELD; text = " put onto battlefield for "; } - card.moveToZone(targetZone, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder("Deadbridge Chant: ").append(card.getName()).append(text).append(player.getLogName()).toString()); + controller.moveCards(card, targetZone, source, game); + game.informPlayers("Deadbridge Chant: " + card.getName() + text + controller.getLogName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java b/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java index 88ace23bc5..8ef3bfb6bd 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeBrawler.java @@ -1,21 +1,21 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.constants.SubType; -import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; +import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DeadeyeBrawler extends CardImpl { @@ -37,7 +37,8 @@ public final class DeadeyeBrawler extends CardImpl { // Whenever Deadeye Brawler deals combat damage to a player, if you have the city's blessing, draw a card. this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new DrawCardSourceControllerEffect(1), false, false), CitysBlessingCondition.instance, - "Whenever {this} deals combat damage to a player, if you have the city's blessing, draw a card.")); + "Whenever {this} deals combat damage to a player, if you have the city's blessing, draw a card.") + .addHint(CitysBlessingHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java index eeb855dd35..f6ef1914b3 100644 --- a/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java +++ b/Mage.Sets/src/mage/cards/d/DeadeyeHarpooner.java @@ -24,10 +24,10 @@ import mage.watchers.common.RevoltWatcher; */ public final class DeadeyeHarpooner extends CardImpl { - private final static FilterOpponentsCreaturePermanent filter = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); + private static final FilterOpponentsCreaturePermanent filter = new FilterOpponentsCreaturePermanent("tapped creature an opponent controls"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public DeadeyeHarpooner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DeadlockTrap.java b/Mage.Sets/src/mage/cards/d/DeadlockTrap.java index 46ce08b19d..1a4c723327 100644 --- a/Mage.Sets/src/mage/cards/d/DeadlockTrap.java +++ b/Mage.Sets/src/mage/cards/d/DeadlockTrap.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -20,14 +18,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreatureOrPlaneswalker; +import java.util.UUID; + /** - * * @author spjspj */ public final class DeadlockTrap extends CardImpl { public DeadlockTrap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // Deadlock Trap enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); @@ -70,7 +69,7 @@ class DeadlockTrapCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/d/DeafeningClarion.java b/Mage.Sets/src/mage/cards/d/DeafeningClarion.java index 70dbbd52c8..ad002fdd2a 100644 --- a/Mage.Sets/src/mage/cards/d/DeafeningClarion.java +++ b/Mage.Sets/src/mage/cards/d/DeafeningClarion.java @@ -31,7 +31,7 @@ public final class DeafeningClarion extends CardImpl { // • Creatures you control gain lifelink until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new GainAbilityControlledEffect( + mode.addEffect(new GainAbilityControlledEffect( LifelinkAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES diff --git a/Mage.Sets/src/mage/cards/d/DealBroker.java b/Mage.Sets/src/mage/cards/d/DealBroker.java new file mode 100644 index 0000000000..432f583693 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DealBroker.java @@ -0,0 +1,50 @@ + +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public final class DealBroker extends CardImpl { + + public DealBroker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT, CardType.CREATURE},"{3}"); + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // TODO: Draft specific abilities not implemented + // Draft Deal Broker face up. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Draft Deal Broker face up."))); + + // Immediately after the draft, you may reveal a card in your card pool. Each other player may offer you one card in their card pool in exchange. You may accept any one offer. + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("Immediately after the draft, you may reveal a card in your card pool. " + + "Each other player may offer you one card in their card pool in exchange. You may accept any one offer."))); + + // {T}: Draw a card, then discard a card. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new TapSourceCost())); + } + + public DealBroker(final DealBroker card) { + super(card); + } + + @Override + public DealBroker copy() { + return new DealBroker(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/d/DeathCloud.java b/Mage.Sets/src/mage/cards/d/DeathCloud.java index c239907ad6..1ce4f41120 100644 --- a/Mage.Sets/src/mage/cards/d/DeathCloud.java +++ b/Mage.Sets/src/mage/cards/d/DeathCloud.java @@ -25,7 +25,7 @@ public final class DeathCloud extends CardImpl { // Each player loses X life, discards X cards, sacrifices X creatures, then sacrifices X lands. - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new LoseLifeAllPlayersEffect(xValue)); Effect effect = new DiscardEachPlayerEffect(xValue, false); effect.setText(", discards X cards"); diff --git a/Mage.Sets/src/mage/cards/d/DeathDenied.java b/Mage.Sets/src/mage/cards/d/DeathDenied.java index 0fe70f8a59..baf509a483 100644 --- a/Mage.Sets/src/mage/cards/d/DeathDenied.java +++ b/Mage.Sets/src/mage/cards/d/DeathDenied.java @@ -2,7 +2,6 @@ package mage.cards.d; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; @@ -13,35 +12,24 @@ import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import java.util.UUID; /** - * * @author LevelX2 */ public final class DeathDenied extends CardImpl { public DeathDenied(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}{B}"); this.subtype.add(SubType.ARCANE); // Return X target creature cards from your graveyard to your hand. Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target creature cards from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(1, new FilterCreatureCard())); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? " creature cards" : "creature card").append(" from your graveyard").toString())); - ability.addTarget(target); - } + this.getSpellAbility().setTargetAdjuster(DeathDeniedAdjuster.instance); } public DeathDenied(final DeathDenied card) { @@ -53,3 +41,15 @@ public final class DeathDenied extends CardImpl { return new DeathDenied(this); } } + +enum DeathDeniedAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? " creature cards" : "creature card").append(" from your graveyard").toString())); + ability.addTarget(target); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathGrasp.java b/Mage.Sets/src/mage/cards/d/DeathGrasp.java index e0e3426b6e..114635e43c 100644 --- a/Mage.Sets/src/mage/cards/d/DeathGrasp.java +++ b/Mage.Sets/src/mage/cards/d/DeathGrasp.java @@ -21,8 +21,8 @@ public final class DeathGrasp extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{W}{B}"); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); - this.getSpellAbility().addEffect(new GainLifeEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/d/DeathMatch.java b/Mage.Sets/src/mage/cards/d/DeathMatch.java index d5827dfbd0..389b27cd26 100644 --- a/Mage.Sets/src/mage/cards/d/DeathMatch.java +++ b/Mage.Sets/src/mage/cards/d/DeathMatch.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -13,17 +11,16 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FirstTargetPointer; +import java.util.UUID; + /** - * * @author LoneFox - * */ public final class DeathMatch extends CardImpl { - private final UUID originalId; - public DeathMatch(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); @@ -32,24 +29,12 @@ public final class DeathMatch extends CardImpl { Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new DeathMatchEffect(), StaticFilters.FILTER_PERMANENT_CREATURE, false, SetTargetPointer.PLAYER, ""); ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(DeathMatchAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - UUID controllerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); - if (controllerId != null) { - ability.getTargets().get(0).setTargetController(controllerId); - ability.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); - } - } } public DeathMatch(final DeathMatch card) { super(card); - this.originalId = card.originalId; } @Override @@ -58,6 +43,19 @@ public final class DeathMatch extends CardImpl { } } +enum DeathMatchAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + UUID controllerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + if (controllerId != null) { + ability.getTargets().get(0).setTargetController(controllerId); + ability.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); + } + } +} + class DeathMatchEffect extends OneShotEffect { public DeathMatchEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DeathMutation.java b/Mage.Sets/src/mage/cards/d/DeathMutation.java index d24bec85c2..879b21f6d8 100644 --- a/Mage.Sets/src/mage/cards/d/DeathMutation.java +++ b/Mage.Sets/src/mage/cards/d/DeathMutation.java @@ -35,7 +35,7 @@ public final class DeathMutation extends CardImpl { this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); this.getSpellAbility().addTarget(new TargetPermanent(filter)); // create X 1/1 green Saproling creature tokens, where X is that creature's converted mana cost. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new TargetConvertedManaCost())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), TargetConvertedManaCost.instance)); } public DeathMutation(final DeathMutation card) { diff --git a/Mage.Sets/src/mage/cards/d/DeathOrGlory.java b/Mage.Sets/src/mage/cards/d/DeathOrGlory.java new file mode 100644 index 0000000000..85efe75cd0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeathOrGlory.java @@ -0,0 +1,128 @@ + +package mage.cards.d; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public final class DeathOrGlory extends CardImpl { + + public DeathOrGlory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + // Separate all creature cards in your graveyard into two piles. Exile the pile of an opponent’s choice and return the other to the battlefield. + this.getSpellAbility().addEffect(new DeathOrGloryEffect()); + } + + public DeathOrGlory(final DeathOrGlory card) { + super(card); + } + + @Override + public DeathOrGlory copy() { + return new DeathOrGlory(this); + } +} + +class DeathOrGloryEffect extends OneShotEffect { + + DeathOrGloryEffect() { + super(Outcome.Benefit); + this.staticText = "Separate all creature cards in your graveyard into two piles. Exile the pile of an opponent’s choice and return the other to the battlefield"; + } + + DeathOrGloryEffect(final DeathOrGloryEffect effect) { + super(effect); + } + + @Override + public DeathOrGloryEffect copy() { + return new DeathOrGloryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Cards cards = new CardsImpl(controller.getGraveyard().getCards(new FilterCreatureCard(), game)); + if (!cards.isEmpty()) { + TargetCard targetCards = new TargetCard(0, cards.size(), Zone.EXILED, new FilterCard("cards to put in the first pile")); + List pile1 = new ArrayList<>(); + if (controller.choose(Outcome.Neutral, cards, targetCards, game)) { + List targets = targetCards.getTargets(); + for (UUID targetId : targets) { + Card card = cards.get(targetId, game); + if (card != null) { + pile1.add(card); + cards.remove(card); + } + } + } + List pile2 = new ArrayList<>(); + pile2.addAll(cards.getCards(game)); + + StringBuilder sb = new StringBuilder("First pile of ").append(controller.getLogName()).append(": "); + sb.append(pile1.stream().map(Card::getLogName).collect(Collectors.joining(", "))); + game.informPlayers(sb.toString()); + + sb = new StringBuilder("Second pile of ").append(controller.getLogName()).append(": "); + sb.append(pile2.stream().map(Card::getLogName).collect(Collectors.joining(", "))); + game.informPlayers(sb.toString()); + + Set opponents = game.getOpponents(source.getControllerId()); + if (!opponents.isEmpty()) { + Player opponent = game.getPlayer(opponents.iterator().next()); + if (opponents.size() > 1) { + Target targetOpponent = new TargetOpponent(true); + if (controller.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) { + opponent = game.getPlayer(targetOpponent.getFirstTarget()); + game.informPlayers(controller.getLogName() + " chose " + opponent.getLogName() + " to choose his pile"); + } + } + if (opponent != null) { + boolean choice = opponent.choosePile(outcome, "Choose a pile to put onto the battlefield.", pile1, pile2, game); + + Zone pile1Zone = Zone.EXILED; + Zone pile2Zone = Zone.BATTLEFIELD; + if (choice) { + pile1Zone = Zone.BATTLEFIELD; + pile2Zone = Zone.EXILED; + } + Set pile1Set = new HashSet<>(); + Set pile2Set = new HashSet<>(); + pile1Set.addAll(pile1); + pile2Set.addAll(pile2); + controller.moveCards(pile1Set, pile1Zone, source, game, false, false, false, null); + controller.moveCards(pile2Set, pile2Zone, source, game, false, false, false, null); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeathStroke.java b/Mage.Sets/src/mage/cards/d/DeathStroke.java index c47e389c79..db727116c4 100644 --- a/Mage.Sets/src/mage/cards/d/DeathStroke.java +++ b/Mage.Sets/src/mage/cards/d/DeathStroke.java @@ -19,7 +19,7 @@ public final class DeathStroke extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public DeathStroke(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DeathWind.java b/Mage.Sets/src/mage/cards/d/DeathWind.java index 69fbaadadf..663ba2f604 100644 --- a/Mage.Sets/src/mage/cards/d/DeathWind.java +++ b/Mage.Sets/src/mage/cards/d/DeathWind.java @@ -22,7 +22,7 @@ public final class DeathWind extends CardImpl { // Target creature gets -X/-X until end of turn. - DynamicValue x = new SignInversionDynamicValue(new ManacostVariableValue()); + DynamicValue x = new SignInversionDynamicValue(ManacostVariableValue.instance); this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java b/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java index 4aa59062ae..023015b9e0 100644 --- a/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java +++ b/Mage.Sets/src/mage/cards/d/DeathbringerRegent.java @@ -29,7 +29,7 @@ public final class DeathbringerRegent extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DeathbringerRegent(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DeathcapCultivator.java b/Mage.Sets/src/mage/cards/d/DeathcapCultivator.java index 6ce0f5c06f..c1d241523b 100644 --- a/Mage.Sets/src/mage/cards/d/DeathcapCultivator.java +++ b/Mage.Sets/src/mage/cards/d/DeathcapCultivator.java @@ -1,12 +1,13 @@ - package mage.cards.d; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.mana.BlackManaAbility; import mage.abilities.mana.GreenManaAbility; @@ -18,13 +19,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class DeathcapCultivator extends CardImpl { public DeathcapCultivator(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.DRUID); this.power = new MageInt(2); @@ -33,11 +33,12 @@ public final class DeathcapCultivator extends CardImpl { // {T}: Add {B} or {G}. this.addAbility(new BlackManaAbility()); this.addAbility(new GreenManaAbility()); - + // Delirium — Deathcap Cultivator has deathtouch as long as there are four or more card types among cards in your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield), - DeliriumCondition.instance, "Delirium — {this} has deathtouch as long as there are four or more card types among cards in your graveyard"))); + DeliriumCondition.instance, "Delirium — {this} has deathtouch as long as there are four or more card types among cards in your graveyard")) + .addHint(DeliriumHint.instance)); } public DeathcapCultivator(final DeathcapCultivator card) { diff --git a/Mage.Sets/src/mage/cards/d/DeathcultRogue.java b/Mage.Sets/src/mage/cards/d/DeathcultRogue.java index cf5b63bea8..c161b415bc 100644 --- a/Mage.Sets/src/mage/cards/d/DeathcultRogue.java +++ b/Mage.Sets/src/mage/cards/d/DeathcultRogue.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -15,14 +13,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DeathcultRogue extends CardImpl { public DeathcultRogue(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U/B}{U/B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U/B}{U/B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); @@ -44,7 +43,7 @@ public final class DeathcultRogue extends CardImpl { } } -class DeathcultRogueRestrictionEffect extends RestrictionEffect { +class DeathcultRogueRestrictionEffect extends RestrictionEffect { public DeathcultRogueRestrictionEffect() { super(Duration.WhileOnBattlefield); @@ -57,18 +56,12 @@ class DeathcultRogueRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (blocker.hasSubtype(SubType.ROGUE, game)) { - return true; - } - return false; + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return blocker.hasSubtype(SubType.ROGUE, game); } @Override diff --git a/Mage.Sets/src/mage/cards/d/DeathforgeShaman.java b/Mage.Sets/src/mage/cards/d/DeathforgeShaman.java index a9c707fd5a..7ebbe2c241 100644 --- a/Mage.Sets/src/mage/cards/d/DeathforgeShaman.java +++ b/Mage.Sets/src/mage/cards/d/DeathforgeShaman.java @@ -69,7 +69,7 @@ class DeathforgeShamanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - DynamicValue value = new MultikickerCount(); + DynamicValue value = MultikickerCount.instance; int damage = value.calculate(game, source, this) * 2; return new DamageTargetEffect(damage).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/d/DeathlessAncient.java b/Mage.Sets/src/mage/cards/d/DeathlessAncient.java index 5d7e604682..6719a9fafa 100644 --- a/Mage.Sets/src/mage/cards/d/DeathlessAncient.java +++ b/Mage.Sets/src/mage/cards/d/DeathlessAncient.java @@ -27,7 +27,7 @@ public final class DeathlessAncient extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Vampires you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/d/DeathlessBehemoth.java b/Mage.Sets/src/mage/cards/d/DeathlessBehemoth.java index 393d20d1e6..0cce899f7e 100644 --- a/Mage.Sets/src/mage/cards/d/DeathlessBehemoth.java +++ b/Mage.Sets/src/mage/cards/d/DeathlessBehemoth.java @@ -23,7 +23,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class DeathlessBehemoth extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("two Eldrazi Scions"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("two Eldrazi Scions"); static { filter.add(Predicates.and( diff --git a/Mage.Sets/src/mage/cards/d/DeathsShadow.java b/Mage.Sets/src/mage/cards/d/DeathsShadow.java index 2591c2d11f..5fa0ee15d9 100644 --- a/Mage.Sets/src/mage/cards/d/DeathsShadow.java +++ b/Mage.Sets/src/mage/cards/d/DeathsShadow.java @@ -28,7 +28,7 @@ public final class DeathsShadow extends CardImpl { this.toughness = new MageInt(13); // Death's Shadow gets -X/-X, where X is your life total. - SignInversionDynamicValue x = new SignInversionDynamicValue(new ControllerLifeCount(), false); + SignInversionDynamicValue x = new SignInversionDynamicValue(ControllerLifeCount.instance, false); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(x, x, Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/cards/d/Deathsprout.java b/Mage.Sets/src/mage/cards/d/Deathsprout.java new file mode 100644 index 0000000000..e7a64af570 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Deathsprout.java @@ -0,0 +1,38 @@ +package mage.cards.d; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Deathsprout extends CardImpl { + + public Deathsprout(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}{B}{G}"); + + // Destroy target creature. Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. + this.getSpellAbility().addEffect(new DestroyTargetEffect().setText("Destroy target creature.")); + this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( + new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND), true + )); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Deathsprout(final Deathsprout card) { + super(card); + } + + @Override + public Deathsprout copy() { + return new Deathsprout(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DebtorsTransport.java b/Mage.Sets/src/mage/cards/d/DebtorsTransport.java new file mode 100644 index 0000000000..ef22d1d33f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DebtorsTransport.java @@ -0,0 +1,36 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +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 DebtorsTransport extends CardImpl { + + public DebtorsTransport(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); + + this.subtype.add(SubType.THRULL); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // Afterlife 2 + this.addAbility(new AfterlifeAbility(2)); + } + + private DebtorsTransport(final DebtorsTransport card) { + super(card); + } + + @Override + public DebtorsTransport copy() { + return new DebtorsTransport(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DecayingSoil.java b/Mage.Sets/src/mage/cards/d/DecayingSoil.java index d32aa25a43..0f6f005166 100644 --- a/Mage.Sets/src/mage/cards/d/DecayingSoil.java +++ b/Mage.Sets/src/mage/cards/d/DecayingSoil.java @@ -40,7 +40,7 @@ public final class DecayingSoil extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static{ filter.add(new OwnerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public DecayingSoil(UUID ownerId, CardSetInfo setInfo) { @@ -99,7 +99,7 @@ class DecayingSoilTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && filter.match(permanent, this.getSourceId(), this.getControllerId(), game)) { getEffects().get(0).setTargetPointer(new FixedTarget(permanent.getId())); @@ -119,7 +119,7 @@ class DecayingSoilTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever a ").append(filter.getMessage()).append(" is put into your graveyard from the battlefield, ").append(super.getRule()).toString(); + return "Whenever a " + filter.getMessage() + " is put into your graveyard from the battlefield, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java index f0a142803f..04fa192c34 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverExarch.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverExarch.java @@ -43,8 +43,8 @@ public final class DeceiverExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new UntapTargetEffect()); ability.addTarget(new TargetControlledPermanent()); Mode mode = new Mode(); - mode.getEffects().add(new TapTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new TapTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java index 1cce7d6d6f..d11d20163e 100644 --- a/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java +++ b/Mage.Sets/src/mage/cards/d/DeceiverOfForm.java @@ -76,7 +76,7 @@ class DeceiverOfFormEffect extends OneShotEffect { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game)) { if (!permanent.getId().equals(sourceObject.getId())) { Permanent newBluePrint = null; - newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game); + newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); newBluePrint.assignNewId(); CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, newBluePrint, permanent.getId()); copyEffect.newId(); diff --git a/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java b/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java index 2d0c35432a..75e0cc4bb4 100644 --- a/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java +++ b/Mage.Sets/src/mage/cards/d/DecimatorBeetle.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -13,24 +12,29 @@ import mage.abilities.effects.common.counter.RemoveCounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author spjspj */ public final class DecimatorBeetle extends CardImpl { - private final UUID originalId; + public static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } public DecimatorBeetle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{G}"); @@ -46,29 +50,14 @@ public final class DecimatorBeetle extends CardImpl { this.addAbility(ability); // Whenever Decimator Beetle attacks, remove a -1/-1 counter from target creature you control and put a -1/-1 counter on up to one target creature defending player controls. - Ability ability2 = new AttacksTriggeredAbility(new DecimatorBeetleEffect(), false); - ability2.addTarget(new TargetControlledCreaturePermanent()); - ability2.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); - this.addAbility(ability2); - this.originalId = ability2.getOriginalId(); + ability = new AttacksTriggeredAbility(new DecimatorBeetleEffect(), false); + ability.addTarget(new TargetControlledCreaturePermanent()); + ability.addTarget(new TargetCreaturePermanent(0, 1, filter, false)); + this.addAbility(ability); } public DecimatorBeetle(final DecimatorBeetle card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - ability.addTarget(new TargetControlledCreaturePermanent()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); - filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); - ability.addTarget(target); - } } @Override diff --git a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java index f53ddd93ae..45cfb5b117 100644 --- a/Mage.Sets/src/mage/cards/d/DeclarationInStone.java +++ b/Mage.Sets/src/mage/cards/d/DeclarationInStone.java @@ -1,9 +1,5 @@ - package mage.cards.d; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -20,9 +16,13 @@ import mage.game.permanent.PermanentToken; import mage.game.permanent.token.ClueArtifactToken; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class DeclarationInStone extends CardImpl { @@ -66,7 +66,7 @@ class DeclarationInStoneEffect extends OneShotEffect { if (targetPermanent != null) { Set cardsToExile = new HashSet<>(); int nonTokenCount = 0; - if (targetPermanent.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature cardsToExile.add(targetPermanent); if (!(targetPermanent instanceof PermanentToken)) { nonTokenCount++; @@ -78,7 +78,7 @@ class DeclarationInStoneEffect extends OneShotEffect { } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, targetPermanent.getControllerId(), game)) { if (!permanent.getId().equals(targetPermanent.getId()) - && permanent.getName().equals(targetPermanent.getName())) { + && CardUtil.haveSameNames(permanent, targetPermanent)) { cardsToExile.add(permanent); // exiled count only matters for non-tokens if (!(permanent instanceof PermanentToken)) { diff --git a/Mage.Sets/src/mage/cards/d/DecoctionModule.java b/Mage.Sets/src/mage/cards/d/DecoctionModule.java index 95b4a39c12..c870592f42 100644 --- a/Mage.Sets/src/mage/cards/d/DecoctionModule.java +++ b/Mage.Sets/src/mage/cards/d/DecoctionModule.java @@ -1,9 +1,8 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; @@ -13,19 +12,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class DecoctionModule extends CardImpl { public DecoctionModule(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Whenever a creature enters the battlefield under your control, you get {E}. - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new GetEnergyCountersControllerEffect(1))); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new GetEnergyCountersControllerEffect(1), + StaticFilters.FILTER_PERMANENT_CREATURE_A, + false) + ); // {4}, {T}: Return target creature you control to its owner's hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new GenericManaCost(4)); diff --git a/Mage.Sets/src/mage/cards/d/DecoratedChampion.java b/Mage.Sets/src/mage/cards/d/DecoratedChampion.java index aff6d8543b..bdae9b0118 100644 --- a/Mage.Sets/src/mage/cards/d/DecoratedChampion.java +++ b/Mage.Sets/src/mage/cards/d/DecoratedChampion.java @@ -22,7 +22,7 @@ public final class DecoratedChampion extends CardImpl { private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "another Warrior"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DecoratedChampion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java b/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java index 27aa099dcd..2da79ce805 100644 --- a/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java +++ b/Mage.Sets/src/mage/cards/d/DecreeOfJustice.java @@ -32,7 +32,7 @@ public final class DecreeOfJustice extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{2}{W}{W}"); // Create X 4/4 white Angel creature tokens with flying. - this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), ManacostVariableValue.instance)); // Cycling {2}{W} this.addAbility(new CyclingAbility(new ManaCostsImpl<>("{2}{W}"))); diff --git a/Mage.Sets/src/mage/cards/d/DeeprootElite.java b/Mage.Sets/src/mage/cards/d/DeeprootElite.java index 8f2133da26..ca4130031c 100644 --- a/Mage.Sets/src/mage/cards/d/DeeprootElite.java +++ b/Mage.Sets/src/mage/cards/d/DeeprootElite.java @@ -26,7 +26,7 @@ public final class DeeprootElite extends CardImpl { private static final FilterPermanent filterYourAnotherMerfolk = new FilterPermanent(SubType.MERFOLK, "another " + SubType.MERFOLK.toString()); static { - filterYourAnotherMerfolk.add(new AnotherPredicate()); + filterYourAnotherMerfolk.add(AnotherPredicate.instance); filterYourAnotherMerfolk.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/Deface.java b/Mage.Sets/src/mage/cards/d/Deface.java new file mode 100644 index 0000000000..fa2d602b2e --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Deface.java @@ -0,0 +1,50 @@ +package mage.cards.d; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetArtifactPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Deface extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with defender"); + + static { + filter.add(new AbilityPredicate(DefenderAbility.class)); + } + + public Deface(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}"); + + // Choose one — + // • Destroy target artifact. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + + // • Destroy target creature with defender. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addMode(mode); + } + + private Deface(final Deface card) { + super(card); + } + + @Override + public Deface copy() { + return new Deface(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java b/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java index b71d27ff4f..731df0f5c7 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java +++ b/Mage.Sets/src/mage/cards/d/DefiantGreatmaw.java @@ -60,7 +60,7 @@ class DefiantGreatmawTriggeredAbility extends TriggeredAbilityImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/DefiantOgre.java b/Mage.Sets/src/mage/cards/d/DefiantOgre.java index 47d56737bf..96405180ce 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantOgre.java +++ b/Mage.Sets/src/mage/cards/d/DefiantOgre.java @@ -33,8 +33,8 @@ public final class DefiantOgre extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); // * Destroy target artifact. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DefiantSalvager.java b/Mage.Sets/src/mage/cards/d/DefiantSalvager.java index 8a6a3fc592..7abc7ce334 100644 --- a/Mage.Sets/src/mage/cards/d/DefiantSalvager.java +++ b/Mage.Sets/src/mage/cards/d/DefiantSalvager.java @@ -24,7 +24,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class DefiantSalvager extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or creature"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or creature"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE))); diff --git a/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java b/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java index 0e97a8be10..2e1f05f99d 100644 --- a/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java +++ b/Mage.Sets/src/mage/cards/d/DefilerOfSouls.java @@ -72,7 +72,7 @@ class DefilerOfSoulsEffect extends OneShotEffect { if (player == null) { return false; } - filter.add(new MonocoloredPredicate()); + filter.add(MonocoloredPredicate.instance); int amount; int realCount = game.getBattlefield().countAll(filter, player.getId(), game); @@ -90,7 +90,7 @@ class DefilerOfSoulsEffect extends OneShotEffect { } for ( int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent((UUID)target.getTargets().get(idx)); + Permanent permanent = game.getPermanent(target.getTargets().get(idx)); if ( permanent != null ) { abilityApplied |= permanent.sacrifice(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/d/Deicide.java b/Mage.Sets/src/mage/cards/d/Deicide.java index 3e72df10a8..a1fa7e3855 100644 --- a/Mage.Sets/src/mage/cards/d/Deicide.java +++ b/Mage.Sets/src/mage/cards/d/Deicide.java @@ -68,7 +68,7 @@ class DeicideExileEffect extends SearchTargetGraveyardHandLibraryForCardNameAndE Card cardInExile = game.getExile().getCard(targetEnchantment.getId(), game); if (cardInExile != null && cardInExile.hasSubtype(SubType.GOD, game)) { Player enchantmentController = game.getPlayer(targetEnchantment.getControllerId()); - return super.applySearchAndExile(game, source, cardInExile.getName(), enchantmentController.getId()); + return enchantmentController != null && super.applySearchAndExile(game, source, cardInExile.getName(), enchantmentController.getId()); } } } diff --git a/Mage.Sets/src/mage/cards/d/DelayTactic.java b/Mage.Sets/src/mage/cards/d/DelayTactic.java index 0353df6c84..7607fe00f8 100644 --- a/Mage.Sets/src/mage/cards/d/DelayTactic.java +++ b/Mage.Sets/src/mage/cards/d/DelayTactic.java @@ -41,10 +41,10 @@ public final class DelayTactic extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent()) .setText("Creatures you control gain hexproof until end of turn")); - // Creatures target opponent controls don't untap during his or her next untap step. + // Creatures target opponent controls don't untap during their next untap step. Mode mode = new Mode(); - mode.getEffects().add(new DelayTacticEffect()); - mode.getTargets().add(new TargetOpponent()); + mode.addEffect(new DelayTacticEffect()); + mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); } @@ -63,7 +63,7 @@ class DelayTacticEffect extends OneShotEffect { DelayTacticEffect() { super(Outcome.Benefit); - this.staticText = "Creatures target opponent controls don't untap during his or her next untap step"; + this.staticText = "Creatures target opponent controls don't untap during their next untap step"; } DelayTacticEffect(final DelayTacticEffect effect) { diff --git a/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java b/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java new file mode 100644 index 0000000000..dd8cf7be8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeliverUntoEvil.java @@ -0,0 +1,102 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeliverUntoEvil extends CardImpl { + + public DeliverUntoEvil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Choose up to four target cards in your graveyard. If you control a Bolas planeswalker, return those cards to your hand. Otherwise, an opponent chooses two of them. Leave the chosen cards in your graveyard and put the rest into your hand. + this.getSpellAbility().addEffect(new DeliverUntoEvilEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 4)); + + // Exile Deliver Unto Evil. + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + private DeliverUntoEvil(final DeliverUntoEvil card) { + super(card); + } + + @Override + public DeliverUntoEvil copy() { + return new DeliverUntoEvil(this); + } +} + +class DeliverUntoEvilEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent(SubType.BOLAS); + private static final FilterCard filter2 = new FilterCard("cards (to leave in the graveyard)"); + + DeliverUntoEvilEffect() { + super(Outcome.Benefit); + staticText = "Choose up to four target cards in your graveyard. If you control a Bolas planeswalker, " + + "return those cards to your hand. Otherwise, an opponent chooses two of them. " + + "Leave the chosen cards in your graveyard and put the rest into your hand.
    "; + } + + private DeliverUntoEvilEffect(final DeliverUntoEvilEffect effect) { + super(effect); + } + + @Override + public DeliverUntoEvilEffect copy() { + return new DeliverUntoEvilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(source.getTargets().get(0).getTargets()); + if (cards.isEmpty()) { + return false; + } + if (!game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game).isEmpty()) { + return player.moveCards(cards, Zone.HAND, source, game); + } + TargetOpponent targetOpponent = new TargetOpponent(); + targetOpponent.setNotTarget(true); + if (!player.choose(outcome, targetOpponent, source.getSourceId(), game)) { + return false; + } + Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); + if (opponent == null) { + return false; + } + TargetCard targetCard = new TargetCardInGraveyard(Math.min(2, cards.size()), filter2); + if (!opponent.choose(outcome, cards, targetCard, game)) { + return false; + } + cards.removeAll(targetCard.getTargets()); + return player.moveCards(cards, Zone.HAND, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/Delraich.java b/Mage.Sets/src/mage/cards/d/Delraich.java index 4691596016..135de65e67 100644 --- a/Mage.Sets/src/mage/cards/d/Delraich.java +++ b/Mage.Sets/src/mage/cards/d/Delraich.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.costs.AlternativeCostSourceAbility; @@ -15,13 +14,15 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Delraich extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("black creature"); + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("black creature"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); @@ -34,15 +35,16 @@ public final class Delraich extends CardImpl { this.power = new MageInt(6); this.toughness = new MageInt(6); + // You may sacrifice three black creatures rather than pay Delraich's mana cost. + this.addAbility(new AlternativeCostSourceAbility(new SacrificeTargetCost( + new TargetControlledPermanent(3, 3, filter, false) + ))); + // Trample this.addAbility(TrampleAbility.getInstance()); - - // You may sacrifice three black creatures rather than pay Delraich's mana cost. - AlternativeCostSourceAbility alternateCosts = new AlternativeCostSourceAbility(new SacrificeTargetCost(new TargetControlledPermanent(3, 3, filter, false))); - this.addAbility(alternateCosts); } - public Delraich(final Delraich card) { + private Delraich(final Delraich card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java index 2b2ea06194..3e2faf4dae 100644 --- a/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java +++ b/Mage.Sets/src/mage/cards/d/DelverOfSecrets.java @@ -76,6 +76,9 @@ class DelverOfSecretsEffect extends OneShotEffect { if (player != null && sourcePermanent != null) { if (player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); + if(card == null){ + return false; + } Cards cards = new CardsImpl(); cards.add(card); player.lookAtCards(sourcePermanent.getName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/d/DementiaSliver.java b/Mage.Sets/src/mage/cards/d/DementiaSliver.java index b6ed719123..40719b4412 100644 --- a/Mage.Sets/src/mage/cards/d/DementiaSliver.java +++ b/Mage.Sets/src/mage/cards/d/DementiaSliver.java @@ -1,6 +1,5 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -18,9 +17,11 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class DementiaSliver extends CardImpl { @@ -44,9 +45,9 @@ public final class DementiaSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(gainedAbility, Duration.WhileOnBattlefield, filter, "All Slivers have \"{T}: Choose a card name. " - + "Target opponent reveals a card at random from their hand." - + " If that card has the chosen name, that player discards it." - + " Activate this ability only during your turn.\"" + + "Target opponent reveals a card at random from their hand." + + " If that card has the chosen name, that player discards it." + + " Activate this ability only during your turn.\"" ) )); } @@ -84,7 +85,7 @@ class DementiaSliverEffect extends OneShotEffect { if (card != null) { revealed.add(card); opponent.revealCards(sourceObject.getName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { opponent.discard(card, source, game); } } diff --git a/Mage.Sets/src/mage/cards/d/Demonfire.java b/Mage.Sets/src/mage/cards/d/Demonfire.java index 71711b70c1..b8dfbc7148 100644 --- a/Mage.Sets/src/mage/cards/d/Demonfire.java +++ b/Mage.Sets/src/mage/cards/d/Demonfire.java @@ -31,7 +31,7 @@ public final class Demonfire extends CardImpl { // Demonfire deals X damage to any target. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(new ManacostVariableValue()), + new DamageTargetEffect(ManacostVariableValue.instance), new InvertCondition(HellbentCondition.instance), "{this} deals X damage to any target")); @@ -41,7 +41,7 @@ public final class Demonfire extends CardImpl { // Hellbent - If you have no cards in hand, Demonfire can't be countered and the damage can't be prevented. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetEffect(new ManacostVariableValue(), false), + new DamageTargetEffect(ManacostVariableValue.instance, false), HellbentCondition.instance, "
    Hellbent — If you have no cards in hand, this spell can't be countered and the damage can't be prevented.")); // can't be countered diff --git a/Mage.Sets/src/mage/cards/d/DemonicPact.java b/Mage.Sets/src/mage/cards/d/DemonicPact.java index aefe13d81c..bfea1c7652 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicPact.java +++ b/Mage.Sets/src/mage/cards/d/DemonicPact.java @@ -38,18 +38,18 @@ public final class DemonicPact extends CardImpl { // - Target opponent discards two cards Mode mode = new Mode(); - mode.getTargets().add(new TargetOpponent()); - mode.getEffects().add(new DiscardTargetEffect(2)); + mode.addTarget(new TargetOpponent()); + mode.addEffect(new DiscardTargetEffect(2)); ability.addMode(mode); // - Draw two cards mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(2)); + mode.addEffect(new DrawCardSourceControllerEffect(2)); ability.addMode(mode); // - You lose the game. mode = new Mode(); - mode.getEffects().add(new LoseGameSourceControllerEffect()); + mode.addEffect(new LoseGameSourceControllerEffect()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java b/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java index 252b91460c..13671d2f68 100644 --- a/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java +++ b/Mage.Sets/src/mage/cards/d/DemonicTaskmaster.java @@ -24,7 +24,7 @@ public final class DemonicTaskmaster extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature other than Demonic Taskmaster"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DemonicTaskmaster(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DemonlordOfAshmouth.java b/Mage.Sets/src/mage/cards/d/DemonlordOfAshmouth.java index e409e89cb4..23928b343a 100644 --- a/Mage.Sets/src/mage/cards/d/DemonlordOfAshmouth.java +++ b/Mage.Sets/src/mage/cards/d/DemonlordOfAshmouth.java @@ -24,7 +24,7 @@ public final class DemonlordOfAshmouth extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(" another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DemonlordOfAshmouth(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DemonsHorn.java b/Mage.Sets/src/mage/cards/d/DemonsHorn.java index bc8400022d..71e71e2d01 100644 --- a/Mage.Sets/src/mage/cards/d/DemonsHorn.java +++ b/Mage.Sets/src/mage/cards/d/DemonsHorn.java @@ -19,7 +19,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class DemonsHorn extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a black spell"); + private static final FilterSpell filter = new FilterSpell("a black spell"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); diff --git a/Mage.Sets/src/mage/cards/d/Denied.java b/Mage.Sets/src/mage/cards/d/Denied.java index 534d1a1a5f..b5825c8b1e 100644 --- a/Mage.Sets/src/mage/cards/d/Denied.java +++ b/Mage.Sets/src/mage/cards/d/Denied.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; @@ -11,19 +9,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; -import mage.players.Player; import mage.game.stack.Spell; +import mage.players.Player; import mage.target.TargetSpell; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class Denied extends CardImpl { public Denied(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + // Choose a card name, then target spell's controller reveals their hand. If a card with the chosen name is revealed this way, counter that spell. this.getSpellAbility().addEffect(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL)); this.getSpellAbility().addEffect(new DeniedEffect()); @@ -58,12 +58,12 @@ class DeniedEffect extends OneShotEffect { return true; } Player player = game.getPlayer(targetSpell.getControllerId()); - Object object = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + Object object = game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (player != null && object instanceof String) { player.revealCards("Denied!", player.getHand(), game, true); String namedCard = (String) object; for (Card card : player.getHand().getCards(game)) { - if (card != null && card.getName().equals(namedCard)) { + if (card != null && CardUtil.haveSameNames(card.getName(), namedCard)) { game.getStack().counter(targetSpell.getId(), source.getSourceId(), game); break; } diff --git a/Mage.Sets/src/mage/cards/d/DenizenOfTheDeep.java b/Mage.Sets/src/mage/cards/d/DenizenOfTheDeep.java index 7797d8b3ce..806ce42168 100644 --- a/Mage.Sets/src/mage/cards/d/DenizenOfTheDeep.java +++ b/Mage.Sets/src/mage/cards/d/DenizenOfTheDeep.java @@ -22,7 +22,7 @@ public final class DenizenOfTheDeep extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static{ - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DenizenOfTheDeep(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DenseCanopy.java b/Mage.Sets/src/mage/cards/d/DenseCanopy.java index df435bc7cb..9a43da5da0 100644 --- a/Mage.Sets/src/mage/cards/d/DenseCanopy.java +++ b/Mage.Sets/src/mage/cards/d/DenseCanopy.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -16,14 +14,15 @@ import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DenseCanopy extends CardImpl { public DenseCanopy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Creatures with flying can block only creatures with flying. @@ -63,7 +62,10 @@ class DenseCanopyCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.hasAbility(FlyingAbility.getInstance().getId(), game); } diff --git a/Mage.Sets/src/mage/cards/d/DenyingWind.java b/Mage.Sets/src/mage/cards/d/DenyingWind.java index e371317b50..9830baaae6 100644 --- a/Mage.Sets/src/mage/cards/d/DenyingWind.java +++ b/Mage.Sets/src/mage/cards/d/DenyingWind.java @@ -63,7 +63,7 @@ class DenyingWindEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 7, new FilterCard("cards from player's library to exile")); - if (controller.searchLibrary(target, game, player.getId())) { + if (controller.searchLibrary(target, source, game, player.getId())) { List targets = target.getTargets(); for (UUID targetId : targets) { Card card = player.getLibrary().remove(targetId, game); diff --git a/Mage.Sets/src/mage/cards/d/DeposeDeploy.java b/Mage.Sets/src/mage/cards/d/DeposeDeploy.java new file mode 100644 index 0000000000..b7a040e204 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeposeDeploy.java @@ -0,0 +1,54 @@ +package mage.cards.d; + +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.ThopterColorlessToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeposeDeploy extends SplitCard { + + public DeposeDeploy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W/U}", "{2}{W}{U}", SpellAbilityType.SPLIT); + + // Depose + // Tap target creature. + // Draw a card. + this.getLeftHalfCard().getSpellAbility().addEffect(new TapTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getLeftHalfCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + + // Deploy + // Creature two 1/1 colorless Thopter artifact creature tokens with flying, then you gain 1 life for each creature you control. + this.getRightHalfCard().getSpellAbility().addEffect( + new CreateTokenEffect(new ThopterColorlessToken(), 2) + ); + this.getRightHalfCard().getSpellAbility().addEffect( + new GainLifeEffect(new PermanentsOnBattlefieldCount( + StaticFilters.FILTER_CONTROLLED_CREATURES + )).setText(", then you gain 1 life for each creature you control.") + ); + + } + + private DeposeDeploy(final DeposeDeploy card) { + super(card); + } + + @Override + public DeposeDeploy copy() { + return new DeposeDeploy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DeputyOfAcquittals.java b/Mage.Sets/src/mage/cards/d/DeputyOfAcquittals.java index ffdc206d10..da6d0e5ba6 100644 --- a/Mage.Sets/src/mage/cards/d/DeputyOfAcquittals.java +++ b/Mage.Sets/src/mage/cards/d/DeputyOfAcquittals.java @@ -26,7 +26,7 @@ public final class DeputyOfAcquittals extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java b/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java new file mode 100644 index 0000000000..d59bc25d3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DeputyOfDetention.java @@ -0,0 +1,110 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DeputyOfDetention extends CardImpl { + + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanent an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public DeputyOfDetention(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // When Deputy of Detention enters the battlefield, exile target nonland permanent an opponent controls and all other nonland permanents that player controls with the same name as that permanent until Deputy of Detention leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new DeputyOfDetentionExileEffect(), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private DeputyOfDetention(final DeputyOfDetention card) { + super(card); + } + + @Override + public DeputyOfDetention copy() { + return new DeputyOfDetention(this); + } +} + +class DeputyOfDetentionExileEffect extends OneShotEffect { + + DeputyOfDetentionExileEffect() { + super(Outcome.Benefit); + this.staticText = "exile target nonland permanent an opponent controls " + + "and all other nonland permanents that player controls " + + "with the same name as that permanent until {this} leaves the battlefield"; + } + + private DeputyOfDetentionExileEffect(final DeputyOfDetentionExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + Permanent targeted = game.getPermanent(source.getFirstTarget()); + + if (permanent == null || controller == null || targeted == null) { + return false; + } + + FilterPermanent filter = new FilterNonlandPermanent(); + filter.add(new ControllerIdPredicate(targeted.getControllerId())); + filter.add(new NamePredicate(targeted.getName())); + + Set toExile = new LinkedHashSet<>(); + for (Permanent creature : game.getBattlefield().getActivePermanents(filter, controller.getId(), game)) { + toExile.add(creature); + } + + if (!toExile.isEmpty()) { + controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); + new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); + } + return true; + } + + @Override + public DeputyOfDetentionExileEffect copy() { + return new DeputyOfDetentionExileEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java index 851eff1ffb..307887aef9 100644 --- a/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java +++ b/Mage.Sets/src/mage/cards/d/DereviEmpyrialTactician.java @@ -1,4 +1,3 @@ - package mage.cards.d; import java.util.UUID; @@ -44,6 +43,7 @@ public final class DereviEmpyrialTactician extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Whenever Derevi, Empyrial Tactician enters the battlefield or a creature you control deals combat damage to a player, you may tap or untap target permanent. Ability ability = new DereviEmpyrialTacticianTriggeredAbility(new MayTapOrUntapTargetEffect()); ability.addTarget(new TargetPermanent()); @@ -75,7 +75,8 @@ class DereviEmpyrialTacticianTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.ENTERS_THE_BATTLEFIELD || event.getType() == EventType.DAMAGED_PLAYER; + return event.getType() == EventType.ENTERS_THE_BATTLEFIELD + || event.getType() == EventType.DAMAGED_PLAYER; } @Override @@ -87,7 +88,8 @@ class DereviEmpyrialTacticianTriggeredAbility extends TriggeredAbilityImpl { if (event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { if (((DamagedPlayerEvent) event).isCombatDamage()) { Permanent creature = game.getPermanent(event.getSourceId()); - if (creature != null && creature.isControlledBy(controllerId)) { + if (creature != null + && creature.isControlledBy(controllerId)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DescendUponTheSinful.java b/Mage.Sets/src/mage/cards/d/DescendUponTheSinful.java index 53e4c70a16..1d287daa38 100644 --- a/Mage.Sets/src/mage/cards/d/DescendUponTheSinful.java +++ b/Mage.Sets/src/mage/cards/d/DescendUponTheSinful.java @@ -1,12 +1,13 @@ - package mage.cards.d; import java.util.UUID; + import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileAllEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,13 +15,12 @@ import mage.filter.StaticFilters; import mage.game.permanent.token.AngelToken; /** - * * @author fireshoes */ public final class DescendUponTheSinful extends CardImpl { public DescendUponTheSinful(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}{W}"); // Exile all creatures this.getSpellAbility().addEffect(new ExileAllEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); @@ -29,6 +29,7 @@ public final class DescendUponTheSinful extends CardImpl { Effect effect = new ConditionalOneShotEffect(new CreateTokenEffect(new AngelToken()), DeliriumCondition.instance); effect.setText("
    Delirium — Create a 4/4 white Angel creature token with flying if there are four or more card types among cards in your graveyard"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addHint(DeliriumHint.instance); } public DescendUponTheSinful(final DescendUponTheSinful card) { diff --git a/Mage.Sets/src/mage/cards/d/DescendantOfSoramaro.java b/Mage.Sets/src/mage/cards/d/DescendantOfSoramaro.java index aad9696a80..ce8cde5bd0 100644 --- a/Mage.Sets/src/mage/cards/d/DescendantOfSoramaro.java +++ b/Mage.Sets/src/mage/cards/d/DescendantOfSoramaro.java @@ -28,7 +28,7 @@ public final class DescendantOfSoramaro extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); // {1}{U}: Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order. - Effect effect = new LookLibraryControllerEffect(new CardsInControllerHandCount()); + Effect effect = new LookLibraryControllerEffect(CardsInControllerHandCount.instance); effect.setText("Look at the top X cards of your library, where X is the number of cards in your hand, then put them back in any order"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{U}"))); diff --git a/Mage.Sets/src/mage/cards/d/DescentOfTheDragons.java b/Mage.Sets/src/mage/cards/d/DescentOfTheDragons.java index bae2a1e14c..52ebc06776 100644 --- a/Mage.Sets/src/mage/cards/d/DescentOfTheDragons.java +++ b/Mage.Sets/src/mage/cards/d/DescentOfTheDragons.java @@ -77,8 +77,8 @@ class DescentOfTheDragonsEffect extends OneShotEffect { } } DragonToken dragonToken = new DragonToken(); - for (UUID playerId : playersWithTargets.keySet()) { - dragonToken.putOntoBattlefield(playersWithTargets.get(playerId), game, source.getSourceId(), playerId); + for (Map.Entry amountTokensPerPlayer : playersWithTargets.entrySet()) { + dragonToken.putOntoBattlefield(amountTokensPerPlayer.getValue(), game, source.getSourceId(), amountTokensPerPlayer.getKey()); } return true; } diff --git a/Mage.Sets/src/mage/cards/d/Desert.java b/Mage.Sets/src/mage/cards/d/Desert.java index e901bdf3d1..06a6c85466 100644 --- a/Mage.Sets/src/mage/cards/d/Desert.java +++ b/Mage.Sets/src/mage/cards/d/Desert.java @@ -27,7 +27,7 @@ public final class Desert extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Desert(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/Desolation.java b/Mage.Sets/src/mage/cards/d/Desolation.java index bed641377a..27824d61c0 100644 --- a/Mage.Sets/src/mage/cards/d/Desolation.java +++ b/Mage.Sets/src/mage/cards/d/Desolation.java @@ -69,7 +69,7 @@ class DesolationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - DesolationWatcher watcher = (DesolationWatcher) game.getState().getWatchers().get(DesolationWatcher.class.getSimpleName()); + DesolationWatcher watcher = game.getState().getWatcher(DesolationWatcher.class); if (watcher != null) { for (UUID playerId : watcher.getPlayersTappedForMana()) { Player player = game.getPlayer(playerId); @@ -106,7 +106,7 @@ class DesolationWatcher extends Watcher { private final Set tappedForManaThisTurnPlayers = new HashSet<>(); public DesolationWatcher() { - super(DesolationWatcher.class.getSimpleName(), WatcherScope.GAME); + super( WatcherScope.GAME); } public DesolationWatcher(final DesolationWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/d/DesolationGiant.java b/Mage.Sets/src/mage/cards/d/DesolationGiant.java index ebe02abc01..5ca7943adb 100644 --- a/Mage.Sets/src/mage/cards/d/DesolationGiant.java +++ b/Mage.Sets/src/mage/cards/d/DesolationGiant.java @@ -27,8 +27,8 @@ public final class DesolationGiant extends CardImpl { private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("other creatures you control"); static { - filter.add(new AnotherPredicate()); - filter2.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); + filter2.add(AnotherPredicate.instance); filter2.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/Despark.java b/Mage.Sets/src/mage/cards/d/Despark.java new file mode 100644 index 0000000000..cca3d6bcae --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Despark.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Despark extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("permanent with converted mana cost 4 or greater"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 3)); + } + + public Despark(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{B}"); + + // Exile target permanent with converted mana cost 4 or greater. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private Despark(final Despark card) { + super(card); + } + + @Override + public Despark copy() { + return new Despark(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DesperateCastaways.java b/Mage.Sets/src/mage/cards/d/DesperateCastaways.java index 8eb7738940..266e087a15 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateCastaways.java +++ b/Mage.Sets/src/mage/cards/d/DesperateCastaways.java @@ -1,23 +1,22 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DesperateCastaways extends CardImpl { @@ -61,17 +60,14 @@ class DesperateCastawaysEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, source.getControllerId(), game) > 0) { - return false; - } - return true; + return game.getBattlefield().countAll(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT, source.getControllerId(), game) <= 0; } // do not apply to other creatures. return false; } diff --git a/Mage.Sets/src/mage/cards/d/DesperateGambit.java b/Mage.Sets/src/mage/cards/d/DesperateGambit.java index eb79f9d262..80351f9dd6 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateGambit.java +++ b/Mage.Sets/src/mage/cards/d/DesperateGambit.java @@ -8,7 +8,6 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.PreventionEffectImpl; -import mage.abilities.effects.common.PreventDamageBySourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -21,7 +20,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.filter.FilterObject; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.players.Player; import mage.target.TargetSource; import mage.util.CardUtil; @@ -68,8 +66,11 @@ class DesperateGambitEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { this.target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game); - this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); - super.init(source, game); + Player you = game.getPlayer(source.getControllerId()); + if(you != null) { + wonFlip = you.flipCoin(source, game, true); + super.init(source, game); + } } @Override diff --git a/Mage.Sets/src/mage/cards/d/DesperateLunge.java b/Mage.Sets/src/mage/cards/d/DesperateLunge.java new file mode 100644 index 0000000000..ba5f659bde --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DesperateLunge.java @@ -0,0 +1,42 @@ +package mage.cards.d; + +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FlyingAbility; +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 DesperateLunge extends CardImpl { + + public DesperateLunge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Target creature gets +2/+2 and gains flying until end of turn. You gain 2 life. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 2, Duration.EndOfTurn + ).setText("Target creature gets +2/+2")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains flying until end of turn.")); + this.getSpellAbility().addEffect(new GainLifeEffect(2)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private DesperateLunge(final DesperateLunge card) { + super(card); + } + + @Override + public DesperateLunge copy() { + return new DesperateLunge(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DesperateSentry.java b/Mage.Sets/src/mage/cards/d/DesperateSentry.java index a1e51ea1b3..28dc4fe5c5 100644 --- a/Mage.Sets/src/mage/cards/d/DesperateSentry.java +++ b/Mage.Sets/src/mage/cards/d/DesperateSentry.java @@ -1,7 +1,7 @@ - package mage.cards.d; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesTriggeredAbility; @@ -10,6 +10,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -19,13 +20,12 @@ import mage.constants.Zone; import mage.game.permanent.token.EldraziHorrorToken; /** - * * @author LevelX2 */ public final class DesperateSentry extends CardImpl { public DesperateSentry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(1); @@ -39,6 +39,7 @@ public final class DesperateSentry extends CardImpl { new BoostSourceEffect(3, 0, Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} gets +3/+0 as long as there are four or more card types among cards in your graveyard."); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DespoticScepter.java b/Mage.Sets/src/mage/cards/d/DespoticScepter.java index b08f92a42a..d4757705eb 100644 --- a/Mage.Sets/src/mage/cards/d/DespoticScepter.java +++ b/Mage.Sets/src/mage/cards/d/DespoticScepter.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class DespoticScepter extends CardImpl { - private final static FilterPermanent FILTER = new FilterPermanent("permanent you own"); + private static final FilterPermanent FILTER = new FilterPermanent("permanent you own"); static { FILTER.add(new OwnerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/d/DestinedLead.java b/Mage.Sets/src/mage/cards/d/DestinedLead.java index b07578b6e8..d9529003d2 100644 --- a/Mage.Sets/src/mage/cards/d/DestinedLead.java +++ b/Mage.Sets/src/mage/cards/d/DestinedLead.java @@ -35,7 +35,7 @@ public final class DestinedLead extends SplitCard { // to // Lead // All creatures able to block target creature this turn must do so. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); getRightHalfCard().getSpellAbility().addEffect(new MustBeBlockedByAllTargetEffect(Duration.EndOfTurn)); } diff --git a/Mage.Sets/src/mage/cards/d/DestructiveTampering.java b/Mage.Sets/src/mage/cards/d/DestructiveTampering.java index 1e07a63875..561e401bde 100644 --- a/Mage.Sets/src/mage/cards/d/DestructiveTampering.java +++ b/Mage.Sets/src/mage/cards/d/DestructiveTampering.java @@ -37,7 +37,7 @@ public final class DestructiveTampering extends CardImpl { // * Creatures without flying can't block this turn. Mode mode = new Mode(); - mode.getEffects().add(new CantBlockAllEffect(filter, Duration.EndOfTurn)); + mode.addEffect(new CantBlockAllEffect(filter, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DestructiveUrge.java b/Mage.Sets/src/mage/cards/d/DestructiveUrge.java index a861a81c13..1ac31870ad 100644 --- a/Mage.Sets/src/mage/cards/d/DestructiveUrge.java +++ b/Mage.Sets/src/mage/cards/d/DestructiveUrge.java @@ -1,23 +1,23 @@ package mage.cards.d; -import java.util.UUID; -import mage.target.common.TargetCreaturePermanent; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToAPlayerAttachedTriggeredAbility; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.SacrificeEffect; -import mage.constants.Outcome; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; import mage.constants.SubType; -import mage.filter.common.FilterLandPermanent; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class DestructiveUrge extends CardImpl { @@ -35,8 +35,10 @@ public final class DestructiveUrge extends CardImpl { this.addAbility(ability); // Whenever enchanted creature deals combat damage to a player, that player sacrifices a land. - ability = new DealsDamageToAPlayerAttachedTriggeredAbility(new SacrificeEffect(new FilterLandPermanent(), 1, "that player"), "enchanted", false, true); - this.addAbility(ability); + this.addAbility(new DealsDamageToAPlayerAttachedTriggeredAbility( + new SacrificeEffect(StaticFilters.FILTER_LAND, 1, "that player"), + "enchanted", false, true + )); } public DestructiveUrge(final DestructiveUrge card) { diff --git a/Mage.Sets/src/mage/cards/d/DetentionSphere.java b/Mage.Sets/src/mage/cards/d/DetentionSphere.java index 5c7466c0b9..64943101ae 100644 --- a/Mage.Sets/src/mage/cards/d/DetentionSphere.java +++ b/Mage.Sets/src/mage/cards/d/DetentionSphere.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -25,8 +23,9 @@ import mage.target.TargetPermanent; import mage.util.CardUtil; import org.apache.log4j.Logger; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DetentionSphere extends CardImpl { @@ -81,12 +80,12 @@ class DetentionSphereEntersEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && exileId != null && targetPermanent != null && controller != null) { - if (targetPermanent.getName().isEmpty()) { // face down creature + if (CardUtil.haveEmptyName(targetPermanent)) { // face down creature controller.moveCardToExileWithInfo(targetPermanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } else { String name = targetPermanent.getName(); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (permanent != null && permanent.getName().equals(name)) { + if (permanent != null && CardUtil.haveSameNames(permanent.getName(), name)) { controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true); } } diff --git a/Mage.Sets/src/mage/cards/d/Detonate.java b/Mage.Sets/src/mage/cards/d/Detonate.java index ff84de2a35..782f5af864 100644 --- a/Mage.Sets/src/mage/cards/d/Detonate.java +++ b/Mage.Sets/src/mage/cards/d/Detonate.java @@ -1,9 +1,7 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetControllerEffect; @@ -16,33 +14,25 @@ import mage.filter.common.FilterArtifactPermanent; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetArtifactPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox */ public final class Detonate extends CardImpl { public Detonate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); // Destroy target artifact with converted mana cost X. It can't be regenerated. Detonate deals X damage to that artifact's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); this.getSpellAbility().addTarget(new TargetArtifactPermanent(new FilterArtifactPermanent("artifact with converted mana cost X"))); - Effect effect = new DamageTargetControllerEffect(new ManacostVariableValue()); + Effect effect = new DamageTargetControllerEffect(ManacostVariableValue.instance); effect.setText("{this} deals X damage to that artifact's controller"); this.getSpellAbility().addEffect(effect); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetArtifactPermanent(filter)); - } + this.getSpellAbility().setTargetAdjuster(DetonateAdjuster.instance); } public Detonate(final Detonate card) { @@ -54,3 +44,16 @@ public final class Detonate extends CardImpl { return new Detonate(this); } } + +enum DetonateAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact with converted mana cost X"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetArtifactPermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DevastatingDreams.java b/Mage.Sets/src/mage/cards/d/DevastatingDreams.java index cebed2d85a..ee0d2b5b27 100644 --- a/Mage.Sets/src/mage/cards/d/DevastatingDreams.java +++ b/Mage.Sets/src/mage/cards/d/DevastatingDreams.java @@ -32,10 +32,10 @@ public final class DevastatingDreams extends CardImpl { this.getSpellAbility().addCost(new DevastatingDreamsAdditionalCost()); // Each player sacrifices X lands. - this.getSpellAbility().addEffect(new SacrificeAllEffect(new GetXValue(), new FilterControlledLandPermanent("lands"))); + this.getSpellAbility().addEffect(new SacrificeAllEffect(GetXValue.instance, new FilterControlledLandPermanent("lands"))); // Devastating Dreams deals X damage to each creature. - this.getSpellAbility().addEffect(new DamageAllEffect(new GetXValue(), new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new DamageAllEffect(GetXValue.instance, new FilterCreaturePermanent())); } public DevastatingDreams(final DevastatingDreams card) { diff --git a/Mage.Sets/src/mage/cards/d/DevastatingSummons.java b/Mage.Sets/src/mage/cards/d/DevastatingSummons.java index e15ae2af9f..c5521add77 100644 --- a/Mage.Sets/src/mage/cards/d/DevastatingSummons.java +++ b/Mage.Sets/src/mage/cards/d/DevastatingSummons.java @@ -55,8 +55,8 @@ class DevastatingSummonsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { DevastatingSummonsElementalToken token = new DevastatingSummonsElementalToken(); - token.getPower().modifyBaseValue(new GetXValue().calculate(game, source, this)); - token.getToughness().modifyBaseValue(new GetXValue().calculate(game, source, this)); + token.getPower().modifyBaseValue(GetXValue.instance.calculate(game, source, this)); + token.getToughness().modifyBaseValue(GetXValue.instance.calculate(game, source, this)); token.putOntoBattlefield(2, game, source.getSourceId(), source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/d/DevilsPlay.java b/Mage.Sets/src/mage/cards/d/DevilsPlay.java index 111f906c86..fad1267f4c 100644 --- a/Mage.Sets/src/mage/cards/d/DevilsPlay.java +++ b/Mage.Sets/src/mage/cards/d/DevilsPlay.java @@ -23,7 +23,7 @@ public final class DevilsPlay extends CardImpl { // Devil's Play deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); // Flashback {X}{R}{R}{R} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{X}{R}{R}{R}"), TimingRule.SORCERY)); diff --git a/Mage.Sets/src/mage/cards/d/DevouringHellion.java b/Mage.Sets/src/mage/cards/d/DevouringHellion.java new file mode 100644 index 0000000000..293a1f6616 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DevouringHellion.java @@ -0,0 +1,97 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DevouringHellion extends CardImpl { + + public DevouringHellion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.HELLION); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // As Devouring Hellion enters the battlefield, you may sacrifice any number of creatures and/or planeswalkers. If you do, it enters with twice that many +1/+1 counters on it. + this.addAbility(new AsEntersBattlefieldAbility(new DevouringHellionEffect())); + } + + private DevouringHellion(final DevouringHellion card) { + super(card); + } + + @Override + public DevouringHellion copy() { + return new DevouringHellion(this); + } +} + +class DevouringHellionEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent("creatures and/or planeswalkers"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + DevouringHellionEffect() { + super(Outcome.Benefit); + staticText = "you may sacrifice any number of creatures and/or planeswalkers. " + + "If you do, it enters with twice that many +1/+1 counters on it."; + } + + private DevouringHellionEffect(final DevouringHellionEffect effect) { + super(effect); + } + + @Override + public DevouringHellionEffect copy() { + return new DevouringHellionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + int xValue = 0; + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null && permanent.sacrifice(source.getSourceId(), game)) { + xValue++; + } + } + return new AddCountersSourceEffect(CounterType.P1P1.createInstance(2 * xValue)).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DevoutChaplain.java b/Mage.Sets/src/mage/cards/d/DevoutChaplain.java index 2f601ef344..02b3d391f4 100644 --- a/Mage.Sets/src/mage/cards/d/DevoutChaplain.java +++ b/Mage.Sets/src/mage/cards/d/DevoutChaplain.java @@ -30,7 +30,7 @@ public final class DevoutChaplain extends CardImpl { private static final FilterControlledPermanent humanFilter = new FilterControlledPermanent("untapped Human you control"); static { - humanFilter.add(Predicates.not(new TappedPredicate())); + humanFilter.add(Predicates.not(TappedPredicate.instance)); humanFilter.add(new SubtypePredicate(SubType.HUMAN)); } diff --git a/Mage.Sets/src/mage/cards/d/DevoutInvocation.java b/Mage.Sets/src/mage/cards/d/DevoutInvocation.java index b9a459fb35..ea6d47b2c7 100644 --- a/Mage.Sets/src/mage/cards/d/DevoutInvocation.java +++ b/Mage.Sets/src/mage/cards/d/DevoutInvocation.java @@ -48,7 +48,7 @@ class DevoutInvocationEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DevoutInvocationEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java index cd93dc22aa..40b7ec3379 100644 --- a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java +++ b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java @@ -58,7 +58,7 @@ class DiabolicRevelationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = new ManacostVariableValue().calculate(game, source, this); + int amount = ManacostVariableValue.instance.calculate(game, source, this); TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard()); Player player = game.getPlayer(source.getControllerId()); @@ -66,7 +66,7 @@ class DiabolicRevelationEffect extends OneShotEffect { return false; } - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().remove(cardId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/d/DiamondKaleidoscope.java b/Mage.Sets/src/mage/cards/d/DiamondKaleidoscope.java index c586f768b7..b34727c950 100644 --- a/Mage.Sets/src/mage/cards/d/DiamondKaleidoscope.java +++ b/Mage.Sets/src/mage/cards/d/DiamondKaleidoscope.java @@ -29,7 +29,7 @@ public final class DiamondKaleidoscope extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Prism token"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new SubtypePredicate(SubType.PRISM)); } diff --git a/Mage.Sets/src/mage/cards/d/DiamondValley.java b/Mage.Sets/src/mage/cards/d/DiamondValley.java index a1a75bb948..530bbee905 100644 --- a/Mage.Sets/src/mage/cards/d/DiamondValley.java +++ b/Mage.Sets/src/mage/cards/d/DiamondValley.java @@ -25,7 +25,7 @@ public final class DiamondValley extends CardImpl { public DiamondValley(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - Effect effect = new GainLifeEffect(new SacrificeCostCreaturesToughness()); + Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance); effect.setText("You gain life equal to the sacrificed creature's toughness"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); diff --git a/Mage.Sets/src/mage/cards/d/Dichotomancy.java b/Mage.Sets/src/mage/cards/d/Dichotomancy.java index c788c4dc8f..dd099831c3 100644 --- a/Mage.Sets/src/mage/cards/d/Dichotomancy.java +++ b/Mage.Sets/src/mage/cards/d/Dichotomancy.java @@ -4,21 +4,15 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.SuspendAbility; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; @@ -59,7 +53,7 @@ class DichotomancyEffect extends OneShotEffect { private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public DichotomancyEffect() { @@ -81,7 +75,7 @@ class DichotomancyEffect extends OneShotEffect { FilterCard filterCard = new FilterCard("card named \""+name+'"'); filterCard.add(new NamePredicate(name)); TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filterCard); - if (controller.searchLibrary(target, game, opponent.getId())) { + if (controller.searchLibrary(target, source, game, opponent.getId())) { controller.moveCards(opponent.getLibrary().getCard(target.getFirstTarget(), game), Zone.BATTLEFIELD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/d/DiligentExcavator.java b/Mage.Sets/src/mage/cards/d/DiligentExcavator.java index 005b0a09be..5723ceb284 100644 --- a/Mage.Sets/src/mage/cards/d/DiligentExcavator.java +++ b/Mage.Sets/src/mage/cards/d/DiligentExcavator.java @@ -23,7 +23,7 @@ public final class DiligentExcavator extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public DiligentExcavator(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java index 69905e9470..98bde31f8f 100644 --- a/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java +++ b/Mage.Sets/src/mage/cards/d/DiluvianPrimordial.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -13,11 +12,7 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -29,10 +24,12 @@ import mage.game.events.ZoneChangeEvent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DiluvianPrimordial extends CardImpl { @@ -48,24 +45,9 @@ public final class DiluvianPrimordial extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Diluvian Primordial enters the battlefield, for each opponent, you may cast up to one target instant or sorcery card from that player's graveyard without paying its mana cost. If a card cast this way would be put into a graveyard this turn, exile it instead. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DiluvianPrimordialEffect(), false)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCard filter = new FilterCard("instant or sorcery card from " + opponent.getLogName() + "'s graveyard"); - filter.add(new OwnerIdPredicate(opponentId)); - filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); - TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(0, 1, filter); - ability.addTarget(target); - } - } - } + Ability ability = new EntersBattlefieldTriggeredAbility(new DiluvianPrimordialEffect(), false); + ability.setTargetAdjuster(DiluvianPrimordialAdjuster.instance); + this.addAbility(ability); } public DiluvianPrimordial(final DiluvianPrimordial card) { @@ -78,6 +60,26 @@ public final class DiluvianPrimordial extends CardImpl { } } +enum DiluvianPrimordialAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + FilterCard filter = new FilterCard("instant or sorcery card from " + opponent.getLogName() + "'s graveyard"); + filter.add(new OwnerIdPredicate(opponentId)); + filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); + TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(0, 1, filter); + ability.addTarget(target); + } + } +} + class DiluvianPrimordialEffect extends OneShotEffect { public DiluvianPrimordialEffect() { @@ -161,6 +163,6 @@ class DiluvianPrimordialReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId().equals(getTargetPointer().getFirst(game, source)); + && event.getTargetId().equals(getTargetPointer().getFirst(game, source)); } } diff --git a/Mage.Sets/src/mage/cards/d/DimirCharm.java b/Mage.Sets/src/mage/cards/d/DimirCharm.java index 53a972d285..16d827dd03 100644 --- a/Mage.Sets/src/mage/cards/d/DimirCharm.java +++ b/Mage.Sets/src/mage/cards/d/DimirCharm.java @@ -47,14 +47,14 @@ public final class DimirCharm extends CardImpl { //or destroy target creature with power 2 or less Mode mode1 = new Mode(); - mode1.getEffects().add(new DestroyTargetEffect()); - mode1.getTargets().add(new TargetCreaturePermanent(filterCreature)); + mode1.addEffect(new DestroyTargetEffect()); + mode1.addTarget(new TargetCreaturePermanent(filterCreature)); this.getSpellAbility().addMode(mode1); //or look at the top three cards of target player's library, then put one back and the rest into that player's graveyard Mode mode2 = new Mode(); - mode2.getEffects().add(new DimirCharmEffect()); - mode2.getTargets().add(new TargetPlayer()); + mode2.addEffect(new DimirCharmEffect()); + mode2.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/d/DimirCutpurse.java b/Mage.Sets/src/mage/cards/d/DimirCutpurse.java index 90bdf07a64..54476bf662 100644 --- a/Mage.Sets/src/mage/cards/d/DimirCutpurse.java +++ b/Mage.Sets/src/mage/cards/d/DimirCutpurse.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -9,20 +7,20 @@ 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.SubType; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class DimirCutpurse extends CardImpl { public DimirCutpurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(2); @@ -30,7 +28,6 @@ public final class DimirCutpurse extends CardImpl { // Whenever Dimir Cutpurse deals combat damage to a player, that player discards a card and you draw a card. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DimirCutpurseEffect(), false, true)); - } public DimirCutpurse(final DimirCutpurse card) { diff --git a/Mage.Sets/src/mage/cards/d/DimirDoppelganger.java b/Mage.Sets/src/mage/cards/d/DimirDoppelganger.java index 388d4d7bfb..e972261d61 100644 --- a/Mage.Sets/src/mage/cards/d/DimirDoppelganger.java +++ b/Mage.Sets/src/mage/cards/d/DimirDoppelganger.java @@ -81,7 +81,7 @@ class DimirDoppelgangerEffect extends OneShotEffect { Cards cardsToExile = new CardsImpl(); cardsToExile.add(copyFromCard); controller.moveCards(cardsToExile, Zone.EXILED, source, game); - newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game); + newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); newBluePrint.assignNewId(); ApplyToPermanent applier = new DimirDoppelgangerApplier(); applier.apply(game, newBluePrint, source, dimirDoppelganger.getId()); diff --git a/Mage.Sets/src/mage/cards/d/DinOfTheFireherd.java b/Mage.Sets/src/mage/cards/d/DinOfTheFireherd.java index f4d6055b6a..a8bc994b4f 100644 --- a/Mage.Sets/src/mage/cards/d/DinOfTheFireherd.java +++ b/Mage.Sets/src/mage/cards/d/DinOfTheFireherd.java @@ -48,8 +48,8 @@ public final class DinOfTheFireherd extends CardImpl { class DinOfTheFireherdEffect extends OneShotEffect { - private final static FilterControlledCreaturePermanent blackCreatureFilter = new FilterControlledCreaturePermanent("black creatures you control"); - private final static FilterControlledCreaturePermanent redCreatureFilter = new FilterControlledCreaturePermanent("red creatures you control"); + private static final FilterControlledCreaturePermanent blackCreatureFilter = new FilterControlledCreaturePermanent("black creatures you control"); + private static final FilterControlledCreaturePermanent redCreatureFilter = new FilterControlledCreaturePermanent("red creatures you control"); static { blackCreatureFilter.add(new ColorPredicate(ObjectColor.BLACK)); diff --git a/Mage.Sets/src/mage/cards/d/DingusEgg.java b/Mage.Sets/src/mage/cards/d/DingusEgg.java index 80e94000fb..cb2bed2f3b 100644 --- a/Mage.Sets/src/mage/cards/d/DingusEgg.java +++ b/Mage.Sets/src/mage/cards/d/DingusEgg.java @@ -56,8 +56,7 @@ class DingusEggTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD - && zEvent.getToZone() == Zone.GRAVEYARD + if (zEvent.isDiesEvent() && zEvent.getTarget().isLand()) { if (getTargets().isEmpty()) { UUID targetId = zEvent.getTarget().getControllerId(); diff --git a/Mage.Sets/src/mage/cards/d/DiplomaticEscort.java b/Mage.Sets/src/mage/cards/d/DiplomaticEscort.java index 6e5555fdf8..4132ba251b 100644 --- a/Mage.Sets/src/mage/cards/d/DiplomaticEscort.java +++ b/Mage.Sets/src/mage/cards/d/DiplomaticEscort.java @@ -25,7 +25,7 @@ import mage.target.TargetStackObject; */ public final class DiplomaticEscort extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("spell or ability that targets a creature"); + private static final FilterStackObject filter = new FilterStackObject("spell or ability that targets a creature"); static { filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/d/DireFleetCaptain.java b/Mage.Sets/src/mage/cards/d/DireFleetCaptain.java index 10efe1d389..45e32a2b7d 100644 --- a/Mage.Sets/src/mage/cards/d/DireFleetCaptain.java +++ b/Mage.Sets/src/mage/cards/d/DireFleetCaptain.java @@ -25,7 +25,7 @@ public final class DireFleetCaptain extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PIRATE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DireFleetCaptain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DireFleetDaredevil.java b/Mage.Sets/src/mage/cards/d/DireFleetDaredevil.java index f49e33e705..c39708c893 100644 --- a/Mage.Sets/src/mage/cards/d/DireFleetDaredevil.java +++ b/Mage.Sets/src/mage/cards/d/DireFleetDaredevil.java @@ -29,8 +29,6 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; -import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.ManaPoolItem; import mage.players.Player; import mage.target.common.TargetCardInOpponentsGraveyard; @@ -81,7 +79,9 @@ class DireFleetDaredevilEffect extends OneShotEffect { public DireFleetDaredevilEffect() { super(Outcome.Benefit); - this.staticText = "exile target instant or sorcery card from an opponent's graveyard. You may cast that card this turn and you may spend mana as though it were mana of any color. If that card would be put into a graveyard this turn, exile it instead"; + this.staticText = "exile target instant or sorcery card from an opponent's graveyard. " + + "You may cast that card this turn and you may spend mana as though it were mana of any color. " + + "If that card would be put into a graveyard this turn, exile it instead"; } public DireFleetDaredevilEffect(final DireFleetDaredevilEffect effect) { @@ -111,11 +111,10 @@ class DireFleetDaredevilEffect extends OneShotEffect { effect = new DireFleetDaredevilReplacementEffect(); effect.setTargetPointer(new FixedTarget(targetCard, game)); game.addEffect(effect, source); - + return true; } } } - return true; } return false; } @@ -144,6 +143,7 @@ class DireFleetDaredevilSpendAnyManaEffect extends AsThoughEffectImpl implements @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards return source.isControlledBy(affectedControllerId) && Objects.equals(objectId, ((FixedTarget) getTargetPointer()).getTarget()) && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) @@ -175,19 +175,9 @@ class DireFleetDaredevilReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - UUID eventObject = event.getTargetId(); - StackObject stackObject = game.getStack().getStackObject(eventObject); - if (stackObject != null) { - if (stackObject instanceof Spell) { - game.rememberLKI(stackObject.getId(), Zone.STACK, (Spell) stackObject); - } - if (stackObject instanceof Card - && stackObject.getSourceId().equals(((FixedTarget) getTargetPointer()).getTarget()) - && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(stackObject.getSourceId()) - && game.getState().getZone(stackObject.getSourceId()) == Zone.STACK) { - ((Card) stackObject).moveToExile(null, null, source.getSourceId(), game); - return true; - } + Card card = game.getCard(event.getTargetId()); + if (card != null) { + return card.moveToZone(Zone.EXILED, source.getSourceId(), game, false); } return false; } @@ -201,6 +191,8 @@ class DireFleetDaredevilReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId().equals(((FixedTarget) getTargetPointer()).getTarget()); + && event.getTargetId().equals(((FixedTarget) getTargetPointer()).getTarget()) + && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 + == game.getState().getZoneChangeCounter(event.getTargetId()); } } diff --git a/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java b/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java index 3e97583f2d..f9199a211b 100644 --- a/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java +++ b/Mage.Sets/src/mage/cards/d/DireFleetPoisoner.java @@ -30,7 +30,7 @@ public final class DireFleetPoisoner extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public DireFleetPoisoner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DireUndercurrents.java b/Mage.Sets/src/mage/cards/d/DireUndercurrents.java index 9c104360e8..ce28bb0433 100644 --- a/Mage.Sets/src/mage/cards/d/DireUndercurrents.java +++ b/Mage.Sets/src/mage/cards/d/DireUndercurrents.java @@ -22,11 +22,11 @@ import mage.target.TargetPlayer; */ public final class DireUndercurrents extends CardImpl { - private final static String rule1 = "Whenever a blue creature enters the battlefield under your control, you may have target player draw a card."; - private final static String rule2 = "Whenever a black creature enters the battlefield under your control, you may have target player discard a card."; + private static final String rule1 = "Whenever a blue creature enters the battlefield under your control, you may have target player draw a card."; + private static final String rule2 = "Whenever a black creature enters the battlefield under your control, you may have target player discard a card."; - private final static FilterControlledPermanent filterBlue = new FilterControlledCreaturePermanent(); - private final static FilterControlledPermanent filterBlack = new FilterControlledCreaturePermanent(); + private static final FilterControlledPermanent filterBlue = new FilterControlledCreaturePermanent(); + private static final FilterControlledPermanent filterBlack = new FilterControlledCreaturePermanent(); static { filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); diff --git a/Mage.Sets/src/mage/cards/d/DiregrafCaptain.java b/Mage.Sets/src/mage/cards/d/DiregrafCaptain.java index 4d77c40513..7417c633a4 100644 --- a/Mage.Sets/src/mage/cards/d/DiregrafCaptain.java +++ b/Mage.Sets/src/mage/cards/d/DiregrafCaptain.java @@ -86,7 +86,7 @@ class DiregrafCaptainTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (!event.getTargetId().equals(this.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent)event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent p = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (p != null && p.isControlledBy(this.controllerId) && filter.match(p, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/d/Disappear.java b/Mage.Sets/src/mage/cards/d/Disappear.java new file mode 100644 index 0000000000..a02d0bf128 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Disappear.java @@ -0,0 +1,87 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class Disappear extends CardImpl { + + public Disappear(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // {U}: Return enchanted creature and Disappear to their owners' hands. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DisappearEffect(), new ManaCostsImpl("{U}"))); + + } + + public Disappear(final Disappear card) { + super(card); + } + + @Override + public Disappear copy() { + return new Disappear(this); + } +} + +class DisappearEffect extends OneShotEffect { + + public DisappearEffect() { + super(Outcome.ReturnToHand); + staticText = "Return enchanted creature and {this} to their owners' hands"; + } + + public DisappearEffect(final DisappearEffect effect) { + super(effect); + } + + @Override + public DisappearEffect copy() { + return new DisappearEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && aura != null + && aura.getAttachedTo() != null) { + Permanent enchantedCreature = game.getPermanent(aura.getAttachedTo()); + controller.moveCards(aura, Zone.HAND, source, game); + if (enchantedCreature != null) { + controller.moveCards(enchantedCreature, Zone.HAND, source, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java b/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java index 5bd24e3e10..51f1c84f64 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfDeceit.java @@ -84,7 +84,7 @@ class DiscipleOfDeceitEffect extends OneShotEffect { if (card == null) { return false; } - String targetName = new StringBuilder("card with converted mana cost of ").append(card.getConvertedManaCost()).toString(); + String targetName = "card with converted mana cost of " + card.getConvertedManaCost(); FilterCard filter = new FilterCard(targetName); filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, card.getConvertedManaCost())); return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java b/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java index 9d1b2a1565..8fabd46578 100644 --- a/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java +++ b/Mage.Sets/src/mage/cards/d/DiscipleOfTheRing.java @@ -52,19 +52,19 @@ public final class DiscipleOfTheRing extends CardImpl { // or Disciple of the Ring gets +1/+1 until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); + mode.addEffect(new BoostSourceEffect(1, 1, Duration.EndOfTurn)); ability.addMode(mode); // or Tap target creature; mode = new Mode(); - mode.getEffects().add(new TapTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new TapTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // or Untap target creature. mode = new Mode(); - mode.getEffects().add(new UntapTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new UntapTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DiscordantDirge.java b/Mage.Sets/src/mage/cards/d/DiscordantDirge.java new file mode 100644 index 0000000000..dcac03578f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiscordantDirge.java @@ -0,0 +1,99 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author jeffwadsworth + */ +public final class DiscordantDirge extends CardImpl { + + private static final String rule = "Look at target opponent's hand and choose up to X cards from it, where X is the number of verse counters on {this}. That player discards those cards.."; + + public DiscordantDirge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); + + // At the beginning of your upkeep, you may put a verse counter on Discordant Dirge. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.VERSE.createInstance(), true), TargetController.YOU, true)); + + // {B}, Sacrifice Discordant Dirge: Look at target opponent's hand and choose up to X cards from it, where X is the number of verse counters on Discordant Dirge. That player discards those cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new DiscordantDirgeEffect(), + new ManaCostsImpl("{B}")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public DiscordantDirge(final DiscordantDirge card) { + super(card); + } + + @Override + public DiscordantDirge copy() { + return new DiscordantDirge(this); + } +} + +class DiscordantDirgeEffect extends OneShotEffect { + + public DiscordantDirgeEffect() { + super(Outcome.Benefit); + staticText = "Look at target opponent's hand and choose up to X cards from it, where X is the number of verse counters on {this}. That player discards those card."; + } + + public DiscordantDirgeEffect(final DiscordantDirgeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent discordantDirge = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (discordantDirge != null) { + int verseCounters = discordantDirge.getCounters(game).getCount(CounterType.VERSE); + Player targetOpponent = game.getPlayer(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (targetOpponent != null + && controller != null) { + controller.lookAtCards(targetOpponent.getName() + " hand", targetOpponent.getHand(), game); + TargetCard target = new TargetCard(0, verseCounters, Zone.HAND, new FilterCard()); + target.setNotTarget(true); + if (controller.choose(Outcome.Benefit, targetOpponent.getHand(), target, game)) { + target.getTargets().stream().map(game::getCard).filter((card) -> (card != null + && targetOpponent.getHand().contains(card.getId()))).forEachOrdered((card) -> { + targetOpponent.discard(card, source, game); + }); + return true; + } + } + } + return false; + } + + @Override + public DiscordantDirgeEffect copy() { + return new DiscordantDirgeEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java index 6e57cee665..6ef69bb789 100644 --- a/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java +++ b/Mage.Sets/src/mage/cards/d/DiscoveryDispersal.java @@ -92,7 +92,7 @@ class DispersalEffect extends OneShotEffect { if (player == null) { return false; } - Set permsToReturn = new HashSet(); + Set permsToReturn = new HashSet<>(); for (UUID opponentId : game.getOpponents(player.getId())) { Player opponent = game.getPlayer(opponentId); if (opponent == null) { diff --git a/Mage.Sets/src/mage/cards/d/DiseasedVermin.java b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java new file mode 100644 index 0000000000..e4c8c5108a --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DiseasedVermin.java @@ -0,0 +1,166 @@ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterOpponent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.watchers.Watcher; + +/** + * + * @author jeffwadsworth + */ +public final class DiseasedVermin extends CardImpl { + + public DiseasedVermin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.RAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever Diseased Vermin deals combat damage to a player, put an infection counter on it. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new AddCountersSourceEffect( + CounterType.INFECTION.createInstance()), + false)); + + // At the beginning of your upkeep, Diseased Vermin deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, + new DiseasedVerminEffect(), + TargetController.YOU, + false); + ability.addWatcher(new DiseasedVerminWatcher()); + this.addAbility(ability); + + } + + private DiseasedVermin(final DiseasedVermin card) { + super(card); + } + + @Override + public DiseasedVermin copy() { + return new DiseasedVermin(this); + } +} + +class DiseasedVerminEffect extends OneShotEffect { + + static final FilterOpponent filter = new FilterOpponent("player previously dealt damage by {this}"); + + static { + filter.add(new DiseasedVerminPredicate()); + } + + public DiseasedVerminEffect() { + super(Outcome.Benefit); + this.staticText = "{this} deals X damage to target opponent previously dealt damage by it, where X is the number of infection counters on it"; + } + + public DiseasedVerminEffect(final DiseasedVerminEffect effect) { + super(effect); + } + + @Override + public DiseasedVerminEffect copy() { + return new DiseasedVerminEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (sourcePermanent != null + && controller != null) { + TargetPlayer targetOpponent = new TargetPlayer(1, 1, false, filter); + if (targetOpponent.canChoose(controller.getId(), game) + && controller.choose(Outcome.Damage, targetOpponent, source.getSourceId(), game)) { + Player opponent = game.getPlayer(targetOpponent.getFirstTarget()); + if (opponent != null + && sourcePermanent.getCounters(game).getCount(CounterType.INFECTION) > 0) { + opponent.damage( + sourcePermanent.getCounters(game).getCount(CounterType.INFECTION), + source.getSourceId(), game, false, true); + return true; + } + } + } + return false; + } +} + +class DiseasedVerminPredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + DiseasedVerminWatcher watcher = game.getState().getWatcher(DiseasedVerminWatcher.class); + if (watcher != null) { + return watcher.hasSourceDoneDamage(input.getObject().getId(), game); + } + return false; + } + + @Override + public String toString() { + return "(Player previously dealt damage by {source})"; + } +} + +class DiseasedVerminWatcher extends Watcher { + + // does not reset!! + private final Set damagedPlayers; + + public DiseasedVerminWatcher() { + super(WatcherScope.GAME); + damagedPlayers = new HashSet<>(); + } + + public DiseasedVerminWatcher(final DiseasedVerminWatcher watcher) { + super(watcher); + this.damagedPlayers = new HashSet<>(); + this.damagedPlayers.addAll(watcher.damagedPlayers); + } + + @Override + public DiseasedVerminWatcher copy() { + return new DiseasedVerminWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.DAMAGED_PLAYER + && event.getSourceId() == sourceId) { + damagedPlayers.add(event.getTargetId()); + } + } + + public boolean hasSourceDoneDamage(UUID playerId, Game game) { + return damagedPlayers.contains(playerId); + } +} diff --git a/Mage.Sets/src/mage/cards/d/Disembowel.java b/Mage.Sets/src/mage/cards/d/Disembowel.java index 3e1f1d500d..6aa70be2ab 100644 --- a/Mage.Sets/src/mage/cards/d/Disembowel.java +++ b/Mage.Sets/src/mage/cards/d/Disembowel.java @@ -1,9 +1,7 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,30 +11,21 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox */ public final class Disembowel extends CardImpl { public Disembowel(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}"); // Destroy target creature with converted mana cost X. - this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with converted mana cost X"))); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetCreaturePermanent(filter)); - } + this.getSpellAbility().addEffect(new DestroyTargetEffect("creature with converted mana cost X")); + this.getSpellAbility().setTargetAdjuster(DisembowelAdjuster.instance); } public Disembowel(final Disembowel card) { @@ -48,3 +37,16 @@ public final class Disembowel extends CardImpl { return new Disembowel(this); } } + +enum DisembowelAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java b/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java index ab9a61804f..7b67d4bc80 100644 --- a/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java +++ b/Mage.Sets/src/mage/cards/d/DisinformationCampaign.java @@ -1,6 +1,5 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -16,8 +15,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DisinformationCampaign extends CardImpl { @@ -27,11 +27,9 @@ public final class DisinformationCampaign extends CardImpl { // When Disinformation Campaign enters the battlefield, you draw a card and each opponent discards a card. Ability ability = new EntersBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(1).setText("you draw a card") - ); + new DrawCardSourceControllerEffect(1, "you")); ability.addEffect(new DiscardEachPlayerEffect( - new StaticValue(1), false, TargetController.OPPONENT - ).setText("and each opponent discards a card")); + new StaticValue(1), false, TargetController.OPPONENT).concatBy("and")); this.addAbility(ability); // Whenever you surveil, return Disinformation Campaign to its owner's hand. diff --git a/Mage.Sets/src/mage/cards/d/Disintegrate.java b/Mage.Sets/src/mage/cards/d/Disintegrate.java index bcd6813763..8b0f12edb5 100644 --- a/Mage.Sets/src/mage/cards/d/Disintegrate.java +++ b/Mage.Sets/src/mage/cards/d/Disintegrate.java @@ -23,7 +23,7 @@ public final class Disintegrate extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); // Disintegrate deals X damage to any target. That creature can't be regenerated this turn. If the creature would die this turn, exile it instead. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addEffect(new CantRegenerateTargetEffect(Duration.EndOfTurn, "That creature")); Effect effect = new ExileTargetIfDiesEffect(); effect.setText("If the creature would die this turn, exile it instead"); diff --git a/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java b/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java index f80123275b..aa7fa1a6c1 100644 --- a/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java +++ b/Mage.Sets/src/mage/cards/d/DisplayOfDominance.java @@ -52,7 +52,7 @@ public final class DisplayOfDominance extends CardImpl { // or Permanents you control can't be the targets of blue or black spells your opponents control this turn Mode mode = new Mode(); - mode.getEffects().add(new DisplayOfDominanceEffect()); + mode.addEffect(new DisplayOfDominanceEffect()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java b/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java index ef89d09984..5719cf8b5b 100644 --- a/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java +++ b/Mage.Sets/src/mage/cards/d/DissensionInTheRanks.java @@ -17,10 +17,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class DissensionInTheRanks extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creature"); static { - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } public DissensionInTheRanks(UUID ownerId, CardSetInfo setInfo) { @@ -34,7 +34,7 @@ public final class DissensionInTheRanks extends CardImpl { FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target blocking creature"); filter2.add(new AnotherTargetPredicate(2)); - filter2.add(new BlockingPredicate()); + filter2.add(BlockingPredicate.instance); TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter2); target2.setTargetTag(2); this.getSpellAbility().addTarget(target2); diff --git a/Mage.Sets/src/mage/cards/d/DistantMemories.java b/Mage.Sets/src/mage/cards/d/DistantMemories.java index 59c52e4c80..68d8ffe9e7 100644 --- a/Mage.Sets/src/mage/cards/d/DistantMemories.java +++ b/Mage.Sets/src/mage/cards/d/DistantMemories.java @@ -62,7 +62,7 @@ class DistantMemoriesEffect extends OneShotEffect { } TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.EXILED, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/d/DistortingWake.java b/Mage.Sets/src/mage/cards/d/DistortingWake.java index 6f0491c67b..e03c667af1 100644 --- a/Mage.Sets/src/mage/cards/d/DistortingWake.java +++ b/Mage.Sets/src/mage/cards/d/DistortingWake.java @@ -1,9 +1,7 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -13,22 +11,23 @@ import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetNonlandPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DistortingWake extends CardImpl { public DistortingWake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}{U}"); // Return X target nonland permanents to their owners' hands. Effect effect = new ReturnToHandTargetEffect(); effect.setText("Return X target nonland permanents to their owners' hands"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetNonlandPermanent()); + this.getSpellAbility().setTargetAdjuster(DistortingWakeAdjuster.instance); } public DistortingWake(final DistortingWake card) { @@ -39,16 +38,17 @@ public final class DistortingWake extends CardImpl { public DistortingWake copy() { return new DistortingWake(this); } +} + +enum DistortingWakeAdjuster implements TargetAdjuster { + instance; @Override public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - Target target = new TargetNonlandPermanent(xValue, xValue, - new FilterNonlandPermanent(xValue + " target nonland permanent(s)"), false); - ability.getTargets().clear(); - ability.getTargets().add(target); - } + int xValue = ability.getManaCostsToPay().getX(); + Target target = new TargetNonlandPermanent(xValue, xValue, + new FilterNonlandPermanent(xValue + " target nonland permanent(s)"), false); + ability.getTargets().clear(); + ability.getTargets().add(target); } - -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java b/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java index 2e9c582c22..79ff36ae6b 100644 --- a/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java +++ b/Mage.Sets/src/mage/cards/d/DiversionaryTactics.java @@ -24,7 +24,7 @@ public final class DiversionaryTactics extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DiversionaryTactics(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DivineArrow.java b/Mage.Sets/src/mage/cards/d/DivineArrow.java new file mode 100644 index 0000000000..11464bc56b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DivineArrow.java @@ -0,0 +1,32 @@ +package mage.cards.d; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DivineArrow extends CardImpl { + + public DivineArrow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Divine Arrow deals 4 damage to target attacking or blocking creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + } + + private DivineArrow(final DivineArrow card) { + super(card); + } + + @Override + public DivineArrow copy() { + return new DivineArrow(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DivineCongregation.java b/Mage.Sets/src/mage/cards/d/DivineCongregation.java index fd2337047f..2d60861dc1 100644 --- a/Mage.Sets/src/mage/cards/d/DivineCongregation.java +++ b/Mage.Sets/src/mage/cards/d/DivineCongregation.java @@ -1,7 +1,6 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -10,13 +9,14 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class DivineCongregation extends CardImpl { @@ -32,7 +32,7 @@ public final class DivineCongregation extends CardImpl { this.addAbility(new SuspendAbility(5, new ManaCostsImpl("{1}{W}"), this)); } - public DivineCongregation(final DivineCongregation card) { + private DivineCongregation(final DivineCongregation card) { super(card); } @@ -44,12 +44,12 @@ public final class DivineCongregation extends CardImpl { class DivineCongregationEffect extends OneShotEffect { - public DivineCongregationEffect() { + DivineCongregationEffect() { super(Outcome.Benefit); staticText = "You gain 2 life for each creature target player controls"; } - public DivineCongregationEffect(final DivineCongregationEffect effect) { + private DivineCongregationEffect(final DivineCongregationEffect effect) { super(effect); } @@ -62,8 +62,8 @@ class DivineCongregationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Player player = game.getPlayer(source.getFirstTarget()); - if (controller != null) { - int critters = game.getBattlefield().getAllActivePermanents(new FilterCreaturePermanent(), player.getId(), game).size(); + if (controller != null && player != null) { + int critters = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game).size(); controller.gainLife(2 * critters, game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/d/DivineOffering.java b/Mage.Sets/src/mage/cards/d/DivineOffering.java index 8682ffefdd..02ddd7a87e 100644 --- a/Mage.Sets/src/mage/cards/d/DivineOffering.java +++ b/Mage.Sets/src/mage/cards/d/DivineOffering.java @@ -23,7 +23,7 @@ public final class DivineOffering extends CardImpl { // Destroy target artifact. You gain life equal to its converted mana cost. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Effect effect = new GainLifeEffect(new TargetConvertedManaCost()); + Effect effect = new GainLifeEffect(TargetConvertedManaCost.instance); effect.setText("You gain life equal to its converted mana cost"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetArtifactPermanent()); diff --git a/Mage.Sets/src/mage/cards/d/DivineReckoning.java b/Mage.Sets/src/mage/cards/d/DivineReckoning.java index 88ec302715..784babe0fc 100644 --- a/Mage.Sets/src/mage/cards/d/DivineReckoning.java +++ b/Mage.Sets/src/mage/cards/d/DivineReckoning.java @@ -4,6 +4,7 @@ package mage.cards.d; import java.util.ArrayList; import java.util.List; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -28,7 +29,7 @@ import mage.target.common.TargetControlledPermanent; public final class DivineReckoning extends CardImpl { public DivineReckoning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); // Each player chooses a creature he or she controls. Destroy the rest. this.getSpellAbility().addEffect(new DivineReckoningEffect()); @@ -65,15 +66,16 @@ class DivineReckoningEffect extends OneShotEffect { if (controller != null) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - - Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); - if (target.canChoose(player.getId(), game)) { - while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), game)) { - player.chooseTarget(Outcome.Benefit, target, source, game); - } - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - chosen.add(permanent); + if (player != null) { + Target target = new TargetControlledPermanent(1, 1, new FilterControlledCreaturePermanent(), true); + if (target.canChoose(player.getId(), game)) { + while (player.canRespond() && !target.isChosen() && target.canChoose(player.getId(), game)) { + player.chooseTarget(Outcome.Benefit, target, source, game); + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + chosen.add(permanent); + } } } } diff --git a/Mage.Sets/src/mage/cards/d/DivinersWand.java b/Mage.Sets/src/mage/cards/d/DivinersWand.java index b1387f8927..5008753221 100644 --- a/Mage.Sets/src/mage/cards/d/DivinersWand.java +++ b/Mage.Sets/src/mage/cards/d/DivinersWand.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DrawCardControllerTriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; @@ -23,40 +21,46 @@ import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DivinersWand extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("a Wizard creature"); + static { filter.add(new SubtypePredicate(SubType.WIZARD)); } public DivinersWand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.WIZARD); this.subtype.add(SubType.EQUIPMENT); - // Equipped creature has "Whenever you draw a card, this creature gets +1/+1 and gains flying until end of turn" and "{4}: Draw a card." - Ability gainedAbility = new DrawCardControllerTriggeredAbility(new BoostSourceEffect(1,1, Duration.EndOfTurn), false); - gainedAbility.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.EQUIPMENT); - effect.setText("Equipped creature has \"Whenever you draw a card, this creature gets +1/+1 and gains flying until end of turn\""); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - effect = new GainAbilityAttachedEffect( - new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(4)), AttachmentType.EQUIPMENT); - effect.setText("and \"{4}: Draw a card.\""); - ability.addEffect(effect); - this.addAbility(ability); - // Whenever a Wizard creature enters the battlefield, you may attach Diviner's Wand to it. this.addAbility(new EntersBattlefieldAllTriggeredAbility( Zone.BATTLEFIELD, new AttachEffect(Outcome.Detriment, "attach {source} to it"), filter, true, SetTargetPointer.PERMANENT, null)); + // Equip {3} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3))); + + // Equipped creature has "Whenever you draw a card, this creature gets +1/+1 and gains flying until end of turn" and "{4}: Draw a card." + // new abilities + Ability newBoost = new DrawCardControllerTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false); + newBoost.addEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn).concatBy("and")); + Ability newDraw = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(4)); + // gain new abilities + Effect effectBoost = new GainAbilityAttachedEffect(newBoost, AttachmentType.EQUIPMENT) + .setText("Equipped creature has \"Whenever you draw a card, this creature gets +1/+1 and gains flying until end of turn\""); + Effect effectDraw = new GainAbilityAttachedEffect(newDraw, AttachmentType.EQUIPMENT) + .setText("\"{4}: Draw a card.\""); + // total ability + Ability totalAbility = new SimpleStaticAbility(Zone.BATTLEFIELD, effectBoost); + totalAbility.addEffect(effectDraw.concatBy("and")); + this.addAbility(totalAbility); } public DivinersWand(final DivinersWand card) { diff --git a/Mage.Sets/src/mage/cards/d/DiviningWitch.java b/Mage.Sets/src/mage/cards/d/DiviningWitch.java index 1a7c10667c..39e231aa20 100644 --- a/Mage.Sets/src/mage/cards/d/DiviningWitch.java +++ b/Mage.Sets/src/mage/cards/d/DiviningWitch.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -21,9 +19,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author maxlebedev */ public final class DiviningWitch extends CardImpl { @@ -92,7 +92,7 @@ public final class DiviningWitch extends CardImpl { if (card != null) { cardsToReaveal.add(card); // Put that card into your hand - if (card.getName().equals(name)) { + if (CardUtil.haveSameNames(card.getName(), name)) { cardToHand = card; break; } diff --git a/Mage.Sets/src/mage/cards/d/DizzyingGaze.java b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java new file mode 100644 index 0000000000..83f24c04ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DizzyingGaze.java @@ -0,0 +1,71 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.constants.SubType; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class DizzyingGaze extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public DizzyingGaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature you control + TargetPermanent auraTarget = new TargetControlledCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // {R}: Enchanted creature deals 1 damage to target creature with flying. + Ability ability2 = new SimpleActivatedAbility(new DamageTargetEffect(1), new ManaCostsImpl("{R}")); + ability2.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAttachedEffect( + ability2, + AttachmentType.AURA, + Duration.WhileOnBattlefield))); + + } + + public DizzyingGaze(final DizzyingGaze card) { + super(card); + } + + @Override + public DizzyingGaze copy() { + return new DizzyingGaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java index bba34f7496..c613b4238d 100644 --- a/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java +++ b/Mage.Sets/src/mage/cards/d/DjinnIlluminatus.java @@ -52,7 +52,7 @@ public final class DjinnIlluminatus extends CardImpl { class DjinnIlluminatusGainReplicateEffect extends ContinuousEffectImpl { - private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); private final Map replicateAbilities = new HashMap<>(); public DjinnIlluminatusGainReplicateEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DoggedHunter.java b/Mage.Sets/src/mage/cards/d/DoggedHunter.java index 2f5c060036..b5e8dd7b43 100644 --- a/Mage.Sets/src/mage/cards/d/DoggedHunter.java +++ b/Mage.Sets/src/mage/cards/d/DoggedHunter.java @@ -24,7 +24,7 @@ public final class DoggedHunter extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature token"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public DoggedHunter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DolmenGate.java b/Mage.Sets/src/mage/cards/d/DolmenGate.java index b5172e1bae..24cad2f4d3 100644 --- a/Mage.Sets/src/mage/cards/d/DolmenGate.java +++ b/Mage.Sets/src/mage/cards/d/DolmenGate.java @@ -21,7 +21,7 @@ public final class DolmenGate extends CardImpl { private static final FilterControlledCreatureInPlay filter = new FilterControlledCreatureInPlay("attacking creatures you control"); static { - filter.getCreatureFilter().add(new AttackingPredicate()); + filter.getCreatureFilter().add(AttackingPredicate.instance); } public DolmenGate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DominariasJudgment.java b/Mage.Sets/src/mage/cards/d/DominariasJudgment.java new file mode 100644 index 0000000000..9da8564410 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DominariasJudgment.java @@ -0,0 +1,63 @@ + +package mage.cards.d; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +/** + * + * @author L_J + */ +public final class DominariasJudgment extends CardImpl { + + private static final FilterLandPermanent filterPlains = new FilterLandPermanent("Plains"); + private static final FilterLandPermanent filterIsland = new FilterLandPermanent("Island"); + private static final FilterLandPermanent filterSwamp = new FilterLandPermanent("Swamp"); + private static final FilterLandPermanent filterMountain = new FilterLandPermanent("Mountain"); + private static final FilterLandPermanent filterForest = new FilterLandPermanent("Forest"); + + static { + filterPlains.add(new SubtypePredicate(SubType.PLAINS)); + filterIsland.add(new SubtypePredicate(SubType.ISLAND)); + filterSwamp.add(new SubtypePredicate(SubType.SWAMP)); + filterMountain.add(new SubtypePredicate(SubType.MOUNTAIN)); + filterForest.add(new SubtypePredicate(SubType.FOREST)); + } + + public DominariasJudgment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Until end of turn, creatures you control gain protection from white if you control a Plains, from blue if you control an Island, from black if you control a Swamp, from red if you control a Mountain, and from green if you control a Forest. + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect(ProtectionAbility.from(ObjectColor.WHITE), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false), new PermanentsOnTheBattlefieldCondition(filterPlains),"Until end of turn, creatures you control gain protection from white if you control a Plains,")); + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect(ProtectionAbility.from(ObjectColor.BLUE), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false), new PermanentsOnTheBattlefieldCondition(filterIsland)," from blue if you control an Island,")); + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect(ProtectionAbility.from(ObjectColor.BLACK), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false), new PermanentsOnTheBattlefieldCondition(filterSwamp)," from black if you control a Swamp,")); + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect(ProtectionAbility.from(ObjectColor.RED), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false), new PermanentsOnTheBattlefieldCondition(filterMountain)," from red if you control a Mountain,")); + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityControlledEffect(ProtectionAbility.from(ObjectColor.GREEN), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, false), new PermanentsOnTheBattlefieldCondition(filterForest)," and from green if you control a Forest")); + } + + public DominariasJudgment(final DominariasJudgment card) { + super(card); + } + + @Override + public DominariasJudgment copy() { + return new DominariasJudgment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/Dominate.java b/Mage.Sets/src/mage/cards/d/Dominate.java index 7ad2e93a8c..d9c74afb3c 100644 --- a/Mage.Sets/src/mage/cards/d/Dominate.java +++ b/Mage.Sets/src/mage/cards/d/Dominate.java @@ -1,9 +1,6 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,38 +12,43 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Dominate extends CardImpl { public Dominate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{1}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{1}{U}{U}"); // Gain control of target creature with converted mana cost X or less. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with converted mana cost X or less"))); + this.getSpellAbility().setTargetAdjuster(DominateAdjuster.instance); } public Dominate(final Dominate card) { super(card); } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X or less"); - filter.add(Predicates.not(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, xValue))); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } @Override public Dominate copy() { return new Dominate(this); } } + +enum DominateAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X or less"); + filter.add(Predicates.not(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, xValue))); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DominatorDrone.java b/Mage.Sets/src/mage/cards/d/DominatorDrone.java index 3a06feb1f1..ece62e0d2a 100644 --- a/Mage.Sets/src/mage/cards/d/DominatorDrone.java +++ b/Mage.Sets/src/mage/cards/d/DominatorDrone.java @@ -28,8 +28,8 @@ public final class DominatorDrone extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public DominatorDrone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/Domineer.java b/Mage.Sets/src/mage/cards/d/Domineer.java index f24c075f69..95afadeb8d 100644 --- a/Mage.Sets/src/mage/cards/d/Domineer.java +++ b/Mage.Sets/src/mage/cards/d/Domineer.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class Domineer extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/d/DomineeringWill.java b/Mage.Sets/src/mage/cards/d/DomineeringWill.java index 808966caef..384ad50460 100644 --- a/Mage.Sets/src/mage/cards/d/DomineeringWill.java +++ b/Mage.Sets/src/mage/cards/d/DomineeringWill.java @@ -33,7 +33,7 @@ public final class DomineeringWill extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonattacking creatures"); static { - filter.add(Predicates.not(new AttackingPredicate())); + filter.add(Predicates.not(AttackingPredicate.instance)); } public DomineeringWill(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java b/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java new file mode 100644 index 0000000000..e6fda3bc43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DomriAnarchOfBolas.java @@ -0,0 +1,102 @@ +package mage.cards.d; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DomriAnarchOfBolas extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public DomriAnarchOfBolas(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOMRI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // Creatures you control get +1/+0. + this.addAbility(new SimpleStaticAbility( + new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield) + )); + + // +1: Add {R} or {G}. Creature spells you cast this turn can't be countered. + this.addAbility(new LoyaltyAbility(new DomriAnarchOfBolasEffect(), 1)); + + // -2: Target creature you control fights target creature you don't control. + Ability ability = new LoyaltyAbility(new FightTargetsEffect(), -2); + ability.addTarget(new TargetControlledCreaturePermanent()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private DomriAnarchOfBolas(final DomriAnarchOfBolas card) { + super(card); + } + + @Override + public DomriAnarchOfBolas copy() { + return new DomriAnarchOfBolas(this); + } +} + +class DomriAnarchOfBolasEffect extends OneShotEffect { + + DomriAnarchOfBolasEffect() { + super(Outcome.Benefit); + staticText = "Add {R} or {G}. Creature spells you cast this turn can't be countered."; + } + + private DomriAnarchOfBolasEffect(final DomriAnarchOfBolasEffect effect) { + super(effect); + } + + @Override + public DomriAnarchOfBolasEffect copy() { + return new DomriAnarchOfBolasEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Mana mana = new Mana(); + if (player.chooseUse(outcome, "Choose a color of mana to add", null, "Red", "Green", source, game)) { + mana.increaseRed(); + } else { + mana.increaseGreen(); + } + player.getManaPool().addMana(mana, game, source); + game.addEffect(new CantBeCounteredControlledEffect(StaticFilters.FILTER_SPELL_A_CREATURE, Duration.EndOfTurn), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java b/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java new file mode 100644 index 0000000000..ed75b4de9e --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DomriChaosBringer.java @@ -0,0 +1,150 @@ +package mage.cards.d; + +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.game.Game; +import mage.game.command.emblems.DomriChaosBringerEmblem; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DomriChaosBringer extends CardImpl { + + public DomriChaosBringer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOMRI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // +1: Add {R} or {G}. If that mana is spent on a creature spell, it gains riot. + this.addAbility(new LoyaltyAbility(new DomriChaosBringerEffect(), 1)); + + // −3: Look at the top four cards of your library. You may reveal up to two creature cards from among them and put them into your hand. Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( + new StaticValue(4), false, new StaticValue(2), + StaticFilters.FILTER_CARD_CREATURE, Zone.LIBRARY, false, + true, true, Zone.HAND, false, false, false + ).setText( + "Look at the top four cards of your library. " + + "You may reveal up to two creature cards from among them " + + "and put them into your hand. Put the rest on the bottom of your library " + + "in a random order." + ), -3)); + + // −8: You get an emblem with "At the beginning of each end step, create a 4/4 red and green Beast creature token with trample." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new DomriChaosBringerEmblem()), -8)); + } + + private DomriChaosBringer(final DomriChaosBringer card) { + super(card); + } + + @Override + public DomriChaosBringer copy() { + return new DomriChaosBringer(this); + } +} + +class DomriChaosBringerEffect extends OneShotEffect { + + DomriChaosBringerEffect() { + super(Outcome.Benefit); + staticText = "Add {R} or {G}. If that mana is spent on a creature spell, it gains riot."; + } + + private DomriChaosBringerEffect(final DomriChaosBringerEffect effect) { + super(effect); + } + + @Override + public DomriChaosBringerEffect copy() { + return new DomriChaosBringerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + ManaEffect manaEffect; + if (player.chooseUse(Outcome.PutManaInPool, "Choose red or green mana", "", "Red", "Green", source, game)) { + manaEffect = new BasicManaEffect(Mana.RedMana(1)); + } else { + manaEffect = new BasicManaEffect(Mana.GreenMana(1)); + } + game.addDelayedTriggeredAbility(new DomriChaosBringerTriggeredAbility(source.getSourceId(), game.getTurnNum()), source); + return manaEffect.apply(game, source); + } +} + +class DomriChaosBringerTriggeredAbility extends DelayedTriggeredAbility { + + private final UUID spellId; + private final int turnNumber; + + DomriChaosBringerTriggeredAbility(UUID spellId, int turnNumber) { + super(null, Duration.Custom, true); + this.spellId = spellId; + this.turnNumber = turnNumber; + this.usesStack = false; + } + + private DomriChaosBringerTriggeredAbility(final DomriChaosBringerTriggeredAbility ability) { + super(ability); + this.spellId = ability.spellId; + this.turnNumber = ability.turnNumber; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.MANA_PAID; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getSourceId().equals(spellId)) { + return false; + } + if (game.getTurnNum() != turnNumber) { + return false; + } + MageObject mo = game.getObject(event.getTargetId()); + if (mo == null || !mo.isCreature()) { + return false; + } + this.getEffects().clear(); + FilterSpell filter = new FilterSpell(); + filter.add(new CardIdPredicate(event.getTargetId())); + this.addEffect(new GainAbilityControlledSpellsEffect(new RiotAbility(), filter)); + return true; + } + + @Override + public DomriChaosBringerTriggeredAbility copy() { + return new DomriChaosBringerTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java b/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java new file mode 100644 index 0000000000..2475c5f7d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DomriCitySmasher.java @@ -0,0 +1,69 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +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.StaticFilters; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DomriCitySmasher extends CardImpl { + + public DomriCitySmasher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOMRI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // +2: Creatures you control get +1/+1 and gain haste until end of turn. + Ability ability = new LoyaltyAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn + ).setText("creatures you control get +1/+1"), 2); + ability.addEffect(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gain haste until end of turn")); + this.addAbility(ability); + + // -3: Domri, City Smasher deals 3 damage to any target. + ability = new LoyaltyAbility(new DamageTargetEffect(3), -3); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + + // -8: Put three +1/+1 counters on each creature you control. Those creatures gain trample until end of turn. + ability = new LoyaltyAbility(new AddCountersAllEffect( + CounterType.P1P1.createInstance(3), + StaticFilters.FILTER_CONTROLLED_CREATURE + ), -8); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn + ).setText("Those creatures gain trample until end of turn")); + this.addAbility(ability); + } + + private DomriCitySmasher(final DomriCitySmasher card) { + super(card); + } + + @Override + public DomriCitySmasher copy() { + return new DomriCitySmasher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DomrisAmbush.java b/Mage.Sets/src/mage/cards/d/DomrisAmbush.java new file mode 100644 index 0000000000..ba5012fd40 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DomrisAmbush.java @@ -0,0 +1,81 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageWithPowerTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DomrisAmbush extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public DomrisAmbush(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{R}{G}"); + + // Put a +1/+1 counter on target creature you control. Then that creature deals damage equal to its power to target creature or planeswalker you don't control. + this.getSpellAbility().addEffect(new DomrisAmbushEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private DomrisAmbush(final DomrisAmbush card) { + super(card); + } + + @Override + public DomrisAmbush copy() { + return new DomrisAmbush(this); + } +} + +class DomrisAmbushEffect extends OneShotEffect { + + DomrisAmbushEffect() { + super(Outcome.Benefit); + staticText = "Put a +1/+1 counter on target creature you control. " + + "Then that creature deals damage equal to its power " + + "to target creature or planeswalker you don't control."; + } + + private DomrisAmbushEffect(final DomrisAmbushEffect effect) { + super(effect); + } + + @Override + public DomrisAmbushEffect copy() { + return new DomrisAmbushEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + game.applyEffects(); + return new DamageWithPowerTargetEffect().apply(game, source); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DomrisNodorog.java b/Mage.Sets/src/mage/cards/d/DomrisNodorog.java new file mode 100644 index 0000000000..2c289dd233 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DomrisNodorog.java @@ -0,0 +1,51 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DomrisNodorog extends CardImpl { + + private static final FilterCard filter = new FilterCard("card named Domri, City Smasher"); + + static { + filter.add(new NamePredicate("Domri, City Smasher")); + } + + public DomrisNodorog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Domri's Nodorog enters the battlefield, you may search your library and/or graveyard for a card named Domri, City Smasher, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SearchLibraryGraveyardPutInHandEffect(filter, false, true) + )); + } + + private DomrisNodorog(final DomrisNodorog card) { + super(card); + } + + @Override + public DomrisNodorog copy() { + return new DomrisNodorog(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/Doomfall.java b/Mage.Sets/src/mage/cards/d/Doomfall.java index e6657abee4..f66ae408c8 100644 --- a/Mage.Sets/src/mage/cards/d/Doomfall.java +++ b/Mage.Sets/src/mage/cards/d/Doomfall.java @@ -37,9 +37,9 @@ public final class Doomfall extends CardImpl { // • Target opponent reveals their hand. You choose a nonland card from it. Exile that card. Mode mode = new Mode(); - mode.getEffects().add(new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_A_NON_LAND) + mode.addEffect(new ExileCardYouChooseTargetOpponentEffect(StaticFilters.FILTER_CARD_A_NON_LAND) .setText("Target opponent reveals their hand. You choose a nonland card from it. Exile that card")); - mode.getTargets().add(new TargetOpponent()); + mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DoranTheSiegeTower.java b/Mage.Sets/src/mage/cards/d/DoranTheSiegeTower.java index 03c4f0c6f1..984b2342ec 100644 --- a/Mage.Sets/src/mage/cards/d/DoranTheSiegeTower.java +++ b/Mage.Sets/src/mage/cards/d/DoranTheSiegeTower.java @@ -1,19 +1,20 @@ package mage.cards.d; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.game.Game; + +import java.util.UUID; /** - * * 613.10. Some continuous effects affect game rules rather than objects. For * example, effects may modify a player's maximum hand size, or say that a * creature must attack this turn if able. These effects are applied after all @@ -22,7 +23,6 @@ import mage.game.Game; * in rule 601.2e. All other such effects are applied in timestamp order. See * also the rules for timestamp order and dependency (rules 613.6 and 613.7) * - * * @author LevelX2 */ public final class DoranTheSiegeTower extends CardImpl { @@ -37,10 +37,15 @@ public final class DoranTheSiegeTower extends CardImpl { this.toughness = new MageInt(5); // Each creature assigns combat damage equal to its toughness rather than its power. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DoranTheSiegeTowerCombatDamageRuleEffect())); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new CombatDamageByToughnessEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, false + ) + )); } - public DoranTheSiegeTower(final DoranTheSiegeTower card) { + private DoranTheSiegeTower(final DoranTheSiegeTower card) { super(card); } @@ -49,38 +54,3 @@ public final class DoranTheSiegeTower extends CardImpl { return new DoranTheSiegeTower(this); } } - -class DoranTheSiegeTowerCombatDamageRuleEffect extends ContinuousEffectImpl { - - public DoranTheSiegeTowerCombatDamageRuleEffect() { - super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Each creature assigns combat damage equal to its toughness rather than its power"; - } - - public DoranTheSiegeTowerCombatDamageRuleEffect(final DoranTheSiegeTowerCombatDamageRuleEffect effect) { - super(effect); - } - - @Override - public DoranTheSiegeTowerCombatDamageRuleEffect copy() { - return new DoranTheSiegeTowerCombatDamageRuleEffect(this); - } - - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - // Change the rule - game.getCombat().setUseToughnessForDamage(true); - game.getCombat().addUseToughnessForDamageFilter(StaticFilters.FILTER_PERMANENT_CREATURES); - return true; - } - - @Override - public boolean apply(Game game, Ability source) { - return false; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.RulesEffects; - } -} diff --git a/Mage.Sets/src/mage/cards/d/DormantVolcano.java b/Mage.Sets/src/mage/cards/d/DormantVolcano.java index d43f82f617..8ee5e9f5bb 100644 --- a/Mage.Sets/src/mage/cards/d/DormantVolcano.java +++ b/Mage.Sets/src/mage/cards/d/DormantVolcano.java @@ -30,7 +30,7 @@ public final class DormantVolcano extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MOUNTAIN)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DormantVolcano(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DoublingChant.java b/Mage.Sets/src/mage/cards/d/DoublingChant.java index 2bc93750d2..1a459bce34 100644 --- a/Mage.Sets/src/mage/cards/d/DoublingChant.java +++ b/Mage.Sets/src/mage/cards/d/DoublingChant.java @@ -78,7 +78,7 @@ class DoublingChantEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard("nothing (no valid card available)"); filter.add(new NamePredicate("creatureName")); TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - controller.searchLibrary(target, game); + controller.searchLibrary(target, source, game); } } for (Permanent creature : creatures) { @@ -91,7 +91,7 @@ class DoublingChantEffect extends OneShotEffect { filter.add(Predicates.not(Predicates.or(uuidPredicates))); } TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { chosenCards.add(card); diff --git a/Mage.Sets/src/mage/cards/d/DoubtlessOne.java b/Mage.Sets/src/mage/cards/d/DoubtlessOne.java index 03a655b148..b29eff1bd4 100644 --- a/Mage.Sets/src/mage/cards/d/DoubtlessOne.java +++ b/Mage.Sets/src/mage/cards/d/DoubtlessOne.java @@ -22,7 +22,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public final class DoubtlessOne extends CardImpl { - final static FilterPermanent filter = new FilterPermanent("Clerics on the battlefield"); + static final FilterPermanent filter = new FilterPermanent("Clerics on the battlefield"); static { filter.add(new SubtypePredicate(SubType.CLERIC)); diff --git a/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java b/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java new file mode 100644 index 0000000000..997df68c94 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinArchitectOfLaw.java @@ -0,0 +1,56 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.*; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinArchitectOfLaw extends CardImpl { + + public DovinArchitectOfLaw(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOVIN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // +1: You gain 2 life and draw a card. + Ability ability = new LoyaltyAbility(new GainLifeEffect(2), 1); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + + // -1: Tap target creature. It doesn't untap during its controller's next untap step. + ability = new LoyaltyAbility(new TapTargetEffect(), -1); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("It")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // -9: Tap all permanents target opponent controls. That player skips their next untap step. + ability = new LoyaltyAbility(new TapAllTargetPlayerControlsEffect(StaticFilters.FILTER_PERMANENT), -9); + ability.addEffect(new SkipNextPlayerUntapStepEffect("That player")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private DovinArchitectOfLaw(final DovinArchitectOfLaw card) { + super(card); + } + + @Override + public DovinArchitectOfLaw copy() { + return new DovinArchitectOfLaw(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java b/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java new file mode 100644 index 0000000000..ea2400d975 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinGrandArbiter.java @@ -0,0 +1,107 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DamagedPlayerEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ThopterColorlessToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinGrandArbiter extends CardImpl { + + public DovinGrandArbiter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOVIN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // +1: Until end of turn, whenever a creature you control deals combat damage to a player, put a loyalty counter on Dovin, Grand Arbiter. + this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( + new DovinGrandArbiterDelayedTriggeredAbility(), false + ), 1)); + + // -1: Create a 1/1 colorless Thopter artifact creature token with flying. You gain 1 life. + Ability ability = new LoyaltyAbility(new CreateTokenEffect(new ThopterColorlessToken()), -1); + ability.addEffect(new GainLifeEffect(1).setText("You gain 1 life.")); + this.addAbility(ability); + + // -7: Look at the top ten cards of your library. Put three of them into your hand and the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( + new StaticValue(10), false, + new StaticValue(3), StaticFilters.FILTER_CARD, + Zone.LIBRARY, false, false, false, + Zone.HAND, false, false, false + ).setBackInRandomOrder(true).setText("Look at the top ten cards of your library. " + + "Put three of them into your hand and the rest " + + "on the bottom of your library in a random order." + ), -7)); + } + + private DovinGrandArbiter(final DovinGrandArbiter card) { + super(card); + } + + @Override + public DovinGrandArbiter copy() { + return new DovinGrandArbiter(this); + } +} + +class DovinGrandArbiterDelayedTriggeredAbility extends DelayedTriggeredAbility { + + DovinGrandArbiterDelayedTriggeredAbility() { + super(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance()), Duration.EndOfTurn, false); + } + + private DovinGrandArbiterDelayedTriggeredAbility(final DovinGrandArbiterDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public DovinGrandArbiterDelayedTriggeredAbility copy() { + return new DovinGrandArbiterDelayedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (((DamagedPlayerEvent) event).isCombatDamage()) { + Permanent creature = game.getPermanent(event.getSourceId()); + if (creature != null && creature.isControlledBy(controllerId)) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Until end of turn, whenever a creature you control " + + "deals combat damage to a player, " + + "put a loyalty counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java b/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java new file mode 100644 index 0000000000..734bef43bd --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinHandOfControl.java @@ -0,0 +1,87 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.SpellAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +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.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinHandOfControl extends CardImpl { + + public DovinHandOfControl(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W/U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DOVIN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Artifact, instant, and sorcery spells your opponents cast cost {1} more to cast. + this.addAbility(new SimpleStaticAbility(new DovinHandOfControlEffect())); + + // -1: Until your next turn, prevent all damage that would be dealt to and dealt by target permanent an opponent controls. + Ability ability = new LoyaltyAbility(new PreventDamageToTargetEffect( + Duration.UntilYourNextTurn + ).setText("Until your next turn, prevent all damage that would be dealt to"), -1); + ability.addEffect(new PreventDamageByTargetEffect( + Duration.UntilYourNextTurn + ).setText("and dealt by target permanent an opponent controls")); + ability.addTarget(new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT)); + this.addAbility(ability); + } + + private DovinHandOfControl(final DovinHandOfControl card) { + super(card); + } + + @Override + public DovinHandOfControl copy() { + return new DovinHandOfControl(this); + } +} + +class DovinHandOfControlEffect extends CostModificationEffectImpl { + + DovinHandOfControlEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "Artifact, instant, and sorcery spells your opponents cast cost {1} more to cast"; + } + + private DovinHandOfControlEffect(DovinHandOfControlEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -1); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + Card card = game.getCard(abilityToModify.getSourceId()); + return card != null && (card.isInstantOrSorcery() || card.isArtifact()) + && game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId()); + } + + @Override + public DovinHandOfControlEffect copy() { + return new DovinHandOfControlEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinsAcuity.java b/Mage.Sets/src/mage/cards/d/DovinsAcuity.java new file mode 100644 index 0000000000..96efb5f977 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinsAcuity.java @@ -0,0 +1,72 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ReturnToHandSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TurnPhase; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; + +import java.util.EnumSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinsAcuity extends CardImpl { + + private static final FilterSpell filter = new FilterSpell(); + + static { + filter.add(new CardTypePredicate(CardType.INSTANT)); + } + + public DovinsAcuity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}"); + + // When Dovin's Acuity enters the battlefield, you gain 2 life and draw a card. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2)); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and draw a card")); + this.addAbility(ability); + + // Whenever you cast an instant spell during your main phase, you may return Dovin's Acuity to its owner's hand. + this.addAbility(new ConditionalTriggeredAbility( + new SpellCastControllerTriggeredAbility( + new ReturnToHandSourceEffect(true), filter, true + ), DovinsAcuityCondition.instance, + "Whenever you cast an instant spell during your main phase, " + + "you may return {this} to its owner's hand." + )); + } + + private DovinsAcuity(final DovinsAcuity card) { + super(card); + } + + @Override + public DovinsAcuity copy() { + return new DovinsAcuity(this); + } +} + +enum DovinsAcuityCondition implements Condition { + + instance; + private static final Set turnPhases = EnumSet.of(TurnPhase.PRECOMBAT_MAIN, TurnPhase.POSTCOMBAT_MAIN); + + @Override + public boolean apply(Game game, Ability source) { + return game.isActivePlayer(source.getControllerId()) + && turnPhases.contains(game.getTurn().getPhase().getType()); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DovinsAutomaton.java b/Mage.Sets/src/mage/cards/d/DovinsAutomaton.java new file mode 100644 index 0000000000..e1e17cde99 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinsAutomaton.java @@ -0,0 +1,61 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +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 mage.constants.Zone; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinsAutomaton extends CardImpl { + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(new FilterControlledPlaneswalkerPermanent(SubType.DOVIN)); + + public DovinsAutomaton(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + + this.subtype.add(SubType.HOMUNCULUS); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // As long as you control a Dovin planeswalker, Dovin's Automaton gets +2/+2 and has vigilance. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), + condition, "As long as you control a Dovin planeswalker, {this} gets +2/+2" + ) + ); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + VigilanceAbility.getInstance(), Duration.WhileOnBattlefield + ), condition, "and has vigilance" + )); + this.addAbility(ability); + } + + private DovinsAutomaton(final DovinsAutomaton card) { + super(card); + } + + @Override + public DovinsAutomaton copy() { + return new DovinsAutomaton(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinsDismissal.java b/Mage.Sets/src/mage/cards/d/DovinsDismissal.java new file mode 100644 index 0000000000..598029d98b --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinsDismissal.java @@ -0,0 +1,49 @@ +package mage.cards.d; + +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinsDismissal extends CardImpl { + + private static final FilterCard filter = new FilterCard("card named Dovin, Architect of Law"); + private static final FilterPermanent filter2 = new FilterCreaturePermanent("tapped creature"); + + static { + filter.add(new NamePredicate("Dovin, Architect of Law")); + filter2.add(TappedPredicate.instance); + } + + public DovinsDismissal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{U}"); + + // Put up to one target tapped creature on top of its owner's library. You may search your library and/or graveyard for a card named Dovin, Architect of Law, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); + this.getSpellAbility().addEffect( + new SearchLibraryGraveyardPutInHandEffect(filter, false, true) + ); + this.getSpellAbility().addTarget(new TargetPermanent(0, 1, filter2, false)); + } + + private DovinsDismissal(final DovinsDismissal card) { + super(card); + } + + @Override + public DovinsDismissal copy() { + return new DovinsDismissal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DovinsVeto.java b/Mage.Sets/src/mage/cards/d/DovinsVeto.java new file mode 100644 index 0000000000..2abe0030c5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DovinsVeto.java @@ -0,0 +1,41 @@ +package mage.cards.d; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CantBeCounteredSourceEffect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DovinsVeto extends CardImpl { + + public DovinsVeto(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{U}"); + + // This spell can't be countered. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new CantBeCounteredSourceEffect() + ).setRuleAtTheTop(true)); + + // Counter target noncreature spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_NON_CREATURE)); + } + + private DovinsVeto(final DovinsVeto card) { + super(card); + } + + @Override + public DovinsVeto copy() { + return new DovinsVeto(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DraconicRoar.java b/Mage.Sets/src/mage/cards/d/DraconicRoar.java index 2eb1d61e95..34102c4f39 100644 --- a/Mage.Sets/src/mage/cards/d/DraconicRoar.java +++ b/Mage.Sets/src/mage/cards/d/DraconicRoar.java @@ -1,15 +1,14 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.RevealTargetFromHandCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -22,23 +21,19 @@ import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreaturePermanent; import mage.watchers.common.DragonOnTheBattlefieldWhileSpellWasCastWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DraconicRoar extends CardImpl { - private static final FilterCard filter = new FilterCard("a Dragon card from your hand (you don't have to)"); - - static { - filter.add(new SubtypePredicate(SubType.DRAGON)); - } - public DraconicRoar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // As an additional cost to cast Draconic Roar, you may reveal a Dragon card from your hand. this.getSpellAbility().addEffect(new InfoEffect("as an additional cost to cast this spell, you may reveal a Dragon card from your hand")); + this.getSpellAbility().setCostAdjuster(DraconicRoarAdjuster.instance); // Draconic Roar deals 3 damage to target creature. If you revealed a Dragon card or controlled a Dragon as you cast Draconic Roar, Draconic Roar deals 3 damage to that creature's controller. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); @@ -47,18 +42,6 @@ public final class DraconicRoar extends CardImpl { this.getSpellAbility().addWatcher(new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); } - @Override - public void adjustCosts(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - if (controller.getHand().count(filter, game) > 0) { - ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0,1, filter))); - } - } - } - } - public DraconicRoar(final DraconicRoar card) { super(card); } @@ -69,6 +52,25 @@ public final class DraconicRoar extends CardImpl { } } +enum DraconicRoarAdjuster implements CostAdjuster { + instance; + + private static final FilterCard filter = new FilterCard("a Dragon card from your hand (you don't have to)"); + + static { + filter.add(new SubtypePredicate(SubType.DRAGON)); + } + + @Override + public void adjustCosts(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + if (controller.getHand().count(filter, game) > 0) { + ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, 1, filter))); + } + } + } +} class DraconicRoarEffect extends OneShotEffect { @@ -90,7 +92,7 @@ class DraconicRoarEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); if (watcher != null && watcher.castWithConditionTrue(source.getId())) { Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/d/Dracoplasm.java b/Mage.Sets/src/mage/cards/d/Dracoplasm.java index aa478448c1..974da8aa9d 100644 --- a/Mage.Sets/src/mage/cards/d/Dracoplasm.java +++ b/Mage.Sets/src/mage/cards/d/Dracoplasm.java @@ -63,7 +63,7 @@ class DracoplasmEffect extends ReplacementEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public DracoplasmEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DragonArch.java b/Mage.Sets/src/mage/cards/d/DragonArch.java index 6b9c444fee..5a152ea013 100644 --- a/Mage.Sets/src/mage/cards/d/DragonArch.java +++ b/Mage.Sets/src/mage/cards/d/DragonArch.java @@ -24,7 +24,7 @@ public final class DragonArch extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("a multicolored creature card"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public DragonArch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DragonGrip.java b/Mage.Sets/src/mage/cards/d/DragonGrip.java index f84bd0ffa2..9280f0c4a2 100644 --- a/Mage.Sets/src/mage/cards/d/DragonGrip.java +++ b/Mage.Sets/src/mage/cards/d/DragonGrip.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.FerociousCondition; @@ -12,6 +10,7 @@ import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; @@ -20,21 +19,23 @@ import mage.constants.*; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DragonGrip extends CardImpl { public DragonGrip(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); this.subtype.add(SubType.AURA); // Ferocious - If you control a creature with power 4 or greater, you may cast Dragon Grip as though it had flash. AsThoughEffect effect = new CastAsThoughItHadFlashSourceEffect(Duration.EndOfGame); effect.setText("Ferocious — If you control a creature with power 4 or greater, you may cast Dragon Grip as though it had flash"); this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalAsThoughEffect(effect, - FerociousCondition.instance))); + FerociousCondition.instance)) + .addHint(FerociousHint.instance)); // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); diff --git a/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java b/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java index dab3732b81..380bcc134b 100644 --- a/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java +++ b/Mage.Sets/src/mage/cards/d/DragonlordKolaghan.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.SimpleStaticAbility; @@ -13,20 +11,18 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DragonlordKolaghan extends CardImpl { @@ -93,16 +89,18 @@ class DragonlordKolaghanTriggeredAbility extends TriggeredAbilityImpl { Spell spell = game.getStack().getSpell(event.getSourceId()); if (spell != null && !spell.isFaceDown(game) && (spell.isCreature() || spell.isPlaneswalker())) { Player opponent = game.getPlayer(event.getPlayerId()); - boolean sameName = false; - for (Card graveCard : opponent.getGraveyard().getCards(game)) { - if (graveCard.getName().equals(spell.getName())) { - sameName = true; - break; + if(opponent != null) { + boolean sameName = false; + for (Card graveCard : opponent.getGraveyard().getCards(game)) { + if (CardUtil.haveSameNames(graveCard, spell)) { + sameName = true; + break; + } + } + if (sameName) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); + return true; } - } - if (sameName) { - this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); - return true; } } } diff --git a/Mage.Sets/src/mage/cards/d/DragonlordsPrerogative.java b/Mage.Sets/src/mage/cards/d/DragonlordsPrerogative.java index 6ce626db3f..68af370d1a 100644 --- a/Mage.Sets/src/mage/cards/d/DragonlordsPrerogative.java +++ b/Mage.Sets/src/mage/cards/d/DragonlordsPrerogative.java @@ -1,11 +1,11 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; import mage.abilities.costs.Cost; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.RevealTargetFromHandCost; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.ContinuousRuleModifyingEffect; @@ -25,24 +25,20 @@ import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DragonlordsPrerogative extends CardImpl { - private static final FilterCard filter = new FilterCard("a Dragon card from your hand"); - - static { - filter.add(new SubtypePredicate(SubType.DRAGON)); - } - public DragonlordsPrerogative(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); // As an additional cost to cast Dragonlord's Prerogative, you may reveal a Dragon card from your hand. this.getSpellAbility().addEffect(new InfoEffect("as an additional cost to cast this spell, you may reveal a Dragon card from your hand")); - + this.getSpellAbility().setCostAdjuster(DragonlordsPrerogativeAdjuster.instance); + // If you revealed a Dragon card or controlled a Dragon as you cast Dragonlord's Prerogative, Dragonlord's Prerogative can't be countered. Condition condition = new DragonlordsPrerogativeCondition(); ContinuousRuleModifyingEffect cantBeCountered = new CantBeCounteredSourceEffect(); @@ -50,22 +46,12 @@ public final class DragonlordsPrerogative extends CardImpl { conditionalCantBeCountered.setText("
    If you revealed a Dragon card or controlled a Dragon as you cast {this}, this spell can't be countered"); Ability ability = new SimpleStaticAbility(Zone.STACK, conditionalCantBeCountered); this.addAbility(ability); - + // Draw four cards. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(4)); } - - @Override - public void adjustCosts(Ability ability, Game game) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - if (controller.getHand().count(filter, game) > 0) { - ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0,1, filter))); - } - } - } - + public DragonlordsPrerogative(final DragonlordsPrerogative card) { super(card); } @@ -76,9 +62,28 @@ public final class DragonlordsPrerogative extends CardImpl { } } +enum DragonlordsPrerogativeAdjuster implements CostAdjuster { + instance; + private static final FilterCard filter = new FilterCard("a Dragon card from your hand"); + + static { + filter.add(new SubtypePredicate(SubType.DRAGON)); + } + + @Override + public void adjustCosts(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + if (controller.getHand().count(filter, game) > 0) { + ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, 1, filter))); + } + } + } +} + class DragonlordsPrerogativeCondition implements Condition { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("Dragon"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Dragon"); static { filter.add(new SubtypePredicate(SubType.DRAGON)); @@ -89,7 +94,7 @@ class DragonlordsPrerogativeCondition implements Condition { boolean applies = false; Spell spell = game.getStack().getSpell(source.getSourceId()); if (spell != null && spell.getSpellAbility() != null) { - for(Cost cost: spell.getSpellAbility().getCosts()) { + for (Cost cost : spell.getSpellAbility().getCosts()) { if (cost instanceof RevealTargetFromHandCost) { applies = !cost.getTargets().isEmpty(); break; diff --git a/Mage.Sets/src/mage/cards/d/Dragonrage.java b/Mage.Sets/src/mage/cards/d/Dragonrage.java index 410fe9bdc5..d378be9433 100644 --- a/Mage.Sets/src/mage/cards/d/Dragonrage.java +++ b/Mage.Sets/src/mage/cards/d/Dragonrage.java @@ -28,7 +28,7 @@ public final class Dragonrage extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature you control"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/d/DragonsClaw.java b/Mage.Sets/src/mage/cards/d/DragonsClaw.java index eafaca5ef5..647d66407c 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsClaw.java +++ b/Mage.Sets/src/mage/cards/d/DragonsClaw.java @@ -17,7 +17,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class DragonsClaw extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a red spell"); + private static final FilterSpell filter = new FilterSpell("a red spell"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java b/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java index 528687ae19..a4fd2922cc 100644 --- a/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java +++ b/Mage.Sets/src/mage/cards/d/DragonsEyeSavants.java @@ -25,7 +25,7 @@ import mage.target.common.TargetOpponent; */ public final class DragonsEyeSavants extends CardImpl { - private final static FilterCard filter = new FilterCard("a blue card in your hand"); + private static final FilterCard filter = new FilterCard("a blue card in your hand"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); } diff --git a/Mage.Sets/src/mage/cards/d/DragonscaleGeneral.java b/Mage.Sets/src/mage/cards/d/DragonscaleGeneral.java index e9ba1f5213..ed08960942 100644 --- a/Mage.Sets/src/mage/cards/d/DragonscaleGeneral.java +++ b/Mage.Sets/src/mage/cards/d/DragonscaleGeneral.java @@ -24,7 +24,7 @@ public final class DragonscaleGeneral extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creatures you control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/DrainLife.java b/Mage.Sets/src/mage/cards/d/DrainLife.java index e3c756037b..9c06c1a2d0 100644 --- a/Mage.Sets/src/mage/cards/d/DrainLife.java +++ b/Mage.Sets/src/mage/cards/d/DrainLife.java @@ -1,29 +1,32 @@ package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; import mage.filter.FilterMana; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author KholdFuzion - * */ public final class DrainLife extends CardImpl { - static final FilterMana filterBlack = new FilterMana(); + private static final FilterMana filterBlack = new FilterMana(); static { filterBlack.setBlack(true); @@ -33,6 +36,10 @@ public final class DrainLife extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{1}{B}"); // Spend only black mana on X. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("Spend only black mana on X")).setRuleAtTheTop(true) + ); + // Drain Life deals X damage to any target. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness. this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new DrainLifeEffect()); @@ -42,7 +49,7 @@ public final class DrainLife extends CardImpl { } } - public DrainLife(final DrainLife card) { + private DrainLife(final DrainLife card) { super(card); } @@ -54,12 +61,14 @@ public final class DrainLife extends CardImpl { class DrainLifeEffect extends OneShotEffect { - public DrainLifeEffect() { + DrainLifeEffect() { super(Outcome.Damage); - staticText = "Spend only black mana on X.
    {this} deals X damage to any target. You gain life equal to the damage dealt, but not more life than the player's life total before Drain Life dealt damage or the creature's toughness"; + staticText = "{this} deals X damage to any target. You gain life equal to the damage dealt, " + + "but not more life than the player’s life total before the damage was dealt, " + + "the planeswalker’s loyalty before the damage was dealt, or the creature’s toughness."; } - public DrainLifeEffect(final DrainLifeEffect effect) { + private DrainLifeEffect(final DrainLifeEffect effect) { super(effect); } @@ -67,31 +76,32 @@ class DrainLifeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int amount = source.getManaCostsToPay().getX(); int lifetogain = amount; - if (amount > 0) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - if (permanent.getToughness().getValue() < amount) { - lifetogain = permanent.getToughness().getValue(); - } - permanent.damage(amount, source.getSourceId(), game, false, true); - } else { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null) { - if (player.getLife() < amount) { - lifetogain = player.getLife(); - } - player.damage(amount, source.getSourceId(), game, false, true); - } else { - return false; - } - } - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.gainLife(lifetogain, game, source); + if (amount == 0) { + return true; + } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (permanent.isCreature()) { + lifetogain = Math.min(permanent.getToughness().getValue(), lifetogain); + } else if (permanent.isPlaneswalker()) { + lifetogain = Math.min(permanent.getCounters(game).getCount(CounterType.LOYALTY), lifetogain); } else { return false; } + permanent.damage(amount, source.getSourceId(), game); + } else { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + lifetogain = Math.min(player.getLife(), lifetogain); + player.damage(amount, source.getSourceId(), game); } + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + controller.gainLife(lifetogain, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/d/DrakeUmbra.java b/Mage.Sets/src/mage/cards/d/DrakeUmbra.java index 299d7b0737..8a124d093f 100644 --- a/Mage.Sets/src/mage/cards/d/DrakeUmbra.java +++ b/Mage.Sets/src/mage/cards/d/DrakeUmbra.java @@ -2,6 +2,7 @@ package mage.cards.d; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -17,13 +18,12 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author Loki */ public final class DrakeUmbra extends CardImpl { public DrakeUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{U}"); this.subtype.add(SubType.AURA); @@ -33,9 +33,12 @@ public final class DrakeUmbra extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature gets +3/+3 and has flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/d/DramaticReversal.java b/Mage.Sets/src/mage/cards/d/DramaticReversal.java index 4d705f42b7..a8d990a82d 100644 --- a/Mage.Sets/src/mage/cards/d/DramaticReversal.java +++ b/Mage.Sets/src/mage/cards/d/DramaticReversal.java @@ -16,7 +16,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class DramaticReversal extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanents"); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanents"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java b/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java index 025eb35774..404fafb5f7 100644 --- a/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java +++ b/Mage.Sets/src/mage/cards/d/DranaKalastriaBloodchief.java @@ -37,8 +37,8 @@ public final class DranaKalastriaBloodchief extends CardImpl { this.toughness = new MageInt(4); this.addAbility(FlyingAbility.getInstance()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(new StaticValue(0), new SignInversionDynamicValue(new ManacostVariableValue()), Duration.EndOfTurn), new ManaCostsImpl("{X}{B}{B}")); - ability.addEffect(new BoostSourceEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(new StaticValue(0), new SignInversionDynamicValue(ManacostVariableValue.instance), Duration.EndOfTurn), new ManaCostsImpl("{X}{B}{B}")); + ability.addEffect(new BoostSourceEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DranasChosen.java b/Mage.Sets/src/mage/cards/d/DranasChosen.java index 3afa5ccd68..d0dd78f548 100644 --- a/Mage.Sets/src/mage/cards/d/DranasChosen.java +++ b/Mage.Sets/src/mage/cards/d/DranasChosen.java @@ -31,7 +31,7 @@ public final class DranasChosen extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DranasChosen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DrasticRevelation.java b/Mage.Sets/src/mage/cards/d/DrasticRevelation.java index 5f314f7ae0..faec9cf5da 100644 --- a/Mage.Sets/src/mage/cards/d/DrasticRevelation.java +++ b/Mage.Sets/src/mage/cards/d/DrasticRevelation.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -13,18 +11,15 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class DrasticRevelation extends CardImpl { public DrasticRevelation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{U}{B}{R}"); - - - - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{B}{R}"); // Discard your hand. Draw seven cards, then discard three cards at random. this.getSpellAbility().addEffect(new DrasticRevelationEffect()); @@ -54,13 +49,15 @@ class DrasticRevelationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - you.discardToMax(game); - you.drawCards(7, game); - Cards hand = you.getHand(); - for (int i = 0; i < 3; i++) { - Card card = hand.getRandom(game); - if (card != null) { - you.discard(card, source, game); + if (you != null) { + you.discard(you.getHand().size(), false, source, game); + you.drawCards(7, game); + Cards hand = you.getHand(); + for (int i = 0; i < 3; i++) { + Card card = hand.getRandom(game); + if (card != null) { + you.discard(card, source, game); + } } } return false; diff --git a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java index 9b8e1ad205..2df82acf88 100644 --- a/Mage.Sets/src/mage/cards/d/DreadCacodemon.java +++ b/Mage.Sets/src/mage/cards/d/DreadCacodemon.java @@ -32,7 +32,7 @@ public final class DreadCacodemon extends CardImpl { private static final FilterCreaturePermanent otherCreaturesYouControl = new FilterCreaturePermanent("other creatures you control"); static { otherCreaturesYouControl.add(new ControllerPredicate(TargetController.YOU)); - otherCreaturesYouControl.add(new AnotherPredicate()); + otherCreaturesYouControl.add(AnotherPredicate.instance); } public DreadCacodemon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DreadSlag.java b/Mage.Sets/src/mage/cards/d/DreadSlag.java index dd7548175b..bebbcd720d 100644 --- a/Mage.Sets/src/mage/cards/d/DreadSlag.java +++ b/Mage.Sets/src/mage/cards/d/DreadSlag.java @@ -32,7 +32,7 @@ public final class DreadSlag extends CardImpl { // Trample this.addAbility(TrampleAbility.getInstance()); // Dread Slag gets -4/-4 for each card in your hand. - DynamicValue amount = new MultipliedValue(new CardsInControllerHandCount(), -4); + DynamicValue amount = new MultipliedValue(CardsInControllerHandCount.instance, -4); Effect effect = new BoostSourceEffect(amount, amount, Duration.WhileOnBattlefield); effect.setText("{this} gets -4/-4 for each card in your hand"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/d/DreadWight.java b/Mage.Sets/src/mage/cards/d/DreadWight.java new file mode 100644 index 0000000000..e3225c405f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadWight.java @@ -0,0 +1,233 @@ +package mage.cards.d; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class DreadWight extends CardImpl { + + public DreadWight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // At end of combat, put a paralyzation counter on each creature blocking or blocked by Dread Wight and tap those creatures. Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. Each of those creatures gains "{4}: Remove a paralyzation counter from this creature." + this.addAbility(new DreadWightTriggeredAbility( + new CreateDelayedTriggeredAbilityEffect( + new AtTheEndOfCombatDelayedTriggeredAbility( + new DreadWightEffect())))); + + } + + public DreadWight(final DreadWight card) { + super(card); + } + + @Override + public DreadWight copy() { + return new DreadWight(this); + } +} + +class DreadWightTriggeredAbility extends TriggeredAbilityImpl { + + DreadWightTriggeredAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect); + this.usesStack = false; + } + + DreadWightTriggeredAbility(final DreadWightTriggeredAbility ability) { + super(ability); + } + + @Override + public DreadWightTriggeredAbility copy() { + return new DreadWightTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return (event.getType() == EventType.BLOCKER_DECLARED); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(getSourceId())) { // Dread Wight is the blocker + getAllEffects().setTargetPointer(new FixedTarget(event.getTargetId())); + return true; + } + if (event.getTargetId().equals(getSourceId())) { // Dread Wight is the attacker + getAllEffects().setTargetPointer(new FixedTarget(event.getSourceId())); + return true; + } + return false; + } + +} + +class DreadWightEffect extends OneShotEffect { + + String rule = "doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it."; + + public DreadWightEffect() { + super(Outcome.Detriment); + this.staticText = "put a paralyzation counter on each creature blocking or blocked by {this} and tap those creatures. " + + "Each of those creatures doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it. " + + "Each of those creatures gains \"{4}: Remove a paralyzation counter from this creature.\""; + } + + public DreadWightEffect(final DreadWightEffect effect) { + super(effect); + } + + @Override + public DreadWightEffect copy() { + return new DreadWightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); + if (permanent != null) { + // add paralyzation counter + Effect effect = new AddCountersTargetEffect(CounterType.PARALYZATION.createInstance()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + effect.apply(game, source); + // tap permanent + permanent.tap(game); + // does not untap while paralyzation counter is on it + ContinuousRuleModifyingEffect effect2 = new DreadWightDoNotUntapEffect( + Duration.WhileOnBattlefield, + permanent.getId()); + effect2.setText("This creature doesn't untap during its controller's untap step for as long as it has a paralyzation counter on it"); + Condition condition = new DreadWightCounterCondition(permanent.getId()); + ConditionalContinuousRuleModifyingEffect conditionalEffect = new ConditionalContinuousRuleModifyingEffect( + effect2, + condition); + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + conditionalEffect); + ContinuousEffect effect3 = new GainAbilityTargetEffect( + ability, + Duration.WhileOnBattlefield); + ability.setRuleVisible(true); + effect3.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect3, source); + // each gains 4: remove paralyzation counter + Ability activatedAbility = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new RemoveCounterSourceEffect(CounterType.PARALYZATION.createInstance()), + new ManaCostsImpl("{4}")); + ContinuousEffect effect4 = new GainAbilityTargetEffect( + activatedAbility, + Duration.WhileOnBattlefield); + effect4.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect4, source); + return true; + } + return false; + } +} + +class DreadWightDoNotUntapEffect extends ContinuousRuleModifyingEffectImpl { + + UUID permanentId; + + public DreadWightDoNotUntapEffect(Duration duration, UUID permanentId) { + super(duration, Outcome.Detriment); + this.permanentId = permanentId; + } + + public DreadWightDoNotUntapEffect(final DreadWightDoNotUntapEffect effect) { + super(effect); + this.permanentId = effect.permanentId; + } + + @Override + public DreadWightDoNotUntapEffect copy() { + return new DreadWightDoNotUntapEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + Permanent permanentToUntap = game.getPermanent((event.getTargetId())); + if (permanentToUntap != null) { + return permanentToUntap.getLogName() + " doesn't untap."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UNTAP; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId() == permanentId + && game.isActivePlayer(game.getPermanent(permanentId).getControllerId()); + } +} + +class DreadWightCounterCondition implements Condition { + + UUID permanentId; + + public DreadWightCounterCondition(UUID permanentId) { + this.permanentId = permanentId; + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null) { + return permanent.getCounters(game).getCount(CounterType.PARALYZATION) > 0; + } + return false; + } + + @Override + public String toString() { + return "has counter on it"; + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java new file mode 100644 index 0000000000..0a7880c94c --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadhordeArcanist.java @@ -0,0 +1,165 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DreadhordeArcanist extends CardImpl { + + private static final FilterCard filter = new FilterInstantOrSorceryCard( + "instant or sorcery card with converted mana cost less than or equal to this creature's power" + ); + + static { + filter.add(DreadhordeArcanistPredicate.instance); + } + + public DreadhordeArcanist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Dreadhorde Arcanist attacks, you may cast target instant or sorcery card with converted mana cost less than or equal to Dreadhorde Arcanist's power from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead. + Ability ability = new AttacksTriggeredAbility(new DreadhordeArcanistEffect(), false); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private DreadhordeArcanist(final DreadhordeArcanist card) { + super(card); + } + + @Override + public DreadhordeArcanist copy() { + return new DreadhordeArcanist(this); + } +} + +enum DreadhordeArcanistPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + return sourcePermanent != null + & input.getObject().getConvertedManaCost() <= sourcePermanent.getPower().getValue(); + } +} + +class DreadhordeArcanistEffect extends OneShotEffect { + + DreadhordeArcanistEffect() { + super(Outcome.Benefit); + this.staticText = "you may cast target instant or sorcery card with converted mana cost " + + "less than or equal to {this}'s power from your graveyard without paying its mana cost. " + + "If that card would be put into your graveyard this turn, exile it instead."; + } + + private DreadhordeArcanistEffect(final DreadhordeArcanistEffect effect) { + super(effect); + } + + @Override + public DreadhordeArcanistEffect copy() { + return new DreadhordeArcanistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); + if (card == null + || !controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game) + || !controller.cast( + card.getSpellAbility(), game, true, + new MageObjectReference(source.getSourceObject(game), game) + )) { + return false; + } + ContinuousEffect effect = new DreadhordeArcanistReplacementEffect(card.getId()); + effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); + game.addEffect(effect, source); + return true; + } +} + +class DreadhordeArcanistReplacementEffect extends ReplacementEffectImpl { + + private final UUID cardId; + + DreadhordeArcanistReplacementEffect(UUID cardId) { + super(Duration.EndOfTurn, Outcome.Exile); + this.cardId = cardId; + staticText = "If that card would be put into your graveyard this turn, exile it instead"; + } + + private DreadhordeArcanistReplacementEffect(final DreadhordeArcanistReplacementEffect effect) { + super(effect); + this.cardId = effect.cardId; + } + + @Override + public DreadhordeArcanistReplacementEffect copy() { + return new DreadhordeArcanistReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(this.cardId); + if (controller != null && card != null) { + controller.moveCardToExileWithInfo( + card, null, "", source.getSourceId(), + game, Zone.STACK, true + ); + return true; + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD + && zEvent.getTargetId().equals(this.cardId); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeButcher.java b/Mage.Sets/src/mage/cards/d/DreadhordeButcher.java new file mode 100644 index 0000000000..6e99a3b55f --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadhordeButcher.java @@ -0,0 +1,57 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DreadhordeButcher extends CardImpl { + + public DreadhordeButcher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Dreadhorde Butcher deals combat damage to a player or planeswalker, put a +1/+1 counter on Dreadhorde Butcher. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance() + ), false).setOrPlaneswalker(true)); + + // When Dreadhorde Butcher dies, it deals damage equal to its power to any target. + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect( + new SourcePermanentPowerCount() + ).setText("it deals damage equal to its power to any target")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private DreadhordeButcher(final DreadhordeButcher card) { + super(card); + } + + @Override + public DreadhordeButcher copy() { + return new DreadhordeButcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeInvasion.java b/Mage.Sets/src/mage/cards/d/DreadhordeInvasion.java new file mode 100644 index 0000000000..5deecbca9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadhordeInvasion.java @@ -0,0 +1,60 @@ +package mage.cards.d; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DreadhordeInvasion extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent(SubType.ZOMBIE, "Zombie token you control with power 6 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 5)); + filter.add(TokenPredicate.instance); + } + + public DreadhordeInvasion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + // At the beginning of your upkeep, you lose 1 life and amass 1. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new LoseLifeSourceControllerEffect(1), TargetController.YOU, false + ); + ability.addEffect(new AmassEffect(1).concatBy("and")); + this.addAbility(ability); + + // Whenever a Zombie token you control with power 6 or greater attacks, it gains lifelink until end of turn. + this.addAbility(new AttacksAllTriggeredAbility( + new GainAbilityTargetEffect( + LifelinkAbility.getInstance(), Duration.EndOfTurn, + "it gains lifelink until end of turn" + ), false, filter, SetTargetPointer.PERMANENT, + false + )); + } + + private DreadhordeInvasion(final DreadhordeInvasion card) { + super(card); + } + + @Override + public DreadhordeInvasion copy() { + return new DreadhordeInvasion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreadhordeTwins.java b/Mage.Sets/src/mage/cards/d/DreadhordeTwins.java new file mode 100644 index 0000000000..ae9100b342 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DreadhordeTwins.java @@ -0,0 +1,56 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DreadhordeTwins extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ZOMBIE, "Zombie tokens"); + + static { + filter.add(TokenPredicate.instance); + } + + public DreadhordeTwins(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.JACKAL); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Dreadhorde Twins enters the battlefield, amass 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(2))); + + // Zombie tokens you control have trample. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + } + + private DreadhordeTwins(final DreadhordeTwins card) { + super(card); + } + + @Override + public DreadhordeTwins copy() { + return new DreadhordeTwins(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/Dreadmalkin.java b/Mage.Sets/src/mage/cards/d/Dreadmalkin.java new file mode 100644 index 0000000000..f31c67f88e --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Dreadmalkin.java @@ -0,0 +1,66 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Dreadmalkin extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("another creature or planeswalker"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.CREATURE) + )); + filter.add(AnotherPredicate.instance); + } + + public Dreadmalkin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.CAT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // {2}{B}, Sacrifice another creature or planeswalker: Put two +1/+1 counters on Dreadmalkin. + Ability ability = new SimpleActivatedAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ManaCostsImpl("{2}{B}") + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private Dreadmalkin(final Dreadmalkin card) { + super(card); + } + + @Override + public Dreadmalkin copy() { + return new Dreadmalkin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DreadshipReef.java b/Mage.Sets/src/mage/cards/d/DreadshipReef.java index 7073e04f11..53a75729b9 100644 --- a/Mage.Sets/src/mage/cards/d/DreadshipReef.java +++ b/Mage.Sets/src/mage/cards/d/DreadshipReef.java @@ -36,7 +36,7 @@ public final class DreadshipReef extends CardImpl { this.addAbility(ability); // {1}, Remove X storage counters from Dreadship Reef: Add X mana in any combination of {U} and/or {B}. ability = new SimpleManaAbility(Zone.BATTLEFIELD, - new AddManaInAnyCombinationEffect(new RemovedCountersForCostValue(), ColoredManaSymbol.U, ColoredManaSymbol.B), + new AddManaInAnyCombinationEffect(RemovedCountersForCostValue.instance, ColoredManaSymbol.U, ColoredManaSymbol.B), new GenericManaCost(1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/d/DreamChisel.java b/Mage.Sets/src/mage/cards/d/DreamChisel.java index 705fe64cc2..8508e9b24b 100644 --- a/Mage.Sets/src/mage/cards/d/DreamChisel.java +++ b/Mage.Sets/src/mage/cards/d/DreamChisel.java @@ -20,7 +20,7 @@ public final class DreamChisel extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public DreamChisel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DreamSalvage.java b/Mage.Sets/src/mage/cards/d/DreamSalvage.java index fcd535a32d..df6fe89ffc 100644 --- a/Mage.Sets/src/mage/cards/d/DreamSalvage.java +++ b/Mage.Sets/src/mage/cards/d/DreamSalvage.java @@ -49,7 +49,7 @@ class CardsDiscardedThisTurnWatcher extends Watcher { private final Map amountOfCardsDiscardedThisTurn = new HashMap<>(); public CardsDiscardedThisTurnWatcher() { - super(CardsDiscardedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CardsDiscardedThisTurnWatcher(final CardsDiscardedThisTurnWatcher watcher) { @@ -102,7 +102,7 @@ class DreamSalvageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CardsDiscardedThisTurnWatcher watcher = (CardsDiscardedThisTurnWatcher) game.getState().getWatchers().get(CardsDiscardedThisTurnWatcher.class.getSimpleName()); + CardsDiscardedThisTurnWatcher watcher = game.getState().getWatcher(CardsDiscardedThisTurnWatcher.class); Player targetOpponent = game.getPlayer(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); if (targetOpponent != null diff --git a/Mage.Sets/src/mage/cards/d/DreamThief.java b/Mage.Sets/src/mage/cards/d/DreamThief.java index 1be3f20e76..4777110118 100644 --- a/Mage.Sets/src/mage/cards/d/DreamThief.java +++ b/Mage.Sets/src/mage/cards/d/DreamThief.java @@ -57,7 +57,7 @@ class CastBlueSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spells != null) { diff --git a/Mage.Sets/src/mage/cards/d/DreamTides.java b/Mage.Sets/src/mage/cards/d/DreamTides.java index 965adba380..6f15d52bf1 100644 --- a/Mage.Sets/src/mage/cards/d/DreamTides.java +++ b/Mage.Sets/src/mage/cards/d/DreamTides.java @@ -59,7 +59,7 @@ class DreamTidesEffect extends OneShotEffect { static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.GREEN))); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } DreamTidesEffect() { diff --git a/Mage.Sets/src/mage/cards/d/DreambornMuse.java b/Mage.Sets/src/mage/cards/d/DreambornMuse.java index 66cc27162b..169107a55c 100644 --- a/Mage.Sets/src/mage/cards/d/DreambornMuse.java +++ b/Mage.Sets/src/mage/cards/d/DreambornMuse.java @@ -25,7 +25,7 @@ public final class DreambornMuse extends CardImpl { this.toughness = new MageInt(2); // At the beginning of each player's upkeep, that player puts the top X cards of their library into their graveyard, where X is the number of cards in their hand. - PutLibraryIntoGraveTargetEffect effect = new PutLibraryIntoGraveTargetEffect(new CardsInTargetPlayerHandCount()); + PutLibraryIntoGraveTargetEffect effect = new PutLibraryIntoGraveTargetEffect(CardsInTargetPlayerHandCount.instance); effect.setText("that player puts the top X cards of their library into their graveyard, where X is the number of cards in their hand."); this.addAbility(new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, false)); diff --git a/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java b/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java index 01d62c7422..c0550a2794 100644 --- a/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java +++ b/Mage.Sets/src/mage/cards/d/DreamcallerSiren.java @@ -32,7 +32,7 @@ public final class DreamcallerSiren extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PIRATE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/d/DreamsGrip.java b/Mage.Sets/src/mage/cards/d/DreamsGrip.java index f136d9ceeb..c15e109f6a 100644 --- a/Mage.Sets/src/mage/cards/d/DreamsGrip.java +++ b/Mage.Sets/src/mage/cards/d/DreamsGrip.java @@ -33,9 +33,9 @@ public final class DreamsGrip extends CardImpl { //or untap target permanent. Mode mode = new Mode(); TargetPermanent target2 = new TargetPermanent(new FilterPermanent("Permanent to untap")); - mode.getTargets().add(target2); + mode.addTarget(target2); Effect untapEffect = new UntapTargetEffect(); - mode.getEffects().add(untapEffect); + mode.addEffect(untapEffect); this.getSpellAbility().addMode(mode); // Entwine {1} diff --git a/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java b/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java index a819a8abf7..06412ef6bf 100644 --- a/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java +++ b/Mage.Sets/src/mage/cards/d/DregsOfSorrow.java @@ -1,10 +1,7 @@ - package mage.cards.d; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -16,39 +13,25 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class DregsOfSorrow extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creatures"); - - static { - filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); - } - public DregsOfSorrow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{4}{B}"); // Destroy X target nonblack creatures. Draw X cards. this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy X target nonblack creatures")); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new ManacostVariableValue())); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.instance)); + this.getSpellAbility().setTargetAdjuster(DregsOfSorrowAdjuster.instance); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetCreaturePermanent(xValue, xValue, filter, false)); - } - } - - public DregsOfSorrow(final DregsOfSorrow card) { super(card); } @@ -58,3 +41,19 @@ public final class DregsOfSorrow extends CardImpl { return new DregsOfSorrow(this); } } + +enum DregsOfSorrowAdjuster implements TargetAdjuster { + instance; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonblack creatures"); + + static { + filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetCreaturePermanent(xValue, xValue, filter, false)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DrillBit.java b/Mage.Sets/src/mage/cards/d/DrillBit.java new file mode 100644 index 0000000000..d229ba4d02 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DrillBit.java @@ -0,0 +1,41 @@ +package mage.cards.d; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DrillBit extends CardImpl { + + public DrillBit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target player reveals their hand. You choose a nonland card from it. That player discards that card. + this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect( + StaticFilters.FILTER_CARD_NON_LAND, TargetController.ANY + )); + this.getSpellAbility().addTarget(new TargetPlayer()); + + // Spectacle {B} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{B}"))); + } + + private DrillBit(final DrillBit card) { + super(card); + } + + @Override + public DrillBit copy() { + return new DrillBit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DrillSkimmer.java b/Mage.Sets/src/mage/cards/d/DrillSkimmer.java index 0b60594721..d379e662a3 100644 --- a/Mage.Sets/src/mage/cards/d/DrillSkimmer.java +++ b/Mage.Sets/src/mage/cards/d/DrillSkimmer.java @@ -30,7 +30,7 @@ public final class DrillSkimmer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("you control another artifact creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CardTypePredicate(CardType.ARTIFACT)); } diff --git a/Mage.Sets/src/mage/cards/d/DrippingTongueZubera.java b/Mage.Sets/src/mage/cards/d/DrippingTongueZubera.java index a5d6b4d3f3..ed36a32932 100644 --- a/Mage.Sets/src/mage/cards/d/DrippingTongueZubera.java +++ b/Mage.Sets/src/mage/cards/d/DrippingTongueZubera.java @@ -27,7 +27,7 @@ public final class DrippingTongueZubera extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new SpiritToken(), new ZuberasDiedDynamicValue()), false), new ZuberasDiedWatcher()); + this.addAbility(new DiesTriggeredAbility(new CreateTokenEffect(new SpiritToken(), ZuberasDiedDynamicValue.instance), false), new ZuberasDiedWatcher()); } public DrippingTongueZubera (final DrippingTongueZubera card) { diff --git a/Mage.Sets/src/mage/cards/d/DrivenDespair.java b/Mage.Sets/src/mage/cards/d/DrivenDespair.java index 7f9b0af253..09d29f92ce 100644 --- a/Mage.Sets/src/mage/cards/d/DrivenDespair.java +++ b/Mage.Sets/src/mage/cards/d/DrivenDespair.java @@ -36,7 +36,7 @@ public final class DrivenDespair extends SplitCard { // Despair {1}{B} // Sorcery // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Until end of turn, creatures you control gain menace and "Whenever this creature deals combat damage to a player, that player discards a card." getRightHalfCard().getSpellAbility().addEffect(new GainAbilityControlledEffect(new MenaceAbility(), Duration.EndOfTurn, StaticFilters.FILTER_CONTROLLED_CREATURES)); ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1), false, true); diff --git a/Mage.Sets/src/mage/cards/d/DrogskolCavalry.java b/Mage.Sets/src/mage/cards/d/DrogskolCavalry.java index 3a2c558bfa..d0613ac520 100644 --- a/Mage.Sets/src/mage/cards/d/DrogskolCavalry.java +++ b/Mage.Sets/src/mage/cards/d/DrogskolCavalry.java @@ -28,7 +28,7 @@ public final class DrogskolCavalry extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another Spirit"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.SPIRIT)); } diff --git a/Mage.Sets/src/mage/cards/d/DromarsCharm.java b/Mage.Sets/src/mage/cards/d/DromarsCharm.java index 3defc227f3..a158e1d80c 100644 --- a/Mage.Sets/src/mage/cards/d/DromarsCharm.java +++ b/Mage.Sets/src/mage/cards/d/DromarsCharm.java @@ -26,12 +26,12 @@ public final class DromarsCharm extends CardImpl { // Choose one - You gain 5 life; or counter target spell; or target creature gets -2/-2 until end of turn. this.getSpellAbility().addEffect(new GainLifeEffect(5)); Mode mode = new Mode(); - mode.getEffects().add(new CounterTargetEffect()); - mode.getTargets().add(new TargetSpell()); + mode.addEffect(new CounterTargetEffect()); + mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DromokasCommand.java b/Mage.Sets/src/mage/cards/d/DromokasCommand.java index 185c7bd0f3..9774d41408 100644 --- a/Mage.Sets/src/mage/cards/d/DromokasCommand.java +++ b/Mage.Sets/src/mage/cards/d/DromokasCommand.java @@ -52,25 +52,25 @@ public final class DromokasCommand extends CardImpl { Mode mode = new Mode(); Effect effect = new SacrificeEffect(filterEnchantment, 1, "target player"); effect.setText("Target player sacrifices an enchantment"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(effect); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // Put a +1/+1 counter on target creature; mode = new Mode(); effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on target creature"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterCreature)); this.getSpellAbility().getModes().addMode(mode); // or Target creature you control fights target creature you don't control. mode = new Mode(); effect = new FightTargetsEffect(); effect.setText("Target creature you control fights target creature you don't control"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetControlledCreaturePermanent()); - mode.getTargets().add(new TargetCreaturePermanent(filterUncontrolledCreature)); + mode.addEffect(effect); + mode.addTarget(new TargetControlledCreaturePermanent()); + mode.addTarget(new TargetCreaturePermanent(filterUncontrolledCreature)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/d/DropOfHoney.java b/Mage.Sets/src/mage/cards/d/DropOfHoney.java index b9c619b819..8f69d77020 100644 --- a/Mage.Sets/src/mage/cards/d/DropOfHoney.java +++ b/Mage.Sets/src/mage/cards/d/DropOfHoney.java @@ -96,7 +96,7 @@ class DropOfHoneyEffect extends OneShotEffect { } } if (permanentToDestroy != null) { - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(" chosen creature: ").append(permanentToDestroy.getName()).toString()); + game.informPlayers(sourcePermanent.getName() + " chosen creature: " + permanentToDestroy.getName()); return permanentToDestroy.destroy(source.getSourceId(), game, true); } return true; @@ -128,6 +128,6 @@ class DropOfHoneyStateTriggeredAbility extends StateTriggeredAbility { @Override public String getRule() { - return new StringBuilder("When there are no creatures on the battlefield, ").append(super.getRule()).toString() ; + return "When there are no creatures on the battlefield, " + super.getRule(); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DrownerOfSecrets.java b/Mage.Sets/src/mage/cards/d/DrownerOfSecrets.java index 149ce963f0..65596971ff 100644 --- a/Mage.Sets/src/mage/cards/d/DrownerOfSecrets.java +++ b/Mage.Sets/src/mage/cards/d/DrownerOfSecrets.java @@ -29,7 +29,7 @@ public final class DrownerOfSecrets extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MERFOLK)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DrownerOfSecrets(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DrudgeSpell.java b/Mage.Sets/src/mage/cards/d/DrudgeSpell.java index 91a2755db4..efd94be990 100644 --- a/Mage.Sets/src/mage/cards/d/DrudgeSpell.java +++ b/Mage.Sets/src/mage/cards/d/DrudgeSpell.java @@ -32,7 +32,7 @@ public final class DrudgeSpell extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SKELETON)); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public DrudgeSpell(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DualNature.java b/Mage.Sets/src/mage/cards/d/DualNature.java index fa4e332271..2105105790 100644 --- a/Mage.Sets/src/mage/cards/d/DualNature.java +++ b/Mage.Sets/src/mage/cards/d/DualNature.java @@ -37,7 +37,7 @@ public final class DualNature extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public DualNature(UUID ownerId, CardSetInfo setInfo) { @@ -130,7 +130,7 @@ class DualNatureCreatureLeavesEffect extends OneShotEffect { Permanent creature = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source)); if (creature != null) { FilterPermanent filter = new FilterPermanent(); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new NamePredicate(creature.getName())); new ExileAllEffect(filter).apply(game, source); return true; diff --git a/Mage.Sets/src/mage/cards/d/DuelingGrounds.java b/Mage.Sets/src/mage/cards/d/DuelingGrounds.java index 92c0cbe041..e1e91f5c25 100644 --- a/Mage.Sets/src/mage/cards/d/DuelingGrounds.java +++ b/Mage.Sets/src/mage/cards/d/DuelingGrounds.java @@ -1,8 +1,5 @@ - package mage.cards.d; -import java.util.Set; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -18,8 +15,10 @@ import mage.game.permanent.Permanent; import mage.watchers.common.AttackedThisTurnWatcher; import mage.watchers.common.BlockedThisTurnWatcher; +import java.util.Set; +import java.util.UUID; + /** - * * @author Quercitron */ public final class DuelingGrounds extends CardImpl { @@ -70,11 +69,14 @@ class NoMoreThanOneCreatureCanAttackEachTurnEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { if (!game.getCombat().getAttackers().isEmpty()) { return false; } - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + if (watcher == null) { + return false; + } Set attackedThisTurnCreatures = watcher.getAttackedThisTurnCreatures(); return attackedThisTurnCreatures.isEmpty() || (attackedThisTurnCreatures.size() == 1 && attackedThisTurnCreatures.contains(new MageObjectReference(attacker, game))); @@ -104,11 +106,14 @@ class NoMoreThanOneCreatureCanBlockEachTurnEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { if (!game.getCombat().getBlockers().isEmpty()) { return false; } - BlockedThisTurnWatcher watcher = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); + BlockedThisTurnWatcher watcher = game.getState().getWatcher(BlockedThisTurnWatcher.class); + if (watcher == null) { + return false; + } Set blockedThisTurnCreatures = watcher.getBlockedThisTurnCreatures(); MageObjectReference blockerReference = new MageObjectReference(blocker.getId(), blocker.getZoneChangeCounter(game), game); return blockedThisTurnCreatures.isEmpty() diff --git a/Mage.Sets/src/mage/cards/d/DuneBroodNephilim.java b/Mage.Sets/src/mage/cards/d/DuneBroodNephilim.java index b4f6e3f9cf..2ea06d3239 100644 --- a/Mage.Sets/src/mage/cards/d/DuneBroodNephilim.java +++ b/Mage.Sets/src/mage/cards/d/DuneBroodNephilim.java @@ -19,7 +19,7 @@ import mage.game.permanent.token.DuneBroodNephilimToken; */ public final class DuneBroodNephilim extends CardImpl { - final static FilterControlledPermanent filterLands = new FilterControlledLandPermanent(); + static final FilterControlledPermanent filterLands = new FilterControlledLandPermanent(); public DuneBroodNephilim(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}{G}{W}"); diff --git a/Mage.Sets/src/mage/cards/d/DuneDiviner.java b/Mage.Sets/src/mage/cards/d/DuneDiviner.java index 72e74cd8e1..55a9939923 100644 --- a/Mage.Sets/src/mage/cards/d/DuneDiviner.java +++ b/Mage.Sets/src/mage/cards/d/DuneDiviner.java @@ -29,7 +29,7 @@ public final class DuneDiviner extends CardImpl { static { filter.add(new SubtypePredicate(SubType.DESERT)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public DuneDiviner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DunesOfTheDead.java b/Mage.Sets/src/mage/cards/d/DunesOfTheDead.java index 26117bd3df..51aa92f461 100644 --- a/Mage.Sets/src/mage/cards/d/DunesOfTheDead.java +++ b/Mage.Sets/src/mage/cards/d/DunesOfTheDead.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.mana.ColorlessManaAbility; @@ -11,21 +9,23 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.game.permanent.token.ZombieToken; +import java.util.UUID; + /** - * * @author ciaccona007 */ public final class DunesOfTheDead extends CardImpl { public DunesOfTheDead(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); - + this.subtype.add(SubType.DESERT); // {T}: Add {C}. addAbility(new ColorlessManaAbility()); + // When Dunes of the Dead is put into a graveyard from the battlefield, create a 2/2 black Zombie creature token. - this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 1), false)); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new CreateTokenEffect(new ZombieToken(), 1))); } public DunesOfTheDead(final DunesOfTheDead card) { diff --git a/Mage.Sets/src/mage/cards/d/DungeonGeists.java b/Mage.Sets/src/mage/cards/d/DungeonGeists.java index ca1adb9746..fe37bde78b 100644 --- a/Mage.Sets/src/mage/cards/d/DungeonGeists.java +++ b/Mage.Sets/src/mage/cards/d/DungeonGeists.java @@ -131,7 +131,7 @@ class DungeonGeistsEffect extends ContinuousRuleModifyingEffectImpl { class DungeonGeistsWatcher extends Watcher { DungeonGeistsWatcher() { - super("ControlLost", WatcherScope.CARD); + super(WatcherScope.CARD); } DungeonGeistsWatcher(DungeonGeistsWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/d/DungroveElder.java b/Mage.Sets/src/mage/cards/d/DungroveElder.java index f12ba5add7..6a3d12ea27 100644 --- a/Mage.Sets/src/mage/cards/d/DungroveElder.java +++ b/Mage.Sets/src/mage/cards/d/DungroveElder.java @@ -23,7 +23,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public final class DungroveElder extends CardImpl { - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); diff --git a/Mage.Sets/src/mage/cards/d/Duplicant.java b/Mage.Sets/src/mage/cards/d/Duplicant.java index 4abfea60c3..0915c8c8da 100644 --- a/Mage.Sets/src/mage/cards/d/Duplicant.java +++ b/Mage.Sets/src/mage/cards/d/Duplicant.java @@ -1,8 +1,5 @@ - package mage.cards.d; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -22,8 +19,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.List; +import java.util.UUID; + /** - * * @author Plopman */ public final class Duplicant extends CardImpl { @@ -31,7 +30,7 @@ public final class Duplicant extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public Duplicant(UUID ownerId, CardSetInfo setInfo) { @@ -117,6 +116,9 @@ class DuplicantContinuousEffect extends ContinuousEffectImpl { if (permanent != null) { if (!permanent.getImprinted().isEmpty()) { List imprinted = permanent.getImprinted(); + if (imprinted == null || imprinted.isEmpty()) { + return false; + } Card card = game.getCard(imprinted.get(imprinted.size() - 1)); if (card != null && card.isCreature()) { switch (layer) { @@ -134,7 +136,6 @@ class DuplicantContinuousEffect extends ContinuousEffectImpl { } } return true; - } } diff --git a/Mage.Sets/src/mage/cards/d/Duplicity.java b/Mage.Sets/src/mage/cards/d/Duplicity.java new file mode 100644 index 0000000000..24b5f48d78 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/Duplicity.java @@ -0,0 +1,244 @@ +package mage.cards.d; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.StaticAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.BeginningOfYourEndStepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.EntersBattlefieldEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class Duplicity extends CardImpl { + + public Duplicity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + // When Duplicity enters the battlefield, exile the top five cards of your library face down. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DuplicityEffect(), false)); + + // At the beginning of your upkeep, you may exile all cards from your hand face down. If you do, put all other cards you own exiled with Duplicity into your hand. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DuplicityExileHandEffect(), TargetController.YOU, true)); + + // At the beginning of your end step, discard a card. + this.addAbility(new BeginningOfYourEndStepTriggeredAbility(new DiscardControllerEffect(1), false)); + + // When you lose control of Duplicity, put all cards exiled with Duplicity into their owner's graveyard. + this.addAbility(new DuplicityEntersBattlefieldAbility(new CreateDelayedTriggeredAbilityEffect(new LoseControlDuplicity()))); + + } + + public Duplicity(final Duplicity card) { + super(card); + } + + @Override + public Duplicity copy() { + return new Duplicity(this); + } +} + +class DuplicityEffect extends OneShotEffect { + + public DuplicityEffect() { + super(Outcome.Exile); + staticText = "exile the top five cards of your library face down"; + } + + public DuplicityEffect(final DuplicityEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null + && sourceObject != null) { + if (controller.getLibrary().hasCards()) { + UUID exileId = source.getSourceId(); + Set cardsToExile = controller.getLibrary().getTopCards(game, 5); + for (Card card : cardsToExile) { + controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName()); + card.setFaceDown(true, game); + } + } + return true; + } + return false; + } + + @Override + public DuplicityEffect copy() { + return new DuplicityEffect(this); + } +} + +class DuplicityExileHandEffect extends OneShotEffect { + + public DuplicityExileHandEffect() { + super(Outcome.Exile); + staticText = "you may exile all cards from your hand face down. If you do, put all other cards you own exiled with {this} into your hand"; + } + + public DuplicityExileHandEffect(final DuplicityExileHandEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (controller != null + && sourceObject != null) { + if (!controller.getHand().isEmpty()) { + UUID exileId = source.getSourceId(); + Set cardsFromHandToExile = controller.getHand().getCards(game); + for (Card card : cardsFromHandToExile) { + controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getName()); + card.setFaceDown(true, game); + } + Set cardsInExile = game.getExile().getExileZone(exileId).getCards(game); + Set cardsToReturnToHandFromExile = new HashSet<>(); + for (Card card : cardsInExile) { + if (!cardsFromHandToExile.contains(card)) { + cardsToReturnToHandFromExile.add(card); + } + } + controller.moveCards(cardsToReturnToHandFromExile, Zone.HAND, source, game); + } + return true; + } + return false; + } + + @Override + public DuplicityExileHandEffect copy() { + return new DuplicityExileHandEffect(this); + } +} + +class LoseControlDuplicity extends DelayedTriggeredAbility { + + public LoseControlDuplicity() { + super(new PutExiledCardsInOwnersGraveyard(), Duration.EndOfGame, false); + } + + public LoseControlDuplicity(final LoseControlDuplicity ability) { + super(ability); + } + + @Override + public LoseControlDuplicity copy() { + return new LoseControlDuplicity(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_CONTROL + || event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.LOST_CONTROL + && event.getPlayerId().equals(controllerId) + && event.getSourceId().equals(getSourceId())) { + return true; + } + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && event.getTargetId().equals(getSourceId()) + && ((ZoneChangeEvent) event).getToZone() != Zone.BATTLEFIELD) { + return true; + } + return false; + } + + @Override + public String getRule() { + return "When you lose control of {this}, put all cards exiled with {this} into their owner's graveyard."; + } +} + +class PutExiledCardsInOwnersGraveyard extends OneShotEffect { + + public PutExiledCardsInOwnersGraveyard() { + super(Outcome.Neutral); + staticText = " put all cards exiled with {this} into their owner's graveyard."; + } + + public PutExiledCardsInOwnersGraveyard(final PutExiledCardsInOwnersGraveyard effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + UUID exileId = source.getSourceId(); + Set cardsInExile = game.getExile().getExileZone(exileId).getCards(game); + if (cardsInExile != null) { + controller.moveCards(cardsInExile, Zone.GRAVEYARD, source, game); + return true; + } + } + return false; + } + + @Override + public PutExiledCardsInOwnersGraveyard copy() { + return new PutExiledCardsInOwnersGraveyard(this); + } +} + +class DuplicityEntersBattlefieldAbility extends StaticAbility { + + public DuplicityEntersBattlefieldAbility(Effect effect) { + super(Zone.ALL, new EntersBattlefieldEffect(effect, null, null, true, false)); + } + + public DuplicityEntersBattlefieldAbility(final DuplicityEntersBattlefieldAbility ability) { + super(ability); + } + + @Override + public void addEffect(Effect effect) { + if (!getEffects().isEmpty()) { + Effect entersBattlefieldEffect = this.getEffects().get(0); + if (entersBattlefieldEffect instanceof EntersBattlefieldEffect) { + ((EntersBattlefieldEffect) entersBattlefieldEffect).addEffect(effect); + return; + } + } + super.addEffect(effect); + } + + @Override + public DuplicityEntersBattlefieldAbility copy() { + return new DuplicityEntersBattlefieldAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DuskCharger.java b/Mage.Sets/src/mage/cards/d/DuskCharger.java index 8f807004e2..7ff23518a1 100644 --- a/Mage.Sets/src/mage/cards/d/DuskCharger.java +++ b/Mage.Sets/src/mage/cards/d/DuskCharger.java @@ -1,7 +1,5 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +7,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,8 +16,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class DuskCharger extends CardImpl { @@ -37,7 +37,7 @@ public final class DuskCharger extends CardImpl { ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, "{this} gets +2/+2 as long as you have the city's blessing"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/d/DuskDawn.java b/Mage.Sets/src/mage/cards/d/DuskDawn.java index 0a5469bcd4..567d818d68 100644 --- a/Mage.Sets/src/mage/cards/d/DuskDawn.java +++ b/Mage.Sets/src/mage/cards/d/DuskDawn.java @@ -43,7 +43,7 @@ public final class DuskDawn extends SplitCard { // Dawn // Return all creature cards with power less than or equal to 2 from your graveyard to your hand. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new DawnEffect()); } diff --git a/Mage.Sets/src/mage/cards/d/DuskLegionZealot.java b/Mage.Sets/src/mage/cards/d/DuskLegionZealot.java index ff374e32e4..a80dddca0d 100644 --- a/Mage.Sets/src/mage/cards/d/DuskLegionZealot.java +++ b/Mage.Sets/src/mage/cards/d/DuskLegionZealot.java @@ -1,24 +1,24 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author JayDi85 */ -public final class DuskLegionZealot extends CardImpl { +public final class DuskLegionZealot extends CardImpl { - public DuskLegionZealot (UUID ownerId, CardSetInfo setInfo) { + public DuskLegionZealot(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.VAMPIRE); @@ -27,21 +27,19 @@ public final class DuskLegionZealot extends CardImpl { this.toughness = new MageInt(1); // When Dusk Legion Zealot enters the battlefield, you draw a card and you lose 1 life. - Effect drawEffect = new DrawCardSourceControllerEffect(1); - drawEffect.setText("you draw a card"); + Effect drawEffect = new DrawCardSourceControllerEffect(1, "you"); Ability ability = new EntersBattlefieldTriggeredAbility(drawEffect); Effect lifeEffect = new LoseLifeSourceControllerEffect(1); - lifeEffect.setText("and you lose 1 life"); - ability.addEffect(lifeEffect); + ability.addEffect(lifeEffect.concatBy("and")); this.addAbility(ability); } - public DuskLegionZealot (final DuskLegionZealot card) { + public DuskLegionZealot(final DuskLegionZealot card) { super(card); } @Override - public DuskLegionZealot copy() { - return new DuskLegionZealot (this); + public DuskLegionZealot copy() { + return new DuskLegionZealot(this); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java b/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java index 17462b8f9d..77a3726456 100644 --- a/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java +++ b/Mage.Sets/src/mage/cards/d/DuskborneSkymarcher.java @@ -28,7 +28,7 @@ public final class DuskborneSkymarcher extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VAMPIRE, "attacking Vampire"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public DuskborneSkymarcher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DuskmantleOperative.java b/Mage.Sets/src/mage/cards/d/DuskmantleOperative.java new file mode 100644 index 0000000000..4f3d69b3d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/d/DuskmantleOperative.java @@ -0,0 +1,51 @@ +package mage.cards.d; + +import mage.MageInt; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class DuskmantleOperative extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public DuskmantleOperative(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Duskmantle Operative can't be blocked by creatures with power 4 or greater. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect( + filter, Duration.WhileOnBattlefield + ))); + } + + private DuskmantleOperative(final DuskmantleOperative card) { + super(card); + } + + @Override + public DuskmantleOperative copy() { + return new DuskmantleOperative(this); + } +} diff --git a/Mage.Sets/src/mage/cards/d/DustOfMoments.java b/Mage.Sets/src/mage/cards/d/DustOfMoments.java index de75c254c0..c461e965ef 100644 --- a/Mage.Sets/src/mage/cards/d/DustOfMoments.java +++ b/Mage.Sets/src/mage/cards/d/DustOfMoments.java @@ -40,7 +40,7 @@ public final class DustOfMoments extends CardImpl { // Or put two time counters on each permanent with a time counter on it and each suspended card Mode mode = new Mode(); - mode.getEffects().add(new AddCountersEffect()); + mode.addEffect(new AddCountersEffect()); this.getSpellAbility().addMode(mode); } @@ -119,10 +119,10 @@ public final class DustOfMoments extends CardImpl { card.addCounters(counter, source, game); } if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ") - .append(controller.getLogName()).append(getActionStr()).append('s') - .append(counter.getCount()).append(' ').append(counterName.toLowerCase(Locale.ENGLISH)) - .append(" counter on ").append(card.getName()).toString()); + game.informPlayers(sourceObject.getName() + ": " + + controller.getLogName() + getActionStr() + 's' + + counter.getCount() + ' ' + counterName.toLowerCase(Locale.ENGLISH) + + " counter on " + card.getName()); } } } @@ -144,10 +144,10 @@ public final class DustOfMoments extends CardImpl { card.addCounters(counter, source, game); } if (!game.isSimulation()) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": ") - .append(controller.getLogName()).append(getActionStr()).append("s ") - .append(counter.getCount()).append(' ').append(counterName.toLowerCase(Locale.ENGLISH)) - .append(" counter on ").append(card.getName()).toString()); + game.informPlayers(sourceObject.getName() + ": " + + controller.getLogName() + getActionStr() + "s " + + counter.getCount() + ' ' + counterName.toLowerCase(Locale.ENGLISH) + + " counter on " + card.getName()); } } } diff --git a/Mage.Sets/src/mage/cards/d/DustStalker.java b/Mage.Sets/src/mage/cards/d/DustStalker.java index c1d604b588..8f2c44d4dd 100644 --- a/Mage.Sets/src/mage/cards/d/DustStalker.java +++ b/Mage.Sets/src/mage/cards/d/DustStalker.java @@ -25,11 +25,11 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class DustStalker extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("if you control no other colorless creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("if you control no other colorless creatures"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public DustStalker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenBloodboiler.java b/Mage.Sets/src/mage/cards/d/DwarvenBloodboiler.java index 8d143825c2..1638cf682b 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenBloodboiler.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenBloodboiler.java @@ -29,7 +29,7 @@ public final class DwarvenBloodboiler extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("an untapped Dwarf you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.DWARF)); } diff --git a/Mage.Sets/src/mage/cards/d/DwarvenHold.java b/Mage.Sets/src/mage/cards/d/DwarvenHold.java index bfc1a8c95c..5c8e97d9e2 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenHold.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenHold.java @@ -44,7 +44,7 @@ public final class DwarvenHold extends CardImpl { // {tap}, Remove any number of storage counters from Dwarven Hold: Add {R} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.RedMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {R} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java b/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java index 1b7f92f62a..056980f895 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenLandslide.java @@ -1,9 +1,7 @@ - package mage.cards.d; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.Cost; import mage.abilities.costs.Costs; @@ -19,6 +17,7 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -27,34 +26,38 @@ import mage.target.common.TargetLandPermanent; public final class DwarvenLandslide extends CardImpl { public DwarvenLandslide(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Kicker-{2}{R}, Sacrifice a land. Costs kickerCosts = new CostsImpl<>(); kickerCosts.add(new ManaCostsImpl<>("{2}{R}")); kickerCosts.add(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land")))); this.addAbility(new KickerAbility(kickerCosts)); + // Destroy target land. If Dwarven Landslide was kicked, destroy another target land. getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target land. if this spell was kicked, destroy another target land")); getSpellAbility().addTarget(new TargetLandPermanent()); + getSpellAbility().setTargetAdjuster(DwarvenLandslideAdjuster.instance); } public DwarvenLandslide(final DwarvenLandslide card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - if (KickedCondition.instance.apply(game, ability)) { - ability.getTargets().clear(); - getSpellAbility().addTarget(new TargetLandPermanent(2)); - } - } - } - @Override public DwarvenLandslide copy() { return new DwarvenLandslide(this); } } + +enum DwarvenLandslideAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.getTargets().clear(); + ability.addTarget(new TargetLandPermanent(2)); + } + } +} diff --git a/Mage.Sets/src/mage/cards/d/DwarvenPriest.java b/Mage.Sets/src/mage/cards/d/DwarvenPriest.java index 3078944ff1..edf1d6dece 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenPriest.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenPriest.java @@ -1,19 +1,17 @@ - package mage.cards.d; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.GainLifeEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class DwarvenPriest extends CardImpl { @@ -27,9 +25,7 @@ public final class DwarvenPriest extends CardImpl { this.toughness = new MageInt(4); // When Dwarven Priest enters the battlefield, you gain 1 life for each creature you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect( - new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE) - ))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(CreaturesYouControlCount.instance))); } public DwarvenPriest(final DwarvenPriest card) { diff --git a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java index 0c37d8c951..8aa1f05f06 100644 --- a/Mage.Sets/src/mage/cards/d/DwarvenShrine.java +++ b/Mage.Sets/src/mage/cards/d/DwarvenShrine.java @@ -67,7 +67,7 @@ class DwarvenShrineTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); MageObject mageObject = game.getObject(sourceId); - if (spell != null) { + if (spell != null && mageObject != null) { game.getState().setValue("dwarvenShrine" + mageObject, spell); return true; } @@ -90,21 +90,23 @@ class DwarvenShrineEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int count = 0; MageObject mageObject = game.getObject(source.getSourceId()); - Spell spell = (Spell) game.getState().getValue("dwarvenShrine" + mageObject); - if (spell != null) { - Player controller = game.getPlayer(spell.getControllerId()); - if (controller != null) { - String name = spell.getName(); - FilterCard filterCardName = new FilterCard(); - filterCardName.add(new NamePredicate(name)); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - count += player.getGraveyard().count(filterCardName, game); + if(mageObject != null) { + Spell spell = (Spell) game.getState().getValue("dwarvenShrine" + mageObject); + if (spell != null) { + Player controller = game.getPlayer(spell.getControllerId()); + if (controller != null) { + String name = spell.getName(); + FilterCard filterCardName = new FilterCard(); + filterCardName.add(new NamePredicate(name)); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + count += player.getGraveyard().count(filterCardName, game); + } } + controller.damage(count * 2, mageObject.getId(), game, false, true); + return true; } - controller.damage(count * 2, mageObject.getId(), game, false, true); - return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java b/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java index 73a10a2f16..fb4ee16fc5 100644 --- a/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java +++ b/Mage.Sets/src/mage/cards/d/DwynenGiltLeafDaen.java @@ -24,7 +24,7 @@ public final class DwynenGiltLeafDaen extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.ELF, "attacking Elf you control"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public DwynenGiltLeafDaen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/d/DwynensElite.java b/Mage.Sets/src/mage/cards/d/DwynensElite.java index 394a7071b5..4e9e11890b 100644 --- a/Mage.Sets/src/mage/cards/d/DwynensElite.java +++ b/Mage.Sets/src/mage/cards/d/DwynensElite.java @@ -27,7 +27,7 @@ public final class DwynensElite extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Elf"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/e/EarlOfSquirrel.java b/Mage.Sets/src/mage/cards/e/EarlOfSquirrel.java index 20259b9d8b..d213ba19de 100644 --- a/Mage.Sets/src/mage/cards/e/EarlOfSquirrel.java +++ b/Mage.Sets/src/mage/cards/e/EarlOfSquirrel.java @@ -28,12 +28,12 @@ import mage.util.SubTypeList; */ public final class EarlOfSquirrel extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens you control"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("Other squirrels you control"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); filter2.add(new SubtypePredicate(SubType.SQUIRREL)); } diff --git a/Mage.Sets/src/mage/cards/e/EarthSurge.java b/Mage.Sets/src/mage/cards/e/EarthSurge.java index 4f82004c4c..6992e2695a 100644 --- a/Mage.Sets/src/mage/cards/e/EarthSurge.java +++ b/Mage.Sets/src/mage/cards/e/EarthSurge.java @@ -4,7 +4,7 @@ package mage.cards.e; import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -29,7 +29,7 @@ public final class EarthSurge extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); //Each land gets +2/+2 as long as it's a creature. - Effect effect = new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter, true); + Effect effect = new BoostAllEffect(2, 2, Duration.WhileOnBattlefield, filter, true); effect.setText("Each land gets +2/+2 as long as it\'s a creature"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } diff --git a/Mage.Sets/src/mage/cards/e/Earthcraft.java b/Mage.Sets/src/mage/cards/e/Earthcraft.java index c89ff398bc..9db0d2926b 100644 --- a/Mage.Sets/src/mage/cards/e/Earthcraft.java +++ b/Mage.Sets/src/mage/cards/e/Earthcraft.java @@ -29,7 +29,7 @@ public final class Earthcraft extends CardImpl { private static final FilterControlledPermanent filterLand = new FilterControlledPermanent("basic land"); static { - filterCreature.add(Predicates.not(new TappedPredicate())); + filterCreature.add(Predicates.not(TappedPredicate.instance)); filterLand.add(new CardTypePredicate(CardType.LAND)); filterLand.add(new SupertypePredicate(SuperType.BASIC)); } diff --git a/Mage.Sets/src/mage/cards/e/Earthlore.java b/Mage.Sets/src/mage/cards/e/Earthlore.java index 78808360e1..2a511fba60 100644 --- a/Mage.Sets/src/mage/cards/e/Earthlore.java +++ b/Mage.Sets/src/mage/cards/e/Earthlore.java @@ -43,7 +43,7 @@ public final class Earthlore extends CardImpl { private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } public Earthlore(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/Earthquake.java b/Mage.Sets/src/mage/cards/e/Earthquake.java index d653f3182d..da844b150d 100644 --- a/Mage.Sets/src/mage/cards/e/Earthquake.java +++ b/Mage.Sets/src/mage/cards/e/Earthquake.java @@ -29,7 +29,7 @@ public final class Earthquake extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}"); // Hurricane deals X damage to each creature with flying and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageEverythingEffect(ManacostVariableValue.instance, filter)); } public Earthquake(final Earthquake card) { diff --git a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java index 0d399a8ab4..d00de4b0c0 100644 --- a/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java +++ b/Mage.Sets/src/mage/cards/e/EarthshakerKhenra.java @@ -1,38 +1,38 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.abilities.keyword.EternalizeAbility; import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; import mage.constants.Duration; -import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class EarthshakerKhenra extends CardImpl { - private final UUID originalId; - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power less than or equal to {this}'s power"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power less than or equal to this creature's power"); + + static { + filter.add(EarthshakerKhenraPredicate.instance); + } public EarthshakerKhenra(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -46,32 +46,20 @@ public final class EarthshakerKhenra extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Earthshaker Khenra enters the battlefield, target creature with power less than or equal to Earthshaker Khenra's power can't block this turn. - Ability ability = new EntersBattlefieldTriggeredAbility(new EarthshakerKhenraEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility( + new CantBlockTargetEffect(Duration.EndOfTurn) + .setText("target creature with power less than or equal " + + "to {this}'s power can't block this turn") + ); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); - originalId = ability.getOriginalId(); // Eternalize {4}{R}{R} this.addAbility(new EternalizeAbility(new ManaCostsImpl("{4}{R}{R}"), this)); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); - if (sourcePermanent != null) { - FilterCreaturePermanent targetFilter = new FilterCreaturePermanent("creature with power less than or equal to " + getLogName() + "'s power"); - targetFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, sourcePermanent.getPower().getValue() + 1)); - ability.getTargets().clear(); - ability.getTargets().add(new TargetCreaturePermanent(targetFilter)); - } - } } public EarthshakerKhenra(final EarthshakerKhenra card) { super(card); - this.originalId = card.originalId; } @Override @@ -80,39 +68,12 @@ public final class EarthshakerKhenra extends CardImpl { } } -class EarthshakerKhenraEffect extends OneShotEffect { - - public EarthshakerKhenraEffect() { - super(Outcome.UnboostCreature); - this.staticText = "target creature with power less than or equal to {this}'s power can't block this turn"; - } - - public EarthshakerKhenraEffect(final EarthshakerKhenraEffect effect) { - super(effect); - } +enum EarthshakerKhenraPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override - public EarthshakerKhenraEffect copy() { - return new EarthshakerKhenraEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourceObject != null) { - Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - /* - 27.06.2017 The target creature's power is checked when you target it with Earthshaker Khenra's ability - and when that ability resolves. Once the ability resolves, if the creature's power increases - or Earthshaker Khenra's power decreases, the target creature will still be unable to block. - */ - if (targetCreature != null && targetCreature.getPower().getValue() <= sourceObject.getPower().getValue()) { - ContinuousEffect effect = new CantBlockTargetEffect(Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(targetCreature, game)); - game.addEffect(effect, source); - } - return true; - } - return false; + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(input.getSourceId()); + return sourcePermanent != null && input.getObject().getPower().getValue() <= sourcePermanent.getPower().getValue(); } } diff --git a/Mage.Sets/src/mage/cards/e/EarwigSquad.java b/Mage.Sets/src/mage/cards/e/EarwigSquad.java index 41c6b6c225..006d6bf757 100644 --- a/Mage.Sets/src/mage/cards/e/EarwigSquad.java +++ b/Mage.Sets/src/mage/cards/e/EarwigSquad.java @@ -79,7 +79,7 @@ class EarwigSquadEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && opponent != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCard("cards from opponents library to exile")); - if (player.searchLibrary(target, game, opponent.getId())) { + if (player.searchLibrary(target, source, game, opponent.getId())) { List targets = target.getTargets(); for (UUID targetId : targets) { Card card = opponent.getLibrary().remove(targetId, game); diff --git a/Mage.Sets/src/mage/cards/e/EaterOfHope.java b/Mage.Sets/src/mage/cards/e/EaterOfHope.java index 7cd660c058..0524a4b541 100644 --- a/Mage.Sets/src/mage/cards/e/EaterOfHope.java +++ b/Mage.Sets/src/mage/cards/e/EaterOfHope.java @@ -30,7 +30,7 @@ public final class EaterOfHope extends CardImpl { private static final FilterControlledCreaturePermanent destroyFilter = new FilterControlledCreaturePermanent("two other creatures"); static { - destroyFilter.add(new AnotherPredicate()); + destroyFilter.add(AnotherPredicate.instance); } public EaterOfHope(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EbonPraetor.java b/Mage.Sets/src/mage/cards/e/EbonPraetor.java index c5a251d7c1..33e1c7eb58 100644 --- a/Mage.Sets/src/mage/cards/e/EbonPraetor.java +++ b/Mage.Sets/src/mage/cards/e/EbonPraetor.java @@ -47,7 +47,7 @@ public final class EbonPraetor extends CardImpl { // Sacrifice a creature: Remove a -2/-2 counter from Ebon Praetor. If the sacrificed creature was a Thrull, put a +1/+0 counter on Ebon Praetor. Activate this ability only during your upkeep and only once each turn. Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new RemoveCounterSourceEffect(CounterType.M2M2.createInstance()), - new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)), 1, new IsStepCondition(PhaseStep.UPKEEP, true)); + new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)), 1, new IsStepCondition(PhaseStep.UPKEEP)); ability.addEffect(new EbonPraetorEffect()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EbonyCharm.java b/Mage.Sets/src/mage/cards/e/EbonyCharm.java index 3c29cf2f24..f3ed1de7c0 100644 --- a/Mage.Sets/src/mage/cards/e/EbonyCharm.java +++ b/Mage.Sets/src/mage/cards/e/EbonyCharm.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.UUID; @@ -27,22 +26,22 @@ import mage.target.common.TargetOpponent; public final class EbonyCharm extends CardImpl { public EbonyCharm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Choose one - Target opponent loses 1 life and you gain 1 life; this.getSpellAbility().addEffect(new EbonyCharmDrainEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); - + // or exile up to three target cards from a single graveyard; Mode mode = new Mode(); - mode.getEffects().add(new EbonyCharmExileEffect()); - mode.getTargets().add((new TargetCardInASingleGraveyard(0, 3, new FilterCard("up to three target cards from a single graveyard")))); + mode.addEffect(new EbonyCharmExileEffect()); + mode.addTarget((new TargetCardInASingleGraveyard(0, 3, new FilterCard("up to three target cards from a single graveyard")))); this.getSpellAbility().addMode(mode); - + // or target creature gains fear until end of turn. mode = new Mode(); - mode.getTargets().add(new TargetCreaturePermanent()); - mode.getEffects().add(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } @@ -69,11 +68,13 @@ class EbonyCharmDrainEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player controllerPlayer = game.getPlayer(source.getControllerId()); - if (targetPlayer != null && controllerPlayer != null) { - targetPlayer.damage(1, source.getSourceId(), game, false, true); - controllerPlayer.gainLife(1, game, source); + Player targetOpponent = game.getPlayer(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (targetOpponent != null + && controller != null) { + targetOpponent.loseLife(1, game, false); + controller.gainLife(1, game, source); + return true; } return false; } @@ -88,17 +89,17 @@ class EbonyCharmDrainEffect extends OneShotEffect { class EbonyCharmExileEffect extends OneShotEffect { public EbonyCharmExileEffect() { - super(Outcome.Exile); - this.staticText = "Exile up to three target cards from a single graveyard"; + super(Outcome.Exile); + this.staticText = "Exile up to three target cards from a single graveyard"; } public EbonyCharmExileEffect(final EbonyCharmExileEffect effect) { - super(effect); + super(effect); } @Override public EbonyCharmExileEffect copy() { - return new EbonyCharmExileEffect(this); + return new EbonyCharmExileEffect(this); } @Override diff --git a/Mage.Sets/src/mage/cards/e/EbonyHorse.java b/Mage.Sets/src/mage/cards/e/EbonyHorse.java index f5bcac6c36..610dd3291c 100644 --- a/Mage.Sets/src/mage/cards/e/EbonyHorse.java +++ b/Mage.Sets/src/mage/cards/e/EbonyHorse.java @@ -30,7 +30,7 @@ public final class EbonyHorse extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public EbonyHorse(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EchoingCalm.java b/Mage.Sets/src/mage/cards/e/EchoingCalm.java index badff50bda..681ad75a60 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingCalm.java +++ b/Mage.Sets/src/mage/cards/e/EchoingCalm.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -12,6 +10,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetEnchantmentPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author Loki @@ -19,7 +20,7 @@ import mage.target.common.TargetEnchantmentPermanent; public final class EchoingCalm extends CardImpl { public EchoingCalm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); // Destroy target enchantment and all other enchantments with the same name as that enchantment. @@ -58,9 +59,9 @@ class EchoingCalmEffect extends OneShotEffect { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { permanent.destroy(source.getSourceId(), game, false); - if (!permanent.getName().isEmpty()) { // in case of face down enchantment creature + if (!CardUtil.haveEmptyName(permanent)) { // in case of face down enchantment creature for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (!perm.getId().equals(permanent.getId()) && perm.getName().equals(permanent.getName()) && perm.isEnchantment()) { + if (!perm.getId().equals(permanent.getId()) && CardUtil.haveSameNames(perm, permanent) && perm.isEnchantment()) { perm.destroy(source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingCourage.java b/Mage.Sets/src/mage/cards/e/EchoingCourage.java index abacfc3385..b256f031a2 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingCourage.java +++ b/Mage.Sets/src/mage/cards/e/EchoingCourage.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -17,15 +15,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class EchoingCourage extends CardImpl { public EchoingCourage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Target creature and all other creatures with the same name as that creature get +2/+2 until end of turn. @@ -64,12 +64,12 @@ class EchoingCourageEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - ContinuousEffect effect = new BoostAllEffect(2,2, Duration.EndOfTurn, filter, false); + ContinuousEffect effect = new BoostAllEffect(2, 2, Duration.EndOfTurn, filter, false); game.addEffect(effect, source); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EchoingDecay.java b/Mage.Sets/src/mage/cards/e/EchoingDecay.java index 2d4523d0dc..89d14b83f8 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingDecay.java +++ b/Mage.Sets/src/mage/cards/e/EchoingDecay.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; @@ -17,15 +15,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class EchoingDecay extends CardImpl { public EchoingDecay(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Target creature and all other creatures with the same name as that creature get -2/-2 until end of turn. this.getSpellAbility().addEffect(new EchoingDecayEffect()); @@ -63,12 +63,12 @@ class EchoingDecayEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - ContinuousEffect effect = new BoostAllEffect(-2,-2, Duration.EndOfTurn, filter, false); + ContinuousEffect effect = new BoostAllEffect(-2, -2, Duration.EndOfTurn, filter, false); game.addEffect(effect, source); return true; } diff --git a/Mage.Sets/src/mage/cards/e/EchoingRuin.java b/Mage.Sets/src/mage/cards/e/EchoingRuin.java index abc6a98bc0..738dba3ba8 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingRuin.java +++ b/Mage.Sets/src/mage/cards/e/EchoingRuin.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,21 +12,23 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class EchoingRuin extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifact"); + private static final FilterPermanent filter = new FilterPermanent("artifact"); + - static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } public EchoingRuin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // Destroy target artifact and all other artifacts with the same name as that artifact. this.getSpellAbility().addTarget(new TargetPermanent(filter)); @@ -66,9 +66,9 @@ class EchoingRuinEffect extends OneShotEffect { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { permanent.destroy(source.getSourceId(), game, false); - if (!permanent.getName().isEmpty()) { // in case of face down artifact creature + if (!CardUtil.haveEmptyName(permanent)) { // in case of face down artifact creature for (Permanent perm : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { - if (!perm.getId().equals(permanent.getId()) && perm.getName().equals(permanent.getName()) && perm.isArtifact()) { + if (!perm.getId().equals(permanent.getId()) && CardUtil.haveSameNames(perm, permanent) && perm.isArtifact()) { perm.destroy(source.getSourceId(), game, false); } } diff --git a/Mage.Sets/src/mage/cards/e/EchoingTruth.java b/Mage.Sets/src/mage/cards/e/EchoingTruth.java index d48bd10ee2..d7a542dbc4 100644 --- a/Mage.Sets/src/mage/cards/e/EchoingTruth.java +++ b/Mage.Sets/src/mage/cards/e/EchoingTruth.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -20,15 +18,17 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetNonlandPermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class EchoingTruth extends CardImpl { public EchoingTruth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return target nonland permanent and all other permanents with the same name as that permanent to their owners' hands. Target target = new TargetNonlandPermanent(); @@ -67,7 +67,7 @@ class ReturnToHandAllNamedPermanentsEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getFirstTarget()); if (controller != null && permanent != null) { FilterPermanent filter = new FilterPermanent(); - if (permanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(permanent)) { filter.add(new PermanentIdPredicate(permanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(permanent.getName())); diff --git a/Mage.Sets/src/mage/cards/e/EddytrailHawk.java b/Mage.Sets/src/mage/cards/e/EddytrailHawk.java index 2c312f1ba2..6428e555f0 100644 --- a/Mage.Sets/src/mage/cards/e/EddytrailHawk.java +++ b/Mage.Sets/src/mage/cards/e/EddytrailHawk.java @@ -26,10 +26,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class EddytrailHawk extends CardImpl { - private final static FilterAttackingCreature filter = new FilterAttackingCreature(); + private static final FilterAttackingCreature filter = new FilterAttackingCreature(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public EddytrailHawk(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java index 9ee96ef783..d6787d80f7 100644 --- a/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java +++ b/Mage.Sets/src/mage/cards/e/EdificeOfAuthority.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.condition.Condition; @@ -15,19 +13,16 @@ import mage.abilities.effects.common.combat.CantAttackTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.turn.Step; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class EdificeOfAuthority extends CardImpl { @@ -133,24 +128,21 @@ class EdificeOfAuthorityRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (this.targetPointer.getTargets(game, source).contains(permanent.getId())) { - return true; - } + return this.targetPointer.getTargets(game, source).contains(permanent.getId()); + } + + @Override + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - return false; - } - - @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/e/EdricSpymasterOfTrest.java b/Mage.Sets/src/mage/cards/e/EdricSpymasterOfTrest.java index e43a5f513c..57e194e74f 100644 --- a/Mage.Sets/src/mage/cards/e/EdricSpymasterOfTrest.java +++ b/Mage.Sets/src/mage/cards/e/EdricSpymasterOfTrest.java @@ -69,7 +69,7 @@ class EdricSpymasterOfTrestTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (((DamagedPlayerEvent) event).isCombatDamage() && - game.getOpponents(this.controllerId).contains(((DamagedPlayerEvent) event).getPlayerId())) { + game.getOpponents(this.controllerId).contains(event.getPlayerId())) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(game.getPermanent(event.getSourceId()).getControllerId())); } diff --git a/Mage.Sets/src/mage/cards/e/EelUmbra.java b/Mage.Sets/src/mage/cards/e/EelUmbra.java index d0d69cce3d..7438c42029 100644 --- a/Mage.Sets/src/mage/cards/e/EelUmbra.java +++ b/Mage.Sets/src/mage/cards/e/EelUmbra.java @@ -2,6 +2,7 @@ package mage.cards.e; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -20,25 +21,28 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author Loki */ public final class EelUmbra extends CardImpl { public EelUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); 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)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature gets +1/+1. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1, Duration.WhileOnBattlefield))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java index a0d9d1f5ba..0f71859dae 100644 --- a/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java +++ b/Mage.Sets/src/mage/cards/e/EfreetWeaponmaster.java @@ -61,7 +61,7 @@ class EfreetWeaponmasterAbility extends TriggeredAbilityImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public EfreetWeaponmasterAbility() { diff --git a/Mage.Sets/src/mage/cards/e/EgoErasure.java b/Mage.Sets/src/mage/cards/e/EgoErasure.java index 71374e44f7..3f7d2fba9a 100644 --- a/Mage.Sets/src/mage/cards/e/EgoErasure.java +++ b/Mage.Sets/src/mage/cards/e/EgoErasure.java @@ -1,9 +1,5 @@ - package mage.cards.e; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; @@ -16,8 +12,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + /** - * * @author Styxo */ public final class EgoErasure extends CardImpl { @@ -74,10 +73,10 @@ class EgoErasureLoseEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { Permanent permanent = it.next().getPermanent(game); if (permanent != null) { - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); } else { it.remove(); } @@ -115,7 +114,7 @@ class EgoErasureBoostEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - for (Iterator it = affectedObjectList.iterator(); it.hasNext();) { + for (Iterator it = affectedObjectList.iterator(); it.hasNext(); ) { Permanent permanent = it.next().getPermanent(game); if (permanent != null) { permanent.addPower(-2); diff --git a/Mage.Sets/src/mage/cards/e/ElandUmbra.java b/Mage.Sets/src/mage/cards/e/ElandUmbra.java index 86a2c8be49..1cbee9cbfa 100644 --- a/Mage.Sets/src/mage/cards/e/ElandUmbra.java +++ b/Mage.Sets/src/mage/cards/e/ElandUmbra.java @@ -2,6 +2,7 @@ package mage.cards.e; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -19,24 +20,25 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author Loki */ public final class ElandUmbra extends CardImpl { public ElandUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature gets +0/+4. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(0, 4, Duration.WhileOnBattlefield))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java index d949dd182a..7c88a09f72 100644 --- a/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java +++ b/Mage.Sets/src/mage/cards/e/ElbrusTheBindingBlade.java @@ -71,7 +71,7 @@ class ElbrusTheBindingBladeEffect extends OneShotEffect { if (attachedTo != null) { attachedTo.removeAttachment(equipment.getId(), game); equipment.transform(game); - game.informPlayers(new StringBuilder(equipment.getName()).append(" transforms into ").append(equipment.getSecondCardFace().getName()).toString()); + game.informPlayers(equipment.getName() + " transforms into " + equipment.getSecondCardFace().getName()); } } diff --git a/Mage.Sets/src/mage/cards/e/ElderOfLaurels.java b/Mage.Sets/src/mage/cards/e/ElderOfLaurels.java index 06414d035e..79873645d2 100644 --- a/Mage.Sets/src/mage/cards/e/ElderOfLaurels.java +++ b/Mage.Sets/src/mage/cards/e/ElderOfLaurels.java @@ -1,29 +1,28 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class ElderOfLaurels extends CardImpl { public ElderOfLaurels(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ADVISOR); @@ -31,11 +30,11 @@ public final class ElderOfLaurels extends CardImpl { this.toughness = new MageInt(3); // {3}{G}: Target creature gets +X/+X until end of turn, where X is the number of creatures you control. - PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(amount, amount, Duration.EndOfTurn, true), + new BoostTargetEffect(CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, true), new ManaCostsImpl("{3}{G}")); ability.addTarget(new TargetCreaturePermanent()); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/ElderSpawn.java b/Mage.Sets/src/mage/cards/e/ElderSpawn.java new file mode 100644 index 0000000000..1d65526cdc --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElderSpawn.java @@ -0,0 +1,102 @@ + +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public final class ElderSpawn extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("red creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + } + + public ElderSpawn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}{U}"); + this.subtype.add(SubType.SPAWN); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // At the beginning of your upkeep, unless you sacrifice an Island, sacrifice Elder Spawn and it deals 6 damage to you. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new ElderSpawnEffect(), TargetController.YOU, false)); + + // Elder Spawn can't be blocked by red creatures. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); + } + + public ElderSpawn(final ElderSpawn card) { + super(card); + } + + @Override + public ElderSpawn copy() { + return new ElderSpawn(this); + } +} + +class ElderSpawnEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an Island"); + static { + filter.add(new SubtypePredicate(SubType.ISLAND)); + } + + public ElderSpawnEffect() { + super(Outcome.Sacrifice); + staticText = "unless you sacrifice an Island, sacrifice {this} and it deals 6 damage to you"; + } + + public ElderSpawnEffect(final ElderSpawnEffect effect) { + super(effect); + } + + @Override + public ElderSpawnEffect copy() { + return new ElderSpawnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + SacrificeTargetCost cost = new SacrificeTargetCost(target); + if (!controller.chooseUse(Outcome.AIDontUseIt, "Do you wish to sacrifice an Island?", source, game) + || !cost.canPay(source, source.getSourceId(), source.getControllerId(), game) + || !cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + sourcePermanent.sacrifice(source.getSourceId(), game); + controller.damage(6, sourcePermanent.getId(), game, false, true); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EldraziAggressor.java b/Mage.Sets/src/mage/cards/e/EldraziAggressor.java index 142cfa2b25..6538c6ac1d 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziAggressor.java +++ b/Mage.Sets/src/mage/cards/e/EldraziAggressor.java @@ -29,8 +29,8 @@ public final class EldraziAggressor extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public EldraziAggressor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java index c5dc494d1f..8618e6afb6 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java +++ b/Mage.Sets/src/mage/cards/e/EldraziDisplacer.java @@ -28,7 +28,7 @@ public final class EldraziDisplacer extends CardImpl { private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("another target creature"); static { - FILTER.add(new AnotherPredicate()); + FILTER.add(AnotherPredicate.instance); } public EldraziDisplacer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EldraziMimic.java b/Mage.Sets/src/mage/cards/e/EldraziMimic.java index d90c7e7838..657a7a8565 100644 --- a/Mage.Sets/src/mage/cards/e/EldraziMimic.java +++ b/Mage.Sets/src/mage/cards/e/EldraziMimic.java @@ -28,8 +28,8 @@ public final class EldraziMimic extends CardImpl { private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("another colorless creature"); static { - FILTER.add(new AnotherPredicate()); - FILTER.add(new ColorlessPredicate()); + FILTER.add(AnotherPredicate.instance); + FILTER.add(ColorlessPredicate.instance); } public EldraziMimic(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EldritchEvolution.java b/Mage.Sets/src/mage/cards/e/EldritchEvolution.java index c1eecf9e53..4ea99a5191 100644 --- a/Mage.Sets/src/mage/cards/e/EldritchEvolution.java +++ b/Mage.Sets/src/mage/cards/e/EldritchEvolution.java @@ -83,7 +83,7 @@ class EldritchEvolutionEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, newConvertedCost+1)); filter.add(new CardTypePredicate(CardType.CREATURE)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); controller.moveCards(card, Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/e/Electrodominance.java b/Mage.Sets/src/mage/cards/e/Electrodominance.java new file mode 100644 index 0000000000..4b9342fcaa --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/Electrodominance.java @@ -0,0 +1,35 @@ +package mage.cards.e; + +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.cost.CastWithoutPayingManaCostEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Electrodominance extends CardImpl { + + public Electrodominance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}{R}"); + + // Electrodominance deals X damage to any target. You may cast a card with converted mana cost X or less from your hand without paying its mana cost. + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().addEffect(new CastWithoutPayingManaCostEffect(ManacostVariableValue.instance)); + } + + private Electrodominance(final Electrodominance card) { + super(card); + } + + @Override + public Electrodominance copy() { + return new Electrodominance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElectrostaticBolt.java b/Mage.Sets/src/mage/cards/e/ElectrostaticBolt.java index af8469673f..b0f405a1cd 100644 --- a/Mage.Sets/src/mage/cards/e/ElectrostaticBolt.java +++ b/Mage.Sets/src/mage/cards/e/ElectrostaticBolt.java @@ -43,7 +43,7 @@ public final class ElectrostaticBolt extends CardImpl { class ElectrostaticBoltDamageValue implements DynamicValue { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java b/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java index 9b6b3c855a..34910dc22e 100644 --- a/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java +++ b/Mage.Sets/src/mage/cards/e/EliminateTheCompetition.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.UUID; @@ -9,11 +8,11 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -22,7 +21,7 @@ import mage.target.common.TargetCreaturePermanent; public final class EliminateTheCompetition extends CardImpl { public EliminateTheCompetition(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); // As an additional cost to cast Eliminate the Competition, sacrifice X creatures. this.getSpellAbility().addCost(new SacrificeXTargetCost(new FilterControlledCreaturePermanent("creatures"), true)); @@ -32,23 +31,26 @@ public final class EliminateTheCompetition extends CardImpl { effect.setText("Destroy X target creatures"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(EliminateTheCompetitionAdjuster.instance); } public EliminateTheCompetition(final EliminateTheCompetition card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { - ability.getTargets().clear(); - int sac = new GetXValue().calculate(game, ability, null); - ability.addTarget(new TargetCreaturePermanent(sac, sac)); - } - } - @Override public EliminateTheCompetition copy() { return new EliminateTheCompetition(this); } } + +enum EliminateTheCompetitionAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int sac = GetXValue.instance.calculate(game, ability, null); + ability.addTarget(new TargetCreaturePermanent(sac, sac)); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EliteArcanist.java b/Mage.Sets/src/mage/cards/e/EliteArcanist.java index ed9cb29391..9ca13d7fa5 100644 --- a/Mage.Sets/src/mage/cards/e/EliteArcanist.java +++ b/Mage.Sets/src/mage/cards/e/EliteArcanist.java @@ -1,12 +1,12 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -25,8 +25,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class EliteArcanist extends CardImpl { @@ -45,6 +46,7 @@ public final class EliteArcanist extends CardImpl { // {X}, {T}: Copy the exiled card. You may cast the copy without paying its mana cost. X is the converted mana cost of the exiled card. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new EliteArcanistCopyEffect(), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); + ability.setCostAdjuster(EliteArcanistAdjuster.instance); this.addAbility(ability); } @@ -52,29 +54,35 @@ public final class EliteArcanist extends CardImpl { super(card); } - @Override - public void adjustCosts(Ability ability, Game game) { - if (ability instanceof SimpleActivatedAbility) { - Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); - if (sourcePermanent != null && sourcePermanent.getImprinted() != null && !sourcePermanent.getImprinted().isEmpty()) { - Card imprintedInstant = game.getCard(sourcePermanent.getImprinted().get(0)); - if (imprintedInstant != null) { - int cmc = imprintedInstant.getConvertedManaCost(); - if (cmc > 0) { - ability.getManaCostsToPay().clear(); - ability.getManaCostsToPay().add(new GenericManaCost(cmc)); - } - } - } - } - } - @Override public EliteArcanist copy() { return new EliteArcanist(this); } } +enum EliteArcanistAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); + if (sourcePermanent == null + || sourcePermanent.getImprinted() == null + || sourcePermanent.getImprinted().isEmpty()) { + return; + } + Card imprintedInstant = game.getCard(sourcePermanent.getImprinted().get(0)); + if (imprintedInstant == null) { + return; + } + int cmc = imprintedInstant.getConvertedManaCost(); + if (cmc > 0) { + ability.getManaCostsToPay().clear(); + ability.getManaCostsToPay().add(new GenericManaCost(cmc)); + } + } +} + class EliteArcanistImprintEffect extends OneShotEffect { private static final FilterCard filter = new FilterCard("instant card from your hand"); @@ -95,7 +103,7 @@ class EliteArcanistImprintEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (!player.getHand().isEmpty()) { + if (player != null && !player.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); if (target.canChoose(source.getSourceId(), source.getControllerId(), game) && player.choose(Outcome.Benefit, player.getHand(), target, game)) { @@ -105,7 +113,7 @@ class EliteArcanistImprintEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { permanent.imprint(card.getId(), game); - permanent.addInfo("imprint", new StringBuilder("[Exiled card - ").append(card.getName()).append(']').toString(), game); + permanent.addInfo("imprint", "[Exiled card - " + card.getName() + ']', game); } return true; } diff --git a/Mage.Sets/src/mage/cards/e/EliteArrester.java b/Mage.Sets/src/mage/cards/e/EliteArrester.java new file mode 100644 index 0000000000..570589d44e --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EliteArrester.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.TapTargetEffect; +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 EliteArrester extends CardImpl { + + public EliteArrester(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // {1}{U}, {T}: Tap target creature. + Ability ability = new SimpleActivatedAbility( + new TapTargetEffect(), new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private EliteArrester(final EliteArrester card) { + super(card); + } + + @Override + public EliteArrester copy() { + return new EliteArrester(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EliteGuardmage.java b/Mage.Sets/src/mage/cards/e/EliteGuardmage.java new file mode 100644 index 0000000000..3ae453a7e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EliteGuardmage.java @@ -0,0 +1,46 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +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 EliteGuardmage extends CardImpl { + + public EliteGuardmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Elite Guardmage enters the battlefield, you can 3 life and draw a card. + Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private EliteGuardmage(final EliteGuardmage card) { + super(card); + } + + @Override + public EliteGuardmage copy() { + return new EliteGuardmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EliteScaleguard.java b/Mage.Sets/src/mage/cards/e/EliteScaleguard.java index 332e040f55..b2c5911d85 100644 --- a/Mage.Sets/src/mage/cards/e/EliteScaleguard.java +++ b/Mage.Sets/src/mage/cards/e/EliteScaleguard.java @@ -1,12 +1,10 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.keyword.BolsterEffect; import mage.cards.CardImpl; @@ -16,25 +14,29 @@ import mage.constants.SubType; import mage.counters.CounterType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.CounterPredicate; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class EliteScaleguard extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature you control with a +1/+1 counter on it"); + private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature defending player controls"); + static { filter.add(new CounterPredicate(CounterType.P1P1)); + filter2.add(DefendingPlayerControlsPredicate.instance); } public EliteScaleguard(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(2); @@ -42,32 +44,16 @@ public final class EliteScaleguard extends CardImpl { // When Elite Scaleguard enters the battlefield, bolster 2. this.addAbility(new EntersBattlefieldTriggeredAbility(new BolsterEffect(2))); - + // Whenever a creature you control with a +1/+1 counter on it attacks, tap target creature defending player controls. Ability ability = new AttacksCreatureYouControlTriggeredAbility(new EliteScaleguardTapEffect(), false, filter, true); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); + ability.addTarget(new TargetCreaturePermanent(filter2)); this.addAbility(ability); } public EliteScaleguard(final EliteScaleguard card) { super(card); } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof AttacksCreatureYouControlTriggeredAbility) { - FilterCreaturePermanent filterDefender = new FilterCreaturePermanent("creature defending player controls"); - for (Effect effect : ability.getEffects()) { - if (effect instanceof EliteScaleguardTapEffect) { - filterDefender.add(new ControllerIdPredicate(game.getCombat().getDefendingPlayerId(effect.getTargetPointer().getFirst(game, ability), game))); - break; - } - } - ability.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filterDefender); - ability.addTarget(target); - } - } @Override public EliteScaleguard copy() { @@ -76,20 +62,20 @@ public final class EliteScaleguard extends CardImpl { } class EliteScaleguardTapEffect extends TapTargetEffect { - + EliteScaleguardTapEffect() { super(); } - + EliteScaleguardTapEffect(final EliteScaleguardTapEffect effect) { super(effect); } - + @Override public EliteScaleguardTapEffect copy() { return new EliteScaleguardTapEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/e/ElkinLair.java b/Mage.Sets/src/mage/cards/e/ElkinLair.java index 8539e15b47..5822a8bfb2 100644 --- a/Mage.Sets/src/mage/cards/e/ElkinLair.java +++ b/Mage.Sets/src/mage/cards/e/ElkinLair.java @@ -6,14 +6,12 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -57,7 +55,10 @@ class ElkinLairUpkeepEffect extends OneShotEffect { public ElkinLairUpkeepEffect() { super(Outcome.Benefit); - this.staticText = "that player exiles a card at random from their hand. The player may play that card this turn. At the beginning of the next end step, if the player hasn't played the card, he or she puts it into their graveyard"; + this.staticText = "that player exiles a card at random from their hand. " + + "The player may play that card this turn. " + + "At the beginning of the next end step, if the " + + "player hasn't played the card, he or she puts it into their graveyard"; } public ElkinLairUpkeepEffect(final ElkinLairUpkeepEffect effect) { @@ -72,8 +73,9 @@ class ElkinLairUpkeepEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(game.getActivePlayerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (player != null && sourcePermanent != null) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + if (player != null + && sourcePermanent != null) { Card[] cards = player.getHand().getCards(new FilterCard(), game).toArray(new Card[0]); if (cards.length > 0) { Card card = cards[RandomUtil.nextInt(cards.length)]; @@ -84,51 +86,19 @@ class ElkinLairUpkeepEffect extends OneShotEffect { ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(card, game)); game.addEffect(effect, source); - - DelayedTriggeredAbility delayed = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ElkinLairPutIntoGraveyardEffect()); + DelayedTriggeredAbility delayed + = new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new ElkinLairPutIntoGraveyardEffect()); game.addDelayedTriggeredAbility(delayed, source); + return true; } } - return true; } } return false; } } -class ElkinLairPlayExiledEffect extends AsThoughEffectImpl { - - public ElkinLairPlayExiledEffect(Duration duration) { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit); - staticText = "The player may play that card this turn"; - } - - public ElkinLairPlayExiledEffect(final ElkinLairPlayExiledEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public ElkinLairPlayExiledEffect copy() { - return new ElkinLairPlayExiledEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - Card card = game.getCard(objectId); - if (card != null - && affectedControllerId.equals(card.getOwnerId()) - && game.getState().getZone(card.getId()) == Zone.EXILED) { - return true; - } - return false; - } -} - class ElkinLairPutIntoGraveyardEffect extends OneShotEffect { public ElkinLairPutIntoGraveyardEffect() { diff --git a/Mage.Sets/src/mage/cards/e/ElvishBranchbender.java b/Mage.Sets/src/mage/cards/e/ElvishBranchbender.java index 0dee090c34..117f6d6381 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishBranchbender.java +++ b/Mage.Sets/src/mage/cards/e/ElvishBranchbender.java @@ -58,7 +58,7 @@ public final class ElvishBranchbender extends CardImpl { class ElvishBranchbenderEffect extends OneShotEffect { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Elves you control"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Elves you control"); static { filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/e/ElvishHouseParty.java b/Mage.Sets/src/mage/cards/e/ElvishHouseParty.java new file mode 100644 index 0000000000..d01550b932 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ElvishHouseParty.java @@ -0,0 +1,73 @@ + +package mage.cards.e; + +import java.time.LocalTime; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; + +/** + * + * @author Ketsuban + */ +public final class ElvishHouseParty extends CardImpl { + + public ElvishHouseParty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{4}{G}{G}"); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Elvish House Party's power and toughness are each equal to the current hour, + // using the twelve-hour system. + this.addAbility(new SimpleStaticAbility(Zone.ALL, + new SetPowerToughnessSourceEffect(new CurrentHourCount(), Duration.WhileOnBattlefield))); + } + + public ElvishHouseParty(final ElvishHouseParty card) { + super(card); + } + + @Override + public ElvishHouseParty copy() { + return new ElvishHouseParty(this); + } +} + +class CurrentHourCount implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int hour = LocalTime.now().getHour(); + // convert 24-hour value to 12-hour + if (hour > 12) { + hour -= 12; + } + if (hour == 0) { + hour = 12; + } + return hour; + } + + @Override + public DynamicValue copy() { + return new CurrentHourCount(); + } + + @Override + public String getMessage() { + return "current hour, using the twelve-hour system"; + } +} diff --git a/Mage.Sets/src/mage/cards/e/ElvishScout.java b/Mage.Sets/src/mage/cards/e/ElvishScout.java index fb03e93495..01a924b85e 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishScout.java +++ b/Mage.Sets/src/mage/cards/e/ElvishScout.java @@ -30,7 +30,7 @@ public final class ElvishScout extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature you control"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public ElvishScout(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java b/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java index 34ec6693f8..e5bbd37e20 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java +++ b/Mage.Sets/src/mage/cards/e/ElvishSoultiller.java @@ -2,6 +2,7 @@ package mage.cards.e; import java.util.UUID; + import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -22,7 +23,6 @@ import mage.game.Game; import mage.players.Player; /** - * * @author LevelX2 */ public final class ElvishSoultiller extends CardImpl { @@ -69,18 +69,20 @@ class ElvishSoultillerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getObject(source.getSourceId()); - Choice typeChoice = new ChoiceCreatureType(mageObject); - if (controller != null && mageObject != null && controller.choose(outcome, typeChoice, game)) { - if (!game.isSimulation()) { - game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + if (controller != null && mageObject != null) { + Choice typeChoice = new ChoiceCreatureType(mageObject); + if (controller.choose(outcome, typeChoice, game)) { + if (!game.isSimulation()) { + game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); + } + Cards cardsToLibrary = new CardsImpl(); + FilterCreatureCard filter = new FilterCreatureCard(); + filter.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); + controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); + controller.shuffleLibrary(source, game); + return true; } - Cards cardsToLibrary = new CardsImpl(); - FilterCreatureCard filter = new FilterCreatureCard(); - filter.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - cardsToLibrary.addAll(controller.getGraveyard().getCards(filter, source.getSourceId(), source.getControllerId(), game)); - controller.putCardsOnTopOfLibrary(cardsToLibrary, game, source, false); - controller.shuffleLibrary(source, game); - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/e/ElvishVanguard.java b/Mage.Sets/src/mage/cards/e/ElvishVanguard.java index a31344e736..7591f62213 100644 --- a/Mage.Sets/src/mage/cards/e/ElvishVanguard.java +++ b/Mage.Sets/src/mage/cards/e/ElvishVanguard.java @@ -24,7 +24,7 @@ public final class ElvishVanguard extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ELF)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ElvishVanguard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EmbalmersTools.java b/Mage.Sets/src/mage/cards/e/EmbalmersTools.java index c81514acd8..4ca900ff9f 100644 --- a/Mage.Sets/src/mage/cards/e/EmbalmersTools.java +++ b/Mage.Sets/src/mage/cards/e/EmbalmersTools.java @@ -35,7 +35,7 @@ public final class EmbalmersTools extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Zombie you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.ZOMBIE)); } diff --git a/Mage.Sets/src/mage/cards/e/EmberFistZubera.java b/Mage.Sets/src/mage/cards/e/EmberFistZubera.java index 0a79c71c41..acfe8a486c 100644 --- a/Mage.Sets/src/mage/cards/e/EmberFistZubera.java +++ b/Mage.Sets/src/mage/cards/e/EmberFistZubera.java @@ -28,7 +28,7 @@ public final class EmberFistZubera extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(new ZuberasDiedDynamicValue())); + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(ZuberasDiedDynamicValue.instance)); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability, new ZuberasDiedWatcher()); } diff --git a/Mage.Sets/src/mage/cards/e/EmeraldCharm.java b/Mage.Sets/src/mage/cards/e/EmeraldCharm.java index 730c1efc3a..bb67f751f5 100644 --- a/Mage.Sets/src/mage/cards/e/EmeraldCharm.java +++ b/Mage.Sets/src/mage/cards/e/EmeraldCharm.java @@ -40,14 +40,14 @@ public final class EmeraldCharm extends CardImpl { // or destroy target non-Aura enchantment; Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetEnchantmentPermanent(filter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent(filter)); this.getSpellAbility().addMode(mode); // or target creature loses flying until end of turn. mode = new Mode(); - mode.getEffects().add(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new LoseAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EmergenceZone.java b/Mage.Sets/src/mage/cards/e/EmergenceZone.java new file mode 100644 index 0000000000..cc1a71180b --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmergenceZone.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterCard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmergenceZone extends CardImpl { + + private static final FilterCard filter = new FilterCard("spells"); + + public EmergenceZone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {1}, {T}, Sacrifice Emergence Zone: You may cast spells this turn as thought they had flash. + Ability ability = new SimpleActivatedAbility( + new CastAsThoughItHadFlashAllEffect( + Duration.EndOfTurn, filter + ), new GenericManaCost(1) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private EmergenceZone(final EmergenceZone card) { + super(card); + } + + @Override + public EmergenceZone copy() { + return new EmergenceZone(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EmergencyPowers.java b/Mage.Sets/src/mage/cards/e/EmergencyPowers.java new file mode 100644 index 0000000000..e2495e3607 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EmergencyPowers.java @@ -0,0 +1,79 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardAllEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.abilities.effects.common.ShuffleHandGraveyardAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EmergencyPowers extends CardImpl { + + public EmergencyPowers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{W}{U}"); + + // Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers. + this.getSpellAbility().addEffect(new ShuffleHandGraveyardAllEffect()); + this.getSpellAbility().addEffect(new DrawCardAllEffect(7).setText(", then draws seven cards")); + + // Addendum — If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield. + this.getSpellAbility().addEffect(new EmergencyPowersEffect()); + } + + private EmergencyPowers(final EmergencyPowers card) { + super(card); + } + + @Override + public EmergencyPowers copy() { + return new EmergencyPowers(this); + } +} + +class EmergencyPowersEffect extends OneShotEffect { + + public static final FilterPermanentCard filter + = new FilterPermanentCard("a permanent card with converted mana cost 7 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 8)); + } + + EmergencyPowersEffect() { + super(Outcome.Benefit); + staticText = "Exile {this}.
    Addendum — If you cast this spell during your main phase, " + + "you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield."; + } + + private EmergencyPowersEffect(final EmergencyPowersEffect effect) { + super(effect); + } + + @Override + public EmergencyPowersEffect copy() { + return new EmergencyPowersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (AddendumCondition.instance.apply(game, source)) { + new PutCardFromHandOntoBattlefieldEffect(filter).apply(game, source); + } + return ExileSpellEffect.getInstance().apply(game, source); + } +} +// I am the senate! diff --git a/Mage.Sets/src/mage/cards/e/EmissaryOfGrudges.java b/Mage.Sets/src/mage/cards/e/EmissaryOfGrudges.java index 9bd4c2fa1f..0f1f1141c2 100644 --- a/Mage.Sets/src/mage/cards/e/EmissaryOfGrudges.java +++ b/Mage.Sets/src/mage/cards/e/EmissaryOfGrudges.java @@ -94,11 +94,11 @@ class EmissaryOfGrudgesEffect extends OneShotEffect { Mode mode = stackObject.getStackAbility().getModes().get(modeId); for (Target target : mode.getTargets()) { for (UUID targetId : target.getTargets()) { - if (source.getControllerId().equals(targetId)) { + if (source.isControlledBy(targetId)) { targetsYouOrAPermanentYouControl = true; } Permanent permanent = game.getPermanent(targetId); - if (permanent != null && source.getControllerId().equals(permanent.getControllerId())) { + if (permanent != null && source.isControlledBy(permanent.getControllerId())) { targetsYouOrAPermanentYouControl = true; } } diff --git a/Mage.Sets/src/mage/cards/e/EmmaraTandris.java b/Mage.Sets/src/mage/cards/e/EmmaraTandris.java index e51f33d712..11d0794557 100644 --- a/Mage.Sets/src/mage/cards/e/EmmaraTandris.java +++ b/Mage.Sets/src/mage/cards/e/EmmaraTandris.java @@ -21,7 +21,7 @@ public final class EmmaraTandris extends CardImpl { private static final FilterCreatureOrPlayer filter = new FilterCreatureOrPlayer("creature tokens you control"); static { - filter.getCreatureFilter().add(new TokenPredicate()); + filter.getCreatureFilter().add(TokenPredicate.instance); filter.getCreatureFilter().add(new ControllerPredicate(TargetController.YOU)); filter.getPlayerFilter().add(new PlayerIdPredicate(UUID.randomUUID())); } diff --git a/Mage.Sets/src/mage/cards/e/EmptyCityRuse.java b/Mage.Sets/src/mage/cards/e/EmptyCityRuse.java index 020899fc0e..8e1ff3e417 100644 --- a/Mage.Sets/src/mage/cards/e/EmptyCityRuse.java +++ b/Mage.Sets/src/mage/cards/e/EmptyCityRuse.java @@ -1,11 +1,11 @@ - package mage.cards.e; import java.util.UUID; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.target.common.TargetOpponent; /** @@ -15,10 +15,10 @@ import mage.target.common.TargetOpponent; public final class EmptyCityRuse extends CardImpl { public EmptyCityRuse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // Target opponent skips all combat phases of their next turn. - this.getSpellAbility().addEffect(new SkipNextCombatEffect()); + this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.UntilYourNextTurn).setText("Target opponent skips all combat phases of their next turn.")); this.getSpellAbility().addTarget(new TargetOpponent()); } @@ -30,4 +30,4 @@ public final class EmptyCityRuse extends CardImpl { public EmptyCityRuse copy() { return new EmptyCityRuse(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/EmptyThePits.java b/Mage.Sets/src/mage/cards/e/EmptyThePits.java index f2bfbd27fb..fb2337fd5e 100644 --- a/Mage.Sets/src/mage/cards/e/EmptyThePits.java +++ b/Mage.Sets/src/mage/cards/e/EmptyThePits.java @@ -24,7 +24,7 @@ public final class EmptyThePits extends CardImpl { this.addAbility(new DelveAbility()); // create X 2/2 black Zombie creature tokens tapped. - this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), new ManacostVariableValue(), true, false)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), ManacostVariableValue.instance, true, false)); } public EmptyThePits(final EmptyThePits card) { diff --git a/Mage.Sets/src/mage/cards/e/EmpyrialArmor.java b/Mage.Sets/src/mage/cards/e/EmpyrialArmor.java index 9ae1b61d02..de4b1ffa23 100644 --- a/Mage.Sets/src/mage/cards/e/EmpyrialArmor.java +++ b/Mage.Sets/src/mage/cards/e/EmpyrialArmor.java @@ -38,7 +38,7 @@ public final class EmpyrialArmor extends CardImpl { this.addAbility(ability); // Enchanted creature gets +1/+1 for each card in your hand. - DynamicValue xValue = new CardsInControllerHandCount(); + DynamicValue xValue = CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(xValue, xValue, Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/cards/e/EmpyrialPlate.java b/Mage.Sets/src/mage/cards/e/EmpyrialPlate.java index d43fe32b16..4116555856 100644 --- a/Mage.Sets/src/mage/cards/e/EmpyrialPlate.java +++ b/Mage.Sets/src/mage/cards/e/EmpyrialPlate.java @@ -25,7 +25,7 @@ public final class EmpyrialPlate extends CardImpl { this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+1 for each card in your hand. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(new CardsInControllerHandCount(), new CardsInControllerHandCount()))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(CardsInControllerHandCount.instance, CardsInControllerHandCount.instance))); // Equip {2} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(2))); diff --git a/Mage.Sets/src/mage/cards/e/EmrakulTheAeonsTorn.java b/Mage.Sets/src/mage/cards/e/EmrakulTheAeonsTorn.java index 9d4c6f1fdb..b08775abcb 100644 --- a/Mage.Sets/src/mage/cards/e/EmrakulTheAeonsTorn.java +++ b/Mage.Sets/src/mage/cards/e/EmrakulTheAeonsTorn.java @@ -28,7 +28,7 @@ public final class EmrakulTheAeonsTorn extends CardImpl { private static final FilterSpell filter = new FilterSpell("colored spells"); static { - filter.add(Predicates.not(new ColorlessPredicate())); + filter.add(Predicates.not(ColorlessPredicate.instance)); } public EmrakulTheAeonsTorn(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EmrakulsEvangel.java b/Mage.Sets/src/mage/cards/e/EmrakulsEvangel.java index 15c20aff64..33faa4a966 100644 --- a/Mage.Sets/src/mage/cards/e/EmrakulsEvangel.java +++ b/Mage.Sets/src/mage/cards/e/EmrakulsEvangel.java @@ -61,7 +61,7 @@ class EmrakulsEvangelCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("non-Eldrazi creatures you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.not(new SubtypePredicate(SubType.ELDRAZI))); } diff --git a/Mage.Sets/src/mage/cards/e/EnchantedBeing.java b/Mage.Sets/src/mage/cards/e/EnchantedBeing.java new file mode 100644 index 0000000000..0843ff51f8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnchantedBeing.java @@ -0,0 +1,79 @@ + +package mage.cards.e; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author L_J + */ +public final class EnchantedBeing extends CardImpl { + + public EnchantedBeing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Prevent all damage that would be dealt to Enchanted Being by enchanted creatures. + Effect effect = new PreventDamageToSourceByEnchantedCreatures(); + effect.setText("Prevent all damage that would be dealt to {this} by enchanted creatures."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + } + + public EnchantedBeing(final EnchantedBeing card) { + super(card); + } + + @Override + public EnchantedBeing copy() { + return new EnchantedBeing(this); + } +} + +class PreventDamageToSourceByEnchantedCreatures extends PreventAllDamageToSourceEffect { + + public PreventDamageToSourceByEnchantedCreatures() { + super(Duration.WhileOnBattlefield); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (isEnchantedCreature(game.getObject(event.getSourceId()), game)) { + if (event.getTargetId().equals(source.getSourceId())) { + return true; + } + } + } + return false; + } + + public boolean isEnchantedCreature(MageObject input, Game game) { + if (input == null || input.isCreature()) { + return false; + } + for (UUID attachmentId : ((Permanent) input).getAttachments()) { + Permanent attachment = game.getPermanent(attachmentId); + if (attachment != null && attachment.isEnchantment()) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnchantmentAlteration.java b/Mage.Sets/src/mage/cards/e/EnchantmentAlteration.java new file mode 100644 index 0000000000..c0594751a6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnchantmentAlteration.java @@ -0,0 +1,145 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.MageItem; +import mage.abilities.Ability; +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.filter.FilterPermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AttachmentAttachedToCardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +/** + * + * @author jeffwadsworth + */ +public final class EnchantmentAlteration extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("aura attached to a creature or land"); + private static final FilterPermanent filter2 = new FilterPermanent("another target permanent that shares that type of creature or land"); + + static { + filter.add(new SubtypePredicate(SubType.AURA)); + filter.add(Predicates.or(new AttachmentAttachedToCardTypePredicate(CardType.CREATURE), + new AttachmentAttachedToCardTypePredicate(CardType.LAND))); + filter2.add(new SharesEnchantedCardTypePredicate()); + // another target permanent is handled in this predicate + } + + public EnchantmentAlteration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Attach target Aura attached to a creature or land to another permanent of that type. + this.getSpellAbility().addEffect(new EnchantmentAlterationEffect()); + TargetPermanent targetAura = new TargetPermanent(filter); + this.getSpellAbility().addTarget(targetAura); + + TargetPermanent targetCreatureOrLandThatSharesTheEnchantedCardType = new TargetPermanent(filter2); + this.getSpellAbility().addTarget(targetCreatureOrLandThatSharesTheEnchantedCardType); + + } + + public EnchantmentAlteration(final EnchantmentAlteration card) { + super(card); + } + + @Override + public EnchantmentAlteration copy() { + return new EnchantmentAlteration(this); + } + +} + +class SharesEnchantedCardTypePredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject source = game.getStack().getStackObject(input.getSourceId()); + Permanent auraIsAttachedToThisPermanent = null; + Permanent newPermanentToAttachAuraTo; + if (source != null) { + if (source.getStackAbility().getTargets().isEmpty() + || source.getStackAbility().getTargets().get(0).getTargets().isEmpty()) { + return true; + } + Permanent auraPermanent = game.getPermanent( + source.getStackAbility().getTargets().get(0).getTargets().get(0)); // targeted aura enchanting land or creature + if (auraPermanent != null) { + auraIsAttachedToThisPermanent = game.getPermanent(auraPermanent.getAttachedTo()); + } + if (auraIsAttachedToThisPermanent == null) { // the original permanent the aura is attached to + return false; + } + newPermanentToAttachAuraTo = game.getPermanent(input.getObject().getId()); // the new target creature or land to enchant + if (newPermanentToAttachAuraTo == auraIsAttachedToThisPermanent) { + return false; // must be another permanent + } + if (auraIsAttachedToThisPermanent.isCreature() + && newPermanentToAttachAuraTo.isCreature()) { + return true; + } + if (auraIsAttachedToThisPermanent.isLand() + && newPermanentToAttachAuraTo.isLand()) { + return true; + } + return false; + } + return true; + } + +} + +class EnchantmentAlterationEffect extends OneShotEffect { + + public EnchantmentAlterationEffect() { + super(Outcome.BoostCreature); + this.staticText = "Attach target Aura attached to a creature or land to another permanent of that type"; + } + + public EnchantmentAlterationEffect(final EnchantmentAlterationEffect effect) { + super(effect); + } + + @Override + public EnchantmentAlterationEffect copy() { + return new EnchantmentAlterationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent aura = game.getPermanent(source.getFirstTarget()); + Permanent permanentToBeAttachedTo = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (aura != null + && permanentToBeAttachedTo != null) { + Permanent oldPermanent = game.getPermanent(aura.getAttachedTo()); + if (oldPermanent != null + && !oldPermanent.equals(permanentToBeAttachedTo)) { + Target auraTarget = aura.getSpellAbility().getTargets().get(0); + if (!auraTarget.canTarget(permanentToBeAttachedTo.getId(), game)) { + game.informPlayers(aura.getLogName() + " was not attched to " + permanentToBeAttachedTo.getLogName() + " because it's no legal target for the aura"); + } else if (oldPermanent.removeAttachment(aura.getId(), game)) { + game.informPlayers(aura.getLogName() + " was unattached from " + oldPermanent.getLogName() + " and attached to " + permanentToBeAttachedTo.getLogName()); + permanentToBeAttachedTo.addAttachment(aura.getId(), game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnclaveElite.java b/Mage.Sets/src/mage/cards/e/EnclaveElite.java index 58f5df9c83..de61d1239d 100644 --- a/Mage.Sets/src/mage/cards/e/EnclaveElite.java +++ b/Mage.Sets/src/mage/cards/e/EnclaveElite.java @@ -36,7 +36,7 @@ public final class EnclaveElite extends CardImpl { // Enclave Elite enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true), "with a +1/+1 counter on it for each time it was kicked")); } diff --git a/Mage.Sets/src/mage/cards/e/EndRazeForerunners.java b/Mage.Sets/src/mage/cards/e/EndRazeForerunners.java new file mode 100644 index 0000000000..f189c0b9ab --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EndRazeForerunners.java @@ -0,0 +1,65 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.TrampleAbility; +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 mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EndRazeForerunners extends CardImpl { + + public EndRazeForerunners(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}{G}"); + + this.subtype.add(SubType.BOAR); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When End-Raze Forerunners enters the battlefield, other creatures you control get +2/+2 and gain vigilance and trample until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostControlledEffect( + 2, 2, Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("other creatures you control get +2/+2")); + ability.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and gain vigilance")); + ability.addEffect(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE, true + ).setText("and trample until end of turn")); + this.addAbility(ability); + } + + private EndRazeForerunners(final EndRazeForerunners card) { + super(card); + } + + @Override + public EndRazeForerunners copy() { + return new EndRazeForerunners(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java index 022cb4b44e..5702db5e5f 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessAtlas.java +++ b/Mage.Sets/src/mage/cards/e/EndlessAtlas.java @@ -51,7 +51,7 @@ class EndlessAtlasCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Map landMap = new HashMap(); + Map landMap = new HashMap<>(); for (Permanent land : game.getBattlefield().getActivePermanents( StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), game diff --git a/Mage.Sets/src/mage/cards/e/EndlessHorizons.java b/Mage.Sets/src/mage/cards/e/EndlessHorizons.java index d02030c854..ef0aee658c 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessHorizons.java +++ b/Mage.Sets/src/mage/cards/e/EndlessHorizons.java @@ -74,7 +74,7 @@ class EndlessHorizonsEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); if (you != null) { - if (you.searchLibrary(target, game)) { + if (you.searchLibrary(target, source, game)) { UUID exileZone = CardUtil.getCardExileZoneId(game, source); if (!target.getTargets().isEmpty()) { for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/e/EndlessSwarm.java b/Mage.Sets/src/mage/cards/e/EndlessSwarm.java index f3eac93fad..a33c408463 100644 --- a/Mage.Sets/src/mage/cards/e/EndlessSwarm.java +++ b/Mage.Sets/src/mage/cards/e/EndlessSwarm.java @@ -22,7 +22,7 @@ public final class EndlessSwarm extends CardImpl { // Create a 1/1 green Snake creature token for each card in your hand. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken(), new CardsInControllerHandCount())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken(), CardsInControllerHandCount.instance)); // Epic this.getSpellAbility().addEffect(new EpicEffect()); diff --git a/Mage.Sets/src/mage/cards/e/Endure.java b/Mage.Sets/src/mage/cards/e/Endure.java index e810f0289d..80c3866cb4 100644 --- a/Mage.Sets/src/mage/cards/e/Endure.java +++ b/Mage.Sets/src/mage/cards/e/Endure.java @@ -8,7 +8,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; -import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.common.FilterCreaturePlayerOrPlaneswalker; import mage.filter.predicate.other.PlayerPredicate; import mage.filter.predicate.permanent.ControllerPredicate; @@ -18,10 +18,10 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class Endure extends CardImpl { - private static final FilterPermanentOrPlayer filter = new FilterPermanentOrPlayer("you and permanents you control"); + private static final FilterCreaturePlayerOrPlaneswalker filter = new FilterCreaturePlayerOrPlaneswalker("you and permanents you control"); static { - filter.getPermanentFilter().add(new ControllerPredicate(TargetController.YOU)); + filter.getCreatureFilter().add(new ControllerPredicate(TargetController.YOU)); filter.getPlayerFilter().add(new PlayerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/e/EnduringIdeal.java b/Mage.Sets/src/mage/cards/e/EnduringIdeal.java index ee3d0919a9..29b2856c17 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringIdeal.java +++ b/Mage.Sets/src/mage/cards/e/EnduringIdeal.java @@ -68,7 +68,7 @@ class EnduringIdealEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - controller.searchLibrary(target, game); + controller.searchLibrary(target, source, game); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard == null) { applied = false; diff --git a/Mage.Sets/src/mage/cards/e/EnduringRenewal.java b/Mage.Sets/src/mage/cards/e/EnduringRenewal.java index 9d8a4e6575..510d9cb83b 100644 --- a/Mage.Sets/src/mage/cards/e/EnduringRenewal.java +++ b/Mage.Sets/src/mage/cards/e/EnduringRenewal.java @@ -82,8 +82,7 @@ class EnduringRenewalReplacementEffect extends ReplacementEffectImpl { } Card card = controller.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.revealCards("Top card of " + controller.getName() + "'s library", cards, game); if (card.isCreature()) { controller.moveCards(card, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/e/EnemyOfTheGuildpact.java b/Mage.Sets/src/mage/cards/e/EnemyOfTheGuildpact.java index eb2fc372c1..ee59ff16cb 100644 --- a/Mage.Sets/src/mage/cards/e/EnemyOfTheGuildpact.java +++ b/Mage.Sets/src/mage/cards/e/EnemyOfTheGuildpact.java @@ -20,7 +20,7 @@ public final class EnemyOfTheGuildpact extends CardImpl { private static final FilterObject filter = new FilterObject("multicolored"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public EnemyOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EnergyBolt.java b/Mage.Sets/src/mage/cards/e/EnergyBolt.java index 1ee26f7ef9..216c983a53 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyBolt.java +++ b/Mage.Sets/src/mage/cards/e/EnergyBolt.java @@ -22,11 +22,11 @@ public final class EnergyBolt extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{W}"); // Choose one - Energy Bolt deals X damage to target player; or target player gains X life. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); Mode mode = new Mode(); - mode.getEffects().add(new GainLifeTargetEffect(new ManacostVariableValue())); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new GainLifeTargetEffect(ManacostVariableValue.instance)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EnergyChamber.java b/Mage.Sets/src/mage/cards/e/EnergyChamber.java index fafd1fc73a..bd906d312c 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyChamber.java +++ b/Mage.Sets/src/mage/cards/e/EnergyChamber.java @@ -43,8 +43,8 @@ public final class EnergyChamber extends CardImpl { // or put a charge counter on target noncreature artifact. Mode mode = new Mode(); - mode.getEffects().add(new AddCountersTargetEffect(CounterType.CHARGE.createInstance(), Outcome.BoostCreature)); - mode.getTargets().add(new TargetPermanent(filter2)); + mode.addEffect(new AddCountersTargetEffect(CounterType.CHARGE.createInstance(), Outcome.BoostCreature)); + mode.addTarget(new TargetPermanent(filter2)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EnergyStorm.java b/Mage.Sets/src/mage/cards/e/EnergyStorm.java index e56b8fd6b0..a3a8cc4593 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyStorm.java +++ b/Mage.Sets/src/mage/cards/e/EnergyStorm.java @@ -24,7 +24,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class EnergyStorm extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with flying"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with flying"); static { filter.add(new AbilityPredicate(FlyingAbility.class)); diff --git a/Mage.Sets/src/mage/cards/e/EnergyTap.java b/Mage.Sets/src/mage/cards/e/EnergyTap.java index ef1aaadbf8..0b8e57fcd8 100644 --- a/Mage.Sets/src/mage/cards/e/EnergyTap.java +++ b/Mage.Sets/src/mage/cards/e/EnergyTap.java @@ -25,7 +25,7 @@ public final class EnergyTap extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public EnergyTap(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EnergyVortex.java b/Mage.Sets/src/mage/cards/e/EnergyVortex.java new file mode 100644 index 0000000000..1d45f4213a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnergyVortex.java @@ -0,0 +1,111 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalTriggeredAbility; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseOpponentEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnergyVortex extends CardImpl { + + public EnergyVortex(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + + // As Energy Vortex enters the battlefield, choose an opponent. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); + + // At the beginning of your upkeep, remove all vortex counters from Energy Vortex. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new RemoveAllCountersSourceEffect(CounterType.VORTEX), TargetController.YOU, false + )); + + // At the beginning of the chosen player's upkeep, Energy Vortex deals 3 damage to that player unless he or she pays {1} for each vortex counter on Energy Vortex. + this.addAbility(new ConditionalTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + new EnergyVortexEffect(), TargetController.ANY, false + ), EnergyVortexCondition.instance, "At the beginning of the chosen player's upkeep, " + + "{this} deals 3 damage to that player unless they pay {1} for each vortex counter on {this}." + )); + + // {X}: Put X vortex counters on Energy Vortex. Activate this ability only during your upkeep. + this.addAbility(new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, + new AddCountersSourceEffect( + CounterType.VORTEX.createInstance(), + ManacostVariableValue.instance, true + ), new ManaCostsImpl("{X}"), + new IsStepCondition(PhaseStep.UPKEEP) + )); + } + + private EnergyVortex(final EnergyVortex card) { + super(card); + } + + @Override + public EnergyVortex copy() { + return new EnergyVortex(this); + } +} + +enum EnergyVortexCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + return game.getActivePlayerId().equals(game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); + } +} + +class EnergyVortexEffect extends OneShotEffect { + + EnergyVortexEffect() { + super(Outcome.Benefit); + } + + private EnergyVortexEffect(final EnergyVortexEffect effect) { + super(effect); + } + + @Override + public EnergyVortexEffect copy() { + return new EnergyVortexEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player == null || permanent == null) { + return false; + } + int counters = permanent.getCounters(game).getCount(CounterType.VORTEX); + Cost cost = new GenericManaCost(counters); + if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + return true; + } + return player.damage(3, source.getSourceId(), game) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EnforcerGriffin.java b/Mage.Sets/src/mage/cards/e/EnforcerGriffin.java new file mode 100644 index 0000000000..ab651488de --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnforcerGriffin.java @@ -0,0 +1,36 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +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 EnforcerGriffin extends CardImpl { + + public EnforcerGriffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.GRIFFIN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + private EnforcerGriffin(final EnforcerGriffin card) { + super(card); + } + + @Override + public EnforcerGriffin copy() { + return new EnforcerGriffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnfysNest.java b/Mage.Sets/src/mage/cards/e/EnfysNest.java index 0fb3a495b8..a1c387a804 100644 --- a/Mage.Sets/src/mage/cards/e/EnfysNest.java +++ b/Mage.Sets/src/mage/cards/e/EnfysNest.java @@ -74,9 +74,11 @@ class EnfysNestEffect extends ExileTargetEffect { // If you do, that player gains life equal to that creature's power. Player player = game.getPlayer(permanent.getControllerId()); - player.gainLife(permanent.getPower().getValue(), game, source); + if(player != null) { + player.gainLife(permanent.getPower().getValue(), game, source); - return true; + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/cards/e/EngineeredMight.java b/Mage.Sets/src/mage/cards/e/EngineeredMight.java index 5db6638c8d..834919d834 100644 --- a/Mage.Sets/src/mage/cards/e/EngineeredMight.java +++ b/Mage.Sets/src/mage/cards/e/EngineeredMight.java @@ -41,10 +41,10 @@ public final class EngineeredMight extends CardImpl { Mode mode = new Mode(); effect = new BoostControlledEffect(2, 2, Duration.EndOfTurn); effect.setText("Creatures you control get +2/+2"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent()); effect.setText("and gain vigilance until end of turn"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/Enrage.java b/Mage.Sets/src/mage/cards/e/Enrage.java index 83c2876c0c..9d83d33659 100644 --- a/Mage.Sets/src/mage/cards/e/Enrage.java +++ b/Mage.Sets/src/mage/cards/e/Enrage.java @@ -22,7 +22,7 @@ public final class Enrage extends CardImpl { // Target creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/e/EnragedCeratok.java b/Mage.Sets/src/mage/cards/e/EnragedCeratok.java new file mode 100644 index 0000000000..5098f50a5d --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnragedCeratok.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnragedCeratok extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public EnragedCeratok(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); + + this.subtype.add(SubType.RHINO); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Enraged Ceratok can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield) + )); + } + + private EnragedCeratok(final EnragedCeratok card) { + super(card); + } + + @Override + public EnragedCeratok copy() { + return new EnragedCeratok(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EnshrinedMemories.java b/Mage.Sets/src/mage/cards/e/EnshrinedMemories.java index 224dcc1d44..9dbaf7728b 100644 --- a/Mage.Sets/src/mage/cards/e/EnshrinedMemories.java +++ b/Mage.Sets/src/mage/cards/e/EnshrinedMemories.java @@ -20,7 +20,7 @@ public final class EnshrinedMemories extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}"); // Reveal the top X cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order. - this.getSpellAbility().addEffect(new RevealLibraryPutIntoHandEffect(new ManacostVariableValue(), new FilterCreatureCard(), Zone.LIBRARY, true)); + this.getSpellAbility().addEffect(new RevealLibraryPutIntoHandEffect(ManacostVariableValue.instance, new FilterCreatureCard(), Zone.LIBRARY, true)); } public EnshrinedMemories(final EnshrinedMemories card) { diff --git a/Mage.Sets/src/mage/cards/e/EnslavedHorror.java b/Mage.Sets/src/mage/cards/e/EnslavedHorror.java index 3fbba05fa1..c8362a0ca2 100644 --- a/Mage.Sets/src/mage/cards/e/EnslavedHorror.java +++ b/Mage.Sets/src/mage/cards/e/EnslavedHorror.java @@ -32,7 +32,7 @@ public final class EnslavedHorror extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(4); - // When Enslaved Horror enters the battlefield, each other player may return a creature card from his or her graveyard to the battlefield. + // When Enslaved Horror enters the battlefield, each other player may return a creature card from their graveyard to the battlefield. this.addAbility(new EntersBattlefieldTriggeredAbility(new EnslavedHorrorEffect())); } diff --git a/Mage.Sets/src/mage/cards/e/EnsnaringBridge.java b/Mage.Sets/src/mage/cards/e/EnsnaringBridge.java index 0fdf7a1862..eb32232266 100644 --- a/Mage.Sets/src/mage/cards/e/EnsnaringBridge.java +++ b/Mage.Sets/src/mage/cards/e/EnsnaringBridge.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -14,8 +12,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author Plopman */ public final class EnsnaringBridge extends CardImpl { @@ -59,7 +58,7 @@ class EnsnaringBridgeRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/e/EntanglingVines.java b/Mage.Sets/src/mage/cards/e/EntanglingVines.java index 808eb3b560..49bd76d564 100644 --- a/Mage.Sets/src/mage/cards/e/EntanglingVines.java +++ b/Mage.Sets/src/mage/cards/e/EntanglingVines.java @@ -26,7 +26,7 @@ public final class EntanglingVines extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public EntanglingVines(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EnterTheGodEternals.java b/Mage.Sets/src/mage/cards/e/EnterTheGodEternals.java new file mode 100644 index 0000000000..fe6bdebf9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EnterTheGodEternals.java @@ -0,0 +1,82 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPlayer; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EnterTheGodEternals extends CardImpl { + + public EnterTheGodEternals(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}{B}"); + + // Enter the God-Eternals deals 4 damage to target creature and you gain life equal to the damage dealt this way. Target player puts the top four cards of their library into their graveyard. Amass 4. + this.getSpellAbility().addEffect(new EnterTheGodEternalsEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetPlayer()); + } + + private EnterTheGodEternals(final EnterTheGodEternals card) { + super(card); + } + + @Override + public EnterTheGodEternals copy() { + return new EnterTheGodEternals(this); + } +} + +class EnterTheGodEternalsEffect extends OneShotEffect { + + EnterTheGodEternalsEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 4 damage to target creature and you gain life equal to the damage dealt this way. " + + "Target player puts the top four cards of their library into their graveyard. Amass 4."; + } + + private EnterTheGodEternalsEffect(final EnterTheGodEternalsEffect effect) { + super(effect); + } + + @Override + public EnterTheGodEternalsEffect copy() { + return new EnterTheGodEternalsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + controller.gainLife(permanent.damage(4, source.getSourceId(), game), game, source); + continue; + } + Player player = game.getPlayer(targetId); + if (player != null) { + player.moveCards(player.getLibrary().getTopCards(game, 4), Zone.GRAVEYARD, source, game); + } + } + } + return new AmassEffect(4).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/Entomb.java b/Mage.Sets/src/mage/cards/e/Entomb.java index acf119d0c5..039d09c2dc 100644 --- a/Mage.Sets/src/mage/cards/e/Entomb.java +++ b/Mage.Sets/src/mage/cards/e/Entomb.java @@ -60,7 +60,7 @@ class SearchLibraryPutInGraveyard extends SearchEffect { if (controller == null) { return false; } - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(game.getCard(target.getFirstTarget()), Zone.GRAVEYARD, source, game); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/e/EntomberExarch.java b/Mage.Sets/src/mage/cards/e/EntomberExarch.java index ff4b4c5d6e..9a43353a32 100644 --- a/Mage.Sets/src/mage/cards/e/EntomberExarch.java +++ b/Mage.Sets/src/mage/cards/e/EntomberExarch.java @@ -42,8 +42,8 @@ public final class EntomberExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnToHandTargetEffect(), false); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); Mode mode = new Mode(); - mode.getEffects().add(new EntomberExarchEffect()); - mode.getTargets().add(new TargetOpponent()); + mode.addEffect(new EntomberExarchEffect()); + mode.addTarget(new TargetOpponent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/e/EntrancingMelody.java b/Mage.Sets/src/mage/cards/e/EntrancingMelody.java index 4c14d0ee0c..5fb6288498 100644 --- a/Mage.Sets/src/mage/cards/e/EntrancingMelody.java +++ b/Mage.Sets/src/mage/cards/e/EntrancingMelody.java @@ -1,9 +1,7 @@ package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,38 +12,45 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class EntrancingMelody extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X"); + public EntrancingMelody(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); // Gain control of target creature with converted mana cost X. this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.Custom, true)); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with converted mana cost X"))); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().setTargetAdjuster(EntrancingMelodyAdjuster.instance); } public EntrancingMelody(final EntrancingMelody card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } - @Override public EntrancingMelody copy() { return new EntrancingMelody(this); } } + +enum EntrancingMelodyAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java index 2853d798b7..846af092c6 100644 --- a/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java +++ b/Mage.Sets/src/mage/cards/e/EntrapmentManeuver.java @@ -66,7 +66,7 @@ class EntrapmentManeuverSacrificeEffect extends OneShotEffect { return false; } FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); int realCount = game.getBattlefield().countAll(filter, player.getId(), game); if (realCount > 0) { Target target = new TargetControlledPermanent(1, 1, filter, true); diff --git a/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java b/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java index e398ee5b5b..234618f351 100644 --- a/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java +++ b/Mage.Sets/src/mage/cards/e/EntreatTheAngels.java @@ -22,7 +22,7 @@ public final class EntreatTheAngels extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{W}{W}{W}"); // Create X 4/4 white Angel creature tokens with flying. - this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new AngelToken(), ManacostVariableValue.instance)); // Miracle {X}{W}{W} this.addAbility(new MiracleAbility(this, new ManaCostsImpl("{X}{W}{W}"))); diff --git a/Mage.Sets/src/mage/cards/e/EntreatTheDead.java b/Mage.Sets/src/mage/cards/e/EntreatTheDead.java index 86d76b7b4a..58b597c89f 100644 --- a/Mage.Sets/src/mage/cards/e/EntreatTheDead.java +++ b/Mage.Sets/src/mage/cards/e/EntreatTheDead.java @@ -2,7 +2,6 @@ package mage.cards.e; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.abilities.keyword.MiracleAbility; @@ -14,6 +13,7 @@ import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -27,25 +27,10 @@ public final class EntreatTheDead extends CardImpl { // Return X target creature cards from your graveyard to the battlefield. this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(1, StaticFilters.FILTER_CARD_CREATURE)); + this.getSpellAbility().setTargetAdjuster(EntreatTheDeadAdjuster.instance); // Miracle {X}{B}{B} this.addAbility(new MiracleAbility(this, new ManaCostsImpl("{X}{B}{B}"))); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - String filterName = xValue - + (xValue != 1 ? " creature cards" : "creature card") - + " from your graveyard"; - Target target = new TargetCardInYourGraveyard( - xValue, new FilterCreatureCard(filterName) - ); - ability.addTarget(target); - } } public EntreatTheDead(final EntreatTheDead card) { @@ -57,3 +42,20 @@ public final class EntreatTheDead extends CardImpl { return new EntreatTheDead(this); } } + +enum EntreatTheDeadAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + String filterName = xValue + + (xValue != 1 ? " creature cards" : "creature card") + + " from your graveyard"; + Target target = new TargetCardInYourGraveyard( + xValue, new FilterCreatureCard(filterName) + ); + ability.addTarget(target); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EntropicSpecter.java b/Mage.Sets/src/mage/cards/e/EntropicSpecter.java index 1102b8e1ba..ef504ece33 100644 --- a/Mage.Sets/src/mage/cards/e/EntropicSpecter.java +++ b/Mage.Sets/src/mage/cards/e/EntropicSpecter.java @@ -1,7 +1,6 @@ package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -19,8 +18,9 @@ import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class EntropicSpecter extends CardImpl { @@ -42,7 +42,7 @@ public final class EntropicSpecter extends CardImpl { // Entropic Specter's power and toughness are each equal to the number of cards in the chosen player's hand. this.addAbility(new SimpleStaticAbility(Zone.ALL, // back to the graveyard or if the choosen player left the gane it's again a 0/0 - new SetPowerToughnessSourceEffect(new CardsInTargetPlayerHandCount(), Duration.WhileOnBattlefield, SubLayer.CharacteristicDefining_7a))); + new SetPowerToughnessSourceEffect(CardsInTargetPlayerHandCount.instance, Duration.WhileOnBattlefield, SubLayer.CharacteristicDefining_7a))); // Whenever Entropic Specter deals damage to a player, that player discards a card. this.addAbility(new DealsDamageToAPlayerTriggeredAbility(new DiscardTargetEffect(1, false), false, true)); @@ -58,7 +58,8 @@ public final class EntropicSpecter extends CardImpl { } } -class CardsInTargetPlayerHandCount implements DynamicValue { +enum CardsInTargetPlayerHandCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -74,7 +75,7 @@ class CardsInTargetPlayerHandCount implements DynamicValue { @Override public DynamicValue copy() { - return new mage.abilities.dynamicvalue.common.CardsInControllerHandCount(); + return instance; } @Override diff --git a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java index 8f149ba496..c3ae62a97a 100644 --- a/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java +++ b/Mage.Sets/src/mage/cards/e/EpharaGodOfThePolis.java @@ -70,7 +70,7 @@ enum HadAnotherCreatureEnterTheBattlefieldCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); return sourcePermanent != null && watcher != null && watcher.anotherCreatureEnteredBattlefieldUnderPlayersControlLastTurn(sourcePermanent, game); diff --git a/Mage.Sets/src/mage/cards/e/EpicExperiment.java b/Mage.Sets/src/mage/cards/e/EpicExperiment.java index f7358be404..ed85156345 100644 --- a/Mage.Sets/src/mage/cards/e/EpicExperiment.java +++ b/Mage.Sets/src/mage/cards/e/EpicExperiment.java @@ -80,12 +80,15 @@ class EpicExperimentEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { Card card = game.getCard(targetCard.getFirstTarget()); if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { - cardsToCast.remove(card); - } else { + if (!controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); } + cardsToCast.remove(card); + } else { + break; } + } else { + break; } } // move cards not cast to graveyard diff --git a/Mage.Sets/src/mage/cards/e/Epicenter.java b/Mage.Sets/src/mage/cards/e/Epicenter.java index 9f2a1f4f4d..aa54475f9d 100644 --- a/Mage.Sets/src/mage/cards/e/Epicenter.java +++ b/Mage.Sets/src/mage/cards/e/Epicenter.java @@ -1,8 +1,6 @@ package mage.cards.e; -import java.util.Iterator; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.CardsInControllerGraveCondition; @@ -18,8 +16,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.Iterator; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Epicenter extends CardImpl { @@ -31,12 +31,15 @@ public final class Epicenter extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new SacrificeEffect(StaticFilters.FILTER_LAND, 1, "Target player"), new InvertCondition(new CardsInControllerGraveCondition(7)), - "Target player sacrifices a land")); + "Target player sacrifices a land" + )); // Threshold - Each player sacrifices all lands he or she controls instead if seven or more cards are in your graveyard. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new EpicenterEffect(), new CardsInControllerGraveCondition(7), - "

    Threshold — Each player sacrifices all lands he or she controls instead if seven or more cards are in your graveyard.")); + "

    Threshold — Each player sacrifices all lands they control instead " + + "if seven or more cards are in your graveyard." + )); this.getSpellAbility().addTarget(new TargetPlayer()); } @@ -55,10 +58,9 @@ class EpicenterEffect extends OneShotEffect { EpicenterEffect() { super(Outcome.DestroyPermanent); - staticText = "Each player sacrifices all lands he or she controls"; } - EpicenterEffect(final EpicenterEffect effect) { + private EpicenterEffect(final EpicenterEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java b/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java index cad05da246..e1b8c901ed 100644 --- a/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java +++ b/Mage.Sets/src/mage/cards/e/EpiphanyAtTheDrownyard.java @@ -68,8 +68,7 @@ class EpiphanyAtTheDrownyardEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX() + 1)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX() + 1)); controller.revealCards(sourceObject.getIdName(), cards, game); Player opponent; diff --git a/Mage.Sets/src/mage/cards/e/ErayoSoratamiAscendant.java b/Mage.Sets/src/mage/cards/e/ErayoSoratamiAscendant.java index 6f50051ae6..6841c7760f 100644 --- a/Mage.Sets/src/mage/cards/e/ErayoSoratamiAscendant.java +++ b/Mage.Sets/src/mage/cards/e/ErayoSoratamiAscendant.java @@ -78,7 +78,7 @@ class ErayoSoratamiAscendantTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); return watcher != null && watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn() == 4; } @@ -134,7 +134,7 @@ class ErayosEssenceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(getControllerId()).contains(event.getPlayerId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 1) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); diff --git a/Mage.Sets/src/mage/cards/e/ErdwalIlluminator.java b/Mage.Sets/src/mage/cards/e/ErdwalIlluminator.java index c5e6480f44..048335a056 100644 --- a/Mage.Sets/src/mage/cards/e/ErdwalIlluminator.java +++ b/Mage.Sets/src/mage/cards/e/ErdwalIlluminator.java @@ -66,7 +66,7 @@ class ErdwalIlluminatorTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - InvestigatedWatcher watcher = (InvestigatedWatcher) game.getState().getWatchers().get(InvestigatedWatcher.class.getSimpleName()); + InvestigatedWatcher watcher = game.getState().getWatcher(InvestigatedWatcher.class); return watcher != null && watcher.getTimesInvestigated(getControllerId()) == 1; } @@ -86,7 +86,7 @@ class InvestigatedWatcher extends Watcher { private final Map timesInvestigated = new HashMap<>(); public InvestigatedWatcher() { - super(InvestigatedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public InvestigatedWatcher(final InvestigatedWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/e/ErebossTitan.java b/Mage.Sets/src/mage/cards/e/ErebossTitan.java index c155d1cf61..d15a436bb8 100644 --- a/Mage.Sets/src/mage/cards/e/ErebossTitan.java +++ b/Mage.Sets/src/mage/cards/e/ErebossTitan.java @@ -34,7 +34,7 @@ import mage.players.Player; */ public final class ErebossTitan extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/e/ErgRaiders.java b/Mage.Sets/src/mage/cards/e/ErgRaiders.java index fbf0ea92e3..01899e227c 100644 --- a/Mage.Sets/src/mage/cards/e/ErgRaiders.java +++ b/Mage.Sets/src/mage/cards/e/ErgRaiders.java @@ -55,8 +55,8 @@ class ErgRaidersCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent raiders = game.getPermanentOrLKIBattlefield(source.getSourceId()); - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); // wasControlledFromStartOfControllerTurn should be checked during resolution I guess, but shouldn't be relevant - return raiders.wasControlledFromStartOfControllerTurn() && !watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(raiders, game)); + return raiders != null &&raiders.wasControlledFromStartOfControllerTurn() && watcher != null && !watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(raiders, game)); } } diff --git a/Mage.Sets/src/mage/cards/e/ErrantMinion.java b/Mage.Sets/src/mage/cards/e/ErrantMinion.java new file mode 100644 index 0000000000..53844a3a82 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ErrantMinion.java @@ -0,0 +1,121 @@ +package mage.cards.e; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.PreventDamageToTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class ErrantMinion extends CardImpl { + + public ErrantMinion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of the upkeep of enchanted creature's controller, that player may pay any amount of mana. Errant Minion deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, + new ErrantMinionEffect(), + TargetController.CONTROLLER_ATTACHED_TO, + false)); + + } + + private ErrantMinion(final ErrantMinion card) { + super(card); + } + + @Override + public ErrantMinion copy() { + return new ErrantMinion(this); + } +} + +class ErrantMinionEffect extends OneShotEffect { + + public ErrantMinionEffect() { + super(Outcome.Damage); + this.staticText = "that player may pay any amount of mana. Errant Minion deals 2 damage to that player. Prevent X of that damage, where X is the amount of mana that player paid this way"; + } + + public ErrantMinionEffect(final ErrantMinionEffect effect) { + super(effect); + } + + @Override + public ErrantMinionEffect copy() { + return new ErrantMinionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent errantMinion = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (errantMinion == null) { + return false; + } + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(errantMinion.getAttachedTo()); + if (enchantedCreature == null) { + return false; + } + Player controllerOfEnchantedCreature = game.getPlayer(enchantedCreature.getControllerId()); + if (controllerOfEnchantedCreature != null) { + int manaPaid = playerPaysXGenericMana(controllerOfEnchantedCreature, source, game); + PreventDamageToTargetEffect effect = new PreventDamageToTargetEffect(Duration.OneUse, manaPaid); + effect.setTargetPointer(new FixedTarget(controllerOfEnchantedCreature.getId())); + game.addEffect(effect, source); + DamageTargetEffect effect2 = new DamageTargetEffect(2); + effect2.setTargetPointer(new FixedTarget(controllerOfEnchantedCreature.getId())); + effect2.apply(game, source); + return true; + } + return false; + } + + protected static int playerPaysXGenericMana(Player player, Ability source, Game game) { + int xValue = 0; + boolean payed = false; + while (!payed) { + xValue = player.announceXMana(0, Integer.MAX_VALUE, "How much mana will you pay?", game, source); + if (xValue > 0) { + Cost cost = new GenericManaCost(xValue); + payed = cost.pay(source, game, source.getSourceId(), player.getId(), false, null); + } else { + payed = true; + } + } + game.informPlayers(player.getLogName() + " pays {" + xValue + '}'); + return xValue; + } + +} diff --git a/Mage.Sets/src/mage/cards/e/ErraticVisionary.java b/Mage.Sets/src/mage/cards/e/ErraticVisionary.java new file mode 100644 index 0000000000..8ae0c49a79 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ErraticVisionary.java @@ -0,0 +1,45 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +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 ErraticVisionary extends CardImpl { + + public ErraticVisionary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {1}{U}, {T}: Draw a card, then discard a card. + Ability ability = new SimpleActivatedAbility( + new DrawDiscardControllerEffect(), new ManaCostsImpl("{1}{U}") + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private ErraticVisionary(final ErraticVisionary card) { + super(card); + } + + @Override + public ErraticVisionary copy() { + return new ErraticVisionary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EsperCharm.java b/Mage.Sets/src/mage/cards/e/EsperCharm.java index 2d077d48f1..560283f8c5 100644 --- a/Mage.Sets/src/mage/cards/e/EsperCharm.java +++ b/Mage.Sets/src/mage/cards/e/EsperCharm.java @@ -27,12 +27,12 @@ public final class EsperCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); // or draw two cards; Mode mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(2)); + mode.addEffect(new DrawCardSourceControllerEffect(2)); this.getSpellAbility().addMode(mode); // or target player discards two cards. mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(2)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new DiscardTargetEffect(2)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EsperStormblade.java b/Mage.Sets/src/mage/cards/e/EsperStormblade.java index a326fa966c..04f376a441 100644 --- a/Mage.Sets/src/mage/cards/e/EsperStormblade.java +++ b/Mage.Sets/src/mage/cards/e/EsperStormblade.java @@ -29,8 +29,8 @@ public final class EsperStormblade extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another multicolor permanent"); static { - filter.add(new MulticoloredPredicate()); - filter.add(new AnotherPredicate()); + filter.add(MulticoloredPredicate.instance); + filter.add(AnotherPredicate.instance); } public EsperStormblade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EssenceCapture.java b/Mage.Sets/src/mage/cards/e/EssenceCapture.java new file mode 100644 index 0000000000..7af749c449 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EssenceCapture.java @@ -0,0 +1,43 @@ +package mage.cards.e; + +import mage.abilities.effects.common.CounterTargetEffect; +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.filter.common.FilterCreatureSpell; +import mage.target.TargetSpell; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.SecondTargetPointer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EssenceCapture extends CardImpl { + + public EssenceCapture(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + // Counter target creature spell. + this.getSpellAbility().addEffect(new CounterTargetEffect()); + this.getSpellAbility().addTarget(new TargetSpell(new FilterCreatureSpell())); + + // Put a +1/+1 counter on up to one target creature you control. + this.getSpellAbility().addEffect(new AddCountersTargetEffect( + CounterType.P1P1.createInstance() + ).setTargetPointer(new SecondTargetPointer())); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent(0, 1)); + } + + private EssenceCapture(final EssenceCapture card) { + super(card); + } + + @Override + public EssenceCapture copy() { + return new EssenceCapture(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EssenceHarvest.java b/Mage.Sets/src/mage/cards/e/EssenceHarvest.java index 3f54818000..797058f974 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceHarvest.java +++ b/Mage.Sets/src/mage/cards/e/EssenceHarvest.java @@ -1,4 +1,3 @@ - package mage.cards.e; import java.util.List; @@ -57,10 +56,12 @@ class EssenceHarvestEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - if (player != null && targetPlayer != null) { - List creatures = game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game); + if (controller != null + && targetPlayer != null) { + List creatures = game.getBattlefield().getAllActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game); int amount = 0; for (Permanent creature : creatures) { int power = creature.getPower().getValue(); @@ -71,7 +72,7 @@ class EssenceHarvestEffect extends OneShotEffect { if (amount > 0) { targetPlayer.loseLife(amount, game, false); - player.gainLife(amount, game, source); + controller.gainLife(amount, game, source); } return true; } diff --git a/Mage.Sets/src/mage/cards/e/EssenceOfTheWild.java b/Mage.Sets/src/mage/cards/e/EssenceOfTheWild.java index 2d1a030d4d..eb64cf137c 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceOfTheWild.java +++ b/Mage.Sets/src/mage/cards/e/EssenceOfTheWild.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,25 +7,22 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CopyEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class EssenceOfTheWild extends CardImpl { public EssenceOfTheWild(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}{G}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(6); @@ -73,11 +68,7 @@ class EssenceOfTheWildEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourceObject != null) { - Permanent permanentReset = sourceObject.copy(); - permanentReset.getCounters(game).clear(); - permanentReset.getPower().resetToBaseValue(); - permanentReset.getToughness().resetToBaseValue(); - game.addEffect(new CopyEffect(Duration.Custom, permanentReset, event.getTargetId()), source); + game.addEffect(new CopyEffect(Duration.Custom, sourceObject, event.getTargetId()), source); } return false; } diff --git a/Mage.Sets/src/mage/cards/e/EssenceWarden.java b/Mage.Sets/src/mage/cards/e/EssenceWarden.java index c66cb98aa7..d260fedbd5 100644 --- a/Mage.Sets/src/mage/cards/e/EssenceWarden.java +++ b/Mage.Sets/src/mage/cards/e/EssenceWarden.java @@ -21,7 +21,7 @@ public final class EssenceWarden extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public EssenceWarden(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java index 9cc5c30fc4..25f0afb81c 100644 --- a/Mage.Sets/src/mage/cards/e/EstridTheMasked.java +++ b/Mage.Sets/src/mage/cards/e/EstridTheMasked.java @@ -38,8 +38,8 @@ public final class EstridTheMasked extends CardImpl { private static final FilterPermanent filter2 = new FilterPermanent("another permanent"); static { - filter.add(new EnchantedPredicate()); - filter2.add(new AnotherPredicate()); + filter.add(EnchantedPredicate.instance); + filter2.add(AnotherPredicate.instance); } public EstridTheMasked(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java index de1af82213..8e1f289874 100644 --- a/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java +++ b/Mage.Sets/src/mage/cards/e/EtaliPrimalStorm.java @@ -58,7 +58,7 @@ public final class EtaliPrimalStorm extends CardImpl { class EtaliPrimalStormEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("nonland cards"); + private static final FilterCard filter = new FilterCard("nonland cards"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); @@ -97,6 +97,7 @@ class EtaliPrimalStormEffect extends OneShotEffect { } } } + // cast the possible cards without paying the mana Cards cardsToCast = new CardsImpl(); cardsToCast.addAll(currentExiledCards); @@ -105,17 +106,21 @@ class EtaliPrimalStormEffect extends OneShotEffect { if (!controller.chooseUse(Outcome.PlayForFree, "Cast a" + (alreadyCast ? "nother" : "") + " card exiled with " + sourceObject.getLogName() + " without paying its mana cost?", source, game)) { break; } + TargetCard targetCard = new TargetCard(1, Zone.EXILED, new FilterCard("nonland card to cast for free")); - if (controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { - alreadyCast = true; - Card card = game.getCard(targetCard.getFirstTarget()); - if (card != null) { - if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { - cardsToCast.remove(card); - } else { + if (!controller.choose(Outcome.PlayForFree, cardsToCast, targetCard, game)) { + break; + } + + alreadyCast = true; + Card card = game.getCard(targetCard.getFirstTarget()); + if (card != null) { + if (!controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { + if (!game.isSimulation()) { game.informPlayer(controller, "You're not able to cast " + card.getIdName() + " or you canceled the casting."); } } + cardsToCast.remove(card); } } return true; diff --git a/Mage.Sets/src/mage/cards/e/EternalDominion.java b/Mage.Sets/src/mage/cards/e/EternalDominion.java index 74c32ebd33..ebaa4377f1 100644 --- a/Mage.Sets/src/mage/cards/e/EternalDominion.java +++ b/Mage.Sets/src/mage/cards/e/EternalDominion.java @@ -77,7 +77,7 @@ class EternalDominionEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (opponent != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(FILTER); - controller.searchLibrary(target, game, opponent.getId()); + controller.searchLibrary(target, source, game, opponent.getId()); Card targetCard = game.getCard(target.getFirstTarget()); if (targetCard != null) { applied = controller.moveCards(targetCard, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/e/EternalSkylord.java b/Mage.Sets/src/mage/cards/e/EternalSkylord.java new file mode 100644 index 0000000000..a6f9bf7626 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EternalSkylord.java @@ -0,0 +1,56 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +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.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EternalSkylord extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent(SubType.ZOMBIE, "Zombie tokens"); + + static { + filter.add(TokenPredicate.instance); + } + + public EternalSkylord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Eternal Skylord enters the batttlefield, amass 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(2))); + + // Zombie tokens you control have flying. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + FlyingAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + } + + private EternalSkylord(final EternalSkylord card) { + super(card); + } + + @Override + public EternalSkylord copy() { + return new EternalSkylord(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EternalTaskmaster.java b/Mage.Sets/src/mage/cards/e/EternalTaskmaster.java new file mode 100644 index 0000000000..919dd61f1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EternalTaskmaster.java @@ -0,0 +1,50 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EternalTaskmaster extends CardImpl { + + public EternalTaskmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Eternal Taskmaster enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // Whenever Eternal Taskmaster attacks, you may pay {2}{B}. If you do, return target creature card from your graveyard to your hand. + Ability ability = new AttacksTriggeredAbility(new DoIfCostPaid( + new ReturnToHandTargetEffect(), new ManaCostsImpl("{2}{B}") + ), false); + ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.addAbility(ability); + } + + private EternalTaskmaster(final EternalTaskmaster card) { + super(card); + } + + @Override + public EternalTaskmaster copy() { + return new EternalTaskmaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EtherWell.java b/Mage.Sets/src/mage/cards/e/EtherWell.java new file mode 100644 index 0000000000..cb578d4bd7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtherWell.java @@ -0,0 +1,74 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EtherWell extends CardImpl { + + public EtherWell(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}"); + + // Put target creature on top of its owner's library. If that creature is red, you may put it on the bottom of its owner's library instead. + this.getSpellAbility().addEffect(new EtherWellEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private EtherWell(final EtherWell card) { + super(card); + } + + @Override + public EtherWell copy() { + return new EtherWell(this); + } +} + +class EtherWellEffect extends OneShotEffect { + + EtherWellEffect() { + super(Outcome.Benefit); + staticText = "Put target creature on top of its owner's library. " + + "If that creature is red, you may put it on the bottom of its owner's library instead."; + } + + private EtherWellEffect(final EtherWellEffect effect) { + super(effect); + } + + @Override + public EtherWellEffect copy() { + return new EtherWellEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (player == null || permanent == null) { + return false; + } + if (permanent.getColor(game).isRed() + && player.chooseUse(outcome, "Put " + permanent.getLogName() + + " on the bottom of its owner's library?", source, game + )) { + player.putCardsOnBottomOfLibrary(permanent, game, source, true); + return true; + } + player.putCardsOnTopOfLibrary(new CardsImpl(permanent), game, source, true); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EtherealAbsolution.java b/Mage.Sets/src/mage/cards/e/EtherealAbsolution.java new file mode 100644 index 0000000000..49bb668e5a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EtherealAbsolution.java @@ -0,0 +1,91 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.BoostOpponentsEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.token.WhiteBlackSpiritToken; +import mage.players.Player; +import mage.target.common.TargetCardInOpponentsGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EtherealAbsolution extends CardImpl { + + public EtherealAbsolution(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}{B}"); + + // Creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility( + new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield) + )); + + // Creatures your opponents control get -1/-1. + this.addAbility(new SimpleStaticAbility( + new BoostOpponentsEffect(-1, -1, Duration.WhileOnBattlefield) + )); + + // {2}{W}{B}: Exile target card from an opponent's graveyard. If it was a creature card, you create a 1/1 white and black Spirit creature token with flying. + Ability ability = new SimpleActivatedAbility( + new EtherealAbsolutionEffect(), new ManaCostsImpl("{2}{W}{B}") + ); + ability.addTarget(new TargetCardInOpponentsGraveyard(StaticFilters.FILTER_CARD)); + this.addAbility(ability); + } + + private EtherealAbsolution(final EtherealAbsolution card) { + super(card); + } + + @Override + public EtherealAbsolution copy() { + return new EtherealAbsolution(this); + } +} + +class EtherealAbsolutionEffect extends OneShotEffect { + + EtherealAbsolutionEffect() { + super(Outcome.Benefit); + staticText = "Exile target card from an opponent's graveyard. " + + "If it was a creature card, you create a 1/1 white and black Spirit creature token with flying."; + } + + private EtherealAbsolutionEffect(final EtherealAbsolutionEffect effect) { + super(effect); + } + + @Override + public EtherealAbsolutionEffect copy() { + return new EtherealAbsolutionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Card card = game.getCard(source.getFirstTarget()); + if (player == null || card == null) { + return false; + } + if (card.isCreature()) { + new CreateTokenEffect(new WhiteBlackSpiritToken()).apply(game, source); + } + return player.moveCards(card, Zone.EXILED, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/e/EtherswornCanonist.java b/Mage.Sets/src/mage/cards/e/EtherswornCanonist.java index 8c0fa6561f..9cfb604d03 100644 --- a/Mage.Sets/src/mage/cards/e/EtherswornCanonist.java +++ b/Mage.Sets/src/mage/cards/e/EtherswornCanonist.java @@ -51,7 +51,7 @@ class EtherswornCanonistWatcher extends Watcher { private Set castNonartifactSpell = new HashSet<>(); public EtherswornCanonistWatcher() { - super(EtherswornCanonistWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public EtherswornCanonistWatcher(final EtherswornCanonistWatcher watcher) { @@ -116,7 +116,7 @@ class EtherswornCanonistReplacementEffect extends ContinuousRuleModifyingEffectI public boolean applies(GameEvent event, Ability source, Game game) { Card card = game.getCard(event.getSourceId()); if (card != null && !card.isArtifact()) { - EtherswornCanonistWatcher watcher = (EtherswornCanonistWatcher) game.getState().getWatchers().get(EtherswornCanonistWatcher.class.getSimpleName()); + EtherswornCanonistWatcher watcher = game.getState().getWatcher(EtherswornCanonistWatcher.class); return watcher != null && watcher.castNonArtifactSpell(event.getPlayerId()); } return false; diff --git a/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java b/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java index 542b34c3af..af14f566d5 100644 --- a/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java +++ b/Mage.Sets/src/mage/cards/e/EtherwroughtPage.java @@ -37,12 +37,12 @@ public final class EtherwroughtPage extends CardImpl { // or look at the top card of your library, then you may put that card into your graveyard; Mode mode = new Mode(); - mode.getEffects().add(new EtherwroughtPageEffect()); + mode.addEffect(new EtherwroughtPageEffect()); ability.addMode(mode); // or each opponent loses 1 life Mode mode1 = new Mode(); - mode1.getEffects().add(new LoseLifeOpponentsEffect(1)); + mode1.addEffect(new LoseLifeOpponentsEffect(1)); ability.addMode(mode1); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java index 9ced408831..fbbef138a6 100644 --- a/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java +++ b/Mage.Sets/src/mage/cards/e/EtrataTheSilencer.java @@ -144,14 +144,18 @@ class EtrataTheSilencerEffect extends OneShotEffect { card.addCounters(CounterType.HIT.createInstance(), source, game); } int cardsFound = 0; - for (Card exiledCard : game.getExile().getAllCards(game)) { - if (exiledCard.getCounters(game).getCount(CounterType.HIT) >= 1 && exiledCard.getOwnerId().equals(player.getId())) { - cardsFound++; - } - } + cardsFound = game.getExile().getAllCards(game).stream().filter((exiledCard) -> (exiledCard.getCounters(game).getCount(CounterType.HIT) >= 1 + && exiledCard.getOwnerId().equals(player.getId()))).map((_item) -> 1).reduce(cardsFound, Integer::sum); if (cardsFound > 2) { player.lost(game); } - return new ShuffleIntoLibrarySourceEffect().apply(game, source); + Permanent etrataTheSilencer = game.getPermanent(source.getSourceId()); + if (etrataTheSilencer != null) { + if (etrataTheSilencer.isPhasedIn()) { + return new ShuffleIntoLibrarySourceEffect().apply(game, source); + } + } + controller.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java index 1daf99900d..2422e5e1bf 100644 --- a/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java +++ b/Mage.Sets/src/mage/cards/e/EunuchsIntrigues.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; @@ -19,8 +17,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 & L_J */ public final class EunuchsIntrigues extends CardImpl { @@ -83,7 +82,7 @@ class EunuchsIntriguesEffect extends OneShotEffect { } class EunuchsIntriguesRestrictionEffect extends RestrictionEffect { - + protected UUID targetId; public EunuchsIntriguesRestrictionEffect(UUID targetId) { @@ -103,17 +102,11 @@ class EunuchsIntriguesRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.isControlledBy(source.getFirstTarget())) { - return true; - } - return false; + return permanent.isControlledBy(source.getFirstTarget()); } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (targetId != null && blocker.getId().equals(targetId)) { - return true; - } - return false; + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return targetId != null && blocker.getId().equals(targetId); } } diff --git a/Mage.Sets/src/mage/cards/e/Eureka.java b/Mage.Sets/src/mage/cards/e/Eureka.java index 7ab838fadd..e76f14de6d 100644 --- a/Mage.Sets/src/mage/cards/e/Eureka.java +++ b/Mage.Sets/src/mage/cards/e/Eureka.java @@ -90,7 +90,7 @@ class EurekaEffect extends OneShotEffect { playerList.getNext(); currentPlayer = game.getPlayer(playerList.get()); // if all player since this player didn't put permanent in play finish the process - if (currentPlayer.getId().equals(firstInactivePlayer)) { + if (currentPlayer != null &¤tPlayer.getId().equals(firstInactivePlayer)) { break; } } diff --git a/Mage.Sets/src/mage/cards/e/EverflowingChalice.java b/Mage.Sets/src/mage/cards/e/EverflowingChalice.java index 98755ba197..256f062d98 100644 --- a/Mage.Sets/src/mage/cards/e/EverflowingChalice.java +++ b/Mage.Sets/src/mage/cards/e/EverflowingChalice.java @@ -33,7 +33,7 @@ public final class EverflowingChalice extends CardImpl { // Everflowing Chalice enters the battlefield with a charge counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.CHARGE.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.CHARGE.createInstance(0), MultikickerCount.instance, true), "with a charge counter on it for each time it was kicked")); // {T}: Add {C} for each charge counter on Everflowing Chalice. diff --git a/Mage.Sets/src/mage/cards/e/Everglades.java b/Mage.Sets/src/mage/cards/e/Everglades.java index 13c7fb1c36..8e2b3ceae0 100644 --- a/Mage.Sets/src/mage/cards/e/Everglades.java +++ b/Mage.Sets/src/mage/cards/e/Everglades.java @@ -30,7 +30,7 @@ public final class Everglades extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SWAMP)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Everglades(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigB.java b/Mage.Sets/src/mage/cards/e/EverythingamajigB.java new file mode 100644 index 0000000000..4c87ca972a --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigB.java @@ -0,0 +1,74 @@ + +package mage.cards.e; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.HellbentCondition; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterPermanentCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.filter.predicate.other.ExpansionSetPredicate; + +/** + * + * @author Ketsuban + */ +public final class EverythingamajigB extends CardImpl { + + private static final FilterPermanentCard filter = new FilterPermanentCard("a silver-bordered permanent card"); + + static { + filter.add(Predicates.and( + Predicates.not(new SupertypePredicate(SuperType.BASIC)), // all Un-set basic lands are black bordered cards, and thus illegal choices + Predicates.not(new NamePredicate("Steamflogger Boss")), // printed in Unstable with a black border + Predicates.or(new ExpansionSetPredicate("UGL"), new ExpansionSetPredicate("UNH"), new ExpansionSetPredicate("UST")) + )); + } + + public EverythingamajigB(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + + // Fool's Tome + // 2, T: Draw a card. Activate this ability only if you have no cards in hand. + Ability ability1 = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new GenericManaCost(2), HellbentCondition.instance); + ability1.addCost(new TapSourceCost()); + this.addAbility(ability1); + + // Tower of Eons + // 8, T: You gain 10 life. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(10), new GenericManaCost(8)); + ability2.addCost(new TapSourceCost()); + this.addAbility(ability2); + + // Spatula of the Ages + // 4, T, Sacrifice Everythingamajig: You may put a silver-bordered permanent card from your hand onto the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutCardFromHandOntoBattlefieldEffect(filter), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public EverythingamajigB(final EverythingamajigB card) { + super(card); + } + + @Override + public EverythingamajigB copy() { + return new EverythingamajigB(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigC.java b/Mage.Sets/src/mage/cards/e/EverythingamajigC.java new file mode 100644 index 0000000000..9868a33f90 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigC.java @@ -0,0 +1,179 @@ + +package mage.cards.e; + +import java.util.UUID; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.ActivateIfConditionActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author Ketsuban + */ +public final class EverythingamajigC extends CardImpl { + + public EverythingamajigC(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + + // Mana Screw + // 1: Flip a coin. If you win the flip, add CC to your mana pool. Activate this ability only any time you could cast an instant. + this.addAbility(new ManaScrewAbility()); + + // Disrupting Scepter + // 3, T: Target player discards a card. Activate this ability only during your turn. + Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(1), new GenericManaCost(3), MyTurnCondition.instance); + ability.addTarget(new TargetPlayer()); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // Chimeric Staff + // X: Everythingamajig becomes an X/X Construct artifact creature until end of turn. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ChimericStaffEffect(), new VariableManaCost())); + } + + public EverythingamajigC(final EverythingamajigC card) { + super(card); + } + + @Override + public EverythingamajigC copy() { + return new EverythingamajigC(this); + } +} + +class ManaScrewAbility extends ActivatedManaAbilityImpl { + + public ManaScrewAbility() { + super(Zone.BATTLEFIELD, new ManaScrewEffect(), new GenericManaCost(1)); + this.netMana.add(new Mana(0, 0, 0, 0, 0, 2, 0, 0)); + } + + public ManaScrewAbility(final ManaScrewAbility ability) { + super(ability); + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + Player player = game.getPlayer(playerId); + if (player != null && !player.isInPayManaMode()) { + return super.canActivate(playerId, game); + } + return ActivationStatus.getFalse(); + } + + @Override + public ManaScrewAbility copy() { + return new ManaScrewAbility(this); + } + + @Override + public String getRule() { + return super.getRule() + " Activate this ability only any time you could cast an instant."; + } +} + +class ManaScrewEffect extends BasicManaEffect { + + public ManaScrewEffect() { + super(Mana.ColorlessMana(2)); + this.staticText = "Flip a coin. If you win the flip, add {C}{C}"; + } + + public ManaScrewEffect(final ManaScrewEffect effect) { + super(effect); + this.manaTemplate = effect.manaTemplate.copy(); + } + + @Override + public ManaScrewEffect copy() { + return new ManaScrewEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null && player.flipCoin(source, game, true)) { + player.getManaPool().addMana(getMana(game, source), game, source); + } + return true; + } +} + +class ChimericStaffEffect extends ContinuousEffectImpl { + + public ChimericStaffEffect() { + super(Duration.EndOfTurn, Outcome.BecomeCreature); + setText(); + } + + public ChimericStaffEffect(final ChimericStaffEffect effect) { + super(effect); + } + + @Override + public ChimericStaffEffect copy() { + return new ChimericStaffEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + permanent.addCardType(CardType.CREATURE); + permanent.getSubtype(game).add(SubType.CONSTRUCT); + } + break; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + int xValue = source.getManaCostsToPay().getX(); + if (xValue != 0) { + permanent.getPower().setValue(xValue); + permanent.getToughness().setValue(xValue); + } + } + } + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + private void setText() { + staticText = duration.toString() + " {this} becomes an X/X Construct artifact creature"; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EverythingamajigE.java b/Mage.Sets/src/mage/cards/e/EverythingamajigE.java new file mode 100644 index 0000000000..439a921abd --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EverythingamajigE.java @@ -0,0 +1,148 @@ + +package mage.cards.e; + +import java.util.UUID; + +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author Ketsuban + */ +public final class EverythingamajigE extends CardImpl { + + public EverythingamajigE(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + + // Zuran Orb + // Sacrifice a land: You gain 2 life. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_LAND_SHORT_TEXT)))); + + // Ashnod's Altar + // Sacrifice a creature: Add CC to your mana pool. + SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledCreaturePermanent(StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT)); + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, Mana.ColorlessMana(2), cost)); + + // Urza's Hot Tub + // 2, Discard a card: Search your library for a card that shares a complete word in its name with the name of the discarded card, reveal it, put it into your hand, then shuffle your library. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new UrzasHotTubEffect(), new GenericManaCost(2)); + ability.addCost(new DiscardTargetCost(new TargetCardInHand())); + this.addAbility(ability); + } + + public EverythingamajigE(final EverythingamajigE card) { + super(card); + } + + @Override + public EverythingamajigE copy() { + return new EverythingamajigE(this); + } +} + +class UrzasHotTubEffect extends OneShotEffect { + + public UrzasHotTubEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Search your library for a card that shares a complete word in its name with the discarded card, reveal it, put it into your hand, then shuffle your library"; + } + + public UrzasHotTubEffect(final UrzasHotTubEffect effect) { + super(effect); + } + + @Override + public UrzasHotTubEffect copy() { + return new UrzasHotTubEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Cost cost : source.getCosts()) { + if (cost instanceof DiscardTargetCost) { + DiscardTargetCost discardCost = (DiscardTargetCost) cost; + Card discardedCard = discardCost.getCards().get(0); + if (discardedCard != null) { + FilterCard filter = new FilterCard(); + filter.add(new UrzasHotTubPredicate(discardedCard.getName())); + return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true, true).apply(game, source); + } + } + } + return false; + } +} + +class UrzasHotTubPredicate implements Predicate { + + private final String referenceName; + + public UrzasHotTubPredicate(String referenceName) { + this.referenceName = referenceName; + } + + @Override + public boolean apply(MageObject input, Game game) { + String name = input.getName(); + if (input instanceof SplitCard) { + return sharesWordWithName(((SplitCard)input).getLeftHalfCard().getName()) || sharesWordWithName(((SplitCard)input).getRightHalfCard().getName()); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ + SplitCard card = (SplitCard) ((Spell)input).getCard(); + return sharesWordWithName(card.getLeftHalfCard().getName()) || sharesWordWithName(card.getRightHalfCard().getName()); + } else { + if (name.contains(" // ")) { + String leftName = name.substring(0, name.indexOf(" // ")); + String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); + return sharesWordWithName(leftName) || sharesWordWithName(rightName); + } else { + return sharesWordWithName(name); + } + } + } + + private boolean sharesWordWithName(String str) { + if (referenceName == null || referenceName == "") { + return false; + } + String[] arr = referenceName.split("\\s+"); + for (int i = 0; i < arr.length; i++) { + if (str.contains(arr[i].replaceAll(",", ""))) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/e/EvilTwin.java b/Mage.Sets/src/mage/cards/e/EvilTwin.java index 51a77803e5..cda27f37ff 100644 --- a/Mage.Sets/src/mage/cards/e/EvilTwin.java +++ b/Mage.Sets/src/mage/cards/e/EvilTwin.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -24,10 +22,12 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; import mage.util.functions.ApplyToPermanent; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class EvilTwin extends CardImpl { @@ -90,7 +90,7 @@ class EvilTwinPredicate implements ObjectSourcePlayerPredicate input, Game game) { Permanent permanent = input.getObject(); Permanent twin = game.getPermanent(input.getSourceId()); - return permanent != null && twin != null && !twin.getName().isEmpty() && permanent.getName().equals(twin.getName()); + return CardUtil.haveSameNames(permanent, twin); } @Override diff --git a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java index feefb4dde2..d552e8ff70 100644 --- a/Mage.Sets/src/mage/cards/e/EvolutionCharm.java +++ b/Mage.Sets/src/mage/cards/e/EvolutionCharm.java @@ -31,14 +31,14 @@ public final class EvolutionCharm extends CardImpl { // or return target creature card from your graveyard to your hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addMode(mode); // or target creature gains flying until end of turn. mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/e/EvolutionSage.java b/Mage.Sets/src/mage/cards/e/EvolutionSage.java new file mode 100644 index 0000000000..9bda060621 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EvolutionSage.java @@ -0,0 +1,47 @@ +package mage.cards.e; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EvolutionSage extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledLandPermanent("a land"); + + public EvolutionSage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever a land enters the battlefield under your control, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new ProliferateEffect(), filter, + false, null, true + )); + } + + private EvolutionSage(final EvolutionSage card) { + super(card); + } + + @Override + public EvolutionSage copy() { + return new EvolutionSage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExavaRakdosBloodWitch.java b/Mage.Sets/src/mage/cards/e/ExavaRakdosBloodWitch.java index 86225e14cb..89feff7739 100644 --- a/Mage.Sets/src/mage/cards/e/ExavaRakdosBloodWitch.java +++ b/Mage.Sets/src/mage/cards/e/ExavaRakdosBloodWitch.java @@ -29,7 +29,7 @@ public final class ExavaRakdosBloodWitch extends CardImpl { filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new CounterPredicate(CounterType.P1P1)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } static final String rule = "Each other creature you control with a +1/+1 counter on it has haste"; diff --git a/Mage.Sets/src/mage/cards/e/Excise.java b/Mage.Sets/src/mage/cards/e/Excise.java index 119914cc3b..a232c41085 100644 --- a/Mage.Sets/src/mage/cards/e/Excise.java +++ b/Mage.Sets/src/mage/cards/e/Excise.java @@ -20,7 +20,7 @@ public final class Excise extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Excise(UUID ownerId, CardSetInfo setInfo) { @@ -28,7 +28,7 @@ public final class Excise extends CardImpl { // Excise target nonwhite attacking creature unless its controller pays {X}. this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addEffect(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new ExileTargetEffect(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new ExileTargetEffect(), ManacostVariableValue.instance)); } public Excise(final Excise card) { diff --git a/Mage.Sets/src/mage/cards/e/Excoriate.java b/Mage.Sets/src/mage/cards/e/Excoriate.java index a015078ba5..fc376d02c1 100644 --- a/Mage.Sets/src/mage/cards/e/Excoriate.java +++ b/Mage.Sets/src/mage/cards/e/Excoriate.java @@ -19,7 +19,7 @@ public final class Excoriate extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public Excoriate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/ExecutionersSwing.java b/Mage.Sets/src/mage/cards/e/ExecutionersSwing.java index 40dae7bd51..dbcf5fd062 100644 --- a/Mage.Sets/src/mage/cards/e/ExecutionersSwing.java +++ b/Mage.Sets/src/mage/cards/e/ExecutionersSwing.java @@ -56,7 +56,7 @@ class TargetCreaturePermanentThatDealtDamageThisTurn extends TargetPermanent { @Override public boolean canTarget(UUID id, Ability source, Game game) { - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); if (watcher != null) { if (watcher.damageSources.contains(id)) { return super.canTarget(id, source, game); @@ -73,8 +73,8 @@ class TargetCreaturePermanentThatDealtDamageThisTurn extends TargetPermanent { } int count = 0; MageObject targetSource = game.getObject(sourceId); - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); - if (watcher != null) { + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); + if (watcher != null && targetSource != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { if (!targets.containsKey(permanent.getId()) && watcher.damageSources.contains(permanent.getId())) { if (!notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { @@ -93,7 +93,7 @@ class TargetCreaturePermanentThatDealtDamageThisTurn extends TargetPermanent { public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); if (watcher != null) { for (UUID targetId : availablePossibleTargets) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/e/Exile.java b/Mage.Sets/src/mage/cards/e/Exile.java index 13067c9439..a8d2819198 100644 --- a/Mage.Sets/src/mage/cards/e/Exile.java +++ b/Mage.Sets/src/mage/cards/e/Exile.java @@ -29,7 +29,7 @@ public final class Exile extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonwhite attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(Predicates.not(new ColorPredicate(ObjectColor.WHITE))); } diff --git a/Mage.Sets/src/mage/cards/e/Exogorth.java b/Mage.Sets/src/mage/cards/e/Exogorth.java index 5fcb04443f..aaa46a05d0 100644 --- a/Mage.Sets/src/mage/cards/e/Exogorth.java +++ b/Mage.Sets/src/mage/cards/e/Exogorth.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -12,14 +10,15 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class Exogorth extends CardImpl { @@ -83,7 +82,10 @@ class CanBlockOnlySpaceflightEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.getAbilities().contains(SpaceflightAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/e/ExperimentKraj.java b/Mage.Sets/src/mage/cards/e/ExperimentKraj.java index e45f52bd33..d4c20acec3 100644 --- a/Mage.Sets/src/mage/cards/e/ExperimentKraj.java +++ b/Mage.Sets/src/mage/cards/e/ExperimentKraj.java @@ -60,7 +60,7 @@ class ExperimentKrajEffect extends ContinuousEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new CounterPredicate(CounterType.P1P1)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ExperimentKrajEffect() { diff --git a/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java b/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java index 50dcb6b5a4..e4d6d07d25 100644 --- a/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java +++ b/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java @@ -1,30 +1,25 @@ package mage.cards.e; -import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.DestroySourceEffect; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; -import mage.players.Player; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ExperimentalFrenzy extends CardImpl { @@ -33,27 +28,19 @@ public final class ExperimentalFrenzy extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); // You may look at the top card of your library any time. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new ExperimentalFrenzyTopCardEffect() - )); + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); // You may play the top card of your library. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new PlayTheTopCardEffect() - )); + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect())); // You can't play cards from your hand. - this.addAbility(new SimpleStaticAbility( - Zone.BATTLEFIELD, new ExperimentalFrenzyRestrictionEffect() - )); + this.addAbility(new SimpleStaticAbility(new ExperimentalFrenzyRestrictionEffect())); // {3}{R}: Destroy Experimental Frenzy. - this.addAbility(new SimpleActivatedAbility( - new DestroySourceEffect(), new ManaCostsImpl("{3}{R}") - )); + this.addAbility(new SimpleActivatedAbility(new DestroySourceEffect(), new ManaCostsImpl("{3}{R}"))); } - public ExperimentalFrenzy(final ExperimentalFrenzy card) { + private ExperimentalFrenzy(final ExperimentalFrenzy card) { super(card); } @@ -63,49 +50,14 @@ public final class ExperimentalFrenzy extends CardImpl { } } -class ExperimentalFrenzyTopCardEffect extends ContinuousEffectImpl { - - public ExperimentalFrenzyTopCardEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "You may look at the top card of your library any time."; - } - - public ExperimentalFrenzyTopCardEffect(final ExperimentalFrenzyTopCardEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return true; - } - Card topCard = controller.getLibrary().getFromTop(game); - if (topCard == null) { - return true; - } - MageObject obj = source.getSourceObject(game); - if (obj == null) { - return true; - } - controller.lookAtCards("Top card of " + obj.getIdName() + " controller's library", topCard, game); - return true; - } - - @Override - public ExperimentalFrenzyTopCardEffect copy() { - return new ExperimentalFrenzyTopCardEffect(this); - } -} - class ExperimentalFrenzyRestrictionEffect extends ContinuousRuleModifyingEffectImpl { - public ExperimentalFrenzyRestrictionEffect() { + ExperimentalFrenzyRestrictionEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); this.staticText = "You can't play cards from your hand"; } - public ExperimentalFrenzyRestrictionEffect(final ExperimentalFrenzyRestrictionEffect effect) { + private ExperimentalFrenzyRestrictionEffect(final ExperimentalFrenzyRestrictionEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/e/ExplorersScope.java b/Mage.Sets/src/mage/cards/e/ExplorersScope.java index b1df107409..fb211ca098 100644 --- a/Mage.Sets/src/mage/cards/e/ExplorersScope.java +++ b/Mage.Sets/src/mage/cards/e/ExplorersScope.java @@ -69,8 +69,7 @@ class ExplorersScopeEffect extends OneShotEffect { Card card = controller.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards(sourceObject.getIdName(), cards, game); if (card.isLand()) { String message = "Put " + card.getLogName() + " onto the battlefield tapped?"; diff --git a/Mage.Sets/src/mage/cards/e/ExposeToDaylight.java b/Mage.Sets/src/mage/cards/e/ExposeToDaylight.java new file mode 100644 index 0000000000..7de10992de --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExposeToDaylight.java @@ -0,0 +1,35 @@ +package mage.cards.e; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ExposeToDaylight extends CardImpl { + + public ExposeToDaylight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Destroy target artifact or enchantment. Scry 1. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + } + + private ExposeToDaylight(final ExposeToDaylight card) { + super(card); + } + + @Override + public ExposeToDaylight copy() { + return new ExposeToDaylight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/Expropriate.java b/Mage.Sets/src/mage/cards/e/Expropriate.java index c61aefe5f7..81761c64af 100644 --- a/Mage.Sets/src/mage/cards/e/Expropriate.java +++ b/Mage.Sets/src/mage/cards/e/Expropriate.java @@ -1,5 +1,3 @@ - - package mage.cards.e; import java.util.ArrayList; @@ -69,7 +67,9 @@ class ExpropriateDilemmaEffect extends CouncilsDilemmaVoteEffect { Player controller = game.getPlayer(source.getControllerId()); //If not controller, exit out here and do not vote. - if (controller == null) return false; + if (controller == null) { + return false; + } this.vote("time", "money", controller, game, source); @@ -92,7 +92,6 @@ class ExpropriateDilemmaEffect extends CouncilsDilemmaVoteEffect { } else { game.informPlayers(controller.getName() + " will take " + timeCount + " extra turns"); } - do { game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false)); timeCount--; @@ -109,26 +108,33 @@ class ExpropriateDilemmaEffect extends CouncilsDilemmaVoteEffect { Target target = new TargetPermanent(filter); target.setNotTarget(true); - if (controller.choose(Outcome.GainControl, target, source.getSourceId(), game)) { + if (controller != null + && controller != game.getPlayer(playerId) + && controller.choose(Outcome.GainControl, target, source.getSourceId(), game)) { Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); - if (targetPermanent != null) chosenCards.add(targetPermanent); + if (targetPermanent != null) { + chosenCards.add(targetPermanent); + } } } - - for (Permanent permanent : chosenCards) { - ContinuousEffect effect = new ExpropriateControlEffect(controller.getId()); - effect.setTargetPointer(new FixedTarget(permanent.getId())); - game.addEffect(effect, source); - game.informPlayers(controller.getName() + " gained control of " + permanent.getName() + " owned by " + game.getPlayer(permanent.getOwnerId()).getName()); + if (controller != null) { + for (Permanent permanent : chosenCards) { + ContinuousEffect effect = new ExpropriateControlEffect(controller.getId()); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + game.informPlayers(controller.getName() + " gained control of " + permanent.getName() + " owned by " + game.getPlayer(permanent.getOwnerId()).getName()); + } } } @Override protected void vote(String choiceOne, String choiceTwo, Player controller, Game game, Ability source) { - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + for (UUID playerId : game.getState().getPlayerList(controller.getId())) { Player player = game.getPlayer(playerId); - if (player != null) { + if (player != null + && player.canRespond() + && player.isInGame()) { if (player.chooseUse(Outcome.Vote, "Choose " + choiceOne + '?', source, game)) { voteOneCount++; game.informPlayers(player.getName() + " has voted for " + choiceOne); @@ -150,7 +156,7 @@ class ExpropriateDilemmaEffect extends CouncilsDilemmaVoteEffect { class ExpropriateControlEffect extends ContinuousEffectImpl { - private UUID controllerId; + private final UUID controllerId; public ExpropriateControlEffect(UUID controllerId) { super(Duration.EndOfGame, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); @@ -170,7 +176,8 @@ class ExpropriateControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); - return permanent != null && controllerId != null && - permanent.changeControllerId(controllerId, game); + return permanent != null + && controllerId != null + && permanent.changeControllerId(controllerId, game); } } diff --git a/Mage.Sets/src/mage/cards/e/Exsanguinate.java b/Mage.Sets/src/mage/cards/e/Exsanguinate.java index 0f461cde29..14b7c2a3e1 100644 --- a/Mage.Sets/src/mage/cards/e/Exsanguinate.java +++ b/Mage.Sets/src/mage/cards/e/Exsanguinate.java @@ -1,5 +1,3 @@ - - package mage.cards.e; import java.util.UUID; @@ -17,13 +15,13 @@ import mage.game.Game; */ public final class Exsanguinate extends CardImpl { - public Exsanguinate (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}{B}"); + public Exsanguinate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); this.getSpellAbility().addEffect(new ExsanguinateEffect()); } - public Exsanguinate (final Exsanguinate card) { + public Exsanguinate(final Exsanguinate card) { super(card); } @@ -35,8 +33,9 @@ public final class Exsanguinate extends CardImpl { } class ExsanguinateEffect extends OneShotEffect { + public ExsanguinateEffect() { - super(Outcome.Damage); + super(Outcome.GainLife); staticText = "Each opponent loses X life. You gain life equal to the life lost this way"; } @@ -46,13 +45,14 @@ class ExsanguinateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int loseLife = 0; - int damage = source.getManaCostsToPay().getX(); + int totalLostLife = 0; + int loseLife = source.getManaCostsToPay().getX(); for (UUID opponentId : game.getOpponents(source.getControllerId())) { - loseLife += game.getPlayer(opponentId).loseLife(damage, game, false); + totalLostLife += game.getPlayer(opponentId).loseLife(loseLife, game, false); + } + if (totalLostLife > 0) { + game.getPlayer(source.getControllerId()).gainLife(totalLostLife, game, source); } - if (loseLife > 0) - game.getPlayer(source.getControllerId()).gainLife(loseLife, game, source); return true; } @@ -61,4 +61,4 @@ class ExsanguinateEffect extends OneShotEffect { return new ExsanguinateEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/e/Extinction.java b/Mage.Sets/src/mage/cards/e/Extinction.java index 5bb472dacc..e77c192cb2 100644 --- a/Mage.Sets/src/mage/cards/e/Extinction.java +++ b/Mage.Sets/src/mage/cards/e/Extinction.java @@ -56,15 +56,18 @@ class ExtinctionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (player != null && player.choose(outcome, typeChoice, game)) { - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); - filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { - creature.destroy(source.getSourceId(), game, true); + if (player != null && sourceObject != null) { + Choice typeChoice = new ChoiceCreatureType(sourceObject); + + if (player.choose(outcome, typeChoice, game)) { + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); + filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { + creature.destroy(source.getSourceId(), game, true); + } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/e/Extirpate.java b/Mage.Sets/src/mage/cards/e/Extirpate.java index 782e418adb..1c74ffd1df 100644 --- a/Mage.Sets/src/mage/cards/e/Extirpate.java +++ b/Mage.Sets/src/mage/cards/e/Extirpate.java @@ -116,7 +116,7 @@ class ExtirpateEffect extends OneShotEffect { // search cards in Library filterNamedCard.setMessage("card named " + chosenCard.getName() + " in the library of " + owner.getName()); TargetCardInLibrary targetCardInLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCard); - if (controller.searchLibrary(targetCardInLibrary, game, owner.getId())) { + if (controller.searchLibrary(targetCardInLibrary, source, game, owner.getId())) { List targets = targetCardInLibrary.getTargets(); for (UUID targetId : targets) { Card targetCard = owner.getLibrary().getCard(targetId, game); diff --git a/Mage.Sets/src/mage/cards/e/Extract.java b/Mage.Sets/src/mage/cards/e/Extract.java index 172eddb25e..cb11605321 100644 --- a/Mage.Sets/src/mage/cards/e/Extract.java +++ b/Mage.Sets/src/mage/cards/e/Extract.java @@ -66,7 +66,7 @@ class ExtractEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && targetPlayer != null) { TargetCardInLibrary target = new TargetCardInLibrary(1, 1, filter); - if (player.searchLibrary(target, game, targetPlayer.getId())) { + if (player.searchLibrary(target, source, game, targetPlayer.getId())) { Card card = targetPlayer.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { player.moveCardToExileWithInfo(card, null, null, source.getSourceId(), game, Zone.LIBRARY, true); diff --git a/Mage.Sets/src/mage/cards/e/ExtractorDemon.java b/Mage.Sets/src/mage/cards/e/ExtractorDemon.java index 651e5e955b..5ae17fa5ac 100644 --- a/Mage.Sets/src/mage/cards/e/ExtractorDemon.java +++ b/Mage.Sets/src/mage/cards/e/ExtractorDemon.java @@ -24,10 +24,10 @@ import mage.target.TargetPlayer; */ public final class ExtractorDemon extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ExtractorDemon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java b/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java index f3568f27ac..39767e1cae 100644 --- a/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java +++ b/Mage.Sets/src/mage/cards/e/ExtraplanarLens.java @@ -138,7 +138,7 @@ class ExtraplanarLensTriggeredAbility extends TriggeredManaAbility { @Override public String getRule() { - return new StringBuilder("Whenever a land with the same name as the exiled card is tapped for mana, ").append(super.getRule()).toString(); + return "Whenever a land with the same name as the exiled card is tapped for mana, " + super.getRule(); } @Override diff --git a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java index 1322d056ff..7f2f2564cd 100644 --- a/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java +++ b/Mage.Sets/src/mage/cards/e/ExtricatorOfSin.java @@ -1,7 +1,7 @@ - package mage.cards.e; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,6 +11,7 @@ import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -24,7 +25,6 @@ import mage.game.permanent.token.EldraziHorrorToken; import mage.target.common.TargetControlledPermanent; /** - * * @author LevelX2 */ public final class ExtricatorOfSin extends CardImpl { @@ -32,11 +32,11 @@ public final class ExtricatorOfSin extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ExtricatorOfSin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(0); @@ -55,7 +55,8 @@ public final class ExtricatorOfSin extends CardImpl { new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new TransformSourceEffect(true), TargetController.YOU, false), DeliriumCondition.instance, "Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, " - + " transform {this}.")); + + " transform {this}.") + .addHint(DeliriumHint.instance)); } public ExtricatorOfSin(final ExtricatorOfSin card) { diff --git a/Mage.Sets/src/mage/cards/e/EyeOfDoom.java b/Mage.Sets/src/mage/cards/e/EyeOfDoom.java index 5c872651e6..da09bdeea4 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfDoom.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfDoom.java @@ -86,11 +86,11 @@ class EyeOfDoomEffect extends OneShotEffect { Player player = game.getPlayer(game.getActivePlayerId()); do { target.clearChosen(); - if (player.chooseTarget(outcome, target, source, game)) { + if (player != null && player.chooseTarget(outcome, target, source, game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { permanents.add(permanent); - game.informPlayers((new StringBuilder(player.getLogName()).append(" chooses ").append(permanent.getName()).toString())); + game.informPlayers(player.getLogName() + " chooses " + permanent.getName()); } } player = playerList.getNext(game); diff --git a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java index 2860e35ddf..563fb12b5c 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfTheStorm.java @@ -1,7 +1,5 @@ - package mage.cards.e; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -23,8 +21,9 @@ import mage.target.TargetCard; import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author spjspj */ public final class EyeOfTheStorm extends CardImpl { @@ -111,7 +110,7 @@ class EyeOfTheStormEffect1 extends OneShotEffect { Card card = spell.getCard(); if (spellController == null || card == null - || !StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY.match(spell, game)) { + || !StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY.match(spell, game)) { return false; } if (!noLongerOnStack) {// the spell is still on the stack, so exile it @@ -125,11 +124,9 @@ class EyeOfTheStormEffect1 extends OneShotEffect { && !eyeOfTheStorm.getImprinted().isEmpty()) { CardsImpl copiedCards = new CardsImpl(); for (UUID uuid : eyeOfTheStorm.getImprinted()) { - card = game.getCard(uuid); - // Check if owner of card is still in game - if (card != null - && game.getPlayer(card.getOwnerId()) != null) { + card = game.getCard(uuid); + if (card != null && game.getPlayer(card.getOwnerId()) != null) { if (card.isSplitCard()) { copiedCards.add(((SplitCard) card).getLeftHalfCard()); copiedCards.add(((SplitCard) card).getRightHalfCard()); diff --git a/Mage.Sets/src/mage/cards/e/EyeOfUgin.java b/Mage.Sets/src/mage/cards/e/EyeOfUgin.java index 67223f4db3..0fef45898f 100644 --- a/Mage.Sets/src/mage/cards/e/EyeOfUgin.java +++ b/Mage.Sets/src/mage/cards/e/EyeOfUgin.java @@ -31,8 +31,8 @@ public final class EyeOfUgin extends CardImpl { private static final FilterCard filterSpells = new FilterCard("Colorless Eldrazi spells"); static { - filter.add(new ColorlessPredicate()); - filterSpells.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); + filterSpells.add(ColorlessPredicate.instance); filterSpells.add(new SubtypePredicate(SubType.ELDRAZI)); } diff --git a/Mage.Sets/src/mage/cards/e/EyesEverywhere.java b/Mage.Sets/src/mage/cards/e/EyesEverywhere.java new file mode 100644 index 0000000000..701e6ef560 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/EyesEverywhere.java @@ -0,0 +1,53 @@ +package mage.cards.e; + +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.target.common.TargetNonlandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class EyesEverywhere extends CardImpl { + + public EyesEverywhere(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // At the beginning of your upkeep, scry 1. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new ScryEffect(1), + TargetController.YOU, false + )); + + // {5}{U}: Exchange control of Eyes Everywhere and target nonland permanent. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, + new ExchangeControlTargetEffect( + Duration.EndOfGame, "Exchange control of {this} " + + "and target nonland permanent", true + ), new ManaCostsImpl("{5}{U}") + ); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + } + + private EyesEverywhere(final EyesEverywhere card) { + super(card); + } + + @Override + public EyesEverywhere copy() { + return new EyesEverywhere(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java index 6ade1dc5b7..ac296ce2dd 100644 --- a/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java +++ b/Mage.Sets/src/mage/cards/e/EzuriClawOfProgress.java @@ -31,7 +31,7 @@ public final class EzuriClawOfProgress extends CardImpl { static { filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } String rule = "Whenever a creature with power 2 or less enters the battlefield under your control, you get an experience counter."; diff --git a/Mage.Sets/src/mage/cards/e/EzurisBrigade.java b/Mage.Sets/src/mage/cards/e/EzurisBrigade.java index 1602de0fe6..28bd5cf374 100644 --- a/Mage.Sets/src/mage/cards/e/EzurisBrigade.java +++ b/Mage.Sets/src/mage/cards/e/EzurisBrigade.java @@ -24,7 +24,7 @@ import mage.constants.Zone; * @author Loki */ public final class EzurisBrigade extends CardImpl { - private static final String text = "Metalcraft — As long as you control three or more artifacts, Ezuri's Brigade gets +4/+4 and has trample"; + private static final String rule = "Metalcraft — As long as you control three or more artifacts, Ezuri's Brigade gets +4/+4 and has trample"; public EzurisBrigade (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); @@ -34,7 +34,7 @@ public final class EzurisBrigade extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(4); ContinuousEffect boostSource = new BoostSourceEffect(4, 4, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, text); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, rule); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield), MetalcraftCondition.instance, "")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FacelessButcher.java b/Mage.Sets/src/mage/cards/f/FacelessButcher.java index f44aec4ce8..42bc86ffe6 100644 --- a/Mage.Sets/src/mage/cards/f/FacelessButcher.java +++ b/Mage.Sets/src/mage/cards/f/FacelessButcher.java @@ -30,7 +30,7 @@ public final class FacelessButcher extends CardImpl { static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/f/FacelessDevourer.java b/Mage.Sets/src/mage/cards/f/FacelessDevourer.java index aa573b1fa1..4148034851 100644 --- a/Mage.Sets/src/mage/cards/f/FacelessDevourer.java +++ b/Mage.Sets/src/mage/cards/f/FacelessDevourer.java @@ -30,7 +30,7 @@ public final class FacelessDevourer extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new AbilityPredicate(ShadowAbility.class)); } diff --git a/Mage.Sets/src/mage/cards/f/FactOrFiction.java b/Mage.Sets/src/mage/cards/f/FactOrFiction.java index 03c5806719..cfb2a3158c 100644 --- a/Mage.Sets/src/mage/cards/f/FactOrFiction.java +++ b/Mage.Sets/src/mage/cards/f/FactOrFiction.java @@ -65,8 +65,7 @@ class FactOrFictionEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.revealCards(sourceObject.getName(), cards, game); Set opponents = game.getOpponents(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java index db39e5549a..f02fa39ba4 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieArtisans.java +++ b/Mage.Sets/src/mage/cards/f/FaerieArtisans.java @@ -32,7 +32,7 @@ public final class FaerieArtisans extends CardImpl { private static final FilterCreaturePermanent filterNontoken = new FilterCreaturePermanent("nontoken creature"); static { - filterNontoken.add(Predicates.not(new TokenPredicate())); + filterNontoken.add(Predicates.not(TokenPredicate.instance)); filterNontoken.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/f/FaerieDuelist.java b/Mage.Sets/src/mage/cards/f/FaerieDuelist.java new file mode 100644 index 0000000000..2529781454 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FaerieDuelist.java @@ -0,0 +1,50 @@ +package mage.cards.f; + +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.abilities.keyword.FlyingAbility; +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 FaerieDuelist extends CardImpl { + + public FaerieDuelist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Faerie Duelist enters the battlefield, 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 FaerieDuelist(final FaerieDuelist card) { + super(card); + } + + @Override + public FaerieDuelist copy() { + return new FaerieDuelist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FaerieImpostor.java b/Mage.Sets/src/mage/cards/f/FaerieImpostor.java index 1a4b526b13..f744e08013 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieImpostor.java +++ b/Mage.Sets/src/mage/cards/f/FaerieImpostor.java @@ -58,7 +58,7 @@ class FaerieImpostorEffect extends OneShotEffect { private static final String effectText = "sacrifice it unless you return another creature you control to its owner's hand"; static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } FaerieImpostorEffect() { diff --git a/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java b/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java index bedb618045..aa826d306a 100644 --- a/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java +++ b/Mage.Sets/src/mage/cards/f/FaerieMiscreant.java @@ -30,7 +30,7 @@ public final class FaerieMiscreant extends CardImpl { static { filter.add(new NamePredicate("Faerie Miscreant")); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/f/FailureComply.java b/Mage.Sets/src/mage/cards/f/FailureComply.java index 1dc66399d6..e7cdbbc5fb 100644 --- a/Mage.Sets/src/mage/cards/f/FailureComply.java +++ b/Mage.Sets/src/mage/cards/f/FailureComply.java @@ -37,7 +37,7 @@ public final class FailureComply extends SplitCard { // to // Comply // Choose a card name. Until your next turn, your opponents can't cast spells with the chosen name - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); Effect effect = new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL); effect.setText("Choose a card name"); getRightHalfCard().getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java index 8a4959443b..1ae545be10 100644 --- a/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java +++ b/Mage.Sets/src/mage/cards/f/FairgroundsTrumpeter.java @@ -57,7 +57,7 @@ enum FairgroundsTrumpeterCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - FairgroundsTrumpeterWatcher watcher = (FairgroundsTrumpeterWatcher) game.getState().getWatchers().get(FairgroundsTrumpeterWatcher.class.getSimpleName()); + FairgroundsTrumpeterWatcher watcher = game.getState().getWatcher(FairgroundsTrumpeterWatcher.class); return watcher != null && watcher.p1p1AddedToPermanent(source.getControllerId()); } @@ -73,7 +73,7 @@ class FairgroundsTrumpeterWatcher extends Watcher { private final Set players = new HashSet<>(); public FairgroundsTrumpeterWatcher() { - super(FairgroundsTrumpeterWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public FairgroundsTrumpeterWatcher(final FairgroundsTrumpeterWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/f/FairgroundsWarden.java b/Mage.Sets/src/mage/cards/f/FairgroundsWarden.java index ad31ca0c71..03ab1b1fd9 100644 --- a/Mage.Sets/src/mage/cards/f/FairgroundsWarden.java +++ b/Mage.Sets/src/mage/cards/f/FairgroundsWarden.java @@ -28,7 +28,7 @@ import mage.util.CardUtil; */ public final class FairgroundsWarden extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/f/FaithsReward.java b/Mage.Sets/src/mage/cards/f/FaithsReward.java index cf44963565..17121aa83c 100644 --- a/Mage.Sets/src/mage/cards/f/FaithsReward.java +++ b/Mage.Sets/src/mage/cards/f/FaithsReward.java @@ -57,9 +57,9 @@ class FaithsRewardEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FaithsRewardWatcher watcher = (FaithsRewardWatcher) game.getState().getWatchers().get(FaithsRewardWatcher.class.getSimpleName()); + FaithsRewardWatcher watcher = game.getState().getWatcher(FaithsRewardWatcher.class); if (watcher != null) { - for (UUID id : watcher.cards) { + for (UUID id : watcher.getCards()) { Card c = game.getCard(id); if (c != null && c.isOwnedBy(source.getControllerId()) && game.getState().getZone(id) == Zone.GRAVEYARD) { c.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); @@ -77,10 +77,10 @@ class FaithsRewardEffect extends OneShotEffect { } class FaithsRewardWatcher extends Watcher { - List cards = new ArrayList<>(); + private List cards = new ArrayList<>(); public FaithsRewardWatcher() { - super(FaithsRewardWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public FaithsRewardWatcher(final FaithsRewardWatcher watcher) { @@ -95,6 +95,10 @@ class FaithsRewardWatcher extends Watcher { } } + public List getCards(){ + return cards; + } + @Override public FaithsRewardWatcher copy() { return new FaithsRewardWatcher(this); diff --git a/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java b/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java index d68b94cc4d..3491dc5262 100644 --- a/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java +++ b/Mage.Sets/src/mage/cards/f/FalkenrathNoble.java @@ -72,7 +72,7 @@ class FalkenrathNobleTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null) { if (permanent.getId().equals(this.getSourceId())) { diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheThran.java b/Mage.Sets/src/mage/cards/f/FallOfTheThran.java index 351672ca51..bae5195fc3 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheThran.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheThran.java @@ -77,13 +77,15 @@ class FallOfTheThranReturnEffect extends OneShotEffect { if (controller != null) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(2, 2, StaticFilters.FILTER_CARD_LAND); - target.setNotTarget(true); - target.setTargetController(playerId); - if (target.canChoose(source.getSourceId(), playerId, game)) { - player.choose(outcome, target, source.getSourceId(), game); - if (target.getTargets().size() == 2) { - toBattlefield.put(playerId, new CardsImpl(target.getTargets()).getCards(game)); + if(player != null) { + TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(2, 2, StaticFilters.FILTER_CARD_LAND); + target.setNotTarget(true); + target.setTargetController(playerId); + if (target.canChoose(source.getSourceId(), playerId, game)) { + player.choose(outcome, target, source.getSourceId(), game); + if (target.getTargets().size() == 2) { + toBattlefield.put(playerId, new CardsImpl(target.getTargets()).getCards(game)); + } } } } diff --git a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java index 71a44fc473..1b45b0e00f 100644 --- a/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java +++ b/Mage.Sets/src/mage/cards/f/FallOfTheTitans.java @@ -21,7 +21,7 @@ public final class FallOfTheTitans extends CardImpl { // Fall of the Titans deals X damage to each of up to two target creatures and/or players. this.getSpellAbility().addTarget(new TargetAnyTarget(0, 2)); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); // Surge {X}{R} addAbility(new SurgeAbility(this, "{X}{R}")); diff --git a/Mage.Sets/src/mage/cards/f/FallingTimber.java b/Mage.Sets/src/mage/cards/f/FallingTimber.java index 90a39c7614..492c7e6f34 100644 --- a/Mage.Sets/src/mage/cards/f/FallingTimber.java +++ b/Mage.Sets/src/mage/cards/f/FallingTimber.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -16,38 +15,30 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * * @author LoneFox - + * */ public final class FallingTimber extends CardImpl { - private final UUID originalId; - public FallingTimber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // Kicker-Sacrifice a land. this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent("a land"), true)))); + // Prevent all combat damage target creature would deal this turn. If Falling Timber was kicked, prevent all combat damage another target creature would deal this turn. Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true); effect.setText("Prevent all combat damage target creature would deal this turn. if this spell was kicked, prevent all combat damage another target creature would deal this turn."); this.getSpellAbility().addEffect(effect); - originalId = this.getSpellAbility().getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - ability.addTarget(new TargetCreaturePermanent(KickedCondition.instance.apply(game, ability) ? 2 : 1)); - } + this.getSpellAbility().setTargetAdjuster(FallingTimberAdjuster.instance); } public FallingTimber(final FallingTimber card) { super(card); - this.originalId = card.originalId; } @Override @@ -55,3 +46,13 @@ public final class FallingTimber extends CardImpl { return new FallingTimber(this); } } + +enum FallingTimberAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(KickedCondition.instance.apply(game, ability) ? 2 : 1)); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FalseOrders.java b/Mage.Sets/src/mage/cards/f/FalseOrders.java index f4c8066db6..7a3279720b 100644 --- a/Mage.Sets/src/mage/cards/f/FalseOrders.java +++ b/Mage.Sets/src/mage/cards/f/FalseOrders.java @@ -104,7 +104,7 @@ class FalseOrdersUnblockEffect extends OneShotEffect { effect.apply(game, source); // Make blocked creatures unblocked - BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName()); + BlockedByOnlyOneCreatureThisCombatWatcher watcher = game.getState().getWatcher(BlockedByOnlyOneCreatureThisCombatWatcher.class); if (watcher != null) { Set combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId()); if (combatGroups != null) { diff --git a/Mage.Sets/src/mage/cards/f/FalsePeace.java b/Mage.Sets/src/mage/cards/f/FalsePeace.java index 026dae7c19..55bfe14023 100644 --- a/Mage.Sets/src/mage/cards/f/FalsePeace.java +++ b/Mage.Sets/src/mage/cards/f/FalsePeace.java @@ -1,11 +1,11 @@ - package mage.cards.f; import java.util.UUID; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.target.TargetPlayer; /** @@ -13,19 +13,19 @@ import mage.target.TargetPlayer; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class FalsePeace extends CardImpl { - + public FalsePeace(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}"); // Target player skips all combat phases of their next turn. - this.getSpellAbility().addEffect(new SkipNextCombatEffect()); + this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.UntilYourNextTurn).setText("Target player skips all combat phases of their next turn.")); this.getSpellAbility().addTarget(new TargetPlayer()); } - + public FalsePeace(final FalsePeace card) { super(card); } - + @Override public FalsePeace copy() { return new FalsePeace(this); diff --git a/Mage.Sets/src/mage/cards/f/FangOfThePack.java b/Mage.Sets/src/mage/cards/f/FangOfThePack.java index 71cda8c6bd..353b13f54e 100644 --- a/Mage.Sets/src/mage/cards/f/FangOfThePack.java +++ b/Mage.Sets/src/mage/cards/f/FangOfThePack.java @@ -26,7 +26,7 @@ public final class FangOfThePack extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FangOfThePack(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FanningTheFlames.java b/Mage.Sets/src/mage/cards/f/FanningTheFlames.java index 4fe03dc2da..e7d224f7e5 100644 --- a/Mage.Sets/src/mage/cards/f/FanningTheFlames.java +++ b/Mage.Sets/src/mage/cards/f/FanningTheFlames.java @@ -23,7 +23,7 @@ public final class FanningTheFlames extends CardImpl { this.addAbility(new BuybackAbility("{3}")); // Fanning the Flames deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/f/FarmMarket.java b/Mage.Sets/src/mage/cards/f/FarmMarket.java index 3b280cd784..53c665b919 100644 --- a/Mage.Sets/src/mage/cards/f/FarmMarket.java +++ b/Mage.Sets/src/mage/cards/f/FarmMarket.java @@ -28,7 +28,7 @@ public final class FarmMarket extends SplitCard { // Market {2}{U} // Sorcery // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Draw two cards, then discard two cards getRightHalfCard().getSpellAbility().addEffect(new DrawDiscardControllerEffect(2, 2)); diff --git a/Mage.Sets/src/mage/cards/f/Fascination.java b/Mage.Sets/src/mage/cards/f/Fascination.java index c24543f8e9..e3aa3f389d 100644 --- a/Mage.Sets/src/mage/cards/f/Fascination.java +++ b/Mage.Sets/src/mage/cards/f/Fascination.java @@ -22,11 +22,11 @@ public final class Fascination extends CardImpl { // Choose one - // * Each player draws X cards. - this.getSpellAbility().addEffect(new DrawCardAllEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardAllEffect(ManacostVariableValue.instance)); // * Each player puts the top X cards of their library into their graveyard. Mode mode = new Mode(); - mode.getEffects().add(new PutTopCardOfLibraryIntoGraveEachPlayerEffect(new ManacostVariableValue(), TargetController.ANY)); + mode.addEffect(new PutTopCardOfLibraryIntoGraveEachPlayerEffect(ManacostVariableValue.instance, TargetController.ANY)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FatalFrenzy.java b/Mage.Sets/src/mage/cards/f/FatalFrenzy.java index a3e9ebd5d3..6b07415820 100644 --- a/Mage.Sets/src/mage/cards/f/FatalFrenzy.java +++ b/Mage.Sets/src/mage/cards/f/FatalFrenzy.java @@ -35,7 +35,7 @@ public final class FatalFrenzy extends CardImpl { this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn) .setText("Until end of turn, target creature you control gains trample") ); - this.getSpellAbility().addEffect(new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true) + this.getSpellAbility().addEffect(new BoostTargetEffect(TargetPermanentPowerCount.instance, new StaticValue(0), Duration.EndOfTurn, true) .setText("and gets +X/+0, where X is its power.") ); this.getSpellAbility().addEffect(new FatalFrenzyEffect()); diff --git a/Mage.Sets/src/mage/cards/f/FatalLore.java b/Mage.Sets/src/mage/cards/f/FatalLore.java new file mode 100644 index 0000000000..c4a641dedc --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FatalLore.java @@ -0,0 +1,91 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.DrawCardTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class FatalLore extends CardImpl { + + public FatalLore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + // An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated. + this.getSpellAbility().addEffect(new FatalLoreEffect()); + this.getSpellAbility().addTarget(new TargetOpponent(true)); + + } + + private FatalLore(final FatalLore card) { + super(card); + } + + @Override + public FatalLore copy() { + return new FatalLore(this); + } +} + +class FatalLoreEffect extends OneShotEffect { + + public FatalLoreEffect() { + super(Outcome.Neutral); + staticText = "An opponent chooses one - You draw three cards; or you destroy up to two target creatures that opponent controls and that player draws up to three cards. Those creatures can't be regenerated"; + } + + public FatalLoreEffect(final FatalLoreEffect effect) { + super(effect); + } + + @Override + public FatalLoreEffect copy() { + return new FatalLoreEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller != null + && chosenOpponent != null) { + if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller draws three cards. If no, the controller gets to destroy up to two target creatures that you control and you get to draw up to 3 cards. Those creatures can't be regenerated.", source, game)) { + controller.drawCards(3, game); + } else { + FilterCreaturePermanent filter = new FilterCreaturePermanent("chosen opponent's creature"); + filter.add(new ControllerIdPredicate(chosenOpponent.getId())); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 2, filter, false); + if (target.canChoose(controller.getId(), game) + && controller.choose(Outcome.DestroyPermanent, target, source.getSourceId(), game)) { + for (UUID targetId : target.getTargets()) { + Effect destroyCreature = new DestroyTargetEffect(true); + destroyCreature.setTargetPointer(new FixedTarget(targetId)); + destroyCreature.apply(game, source); + } + Effect opponentDrawsCards = new DrawCardTargetEffect(new StaticValue(3), false, true); + opponentDrawsCards.setTargetPointer(new FixedTarget(chosenOpponent.getId())); + opponentDrawsCards.apply(game, source); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FatefulShowdown.java b/Mage.Sets/src/mage/cards/f/FatefulShowdown.java index 02b4db6762..11f60f0501 100644 --- a/Mage.Sets/src/mage/cards/f/FatefulShowdown.java +++ b/Mage.Sets/src/mage/cards/f/FatefulShowdown.java @@ -21,7 +21,7 @@ public final class FatefulShowdown extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}"); // Fateful Showdown deals damage to any target equal to the number of cards in your hand. Discard all the cards in your hand, then draw that many cards. - Effect effect = new DamageTargetEffect(new CardsInControllerHandCount()); + Effect effect = new DamageTargetEffect(CardsInControllerHandCount.instance); effect.setText("{this} deals damage to any target equal to the number of cards in your hand"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/f/Fatestitcher.java b/Mage.Sets/src/mage/cards/f/Fatestitcher.java index dc642fbbbf..aec4bcc54a 100644 --- a/Mage.Sets/src/mage/cards/f/Fatestitcher.java +++ b/Mage.Sets/src/mage/cards/f/Fatestitcher.java @@ -26,7 +26,7 @@ public final class Fatestitcher extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static{ - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Fatestitcher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FathomFleetBoarder.java b/Mage.Sets/src/mage/cards/f/FathomFleetBoarder.java index 90c40439fa..c697a74221 100644 --- a/Mage.Sets/src/mage/cards/f/FathomFleetBoarder.java +++ b/Mage.Sets/src/mage/cards/f/FathomFleetBoarder.java @@ -26,7 +26,7 @@ public final class FathomFleetBoarder extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PIRATE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FathomFleetBoarder(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java b/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java index d4f6bf4026..ba624da793 100644 --- a/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java +++ b/Mage.Sets/src/mage/cards/f/FathomFleetCaptain.java @@ -31,8 +31,8 @@ public final class FathomFleetCaptain extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PIRATE)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public FathomFleetCaptain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/Fatigue.java b/Mage.Sets/src/mage/cards/f/Fatigue.java new file mode 100644 index 0000000000..8f3ae9784b --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Fatigue.java @@ -0,0 +1,36 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.effects.common.SkipNextDrawStepTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class Fatigue extends CardImpl { + + private static final String rule = "Target player skips his or her next draw step."; + + public Fatigue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + + + // Target player skips his or her next draw step. + this.getSpellAbility().addEffect(new SkipNextDrawStepTargetEffect().setText(rule)); + this.getSpellAbility().addTarget(new TargetPlayer()); + + } + + public Fatigue(final Fatigue card) { + super(card); + } + + @Override + public Fatigue copy() { + return new Fatigue(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FblthpTheLost.java b/Mage.Sets/src/mage/cards/f/FblthpTheLost.java new file mode 100644 index 0000000000..3de4f8abcd --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FblthpTheLost.java @@ -0,0 +1,175 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ShuffleIntoLibrarySourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FblthpTheLost extends CardImpl { + + public FblthpTheLost(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HOMUNCULUS); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Fblthp, the Lost enters the battlefield, draw a card. If it entered from your library or was cast from your library, draw two cards instead. + this.addAbility(new FblthpTheLostTriggeredAbility()); + + // When Fblthp becomes the target of a spell, shuffle Fblthp into its owner's library. + this.addAbility(new FblthpTheLostTargetedTriggeredAbility()); + } + + private FblthpTheLost(final FblthpTheLost card) { + super(card); + } + + @Override + public FblthpTheLost copy() { + return new FblthpTheLost(this); + } +} + +class FblthpTheLostTriggeredAbility extends EntersBattlefieldTriggeredAbility { + FblthpTheLostTriggeredAbility() { + super(new DrawCardSourceControllerEffect(1)); + this.addWatcher(new FblthpTheLostWatcher()); + } + + private FblthpTheLostTriggeredAbility(final FblthpTheLostTriggeredAbility ability) { + super(ability); + } + + public FblthpTheLostTriggeredAbility copy() { + return new FblthpTheLostTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!super.checkTrigger(event, game)) { + return false; + } + EntersTheBattlefieldEvent entersEvent = (EntersTheBattlefieldEvent) event; + if (entersEvent.getFromZone() == Zone.LIBRARY) { + this.getEffects().clear(); + this.addEffect(new DrawCardSourceControllerEffect(2)); + return true; + } + FblthpTheLostWatcher watcher = game.getState().getWatcher(FblthpTheLostWatcher.class); + int zcc = entersEvent.getTarget().getZoneChangeCounter(game) - 1; + MageObjectReference mor = new MageObjectReference(entersEvent.getTargetId(), zcc, game); + if (watcher != null && watcher.spellWasCastFromLibrary(mor)) { + this.getEffects().clear(); + this.addEffect(new DrawCardSourceControllerEffect(2)); + return true; + } + this.getEffects().clear(); + this.addEffect(new DrawCardSourceControllerEffect(1)); + return true; + } + + @Override + public String getRule() { + return "When {this} enters the battlefield, draw a card. " + + "If it entered from your library or was cast from your library, draw two cards instead."; + } +} + +class FblthpTheLostWatcher extends Watcher { + + private final Set spellsCastFromLibrary = new HashSet(); + + FblthpTheLostWatcher() { + super(WatcherScope.GAME); + } + + private FblthpTheLostWatcher(final FblthpTheLostWatcher watcher) { + super(watcher); + spellsCastFromLibrary.addAll(watcher.spellsCastFromLibrary); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.LIBRARY) { + Spell spell = (Spell) game.getObject(event.getTargetId()); + if (spell != null) { + spellsCastFromLibrary.add(new MageObjectReference(spell, game)); + } + + } + } + + boolean spellWasCastFromLibrary(MageObjectReference mor) { + return spellsCastFromLibrary.contains(mor); + + } + + @Override + public void reset() { + super.reset(); + spellsCastFromLibrary.clear(); + } + + @Override + public FblthpTheLostWatcher copy() { + return new FblthpTheLostWatcher(this); + } +} + +class FblthpTheLostTargetedTriggeredAbility extends TriggeredAbilityImpl { + + FblthpTheLostTargetedTriggeredAbility() { + super(Zone.BATTLEFIELD, new ShuffleIntoLibrarySourceEffect(), false); + } + + private FblthpTheLostTargetedTriggeredAbility(final FblthpTheLostTargetedTriggeredAbility ability) { + super(ability); + } + + @Override + public FblthpTheLostTargetedTriggeredAbility copy() { + return new FblthpTheLostTargetedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TARGETED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + MageObject eventSourceObject = game.getObject(event.getSourceId()); + if (event.getTargetId().equals(this.getSourceId()) && eventSourceObject instanceof Spell) { + getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); + return true; + } + return false; + } + + @Override + public String getRule() { + return "When {this} becomes the target of a spell, shuffle {this} into its owner's library."; + } + +} diff --git a/Mage.Sets/src/mage/cards/f/FeastOfDreams.java b/Mage.Sets/src/mage/cards/f/FeastOfDreams.java index 96f547e448..b42e154268 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOfDreams.java +++ b/Mage.Sets/src/mage/cards/f/FeastOfDreams.java @@ -22,7 +22,7 @@ public final class FeastOfDreams extends CardImpl { static { filter.add(Predicates.or( - new EnchantedPredicate(), + EnchantedPredicate.instance, new CardTypePredicate(CardType.ENCHANTMENT) )); } diff --git a/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java b/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java index 22d1800804..78c8edfd69 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java +++ b/Mage.Sets/src/mage/cards/f/FeastOnTheFallen.java @@ -54,10 +54,10 @@ enum FeastOnTheFallenCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { - if (watcher.getLiveLostLastTurn(opponentId) > 0) { + if (watcher.getLifeLostLastTurn(opponentId) > 0) { return true; } } diff --git a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java index a8b2d0b4b1..f0ac477274 100644 --- a/Mage.Sets/src/mage/cards/f/FeastOrFamine.java +++ b/Mage.Sets/src/mage/cards/f/FeastOrFamine.java @@ -37,8 +37,8 @@ public final class FeastOrFamine extends CardImpl { // or destroy target nonartifact, nonblack creature and it can't be regenerated. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect(true)); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DestroyTargetEffect(true)); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java b/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java new file mode 100644 index 0000000000..74de65b44f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeatherTheRedeemed.java @@ -0,0 +1,184 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.SpellAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.Target; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FeatherTheRedeemed extends CardImpl { + + public FeatherTheRedeemed(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast an instant or sorcery spell that targets a creature you control, exile that card instead of putting it into your graveyard as it resolves. If you do, return it to your hand at the beginning of the next end step. + this.addAbility(new FeatherTheRedeemedTriggeredAbility()); + } + + private FeatherTheRedeemed(final FeatherTheRedeemed card) { + super(card); + } + + @Override + public FeatherTheRedeemed copy() { + return new FeatherTheRedeemed(this); + } +} + +class FeatherTheRedeemedTriggeredAbility extends TriggeredAbilityImpl { + + FeatherTheRedeemedTriggeredAbility() { + super(Zone.BATTLEFIELD, null, false); + } + + private FeatherTheRedeemedTriggeredAbility(final FeatherTheRedeemedTriggeredAbility ability) { + super(ability); + } + + @Override + public FeatherTheRedeemedTriggeredAbility copy() { + return new FeatherTheRedeemedTriggeredAbility(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 (!event.getPlayerId().equals(this.getControllerId())) { + return false; + } + Spell spell = game.getStack().getSpell(event.getTargetId()); + return checkSpell(spell, game); + } + + private boolean checkSpell(Spell spell, Game game) { + if (spell == null) { + return false; + } + SpellAbility sa = spell.getSpellAbility(); + for (UUID modeId : sa.getModes().getSelectedModes()) { + Mode mode = sa.getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null && permanent.isCreature() + && permanent.isControlledBy(getControllerId())) { + this.getEffects().clear(); + this.addEffect(new FeatherTheRedeemedEffect(new MageObjectReference(spell, game))); + return true; + } + } + } + for (Effect effect : mode.getEffects()) { + for (UUID targetId : effect.getTargetPointer().getTargets(game, sa)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null && permanent.isCreature() + && permanent.isControlledBy(getControllerId())) { + this.getEffects().clear(); + this.addEffect(new FeatherTheRedeemedEffect(new MageObjectReference(spell, game))); + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast an instant or sorcery spell that targets a creature you control, " + + "exile that card instead of putting it into your graveyard as it resolves. " + + "If you do, return it to your hand at the beginning of the next end step."; + } +} + +class FeatherTheRedeemedEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + FeatherTheRedeemedEffect(MageObjectReference mor) { + super(Duration.WhileOnStack, Outcome.Benefit); + this.mor = mor; + } + + private FeatherTheRedeemedEffect(final FeatherTheRedeemedEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Spell sourceSpell = game.getStack().getSpell(event.getTargetId()); + if (sourceSpell == null || sourceSpell.isCopy()) { + return false; + } + Player player = game.getPlayer(sourceSpell.getOwnerId()); + if (player == null) { + return false; + } + Effect effect = new ReturnToHandTargetEffect().setText("return " + sourceSpell.getName() + " to its owner's hand"); + player.moveCards(sourceSpell, Zone.EXILED, source, game); + effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = ((ZoneChangeEvent) event); + if (zEvent.getFromZone() == Zone.STACK + && zEvent.getToZone() == Zone.GRAVEYARD + && event.getSourceId() != null) { + if (event.getSourceId().equals(event.getTargetId())) { + Spell spell = game.getStack().getSpell(mor.getSourceId()); + if (spell != null && spell.isInstantOrSorcery()) { + return true; + } + } + } + return false; + } + + @Override + public FeatherTheRedeemedEffect copy() { + return new FeatherTheRedeemedEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FeedTheClan.java b/Mage.Sets/src/mage/cards/f/FeedTheClan.java index 63a5945c35..264c5571d9 100644 --- a/Mage.Sets/src/mage/cards/f/FeedTheClan.java +++ b/Mage.Sets/src/mage/cards/f/FeedTheClan.java @@ -1,22 +1,22 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FeedTheClan extends CardImpl { public FeedTheClan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // You gain 5 life. // Ferocious - You gain 10 life instead if you control a creature with power 4 or greater @@ -25,7 +25,7 @@ public final class FeedTheClan extends CardImpl { new GainLifeEffect(5), FerociousCondition.instance, "You gain 5 life.
    Ferocious — You gain 10 life instead if you control a creature with power 4 or greater")); - + this.getSpellAbility().addHint(FerociousHint.instance); } public FeedTheClan(final FeedTheClan card) { diff --git a/Mage.Sets/src/mage/cards/f/FeedThePack.java b/Mage.Sets/src/mage/cards/f/FeedThePack.java index 7e5ce9cadc..181022e5ef 100644 --- a/Mage.Sets/src/mage/cards/f/FeedThePack.java +++ b/Mage.Sets/src/mage/cards/f/FeedThePack.java @@ -48,7 +48,7 @@ class FeedThePackEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public FeedThePackEffect() { @@ -69,7 +69,7 @@ class FeedThePackEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Target target = new TargetPermanent(filter); Player player = game.getPlayer(source.getControllerId()); - if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { + if (player != null && player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null && permanent.sacrifice(source.getSourceId(), game)) { int toughness = permanent.getToughness().getValue(); diff --git a/Mage.Sets/src/mage/cards/f/Feint.java b/Mage.Sets/src/mage/cards/f/Feint.java new file mode 100644 index 0000000000..bccd33ddce --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/Feint.java @@ -0,0 +1,85 @@ + +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.PreventionEffect; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +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.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetAttackingCreature; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public final class Feint extends CardImpl { + + public Feint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + + // Tap all creatures blocking target attacking creature. Prevent all combat damage that would be dealt this turn by that creature and each creature blocking it. + this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true).setText("")); + this.getSpellAbility().addEffect(new FeintEffect()); + this.getSpellAbility().addTarget(new TargetAttackingCreature()); + } + + public Feint(final Feint card) { + super(card); + } + + @Override + public Feint copy() { + return new Feint(this); + } + +} + +class FeintEffect extends OneShotEffect { + + public FeintEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Tap all creatures blocking target attacking creature. Prevent all combat damage that would be dealt this turn by that creature and each creature blocking it"; + } + + public FeintEffect(final FeintEffect effect) { + super(effect); + } + + @Override + public FeintEffect copy() { + return new FeintEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller != null && creature != null) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getAttackers().contains(creature.getId())) { + for (UUID blockerId : combatGroup.getBlockers()) { + Permanent blocker = game.getPermanent(blockerId); + if (blocker != null) { + blocker.tap(game); + PreventionEffect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true); + effect.setTargetPointer(new FixedTarget(blocker.getId())); + game.addEffect(effect, source); + } + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FelhideBrawler.java b/Mage.Sets/src/mage/cards/f/FelhideBrawler.java index 03b687cead..119599817e 100644 --- a/Mage.Sets/src/mage/cards/f/FelhideBrawler.java +++ b/Mage.Sets/src/mage/cards/f/FelhideBrawler.java @@ -24,7 +24,7 @@ public final class FelhideBrawler extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MINOTAUR)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FelhideBrawler(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java index 2360250bd8..4b7c656183 100644 --- a/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java +++ b/Mage.Sets/src/mage/cards/f/FelhideSpiritbinder.java @@ -33,7 +33,7 @@ public final class FelhideSpiritbinder extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FelhideSpiritbinder(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java index 9931f38d36..cbd687eea8 100644 --- a/Mage.Sets/src/mage/cards/f/FelidarGuardian.java +++ b/Mage.Sets/src/mage/cards/f/FelidarGuardian.java @@ -25,7 +25,7 @@ public final class FelidarGuardian extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target permanent you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FelidarGuardian(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FellShepherd.java b/Mage.Sets/src/mage/cards/f/FellShepherd.java index 626237217f..6e2e833391 100644 --- a/Mage.Sets/src/mage/cards/f/FellShepherd.java +++ b/Mage.Sets/src/mage/cards/f/FellShepherd.java @@ -65,7 +65,7 @@ class FellShepherdWatcher extends Watcher { private Set creatureIds = new HashSet<>(); public FellShepherdWatcher() { - super(FellShepherdWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); condition = true; } @@ -118,7 +118,7 @@ class FellShepherdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FellShepherdWatcher watcher = (FellShepherdWatcher) game.getState().getWatchers().get(FellShepherdWatcher.class.getSimpleName(), source.getControllerId()); + FellShepherdWatcher watcher = game.getState().getWatcher(FellShepherdWatcher.class, source.getControllerId()); if (watcher != null) { StringBuilder sb = new StringBuilder(); for (UUID creatureId : watcher.getCreaturesIds()) { diff --git a/Mage.Sets/src/mage/cards/f/FenStalker.java b/Mage.Sets/src/mage/cards/f/FenStalker.java index d0e606cb07..e1821d199b 100644 --- a/Mage.Sets/src/mage/cards/f/FenStalker.java +++ b/Mage.Sets/src/mage/cards/f/FenStalker.java @@ -28,7 +28,7 @@ public final class FenStalker extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public FenStalker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FencersMagemark.java b/Mage.Sets/src/mage/cards/f/FencersMagemark.java index 593ad6407c..60aad9afb0 100644 --- a/Mage.Sets/src/mage/cards/f/FencersMagemark.java +++ b/Mage.Sets/src/mage/cards/f/FencersMagemark.java @@ -27,7 +27,7 @@ public final class FencersMagemark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control that are enchanted"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/f/FendOff.java b/Mage.Sets/src/mage/cards/f/FendOff.java new file mode 100644 index 0000000000..045d166fe7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FendOff.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class FendOff extends CardImpl { + + private static final String rule = "Prevent all combat damage that would be dealt by target creature this turn."; + + public FendOff(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Prevent all combat damage that would be dealt by target creature this turn. + this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true).setText(rule)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + + } + + public FendOff(final FendOff card) { + super(card); + } + + @Override + public FendOff copy() { + return new FendOff(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FeralDeceiver.java b/Mage.Sets/src/mage/cards/f/FeralDeceiver.java index 32aa366413..f04e3ecb81 100644 --- a/Mage.Sets/src/mage/cards/f/FeralDeceiver.java +++ b/Mage.Sets/src/mage/cards/f/FeralDeceiver.java @@ -78,10 +78,9 @@ class FeralDeceiverEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); if (card != null) { - cards.add(card); + Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game); if (card.isLand()) { game.addEffect(new BoostSourceEffect(2, 2, Duration.EndOfTurn), source); diff --git a/Mage.Sets/src/mage/cards/f/FeralMaaka.java b/Mage.Sets/src/mage/cards/f/FeralMaaka.java new file mode 100644 index 0000000000..fabc1d3d6f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeralMaaka.java @@ -0,0 +1,32 @@ +package mage.cards.f; + +import mage.MageInt; +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 FeralMaaka extends CardImpl { + + public FeralMaaka(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + private FeralMaaka(final FeralMaaka card) { + super(card); + } + + @Override + public FeralMaaka copy() { + return new FeralMaaka(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FeralRoar.java b/Mage.Sets/src/mage/cards/f/FeralRoar.java new file mode 100644 index 0000000000..46598d12af --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FeralRoar.java @@ -0,0 +1,33 @@ +package mage.cards.f; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 JayDi85 + */ +public final class FeralRoar extends CardImpl { + + public FeralRoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{G}"); + + // Target creature gets +4/+4 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(4, 4, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public FeralRoar(final FeralRoar card) { + super(card); + } + + @Override + public FeralRoar copy() { + return new FeralRoar(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java b/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java index e846026f4d..85e42cac3b 100644 --- a/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java +++ b/Mage.Sets/src/mage/cards/f/FerocityOfTheUnderworld.java @@ -38,14 +38,14 @@ public final class FerocityOfTheUnderworld extends CardImpl { // Copy target instant or sorcery spell. You may choose new targets for the copy. Mode mode = new Mode(); - mode.getEffects().add(new CopyTargetSpellEffect()); - mode.getTargets().add(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); + mode.addEffect(new CopyTargetSpellEffect()); + mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); this.getSpellAbility().addMode(mode); // Return target card from your graveyard to your hand. mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard()); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FertileThicket.java b/Mage.Sets/src/mage/cards/f/FertileThicket.java index 1e6f8f9cc1..8ec4913fdd 100644 --- a/Mage.Sets/src/mage/cards/f/FertileThicket.java +++ b/Mage.Sets/src/mage/cards/f/FertileThicket.java @@ -71,8 +71,7 @@ class FertileThicketEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.lookAtCards(sourceObject.getIdName(), cards, game); TargetCard target = new TargetCard(0, 1, Zone.LIBRARY, StaticFilters.FILTER_CARD_BASIC_LAND); controller.chooseTarget(outcome, cards, target, source, game); diff --git a/Mage.Sets/src/mage/cards/f/FestivalOfTheGuildpact.java b/Mage.Sets/src/mage/cards/f/FestivalOfTheGuildpact.java index 414368c1ab..be5027f518 100644 --- a/Mage.Sets/src/mage/cards/f/FestivalOfTheGuildpact.java +++ b/Mage.Sets/src/mage/cards/f/FestivalOfTheGuildpact.java @@ -20,7 +20,7 @@ public final class FestivalOfTheGuildpact extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}"); // Prevent the next X damage that would be dealt to you this turn. - this.getSpellAbility().addEffect(new PreventDamageToControllerEffect(Duration.EndOfTurn, false, true, new ManacostVariableValue())); + this.getSpellAbility().addEffect(new PreventDamageToControllerEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.instance)); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); diff --git a/Mage.Sets/src/mage/cards/f/Fettergeist.java b/Mage.Sets/src/mage/cards/f/Fettergeist.java index 6308282730..cb52e0ad48 100644 --- a/Mage.Sets/src/mage/cards/f/Fettergeist.java +++ b/Mage.Sets/src/mage/cards/f/Fettergeist.java @@ -56,7 +56,7 @@ class FettergeistUnlessPaysEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FettergeistUnlessPaysEffect() { diff --git a/Mage.Sets/src/mage/cards/f/FeverCharm.java b/Mage.Sets/src/mage/cards/f/FeverCharm.java index c989812773..155b3f2d57 100644 --- a/Mage.Sets/src/mage/cards/f/FeverCharm.java +++ b/Mage.Sets/src/mage/cards/f/FeverCharm.java @@ -36,13 +36,13 @@ public final class FeverCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature gets +2/+0 until end of turn Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or Fever Charm deals 3 damage to target Wizard creature. mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(3)); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DamageTargetEffect(3)); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FickleEfreet.java b/Mage.Sets/src/mage/cards/f/FickleEfreet.java index 3d0cf974d4..4e67afe38f 100644 --- a/Mage.Sets/src/mage/cards/f/FickleEfreet.java +++ b/Mage.Sets/src/mage/cards/f/FickleEfreet.java @@ -71,7 +71,7 @@ class FickleEfreetChangeControlEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null) { - if (!controller.flipCoin(game)) { + if (!controller.flipCoin(source, game, true)) { if (sourcePermanent != null) { Target target = new TargetOpponent(true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/f/FieldOfRuin.java b/Mage.Sets/src/mage/cards/f/FieldOfRuin.java index 3b559ff471..8070b83b55 100644 --- a/Mage.Sets/src/mage/cards/f/FieldOfRuin.java +++ b/Mage.Sets/src/mage/cards/f/FieldOfRuin.java @@ -90,7 +90,7 @@ class FieldOfRuinEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game); player.shuffleLibrary(source, game); } diff --git a/Mage.Sets/src/mage/cards/f/FieldOfSouls.java b/Mage.Sets/src/mage/cards/f/FieldOfSouls.java index 3389be54d9..682ac54ff2 100644 --- a/Mage.Sets/src/mage/cards/f/FieldOfSouls.java +++ b/Mage.Sets/src/mage/cards/f/FieldOfSouls.java @@ -1,8 +1,7 @@ - package mage.cards.f; import java.util.UUID; -import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -10,7 +9,7 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.other.OwnerPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.SpiritWhiteToken; @@ -19,18 +18,26 @@ import mage.game.permanent.token.SpiritWhiteToken; * @author fireshoes */ public final class FieldOfSouls extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); - static{ - filter.add(new OwnerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(Predicates.not(TokenPredicate.instance)); } public FieldOfSouls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // Whenever a nontoken creature is put into your graveyard from the battlefield, create a 1/1 white Spirit creature token with flying. - this.addAbility(new DiesCreatureTriggeredAbility(new CreateTokenEffect(new SpiritWhiteToken()), false, filter)); + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility( + new CreateTokenEffect( + new SpiritWhiteToken()), + false, + filter, + false, + true)); + } public FieldOfSouls(final FieldOfSouls card) { diff --git a/Mage.Sets/src/mage/cards/f/FieldSurgeon.java b/Mage.Sets/src/mage/cards/f/FieldSurgeon.java index 7931385c8e..93b62fb1f8 100644 --- a/Mage.Sets/src/mage/cards/f/FieldSurgeon.java +++ b/Mage.Sets/src/mage/cards/f/FieldSurgeon.java @@ -28,7 +28,7 @@ public final class FieldSurgeon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public FieldSurgeon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FiendBinder.java b/Mage.Sets/src/mage/cards/f/FiendBinder.java index 64a65b7506..1cbc7e0cc7 100644 --- a/Mage.Sets/src/mage/cards/f/FiendBinder.java +++ b/Mage.Sets/src/mage/cards/f/FiendBinder.java @@ -22,7 +22,7 @@ public final class FiendBinder extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public FiendBinder(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FiendHunter.java b/Mage.Sets/src/mage/cards/f/FiendHunter.java index c1ab64d1b2..bd868bf9c8 100644 --- a/Mage.Sets/src/mage/cards/f/FiendHunter.java +++ b/Mage.Sets/src/mage/cards/f/FiendHunter.java @@ -25,7 +25,7 @@ public final class FiendHunter extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FiendHunter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FiendslayerPaladin.java b/Mage.Sets/src/mage/cards/f/FiendslayerPaladin.java index 3749823252..e1a9eb05d9 100644 --- a/Mage.Sets/src/mage/cards/f/FiendslayerPaladin.java +++ b/Mage.Sets/src/mage/cards/f/FiendslayerPaladin.java @@ -94,7 +94,7 @@ class FiendslayerPaladinEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Card targetCard = game.getCard(event.getTargetId()); - StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId()); + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (targetCard != null && stackObject != null && targetCard.getId().equals(source.getSourceId())) { if (stackObject.getColor(game).isBlack() || stackObject.getColor(game).isRed()) { if (!stackObject.isControlledBy(source.getControllerId()) diff --git a/Mage.Sets/src/mage/cards/f/FieryConfluence.java b/Mage.Sets/src/mage/cards/f/FieryConfluence.java index 530b53be80..6d15e1f164 100644 --- a/Mage.Sets/src/mage/cards/f/FieryConfluence.java +++ b/Mage.Sets/src/mage/cards/f/FieryConfluence.java @@ -32,13 +32,13 @@ public final class FieryConfluence extends CardImpl { // Fiery Confluence deals 2 damage to each opponent; Mode mode = new Mode(); - mode.getEffects().add(new DamagePlayersEffect(2, TargetController.OPPONENT)); + mode.addEffect(new DamagePlayersEffect(2, TargetController.OPPONENT)); this.getSpellAbility().getModes().addMode(mode); // Destroy target artifact. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FieryGambit.java b/Mage.Sets/src/mage/cards/f/FieryGambit.java index 0502117389..36177cf86d 100644 --- a/Mage.Sets/src/mage/cards/f/FieryGambit.java +++ b/Mage.Sets/src/mage/cards/f/FieryGambit.java @@ -64,10 +64,10 @@ class FieryGambitEffect extends OneShotEffect { if (controller != null && sourceObject != null) { int flipsWon = 0; boolean controllerStopped = false; - while (controller.flipCoin(game)) { + while (controller.flipCoin(source, game, true)) { ++flipsWon; - if (!controller.chooseUse(outcome, new StringBuilder("You won ").append(flipsWon).append(flipsWon == 1 ? " flip." : " flips.") - .append(" Flip another coin?").toString(), source, game)) { + if (!controller.chooseUse(outcome, "You won " + flipsWon + (flipsWon == 1 ? " flip." : " flips.") + + " Flip another coin?", source, game)) { controllerStopped = true; break; } diff --git a/Mage.Sets/src/mage/cards/f/FieryIntervention.java b/Mage.Sets/src/mage/cards/f/FieryIntervention.java index cb0c469a01..a6f1d27277 100644 --- a/Mage.Sets/src/mage/cards/f/FieryIntervention.java +++ b/Mage.Sets/src/mage/cards/f/FieryIntervention.java @@ -27,8 +27,8 @@ public final class FieryIntervention extends CardImpl { // -Destroy target artifact. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FightOrFlight.java b/Mage.Sets/src/mage/cards/f/FightOrFlight.java new file mode 100644 index 0000000000..6e88e228ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FightOrFlight.java @@ -0,0 +1,107 @@ + +package mage.cards.f; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantAttackTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 & L_J + */ +public final class FightOrFlight extends CardImpl { + + public FightOrFlight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + + // At the beginning of combat on each opponent’s turn, separate all creatures that player controls into two piles. Only creatures in the pile of their choice can attack this turn. + this.addAbility(new BeginningOfCombatTriggeredAbility(new FightOrFlightEffect(), TargetController.OPPONENT, false)); + } + + public FightOrFlight(final FightOrFlight card) { + super(card); + } + + @Override + public FightOrFlight copy() { + return new FightOrFlight(this); + } +} + +class FightOrFlightEffect extends OneShotEffect { + + public FightOrFlightEffect() { + super(Outcome.Detriment); + this.staticText = "separate all creatures that player controls into two piles. Only creatures in the pile of their choice can attack this turn"; + } + + public FightOrFlightEffect(final FightOrFlightEffect effect) { + super(effect); + } + + @Override + public FightOrFlightEffect copy() { + return new FightOrFlightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Player targetPlayer = game.getPlayer(game.getCombat().getAttackingPlayerId()); + if (player != null && targetPlayer != null) { + int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURES, targetPlayer.getId(), game); + TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, count, new FilterCreaturePermanent("creatures to put in the first pile"), true); + List pile1 = new ArrayList<>(); + creatures.setRequired(false); + if (player.choose(Outcome.Neutral, creatures, source.getSourceId(), game)) { + List targets = creatures.getTargets(); + for (UUID targetId : targets) { + Permanent p = game.getPermanent(targetId); + if (p != null) { + pile1.add(p); + } + } + } + List pile2 = new ArrayList<>(); + for (Permanent p : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, targetPlayer.getId(), game)) { + if (!pile1.contains(p)) { + pile2.add(p); + } + } + + boolean choice = targetPlayer.choosePile(outcome, "Choose which pile can attack this turn.", pile1, pile2, game); + List chosenPile = choice ? pile2 : pile1; + List otherPile = choice ? pile1 : pile2; + for (Permanent permanent : chosenPile) { + if (permanent != null) { + RestrictionEffect effect = new CantAttackTargetEffect(Duration.EndOfTurn); + effect.setText(""); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + } + game.informPlayers("Creatures that can attack this turn: " + otherPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FightToTheDeath.java b/Mage.Sets/src/mage/cards/f/FightToTheDeath.java index 7f95878400..b0b1ec365d 100644 --- a/Mage.Sets/src/mage/cards/f/FightToTheDeath.java +++ b/Mage.Sets/src/mage/cards/f/FightToTheDeath.java @@ -21,8 +21,8 @@ public final class FightToTheDeath extends CardImpl { static { filter.add(Predicates.or( - new BlockingPredicate(), - new BlockedPredicate())); + BlockingPredicate.instance, + BlockedPredicate.instance)); } public FightToTheDeath(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FightWithFire.java b/Mage.Sets/src/mage/cards/f/FightWithFire.java index ebad07ad96..67b7b683a8 100644 --- a/Mage.Sets/src/mage/cards/f/FightWithFire.java +++ b/Mage.Sets/src/mage/cards/f/FightWithFire.java @@ -1,9 +1,7 @@ - package mage.cards.f; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageMultiEffect; @@ -16,6 +14,7 @@ import mage.game.Game; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetAnyTargetAmount; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -39,26 +38,29 @@ public final class FightWithFire extends CardImpl { + " (Those targets can include players and planeswalkers.)" )); this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().setTargetAdjuster(FightWithFireAdjuster.instance); } public FightWithFire(final FightWithFire card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - ability.getTargets().clear(); - if (ability instanceof SpellAbility) { - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetAnyTargetAmount(10)); - } else { - ability.addTarget(new TargetCreaturePermanent()); - } - } - } - @Override public FightWithFire copy() { return new FightWithFire(this); } } + +enum FightWithFireAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetAnyTargetAmount(10)); + } else { + ability.addTarget(new TargetCreaturePermanent()); + } + } +} diff --git a/Mage.Sets/src/mage/cards/f/FightingChance.java b/Mage.Sets/src/mage/cards/f/FightingChance.java index 896e01dcfe..d67bef03c3 100644 --- a/Mage.Sets/src/mage/cards/f/FightingChance.java +++ b/Mage.Sets/src/mage/cards/f/FightingChance.java @@ -61,7 +61,7 @@ class FightingChanceEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { for (UUID blocker : game.getCombat().getBlockers()) { - if (player.flipCoin(game)) { + if (player.flipCoin(source, game, true)) { PreventDamageByTargetEffect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn, true); effect.setTargetPointer(new FixedTarget(blocker)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/f/FinalParting.java b/Mage.Sets/src/mage/cards/f/FinalParting.java index 76239b9c4b..2705156ea5 100644 --- a/Mage.Sets/src/mage/cards/f/FinalParting.java +++ b/Mage.Sets/src/mage/cards/f/FinalParting.java @@ -1,7 +1,6 @@ package mage.cards.f; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -66,10 +65,10 @@ class FinalPartingEffect extends OneShotEffect { if (controller != null) { // Unlike Jarad's Orders, which this mostly copies, you can't fail to find TargetCardInLibrary target = new TargetCardInLibrary(2, 2, new FilterCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards searched = new CardsImpl(); - for (UUID cardId : (List) target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); searched.add(card); } diff --git a/Mage.Sets/src/mage/cards/f/FinalPayment.java b/Mage.Sets/src/mage/cards/f/FinalPayment.java new file mode 100644 index 0000000000..22486309c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinalPayment.java @@ -0,0 +1,60 @@ +package mage.cards.f; + +import java.util.UUID; + +import mage.abilities.costs.AlternativeCostSourceAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.OptionalAdditionalCost; +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.PayLifeCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesToughness; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +/** + * + * @author FateRevoked + */ +public final class FinalPayment extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a creature or enchantment"); + + static { + filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.ENCHANTMENT))); + } + + public FinalPayment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{B}"); + + // As an additional cost to cast this spell, pay 5 life or sacrifice a creature or enchantment. + final Cost lifeCost = new PayLifeCost(5); + final Cost sacrificeCost = new SacrificeTargetCost(new TargetControlledPermanent(filter)); + + this.getSpellAbility().addCost(new OrCost(lifeCost, sacrificeCost, + "pay 5 life or sacrifice a creature or enchantment")); + + // Destroy target creature + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + public FinalPayment(final FinalPayment card) { + super(card); + } + + @Override + public FinalPayment copy() { + return new FinalPayment(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FinalPunishment.java b/Mage.Sets/src/mage/cards/f/FinalPunishment.java index f4dc817ccc..abf048a636 100644 --- a/Mage.Sets/src/mage/cards/f/FinalPunishment.java +++ b/Mage.Sets/src/mage/cards/f/FinalPunishment.java @@ -45,7 +45,7 @@ class FinalPunishmentAmount implements DynamicValue { @Override public int calculate(Game game, Ability source, Effect effect) { AmountOfDamageAPlayerReceivedThisTurnWatcher watcher - = (AmountOfDamageAPlayerReceivedThisTurnWatcher) game.getState().getWatchers().get(AmountOfDamageAPlayerReceivedThisTurnWatcher.class.getSimpleName()); + = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class); if(watcher != null) { return watcher.getAmountOfDamageReceivedThisTurn(source.getFirstTarget()); } diff --git a/Mage.Sets/src/mage/cards/f/FinalRevels.java b/Mage.Sets/src/mage/cards/f/FinalRevels.java index 5944b0285b..0b732ddcb9 100644 --- a/Mage.Sets/src/mage/cards/f/FinalRevels.java +++ b/Mage.Sets/src/mage/cards/f/FinalRevels.java @@ -21,7 +21,7 @@ public final class FinalRevels extends CardImpl { this.getSpellAbility().addEffect(new BoostAllEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); Mode mode = new Mode(); - mode.getEffects().add(new BoostAllEffect(0, -2, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + mode.addEffect(new BoostAllEffect(0, -2, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FinalStrike.java b/Mage.Sets/src/mage/cards/f/FinalStrike.java index 4cd4c7f167..6881b64020 100644 --- a/Mage.Sets/src/mage/cards/f/FinalStrike.java +++ b/Mage.Sets/src/mage/cards/f/FinalStrike.java @@ -26,7 +26,7 @@ public final class FinalStrike extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); // Final Strike deals damage to target opponent equal to the sacrificed creature's power. - Effect effect = new DamageTargetEffect(new SacrificeCostCreaturesPower()); + Effect effect = new DamageTargetEffect(SacrificeCostCreaturesPower.instance); effect.setText("{this} deals damage to target opponent or planeswalker equal to the sacrificed creature's power"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetOpponentOrPlaneswalker()); diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java b/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java new file mode 100644 index 0000000000..7afc58140a --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java @@ -0,0 +1,80 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; + +import mage.abilities.Ability; +import mage.constants.Outcome; +import mage.game.Game; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.constants.CardType; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.abilities.effects.common.search.SearchLibraryGraveyardWithLessCMCPutIntoPlay; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.constants.Duration; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; + + +/** + * + * @author antoni-g + */ +public final class FinaleOfDevastation extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public FinaleOfDevastation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{G}"); + // Search your library and/or graveyard for a creature card with converted mana cost X or less and put it onto the battlefield. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardWithLessCMCPutIntoPlay(filter)); + // If X is 10 or more, creatures you control get +X/+X and gain haste until end of turn. + this.getSpellAbility().addEffect(new FinaleOfDevastationEffect()); + } + + private FinaleOfDevastation(final FinaleOfDevastation card) { + super(card); + } + + @Override + public FinaleOfDevastation copy() { + return new FinaleOfDevastation(this); + } +} + +class FinaleOfDevastationEffect extends OneShotEffect { + + FinaleOfDevastationEffect() { + super(Outcome.Benefit); + staticText = "If X is 10 or more, creatures you control get +X/+X and gain haste until end of turn."; + } + + private FinaleOfDevastationEffect(final FinaleOfDevastationEffect effect) { + super(effect); + } + + @Override + public FinaleOfDevastationEffect copy() { + return new FinaleOfDevastationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int xValue = source.getManaCostsToPay().getX(); + if (xValue >= 10) { + ContinuousEffect effect1 = new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn); + game.addEffect(effect1, source); + ContinuousEffect effect2 = new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent()); + game.addEffect(effect2, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfEternity.java b/Mage.Sets/src/mage/cards/f/FinaleOfEternity.java new file mode 100644 index 0000000000..b753855442 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfEternity.java @@ -0,0 +1,92 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FinaleOfEternity extends CardImpl { + + public FinaleOfEternity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); + + // Destroy up to three target creatures with toughness X or less. If X is 10 or more, return all creature cards from your graveyard to the battlefield. + this.getSpellAbility().addEffect(new FinaleOfEternityEffect()); + this.getSpellAbility().setTargetAdjuster(FinaleOfEternityAdjuster.instance); + } + + private FinaleOfEternity(final FinaleOfEternity card) { + super(card); + } + + @Override + public FinaleOfEternity copy() { + return new FinaleOfEternity(this); + } +} + +enum FinaleOfEternityAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + FilterPermanent filter = new FilterCreaturePermanent("creatures with toughness " + xValue + " or less"); + filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(0, 3, filter, false)); + } +} + +class FinaleOfEternityEffect extends OneShotEffect { + + FinaleOfEternityEffect() { + super(Outcome.Benefit); + staticText = "Destroy up to three target creatures with toughness X or less. " + + "If X is 10 or more, return all creature cards from your graveyard to the battlefield."; + } + + private FinaleOfEternityEffect(final FinaleOfEternityEffect effect) { + super(effect); + } + + @Override + public FinaleOfEternityEffect copy() { + return new FinaleOfEternityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new DestroyTargetEffect(false, true).apply(game, source); + if (source.getManaCostsToPay().getX() < 10) { + return true; + } + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + return player.moveCards( + player.getGraveyard().getCards( + StaticFilters.FILTER_CARD_CREATURE, game + ), Zone.BATTLEFIELD, source, game + ); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfGlory.java b/Mage.Sets/src/mage/cards/f/FinaleOfGlory.java new file mode 100644 index 0000000000..9f1017131f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfGlory.java @@ -0,0 +1,67 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +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.AngelVigilanceToken; +import mage.game.permanent.token.SoldierVigilanceToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FinaleOfGlory extends CardImpl { + + public FinaleOfGlory(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{W}{W}"); + + // Create X 2/2 white Soldier creature tokens with vigilance. If X is 10 or more, also create X 4/4 white Angel creature tokens with flying and vigilance. + this.getSpellAbility().addEffect(new FinaleOfGloryEffect()); + } + + private FinaleOfGlory(final FinaleOfGlory card) { + super(card); + } + + @Override + public FinaleOfGlory copy() { + return new FinaleOfGlory(this); + } +} + +class FinaleOfGloryEffect extends OneShotEffect { + + FinaleOfGloryEffect() { + super(Outcome.Benefit); + staticText = "Create X 2/2 white Soldier creature tokens with vigilance. " + + "If X is 10 or more, also create X 4/4 white Angel creature tokens with flying and vigilance."; + } + + private FinaleOfGloryEffect(final FinaleOfGloryEffect effect) { + super(effect); + } + + @Override + public FinaleOfGloryEffect copy() { + return new FinaleOfGloryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int xValue = source.getManaCostsToPay().getX(); + if (xValue == 0) { + return false; + } + new CreateTokenEffect(new SoldierVigilanceToken(), xValue).apply(game, source); + if (xValue >= 10) { + new CreateTokenEffect(new AngelVigilanceToken(), xValue).apply(game, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java b/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java new file mode 100644 index 0000000000..339ef3a9d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfPromise.java @@ -0,0 +1,198 @@ +package mage.cards.f; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FixedTarget; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class FinaleOfPromise extends CardImpl { + + static final FilterCard filterInstant = new FilterCard("instant card from your graveyard"); + static final FilterCard filterSorcery = new FilterCard("sorcery card from your graveyard"); + + static { + filterInstant.add(new CardTypePredicate(CardType.INSTANT)); + filterSorcery.add(new CardTypePredicate(CardType.SORCERY)); + } + + public FinaleOfPromise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}"); + + // You may cast up to one target instant card and/or up to one target sorcery card from your graveyard + // each with converted mana cost X or less without paying their mana costs. + // If a card cast this way would be put into your graveyard this turn, exile it instead. + // If X is 10 or more, copy each of those spells twice. You may choose new targets for the copies. + this.getSpellAbility().addEffect(new FinaleOfPromiseEffect()); + this.getSpellAbility().setTargetAdjuster(FinaleOfPromiseAdjuster.instance); + } + + public FinaleOfPromise(final FinaleOfPromise card) { + super(card); + } + + @Override + public FinaleOfPromise copy() { + return new FinaleOfPromise(this); + } +} + +enum FinaleOfPromiseAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + + int xValue = ManacostVariableValue.instance.calculate(game, ability, null); + + // <= must be replaced to <= for html view + FilterCard filter1 = FinaleOfPromise.filterInstant.copy(); + filter1.setMessage("up to one INSTANT card from your graveyard with CMC <= " + xValue + " (target 1 of 2)"); + filter1.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter1)); + + FilterCard filter2 = FinaleOfPromise.filterSorcery.copy(); + filter2.setMessage("up to one SORCERY card from your graveyard with CMC <=" + xValue + " (target 2 of 2)"); + filter2.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.addTarget(new TargetCardInYourGraveyard(0, 1, filter2)); + } +} + +class FinaleOfPromiseEffect extends OneShotEffect { + + public FinaleOfPromiseEffect() { + super(Outcome.PlayForFree); + this.staticText = "You may cast up to one target instant card and/or up to one target sorcery card from your graveyard " + + "each with converted mana cost X or less without paying their mana costs. If a card cast this way would " + + "be put into your graveyard this turn, exile it instead. If X is 10 or more, copy each of those spells " + + "twice. You may choose new targets for the copies."; + } + + public FinaleOfPromiseEffect(final FinaleOfPromiseEffect effect) { + super(effect); + } + + @Override + public FinaleOfPromiseEffect copy() { + return new FinaleOfPromiseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + // split card can be targeted two time -- but can cast only one + List cardsToCast = new ArrayList<>(); + for (Target target : source.getTargets()) { + for (UUID id : target.getTargets()) { + if (id != null && !cardsToCast.contains(id)) { + cardsToCast.add(id); + } + } + } + + // free cast + replace effect + for (UUID id : cardsToCast) { + Card card = game.getCard(id); + if (card != null) { + controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + ContinuousEffect effect = new FinaleOfPromiseReplacementEffect(); + effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); + game.addEffect(effect, source); + } + } + + // If X is 10 or more, copy each of those spells twice. You may choose new targets for the copies + int xValue = ManacostVariableValue.instance.calculate(game, source, null); + if (xValue >= 10) { + for (UUID id : cardsToCast) { + Card card = game.getCard(id); + if (card != null) { + Spell spell = game.getStack().getSpell(card.getId()); + if (spell != null) { + spell.createCopyOnStack(game, source, controller.getId(), true); + spell.createCopyOnStack(game, source, controller.getId(), true); + game.informPlayers(controller.getLogName() + " copies " + spell.getName() + " twice."); + } + } + } + } + + return true; + } +} + +class FinaleOfPromiseReplacementEffect extends ReplacementEffectImpl { + + public FinaleOfPromiseReplacementEffect() { + super(Duration.EndOfTurn, Outcome.Exile); + staticText = "If a card cast this way would be put into your graveyard this turn, exile it instead"; + } + + public FinaleOfPromiseReplacementEffect(final FinaleOfPromiseReplacementEffect effect) { + super(effect); + } + + @Override + public FinaleOfPromiseReplacementEffect copy() { + return new FinaleOfPromiseReplacementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card != null) { + card.moveToExile(null, "", source.getSourceId(), game); + return true; + } + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getToZone() == Zone.GRAVEYARD && event.getTargetId().equals(getTargetPointer().getFirst(game, source)); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfRevelation.java b/Mage.Sets/src/mage/cards/f/FinaleOfRevelation.java new file mode 100644 index 0000000000..afaf5aee13 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfRevelation.java @@ -0,0 +1,83 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileSpellEffect; +import mage.abilities.effects.common.UntapLandsEffect; +import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; +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.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FinaleOfRevelation extends CardImpl { + + public FinaleOfRevelation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); + + // Draw X cards. If X is 10 or more, instead shuffle your graveyard into your library, draw X cards, untap up to five lands, and you have no maximum hand size for the rest of the game. + this.getSpellAbility().addEffect(new FinaleOfRevelationEffect()); + + // Exile Finale of Revelation. + this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); + } + + private FinaleOfRevelation(final FinaleOfRevelation card) { + super(card); + } + + @Override + public FinaleOfRevelation copy() { + return new FinaleOfRevelation(this); + } +} + +class FinaleOfRevelationEffect extends OneShotEffect { + + FinaleOfRevelationEffect() { + super(Outcome.Benefit); + staticText = "Draw X cards. If X is 10 or more, instead shuffle your graveyard into your library, " + + "draw X cards, untap up to five lands, and you have no maximum hand size for the rest of the game."; + } + + private FinaleOfRevelationEffect(final FinaleOfRevelationEffect effect) { + super(effect); + } + + @Override + public FinaleOfRevelationEffect copy() { + return new FinaleOfRevelationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int xValue = source.getManaCostsToPay().getX(); + + if (xValue < 10) { + player.drawCards(xValue, game); + } else { + player.putCardsOnTopOfLibrary(player.getGraveyard(), game, source, false); + player.shuffleLibrary(source, game); + player.drawCards(xValue, game); + new UntapLandsEffect(5).apply(game, source); + game.addEffect(new MaximumHandSizeControllerEffect( + Integer.MAX_VALUE, Duration.EndOfGame, + MaximumHandSizeControllerEffect.HandSizeModification.SET + ), source); + } + + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/Finn.java b/Mage.Sets/src/mage/cards/f/Finn.java index b4429e90ae..6408b55ac2 100644 --- a/Mage.Sets/src/mage/cards/f/Finn.java +++ b/Mage.Sets/src/mage/cards/f/Finn.java @@ -28,7 +28,7 @@ public final class Finn extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public Finn(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java b/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java index 72ce9e2c9d..92e9f2cf2a 100644 --- a/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java +++ b/Mage.Sets/src/mage/cards/f/FireAndBrimstone.java @@ -59,7 +59,7 @@ class FireAndBrimstonePredicate extends PlayerPredicate { if (player == null || playerId == null) { return false; } - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null) { if (!watcher.getAttackedThisTurnCreatures().isEmpty()) { return player.getId().equals(game.getActivePlayerId()); diff --git a/Mage.Sets/src/mage/cards/f/FireAnts.java b/Mage.Sets/src/mage/cards/f/FireAnts.java index 208565fb1b..a8bed48f78 100644 --- a/Mage.Sets/src/mage/cards/f/FireAnts.java +++ b/Mage.Sets/src/mage/cards/f/FireAnts.java @@ -27,7 +27,7 @@ public final class FireAnts extends CardImpl { static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FireAnts(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FireAtWill.java b/Mage.Sets/src/mage/cards/f/FireAtWill.java index 706a5cee46..efe7a67bce 100644 --- a/Mage.Sets/src/mage/cards/f/FireAtWill.java +++ b/Mage.Sets/src/mage/cards/f/FireAtWill.java @@ -23,8 +23,8 @@ public final class FireAtWill extends CardImpl { static { filter.add(Predicates.or( - new AttackingPredicate(), - new BlockingPredicate())); + AttackingPredicate.instance, + BlockingPredicate.instance)); } public FireAtWill(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FireCovenant.java b/Mage.Sets/src/mage/cards/f/FireCovenant.java index ae9870a467..80f8f72909 100644 --- a/Mage.Sets/src/mage/cards/f/FireCovenant.java +++ b/Mage.Sets/src/mage/cards/f/FireCovenant.java @@ -25,7 +25,7 @@ public final class FireCovenant extends CardImpl { this.getSpellAbility().addCost(new PayVariableLifeCost(true)); // Fire Covenant deals X damage divided as you choose among any number of target creatures. - DynamicValue xValue = new GetXValue(); + DynamicValue xValue = GetXValue.instance; this.getSpellAbility().addEffect(new DamageMultiEffect(xValue)); this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(xValue)); } diff --git a/Mage.Sets/src/mage/cards/f/Fireball.java b/Mage.Sets/src/mage/cards/f/Fireball.java index df0543c9c6..7e56cf8017 100644 --- a/Mage.Sets/src/mage/cards/f/Fireball.java +++ b/Mage.Sets/src/mage/cards/f/Fireball.java @@ -1,8 +1,8 @@ package mage.cards.f; -import java.util.*; import mage.abilities.Ability; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,8 +14,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public final class Fireball extends CardImpl { @@ -27,14 +28,7 @@ public final class Fireball extends CardImpl { // Fireball costs 1 more to cast for each target beyond the first. this.getSpellAbility().addTarget(new FireballTargetCreatureOrPlayer(0, Integer.MAX_VALUE)); this.getSpellAbility().addEffect(new FireballEffect()); - } - - @Override - public void adjustCosts(Ability ability, Game game) { - int numTargets = ability.getTargets().isEmpty() ? 0 : ability.getTargets().get(0).getTargets().size(); - if (numTargets > 1) { - ability.getManaCostsToPay().add(new GenericManaCost(numTargets - 1)); - } + this.getSpellAbility().setCostAdjuster(FireballAdjuster.instance); } public Fireball(final Fireball card) { @@ -47,6 +41,18 @@ public final class Fireball extends CardImpl { } } +enum FireballAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + int numTargets = ability.getTargets().isEmpty() ? 0 : ability.getTargets().get(0).getTargets().size(); + if (numTargets > 1) { + ability.getManaCostsToPay().add(new GenericManaCost(numTargets - 1)); + } + } +} + class FireballEffect extends OneShotEffect { public FireballEffect() { diff --git a/Mage.Sets/src/mage/cards/f/FirebladeArtist.java b/Mage.Sets/src/mage/cards/f/FirebladeArtist.java new file mode 100644 index 0000000000..e11b412cc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FirebladeArtist.java @@ -0,0 +1,116 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.SendOptionUsedEventEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetOpponentOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FirebladeArtist extends CardImpl { + + public FirebladeArtist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // At the beginning of your upkeep, you may sacrifice a creature. When you do, Fireblade Artist deals 2 damage to target opponent or planeswalker. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoIfCostPaid( + new FirebladeArtistCreateReflexiveTriggerEffect(), + new SacrificeTargetCost(new TargetControlledPermanent( + StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT + )), "Sacrifice a creature to deal 2 damage to an opponent or planeswalker?" + ).setText("you may sacrifice a creature. When you do, " + + "{this} deals 2 damage to target opponent or planeswalker."), + TargetController.YOU, false + )); + } + + private FirebladeArtist(final FirebladeArtist card) { + super(card); + } + + @Override + public FirebladeArtist copy() { + return new FirebladeArtist(this); + } +} + +class FirebladeArtistCreateReflexiveTriggerEffect extends OneShotEffect { + + FirebladeArtistCreateReflexiveTriggerEffect() { + super(Outcome.Benefit); + } + + private FirebladeArtistCreateReflexiveTriggerEffect(final FirebladeArtistCreateReflexiveTriggerEffect effect) { + super(effect); + } + + @Override + public FirebladeArtistCreateReflexiveTriggerEffect copy() { + return new FirebladeArtistCreateReflexiveTriggerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.addDelayedTriggeredAbility(new FirebladeArtistReflexiveTriggeredAbility(), source); + return new SendOptionUsedEventEffect().apply(game, source); + } +} + +class FirebladeArtistReflexiveTriggeredAbility extends DelayedTriggeredAbility { + + FirebladeArtistReflexiveTriggeredAbility() { + super(new DamageTargetEffect(2), Duration.OneUse, true); + this.addTarget(new TargetOpponentOrPlaneswalker()); + } + + private FirebladeArtistReflexiveTriggeredAbility(final FirebladeArtistReflexiveTriggeredAbility ability) { + super(ability); + } + + @Override + public FirebladeArtistReflexiveTriggeredAbility copy() { + return new FirebladeArtistReflexiveTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.OPTION_USED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getPlayerId().equals(this.getControllerId()) + && event.getSourceId().equals(this.getSourceId()); + } + + @Override + public String getRule() { + return "{this} deals 2 damage to target opponent or planeswalker."; + } +} diff --git a/Mage.Sets/src/mage/cards/f/FiremindVessel.java b/Mage.Sets/src/mage/cards/f/FiremindVessel.java new file mode 100644 index 0000000000..ca305fb40c --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FiremindVessel.java @@ -0,0 +1,110 @@ +package mage.cards.f; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FiremindVessel extends CardImpl { + + public FiremindVessel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // Firemind Vessel enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add two mana of different colors. + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, new FiremindVesselManaEffect(), new TapSourceCost() + )); + } + + private FiremindVessel(final FiremindVessel card) { + super(card); + } + + @Override + public FiremindVessel copy() { + return new FiremindVessel(this); + } +} + +class FiremindVesselManaEffect extends ManaEffect { + + FiremindVesselManaEffect() { + super(); + staticText = "Add two mana of different colors."; + } + + private FiremindVesselManaEffect(final FiremindVesselManaEffect effect) { + super(effect); + } + + @Override + public Mana produceMana(boolean netMana, Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return null; + } + + ChoiceColor color1 = new ChoiceColor(true, "Choose color 1"); + if (!player.choose(outcome, color1, game) || color1.getColor() == null) { + return null; + } + + ChoiceColor color2 = new ChoiceColor(true, "Choose color 2"); + color2.removeColorFromChoices(color1.getChoice()); + if (!player.choose(outcome, color2, game) || color2.getColor() == null) { + return null; + } + + if (color1.getColor().equals(color2.getColor())) { + game.informPlayers("Player " + player.getName() + " is cheating with mana choices."); + return null; + } + + Mana mana = new Mana(); + mana.add(color1.getMana(1)); + mana.add(color2.getMana(1)); + return mana; + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + checkToFirePossibleEvents(getMana(game, source), game, source); + player.getManaPool().addMana(getMana(game, source), game, source); + return true; + } + return false; + } + + @Override + public List getNetMana(Game game, Ability source) { + ArrayList netMana = new ArrayList<>(); + netMana.add(new Mana(0, 0, 0, 0, 0, 0, 2, 0)); + return netMana; + } + + @Override + public FiremindVesselManaEffect copy() { + return new FiremindVesselManaEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FiremindsForesight.java b/Mage.Sets/src/mage/cards/f/FiremindsForesight.java index f7fb939a93..05b4376308 100644 --- a/Mage.Sets/src/mage/cards/f/FiremindsForesight.java +++ b/Mage.Sets/src/mage/cards/f/FiremindsForesight.java @@ -79,7 +79,7 @@ class FiremindsForesightSearchEffect extends OneShotEffect { cardsCount = cardsInLibrary.count(filter, game); if (cardsCount > 0) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { for (UUID cardId: target.getTargets()) { Card card = player.getLibrary().remove(cardId, game); if (card != null){ diff --git a/Mage.Sets/src/mage/cards/f/Firestorm.java b/Mage.Sets/src/mage/cards/f/Firestorm.java index 584afbec57..b489ee21b6 100644 --- a/Mage.Sets/src/mage/cards/f/Firestorm.java +++ b/Mage.Sets/src/mage/cards/f/Firestorm.java @@ -1,4 +1,3 @@ - package mage.cards.f; import java.util.UUID; @@ -16,6 +15,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -24,32 +24,36 @@ import mage.target.common.TargetAnyTarget; public final class Firestorm extends CardImpl { public Firestorm(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // As an additional cost to cast Firestorm, discard X cards. this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); // Firestorm deals X damage to each of X target creatures and/or players. this.getSpellAbility().addEffect(new FirestormEffect()); + this.getSpellAbility().setTargetAdjuster(FirestormAdjuster.instance); } public Firestorm(final Firestorm card) { super(card); } + @Override + public Firestorm copy() { + return new Firestorm(this); + } +} + +enum FirestormAdjuster implements TargetAdjuster { + instance; + @Override public void adjustTargets(Ability ability, Game game) { - int xValue = new GetXValue().calculate(game, ability, null); + int xValue = GetXValue.instance.calculate(game, ability, null); if (xValue > 0) { Target target = new TargetAnyTarget(xValue); ability.addTarget(target); } } - - @Override - public Firestorm copy() { - return new Firestorm(this); - } } class FirestormEffect extends OneShotEffect { @@ -66,7 +70,7 @@ class FirestormEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); - int amount = (new GetXValue()).calculate(game, source, this); + int amount = (GetXValue.instance).calculate(game, source, this); if (you != null) { if (!source.getTargets().isEmpty()) { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { @@ -85,9 +89,6 @@ class FirestormEffect extends OneShotEffect { } return false; } - - - @Override public FirestormEffect copy() { diff --git a/Mage.Sets/src/mage/cards/f/FissureVent.java b/Mage.Sets/src/mage/cards/f/FissureVent.java index 4ebdfecea7..b874f6eaf8 100644 --- a/Mage.Sets/src/mage/cards/f/FissureVent.java +++ b/Mage.Sets/src/mage/cards/f/FissureVent.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -10,25 +8,26 @@ import mage.constants.CardType; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetNonBasicLandPermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class FissureVent extends CardImpl { public FissureVent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}"); // Choose one or both - Destroy target artifact; and/or destroy target nonbasic land. this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); Mode mode1 = new Mode(); - mode1.getTargets().add(new TargetNonBasicLandPermanent()); - mode1.getEffects().add(new DestroyTargetEffect()); + mode1.addEffect(new DestroyTargetEffect()); + mode1.addTarget(new TargetNonBasicLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java b/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java index 674adbeb78..522d33e117 100644 --- a/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java +++ b/Mage.Sets/src/mage/cards/f/FlagstonesOfTrokair.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.mana.WhiteManaAbility; @@ -14,8 +12,9 @@ import mage.filter.common.FilterLandCard; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FlagstonesOfTrokair extends CardImpl { @@ -34,7 +33,7 @@ public final class FlagstonesOfTrokair extends CardImpl { this.addAbility(new WhiteManaAbility()); // When Flagstones of Trokair is put into a graveyard from the battlefield, you may search your library for a Plains card and put it onto the battlefield tapped. If you do, shuffle your library. - this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(FILTER), true, false), true)); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(FILTER), true, false), true, false)); } public FlagstonesOfTrokair(final FlagstonesOfTrokair card) { diff --git a/Mage.Sets/src/mage/cards/f/FlameKinWarScout.java b/Mage.Sets/src/mage/cards/f/FlameKinWarScout.java index f255bdf536..73580ab86c 100644 --- a/Mage.Sets/src/mage/cards/f/FlameKinWarScout.java +++ b/Mage.Sets/src/mage/cards/f/FlameKinWarScout.java @@ -29,7 +29,7 @@ public final class FlameKinWarScout extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FlameKinWarScout(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/Flamebreak.java b/Mage.Sets/src/mage/cards/f/Flamebreak.java index f80450b3a6..1e834bd05a 100644 --- a/Mage.Sets/src/mage/cards/f/Flamebreak.java +++ b/Mage.Sets/src/mage/cards/f/Flamebreak.java @@ -76,7 +76,7 @@ class FlamebreakCantRegenerateEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.REGENERATE) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(event.getTargetId(), game); } diff --git a/Mage.Sets/src/mage/cards/f/FlamerushRider.java b/Mage.Sets/src/mage/cards/f/FlamerushRider.java index e6ed2e29da..be2c67e9fd 100644 --- a/Mage.Sets/src/mage/cards/f/FlamerushRider.java +++ b/Mage.Sets/src/mage/cards/f/FlamerushRider.java @@ -35,8 +35,8 @@ public final class FlamerushRider extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target attacking creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new AttackingPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(AttackingPredicate.instance); } public FlamerushRider(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FlamesOfTheRazeBoar.java b/Mage.Sets/src/mage/cards/f/FlamesOfTheRazeBoar.java new file mode 100644 index 0000000000..35f5be6fd2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FlamesOfTheRazeBoar.java @@ -0,0 +1,80 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.hint.common.FerociousHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FlamesOfTheRazeBoar extends CardImpl { + + public FlamesOfTheRazeBoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{5}{R}"); + + // Flames of the Raze-Boar deals 4 damage to target creature an opponent controls. Then Flames of the Raze-Boar deals 2 damage to each other creature that player controls if you control a creature with power 4 or greater. + this.getSpellAbility().addEffect(new FlamesOfTheRazeBoarEffect()); + this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent()); + this.getSpellAbility().addHint(FerociousHint.instance); + } + + private FlamesOfTheRazeBoar(final FlamesOfTheRazeBoar card) { + super(card); + } + + @Override + public FlamesOfTheRazeBoar copy() { + return new FlamesOfTheRazeBoar(this); + } +} + +class FlamesOfTheRazeBoarEffect extends OneShotEffect { + + FlamesOfTheRazeBoarEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 4 damage to target creature an opponent controls. " + + "Then {this} deals 2 damage to each other creature that player controls " + + "if you control a creature with power 4 or greater."; + } + + private FlamesOfTheRazeBoarEffect(final FlamesOfTheRazeBoarEffect effect) { + super(effect); + } + + @Override + public FlamesOfTheRazeBoarEffect copy() { + return new FlamesOfTheRazeBoarEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.damage(4, source.getSourceId(), game); + if (!FerociousCondition.instance.apply(game, source)) { + return true; + } + FilterPermanent filter = new FilterCreaturePermanent(); + filter.add(new ControllerIdPredicate(permanent.getControllerId())); + filter.add(Predicates.not(new PermanentIdPredicate(permanent.getId()))); + return new DamageAllEffect(2, filter).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java b/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java index c490eb8191..9db0cd3935 100644 --- a/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java +++ b/Mage.Sets/src/mage/cards/f/FlameshadowConjuring.java @@ -33,7 +33,7 @@ public final class FlameshadowConjuring extends CardImpl { private static final FilterControlledCreaturePermanent filterNontoken = new FilterControlledCreaturePermanent("nontoken creature"); static { - filterNontoken.add(Predicates.not(new TokenPredicate())); + filterNontoken.add(Predicates.not(TokenPredicate.instance)); } public FlameshadowConjuring(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FlamewakePhoenix.java b/Mage.Sets/src/mage/cards/f/FlamewakePhoenix.java index 5f806e6506..28d008efd6 100644 --- a/Mage.Sets/src/mage/cards/f/FlamewakePhoenix.java +++ b/Mage.Sets/src/mage/cards/f/FlamewakePhoenix.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksEachCombatStaticAbility; import mage.abilities.common.BeginningOfCombatTriggeredAbility; @@ -10,6 +8,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlSourceEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; @@ -19,8 +18,9 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FlamewakePhoenix extends CardImpl { @@ -46,7 +46,7 @@ public final class FlamewakePhoenix extends CardImpl { TargetController.YOU, false, false), FerociousCondition.instance, "Ferocious — At the beginning of combat on your turn, if you control a creature with power 4 or greater, you may pay {R}. If you do, return {this} from your graveyard to the battlefield." - )); + ).addHint(FerociousHint.instance)); } public FlamewakePhoenix(final FlamewakePhoenix card) { diff --git a/Mage.Sets/src/mage/cards/f/FlashFlood.java b/Mage.Sets/src/mage/cards/f/FlashFlood.java index 40a32ebe3b..7a5ab5d8ec 100644 --- a/Mage.Sets/src/mage/cards/f/FlashFlood.java +++ b/Mage.Sets/src/mage/cards/f/FlashFlood.java @@ -37,8 +37,8 @@ public final class FlashFlood extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or return target Mountain to its owner's hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter2)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FlashFoliage.java b/Mage.Sets/src/mage/cards/f/FlashFoliage.java index 2460dffc86..a2c013efba 100644 --- a/Mage.Sets/src/mage/cards/f/FlashFoliage.java +++ b/Mage.Sets/src/mage/cards/f/FlashFoliage.java @@ -18,7 +18,7 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.SaprolingToken; import mage.game.permanent.token.Token; import mage.players.Player; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/f/FlashOfInsight.java b/Mage.Sets/src/mage/cards/f/FlashOfInsight.java index 7303d86cc3..2ea61b3c83 100644 --- a/Mage.Sets/src/mage/cards/f/FlashOfInsight.java +++ b/Mage.Sets/src/mage/cards/f/FlashOfInsight.java @@ -87,8 +87,7 @@ class FlashOfInsightEffect extends OneShotEffect { } } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, xValue)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); controller.lookAtCards(sourceObject.getIdName(), cards, game); TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); diff --git a/Mage.Sets/src/mage/cards/f/FlayerDrone.java b/Mage.Sets/src/mage/cards/f/FlayerDrone.java index 19482d906b..548e19f018 100644 --- a/Mage.Sets/src/mage/cards/f/FlayerDrone.java +++ b/Mage.Sets/src/mage/cards/f/FlayerDrone.java @@ -27,8 +27,8 @@ public final class FlayerDrone extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public FlayerDrone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FlayingTendrils.java b/Mage.Sets/src/mage/cards/f/FlayingTendrils.java index 03e6617535..4531b66035 100644 --- a/Mage.Sets/src/mage/cards/f/FlayingTendrils.java +++ b/Mage.Sets/src/mage/cards/f/FlayingTendrils.java @@ -67,7 +67,7 @@ class FlayingTendrilsReplacementEffect extends ReplacementEffectImpl { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && permanent != null) { - return controller.moveCards((Card) permanent, Zone.EXILED, source, game); + return controller.moveCards(permanent, Zone.EXILED, source, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/f/FleshAllergy.java b/Mage.Sets/src/mage/cards/f/FleshAllergy.java index fb92c9a5c1..1ea3c3d811 100644 --- a/Mage.Sets/src/mage/cards/f/FleshAllergy.java +++ b/Mage.Sets/src/mage/cards/f/FleshAllergy.java @@ -54,13 +54,13 @@ public final class FleshAllergy extends CardImpl { class FleshAllergyWatcher extends Watcher { - public int creaturesDiedThisTurn = 0; + private int creaturesDiedThisTurn = 0; public FleshAllergyWatcher() { - super(FleshAllergyWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public FleshAllergyWatcher(final FleshAllergyWatcher watcher) { + private FleshAllergyWatcher(final FleshAllergyWatcher watcher) { super(watcher); } @@ -79,6 +79,10 @@ class FleshAllergyWatcher extends Watcher { } } + public int getCreaturesDiedThisTurn(){ + return creaturesDiedThisTurn; + } + @Override public void reset() { super.reset(); @@ -94,7 +98,7 @@ class FleshAllergyEffect extends OneShotEffect { staticText = "Its controller loses life equal to the number of creatures that died this turn"; } - public FleshAllergyEffect(final FleshAllergyEffect effect) { + private FleshAllergyEffect(final FleshAllergyEffect effect) { super(effect); } @@ -105,12 +109,12 @@ class FleshAllergyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - FleshAllergyWatcher watcher = (FleshAllergyWatcher) game.getState().getWatchers().get(FleshAllergyWatcher.class.getSimpleName()); + FleshAllergyWatcher watcher = game.getState().getWatcher(FleshAllergyWatcher.class); Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); if (permanent != null && watcher != null) { Player player = game.getPlayer(permanent.getControllerId()); if (player != null) { - int amount = watcher.creaturesDiedThisTurn; + int amount = watcher.getCreaturesDiedThisTurn(); if (amount > 0) { player.loseLife(amount, game, false); return true; diff --git a/Mage.Sets/src/mage/cards/f/FleshmadSteed.java b/Mage.Sets/src/mage/cards/f/FleshmadSteed.java index 491b9ce5f1..8b8a9ca914 100644 --- a/Mage.Sets/src/mage/cards/f/FleshmadSteed.java +++ b/Mage.Sets/src/mage/cards/f/FleshmadSteed.java @@ -20,7 +20,7 @@ public final class FleshmadSteed extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public FleshmadSteed(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/Fleshwrither.java b/Mage.Sets/src/mage/cards/f/Fleshwrither.java index 7fd31d85a2..a9f58feaad 100644 --- a/Mage.Sets/src/mage/cards/f/Fleshwrither.java +++ b/Mage.Sets/src/mage/cards/f/Fleshwrither.java @@ -74,7 +74,7 @@ class FleshwritherEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard("creature with converted mana cost " + sourceObject.getConvertedManaCost()); filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, sourceObject.getConvertedManaCost())); TargetCardInLibrary target = new TargetCardInLibrary(1, filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards chosen = new CardsImpl(target.getTargets()); controller.moveCards(chosen, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/f/Flicker.java b/Mage.Sets/src/mage/cards/f/Flicker.java index b463128152..dd16b1d1cb 100644 --- a/Mage.Sets/src/mage/cards/f/Flicker.java +++ b/Mage.Sets/src/mage/cards/f/Flicker.java @@ -21,7 +21,7 @@ public final class Flicker extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("nontoken permanent"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public Flicker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/Flickerform.java b/Mage.Sets/src/mage/cards/f/Flickerform.java index 550ae27ce6..0f0ef9da3e 100644 --- a/Mage.Sets/src/mage/cards/f/Flickerform.java +++ b/Mage.Sets/src/mage/cards/f/Flickerform.java @@ -156,39 +156,44 @@ class FlickerformReturnEffect extends OneShotEffect { } ExileZone exileZone = game.getExile().getExileZone(exileZoneId); Card enchantedCard = exileZone.get(enchantedCardId, game); + //skip if exiled card is missing if (enchantedCard != null) { - controller.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game); - Permanent newPermanent = game.getPermanent(enchantedCardId); - if (newPermanent != null) { - Set toBattlefieldAttached = new HashSet(); - for (Card enchantment : exileZone.getCards(game)) { - if (filterAura.match(enchantment, game)) { - boolean canTarget = false; - for (Target target : enchantment.getSpellAbility().getTargets()) { - Filter filter = target.getFilter(); - if (filter.match(newPermanent, game)) { - canTarget = true; - break; + Player owner = game.getPlayer(enchantedCard.getOwnerId()); + //skip if card's owner is missing + if (owner != null) { + owner.moveCards(enchantedCard, Zone.BATTLEFIELD, source, game); + Permanent newPermanent = game.getPermanent(enchantedCardId); + if (newPermanent != null) { + Set toBattlefieldAttached = new HashSet(); + for (Card enchantment : exileZone.getCards(game)) { + if (filterAura.match(enchantment, game)) { + boolean canTarget = false; + for (Target target : enchantment.getSpellAbility().getTargets()) { + Filter filter = target.getFilter(); + if (filter.match(newPermanent, game)) { + canTarget = true; + break; + } + } + if (!canTarget) { + // Aura stays exiled + continue; + } + game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent); + } + toBattlefieldAttached.add(enchantment); + } + if (!toBattlefieldAttached.isEmpty()) { + controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game); + for (Card card : toBattlefieldAttached) { + if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) { + newPermanent.addAttachment(card.getId(), game); } } - if (!canTarget) { - // Aura stays exiled - continue; - } - game.getState().setValue("attachTo:" + enchantment.getId(), newPermanent); - } - toBattlefieldAttached.add(enchantment); - } - if (!toBattlefieldAttached.isEmpty()) { - controller.moveCards(toBattlefieldAttached, Zone.BATTLEFIELD, source, game); - for (Card card : toBattlefieldAttached) { - if (game.getState().getZone(card.getId()) == Zone.BATTLEFIELD) { - newPermanent.addAttachment(card.getId(), game); - } } } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/f/Flickerwisp.java b/Mage.Sets/src/mage/cards/f/Flickerwisp.java index 828b1b8d3b..b4af63cae7 100644 --- a/Mage.Sets/src/mage/cards/f/Flickerwisp.java +++ b/Mage.Sets/src/mage/cards/f/Flickerwisp.java @@ -33,7 +33,7 @@ public final class Flickerwisp extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Flickerwisp(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/Fling.java b/Mage.Sets/src/mage/cards/f/Fling.java index 422ec3263e..67de60eca9 100644 --- a/Mage.Sets/src/mage/cards/f/Fling.java +++ b/Mage.Sets/src/mage/cards/f/Fling.java @@ -22,7 +22,7 @@ public final class Fling extends CardImpl { public Fling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); - Effect effect = new DamageTargetEffect(new SacrificeCostCreaturesPower()); + Effect effect = new DamageTargetEffect(SacrificeCostCreaturesPower.instance); effect.setText("{this} deals damage equal to the sacrificed creature's power to any target"); this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); this.getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/f/FloatingDreamZubera.java b/Mage.Sets/src/mage/cards/f/FloatingDreamZubera.java index a5aa32a32a..f2e77e0b50 100644 --- a/Mage.Sets/src/mage/cards/f/FloatingDreamZubera.java +++ b/Mage.Sets/src/mage/cards/f/FloatingDreamZubera.java @@ -25,7 +25,7 @@ public final class FloatingDreamZubera extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(2); - this.addAbility(new DiesTriggeredAbility(new DrawCardSourceControllerEffect(new ZuberasDiedDynamicValue())), new ZuberasDiedWatcher()); + this.addAbility(new DiesTriggeredAbility(new DrawCardSourceControllerEffect(ZuberasDiedDynamicValue.instance)), new ZuberasDiedWatcher()); } public FloatingDreamZubera(final FloatingDreamZubera card) { diff --git a/Mage.Sets/src/mage/cards/f/FlockOfRabidSheep.java b/Mage.Sets/src/mage/cards/f/FlockOfRabidSheep.java index 79ac3e5e97..018f5f3b23 100644 --- a/Mage.Sets/src/mage/cards/f/FlockOfRabidSheep.java +++ b/Mage.Sets/src/mage/cards/f/FlockOfRabidSheep.java @@ -59,7 +59,7 @@ class FlockOfRabidSheepEffect extends OneShotEffect { int repeat = source.getManaCostsToPay().getX(); int wonCount = 0; for (int i = 1; i <= repeat; i++) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { wonCount++; } } diff --git a/Mage.Sets/src/mage/cards/f/FloralSpuzzem.java b/Mage.Sets/src/mage/cards/f/FloralSpuzzem.java index c418a87926..8fde7de47c 100644 --- a/Mage.Sets/src/mage/cards/f/FloralSpuzzem.java +++ b/Mage.Sets/src/mage/cards/f/FloralSpuzzem.java @@ -27,7 +27,7 @@ public final class FloralSpuzzem extends CardImpl { static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public FloralSpuzzem(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/FloweringLumberknot.java b/Mage.Sets/src/mage/cards/f/FloweringLumberknot.java index 22c57fd9a6..990443b39d 100644 --- a/Mage.Sets/src/mage/cards/f/FloweringLumberknot.java +++ b/Mage.Sets/src/mage/cards/f/FloweringLumberknot.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,19 +8,21 @@ import mage.abilities.keyword.SoulbondAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** * @author noxx */ public final class FloweringLumberknot extends CardImpl { public FloweringLumberknot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.TREEFOLK); this.power = new MageInt(5); @@ -66,9 +66,8 @@ class FloweringLumberknotEffect extends RestrictionEffect { break; } } - if (found) { - return false;// paired => can attack or block - } + // paired => can attack or block + return !found; } } // can't attack or block @@ -79,12 +78,12 @@ class FloweringLumberknotEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/f/FlowstoneSlide.java b/Mage.Sets/src/mage/cards/f/FlowstoneSlide.java index 479d9f124b..fe68ae63e8 100644 --- a/Mage.Sets/src/mage/cards/f/FlowstoneSlide.java +++ b/Mage.Sets/src/mage/cards/f/FlowstoneSlide.java @@ -20,8 +20,8 @@ public final class FlowstoneSlide extends CardImpl { public FlowstoneSlide(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{2}{R}{R}"); - DynamicValue xPos = new ManacostVariableValue(); - DynamicValue xNeg = new SignInversionDynamicValue(new ManacostVariableValue()); + DynamicValue xPos = ManacostVariableValue.instance; + DynamicValue xNeg = new SignInversionDynamicValue(ManacostVariableValue.instance); // All creatures get +X/-X until end of turn. this.getSpellAbility().addEffect(new BoostAllEffect(xPos, xNeg, Duration.EndOfTurn)); diff --git a/Mage.Sets/src/mage/cards/f/FluxChanneler.java b/Mage.Sets/src/mage/cards/f/FluxChanneler.java new file mode 100644 index 0000000000..db14684b2f --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FluxChanneler.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FluxChanneler extends CardImpl { + + public FluxChanneler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a noncreature spell, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new SpellCastControllerTriggeredAbility( + new ProliferateEffect(), StaticFilters.FILTER_SPELL_NON_CREATURE, false + )); + } + + private FluxChanneler(final FluxChanneler card) { + super(card); + } + + @Override + public FluxChanneler copy() { + return new FluxChanneler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/Fluxcharger.java b/Mage.Sets/src/mage/cards/f/Fluxcharger.java index fecfe06e92..5f31edb2b6 100644 --- a/Mage.Sets/src/mage/cards/f/Fluxcharger.java +++ b/Mage.Sets/src/mage/cards/f/Fluxcharger.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.continuous.SwitchPowerToughnessSourceEffect; @@ -9,18 +7,19 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Fluxcharger extends CardImpl { public Fluxcharger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{R}"); this.subtype.add(SubType.WEIRD); this.power = new MageInt(1); @@ -29,7 +28,7 @@ public final class Fluxcharger extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever you cast an instant or sorcery spell, you may switch Fluxcharger's power and toughness until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, true)); + this.addAbility(new SpellCastControllerTriggeredAbility(new SwitchPowerToughnessSourceEffect(Duration.EndOfTurn), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, true)); } diff --git a/Mage.Sets/src/mage/cards/f/FolkMedicine.java b/Mage.Sets/src/mage/cards/f/FolkMedicine.java index f89a831614..ec8785eb2e 100644 --- a/Mage.Sets/src/mage/cards/f/FolkMedicine.java +++ b/Mage.Sets/src/mage/cards/f/FolkMedicine.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -11,19 +9,20 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TimingRule; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author fireshoes */ public final class FolkMedicine extends CardImpl { public FolkMedicine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); // You gain 1 life for each creature you control. - DynamicValue amount = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); + DynamicValue amount = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); this.getSpellAbility().addEffect(new GainLifeEffect(amount)); // Flashback {1}{W} this.addAbility(new FlashbackAbility(new ManaCostsImpl("{1}{W}"), TimingRule.INSTANT)); diff --git a/Mage.Sets/src/mage/cards/f/FontOfAgonies.java b/Mage.Sets/src/mage/cards/f/FontOfAgonies.java new file mode 100644 index 0000000000..4abcc4eb09 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FontOfAgonies.java @@ -0,0 +1,83 @@ +package mage.cards.f; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FontOfAgonies extends CardImpl { + + public FontOfAgonies(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); + + // Whenever you pay life, put that many blood counters on Font of Agonies. + this.addAbility(new FontOfAgoniesTriggeredAbility()); + + // {1}{B}, Remove four blood counters from Font of Agonies: Destroy target creature. + Ability ability = new SimpleActivatedAbility(new DestroyTargetEffect(), new ManaCostsImpl("{1}{B}")); + ability.addCost(new RemoveCountersSourceCost(CounterType.BLOOD.createInstance(4))); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private FontOfAgonies(final FontOfAgonies card) { + super(card); + } + + @Override + public FontOfAgonies copy() { + return new FontOfAgonies(this); + } +} + +class FontOfAgoniesTriggeredAbility extends TriggeredAbilityImpl { + + FontOfAgoniesTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.BLOOD.createInstance()), false); + } + + private FontOfAgoniesTriggeredAbility(final FontOfAgoniesTriggeredAbility ability) { + super(ability); + } + + @Override + public FontOfAgoniesTriggeredAbility copy() { + return new FontOfAgoniesTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType().equals(GameEvent.EventType.LIFE_PAID); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(controllerId) && event.getAmount() > 0) { + this.getEffects().clear(); + this.addEffect(new AddCountersSourceEffect(CounterType.BLOOD.createInstance(event.getAmount()))); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you pay life, put that many blood counters on {this}."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FootlightFiend.java b/Mage.Sets/src/mage/cards/f/FootlightFiend.java new file mode 100644 index 0000000000..6d7d41f979 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FootlightFiend.java @@ -0,0 +1,41 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FootlightFiend extends CardImpl { + + public FootlightFiend(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B/R}"); + + this.subtype.add(SubType.DEVIL); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Footlight Fiend dies, it deals 1 damage to any target. + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(1, "it")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private FootlightFiend(final FootlightFiend card) { + super(card); + } + + @Override + public FootlightFiend copy() { + return new FootlightFiend(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java b/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java new file mode 100644 index 0000000000..b96e38211d --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForbiddingSpirit.java @@ -0,0 +1,47 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.common.combat.CantAttackYouUnlessPayManaAllEffect; +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 ForbiddingSpirit extends CardImpl { + + public ForbiddingSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Forbidding Spirit enters the battlefield, until your next turn, creatures can't attack you or a planeswalker you control unless their controller pays {2} for each of those creatures. + ContinuousEffect effect = new CantAttackYouUnlessPayManaAllEffect( + new ManaCostsImpl("{2}"), true + ); + effect.setDuration(Duration.UntilYourNextTurn); + effect.setText("until your next turn, creatures can't attack you or a planeswalker you control " + + "unless their controller pays {2} for each of those creatures."); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect)); + } + + private ForbiddingSpirit(final ForbiddingSpirit card) { + super(card); + } + + @Override + public ForbiddingSpirit copy() { + return new ForbiddingSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForceAway.java b/Mage.Sets/src/mage/cards/f/ForceAway.java index 186de960f8..766dc39d9f 100644 --- a/Mage.Sets/src/mage/cards/f/ForceAway.java +++ b/Mage.Sets/src/mage/cards/f/ForceAway.java @@ -1,34 +1,35 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ForceAway extends CardImpl { public ForceAway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Return target creature to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Ferocious — If you control a creature with power 4 or greater, you may draw a card. If you do, discard a card. - Effect effect = new ConditionalOneShotEffect(new DrawDiscardControllerEffect(1,1, true), - FerociousCondition.instance , "
    Ferocious — If you control a creature with power 4 or greater, you may draw a card. If you do, discard a card"); + Effect effect = new ConditionalOneShotEffect(new DrawDiscardControllerEffect(1, 1, true), + FerociousCondition.instance, "
    Ferocious — If you control a creature with power 4 or greater, you may draw a card. If you do, discard a card"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addHint(FerociousHint.instance); } public ForceAway(final ForceAway card) { diff --git a/Mage.Sets/src/mage/cards/f/ForceLightning.java b/Mage.Sets/src/mage/cards/f/ForceLightning.java index 64b07aa29d..46793dcd5d 100644 --- a/Mage.Sets/src/mage/cards/f/ForceLightning.java +++ b/Mage.Sets/src/mage/cards/f/ForceLightning.java @@ -24,7 +24,7 @@ public final class ForceLightning extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}"); // Force Lightning deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); // Scry X. diff --git a/Mage.Sets/src/mage/cards/f/ForceStasis.java b/Mage.Sets/src/mage/cards/f/ForceStasis.java index ed4e6e25ae..bca7faa324 100644 --- a/Mage.Sets/src/mage/cards/f/ForceStasis.java +++ b/Mage.Sets/src/mage/cards/f/ForceStasis.java @@ -43,8 +43,8 @@ public final class ForceStasis extends CardImpl { // Return target instant or sorcery spell you don't control to its owner's hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetSpell(filter)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetSpell(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/ForcedLanding.java b/Mage.Sets/src/mage/cards/f/ForcedLanding.java new file mode 100644 index 0000000000..fe46b1c5ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForcedLanding.java @@ -0,0 +1,42 @@ +package mage.cards.f; + +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ForcedLanding extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public ForcedLanding(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Put target creature with flying on the bottom of its owner's library. + this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(false)); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private ForcedLanding(final ForcedLanding card) { + super(card); + } + + @Override + public ForcedLanding copy() { + return new ForcedLanding(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/Forcefield.java b/Mage.Sets/src/mage/cards/f/Forcefield.java index e225e7c328..9534b45eb5 100644 --- a/Mage.Sets/src/mage/cards/f/Forcefield.java +++ b/Mage.Sets/src/mage/cards/f/Forcefield.java @@ -53,7 +53,7 @@ class ForcefieldEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("an unblocked creature"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } ForcefieldEffect() { diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java index 710d7d1297..558a0caccb 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfSlaughter.java @@ -25,10 +25,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class ForerunnerOfSlaughter extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public ForerunnerOfSlaughter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java index bb62690e7d..1cd38f8a52 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheCoalition.java @@ -26,7 +26,7 @@ public final class ForerunnerOfTheCoalition extends CardImpl { private static final FilterPermanent filterAnotherPirate = new FilterPermanent(SubType.PIRATE, "another " + SubType.PIRATE.toString()); static { - filterAnotherPirate.add(new AnotherPredicate()); + filterAnotherPirate.add(AnotherPredicate.instance); filterAnotherPirate.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java index a2789bf555..a33e5bfc1b 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheEmpire.java @@ -1,23 +1,26 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.common.FilterBySubtypeCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author JayDi85 */ public final class ForerunnerOfTheEmpire extends CardImpl { @@ -49,12 +52,11 @@ public final class ForerunnerOfTheEmpire extends CardImpl { ); // Whenever a Dinosaur enters the battlefield under your control, you may have Forerunner of the Empire deal 1 damage to each creature. - Ability ability = new CreatureEntersBattlefieldTriggeredAbility( + Ability ability = new EntersBattlefieldControlledTriggeredAbility( Zone.BATTLEFIELD, new DamageAllEffect(1, new FilterCreaturePermanent()).setText("have {this} deal 1 damage to each creature"), filterAnyDinosaur, - true, - false); + true); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java index c1eef1e04d..1a161bba1c 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheHeralds.java @@ -28,7 +28,7 @@ public final class ForerunnerOfTheHeralds extends CardImpl { private static final FilterPermanent filterAnotherMerfolk = new FilterPermanent(SubType.MERFOLK, "another " + SubType.MERFOLK.toString()); static { - filterAnotherMerfolk.add(new AnotherPredicate()); + filterAnotherMerfolk.add(AnotherPredicate.instance); filterAnotherMerfolk.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java index 2ada4b8d5a..f5efb3eea3 100644 --- a/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java +++ b/Mage.Sets/src/mage/cards/f/ForerunnerOfTheLegion.java @@ -26,7 +26,7 @@ public final class ForerunnerOfTheLegion extends CardImpl { private static final FilterPermanent filterAnotherVampire = new FilterPermanent(SubType.VAMPIRE, "another " + SubType.VAMPIRE.toString()); static { - filterAnotherVampire.add(new AnotherPredicate()); + filterAnotherVampire.add(AnotherPredicate.instance); filterAnotherVampire.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/f/Foresee.java b/Mage.Sets/src/mage/cards/f/Foresee.java index d9e6c20b29..52b112e3a0 100644 --- a/Mage.Sets/src/mage/cards/f/Foresee.java +++ b/Mage.Sets/src/mage/cards/f/Foresee.java @@ -1,25 +1,23 @@ - - package mage.cards.f; -import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class Foresee extends CardImpl { public Foresee(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); - this.getSpellAbility().addEffect(new ScryEffect(4)); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + this.getSpellAbility().addEffect(new ScryEffect(4).setText("scry 4,")); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).setText("then draw two cards")); } public Foresee(final Foresee card) { diff --git a/Mage.Sets/src/mage/cards/f/Foreshadow.java b/Mage.Sets/src/mage/cards/f/Foreshadow.java index 6299ff05b7..01fabc683e 100644 --- a/Mage.Sets/src/mage/cards/f/Foreshadow.java +++ b/Mage.Sets/src/mage/cards/f/Foreshadow.java @@ -1,13 +1,11 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseACardNameEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.abilities.effects.common.ChooseACardNameEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,21 +15,23 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron & L_J */ public final class Foreshadow extends CardImpl { public Foreshadow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Choose a card name, then target opponent puts the top card of their library into their graveyard. If that card has the chosen name, you draw a card. this.getSpellAbility().addEffect(new ChooseACardNameEffect(ChooseACardNameEffect.TypeOfName.ALL)); - this.getSpellAbility().addEffect(new ForeshadowEffect()); + this.getSpellAbility().addEffect(new ForeshadowEffect().concatBy("then")); this.getSpellAbility().addTarget(new TargetOpponent()); - + // Draw a card at the beginning of the next turn's upkeep. this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); @@ -51,7 +51,7 @@ class ForeshadowEffect extends OneShotEffect { public ForeshadowEffect() { super(Outcome.DrawCard); - this.staticText = ", then target opponent puts the top card of their library into their graveyard. If that card has the chosen name, you draw a card"; + this.staticText = "target opponent puts the top card of their library into their graveyard. If that card has the chosen name, you draw a card"; } public ForeshadowEffect(final ForeshadowEffect effect) { @@ -72,8 +72,8 @@ class ForeshadowEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { - controller.drawCards(1, game); + if (CardUtil.haveSameNames(card.getName(), cardName)) { + controller.drawCards(1, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/f/Foresight.java b/Mage.Sets/src/mage/cards/f/Foresight.java index b424fce3f6..296793c6bb 100644 --- a/Mage.Sets/src/mage/cards/f/Foresight.java +++ b/Mage.Sets/src/mage/cards/f/Foresight.java @@ -63,16 +63,16 @@ class ForesightEffect extends SearchEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player.searchLibrary(target, game)) { + if (player != null && player.searchLibrary(target, source, game)) { for (UUID targetId : getTargets()) { Card card = player.getLibrary().getCard(targetId, game); if (card != null) { card.moveToExile(null, null, targetId, game); } } + player.shuffleLibrary(source, game); return true; } - player.shuffleLibrary(source, game); return false; } diff --git a/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java b/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java new file mode 100644 index 0000000000..f6eff9d8ff --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/ForethoughtAmulet.java @@ -0,0 +1,91 @@ + +package mage.cards.f; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent; + +/** + * + * @author L_J + */ +public final class ForethoughtAmulet extends CardImpl { + + public ForethoughtAmulet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + // At the beginning of your upkeep, sacrifice Forethought Amulet unless you pay {3}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new GenericManaCost(3)), TargetController.YOU, false)); + + // If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ForethoughtAmuletEffect())); + } + + public ForethoughtAmulet(final ForethoughtAmulet card) { + super(card); + } + + @Override + public ForethoughtAmulet copy() { + return new ForethoughtAmulet(this); + } +} + +class ForethoughtAmuletEffect extends ReplacementEffectImpl { + + public ForethoughtAmuletEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "If an instant or sorcery source would deal 3 or more damage to you, it deals 2 damage to you instead"; + } + + public ForethoughtAmuletEffect(final ForethoughtAmuletEffect effect) { + super(effect); + } + + @Override + public ForethoughtAmuletEffect copy() { + return new ForethoughtAmuletEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getAmount() >= 3) { + MageObject object = game.getObject(event.getSourceId()); + return object != null && (object.isInstant() || object.isSorcery()); + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(source.getControllerId())) { + event.setAmount(2); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/f/ForgeOfHeroes.java b/Mage.Sets/src/mage/cards/f/ForgeOfHeroes.java index e3e24edaa2..b745f92800 100644 --- a/Mage.Sets/src/mage/cards/f/ForgeOfHeroes.java +++ b/Mage.Sets/src/mage/cards/f/ForgeOfHeroes.java @@ -29,7 +29,7 @@ public final class ForgeOfHeroes extends CardImpl { = new FilterPermanent("commander that entered the battlefield this turn"); static { - filter.add(new CommanderPredicate()); + filter.add(CommanderPredicate.instance); filter.add(new EnteredThisTurnPredicate()); } diff --git a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java index 6693a73de1..17c36972bf 100644 --- a/Mage.Sets/src/mage/cards/f/ForgottenAncient.java +++ b/Mage.Sets/src/mage/cards/f/ForgottenAncient.java @@ -10,11 +10,7 @@ import mage.abilities.effects.OneShotEffect; 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.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -29,17 +25,17 @@ import java.util.List; import java.util.UUID; /** - * * @author Blinke */ public final class ForgottenAncient extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ForgottenAncient(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(0); this.toughness = new MageInt(3); @@ -48,7 +44,7 @@ public final class ForgottenAncient extends CardImpl { Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance()); Ability ability = new SpellCastAllTriggeredAbility(effect, true); this.addAbility(ability); - + // At the beginning of your upkeep, you may move any number of +1/+1 counters from Forgotten Ancient onto other creatures. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ForgottenAncientEffect(), TargetController.YOU, true)); } @@ -61,70 +57,79 @@ public final class ForgottenAncient extends CardImpl { public ForgottenAncient copy() { return new ForgottenAncient(this); } - + class CounterMovement { public UUID target; public int counters; } - + class ForgottenAncientEffect extends OneShotEffect { - + public ForgottenAncientEffect() { super(Outcome.Benefit); this.staticText = "you may move any number of +1/+1 counters from {this} onto other creatures."; } - + public ForgottenAncientEffect(final ForgottenAncientEffect effect) { super(effect); } - + @Override public ForgottenAncientEffect copy() { return new ForgottenAncientEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if(controller == null || sourcePermanent == null) { + if (controller == null || sourcePermanent == null) { return false; } - + int numCounters = sourcePermanent.getCounters(game).getCount(CounterType.P1P1); + if (numCounters == 0) { + return false; + } + List counterMovements = new ArrayList<>(); - + do { Target target = new TargetCreaturePermanent(1, 1, filter, true); - if(numCounters == 0 || !target.choose(Outcome.Benefit, source.getControllerId(), source.getSourceId(), game)) { - continue; + if (!target.canChoose(source.getSourceId(), controller.getId(), game)) { + break; + } + + if (!target.choose(Outcome.BoostCreature, source.getControllerId(), source.getSourceId(), game)) { + break; } int amountToMove = controller.getAmount(0, numCounters, "How many counters do you want to move? " + '(' + numCounters + ')' + " counters remaining.", game); - if(amountToMove > 0) - { - boolean previouslyChosen = false; - for (CounterMovement cm : counterMovements) { - if(cm.target.equals(target.getFirstTarget())) - { - cm.counters += amountToMove; - previouslyChosen = true; - } - } - if(!previouslyChosen) { - CounterMovement cm = new CounterMovement(); - cm.target = target.getFirstTarget(); - cm.counters = amountToMove; - counterMovements.add(cm); - } - - numCounters -= amountToMove; + if (amountToMove == 0) { + break; } - } while(numCounters > 0 && controller.chooseUse(Outcome.Benefit, "Move additonal counters?", source, game)); - + + boolean previouslyChosen = false; + for (CounterMovement cm : counterMovements) { + if (cm.target.equals(target.getFirstTarget())) { + cm.counters += amountToMove; + previouslyChosen = true; + } + } + if (!previouslyChosen) { + CounterMovement cm = new CounterMovement(); + cm.target = target.getFirstTarget(); + cm.counters = amountToMove; + counterMovements.add(cm); + } + + numCounters -= amountToMove; + + } while (numCounters > 0 && controller.chooseUse(Outcome.Benefit, "Move additional counters?", source, game)); + //Move all the counters for each chosen creature - for(CounterMovement cm: counterMovements) { + for (CounterMovement cm : counterMovements) { sourcePermanent.removeCounters(CounterType.P1P1.createInstance(cm.counters), game); game.getPermanent(cm.target).addCounters(CounterType.P1P1.createInstance(cm.counters), source, game); } diff --git a/Mage.Sets/src/mage/cards/f/ForgottenLore.java b/Mage.Sets/src/mage/cards/f/ForgottenLore.java index 62ec82fcf4..8798d3f755 100644 --- a/Mage.Sets/src/mage/cards/f/ForgottenLore.java +++ b/Mage.Sets/src/mage/cards/f/ForgottenLore.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; @@ -18,14 +16,16 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetOpponent; + +import java.util.UUID; + /** - * * @author LoneFox */ public final class ForgottenLore extends CardImpl { public ForgottenLore(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Target opponent chooses a card in your graveyard. You may pay {G}. If you do, repeat this process except that opponent can't choose a card already chosen for Forgotten Lore. Then put the last chosen card into your hand. this.getSpellAbility().addEffect(new ForgottenLoreEffect()); @@ -62,8 +62,7 @@ class ForgottenLoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - if(you != null && opponent != null) - { + if (you != null && opponent != null) { FilterCard filter = new FilterCard(); filter.add(new OwnerIdPredicate(you.getId())); Cost cost = new ManaCostsImpl("{G}"); @@ -73,31 +72,31 @@ class ForgottenLoreEffect extends OneShotEffect { do { chosenCard = new TargetCardInGraveyard(filter); chosenCard.setNotTarget(true); - if(chosenCard.canChoose(opponent.getId(), game)) { + if (chosenCard.canChoose(opponent.getId(), game)) { opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); card = game.getCard(chosenCard.getFirstTarget()); - filter.add(Predicates.not(new CardIdPredicate(card.getId()))); - game.informPlayers("Forgotten Lore: " + opponent.getLogName() + " has chosen " + card.getLogName()); - } - else { + if (card != null) { + filter.add(Predicates.not(new CardIdPredicate(card.getId()))); + game.informPlayers("Forgotten Lore: " + opponent.getLogName() + " has chosen " + card.getLogName()); + } + } else { done = true; } - if(!done) { - if(cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {G} to choose a different card ?", source, game)) { + if (!done) { + if (cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {G} to choose a different card ?", source, game)) { cost.clearPaid(); - if(!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { + if (!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { done = true; } - } - else { + } else { done = true; } } - } while(!done); + } while (!done); - if(card != null) { + if (card != null) { Cards cardsToHand = new CardsImpl(); cardsToHand.add(card); you.moveCards(cardsToHand, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/f/ForiysianTotem.java b/Mage.Sets/src/mage/cards/f/ForiysianTotem.java index ce7ea5dacc..ee0c003374 100644 --- a/Mage.Sets/src/mage/cards/f/ForiysianTotem.java +++ b/Mage.Sets/src/mage/cards/f/ForiysianTotem.java @@ -28,7 +28,7 @@ import mage.game.permanent.token.Token; */ public final class ForiysianTotem extends CardImpl { - private final static String ruleText = "As long as {this} is a creature, it can block an additional creature each combat."; + private static final String ruleText = "As long as {this} is a creature, it can block an additional creature each combat."; public ForiysianTotem(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); diff --git a/Mage.Sets/src/mage/cards/f/Fork.java b/Mage.Sets/src/mage/cards/f/Fork.java index 3c1e610ac8..3c18033485 100644 --- a/Mage.Sets/src/mage/cards/f/Fork.java +++ b/Mage.Sets/src/mage/cards/f/Fork.java @@ -58,7 +58,7 @@ class ForkEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell != null) { + if (spell != null && controller != null) { Spell copy = spell.copySpell(source.getControllerId()); copy.getColor(game).setRed(true); game.getStack().push(copy); diff --git a/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java b/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java index d3f6c14c81..41be4c4330 100644 --- a/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java +++ b/Mage.Sets/src/mage/cards/f/ForkInTheRoad.java @@ -66,7 +66,7 @@ class ForkInTheRoadEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/f/Fortify.java b/Mage.Sets/src/mage/cards/f/Fortify.java index cf0a112bc3..5035a402d7 100644 --- a/Mage.Sets/src/mage/cards/f/Fortify.java +++ b/Mage.Sets/src/mage/cards/f/Fortify.java @@ -22,7 +22,7 @@ public final class Fortify extends CardImpl { // Choose one - Creatures you control get +2/+0 until end of turn; or creatures you control get +0/+2 until end of turn. this.getSpellAbility().addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn)); Mode mode = new Mode(); - mode.getEffects().add(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); + mode.addEffect(new BoostControlledEffect(0, 2, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FortuitousFind.java b/Mage.Sets/src/mage/cards/f/FortuitousFind.java index 7b4a1dfd77..7abe29c978 100644 --- a/Mage.Sets/src/mage/cards/f/FortuitousFind.java +++ b/Mage.Sets/src/mage/cards/f/FortuitousFind.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -11,8 +9,9 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class FortuitousFind extends CardImpl { @@ -26,12 +25,12 @@ public final class FortuitousFind extends CardImpl { // Return target artifact card from your graveyard to your hand.; this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterArtifactCard("artifact card from your graveyard")).withChooseHint("return to hand")); // or Return target creature card from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FortunesFavor.java b/Mage.Sets/src/mage/cards/f/FortunesFavor.java index 2ebbfbc103..2ff7942be0 100644 --- a/Mage.Sets/src/mage/cards/f/FortunesFavor.java +++ b/Mage.Sets/src/mage/cards/f/FortunesFavor.java @@ -64,13 +64,11 @@ class FortunesFavorEffect extends OneShotEffect { Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source)); MageObject sourceObject = source.getSourceObject(game); if (controller != null && targetOpponent != null && sourceObject != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); TargetCard target = new TargetCard(0, Integer.MAX_VALUE, Zone.LIBRARY, new FilterCard("cards for the face-down pile")); targetOpponent.choose(outcome, cards, target, game); - Cards faceDownPile = new CardsImpl(); - faceDownPile.addAll(target.getTargets()); + Cards faceDownPile = new CardsImpl(target.getTargets()); cards.removeAll(target.getTargets()); controller.revealCards(sourceObject.getIdName() + " - cards in face-up pile", cards, game); game.informPlayers(targetOpponent.getLogName() + " puts " + faceDownPile.size() + " card(s) into the face-down pile"); diff --git a/Mage.Sets/src/mage/cards/f/FoulTongueInvocation.java b/Mage.Sets/src/mage/cards/f/FoulTongueInvocation.java index 629c797974..cb2a1d7d70 100644 --- a/Mage.Sets/src/mage/cards/f/FoulTongueInvocation.java +++ b/Mage.Sets/src/mage/cards/f/FoulTongueInvocation.java @@ -1,15 +1,14 @@ package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.RevealTargetFromHandCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.SacrificeEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityType; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -22,23 +21,19 @@ import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; import mage.watchers.common.DragonOnTheBattlefieldWhileSpellWasCastWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FoulTongueInvocation extends CardImpl { - private static final FilterCard filter = new FilterCard("a Dragon card from your hand (you don't have to)"); - - static { - filter.add(new SubtypePredicate(SubType.DRAGON)); - } - public FoulTongueInvocation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // As an additional cost to cast Foul-Tongue Invocation, you may reveal a Dragon card from your hand. this.getSpellAbility().addEffect(new InfoEffect("as an additional cost to cast this spell, you may reveal a Dragon card from your hand")); + this.getSpellAbility().setCostAdjuster(FoulTongueInvocationAdjuster.instance); // Target player sacrifices a creature. If you revealed a Dragon card or controlled a Dragon as you cast Foul-Tongue Invocation, you gain 4 life. this.getSpellAbility().addTarget(new TargetPlayer()); @@ -47,18 +42,6 @@ public final class FoulTongueInvocation extends CardImpl { this.getSpellAbility().addWatcher(new DragonOnTheBattlefieldWhileSpellWasCastWatcher()); } - @Override - public void adjustCosts(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - if (controller.getHand().count(filter, game) > 0) { - ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, 1, filter))); - } - } - } - } - public FoulTongueInvocation(final FoulTongueInvocation card) { super(card); } @@ -69,6 +52,25 @@ public final class FoulTongueInvocation extends CardImpl { } } +enum FoulTongueInvocationAdjuster implements CostAdjuster { + instance; + private static final FilterCard filter = new FilterCard("a Dragon card from your hand (you don't have to)"); + + static { + filter.add(new SubtypePredicate(SubType.DRAGON)); + } + + @Override + public void adjustCosts(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + if (controller.getHand().count(filter, game) > 0) { + ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, 1, filter))); + } + } + } +} + class FoulTongueInvocationEffect extends OneShotEffect { public FoulTongueInvocationEffect() { @@ -89,7 +91,7 @@ class FoulTongueInvocationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); if (watcher != null && watcher.castWithConditionTrue(source.getId())) { controller.gainLife(4, game, source); } diff --git a/Mage.Sets/src/mage/cards/f/FoundryChampion.java b/Mage.Sets/src/mage/cards/f/FoundryChampion.java index 235f269014..bdc56fb7bf 100644 --- a/Mage.Sets/src/mage/cards/f/FoundryChampion.java +++ b/Mage.Sets/src/mage/cards/f/FoundryChampion.java @@ -1,25 +1,25 @@ package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Plopman */ public final class FoundryChampion extends CardImpl { @@ -33,8 +33,9 @@ public final class FoundryChampion extends CardImpl { this.toughness = new MageInt(4); //When Foundry Champion enters the battlefield, it deals damage to any target equal to the number of creatures you control. - Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), "it")); + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(CreaturesYouControlCount.instance, "it")); ability.addTarget(new TargetAnyTarget()); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); //{R}: Foundry Champion gets +1/+0 until end of turn. diff --git a/Mage.Sets/src/mage/cards/f/FoundryHornet.java b/Mage.Sets/src/mage/cards/f/FoundryHornet.java index dc9eb22f34..86571157dc 100644 --- a/Mage.Sets/src/mage/cards/f/FoundryHornet.java +++ b/Mage.Sets/src/mage/cards/f/FoundryHornet.java @@ -28,7 +28,7 @@ import mage.filter.predicate.permanent.CounterPredicate; public final class FoundryHornet extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a creature with a +1/+1 counter on it"); - private final static FilterCreaturePermanent filterOpponent = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filterOpponent = new FilterCreaturePermanent(); static { filter.add(new CounterPredicate(CounterType.P1P1)); diff --git a/Mage.Sets/src/mage/cards/f/FoundryStreetDenizen.java b/Mage.Sets/src/mage/cards/f/FoundryStreetDenizen.java index 49fb798971..e60bfdec3b 100644 --- a/Mage.Sets/src/mage/cards/f/FoundryStreetDenizen.java +++ b/Mage.Sets/src/mage/cards/f/FoundryStreetDenizen.java @@ -27,7 +27,7 @@ public final class FoundryStreetDenizen extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another red creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new ColorPredicate(ObjectColor.RED)); } diff --git a/Mage.Sets/src/mage/cards/f/FountainOfCho.java b/Mage.Sets/src/mage/cards/f/FountainOfCho.java index 566c64e58f..1686099ab5 100644 --- a/Mage.Sets/src/mage/cards/f/FountainOfCho.java +++ b/Mage.Sets/src/mage/cards/f/FountainOfCho.java @@ -34,7 +34,7 @@ public final class FountainOfCho extends CardImpl { // {T}, Remove any number of storage counters from Fountain of Cho: Add {W} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.WhiteMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {W} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/f/FrayingSanity.java b/Mage.Sets/src/mage/cards/f/FrayingSanity.java index c53c85c054..501a6e021f 100644 --- a/Mage.Sets/src/mage/cards/f/FrayingSanity.java +++ b/Mage.Sets/src/mage/cards/f/FrayingSanity.java @@ -113,7 +113,7 @@ class FrayingSanityEffect extends OneShotEffect { } Player enchantedPlayer = game.getPlayer(enchantment.getAttachedTo()); if (enchantedPlayer != null) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); if (watcher != null) { xAmount = watcher.getAmountCardsPutToGraveyard(enchantedPlayer.getId()); } diff --git a/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java b/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java index 47310ccc4b..44fa863213 100644 --- a/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java +++ b/Mage.Sets/src/mage/cards/f/FreeRangeChicken.java @@ -75,7 +75,7 @@ class FreeRangeChickenEffect extends OneShotEffect { if (firstRoll == secondRoll) { game.addEffect(new BoostSourceEffect(firstRoll, firstRoll, Duration.EndOfTurn), source); } - FreeRangeChickenWatcher watcher = (FreeRangeChickenWatcher) game.getState().getWatchers().get(FreeRangeChickenWatcher.class.getSimpleName()); + FreeRangeChickenWatcher watcher = game.getState().getWatcher(FreeRangeChickenWatcher.class); if (watcher != null) { int totalRoll = firstRoll + secondRoll; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); @@ -98,7 +98,7 @@ class FreeRangeChickenWatcher extends Watcher { private final Map totalRolls = new HashMap<>(); public FreeRangeChickenWatcher() { - super(FreeRangeChickenWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public FreeRangeChickenWatcher(final FreeRangeChickenWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/f/FreneticEfreet.java b/Mage.Sets/src/mage/cards/f/FreneticEfreet.java index b2f407420b..e5d37014a0 100644 --- a/Mage.Sets/src/mage/cards/f/FreneticEfreet.java +++ b/Mage.Sets/src/mage/cards/f/FreneticEfreet.java @@ -69,7 +69,7 @@ class FreneticEfreetEffect extends OneShotEffect { if (controller == null) { return false; } - boolean flip = controller.flipCoin(game); + boolean flip = controller.flipCoin(source, game, true); if (permanent == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/f/FreneticSliver.java b/Mage.Sets/src/mage/cards/f/FreneticSliver.java index 6655f21dbd..e054ecb968 100644 --- a/Mage.Sets/src/mage/cards/f/FreneticSliver.java +++ b/Mage.Sets/src/mage/cards/f/FreneticSliver.java @@ -76,7 +76,7 @@ class FreneticSliverEffect extends OneShotEffect { if (player == null || perm == null) { return false; } - if (player.flipCoin(game)) { + if (player.flipCoin(source, game, true)) { return new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true).apply(game, source); } else { return perm.sacrifice(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/f/FrenziedArynx.java b/Mage.Sets/src/mage/cards/f/FrenziedArynx.java new file mode 100644 index 0000000000..26ceb3e0ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FrenziedArynx.java @@ -0,0 +1,51 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.RiotAbility; +import mage.abilities.keyword.TrampleAbility; +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 FrenziedArynx extends CardImpl { + + public FrenziedArynx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Riot + this.addAbility(new RiotAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // {4}{R}{G}: Frenzied Arynx gets +3/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(3, 0, Duration.EndOfTurn), + new ManaCostsImpl("{4}{R}{G}") + )); + } + + public FrenziedArynx(final FrenziedArynx card) { + super(card); + } + + @Override + public FrenziedArynx copy() { + return new FrenziedArynx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FreshMeat.java b/Mage.Sets/src/mage/cards/f/FreshMeat.java index 886d76becd..9938654926 100644 --- a/Mage.Sets/src/mage/cards/f/FreshMeat.java +++ b/Mage.Sets/src/mage/cards/f/FreshMeat.java @@ -41,7 +41,7 @@ class FreshMeatDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CreaturesDiedWatcher watcher = (CreaturesDiedWatcher) game.getState().getWatchers().get(CreaturesDiedWatcher.class.getSimpleName()); + CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class); if (watcher != null) { return watcher.getAmountOfCreaturesDiedThisTurnByController(sourceAbility.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/f/FretworkColony.java b/Mage.Sets/src/mage/cards/f/FretworkColony.java index 6c08fb8a16..5521f29bbb 100644 --- a/Mage.Sets/src/mage/cards/f/FretworkColony.java +++ b/Mage.Sets/src/mage/cards/f/FretworkColony.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -16,14 +14,15 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class FretworkColony extends CardImpl { public FretworkColony(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.INSECT); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -34,8 +33,7 @@ public final class FretworkColony extends CardImpl { // At the beginning of your upkeep, put a +1/+1 counter on Fretwork Colony and you lose 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.YOU, false); Effect effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability.addEffect(effect); + ability.addEffect(effect.concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/f/FreyaliseSupplicant.java b/Mage.Sets/src/mage/cards/f/FreyaliseSupplicant.java new file mode 100644 index 0000000000..3a0d18ab5c --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FreyaliseSupplicant.java @@ -0,0 +1,61 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.dynamicvalue.common.HalfValue; +import mage.abilities.dynamicvalue.common.SacrificeCostCreaturesPower; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class FreyaliseSupplicant extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("red or white creature"); + + static { + filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), + new ColorPredicate(ObjectColor.WHITE))); + } + + public FreyaliseSupplicant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {tap}, Sacrifice a red or white creature: Freyalise Supplicant deals damage to any target equal to half the sacrificed creature's power, rounded down. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new HalfValue(SacrificeCostCreaturesPower.instance, false)), new TapSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + + } + + private FreyaliseSupplicant(final FreyaliseSupplicant card) { + super(card); + } + + @Override + public FreyaliseSupplicant copy() { + return new FreyaliseSupplicant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FreyalisesCharm.java b/Mage.Sets/src/mage/cards/f/FreyalisesCharm.java index 2690555929..35a573cb4f 100644 --- a/Mage.Sets/src/mage/cards/f/FreyalisesCharm.java +++ b/Mage.Sets/src/mage/cards/f/FreyalisesCharm.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SpellCastOpponentTriggeredAbility; @@ -15,8 +13,9 @@ import mage.constants.CardType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class FreyalisesCharm extends CardImpl { @@ -33,7 +32,7 @@ public final class FreyalisesCharm extends CardImpl { // Whenever an opponent casts a black spell, you may pay {G}{G}. If you do, you draw a card. this.addAbility(new SpellCastOpponentTriggeredAbility( new DoIfCostPaid( - new DrawCardSourceControllerEffect(1), + new DrawCardSourceControllerEffect(1, "you"), new ManaCostsImpl("{G}{G}") ), filter, false )); diff --git a/Mage.Sets/src/mage/cards/f/FreyalisesWinds.java b/Mage.Sets/src/mage/cards/f/FreyalisesWinds.java new file mode 100644 index 0000000000..1c5b0a0922 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FreyalisesWinds.java @@ -0,0 +1,93 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BecomesTappedTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public final class FreyalisesWinds extends CardImpl { + + public FreyalisesWinds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); + + // Whenever a permanent becomes tapped, put a wind counter on it. + Effect effect = new AddCountersTargetEffect(CounterType.WIND.createInstance()); + effect.setText("put a wind counter on it."); + this.addAbility(new BecomesTappedTriggeredAbility(effect, false, new FilterPermanent("a permanent"), true)); + + // If a permanent with a wind counter on it would untap during its controller's untap step, remove all wind counters from it instead. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new FreyalisesWindsReplacementEffect())); + + } + + private FreyalisesWinds(final FreyalisesWinds card) { + super(card); + } + + @Override + public FreyalisesWinds copy() { + return new FreyalisesWinds(this); + } +} + +class FreyalisesWindsReplacementEffect extends ReplacementEffectImpl { + + FreyalisesWindsReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a permanent with a wind counter on it would untap during its controller's untap step, remove all wind counters from it instead"; + } + + FreyalisesWindsReplacementEffect(final FreyalisesWindsReplacementEffect effect) { + super(effect); + } + + @Override + public FreyalisesWindsReplacementEffect copy() { + return new FreyalisesWindsReplacementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent permanentUntapping = game.getPermanent(event.getTargetId()); + permanentUntapping.removeCounters(CounterType.WIND.createInstance(), game); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return (event.getType() == GameEvent.EventType.UNTAP + && game.getPhase().getStep().getType() == PhaseStep.UNTAP); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent permanentUntapping = game.getPermanent(event.getTargetId()); + return (permanentUntapping != null + && event.getPlayerId().equals(permanentUntapping.getControllerId()) + && permanentUntapping.getCounters(game).getCount(CounterType.WIND) > 0); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FriendlyFire.java b/Mage.Sets/src/mage/cards/f/FriendlyFire.java index 61212e644a..ca6ebfc24d 100644 --- a/Mage.Sets/src/mage/cards/f/FriendlyFire.java +++ b/Mage.Sets/src/mage/cards/f/FriendlyFire.java @@ -64,10 +64,9 @@ class FriendlyFireEffect extends OneShotEffect { Player controllerOfTargetCreature = game.getPlayer(targetCreature.getControllerId()); if (controllerOfTargetCreature != null) { if (!controllerOfTargetCreature.getHand().isEmpty()) { - Cards cards = new CardsImpl(); Card card = controllerOfTargetCreature.getHand().getRandom(game); if (card != null) { - cards.add(card); + Cards cards = new CardsImpl(card); controllerOfTargetCreature.revealCards(sourceObject.getName(), cards, game); int damage = card.getConvertedManaCost(); targetCreature.damage(damage, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/f/FrilledMystic.java b/Mage.Sets/src/mage/cards/f/FrilledMystic.java new file mode 100644 index 0000000000..c8332b4a85 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FrilledMystic.java @@ -0,0 +1,48 @@ +package mage.cards.f; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class FrilledMystic extends CardImpl { + + public FrilledMystic(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}{U}{U}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // When Frilled Mystic enters the battlefield, you may counter target spell. + Ability ability = new EntersBattlefieldTriggeredAbility(new CounterTargetEffect(), true); + ability.addTarget(new TargetSpell()); + this.addAbility(ability); + } + + private FrilledMystic(final FrilledMystic card) { + super(card); + } + + @Override + public FrilledMystic copy() { + return new FrilledMystic(this); + } +} +// nonagon infinity opens the door \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/f/FromTheAshes.java b/Mage.Sets/src/mage/cards/f/FromTheAshes.java index 7adcaf8bd0..77d8390df9 100644 --- a/Mage.Sets/src/mage/cards/f/FromTheAshes.java +++ b/Mage.Sets/src/mage/cards/f/FromTheAshes.java @@ -81,7 +81,7 @@ class FromTheAshesEffect extends OneShotEffect { Player player = game.getPlayer(entry.getKey()); if (player != null && player.chooseUse(outcome, "Search your library for up to " + entry.getValue() + " basic land card(s) to put it onto the battlefield?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(0, entry.getValue(), StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/f/FrontierMastodon.java b/Mage.Sets/src/mage/cards/f/FrontierMastodon.java index cb19bf01a4..505c938a10 100644 --- a/Mage.Sets/src/mage/cards/f/FrontierMastodon.java +++ b/Mage.Sets/src/mage/cards/f/FrontierMastodon.java @@ -1,25 +1,25 @@ - package mage.cards.f; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.FerociousHint; 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 LevelX2 */ public final class FrontierMastodon extends CardImpl { public FrontierMastodon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); this.subtype.add(SubType.ELEPHANT); this.power = new MageInt(3); this.toughness = new MageInt(2); @@ -28,8 +28,8 @@ public final class FrontierMastodon extends CardImpl { this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), FerociousCondition.instance, - "Ferocious — {this} enters the battlefield with a +1/+1 counter on it if you control a creature with power 4 or greater.","" - )); + "Ferocious — {this} enters the battlefield with a +1/+1 counter on it if you control a creature with power 4 or greater.", "" + ).addHint(FerociousHint.instance)); } public FrontierMastodon(final FrontierMastodon card) { diff --git a/Mage.Sets/src/mage/cards/f/FrontierSiege.java b/Mage.Sets/src/mage/cards/f/FrontierSiege.java index 6674c0568f..00af641bf3 100644 --- a/Mage.Sets/src/mage/cards/f/FrontierSiege.java +++ b/Mage.Sets/src/mage/cards/f/FrontierSiege.java @@ -39,8 +39,8 @@ public final class FrontierSiege extends CardImpl { filter.add(new AbilityPredicate(FlyingAbility.class)); filter2.add(new ControllerPredicate(TargetController.NOT_YOU)); } - private final static String ruleTrigger1 = "&bull Khans — At the beginning of each of your main phases, add {G}{G}."; - private final static String ruleTrigger2 = "&bull Dragons — Whenever a creature with flying enters the battlefield under your control, you may have it fight target creature you don't control."; + private static final String ruleTrigger1 = "&bull Khans — At the beginning of each of your main phases, add {G}{G}."; + private static final String ruleTrigger2 = "&bull Dragons — Whenever a creature with flying enters the battlefield under your control, you may have it fight target creature you don't control."; public FrontierSiege(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); diff --git a/Mage.Sets/src/mage/cards/f/FuelForTheCause.java b/Mage.Sets/src/mage/cards/f/FuelForTheCause.java index a536fa6bc9..e60955e6e7 100644 --- a/Mage.Sets/src/mage/cards/f/FuelForTheCause.java +++ b/Mage.Sets/src/mage/cards/f/FuelForTheCause.java @@ -1,8 +1,5 @@ - - package mage.cards.f; -import java.util.UUID; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; @@ -10,21 +7,23 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.TargetSpell; +import java.util.UUID; + /** - * * @author Loki */ public final class FuelForTheCause extends CardImpl { - public FuelForTheCause (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}{U}"); + public FuelForTheCause(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + // Counter target spell, then proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.getSpellAbility().addTarget(new TargetSpell()); this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy(", then")); } - public FuelForTheCause (final FuelForTheCause card) { + public FuelForTheCause(final FuelForTheCause card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/f/FuneralCharm.java b/Mage.Sets/src/mage/cards/f/FuneralCharm.java index abbced9ea5..b282539153 100644 --- a/Mage.Sets/src/mage/cards/f/FuneralCharm.java +++ b/Mage.Sets/src/mage/cards/f/FuneralCharm.java @@ -28,12 +28,12 @@ public final class FuneralCharm extends CardImpl { this.getSpellAbility().addEffect(new DiscardTargetEffect(1)); this.getSpellAbility().addTarget(new TargetPlayer()); Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(new SwampwalkAbility(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(new SwampwalkAbility(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FuneralMarch.java b/Mage.Sets/src/mage/cards/f/FuneralMarch.java index e5b80c6489..9de029d752 100644 --- a/Mage.Sets/src/mage/cards/f/FuneralMarch.java +++ b/Mage.Sets/src/mage/cards/f/FuneralMarch.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ZoneChangeTriggeredAbility; import mage.abilities.effects.Effect; @@ -23,14 +21,15 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class FuneralMarch extends CardImpl { public FuneralMarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -73,17 +72,19 @@ class FuneralMarchTriggeredAbility extends ZoneChangeTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { Permanent enchantment = game.getPermanentOrLKIBattlefield(this.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null && event.getTargetId().equals(enchantment.getAttachedTo())) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if ((fromZone == null || zEvent.getFromZone() == fromZone) && (toZone == null || zEvent.getToZone() == toZone)) { - for (Effect effect : getEffects()) { - if (zEvent.getTarget() != null) { - Permanent attachedTo = (Permanent) game.getLastKnownInformation(enchantment.getAttachedTo(), Zone.BATTLEFIELD, enchantment.getAttachedToZoneChangeCounter()); - if (attachedTo != null) { - effect.setTargetPointer(new FixedTarget(attachedTo.getControllerId())); + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if ((fromZone == null || zEvent.getFromZone() == fromZone) && (toZone == null || zEvent.getToZone() == toZone)) { + for (Effect effect : getEffects()) { + if (zEvent.getTarget() != null) { + Permanent attachedTo = (Permanent) game.getLastKnownInformation(enchantment.getAttachedTo(), Zone.BATTLEFIELD, enchantment.getAttachedToZoneChangeCounter()); + if (attachedTo != null) { + effect.setTargetPointer(new FixedTarget(attachedTo.getControllerId())); + } } - } + } + return true; } - return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/f/FungalReaches.java b/Mage.Sets/src/mage/cards/f/FungalReaches.java index 92598fdd61..69f0a3cbe6 100644 --- a/Mage.Sets/src/mage/cards/f/FungalReaches.java +++ b/Mage.Sets/src/mage/cards/f/FungalReaches.java @@ -38,7 +38,7 @@ public final class FungalReaches extends CardImpl { // {1}, Remove X storage counters from Fungal Reaches: Add X mana in any combination of {R} and/or {G}. ability = new SimpleManaAbility(Zone.BATTLEFIELD, - new AddManaInAnyCombinationEffect(new RemovedCountersForCostValue(), ColoredManaSymbol.R, ColoredManaSymbol.G), + new AddManaInAnyCombinationEffect(RemovedCountersForCostValue.instance, ColoredManaSymbol.R, ColoredManaSymbol.G), new GenericManaCost(1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/f/FungalSprouting.java b/Mage.Sets/src/mage/cards/f/FungalSprouting.java index d363b9a9ed..6692362537 100644 --- a/Mage.Sets/src/mage/cards/f/FungalSprouting.java +++ b/Mage.Sets/src/mage/cards/f/FungalSprouting.java @@ -19,7 +19,7 @@ public final class FungalSprouting extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); // create X 1/1 green Saproling creature tokens, where X is the greatest power among creatures you control. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new GreatestPowerAmongControlledCreaturesValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), GreatestPowerAmongControlledCreaturesValue.instance)); } public FungalSprouting(final FungalSprouting card) { diff --git a/Mage.Sets/src/mage/cards/f/FuryCharm.java b/Mage.Sets/src/mage/cards/f/FuryCharm.java index 4f7888dd71..1668f4053c 100644 --- a/Mage.Sets/src/mage/cards/f/FuryCharm.java +++ b/Mage.Sets/src/mage/cards/f/FuryCharm.java @@ -52,16 +52,16 @@ public final class FuryCharm extends CardImpl { Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1,1, Duration.EndOfTurn); effect.setText("target creature gets +1/+1"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(),Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // or remove two time counters from target permanent or suspended card. mode = new Mode(); - mode.getTargets().add(new TargetPermanentOrSuspendedCard()); - mode.getEffects().add(new FuryCharmRemoveCounterEffect()); + mode.addTarget(new TargetPermanentOrSuspendedCard()); + mode.addEffect(new FuryCharmRemoveCounterEffect()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/f/FyndhornDruid.java b/Mage.Sets/src/mage/cards/f/FyndhornDruid.java new file mode 100644 index 0000000000..a1b1fb15af --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FyndhornDruid.java @@ -0,0 +1,56 @@ + +package mage.cards.f; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.watchers.common.WasBlockedThisTurnWatcher; + +/** + * + * @author L_J + */ +public final class FyndhornDruid extends CardImpl { + + public FyndhornDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}"); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Fyndhorn Druid dies, if it was blocked this turn, you gain 4 life. + this.addAbility(new ConditionalInterveningIfTriggeredAbility(new DiesTriggeredAbility(new GainLifeEffect(4)), new SourceWasBlockedThisTurnCondition(), + "When {this} dies, if it was blocked this turn, you gain 4 life."), new WasBlockedThisTurnWatcher()); + } + + public FyndhornDruid(final FyndhornDruid card) { + super(card); + } + + @Override + public FyndhornDruid copy() { + return new FyndhornDruid(this); + } +} + +class SourceWasBlockedThisTurnCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + WasBlockedThisTurnWatcher watcher = game.getState().getWatcher(WasBlockedThisTurnWatcher.class); + return sourcePermanent != null && watcher != null && watcher.getWasBlockedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game)); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java index a7977281ff..acfb52eb17 100644 --- a/Mage.Sets/src/mage/cards/g/GOTOJAIL.java +++ b/Mage.Sets/src/mage/cards/g/GOTOJAIL.java @@ -33,7 +33,7 @@ import mage.util.CardUtil; */ public final class GOTOJAIL extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -118,7 +118,7 @@ class GoToJailTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals((UUID) game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); + return event.getPlayerId().equals(game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override @@ -145,7 +145,6 @@ class GoToJailUpkeepEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObjectIfItStillExists(game); Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); diff --git a/Mage.Sets/src/mage/cards/g/GaeasBlessing.java b/Mage.Sets/src/mage/cards/g/GaeasBlessing.java index f3ab537d19..62b9516c83 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasBlessing.java +++ b/Mage.Sets/src/mage/cards/g/GaeasBlessing.java @@ -155,7 +155,7 @@ class GaeasBlessingGraveToLibraryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" shuffle their graveyard into their library").toString()); + game.informPlayers(controller.getLogName() + " shuffle their graveyard into their library"); for (Card card : controller.getGraveyard().getCards(game)) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.GRAVEYARD, true, true); } diff --git a/Mage.Sets/src/mage/cards/g/GaeasCradle.java b/Mage.Sets/src/mage/cards/g/GaeasCradle.java index fefd6aba8a..a79fa4c13d 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasCradle.java +++ b/Mage.Sets/src/mage/cards/g/GaeasCradle.java @@ -9,6 +9,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; /** @@ -24,7 +25,7 @@ public final class GaeasCradle extends CardImpl { // {T}: Add {G} for each creature you control. DynamicManaAbility ability = new DynamicManaAbility( Mana.GreenMana(1), - new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creature you control")) + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED) ); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GaeasLiege.java b/Mage.Sets/src/mage/cards/g/GaeasLiege.java index b5c0f24259..99c8c30d33 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasLiege.java +++ b/Mage.Sets/src/mage/cards/g/GaeasLiege.java @@ -1,6 +1,6 @@ - package mage.cards.g; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -28,15 +28,13 @@ import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; import mage.target.common.TargetLandPermanent; -import java.util.UUID; - /** * * @author anonymous */ public final class GaeasLiege extends CardImpl { - - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); @@ -44,7 +42,7 @@ public final class GaeasLiege extends CardImpl { public GaeasLiege(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}{G}"); - + this.subtype.add(SubType.AVATAR); this.power = new MageInt(0); this.toughness = new MageInt(0); @@ -55,8 +53,8 @@ public final class GaeasLiege extends CardImpl { new SetPowerToughnessSourceEffect(new DefendersForestCount(), Duration.EndOfCombat), new InvertCondition(SourceAttackingCondition.instance), "As long as {this} isn't attacking, its power and toughness are each equal to the number of Forests you control. As long as {this} is attacking, its power and toughness are each equal to the number of Forests defending player controls."))); - // {tap}: Target land becomes a Forest until Gaea's Liege leaves the battlefield. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.WhileOnBattlefield, SubType.FOREST), new TapSourceCost()); + // {T}: Target land becomes a Forest until Gaea's Liege leaves the battlefield. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesBasicLandTargetEffect(Duration.UntilSourceLeavesBattlefield, SubType.FOREST), new TapSourceCost()); ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); } @@ -75,7 +73,7 @@ class DefendersForestCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - for (CombatGroup group :game.getCombat().getGroups()) { + for (CombatGroup group : game.getCombat().getGroups()) { if (group.getAttackers().contains(sourceAbility.getSourceId())) { UUID defenderId = group.getDefenderId(); if (group.isDefenderIsPlaneswalker()) { @@ -84,7 +82,7 @@ class DefendersForestCount implements DynamicValue { defenderId = permanent.getControllerId(); } } - + FilterLandPermanent filter = new FilterLandPermanent("forest"); filter.add(new SubtypePredicate(SubType.FOREST)); return game.getBattlefield().countAll(filter, defenderId, game); diff --git a/Mage.Sets/src/mage/cards/g/GalecasterColossus.java b/Mage.Sets/src/mage/cards/g/GalecasterColossus.java index 93ed2f360e..9c00fb80e7 100644 --- a/Mage.Sets/src/mage/cards/g/GalecasterColossus.java +++ b/Mage.Sets/src/mage/cards/g/GalecasterColossus.java @@ -34,7 +34,7 @@ public final class GalecasterColossus extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); filter2.add(new SubtypePredicate(SubType.WIZARD)); - filter2.add(Predicates.not(new TappedPredicate())); + filter2.add(Predicates.not(TappedPredicate.instance)); } public GalecasterColossus(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GalepowderMage.java b/Mage.Sets/src/mage/cards/g/GalepowderMage.java index 28a2c19cce..f59ef1f927 100644 --- a/Mage.Sets/src/mage/cards/g/GalepowderMage.java +++ b/Mage.Sets/src/mage/cards/g/GalepowderMage.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -15,8 +13,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -26,8 +24,9 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GalepowderMage extends CardImpl { @@ -35,11 +34,11 @@ public final class GalepowderMage extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GalepowderMage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.KITHKIN); this.subtype.add(SubType.WIZARD); @@ -87,10 +86,10 @@ class GalepowderMageEffect extends OneShotEffect { if (controller != null && sourceObject != null) { if (getTargetPointer().getFirst(game, source) != null) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (permanent != null) { UUID exileId = UUID.randomUUID(); if (controller.moveCardToExileWithInfo(permanent, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); if (card != null) { Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); diff --git a/Mage.Sets/src/mage/cards/g/Galestrike.java b/Mage.Sets/src/mage/cards/g/Galestrike.java index 372e5bcb88..01a3fd7702 100644 --- a/Mage.Sets/src/mage/cards/g/Galestrike.java +++ b/Mage.Sets/src/mage/cards/g/Galestrike.java @@ -20,7 +20,7 @@ public final class Galestrike extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public Galestrike(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GallopingLizrog.java b/Mage.Sets/src/mage/cards/g/GallopingLizrog.java new file mode 100644 index 0000000000..34362d524e --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GallopingLizrog.java @@ -0,0 +1,87 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.RemoveVariableCountersTargetCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +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.StaticFilters; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GallopingLizrog extends CardImpl { + + public GallopingLizrog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{U}"); + + this.subtype.add(SubType.FROG); + this.subtype.add(SubType.LIZARD); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Galloping Lizrog enters the battlefield, you may remove any number of +1/+1 counters from among creatures you control. If you do, put twice that many +1/+1 counters on Galloping Lizrog. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GallopingLizrogEffect(), true)); + } + + private GallopingLizrog(final GallopingLizrog card) { + super(card); + } + + @Override + public GallopingLizrog copy() { + return new GallopingLizrog(this); + } +} + +class GallopingLizrogEffect extends OneShotEffect { + + GallopingLizrogEffect() { + super(Outcome.Benefit); + staticText = "remove any number of +1/+1 counters from among creatures you control. " + + "If you do, put twice that many +1/+1 counters on {this}"; + } + + private GallopingLizrogEffect(final GallopingLizrogEffect effect) { + super(effect); + } + + @Override + public GallopingLizrogEffect copy() { + return new GallopingLizrogEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + RemoveVariableCountersTargetCost variableCost + = new RemoveVariableCountersTargetCost(StaticFilters.FILTER_CONTROLLED_CREATURE, CounterType.P1P1); + int toPay = variableCost.announceXValue(source, game); + Cost cost = variableCost.getFixedCostsFromAnnouncedValue(toPay); + if (!cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + return false; + } + return new AddCountersSourceEffect( + CounterType.P1P1.createInstance(2 * toPay) + ).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java b/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java index c8ca0944f9..c7ce35b44f 100644 --- a/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java +++ b/Mage.Sets/src/mage/cards/g/GallowsAtWillowHill.java @@ -35,7 +35,7 @@ public final class GallowsAtWillowHill extends CardImpl { private static final FilterControlledPermanent humanFilter = new FilterControlledPermanent("untapped Human you control"); static { - humanFilter.add(Predicates.not(new TappedPredicate())); + humanFilter.add(Predicates.not(TappedPredicate.instance)); humanFilter.add(new SubtypePredicate(SubType.HUMAN)); } diff --git a/Mage.Sets/src/mage/cards/g/GameOfChaos.java b/Mage.Sets/src/mage/cards/g/GameOfChaos.java index 6c5f2f9386..53010b05fa 100644 --- a/Mage.Sets/src/mage/cards/g/GameOfChaos.java +++ b/Mage.Sets/src/mage/cards/g/GameOfChaos.java @@ -63,7 +63,7 @@ class GameOfChaosEffect extends OneShotEffect { if (you != null && targetOpponent != null) { boolean continueFlipping = true; - boolean youWonFlip = you.flipCoin(game); // controller flips first + boolean youWonFlip = you.flipCoin(source, game, true); // controller flips first boolean youWonLastFlip = false; // tracks if you won the flip last, negation of it means opponent won last int lifeAmount = 1; // starts stakes with 1 life @@ -88,7 +88,7 @@ class GameOfChaosEffect extends OneShotEffect { if (continueFlipping) { lifeAmount *= 2; // double the life each time - youWonFlip = youWonLastFlip ? you.flipCoin(game) : !targetOpponent.flipCoin(game); // negate the opponent's results for proper evaluation of if you won in next iteration + youWonFlip = youWonLastFlip ? you.flipCoin(source, game, true) : !targetOpponent.flipCoin(source, game, true); // negate the opponent's results for proper evaluation of if you won in next iteration } } diff --git a/Mage.Sets/src/mage/cards/g/GangUp.java b/Mage.Sets/src/mage/cards/g/GangUp.java index 5106c8e463..a49f70ff1d 100644 --- a/Mage.Sets/src/mage/cards/g/GangUp.java +++ b/Mage.Sets/src/mage/cards/g/GangUp.java @@ -1,9 +1,7 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.keyword.AssistAbility; import mage.cards.CardImpl; @@ -14,9 +12,11 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class GangUp extends CardImpl { @@ -28,27 +28,29 @@ public final class GangUp extends CardImpl { this.addAbility(new AssistAbility()); // Destroy target creature with power X or less. - this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with power X or less"))); + this.getSpellAbility().addEffect(new DestroyTargetEffect("destroy target creature with power X or less")); + this.getSpellAbility().setTargetAdjuster(GangUpAdjuster.instance); } public GangUp(final GangUp card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent(new StringBuilder("creature with power ").append(xValue).append(" or less").toString()); - filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } - @Override public GangUp copy() { return new GangUp(this); } } + +enum GangUpAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power " + xValue + " or less"); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GangrenousZombies.java b/Mage.Sets/src/mage/cards/g/GangrenousZombies.java index 4fd7847eb5..17fca38a81 100644 --- a/Mage.Sets/src/mage/cards/g/GangrenousZombies.java +++ b/Mage.Sets/src/mage/cards/g/GangrenousZombies.java @@ -27,7 +27,7 @@ import java.util.UUID; */ public final class GangrenousZombies extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterLandPermanent filter = new FilterLandPermanent(); static { filter.add(new SupertypePredicate(SuperType.SNOW)); diff --git a/Mage.Sets/src/mage/cards/g/GarbageElementalC.java b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java index 73006d934d..cc7ba6b320 100644 --- a/Mage.Sets/src/mage/cards/g/GarbageElementalC.java +++ b/Mage.Sets/src/mage/cards/g/GarbageElementalC.java @@ -37,7 +37,7 @@ public final class GarbageElementalC extends CardImpl { this.addAbility(new BattleCryAbility()); // When Garbage Elemental enters the battlefield, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results. - this.addAbility(new EntersBattlefieldAbility(new GarbageElementalEffect(), + this.addAbility(new EntersBattlefieldAbility(new GarbageElementalCEffect(), null, "When {this} enters the battlefield, roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results", null)); @@ -54,26 +54,20 @@ public final class GarbageElementalC extends CardImpl { } } -class GarbageElementalEffect extends OneShotEffect { +class GarbageElementalCEffect extends OneShotEffect { - private static final FilterPermanent filter = new FilterPermanent("permanent with a counter"); - - static { - filter.add(new CounterPredicate(null)); - } - - GarbageElementalEffect() { + GarbageElementalCEffect() { super(Outcome.PutCreatureInPlay); this.staticText = "roll two six-sided dice. Create a number of 1/1 red Goblin creature tokens equal to the difference between those results"; } - GarbageElementalEffect(final GarbageElementalEffect effect) { + GarbageElementalCEffect(final GarbageElementalCEffect effect) { super(effect); } @Override - public GarbageElementalEffect copy() { - return new GarbageElementalEffect(this); + public GarbageElementalCEffect copy() { + return new GarbageElementalCEffect(this); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GarbageElementalD.java b/Mage.Sets/src/mage/cards/g/GarbageElementalD.java new file mode 100644 index 0000000000..e8152cc11e --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GarbageElementalD.java @@ -0,0 +1,80 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CascadeAbility; +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.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author spjspj + */ +public final class GarbageElementalD extends CardImpl { + + public GarbageElementalD(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Cascade + this.addAbility(new CascadeAbility()); + + // When Garbage Elemental enters the battlefield, roll a six-sided die. Garbage Elemental deals damage equal to the result to target opponent. + Ability ability = new EntersBattlefieldAbility(new GarbageElementalDEffect(), + null, + "When {this} enters the battlefield, roll a six-sided die. {this} deals damage equal to the result to target opponent", + null); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + } + + public GarbageElementalD(final GarbageElementalD card) { + super(card); + } + + @Override + public GarbageElementalD copy() { + return new GarbageElementalD(this); + } +} + +class GarbageElementalDEffect extends OneShotEffect { + + GarbageElementalDEffect() { + super(Outcome.Benefit); + this.staticText = "roll a six-sided die. {this} deals damage equal to the result to target opponent"; + } + + GarbageElementalDEffect(final GarbageElementalDEffect effect) { + super(effect); + } + + @Override + public GarbageElementalDEffect copy() { + return new GarbageElementalDEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller != null && opponent != null) { + int damage = controller.rollDice(game, 6); + return game.damagePlayerOrPlaneswalker(opponent.getId(), damage, source.getId(), game, false, true) > 0; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java b/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java new file mode 100644 index 0000000000..31c0bbbcf4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GargantuanGorilla.java @@ -0,0 +1,154 @@ + +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class GargantuanGorilla extends CardImpl { + + public GargantuanGorilla(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}{G}"); + this.subtype.add(SubType.APE); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // At the beginning of your upkeep, you may sacrifice a Forest. If you sacrifice a snow Forest this way, Gargantuan Gorilla gains trample until end of turn. If you don’t sacrifice a Forest, sacrifice Gargantuan Gorilla and it deals 7 damage to you. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GargantuanGorillaSacrificeEffect(), TargetController.YOU, false)); + + // {T}: Gargantuan Gorilla deals damage equal to its power to another target creature. That creature deals damage equal to its power to Gargantuan Gorilla. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GargantuanGorillaFightEffect(), new TapSourceCost()); + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(AnotherPredicate.instance); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public GargantuanGorilla(final GargantuanGorilla card) { + super(card); + } + + @Override + public GargantuanGorilla copy() { + return new GargantuanGorilla(this); + } +} + +class GargantuanGorillaSacrificeEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a Forest"); + private static final FilterPermanent filterSnow = new FilterPermanent("snow permanent"); + static { + filter.add(new SubtypePredicate(SubType.FOREST)); + filterSnow.add(new SupertypePredicate(SuperType.SNOW)); + } + + public GargantuanGorillaSacrificeEffect() { + super(Outcome.Sacrifice); + staticText = "you may sacrifice a Forest. If you sacrifice a snow Forest this way, {this} gains trample until end of turn. If you don’t sacrifice a Forest, sacrifice {this} and it deals 7 damage to you."; + } + + public GargantuanGorillaSacrificeEffect(final GargantuanGorillaSacrificeEffect effect) { + super(effect); + } + + @Override + public GargantuanGorillaSacrificeEffect copy() { + return new GargantuanGorillaSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + SacrificeTargetCost cost = new SacrificeTargetCost(target); + if (!controller.chooseUse(Outcome.Benefit, "Do you wish to sacrifice a Forest?", source, game) + || !cost.canPay(source, source.getSourceId(), source.getControllerId(), game) + || !cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + sourcePermanent.sacrifice(source.getSourceId(), game); + controller.damage(7, sourcePermanent.getId(), game, false, true); + } else if (cost.isPaid()) { + for (Permanent permanent : cost.getPermanents()) { + if (filterSnow.match(permanent, game)) { + game.addEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), source); + break; + } + } + } + return true; + } + return false; + } +} + +class GargantuanGorillaFightEffect extends OneShotEffect { + + public GargantuanGorillaFightEffect() { + super(Outcome.Damage); + this.staticText = "{this} deals damage equal to its power to another target creature. That creature deals damage equal to its power to {this}"; + } + + public GargantuanGorillaFightEffect(final GargantuanGorillaFightEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + Permanent creature1 = game.getPermanent(getTargetPointer().getFirst(game, source)); + // 20110930 - 701.10 + if (creature1 != null && sourcePermanent != null) { + if (creature1.isCreature() && sourcePermanent.isCreature()) { + sourcePermanent.damage(creature1.getPower().getValue(), creature1.getId(), game, false, true); + creature1.damage(sourcePermanent.getPower().getValue(), sourcePermanent.getId(), game, false, true); + return true; + } + } + if (!game.isSimulation()) { + game.informPlayers(sourceObject.getLogName() + ": Fighting effect has been fizzled."); + } + } + return false; + } + + @Override + public GargantuanGorillaFightEffect copy() { + return new GargantuanGorillaFightEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java b/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java index 74585b1ffe..2583df059c 100644 --- a/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java +++ b/Mage.Sets/src/mage/cards/g/GarnaTheBloodflame.java @@ -80,7 +80,7 @@ class GarnaTheBloodflameEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - GarnaTheBloodflameWatcher watcher = (GarnaTheBloodflameWatcher) game.getState().getWatchers().get(GarnaTheBloodflameWatcher.class.getSimpleName()); + GarnaTheBloodflameWatcher watcher = game.getState().getWatcher(GarnaTheBloodflameWatcher.class); if (watcher != null) { Set toHand = new HashSet<>(); for (UUID cardId : watcher.getCardsPutToGraveyardThisTurn()) { @@ -109,7 +109,7 @@ class GarnaTheBloodflameWatcher extends Watcher { private final Set cards = new HashSet<>(); public GarnaTheBloodflameWatcher() { - super(GarnaTheBloodflameWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public GarnaTheBloodflameWatcher(final GarnaTheBloodflameWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java b/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java index 58e8d5284b..c3675b9676 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java +++ b/Mage.Sets/src/mage/cards/g/GarrukApexPredator.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; @@ -12,7 +10,10 @@ import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GetEmblemTargetPlayerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; @@ -25,8 +26,9 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GarrukApexPredator extends CardImpl { @@ -35,7 +37,7 @@ public final class GarrukApexPredator extends CardImpl { static { filter.add(new CardTypePredicate(CardType.PLANESWALKER)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GarrukApexPredator(UUID ownerId, CardSetInfo setInfo) { @@ -62,7 +64,6 @@ public final class GarrukApexPredator extends CardImpl { // -8: Target opponent gets an emblem with "Whenever a creature attacks you, it gets +5/+5 and gains trample until end of turn." Effect effect = new GetEmblemTargetPlayerEffect(new GarrukApexPredatorEmblem()); - effect.setText("Target opponent gets an emblem with \"Whenever a creature attacks you, it gets +5/+5 and gains trample until end of turn.\""); ability = new LoyaltyAbility(effect, -8); ability.addTarget(new TargetOpponent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java b/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java index 55c2665e2f..26c6b633b1 100644 --- a/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java +++ b/Mage.Sets/src/mage/cards/g/GarrukTheVeilCursed.java @@ -145,7 +145,7 @@ class GarrukTheVeilCursedEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard(); TargetCardInLibrary targetInLibrary = new TargetCardInLibrary(filter); Cards cards = new CardsImpl(); - if (controller.searchLibrary(targetInLibrary, game)) { + if (controller.searchLibrary(targetInLibrary, source, game)) { for (UUID cardId : targetInLibrary.getTargets()) { Card card = controller.getLibrary().remove(cardId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/g/GarruksPackleader.java b/Mage.Sets/src/mage/cards/g/GarruksPackleader.java index 52fbd22205..92a47c1016 100644 --- a/Mage.Sets/src/mage/cards/g/GarruksPackleader.java +++ b/Mage.Sets/src/mage/cards/g/GarruksPackleader.java @@ -25,7 +25,7 @@ public final class GarruksPackleader extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature with power 3 or greater"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); } diff --git a/Mage.Sets/src/mage/cards/g/GateColossus.java b/Mage.Sets/src/mage/cards/g/GateColossus.java new file mode 100644 index 0000000000..633370862b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GateColossus.java @@ -0,0 +1,103 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.PutOnLibrarySourceEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.hint.common.GateYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GateColossus extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with power 2 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public GateColossus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{8}"); + + this.subtype.add(SubType.CONSTRUCT); + this.power = new MageInt(8); + this.toughness = new MageInt(8); + + // This spell costs {1} less to cast for each Gate you control. + this.addAbility(new SimpleStaticAbility(Zone.STACK, new GateColossusCostReductionEffect()) + .addHint(GateYouControlHint.instance)); + + // Gate Colossus can't be blocked by creatures with power 2 or less. + this.addAbility(new SimpleEvasionAbility(new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield))); + + // Whenever a Gate enters the battlefield under your control, you may put Gate Colossus from your graveyard on top of your library. + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + Zone.GRAVEYARD, + new PutOnLibrarySourceEffect( + true, "put {this} from your graveyard on top of your library" + ), GateColossusCostReductionEffect.filter, true + )); + } + + public GateColossus(final GateColossus card) { + super(card); + } + + @Override + public GateColossus copy() { + return new GateColossus(this); + } +} + +class GateColossusCostReductionEffect extends CostModificationEffectImpl { + + static final FilterControlledPermanent filter = new FilterControlledPermanent("a Gate"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + public GateColossusCostReductionEffect() { + super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = "This spell costs {1} less to cast for each Gate you control"; + } + + protected GateColossusCostReductionEffect(final GateColossusCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + int count = game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).size(); + if (count > 0) { + CardUtil.reduceCost(abilityToModify, count); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify.getSourceId().equals(source.getSourceId()); + } + + @Override + public GateColossusCostReductionEffect copy() { + return new GateColossusCostReductionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java b/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java index 21cdf77468..4137396dcd 100644 --- a/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java +++ b/Mage.Sets/src/mage/cards/g/GateToPhyrexia.java @@ -28,7 +28,7 @@ public final class GateToPhyrexia extends CardImpl { // Sacrifice a creature: Destroy target artifact. Activate this ability only during your upkeep and only once each turn. Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)), - 1, new IsStepCondition(PhaseStep.UPKEEP, true)); + 1, new IsStepCondition(PhaseStep.UPKEEP)); ability.addTarget(new TargetArtifactPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java b/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java index 8bc4dba224..cd375ad4f5 100644 --- a/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java +++ b/Mage.Sets/src/mage/cards/g/GateToTheAfterlife.java @@ -42,7 +42,7 @@ public final class GateToTheAfterlife extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public GateToTheAfterlife(UUID ownerId, CardSetInfo setInfo) { @@ -123,7 +123,7 @@ class GateToTheAfterlifeEffect extends OneShotEffect { if (card == null && controller.chooseUse(Outcome.Benefit, "Do you want to search your library for " + cardName + "?", source, game)) { librarySearched = true; TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/g/GatebreakerRam.java b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java new file mode 100644 index 0000000000..8ef7e9738b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatebreakerRam.java @@ -0,0 +1,77 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.GateYouControlHint; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatebreakerRam extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + private static final DynamicValue xValue + = new PermanentsOnBattlefieldCount(filter); + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public GatebreakerRam(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.SHEEP); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Gatebreaker Ram gets +1/+1 for each Gate you control. + this.addAbility(new SimpleStaticAbility( + new BoostSourceEffect(xValue, xValue, Duration.WhileOnBattlefield) + .setText("{this} gets +1/+1 for each Gate you control.") + ).addHint(GateYouControlHint.instance)); + + // As long as you control two or more Gates, Gatebreaker Ram has vigilance and trample. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(VigilanceAbility.getInstance()), + condition, "As long as you control two or more Gates, {this} has vigilance" + )); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(TrampleAbility.getInstance()), + condition, "and trample" + )); + this.addAbility(ability); + } + + private GatebreakerRam(final GatebreakerRam card) { + super(card); + } + + @Override + public GatebreakerRam copy() { + return new GatebreakerRam(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java b/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java index bc1dc58488..43a3218777 100644 --- a/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java +++ b/Mage.Sets/src/mage/cards/g/GatekeeperGargoyle.java @@ -1,32 +1,24 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.GateYouControlCount; import mage.abilities.effects.common.counter.AddCountersSourceEffect; -import mage.constants.SubType; +import mage.abilities.hint.common.GateYouControlHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.counters.CounterType; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class GatekeeperGargoyle extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(new SubtypePredicate(SubType.GATE)); - } - public GatekeeperGargoyle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{6}"); @@ -41,9 +33,9 @@ public final class GatekeeperGargoyle extends CardImpl { this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect( CounterType.P1P1.createInstance(), - new PermanentsOnBattlefieldCount(filter), true + GateYouControlCount.instance, true ), "with a +1/+1 counter on it for each Gate you control" - )); + ).addHint(GateYouControlHint.instance)); } public GatekeeperGargoyle(final GatekeeperGargoyle card) { diff --git a/Mage.Sets/src/mage/cards/g/GatesAblaze.java b/Mage.Sets/src/mage/cards/g/GatesAblaze.java new file mode 100644 index 0000000000..780aa83f1a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatesAblaze.java @@ -0,0 +1,46 @@ +package mage.cards.g; + +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamageAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatesAblaze extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("the number of Gates you control"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter); + + public GatesAblaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Gates Ablaze deals X damage to each creature, where X is the number of Gates you control. + this.getSpellAbility().addEffect(new DamageAllEffect(xValue, StaticFilters.FILTER_PERMANENT_CREATURE)); + } + + private GatesAblaze(final GatesAblaze card) { + super(card); + } + + @Override + public GatesAblaze copy() { + return new GatesAblaze(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatewayPlaza.java b/Mage.Sets/src/mage/cards/g/GatewayPlaza.java index 882a7de195..3d0ac49471 100644 --- a/Mage.Sets/src/mage/cards/g/GatewayPlaza.java +++ b/Mage.Sets/src/mage/cards/g/GatewayPlaza.java @@ -1,18 +1,18 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.abilities.mana.AnyColorManaAbility; -import mage.constants.SubType; 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 GatewayPlaza extends CardImpl { @@ -27,9 +27,7 @@ public final class GatewayPlaza extends CardImpl { // When Gateway Plaza enters the battlefield, sacrifice it unless you pay {1}. this.addAbility(new EntersBattlefieldTriggeredAbility( - new SacrificeSourceUnlessPaysEffect( - new GenericManaCost(1) - ), false + new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1)).setText("sacrifice it unless you pay {1}") )); // {T}: Add one mana of any color. diff --git a/Mage.Sets/src/mage/cards/g/GatewayShade.java b/Mage.Sets/src/mage/cards/g/GatewayShade.java index 684d873a8e..cb36365322 100644 --- a/Mage.Sets/src/mage/cards/g/GatewayShade.java +++ b/Mage.Sets/src/mage/cards/g/GatewayShade.java @@ -28,7 +28,7 @@ public final class GatewayShade extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("untapped Gate you control"); static { filter.add(new SubtypePredicate(SubType.GATE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public GatewayShade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GatewaySneak.java b/Mage.Sets/src/mage/cards/g/GatewaySneak.java new file mode 100644 index 0000000000..9d0596cb77 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GatewaySneak.java @@ -0,0 +1,51 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GatewaySneak extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.GATE, "a Gate"); + + public GatewaySneak(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever a Gate enters the battlefield under your control, Gateway Sneak can't be blocked this turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new CantBeBlockedSourceEffect(Duration.EndOfTurn), filter + )); + + // Whenever Gateway Sneak deals combat damage to a player, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + )); + } + + private GatewaySneak(final GatewaySneak card) { + super(card); + } + + @Override + public GatewaySneak copy() { + return new GatewaySneak(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GatherSpecimens.java b/Mage.Sets/src/mage/cards/g/GatherSpecimens.java index 812e8a993e..9efc66b27b 100644 --- a/Mage.Sets/src/mage/cards/g/GatherSpecimens.java +++ b/Mage.Sets/src/mage/cards/g/GatherSpecimens.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.Card; @@ -16,14 +14,15 @@ import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GatherSpecimens extends CardImpl { public GatherSpecimens(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}{U}"); // If a creature would enter the battlefield under an opponent's control this turn, it enters the battlefield under your control instead. this.getSpellAbility().addEffect(new GatherSpecimensReplacementEffect()); @@ -70,7 +69,7 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { if (event.getType() == GameEvent.EventType.ZONE_CHANGE && ((ZoneChangeEvent) event).getToZone().match(Zone.BATTLEFIELD)) { Card card = game.getCard(event.getTargetId()); - if (card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly + if (card != null && card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly Player controller = game.getPlayer(source.getControllerId()); if (controller != null && controller.hasOpponent(event.getPlayerId(), game)) { return true; @@ -79,9 +78,7 @@ class GatherSpecimensReplacementEffect extends ReplacementEffectImpl { } if (event.getType() == GameEvent.EventType.CREATE_TOKEN && event.getFlag()) { // flag indicates if it's a creature token Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && controller.hasOpponent(event.getPlayerId(), game)) { - return true; - } + return controller != null && controller.hasOpponent(event.getPlayerId(), game); } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GatherThePack.java b/Mage.Sets/src/mage/cards/g/GatherThePack.java index 9569692e94..7f51389ac7 100644 --- a/Mage.Sets/src/mage/cards/g/GatherThePack.java +++ b/Mage.Sets/src/mage/cards/g/GatherThePack.java @@ -61,8 +61,7 @@ class GatherThePackEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); int creatures = cards.count(new FilterCreatureCard(), source.getSourceId(), source.getControllerId(), game); diff --git a/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java b/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java index 76865d61d0..a466ce4acd 100644 --- a/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java +++ b/Mage.Sets/src/mage/cards/g/GauntletsOfChaos.java @@ -1,10 +1,6 @@ package mage.cards.g; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,11 +9,7 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; @@ -27,20 +19,24 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 & L_J */ public final class GauntletsOfChaos extends CardImpl { public GauntletsOfChaos(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // {5}, Sacrifice Gauntlets of Chaos: Exchange control of target artifact, creature, or land you control and target permanent an opponent controls that shares one of those types with it. If those permanents are exchanged this way, destroy all Auras attached to them. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExchangeControlTargetEffect(Duration.EndOfGame, - "exchange control of target artifact, creature, or land you control and target permanent an opponent controls that shares one of those types with it." - + " If those permanents are exchanged this way, destroy all Auras attached to them", false, true, true), - new ManaCostsImpl("{5}") + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExchangeControlTargetEffect(Duration.EndOfGame, + "exchange control of target artifact, creature, or land you control and target permanent an opponent controls that shares one of those types with it." + + " If those permanents are exchanged this way, destroy all Auras attached to them", false, true, true), + new ManaCostsImpl("{5}") ); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new GauntletsOfChaosFirstTarget()); @@ -59,7 +55,7 @@ public final class GauntletsOfChaos extends CardImpl { } class GauntletsOfChaosFirstTarget extends TargetControlledPermanent { - + public GauntletsOfChaosFirstTarget() { super(); this.filter = this.filter.copy(); @@ -68,17 +64,17 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent { new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); setTargetName("artifact, creature, or land you control"); - } - + } + public GauntletsOfChaosFirstTarget(final GauntletsOfChaosFirstTarget target) { super(target); } - + @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { if (super.canTarget(controllerId, id, source, game)) { Set cardTypes = getOpponentPermanentCardTypes(source.getSourceId(), controllerId, game); - Permanent permanent = game.getPermanent(id); + Permanent permanent = game.getPermanent(id); for (CardType type : permanent.getCardType()) { if (cardTypes.contains(type)) { return true; @@ -87,36 +83,38 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent { } return false; } - + @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { // get all cardtypes from opponents permanents Set cardTypes = getOpponentPermanentCardTypes(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - for (CardType type : permanent.getCardType()) { - if (cardTypes.contains(type)) { - possibleTargets.add(permanent.getId()); - break; - } + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + for (CardType type : permanent.getCardType()) { + if (cardTypes.contains(type)) { + possibleTargets.add(permanent.getId()); + break; + } + } } } } - return possibleTargets; + return possibleTargets; } - + @Override public GauntletsOfChaosFirstTarget copy() { return new GauntletsOfChaosFirstTarget(this); } - + private EnumSet getOpponentPermanentCardTypes(UUID sourceId, UUID sourceControllerId, Game game) { Player controller = game.getPlayer(sourceControllerId); - EnumSet cardTypes =EnumSet.noneOf(CardType.class); + EnumSet cardTypes = EnumSet.noneOf(CardType.class); if (controller != null) { - for (Permanent permanent: game.getBattlefield().getActivePermanents(sourceControllerId, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(sourceControllerId, game)) { if (controller.hasOpponent(permanent.getControllerId(), game)) { cardTypes.addAll(permanent.getCardType()); } @@ -130,20 +128,20 @@ class GauntletsOfChaosFirstTarget extends TargetControlledPermanent { class GauntletsOfChaosSecondTarget extends TargetPermanent { private Permanent firstTarget = null; - + public GauntletsOfChaosSecondTarget() { super(); this.filter = this.filter.copy(); filter.add(new ControllerPredicate(TargetController.OPPONENT)); setTargetName("permanent an opponent controls that shares one of those types with it"); - } + } public GauntletsOfChaosSecondTarget(final GauntletsOfChaosSecondTarget target) { super(target); this.firstTarget = target.firstTarget; } - + @Override public boolean canTarget(UUID id, Ability source, Game game) { if (super.canTarget(id, source, game)) { @@ -155,29 +153,31 @@ class GauntletsOfChaosSecondTarget extends TargetPermanent { } return false; } - + @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if (permanent.shareTypes(firstTarget)) { - possibleTargets.add(permanent.getId()); + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (permanent.shareTypes(firstTarget)) { + possibleTargets.add(permanent.getId()); + } } } } } return possibleTargets; } - + @Override public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { firstTarget = game.getPermanent(source.getFirstTarget()); return super.chooseTarget(Outcome.Damage, playerId, source, game); - } - + } + @Override public GauntletsOfChaosSecondTarget copy() { return new GauntletsOfChaosSecondTarget(this); diff --git a/Mage.Sets/src/mage/cards/g/GavonyTownship.java b/Mage.Sets/src/mage/cards/g/GavonyTownship.java index 03f2ae41d0..ed8039b35e 100644 --- a/Mage.Sets/src/mage/cards/g/GavonyTownship.java +++ b/Mage.Sets/src/mage/cards/g/GavonyTownship.java @@ -12,6 +12,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; public final class GavonyTownship extends CardImpl { @@ -23,7 +24,7 @@ public final class GavonyTownship extends CardImpl { this.addAbility(new ColorlessManaAbility()); // {2}{G}{W}, {T}: Put a +1/+1 counter on each creature you control. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent("creature you control")), new ManaCostsImpl("{2}{G}{W}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect(CounterType.P1P1.createInstance(), StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED), new ManaCostsImpl("{2}{G}{W}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GavonyUnhallowed.java b/Mage.Sets/src/mage/cards/g/GavonyUnhallowed.java index f8d8ce3d8e..17b8d03727 100644 --- a/Mage.Sets/src/mage/cards/g/GavonyUnhallowed.java +++ b/Mage.Sets/src/mage/cards/g/GavonyUnhallowed.java @@ -24,7 +24,7 @@ public final class GavonyUnhallowed extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/g/GazeOfJustice.java b/Mage.Sets/src/mage/cards/g/GazeOfJustice.java index 4735ad605b..10b93cd0ba 100644 --- a/Mage.Sets/src/mage/cards/g/GazeOfJustice.java +++ b/Mage.Sets/src/mage/cards/g/GazeOfJustice.java @@ -28,7 +28,7 @@ public final class GazeOfJustice extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public GazeOfJustice(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GazeOfPain.java b/Mage.Sets/src/mage/cards/g/GazeOfPain.java new file mode 100644 index 0000000000..139cb07c2c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GazeOfPain.java @@ -0,0 +1,188 @@ +package mage.cards.g; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DamageTargetEffect; +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.combat.CombatGroup; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class GazeOfPain extends CardImpl { + + public GazeOfPain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); + + // Until end of turn, whenever a creature you control attacks and isn't blocked, you may choose to have it deal damage equal to its power to a target creature. If you do, it assigns no combat damage this turn. + this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new GazeOfPainDelayedTriggeredAbility())); + } + + public GazeOfPain(final GazeOfPain card) { + super(card); + } + + @Override + public GazeOfPain copy() { + return new GazeOfPain(this); + } +} + +class GazeOfPainDelayedTriggeredAbility extends DelayedTriggeredAbility { + + Set creatures = new HashSet<>(); + + public GazeOfPainDelayedTriggeredAbility() { + super(new GazeOfPainEffect(), Duration.EndOfTurn, false, true); + } + + public GazeOfPainDelayedTriggeredAbility(GazeOfPainDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARE_BLOCKERS_STEP; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + for (CombatGroup combatGroup : game.getCombat().getGroups()) { + if (combatGroup.getBlockers().isEmpty()) { + for (UUID attackerId : combatGroup.getAttackers()) { + if (game.getPermanent(attackerId).getControllerId() == controllerId + && game.getPermanent(attackerId).isAttacking()) { + creatures.add(attackerId); + } + } + } + } + if (!creatures.isEmpty()) { + game.getState().setValue("gazeOfPain", creatures); + return true; + } + return false; + } + + @Override + public GazeOfPainDelayedTriggeredAbility copy() { + return new GazeOfPainDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Until end of turn, whenever a creature you control attacks and isn't blocked, " + super.getRule(); + } +} + +class GazeOfPainEffect extends OneShotEffect { + + Set creatures = new HashSet<>(); + + GazeOfPainEffect() { + super(Outcome.Benefit); + this.staticText = "you may choose to have it deal damage equal to its power to a target creature. If you do, it assigns no combat damage this turn."; + } + + GazeOfPainEffect(final GazeOfPainEffect effect) { + super(effect); + } + + @Override + public GazeOfPainEffect copy() { + return new GazeOfPainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + creatures = (Set) game.getState().getValue("gazeOfPain"); + if (!creatures.isEmpty()) { + for (UUID attackerId : creatures) { + Permanent attacker = game.getPermanent(attackerId); + if (controller != null + && attacker != null) { + if (controller.chooseUse(outcome, "Do you wish to deal damage equal to " + attacker.getName() + "'s power to a target creature?", source, game)) { + TargetCreaturePermanent target = new TargetCreaturePermanent(); + if (target.canChoose(controller.getId(), game) + && controller.choose(Outcome.Detriment, target, source.getSourceId(), game)) { + Effect effect = new DamageTargetEffect(attacker.getPower().getValue()); + effect.setTargetPointer(new FixedTarget(target.getFirstTarget())); + effect.apply(game, source); + ContinuousEffect effect2 = new AssignNoCombatDamageTargetEffect(); + effect2.setTargetPointer(new FixedTarget(attackerId)); + game.addEffect(effect2, source); + } + } + } + } + return true; + } + return false; + } +} + +class AssignNoCombatDamageTargetEffect extends ReplacementEffectImpl { + + public AssignNoCombatDamageTargetEffect() { + super(Duration.EndOfTurn, Outcome.Neutral); + } + + public AssignNoCombatDamageTargetEffect(final AssignNoCombatDamageTargetEffect effect) { + super(effect); + } + + @Override + public AssignNoCombatDamageTargetEffect copy() { + return new AssignNoCombatDamageTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + return event.getSourceId().equals(targetPointer.getFirst(game, source)) + && damageEvent.isCombatDamage(); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java index ecdd1863e5..c2889337d5 100644 --- a/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java +++ b/Mage.Sets/src/mage/cards/g/GazeOfTheGorgon.java @@ -98,7 +98,7 @@ class GazeOfTheGorgonEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && targetCreature != null) { - BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java index 9cd4533298..1bc10b186e 100644 --- a/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java +++ b/Mage.Sets/src/mage/cards/g/GearseekerSerpent.java @@ -58,7 +58,7 @@ class GearseekerSerpentCostReductionEffect extends CostModificationEffectImpl { public GearseekerSerpentCostReductionEffect() { super(Duration.WhileOnStack, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "{this} costs {1} less to cast for each artifact you control"; + staticText = "This spell costs {1} less to cast for each artifact you control"; } protected GearseekerSerpentCostReductionEffect(final GearseekerSerpentCostReductionEffect effect) { diff --git a/Mage.Sets/src/mage/cards/g/GeistHonoredMonk.java b/Mage.Sets/src/mage/cards/g/GeistHonoredMonk.java index 7b11a00be5..879fce467c 100644 --- a/Mage.Sets/src/mage/cards/g/GeistHonoredMonk.java +++ b/Mage.Sets/src/mage/cards/g/GeistHonoredMonk.java @@ -1,30 +1,30 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.permanent.token.SpiritWhiteToken; +import java.util.UUID; + /** * @author nantuko */ public final class GeistHonoredMonk extends CardImpl { public GeistHonoredMonk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.MONK); @@ -34,7 +34,8 @@ public final class GeistHonoredMonk extends CardImpl { this.addAbility(VigilanceAbility.getInstance()); // Geist-Honored Monk's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); // When Geist-Honored Monk enters the battlefield, create two 1/1 white Spirit creature tokens with flying. this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiritWhiteToken("ISD"), 2))); diff --git a/Mage.Sets/src/mage/cards/g/GeistOfTheLonelyVigil.java b/Mage.Sets/src/mage/cards/g/GeistOfTheLonelyVigil.java index f2b3c24037..4e01c10e3f 100644 --- a/Mage.Sets/src/mage/cards/g/GeistOfTheLonelyVigil.java +++ b/Mage.Sets/src/mage/cards/g/GeistOfTheLonelyVigil.java @@ -1,13 +1,14 @@ - package mage.cards.g; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalAsThoughEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -18,13 +19,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class GeistOfTheLonelyVigil extends CardImpl { public GeistOfTheLonelyVigil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.SPIRIT); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); @@ -40,7 +40,7 @@ public final class GeistOfTheLonelyVigil extends CardImpl { new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), DeliriumCondition.instance); effect.setText("Delirium — {this} can attack as though it didn't have defender as long as there are four or more card types among cards in your graveyard"); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(DeliriumHint.instance)); } public GeistOfTheLonelyVigil(final GeistOfTheLonelyVigil card) { diff --git a/Mage.Sets/src/mage/cards/g/GemOfBecoming.java b/Mage.Sets/src/mage/cards/g/GemOfBecoming.java index 294b640c8d..64e607e0f8 100644 --- a/Mage.Sets/src/mage/cards/g/GemOfBecoming.java +++ b/Mage.Sets/src/mage/cards/g/GemOfBecoming.java @@ -85,7 +85,7 @@ class GemOfBecomingEffect extends OneShotEffect { FilterLandCard filter = new FilterLandCard(subtype); filter.add(new SubtypePredicate(SubType.byDescription(subtype))); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/g/GeneralHux.java b/Mage.Sets/src/mage/cards/g/GeneralHux.java index 653a5381f2..42bfd880d2 100644 --- a/Mage.Sets/src/mage/cards/g/GeneralHux.java +++ b/Mage.Sets/src/mage/cards/g/GeneralHux.java @@ -29,7 +29,7 @@ public final class GeneralHux extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public GeneralHux(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GeneralTazri.java b/Mage.Sets/src/mage/cards/g/GeneralTazri.java index c66d44f250..013d1bd919 100644 --- a/Mage.Sets/src/mage/cards/g/GeneralTazri.java +++ b/Mage.Sets/src/mage/cards/g/GeneralTazri.java @@ -68,7 +68,7 @@ public final class GeneralTazri extends CardImpl { class GeneralTazriColorCount implements DynamicValue { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new SubtypePredicate((SubType.ALLY))); diff --git a/Mage.Sets/src/mage/cards/g/GeneratorServant.java b/Mage.Sets/src/mage/cards/g/GeneratorServant.java index 567c43884d..1cf33279df 100644 --- a/Mage.Sets/src/mage/cards/g/GeneratorServant.java +++ b/Mage.Sets/src/mage/cards/g/GeneratorServant.java @@ -48,7 +48,7 @@ public final class GeneratorServant extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new GeneratorServantHasteEffect()), new GeneratorServantWatcher()); } - public GeneratorServant(final GeneratorServant card) { + private GeneratorServant(final GeneratorServant card) { super(card); } @@ -60,13 +60,13 @@ public final class GeneratorServant extends CardImpl { class GeneratorServantWatcher extends Watcher { - public List creatures = new ArrayList<>(); + private List creatures = new ArrayList<>(); public GeneratorServantWatcher() { - super(GeneratorServantWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } - public GeneratorServantWatcher(final GeneratorServantWatcher watcher) { + private GeneratorServantWatcher(final GeneratorServantWatcher watcher) { super(watcher); this.creatures.addAll(watcher.creatures); } @@ -95,6 +95,10 @@ class GeneratorServantWatcher extends Watcher { creatures.clear(); } + public boolean creatureCastWithServantsMana(UUID permanentId){ + return creatures.contains(permanentId); + } + } class GeneratorServantHasteEffect extends ContinuousEffectImpl { @@ -114,10 +118,10 @@ class GeneratorServantHasteEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - GeneratorServantWatcher watcher = (GeneratorServantWatcher) game.getState().getWatchers().get(GeneratorServantWatcher.class.getSimpleName(), source.getSourceId()); + GeneratorServantWatcher watcher = game.getState().getWatcher(GeneratorServantWatcher.class, source.getSourceId()); if (watcher != null) { for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { - if (watcher.creatures.contains(perm.getId())) { + if (watcher.creatureCastWithServantsMana(perm.getId())) { perm.addAbility(HasteAbility.getInstance(), source.getSourceId(), game); } } diff --git a/Mage.Sets/src/mage/cards/g/GenesisChamber.java b/Mage.Sets/src/mage/cards/g/GenesisChamber.java index 709aa2b523..a739a91f3c 100644 --- a/Mage.Sets/src/mage/cards/g/GenesisChamber.java +++ b/Mage.Sets/src/mage/cards/g/GenesisChamber.java @@ -30,7 +30,7 @@ public final class GenesisChamber extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public GenesisChamber(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GeodeGolem.java b/Mage.Sets/src/mage/cards/g/GeodeGolem.java index f4842176da..d35482b02e 100644 --- a/Mage.Sets/src/mage/cards/g/GeodeGolem.java +++ b/Mage.Sets/src/mage/cards/g/GeodeGolem.java @@ -1,6 +1,5 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -20,8 +19,9 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author spjspj */ public final class GeodeGolem extends CardImpl { @@ -68,7 +68,6 @@ class GeodeGolemEffect extends OneShotEffect { for (UUID commanderId : controller.getCommandersIds()) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card commander = game.getCard(commanderId); - if (commander != null && game.getState().getZone(commanderId) == Zone.COMMAND) { SpellAbility ability = commander.getSpellAbility(); SpellAbility newAbility = commander.getSpellAbility().copy(); diff --git a/Mage.Sets/src/mage/cards/g/GeralfsMasterpiece.java b/Mage.Sets/src/mage/cards/g/GeralfsMasterpiece.java index 629686108c..f5137eb43b 100644 --- a/Mage.Sets/src/mage/cards/g/GeralfsMasterpiece.java +++ b/Mage.Sets/src/mage/cards/g/GeralfsMasterpiece.java @@ -41,7 +41,7 @@ public final class GeralfsMasterpiece extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Geralf's Masterpiece gets -1/-1 for each card in your hand. - DynamicValue count = new SignInversionDynamicValue(new CardsInControllerHandCount()); + DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.instance); Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield); effect.setText("{this} gets -1/-1 for each card in your hand"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/g/GerrardsWisdom.java b/Mage.Sets/src/mage/cards/g/GerrardsWisdom.java index 23e378f90a..27694f04d2 100644 --- a/Mage.Sets/src/mage/cards/g/GerrardsWisdom.java +++ b/Mage.Sets/src/mage/cards/g/GerrardsWisdom.java @@ -20,7 +20,7 @@ public final class GerrardsWisdom extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{W}{W}"); // You gain 2 life for each card in your hand. - this.getSpellAbility().addEffect(new GainLifeEffect(new MultipliedValue(new CardsInControllerHandCount(), 2), + this.getSpellAbility().addEffect(new GainLifeEffect(new MultipliedValue(CardsInControllerHandCount.instance, 2), "You gain 2 life for each card in your hand")); } diff --git a/Mage.Sets/src/mage/cards/g/GetThePoint.java b/Mage.Sets/src/mage/cards/g/GetThePoint.java new file mode 100644 index 0000000000..1e61882237 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GetThePoint.java @@ -0,0 +1,34 @@ +package mage.cards.g; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GetThePoint extends CardImpl { + + public GetThePoint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}{R}"); + + // Destroy target creature. Scry 1. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private GetThePoint(final GetThePoint card) { + super(card); + } + + @Override + public GetThePoint copy() { + return new GetThePoint(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GhalmasWarden.java b/Mage.Sets/src/mage/cards/g/GhalmasWarden.java index 22f8bb494b..a371efbecb 100644 --- a/Mage.Sets/src/mage/cards/g/GhalmasWarden.java +++ b/Mage.Sets/src/mage/cards/g/GhalmasWarden.java @@ -22,7 +22,7 @@ import mage.constants.Zone; */ public final class GhalmasWarden extends CardImpl { - private static final String text = "Metalcraft — Ghalma's Warden gets +2/+2 as long as you control three or more artifacts"; + private static final String rule = "Metalcraft — Ghalma's Warden gets +2/+2 as long as you control three or more artifacts"; public GhalmasWarden (UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); @@ -32,7 +32,7 @@ public final class GhalmasWarden extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(4); ContinuousEffect boostSource = new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield); - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, text); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, MetalcraftCondition.instance, rule); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); } diff --git a/Mage.Sets/src/mage/cards/g/GhirapurAetherGrid.java b/Mage.Sets/src/mage/cards/g/GhirapurAetherGrid.java index da3c5fdb83..aa6f6beadc 100644 --- a/Mage.Sets/src/mage/cards/g/GhirapurAetherGrid.java +++ b/Mage.Sets/src/mage/cards/g/GhirapurAetherGrid.java @@ -26,7 +26,7 @@ public final class GhirapurAetherGrid extends CardImpl { static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public GhirapurAetherGrid(UUID ownerId, CardSetInfo setInfo) { @@ -36,7 +36,7 @@ public final class GhirapurAetherGrid extends CardImpl { SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new TapTargetCost(new TargetControlledPermanent(2, 2, filter, true))); - ability.addTarget(new TargetAnyTarget()); + ability.addTarget(new TargetAnyTarget().withChooseHint("deals 1 damage to")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GhituFire.java b/Mage.Sets/src/mage/cards/g/GhituFire.java index 4da3bde52b..02c5fb90c3 100644 --- a/Mage.Sets/src/mage/cards/g/GhituFire.java +++ b/Mage.Sets/src/mage/cards/g/GhituFire.java @@ -23,7 +23,7 @@ public final class GhituFire extends CardImpl { public GhituFire(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); - Effect effect = new DamageTargetEffect(new ManacostVariableValue()); + Effect effect = new DamageTargetEffect(ManacostVariableValue.instance); // You may cast Ghitu Fire as though it had flash if you pay {2} more to cast it. Ability ability = new PayMoreToCastAsThoughtItHadFlashAbility(this, new ManaCostsImpl("{2}")); ability.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/g/GhituJourneymage.java b/Mage.Sets/src/mage/cards/g/GhituJourneymage.java index 2c7c677c62..8075d92fd9 100644 --- a/Mage.Sets/src/mage/cards/g/GhituJourneymage.java +++ b/Mage.Sets/src/mage/cards/g/GhituJourneymage.java @@ -26,7 +26,7 @@ public final class GhituJourneymage extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Wizard"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.WIZARD)); } diff --git a/Mage.Sets/src/mage/cards/g/GhorClanWrecker.java b/Mage.Sets/src/mage/cards/g/GhorClanWrecker.java new file mode 100644 index 0000000000..eaa24ff172 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GhorClanWrecker.java @@ -0,0 +1,41 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.keyword.RiotAbility; +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 GhorClanWrecker extends CardImpl { + + public GhorClanWrecker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Riot + this.addAbility(new RiotAbility()); + + // Menace + this.addAbility(new MenaceAbility()); + } + + private GhorClanWrecker(final GhorClanWrecker card) { + super(card); + } + + @Override + public GhorClanWrecker copy() { + return new GhorClanWrecker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java b/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java index 91d436f830..e9181831f2 100644 --- a/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java +++ b/Mage.Sets/src/mage/cards/g/GhostCouncilOfOrzhova.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -43,8 +42,13 @@ public final class GhostCouncilOfOrzhova extends CardImpl { this.addAbility(ability); // {1}, Sacrifice a creature: Exile Ghost Council of Orzhova. Return it to the battlefield under its owner's control at the beginning of the next end step. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), new GenericManaCost(1)); - ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); + ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ExileReturnBattlefieldOwnerNextEndStepSourceEffect(true), + new GenericManaCost(1)); + ability.addCost(new SacrificeTargetCost( + new TargetControlledCreaturePermanent( + FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); this.addAbility(ability); } @@ -62,7 +66,7 @@ public final class GhostCouncilOfOrzhova extends CardImpl { class GhostCouncilOfOrzhovaEffect extends OneShotEffect { GhostCouncilOfOrzhovaEffect() { - super(Outcome.Damage); + super(Outcome.GainLife); staticText = "target opponent loses 1 life and you gain 1 life"; } @@ -73,10 +77,12 @@ class GhostCouncilOfOrzhovaEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); - Player controllerPlayer = game.getPlayer(source.getControllerId()); - if (targetPlayer != null && controllerPlayer != null) { + Player controller = game.getPlayer(source.getControllerId()); + if (targetPlayer != null + && controller != null) { targetPlayer.loseLife(1, game, false); - controllerPlayer.gainLife(1, game, source); + controller.gainLife(1, game, source); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GhostQuarter.java b/Mage.Sets/src/mage/cards/g/GhostQuarter.java index b84b4a3ba4..881f2da242 100644 --- a/Mage.Sets/src/mage/cards/g/GhostQuarter.java +++ b/Mage.Sets/src/mage/cards/g/GhostQuarter.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -16,7 +15,6 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.StaticFilters; -import mage.filter.common.FilterBasicLandCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -30,7 +28,7 @@ import mage.target.common.TargetLandPermanent; public final class GhostQuarter extends CardImpl { public GhostQuarter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // {T}: Add {C}. this.addAbility(new ColorlessManaAbility()); @@ -73,9 +71,9 @@ class GhostQuarterEffect extends OneShotEffect { Permanent permanent = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (permanent != null) { Player controller = game.getPlayer(permanent.getControllerId()); - if (controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { + if (controller != null && controller.chooseUse(Outcome.PutLandInPlay, "Do you wish to search for a basic land, put it onto the battlefield and then shuffle your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/g/GhostlyWings.java b/Mage.Sets/src/mage/cards/g/GhostlyWings.java index 68832eec27..0451e1a387 100644 --- a/Mage.Sets/src/mage/cards/g/GhostlyWings.java +++ b/Mage.Sets/src/mage/cards/g/GhostlyWings.java @@ -80,7 +80,7 @@ class GhostlyWingsReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && permanent != null && permanent.getAttachedTo() != null) { Permanent enchantedCreature = game.getPermanent(permanent.getAttachedTo()); diff --git a/Mage.Sets/src/mage/cards/g/Ghostway.java b/Mage.Sets/src/mage/cards/g/Ghostway.java index 5f965b71af..957731373b 100644 --- a/Mage.Sets/src/mage/cards/g/Ghostway.java +++ b/Mage.Sets/src/mage/cards/g/Ghostway.java @@ -76,7 +76,7 @@ class GhostwayEffect extends OneShotEffect { Cards cardsToReturn = new CardsImpl(); for (Card exiled : toExile) { - if (((Permanent) exiled).getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) { + if (exiled.getZoneChangeCounter(game) == game.getState().getZoneChangeCounter(exiled.getId()) - 1) { cardsToReturn.add(exiled); } } diff --git a/Mage.Sets/src/mage/cards/g/GhoulcallerGisa.java b/Mage.Sets/src/mage/cards/g/GhoulcallerGisa.java index 273ee19760..89b9458fc4 100644 --- a/Mage.Sets/src/mage/cards/g/GhoulcallerGisa.java +++ b/Mage.Sets/src/mage/cards/g/GhoulcallerGisa.java @@ -40,7 +40,7 @@ public final class GhoulcallerGisa extends CardImpl { this.toughness = new MageInt(4); // {B}, {tap}, Sacrifice another creature: create X 2/2 black Zombie creature tokens, where X is the sacrificed creature's power. - DynamicValue xValue = new SacrificeCostCreaturesPower(); + DynamicValue xValue = SacrificeCostCreaturesPower.instance; Token zombie = new ZombieToken(); zombie.setTokenType(2); Effect effect = new CreateTokenEffect(zombie, xValue); diff --git a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java index 52faf34e7c..7489c01982 100644 --- a/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java +++ b/Mage.Sets/src/mage/cards/g/GhoulcallersChant.java @@ -33,8 +33,8 @@ public final class GhoulcallersChant extends CardImpl { this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // or return two target Zombie cards from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(2, filter)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(2, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GiantAlbatross.java b/Mage.Sets/src/mage/cards/g/GiantAlbatross.java index d2c05f3e8c..f6f27628e4 100644 --- a/Mage.Sets/src/mage/cards/g/GiantAlbatross.java +++ b/Mage.Sets/src/mage/cards/g/GiantAlbatross.java @@ -74,7 +74,7 @@ class GiantAlbatrossEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null) { + if (sourcePermanent != null && controller != null) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/g/GiantOyster.java b/Mage.Sets/src/mage/cards/g/GiantOyster.java index 05617d00dc..6b4dacd028 100644 --- a/Mage.Sets/src/mage/cards/g/GiantOyster.java +++ b/Mage.Sets/src/mage/cards/g/GiantOyster.java @@ -1,5 +1,6 @@ package mage.cards.g; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -27,8 +28,6 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; -import java.util.UUID; - /** * * @author noahg @@ -38,12 +37,12 @@ public final class GiantOyster extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public GiantOyster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); - + this.subtype.add(SubType.OYSTER); this.power = new MageInt(0); this.toughness = new MageInt(3); @@ -111,7 +110,6 @@ class GiantOysterCreateDelayedTriggerEffects extends OneShotEffect { Effect addCountersEffect = new AddCountersTargetEffect(CounterType.M1M1.createInstance(1)); addCountersEffect.setTargetPointer(getTargetPointer().getFixedTarget(game, source)); DelayedTriggeredAbility drawStepAbility = new AtTheBeginOfYourNextDrawStepDelayedTriggeredAbility(addCountersEffect, Duration.Custom, false); - drawStepAbility.setSourceObject(oyster, game); drawStepAbility.setControllerId(source.getControllerId()); UUID drawStepAbilityUUID = game.addDelayedTriggeredAbility(drawStepAbility, source); @@ -161,4 +159,4 @@ class GiantOysterLeaveUntapDelayedTriggeredAbility extends DelayedTriggeredAbili public String getRule() { return "When {this} leaves the battlefield or becomes untapped, remove all -1/-1 counters from the creature."; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GiantSlug.java b/Mage.Sets/src/mage/cards/g/GiantSlug.java new file mode 100644 index 0000000000..8cfc8d42f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiantSlug.java @@ -0,0 +1,104 @@ + +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.LandwalkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceBasicLandType; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author L_J + */ +public final class GiantSlug extends CardImpl { + + public GiantSlug(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.SLUG); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {5}: At the beginning of your next upkeep, choose a basic land type. Giant Slug gains landwalk of the chosen type until the end of that turn. + AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility ability = new AtTheBeginOfYourNextUpkeepDelayedTriggeredAbility(new GiantSlugEffect()); + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateDelayedTriggeredAbilityEffect(ability), new ManaCostsImpl("{5}"))); + } + + public GiantSlug(final GiantSlug card) { + super(card); + } + + @Override + public GiantSlug copy() { + return new GiantSlug(this); + } + +} + +class GiantSlugEffect extends OneShotEffect { + + public GiantSlugEffect() { + super(Outcome.AddAbility); + this.staticText = "At the beginning of your next upkeep, choose a basic land type. {this} gains landwalk of the chosen type until the end of that turn"; + } + + public GiantSlugEffect(final GiantSlugEffect effect) { + super(effect); + } + + @Override + public GiantSlugEffect copy() { + return new GiantSlugEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + ChoiceImpl choices = new ChoiceBasicLandType(); + if (controller.choose(outcome, choices, game)) { + game.informPlayers(sourcePermanent.getName() + ": Chosen basic land type is " + choices.getChoice()); + FilterLandPermanent filter = new FilterLandPermanent(choices.getChoice()); + if (choices.getChoice().equals("Plains")) { + filter.add(new SubtypePredicate(SubType.PLAINS)); + } + if (choices.getChoice().equals("Island")) { + filter.add(new SubtypePredicate(SubType.ISLAND)); + } + if (choices.getChoice().equals("Swamp")) { + filter.add(new SubtypePredicate(SubType.SWAMP)); + } + if (choices.getChoice().equals("Mountain")) { + filter.add(new SubtypePredicate(SubType.MOUNTAIN)); + } + if (choices.getChoice().equals("Forest")) { + filter.add(new SubtypePredicate(SubType.FOREST)); + } + Ability landwalkAbility = new LandwalkAbility(filter); + game.addEffect(new GainAbilitySourceEffect(landwalkAbility, Duration.EndOfTurn, false), source); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java index 3e25f1cff0..d885595e3f 100644 --- a/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java +++ b/Mage.Sets/src/mage/cards/g/GiantTrapDoorSpider.java @@ -17,7 +17,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/g/GiantTurtle.java b/Mage.Sets/src/mage/cards/g/GiantTurtle.java index 6d0e100c75..dc7c0aabd6 100644 --- a/Mage.Sets/src/mage/cards/g/GiantTurtle.java +++ b/Mage.Sets/src/mage/cards/g/GiantTurtle.java @@ -1,8 +1,5 @@ - package mage.cards.g; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -18,8 +15,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.AttackedLastTurnWatcher; +import java.util.Set; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class GiantTurtle extends CardImpl { @@ -62,14 +61,12 @@ class CantAttackIfAttackedLastTurnEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { - AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName()); + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + AttackedLastTurnWatcher watcher = game.getState().getWatcher(AttackedLastTurnWatcher.class); if (watcher != null) { Set attackingCreatures = watcher.getAttackedLastTurnCreatures(attacker.getControllerId()); MageObjectReference mor = new MageObjectReference(attacker, game); - if (attackingCreatures.contains(mor)) { - return false; - } + return !attackingCreatures.contains(mor); } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GibberingFiend.java b/Mage.Sets/src/mage/cards/g/GibberingFiend.java index 024fd71faa..bc508eb7c0 100644 --- a/Mage.Sets/src/mage/cards/g/GibberingFiend.java +++ b/Mage.Sets/src/mage/cards/g/GibberingFiend.java @@ -1,7 +1,7 @@ - package mage.cards.g; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,13 +18,12 @@ import mage.constants.TargetController; import mage.constants.Zone; /** - * * @author fireshoes */ public final class GibberingFiend extends CardImpl { public GibberingFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.DEVIL); this.power = new MageInt(2); this.toughness = new MageInt(1); @@ -37,7 +37,8 @@ public final class GibberingFiend extends CardImpl { new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), TargetController.OPPONENT, false, true), DeliriumCondition.instance, "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "{this} deals 1 damage to that player.")); + + "{this} deals 1 damage to that player.") + .addHint(DeliriumHint.instance)); } public GibberingFiend(final GibberingFiend card) { diff --git a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java index 79b4801059..b1957ada17 100644 --- a/Mage.Sets/src/mage/cards/g/GideonBattleForged.java +++ b/Mage.Sets/src/mage/cards/g/GideonBattleForged.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -16,12 +14,7 @@ import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.constants.TurnPhase; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -29,20 +22,21 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.TokenImpl; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GideonBattleForged extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); } public GideonBattleForged(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},""); + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GIDEON); @@ -98,6 +92,7 @@ class GideonBattleForgedToken extends TokenImpl { toughness = new MageInt(4); this.addAbility(IndestructibleAbility.getInstance()); } + public GideonBattleForgedToken(final GideonBattleForgedToken token) { super(token); } @@ -109,7 +104,6 @@ class GideonBattleForgedToken extends TokenImpl { class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { - int nextTurnTargetController = 0; protected MageObjectReference targetPermanentReference; public GideonBattleForgedAttacksIfAbleTargetEffect(Duration duration) { @@ -119,7 +113,6 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { public GideonBattleForgedAttacksIfAbleTargetEffect(final GideonBattleForgedAttacksIfAbleTargetEffect effect) { super(effect); - this.nextTurnTargetController = effect.nextTurnTargetController; this.targetPermanentReference = effect.targetPermanentReference; } @@ -137,10 +130,7 @@ class GideonBattleForgedAttacksIfAbleTargetEffect extends RequirementEffect { if (targetPermanent == null) { return true; } - if (nextTurnTargetController == 0 && startingTurn != game.getTurnNum() && game.isActivePlayer(targetPermanent.getControllerId())) { - nextTurnTargetController = game.getTurnNum(); - } - return game.getPhase().getType() == TurnPhase.END && nextTurnTargetController > 0 && game.getTurnNum() > nextTurnTargetController; + return game.getPhase().getType() == TurnPhase.END && game.getTurnNum() > getNextStartingControllerTurnNum(); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GideonBlackblade.java b/Mage.Sets/src/mage/cards/g/GideonBlackblade.java new file mode 100644 index 0000000000..c45c68e9be --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonBlackblade.java @@ -0,0 +1,166 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TokenImpl; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetNonlandPermanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonBlackblade extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another other creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public GideonBlackblade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.GIDEON); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // As long as it's your turn, Gideon Blackblade is a 4/4 Human Soldier creature with indestructible that's still a planeswalker. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new BecomesCreatureSourceEffect( + new GideonBlackbladeToken(), "planeswalker", Duration.WhileOnBattlefield + ), MyTurnCondition.instance, "As long as it's your turn, " + + "{this} is a 4/4 Human Soldier creature with indestructible that's still a planeswalker." + ))); + + // Prevent all damage that would be dealt to Gideon Blackblade during your turn. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new PreventAllDamageToSourceEffect(Duration.WhileOnBattlefield), + MyTurnCondition.instance, "Prevent all damage that would be dealt to {this} during your turn." + ))); + + // +1: Up to one other target creature you control gains your choice of vigilance, lifelink, or indestructible until end of turn. + Ability ability = new LoyaltyAbility(new GideonBlackbladeEffect(), 1); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + this.addAbility(ability); + + // -6: Exile target nonland permanent. + ability = new LoyaltyAbility(new ExileTargetEffect(), -6); + ability.addTarget(new TargetNonlandPermanent()); + this.addAbility(ability); + } + + private GideonBlackblade(final GideonBlackblade card) { + super(card); + } + + @Override + public GideonBlackblade copy() { + return new GideonBlackblade(this); + } +} + +class GideonBlackbladeToken extends TokenImpl { + + GideonBlackbladeToken() { + super("", "4/4 Human Soldier creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HUMAN); + subtype.add(SubType.SOLDIER); + power = new MageInt(4); + toughness = new MageInt(4); + addAbility(IndestructibleAbility.getInstance()); + } + + private GideonBlackbladeToken(final GideonBlackbladeToken token) { + super(token); + } + + @Override + public GideonBlackbladeToken copy() { + return new GideonBlackbladeToken(this); + } +} + +class GideonBlackbladeEffect extends OneShotEffect { + private static final Set choices = new HashSet(); + + static { + choices.add("Vigilance"); + choices.add("Lifelink"); + choices.add("Indestructible"); + } + + GideonBlackbladeEffect() { + super(Outcome.Benefit); + staticText = "Up to one other target creature you control gains your choice of " + + "vigilance, lifelink, or indestructible until end of turn."; + } + + private GideonBlackbladeEffect(final GideonBlackbladeEffect effect) { + super(effect); + } + + @Override + public GideonBlackbladeEffect copy() { + return new GideonBlackbladeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (player == null || permanent == null) { + return false; + } + Choice choice = new ChoiceImpl(true); + choice.setMessage("Choose an ability to give to " + permanent.getLogName()); + choice.setChoices(choices); + if (!player.choose(outcome, choice, game)) { + return false; + } + Ability ability = null; + switch (choice.getChoice()) { + case "Vigilance": + ability = VigilanceAbility.getInstance(); + break; + case "Lifelink": + ability = LifelinkAbility.getInstance(); + break; + case "Indestructible": + ability = IndestructibleAbility.getInstance(); + break; + } + if (ability != null) { + game.addEffect(new GainAbilityTargetEffect(ability, Duration.EndOfTurn), source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GideonJura.java b/Mage.Sets/src/mage/cards/g/GideonJura.java index d18f502891..20c597978c 100644 --- a/Mage.Sets/src/mage/cards/g/GideonJura.java +++ b/Mage.Sets/src/mage/cards/g/GideonJura.java @@ -1,6 +1,5 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -13,11 +12,7 @@ import mage.abilities.effects.common.PreventAllDamageToSourceEffect; import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; 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.constants.TurnPhase; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; @@ -26,8 +21,9 @@ import mage.game.permanent.token.TokenImpl; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class GideonJura extends CardImpl { @@ -35,7 +31,7 @@ public final class GideonJura extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public GideonJura(UUID ownerId, CardSetInfo setInfo) { @@ -127,7 +123,7 @@ class GideonJuraEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { - return (startingTurn != game.getTurnNum() + return (getStartingTurnNum() != game.getTurnNum() && (game.getPhase().getType() == TurnPhase.END && game.isActivePlayer(source.getFirstTarget()))) || // 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura (because he's no longer on the battlefield, for example), that player may have it attack you, another one of your planeswalkers, or nothing at all. diff --git a/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java b/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java new file mode 100644 index 0000000000..d1ab66a505 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonTheOathsworn.java @@ -0,0 +1,167 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileAllEffect; +import mage.abilities.effects.common.ExileSourceEffect; +import mage.abilities.effects.common.PreventAllDamageToSourceEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TokenImpl; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonTheOathsworn extends CardImpl { + + public GideonTheOathsworn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.GIDEON); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Whenever you attack with two or more non-Gideon creatures, put a +1/+1 counter on each of those creatures. + this.addAbility(new GideonTheOathswornTriggeredAbility()); + + // +2: Until end of turn, Gideon, the Oathsworn becomes a 5/5 white Soldier creature that's still a planeswalker. Prevent all damage that would be dealt to him this turn. + Ability ability = new LoyaltyAbility(new BecomesCreatureSourceEffect( + new GideonTheOathswornToken(), "planeswalker", Duration.EndOfTurn + ), 2); + ability.addEffect(new PreventAllDamageToSourceEffect( + Duration.EndOfTurn + ).setText("Prevent all damage that would be dealt to him this turn")); + this.addAbility(ability); + + // -9: Exile Gideon, the Oathsworn and each creature your opponents control. + ability = new LoyaltyAbility(new ExileSourceEffect(), -9); + ability.addEffect(new ExileAllEffect( + StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE + ).setText("and each creature your opponents control")); + this.addAbility(ability); + } + + private GideonTheOathsworn(final GideonTheOathsworn card) { + super(card); + } + + @Override + public GideonTheOathsworn copy() { + return new GideonTheOathsworn(this); + } +} + +class GideonTheOathswornTriggeredAbility extends TriggeredAbilityImpl { + + GideonTheOathswornTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + private GideonTheOathswornTriggeredAbility(final GideonTheOathswornTriggeredAbility ability) { + super(ability); + } + + @Override + public GideonTheOathswornTriggeredAbility copy() { + return new GideonTheOathswornTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.getCombat().getAttackingPlayerId().equals(getControllerId())) { + int attackerCount = 0; + Set attackers = new HashSet(); + for (UUID attackerId : game.getCombat().getAttackers()) { + Permanent permanent = game.getPermanent(attackerId); + if (permanent != null && permanent.isCreature() && !permanent.hasSubtype(SubType.GIDEON, game)) { + attackerCount++; + attackers.add(new MageObjectReference(permanent, game)); + } + } + if (attackerCount >= 2) { + this.getEffects().clear(); + this.addEffect(new GideonTheOathswornEffect(attackers)); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you attack with two or more non-Gideon creatures, " + + "put a +1/+1 counter on each of those creatures."; + } +} + +class GideonTheOathswornEffect extends OneShotEffect { + + private final Set attackers; + + GideonTheOathswornEffect(Set attackers) { + super(Outcome.Benefit); + this.attackers = attackers; + } + + private GideonTheOathswornEffect(final GideonTheOathswornEffect effect) { + super(effect); + this.attackers = effect.attackers; + } + + @Override + public GideonTheOathswornEffect copy() { + return new GideonTheOathswornEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (MageObjectReference mor : attackers) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null) { + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + } + return true; + } +} + +class GideonTheOathswornToken extends TokenImpl { + + GideonTheOathswornToken() { + super("", "5/5 white Soldier creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SOLDIER); + power = new MageInt(5); + toughness = new MageInt(5); + } + + private GideonTheOathswornToken(final GideonTheOathswornToken token) { + super(token); + } + + @Override + public GideonTheOathswornToken copy() { + return new GideonTheOathswornToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GideonsBattleCry.java b/Mage.Sets/src/mage/cards/g/GideonsBattleCry.java new file mode 100644 index 0000000000..7a48f5008d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonsBattleCry.java @@ -0,0 +1,46 @@ +package mage.cards.g; + +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.NamePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonsBattleCry extends CardImpl { + + private static final FilterCard filter = new FilterCard("Gideon, the Oathsworn"); + + static { + filter.add(new NamePredicate("Gideon, the Oathsworn")); + } + + public GideonsBattleCry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}"); + + // Put a +1/+1 counter on each creature you control. You may search your library and/or graveyard for a card named Gideon, the Oathsworn, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + )); + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect( + filter, false, true + )); + } + + private GideonsBattleCry(final GideonsBattleCry card) { + super(card); + } + + @Override + public GideonsBattleCry copy() { + return new GideonsBattleCry(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GideonsCompany.java b/Mage.Sets/src/mage/cards/g/GideonsCompany.java new file mode 100644 index 0000000000..f5e3a03f7d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonsCompany.java @@ -0,0 +1,57 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.GainLifeControllerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.filter.FilterPermanent; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonsCompany extends CardImpl { + + private static final FilterPermanent filter = new FilterPlaneswalkerPermanent(SubType.GIDEON); + + public GideonsCompany(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever you gain life, put two +1/+1 counters on Gideon's Company. + this.addAbility(new GainLifeControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), false + )); + + // {3}{W}: Put a loyalty counter on target Gideon planeswalker. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.LOYALTY.createInstance()), new ManaCostsImpl("{3}{W}") + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private GideonsCompany(final GideonsCompany card) { + super(card); + } + + @Override + public GideonsCompany copy() { + return new GideonsCompany(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GideonsResolve.java b/Mage.Sets/src/mage/cards/g/GideonsResolve.java index c5826bf335..561bac51b2 100644 --- a/Mage.Sets/src/mage/cards/g/GideonsResolve.java +++ b/Mage.Sets/src/mage/cards/g/GideonsResolve.java @@ -20,7 +20,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class GideonsResolve extends CardImpl { - private final static FilterCard filter = new FilterCard("Gideon, Martial Paragon"); + private static final FilterCard filter = new FilterCard("Gideon, Martial Paragon"); static { filter.add(new NamePredicate("Gideon, Martial Paragon")); diff --git a/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java b/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java new file mode 100644 index 0000000000..4bdccaf0aa --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonsSacrifice.java @@ -0,0 +1,181 @@ +package mage.cards.g; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonsSacrifice extends CardImpl { + + public GideonsSacrifice(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Choose a creature or planeswalker you control. All damage that would be dealt this turn to you and permanents you control is dealt to the chosen permanent instead. + this.getSpellAbility().addEffect(new GideonsSacrificeEffect()); + } + + private GideonsSacrifice(final GideonsSacrifice card) { + super(card); + } + + @Override + public GideonsSacrifice copy() { + return new GideonsSacrifice(this); + } +} + +class GideonsSacrificeEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledPermanent("creature or planeswalker you controls"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.CREATURE) + )); + } + + GideonsSacrificeEffect() { + super(Outcome.Benefit); + staticText = "Choose a creature or planeswalker you control. " + + "All damage that would be dealt this turn to you " + + "and permanents you control is dealt to the chosen permanent instead."; + } + + private GideonsSacrificeEffect(final GideonsSacrificeEffect effect) { + super(effect); + } + + @Override + public GideonsSacrificeEffect copy() { + return new GideonsSacrificeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetPermanent(filter); + target.setNotTarget(true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + game.addEffect(new GideonsSacrificeEffectReplacementEffect( + new MageObjectReference(target.getFirstTarget(), game) + ), source); + return true; + } +} + +class GideonsSacrificeEffectReplacementEffect extends ReplacementEffectImpl { + + private final MageObjectReference mor; + + GideonsSacrificeEffectReplacementEffect(MageObjectReference mor) { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + this.mor = mor; + } + + private GideonsSacrificeEffectReplacementEffect(final GideonsSacrificeEffectReplacementEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER + && event.getPlayerId().equals(source.getControllerId())) { + return true; + } + if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE + || event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER) { + Permanent targetPermanent = game.getPermanent(event.getTargetId()); + if (targetPermanent != null + && targetPermanent.isControlledBy(source.getControllerId())) { + return true; + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + + Permanent permanent = mor.getPermanent(game); + + if (permanent == null) { + return false; + } + + // Name of old target + Permanent targetPermanent = game.getPermanent(event.getTargetId()); + StringBuilder message = new StringBuilder(); + message.append(permanent.getName()).append(": gets "); + message.append(damageEvent.getAmount()).append(" damage redirected from "); + if (targetPermanent != null) { + message.append(targetPermanent.getName()); + } else { + Player targetPlayer = game.getPlayer(event.getTargetId()); + if (targetPlayer != null) { + message.append(targetPlayer.getLogName()); + } else { + message.append("unknown"); + } + + } + game.informPlayers(message.toString()); + // Redirect damage + permanent.damage( + damageEvent.getAmount(), damageEvent.getSourceId(), game, + damageEvent.isCombatDamage(), damageEvent.isPreventable(), event.getAppliedEffects() + ); + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public GideonsSacrificeEffectReplacementEffect copy() { + return new GideonsSacrificeEffectReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GideonsTriumph.java b/Mage.Sets/src/mage/cards/g/GideonsTriumph.java new file mode 100644 index 0000000000..cd8c9b6242 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GideonsTriumph.java @@ -0,0 +1,131 @@ +package mage.cards.g; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetOpponent; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GideonsTriumph extends CardImpl { + + public GideonsTriumph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Target opponent sacrifices a creature that attacked or blocked this turn. If you control a Gideon planeswalker, that player sacrifices two of those creatures instead. + this.getSpellAbility().addEffect(new GideonsTriumphEffect()); + this.getSpellAbility().addTarget(new TargetOpponent()); + this.getSpellAbility().addWatcher(new GideonsTriumphWatcher()); + } + + private GideonsTriumph(final GideonsTriumph card) { + super(card); + } + + @Override + public GideonsTriumph copy() { + return new GideonsTriumph(this); + } +} + +class GideonsTriumphEffect extends OneShotEffect { + + private static final FilterControlledPlaneswalkerPermanent filterGideon + = new FilterControlledPlaneswalkerPermanent(SubType.GIDEON); + private static final FilterPermanent filterSacrifice + = new FilterPermanent("creature that attacked or blocked this turn"); + + static { + filterSacrifice.add(GideonsTriumphPredicate.instance); + } + + GideonsTriumphEffect() { + super(Outcome.Benefit); + staticText = "Target opponent sacrifices a creature that attacked or blocked this turn. " + + "If you control a Gideon planeswalker, that player sacrifices two of those creatures instead."; + } + + private GideonsTriumphEffect(final GideonsTriumphEffect effect) { + super(effect); + } + + @Override + public GideonsTriumphEffect copy() { + return new GideonsTriumphEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int count = 1; + if (!game.getBattlefield().getActivePermanents(filterGideon, source.getControllerId(), game).isEmpty()) { + count++; + } + return new SacrificeEffect(filterSacrifice, count, "Target opponent").apply(game, source); + } +} + +enum GideonsTriumphPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + GideonsTriumphWatcher watcher = game.getState().getWatcher(GideonsTriumphWatcher.class); + return input.isCreature() && watcher.attackedOrBlockedThisTurn(input, game); + } +} + +class GideonsTriumphWatcher extends Watcher { + + private final Set attackedOrBlockedThisTurnCreatures = new HashSet<>(); + + public GideonsTriumphWatcher() { + super(WatcherScope.GAME); + } + + private GideonsTriumphWatcher(final GideonsTriumphWatcher watcher) { + super(watcher); + this.attackedOrBlockedThisTurnCreatures.addAll(watcher.attackedOrBlockedThisTurnCreatures); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED || event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { + this.attackedOrBlockedThisTurnCreatures.add(new MageObjectReference(event.getSourceId(), game)); + } + } + + boolean attackedOrBlockedThisTurn(Permanent permanent, Game game) { + return this.attackedOrBlockedThisTurnCreatures.contains(new MageObjectReference(permanent, game)); + } + + + @Override + public GideonsTriumphWatcher copy() { + return new GideonsTriumphWatcher(this); + } + + @Override + public void reset() { + attackedOrBlockedThisTurnCreatures.clear(); + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java b/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java new file mode 100644 index 0000000000..185f1a9eb7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GiftOfTheWoods.java @@ -0,0 +1,54 @@ + +package mage.cards.g; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Ketsuban + */ +public final class GiftOfTheWoods extends CardImpl { + + public GiftOfTheWoods(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.ENCHANTMENT }, "{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); + this.getSpellAbility().addTarget(auraTarget); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature blocks or becomes blocked, it gets +0/+3 until + // end of turn and you gain 1 life. + Ability ability2 = new BlocksOrBecomesBlockedTriggeredAbility( + new BoostEnchantedEffect(0, 3, Duration.EndOfTurn), false); + ability2.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability2); + } + + public GiftOfTheWoods(final GiftOfTheWoods card) { + super(card); + } + + @Override + public GiftOfTheWoods copy() { + return new GiftOfTheWoods(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java index 154e932ad9..c99f4c54f1 100644 --- a/Mage.Sets/src/mage/cards/g/GiftsUngiven.java +++ b/Mage.Sets/src/mage/cards/g/GiftsUngiven.java @@ -67,7 +67,7 @@ class GiftsUngivenEffect extends OneShotEffect { return false; } GiftsUngivenTarget target = new GiftsUngivenTarget(); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/g/Gigantiform.java b/Mage.Sets/src/mage/cards/g/Gigantiform.java index 35c5f5742d..f20cfb120c 100644 --- a/Mage.Sets/src/mage/cards/g/Gigantiform.java +++ b/Mage.Sets/src/mage/cards/g/Gigantiform.java @@ -113,7 +113,7 @@ class GigantiformEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller != null && controller.searchLibrary(target, game)) { + if (controller != null && controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/g/Gigantoplasm.java b/Mage.Sets/src/mage/cards/g/Gigantoplasm.java index 2b0eab220b..df6f0f4eae 100644 --- a/Mage.Sets/src/mage/cards/g/Gigantoplasm.java +++ b/Mage.Sets/src/mage/cards/g/Gigantoplasm.java @@ -57,7 +57,7 @@ class GigantoplasmApplyToPermanent extends ApplyToPermanent { @Override public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) { - DynamicValue variableMana = new ManacostVariableValue(); + DynamicValue variableMana = ManacostVariableValue.instance; Effect effect = new SetPowerToughnessSourceEffect(variableMana, Duration.WhileOnBattlefield, SubLayer.SetPT_7b); effect.setText("This creature has base power and toughness X/X"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); @@ -67,7 +67,7 @@ class GigantoplasmApplyToPermanent extends ApplyToPermanent { @Override public boolean apply(Game game, MageObject mageObject, Ability source, UUID copyToObjectId) { - DynamicValue variableMana = new ManacostVariableValue(); + DynamicValue variableMana = ManacostVariableValue.instance; Effect effect = new SetPowerToughnessSourceEffect(variableMana, Duration.WhileOnBattlefield, SubLayer.SetPT_7b); effect.setText("This creature has base power and toughness X/X"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); diff --git a/Mage.Sets/src/mage/cards/g/GildedCerodon.java b/Mage.Sets/src/mage/cards/g/GildedCerodon.java index c2abfda696..f89e51e141 100644 --- a/Mage.Sets/src/mage/cards/g/GildedCerodon.java +++ b/Mage.Sets/src/mage/cards/g/GildedCerodon.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -66,12 +65,8 @@ class GildedCerodonCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null - && (!game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).isEmpty() - || controller.getGraveyard().count(filter2, game) > 0)) { - return true; - } - return false; + return (!game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game).isEmpty() + || !controller.getGraveyard().getCards(filter2, game).isEmpty()); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java b/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java index 07e4251a6a..3395c5e64b 100644 --- a/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java +++ b/Mage.Sets/src/mage/cards/g/GiltLeafWinnower.java @@ -25,7 +25,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class GiltLeafWinnower extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Elf creature whose power and toughness aren't equal"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Elf creature whose power and toughness aren't equal"); static { filter.add(Predicates.not(new SubtypePredicate(SubType.ELF))); diff --git a/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java b/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java index 82ac97ef3c..1c0fd0e869 100644 --- a/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java +++ b/Mage.Sets/src/mage/cards/g/GiltspireAvenger.java @@ -68,7 +68,7 @@ class GiltspireAvengerTarget extends TargetPermanent { @Override public boolean canTarget(UUID id, Ability source, Game game) { - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), source.getControllerId()); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, source.getControllerId()); if (watcher != null && watcher.hasSourceDoneDamage(id, game)) { return super.canTarget(id, source, game); } @@ -79,7 +79,7 @@ class GiltspireAvengerTarget extends TargetPermanent { public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), sourceControllerId); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); for (UUID targetId : availablePossibleTargets) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && watcher != null && watcher.hasSourceDoneDamage(targetId, game)) { @@ -97,7 +97,7 @@ class GiltspireAvengerTarget extends TargetPermanent { } int count = 0; MageObject targetSource = game.getObject(sourceId); - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), sourceControllerId); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game) && watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java b/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java index 66e7d23cbd..b0080c17d2 100644 --- a/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java +++ b/Mage.Sets/src/mage/cards/g/GisaAndGeralf.java @@ -120,8 +120,8 @@ class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl { public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { if (objectId.equals(getTargetPointer().getFirst(game, source))) { if (affectedControllerId.equals(source.getControllerId())) { - GisaAndGeralfWatcher watcher = (GisaAndGeralfWatcher) game.getState().getWatchers().get(GisaAndGeralfWatcher.class.getSimpleName(), source.getSourceId()); - return !watcher.isAbilityUsed(); + GisaAndGeralfWatcher watcher = game.getState().getWatcher(GisaAndGeralfWatcher.class, source.getSourceId()); + return watcher != null && !watcher.isAbilityUsed(); } } return false; @@ -130,10 +130,10 @@ class GisaAndGeralfCastFromGraveyardEffect extends AsThoughEffectImpl { class GisaAndGeralfWatcher extends Watcher { - boolean abilityUsed = false; + private boolean abilityUsed = false; GisaAndGeralfWatcher() { - super("GisaAndGeralfWatcher", WatcherScope.CARD); + super(WatcherScope.CARD); } GisaAndGeralfWatcher(final GisaAndGeralfWatcher watcher) { @@ -145,7 +145,7 @@ class GisaAndGeralfWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.GRAVEYARD) { Spell spell = (Spell) game.getObject(event.getTargetId()); - if (spell.isCreature() && spell.hasSubtype(SubType.ZOMBIE, game)) { + if (spell != null && spell.isCreature() && spell.hasSubtype(SubType.ZOMBIE, game)) { abilityUsed = true; } } diff --git a/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java b/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java index 79dd93dfd9..58cdb7b47a 100644 --- a/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java +++ b/Mage.Sets/src/mage/cards/g/GiselaBladeOfGoldnight.java @@ -1,10 +1,11 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.FlyingAbility; @@ -13,12 +14,13 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; +import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * @author noxx + * @author TheElk801 */ public final class GiselaBladeOfGoldnight extends CardImpl { @@ -34,11 +36,13 @@ public final class GiselaBladeOfGoldnight extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // If a source would deal damage to an opponent or a permanent an opponent controls, that source deals double that damage to that player or permanent instead. + this.addAbility(new SimpleStaticAbility(new GiselaBladeOfGoldnightDoubleDamageEffect())); + // If a source would deal damage to you or a permanent you control, prevent half that damage, rounded up. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GiselaBladeOfGoldnightDoubleDamageEffect())); + this.addAbility(new SimpleStaticAbility(new GiselaBladeOfGoldnightPreventionEffect())); } - public GiselaBladeOfGoldnight(final GiselaBladeOfGoldnight card) { + private GiselaBladeOfGoldnight(final GiselaBladeOfGoldnight card) { super(card); } @@ -50,13 +54,13 @@ public final class GiselaBladeOfGoldnight extends CardImpl { class GiselaBladeOfGoldnightDoubleDamageEffect extends ReplacementEffectImpl { - public GiselaBladeOfGoldnightDoubleDamageEffect() { + GiselaBladeOfGoldnightDoubleDamageEffect() { super(Duration.WhileOnBattlefield, Outcome.Damage); - staticText = "If a source would deal damage to an opponent or a permanent an opponent controls, that source deals double that damage to that player or permanent instead." - + "If a source would deal damage to you or a permanent you control, prevent half that damage, rounded up"; + staticText = "If a source would deal damage to an opponent or a permanent an opponent controls, " + + "that source deals double that damage to that player or permanent instead."; } - public GiselaBladeOfGoldnightDoubleDamageEffect(final GiselaBladeOfGoldnightDoubleDamageEffect effect) { + private GiselaBladeOfGoldnightDoubleDamageEffect(final GiselaBladeOfGoldnightDoubleDamageEffect effect) { super(effect); } @@ -67,24 +71,24 @@ class GiselaBladeOfGoldnightDoubleDamageEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == EventType.DAMAGE_CREATURE || - event.getType() == EventType.DAMAGE_PLANESWALKER || - event.getType() == EventType.DAMAGE_PLAYER; + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLAYER: + case DAMAGE_PLANESWALKER: + return true; + default: + return false; + } } - @Override public boolean applies(GameEvent event, Ability source, Game game) { - return true; - } - - private void preventDamage(GameEvent event, Ability source, UUID target, Game game) { - int amount = (int) Math.ceil(event.getAmount() / 2.0); - GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, target, source.getSourceId(), source.getControllerId(), amount, false); - if (!game.replaceEvent(preventEvent)) { - event.setAmount(event.getAmount() - amount); - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, target, source.getSourceId(), source.getControllerId(), amount)); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; } + return player.hasOpponent(event.getTargetId(), game) + || player.hasOpponent(game.getControllerId(event.getTargetId()), game); } @Override @@ -94,25 +98,36 @@ class GiselaBladeOfGoldnightDoubleDamageEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - switch (event.getType()) { - case DAMAGE_PLAYER: - if (event.getTargetId().equals(source.getControllerId())) { - preventDamage(event, source, source.getControllerId(), game); - } else if (game.getOpponents(source.getControllerId()).contains(event.getTargetId())) { - event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); - } - break; - case DAMAGE_CREATURE: - case DAMAGE_PLANESWALKER: - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - if (permanent.isControlledBy(source.getControllerId())) { - preventDamage(event, source, permanent.getId(), game); - } else if (game.getOpponents(source.getControllerId()).contains(permanent.getControllerId())) { - event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); - } - } - } + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); return false; } } + +class GiselaBladeOfGoldnightPreventionEffect extends PreventionEffectImpl { + + GiselaBladeOfGoldnightPreventionEffect() { + super(Duration.WhileOnBattlefield); + this.staticText = "If a source would deal damage to you or a permanent you control, " + + "prevent half that damage, rounded up"; + } + + private GiselaBladeOfGoldnightPreventionEffect(final GiselaBladeOfGoldnightPreventionEffect effect) { + super(effect); + } + + @Override + public GiselaBladeOfGoldnightPreventionEffect copy() { + return new GiselaBladeOfGoldnightPreventionEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return source.isControlledBy(event.getTargetId()) + || source.isControlledBy(game.getControllerId(event.getTargetId())); + } + + @Override + protected PreventionEffectData preventDamageAction(GameEvent event, Ability source, Game game) { + return game.preventDamage(event, source, game, Math.floorDiv(event.getAmount(), 2) + (event.getAmount() % 2)); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlacialCrasher.java b/Mage.Sets/src/mage/cards/g/GlacialCrasher.java index 36a1fab245..ba066a828b 100644 --- a/Mage.Sets/src/mage/cards/g/GlacialCrasher.java +++ b/Mage.Sets/src/mage/cards/g/GlacialCrasher.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -18,14 +16,15 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GlacialCrasher extends CardImpl { public GlacialCrasher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(5); @@ -71,16 +70,14 @@ class GlacialCrasherEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 1) { - return true; - } + return game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 1; } return false; } diff --git a/Mage.Sets/src/mage/cards/g/Glaciers.java b/Mage.Sets/src/mage/cards/g/Glaciers.java new file mode 100644 index 0000000000..6d2ae05de9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Glaciers.java @@ -0,0 +1,133 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; + +/** + * + * @author jmharmon + */ +public final class Glaciers extends CardImpl { + + public Glaciers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{U}"); + + // At the beginning of your upkeep, sacrifice Glaciers unless you pay {W}{U}. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{W}{U}")), TargetController.YOU, false)); + + // All Mountains are Plains. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GlaciersEffect())); + } + + public Glaciers(final Glaciers card) { + super(card); + } + + @Override + public Glaciers copy() { + return new Glaciers(this); + } + + static class GlaciersEffect extends ContinuousEffectImpl { + + GlaciersEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "All Mountains are Plains"; + } + + GlaciersEffect(final GlaciersEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public GlaciersEffect copy() { + return new GlaciersEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(CardType.LAND)) { + switch (layer) { + case TypeChangingEffects_4: + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.getSubtype(game).clear(); + land.getSubtype(game).add(SubType.PLAINS); + game.getState().setValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), "true"); + } + break; + case AbilityAddingRemovingEffects_6: + if (game.getState().getValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("glaciers" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } + } + break; + } + } + return true; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; + } + + @Override + public Set isDependentTo(List allEffectsInLayer) { + return allEffectsInLayer + .stream() + .filter(effect -> effect.getDependencyTypes().contains(DependencyType.BecomePlains)) + .map(Effect::getId) + .collect(Collectors.toSet()); + } + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java b/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java index 632d3e4f30..c46079038b 100644 --- a/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java +++ b/Mage.Sets/src/mage/cards/g/GlaiveOfTheGuildpact.java @@ -1,12 +1,12 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.GateYouControlCount; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostEquippedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.hint.common.GateYouControlHint; import mage.abilities.keyword.EquipAbility; import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.VigilanceAbility; @@ -16,23 +16,14 @@ import mage.constants.AttachmentType; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterPermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class GlaiveOfTheGuildpact extends CardImpl { - private static final FilterPermanent filter - = new FilterControlledPermanent("Gate you control"); - - static { - filter.add(new SubtypePredicate(SubType.GATE)); - } - public GlaiveOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); @@ -42,7 +33,7 @@ public final class GlaiveOfTheGuildpact extends CardImpl { Ability ability = new SimpleStaticAbility( Zone.BATTLEFIELD, new BoostEquippedEffect( - new PermanentsOnBattlefieldCount(filter), + GateYouControlCount.instance, new StaticValue(0) ) ); @@ -52,6 +43,7 @@ public final class GlaiveOfTheGuildpact extends CardImpl { ability.addEffect(new GainAbilityAttachedEffect( new MenaceAbility(), AttachmentType.EQUIPMENT ).setText("and menace")); + ability.addHint(GateYouControlHint.instance); this.addAbility(ability); // Equip {3} diff --git a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java index 0ff769a8b1..7723affb53 100644 --- a/Mage.Sets/src/mage/cards/g/GlamerSpinners.java +++ b/Mage.Sets/src/mage/cards/g/GlamerSpinners.java @@ -117,8 +117,10 @@ class GlamerSpinnersEffect extends OneShotEffect { } // Check for protection MageObject auraObject = game.getObject(auraId); - if (permanentToAttachAuras.cantBeAttachedBy(auraObject, game)) { - passed = false; + if(auraObject != null) { + if (permanentToAttachAuras.cantBeAttachedBy(auraObject, game)) { + passed = false; + } } } } diff --git a/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java b/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java index 372a87e19d..8683602db5 100644 --- a/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java +++ b/Mage.Sets/src/mage/cards/g/GlareOfSubdual.java @@ -28,7 +28,7 @@ public final class GlareOfSubdual extends CardImpl { private static final FilterPermanent filterTarget = new FilterPermanent("artifact or creature"); static { - filterCost.add(Predicates.not(new TappedPredicate())); + filterCost.add(Predicates.not(TappedPredicate.instance)); filterTarget.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE))); diff --git a/Mage.Sets/src/mage/cards/g/GlassOfTheGuildpact.java b/Mage.Sets/src/mage/cards/g/GlassOfTheGuildpact.java new file mode 100644 index 0000000000..a5e095017f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlassOfTheGuildpact.java @@ -0,0 +1,43 @@ +package mage.cards.g; + +import mage.abilities.common.SimpleStaticAbility; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.MulticoloredPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GlassOfTheGuildpact extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("multicolored creatures"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + public GlassOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // Multicolored creatures you control get +1/+1. + this.addAbility(new SimpleStaticAbility( + new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter) + )); + } + + private GlassOfTheGuildpact(final GlassOfTheGuildpact card) { + super(card); + } + + @Override + public GlassOfTheGuildpact copy() { + return new GlassOfTheGuildpact(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlassdustHulk.java b/Mage.Sets/src/mage/cards/g/GlassdustHulk.java index 419a50f73a..69c9f6c2bd 100644 --- a/Mage.Sets/src/mage/cards/g/GlassdustHulk.java +++ b/Mage.Sets/src/mage/cards/g/GlassdustHulk.java @@ -30,7 +30,7 @@ public final class GlassdustHulk extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GlassdustHulk(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlazeFiend.java b/Mage.Sets/src/mage/cards/g/GlazeFiend.java index b4e70d85d3..ca91ea3129 100644 --- a/Mage.Sets/src/mage/cards/g/GlazeFiend.java +++ b/Mage.Sets/src/mage/cards/g/GlazeFiend.java @@ -24,7 +24,7 @@ public final class GlazeFiend extends CardImpl { private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("another artifact"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/g/GleamingOverseer.java b/Mage.Sets/src/mage/cards/g/GleamingOverseer.java new file mode 100644 index 0000000000..dd69239593 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GleamingOverseer.java @@ -0,0 +1,61 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GleamingOverseer extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ZOMBIE, "Zombie tokens"); + + static { + filter.add(TokenPredicate.instance); + } + + public GleamingOverseer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // When Gleaming Overseer enters the battlefield, amass 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(1))); + + // Zombie tokens you control have hexproof and menace. + Ability ability = new SimpleStaticAbility(new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.WhileOnBattlefield, filter + )); + ability.addEffect(new GainAbilityControlledEffect( + new MenaceAbility(), Duration.WhileOnBattlefield, filter + ).setText("and menace")); + this.addAbility(ability); + } + + private GleamingOverseer(final GleamingOverseer card) { + super(card); + } + + @Override + public GleamingOverseer copy() { + return new GleamingOverseer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Gleancrawler.java b/Mage.Sets/src/mage/cards/g/Gleancrawler.java index 9b183e132c..1daa26ff28 100644 --- a/Mage.Sets/src/mage/cards/g/Gleancrawler.java +++ b/Mage.Sets/src/mage/cards/g/Gleancrawler.java @@ -73,7 +73,7 @@ class GleancrawlerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && watcher != null) { Set cardsToGraveyardThisTurn = watcher.getCardsPutToGraveyardFromBattlefield(); diff --git a/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java b/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java index 55bfd2f749..ced28deab9 100644 --- a/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java +++ b/Mage.Sets/src/mage/cards/g/GlimmerdustNap.java @@ -26,7 +26,7 @@ public final class GlimmerdustNap extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public GlimmerdustNap(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlimmerpointStag.java b/Mage.Sets/src/mage/cards/g/GlimmerpointStag.java index d4b7a1630c..939b63db59 100644 --- a/Mage.Sets/src/mage/cards/g/GlimmerpointStag.java +++ b/Mage.Sets/src/mage/cards/g/GlimmerpointStag.java @@ -30,10 +30,10 @@ import mage.target.targetpointer.FixedTarget; */ public final class GlimmerpointStag extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("another target permanent"); + private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GlimmerpointStag(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlimpseTheSunGod.java b/Mage.Sets/src/mage/cards/g/GlimpseTheSunGod.java index 4ab2832a67..f0c457aa4f 100644 --- a/Mage.Sets/src/mage/cards/g/GlimpseTheSunGod.java +++ b/Mage.Sets/src/mage/cards/g/GlimpseTheSunGod.java @@ -1,20 +1,21 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.effects.keyword.ScryEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; /** - * * @author LevelX2 */ public final class GlimpseTheSunGod extends CardImpl { @@ -24,26 +25,27 @@ public final class GlimpseTheSunGod extends CardImpl { // Tap X target creatures. Scry 1. this.getSpellAbility().addEffect(new TapTargetEffect("X target creatures")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, FILTER_PERMANENT_CREATURES, false)); this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().setTargetAdjuster(GlimpseTheSunGodAdjuster.instance); } public GlimpseTheSunGod(final GlimpseTheSunGod card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numberToTap = ability.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().count(FILTER_PERMANENT_CREATURES, ability.getSourceId(), ability.getControllerId(), game), numberToTap); - ability.addTarget(new TargetCreaturePermanent(numberToTap, numberToTap, FILTER_PERMANENT_CREATURES, false)); - } - } - @Override public GlimpseTheSunGod copy() { return new GlimpseTheSunGod(this); } } + +enum GlimpseTheSunGodAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numberToTap = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetCreaturePermanent(numberToTap, numberToTap, FILTER_PERMANENT_CREATURES, false)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GlintHawkIdol.java b/Mage.Sets/src/mage/cards/g/GlintHawkIdol.java index 5352599b85..ceb983bfbf 100644 --- a/Mage.Sets/src/mage/cards/g/GlintHawkIdol.java +++ b/Mage.Sets/src/mage/cards/g/GlintHawkIdol.java @@ -28,7 +28,7 @@ public final class GlintHawkIdol extends CardImpl { private static final FilterPermanent filter = new FilterArtifactPermanent("another artifact"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GlintHawkIdol (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java b/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java index 09d2a2af10..27d9623720 100644 --- a/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java +++ b/Mage.Sets/src/mage/cards/g/GlintSleeveSiphoner.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; @@ -19,8 +17,9 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GlintSleeveSiphoner extends CardImpl { @@ -42,8 +41,7 @@ public final class GlintSleeveSiphoner extends CardImpl { // At the beginning of your upkeep, you may pay {E}{E}. If you do, draw a card and you lose 1 life. DoIfCostPaid doIfCostPaidEffect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new PayEnergyCost(2)); Effect effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - doIfCostPaidEffect.addEffect(effect); + doIfCostPaidEffect.addEffect(effect.concatBy("and")); this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, doIfCostPaidEffect, TargetController.YOU, false, false, "At the beginning of your upkeep, ")); } diff --git a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java index 35a5e60540..04337ad939 100644 --- a/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java +++ b/Mage.Sets/src/mage/cards/g/GlissaTheTraitor.java @@ -64,7 +64,7 @@ class GlissaTheTraitorTriggeredAbility extends TriggeredAbilityImpl { } GlissaTheTraitorTriggeredAbility() { - super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect()); + super(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), true); this.addTarget(new TargetCardInYourGraveyard(filter)); } @@ -95,6 +95,6 @@ class GlissaTheTraitorTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever a creature an opponent controls is put into a graveyard from the battlefield, you may " + super.getRule(); + return "Whenever a creature an opponent controls is put into a graveyard from the battlefield, " + super.getRule(); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/g/GlitteringWish.java b/Mage.Sets/src/mage/cards/g/GlitteringWish.java index 9b063c47ff..355eb718f9 100644 --- a/Mage.Sets/src/mage/cards/g/GlitteringWish.java +++ b/Mage.Sets/src/mage/cards/g/GlitteringWish.java @@ -19,7 +19,7 @@ public final class GlitteringWish extends CardImpl { private static final FilterCard filter = new FilterCard("a multicolored card"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public GlitteringWish(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlobalRuin.java b/Mage.Sets/src/mage/cards/g/GlobalRuin.java index 75906072ee..0f191c5218 100644 --- a/Mage.Sets/src/mage/cards/g/GlobalRuin.java +++ b/Mage.Sets/src/mage/cards/g/GlobalRuin.java @@ -67,13 +67,15 @@ class GlobalRuinDestroyLandEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); - for (SubType landName : Arrays.stream(SubType.values()).filter(p -> p.getSubTypeSet() == SubTypeSet.BasicLandType).collect(Collectors.toSet())) { - FilterControlledLandPermanent filter = new FilterControlledLandPermanent(landName + " you control"); - filter.add(new SubtypePredicate(landName)); - Target target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(player.getId(), game)) { - player.chooseTarget(outcome, target, source, game); - lands.add(target.getFirstTarget()); + if(player != null) { + for (SubType landName : Arrays.stream(SubType.values()).filter(p -> p.getSubTypeSet() == SubTypeSet.BasicLandType).collect(Collectors.toSet())) { + FilterControlledLandPermanent filter = new FilterControlledLandPermanent(landName + " you control"); + filter.add(new SubtypePredicate(landName)); + Target target = new TargetControlledPermanent(1, 1, filter, true); + if (target.canChoose(player.getId(), game)) { + player.chooseTarget(outcome, target, source, game); + lands.add(target.getFirstTarget()); + } } } } diff --git a/Mage.Sets/src/mage/cards/g/Gloomlance.java b/Mage.Sets/src/mage/cards/g/Gloomlance.java index f0a7097575..f7a42d9e08 100644 --- a/Mage.Sets/src/mage/cards/g/Gloomlance.java +++ b/Mage.Sets/src/mage/cards/g/Gloomlance.java @@ -63,8 +63,10 @@ class GloomlanceEffect extends OneShotEffect { Permanent destroyedCreature = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); if (destroyedCreature.getColor(game).isGreen() || destroyedCreature.getColor(game).isWhite()) { - targetController.discard(1, false, source, game); - return true; + if(targetController != null) { + targetController.discard(1, false, source, game); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/g/GlyphKeeper.java b/Mage.Sets/src/mage/cards/g/GlyphKeeper.java index 697acf4696..69d358409e 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphKeeper.java +++ b/Mage.Sets/src/mage/cards/g/GlyphKeeper.java @@ -79,7 +79,7 @@ class GlyphKeeperAbility extends TriggeredAbilityImpl { if (event.getTargetId().equals(this.getSourceId())) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isCreature()) { - NumberOfTimesPermanentTargetedATurnWatcher watcher = (NumberOfTimesPermanentTargetedATurnWatcher) game.getState().getWatchers().get(NumberOfTimesPermanentTargetedATurnWatcher.class.getSimpleName()); + NumberOfTimesPermanentTargetedATurnWatcher watcher = game.getState().getWatcher(NumberOfTimesPermanentTargetedATurnWatcher.class); if (watcher != null && watcher.notMoreThanOnceTargetedThisTurn(permanent, game)) { for (Effect effect : getEffects()) { diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java new file mode 100644 index 0000000000..f035da7779 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDelusion.java @@ -0,0 +1,154 @@ + +package mage.cards.g; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.common.BlockedAttackerWatcher; + +/** + * + * @author L_J + */ +public final class GlyphOfDelusion extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature"); + + static { + filter.add(new SubtypePredicate(SubType.WALL)); + } + + public GlyphOfDelusion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); + + // Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains “This creature doesn’t untap during your untap step if it has a glyph counter on it” and “At the beginning of your upkeep, remove a glyph counter from this creature.” + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new GlyphOfDelusionSecondTarget()); + this.getSpellAbility().addEffect(new GlyphOfDelusionEffect()); + this.getSpellAbility().addWatcher(new BlockedAttackerWatcher()); + } + + public GlyphOfDelusion(final GlyphOfDelusion card) { + super(card); + } + + @Override + public GlyphOfDelusion copy() { + return new GlyphOfDelusion(this); + } +} + +class GlyphOfDelusionSecondTarget extends TargetPermanent { + + private Permanent firstTarget = null; + + public GlyphOfDelusionSecondTarget() { + super(); + setTargetName("target creature that target Wall blocked this turn"); + } + + public GlyphOfDelusionSecondTarget(final GlyphOfDelusionSecondTarget target) { + super(target); + this.firstTarget = target.firstTarget; + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + if (firstTarget != null) { + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); + if (watcher != null) { + MageObject targetSource = game.getObject(sourceId); + if (targetSource != null) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(creature.getId()) && creature.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(firstTarget, game), game)) { + possibleTargets.add(creature.getId()); + } + } + } + } + } + } + return possibleTargets; + } + + @Override + public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { + firstTarget = game.getPermanent(source.getFirstTarget()); + return super.chooseTarget(Outcome.Tap, playerId, source, game); + } + + @Override + public GlyphOfDelusionSecondTarget copy() { + return new GlyphOfDelusionSecondTarget(this); + } +} + +class GlyphOfDelusionEffect extends OneShotEffect { + + public GlyphOfDelusionEffect() { + super(Outcome.Detriment); + this.staticText = "Put X glyph counters on target creature that target Wall blocked this turn, where X is the power of that blocked creature. The creature gains \"This creature doesn’t untap during your untap step if it has a glyph counter on it\" and \"At the beginning of your upkeep, remove a glyph counter from this creature.\""; + } + + public GlyphOfDelusionEffect(final GlyphOfDelusionEffect effect) { + super(effect); + } + + @Override + public GlyphOfDelusionEffect copy() { + return new GlyphOfDelusionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (source.getTargets().get(1) != null) { + Permanent targetPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.addCounters(CounterType.GLYPH.createInstance(targetPermanent.getPower().getValue()), source, game); + + SimpleStaticAbility ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepSourceEffect(), + new SourceHasCounterCondition(CounterType.GLYPH)).setText("This creature doesn’t untap during your untap step if it has a glyph counter on it")); + GainAbilityTargetEffect effect = new GainAbilityTargetEffect(ability, Duration.Custom); + effect.setTargetPointer(new FixedTarget(targetPermanent.getId())); + game.addEffect(effect, source); + + BeginningOfUpkeepTriggeredAbility ability2 = new BeginningOfUpkeepTriggeredAbility(new RemoveCounterSourceEffect(CounterType.GLYPH.createInstance()), + TargetController.YOU, false); + GainAbilityTargetEffect effect2 = new GainAbilityTargetEffect(ability2, Duration.Custom); + effect2.setTargetPointer(new FixedTarget(targetPermanent.getId())); + game.addEffect(effect2, source); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java b/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java index 29a587f8cd..016c25f35a 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDestruction.java @@ -25,7 +25,7 @@ public final class GlyphOfDestruction extends CardImpl { static { filter.add(new SubtypePredicate(SubType.WALL)); - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } public GlyphOfDestruction(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java index ea23f5b02b..5862096bd5 100644 --- a/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java +++ b/Mage.Sets/src/mage/cards/g/GlyphOfDoom.java @@ -106,7 +106,7 @@ class GlyphOfDoomEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && targetCreature != null) { - BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java new file mode 100644 index 0000000000..b422b7d662 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GlyphOfReincarnation.java @@ -0,0 +1,129 @@ + +package mage.cards.g; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.condition.common.AfterCombatCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCreaturePermanent; +import mage.watchers.common.BlockedAttackerWatcher; + +/** + * + * @author L_J + */ +public final class GlyphOfReincarnation extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Wall creature"); + + static { + filter.add(new SubtypePredicate(SubType.WALL)); + } + + public GlyphOfReincarnation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Cast this spell only after combat. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, AfterCombatCondition.instance, "Cast this spell only after combat")); + + // Destroy all creatures that were blocked by target Wall this turn. They can’t be regenerated. For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall onto the battlefield under its owner’s control. + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addEffect(new GlyphOfReincarnationEffect()); + this.getSpellAbility().addWatcher(new BlockedAttackerWatcher()); + } + + public GlyphOfReincarnation(final GlyphOfReincarnation card) { + super(card); + } + + @Override + public GlyphOfReincarnation copy() { + return new GlyphOfReincarnation(this); + } +} + +class GlyphOfReincarnationEffect extends OneShotEffect { + + public GlyphOfReincarnationEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Destroy all creatures that were blocked by target Wall this turn. They can’t be regenerated. For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall onto the battlefield under its owner’s control"; + } + + public GlyphOfReincarnationEffect(final GlyphOfReincarnationEffect effect) { + super(effect); + } + + @Override + public GlyphOfReincarnationEffect copy() { + return new GlyphOfReincarnationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent targetWall = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); + if (controller != null && targetWall != null) { + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); + if (watcher != null) { + Map destroyed = new HashMap<>(); + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + if (!creature.getId().equals(targetWall.getId())) { + if (watcher.creatureHasBlockedAttacker(new MageObjectReference(creature, game), new MageObjectReference(targetWall, game), game)) { + if (creature.destroy(source.getSourceId(), game, true) + && game.getState().getZone(creature.getId()) == Zone.GRAVEYARD) { // If a commander is replaced to command zone, the creature does not die + Player permController = game.getPlayer(creature.getControllerId()); + if (permController != null) { + destroyed.put(creature.getId(), permController); + } + } + } + } + } + // For each creature that died this way, put a creature card from the graveyard of the player who controlled that creature the last time it became blocked by that Wall + // onto the battlefield under its owner’s control + for (Map.Entry entry : destroyed.entrySet()) { + Permanent permanent = (Permanent) game.getLastKnownInformation(entry.getKey(), Zone.BATTLEFIELD); + Player player = entry.getValue(); + if (permanent != null && player != null) { + FilterCreatureCard filter = new FilterCreatureCard("a creature card from " + player.getName() + "'s graveyard"); + filter.add(new OwnerIdPredicate(player.getId())); + Target targetCreature = new TargetCardInGraveyard(filter); + targetCreature.setNotTarget(true); + if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseTarget(outcome, targetCreature, source, game)) { + Card card = game.getCard(targetCreature.getFirstTarget()); + if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); + } + } + } + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GnarlidPack.java b/Mage.Sets/src/mage/cards/g/GnarlidPack.java index 24ce6b741a..63e7c60edb 100644 --- a/Mage.Sets/src/mage/cards/g/GnarlidPack.java +++ b/Mage.Sets/src/mage/cards/g/GnarlidPack.java @@ -31,7 +31,7 @@ public final class GnarlidPack extends CardImpl { // Gnarlid Pack enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true), "with a +1/+1 counter on it for each time it was kicked")); } diff --git a/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java b/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java index 896252385a..be62dc9f0f 100644 --- a/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java +++ b/Mage.Sets/src/mage/cards/g/GnarlrootTrapper.java @@ -35,10 +35,10 @@ import java.util.UUID; */ public final class GnarlrootTrapper extends CardImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking ELf you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking ELf you control"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(new SubtypePredicate(SubType.ELF)); } @@ -92,7 +92,7 @@ class GnarlrootTrapperManaCondition extends CreatureCastManaCondition { public boolean apply(Game game, Ability source) { if (super.apply(game, source)) { MageObject object = game.getObject(source.getSourceId()); - if (object.hasSubtype(SubType.ELF, game) + if (object != null && object.hasSubtype(SubType.ELF, game) && object.isCreature()) { return true; } diff --git a/Mage.Sets/src/mage/cards/g/GnarlwoodDryad.java b/Mage.Sets/src/mage/cards/g/GnarlwoodDryad.java index 27d2a2bc20..599aae3564 100644 --- a/Mage.Sets/src/mage/cards/g/GnarlwoodDryad.java +++ b/Mage.Sets/src/mage/cards/g/GnarlwoodDryad.java @@ -1,13 +1,14 @@ - package mage.cards.g; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,13 +18,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class GnarlwoodDryad extends CardImpl { public GnarlwoodDryad(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.DRYAD); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); @@ -37,6 +37,7 @@ public final class GnarlwoodDryad extends CardImpl { new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} gets +2/+2 as long as there are four or more card types among cards in your graveyard."); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinArchaeologist.java b/Mage.Sets/src/mage/cards/g/GoblinArchaeologist.java index 78a1c2c194..5b04f0b8fe 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinArchaeologist.java +++ b/Mage.Sets/src/mage/cards/g/GoblinArchaeologist.java @@ -75,7 +75,7 @@ class GoblinArchaeologistEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { permanent.sacrifice(source.getSourceId(), game); }else{ Permanent targetArtifact = game.getPermanent(source.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java index 97b830bea1..876e1ee6dc 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinArtisans.java +++ b/Mage.Sets/src/mage/cards/g/GoblinArtisans.java @@ -78,7 +78,7 @@ class GoblinArtisansEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { controller.drawCards(1, game); } else { List artifacts = game.getBattlefield().getActivePermanents(new FilterControlledArtifactPermanent(), source.getControllerId(), game); diff --git a/Mage.Sets/src/mage/cards/g/GoblinAssailant.java b/Mage.Sets/src/mage/cards/g/GoblinAssailant.java new file mode 100644 index 0000000000..13f7189bb0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinAssailant.java @@ -0,0 +1,33 @@ +package mage.cards.g; + +import mage.MageInt; +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 GoblinAssailant extends CardImpl { + + public GoblinAssailant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + private GoblinAssailant(final GoblinAssailant card) { + super(card); + } + + @Override + public GoblinAssailant copy() { + return new GoblinAssailant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinAssassin.java b/Mage.Sets/src/mage/cards/g/GoblinAssassin.java index d872d6b038..c94cb90e39 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinAssassin.java +++ b/Mage.Sets/src/mage/cards/g/GoblinAssassin.java @@ -99,7 +99,7 @@ class GoblinAssassinTriggeredEffect extends OneShotEffect { if (controller != null) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null && !player.flipCoin(game)) { + if (player != null && !player.flipCoin(source, game, false)) { TargetControlledCreaturePermanent target = new TargetControlledCreaturePermanent(); target.setNotTarget(true); if (target.canChoose(player.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinAssaultTeam.java b/Mage.Sets/src/mage/cards/g/GoblinAssaultTeam.java new file mode 100644 index 0000000000..6efdad649a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinAssaultTeam.java @@ -0,0 +1,47 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.HasteAbility; +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 GoblinAssaultTeam extends CardImpl { + + public GoblinAssaultTeam(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // When Goblin Assault Team dies, put a +1/+1 counter on target creature you control. + Ability ability = new DiesTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private GoblinAssaultTeam(final GoblinAssaultTeam card) { + super(card); + } + + @Override + public GoblinAssaultTeam copy() { + return new GoblinAssaultTeam(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinBangchuckers.java b/Mage.Sets/src/mage/cards/g/GoblinBangchuckers.java index 2f7b0c8669..ff27db96da 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBangchuckers.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBangchuckers.java @@ -63,7 +63,7 @@ class GoblinBangchuckersEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { Permanent permanent = game.getPermanent(targetPointer.getFirst(game, source)); if (permanent != null) { permanent.damage(2, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/g/GoblinBarrage.java b/Mage.Sets/src/mage/cards/g/GoblinBarrage.java index cfc82c9248..57f2fef6e7 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBarrage.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBarrage.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.common.SacrificeTargetCost; @@ -19,19 +18,28 @@ import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class GoblinBarrage extends CardImpl { + private static final FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Goblin"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new SubtypePredicate(SubType.GOBLIN) + )); + } + public GoblinBarrage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Kicker—Sacrifice an artifact or Goblin. - FilterControlledPermanent filter = new FilterControlledPermanent("an artifact or Goblin"); - filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new SubtypePredicate(SubType.GOBLIN))); this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(filter)))); // Goblin Barrage deals 4 damage to target creature. If this spell was kicked, it also deals 4 damage to target player or planeswalker. @@ -40,13 +48,7 @@ public final class GoblinBarrage extends CardImpl { + "it also deals 4 damage to target player or planeswalker") ); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetPlayerOrPlaneswalker()); - } + this.getSpellAbility().setTargetAdjuster(GoblinBarrageAdjuster.instance); } public GoblinBarrage(final GoblinBarrage card) { @@ -58,3 +60,14 @@ public final class GoblinBarrage extends CardImpl { return new GoblinBarrage(this); } } + +enum GoblinBarrageAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetPlayerOrPlaneswalker()); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GoblinBomb.java b/Mage.Sets/src/mage/cards/g/GoblinBomb.java index fdab4e863c..a8ced2d782 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBomb.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBomb.java @@ -72,7 +72,7 @@ class GoblinBombEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.informPlayers("Goblin Bomb: Won flip. Put a fuse counter on Goblin Bomb."); new AddCountersSourceEffect(CounterType.FUSE.createInstance(1)).apply(game, source); return true; diff --git a/Mage.Sets/src/mage/cards/g/GoblinBoomKeg.java b/Mage.Sets/src/mage/cards/g/GoblinBoomKeg.java index 14007b84d9..25eece23e9 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinBoomKeg.java +++ b/Mage.Sets/src/mage/cards/g/GoblinBoomKeg.java @@ -1,11 +1,8 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.SacrificeSourceEffect; import mage.cards.CardImpl; @@ -14,20 +11,21 @@ import mage.constants.CardType; import mage.constants.TargetController; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GoblinBoomKeg extends CardImpl { public GoblinBoomKeg(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // At the beginning of your upkeep, sacrifice Goblin Boom Keg. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect(), TargetController.YOU, false)); // When Goblin Boom Keg is put into a graveyard from the battlefield, it deals 3 damage to any target. - Ability ability = new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DamageTargetEffect(3, "it"), false); + Ability ability = new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DamageTargetEffect(3, "it")); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinBruiser.java b/Mage.Sets/src/mage/cards/g/GoblinBruiser.java new file mode 100644 index 0000000000..ab4b7acfe0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinBruiser.java @@ -0,0 +1,33 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class GoblinBruiser extends CardImpl { + + public GoblinBruiser(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{R}"); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.WARRIOR); + + this.power = new MageInt(3); + this.toughness = new MageInt(3); + } + + public GoblinBruiser(final GoblinBruiser card) { + super(card); + } + + @Override + public GoblinBruiser copy() { + return new GoblinBruiser(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinChainwhirler.java b/Mage.Sets/src/mage/cards/g/GoblinChainwhirler.java index b199353a7e..9444c59451 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinChainwhirler.java +++ b/Mage.Sets/src/mage/cards/g/GoblinChainwhirler.java @@ -24,7 +24,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class GoblinChainwhirler extends CardImpl { - final static FilterPermanent filter = new FilterPermanent("creatures and planeswalkers your opponents control"); + static final FilterPermanent filter = new FilterPermanent("creatures and planeswalkers your opponents control"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/g/GoblinCohort.java b/Mage.Sets/src/mage/cards/g/GoblinCohort.java index 592c7e6759..7410b939c3 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinCohort.java +++ b/Mage.Sets/src/mage/cards/g/GoblinCohort.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,21 +7,22 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.PlayerCastCreatureWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GoblinCohort extends CardImpl { public GoblinCohort(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.WARRIOR); @@ -62,17 +61,15 @@ class GoblinCohortEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - PlayerCastCreatureWatcher watcher = (PlayerCastCreatureWatcher) game.getState().getWatchers().get(PlayerCastCreatureWatcher.class.getSimpleName()); - if (watcher != null && !watcher.playerDidCastCreatureThisTurn(source.getControllerId())) { - return true; - } + PlayerCastCreatureWatcher watcher = game.getState().getWatcher(PlayerCastCreatureWatcher.class); + return watcher != null && !watcher.playerDidCastCreatureThisTurn(source.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java b/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java index bfd07f08b7..9b54aac730 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java +++ b/Mage.Sets/src/mage/cards/g/GoblinCratermaker.java @@ -29,7 +29,7 @@ public final class GoblinCratermaker extends CardImpl { = new FilterNonlandPermanent("colorless nonland permanent"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public GoblinCratermaker(UUID ownerId, CardSetInfo setInfo) { @@ -50,8 +50,8 @@ public final class GoblinCratermaker extends CardImpl { // • Destroy target colorless nonland permanent. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GoblinDynamo.java b/Mage.Sets/src/mage/cards/g/GoblinDynamo.java index 557ca2341d..207bfd0dfb 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinDynamo.java +++ b/Mage.Sets/src/mage/cards/g/GoblinDynamo.java @@ -35,7 +35,7 @@ public final class GoblinDynamo extends CardImpl { this.addAbility(ability); //{X}{R}, {T}, Sacrifice Goblin Dynamo: Goblin Dynamo deals X damage to any target. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD,new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{R}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/g/GoblinFestival.java b/Mage.Sets/src/mage/cards/g/GoblinFestival.java index 9c4b52b88f..e8e202928f 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFestival.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFestival.java @@ -68,7 +68,7 @@ class GoblinFestivalChangeControlEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (controller != null) { - if (!controller.flipCoin(game)) { + if (!controller.flipCoin(source, game, true)) { if (sourcePermanent != null) { Target target = new TargetOpponent(true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinFlotilla.java b/Mage.Sets/src/mage/cards/g/GoblinFlotilla.java index caaa53ed51..2abda79241 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinFlotilla.java +++ b/Mage.Sets/src/mage/cards/g/GoblinFlotilla.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.UUID; @@ -6,6 +5,7 @@ import mage.MageInt; import mage.abilities.common.BeginningOfCombatTriggeredAbility; import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DoUnlessControllerPaysEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -27,22 +27,32 @@ public final class GoblinFlotilla extends CardImpl { public GoblinFlotilla(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); - + this.power = new MageInt(2); this.toughness = new MageInt(2); // Islandwalk this.addAbility(new IslandwalkAbility()); + // At the beginning of each combat, unless you pay {R}, whenever Goblin Flotilla blocks or becomes blocked by a creature this combat, that creature gains first strike until end of turn. + Effect effect = new DoUnlessControllerPaysEffect( + new GainAbilitySourceEffect( + new BlocksOrBecomesBlockedTriggeredAbility( + new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), + Duration.EndOfTurn, + "Blocks or Blocked by Goblin Flotilla"), + false), + Duration.EndOfCombat), + new ManaCostsImpl("{R}"), + "Pay Goblin Flotilla combat effect?" + ); + effect.setText("unless you pay {R}, whenever {this} blocks or becomes blocked by a creature this combat, that creature gains first strike until end of turn."); this.addAbility(new BeginningOfCombatTriggeredAbility( - new DoUnlessControllerPaysEffect( - new GainAbilitySourceEffect(new BlocksOrBecomesBlockedTriggeredAbility(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, "Blocks or Blocked by Goblin Flotilla"), false), Duration.EndOfCombat), - new ManaCostsImpl("{R}"), - "Pay Goblin Flotilla combat effect?" - ), + effect, TargetController.ANY, false )); + } public GoblinFlotilla(final GoblinFlotilla card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinGangLeader.java b/Mage.Sets/src/mage/cards/g/GoblinGangLeader.java new file mode 100644 index 0000000000..db0e80fc8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinGangLeader.java @@ -0,0 +1,39 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.GoblinToken; + +import java.util.UUID; + +/** + * + * @author JayDi85 + */ +public final class GoblinGangLeader extends CardImpl { + + public GoblinGangLeader(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + this.subtype.add(SubType.GOBLIN, SubType.WARRIOR); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Goblin Gang Leader enters the battlefield, create two 1/1 red Goblin creature tokens. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new GoblinToken("ANA"), 2))); + } + + public GoblinGangLeader(final GoblinGangLeader card) { + super(card); + } + + @Override + public GoblinGangLeader copy() { + return new GoblinGangLeader(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinGathering.java b/Mage.Sets/src/mage/cards/g/GoblinGathering.java new file mode 100644 index 0000000000..7f93f57fbc --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinGathering.java @@ -0,0 +1,80 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.ValueHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.game.Game; +import mage.game.permanent.token.GoblinToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GoblinGathering extends CardImpl { + + public GoblinGathering(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Create a number of 1/1 red Goblin creature tokens equal to two plus the number of cards named Goblin Gathering in your graveyard. + this.getSpellAbility().addEffect(new CreateTokenEffect( + new GoblinToken(), GoblinGatheringDynamicValue.instance + )); + this.getSpellAbility().addHint(new ValueHint("You can create tokens", GoblinGatheringDynamicValue.instance)); + } + + private GoblinGathering(final GoblinGathering card) { + super(card); + } + + @Override + public GoblinGathering copy() { + return new GoblinGathering(this); + } +} + +enum GoblinGatheringDynamicValue implements DynamicValue { + + instance; + private static final FilterCard filter = new FilterCard(); + + static { + filter.add(new NamePredicate("Goblin Gathering")); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = 0; + Player player = game.getPlayer(sourceAbility.getControllerId()); + if (player != null) { + amount += player.getGraveyard().count( + filter, sourceAbility.getSourceId(), + sourceAbility.getControllerId(), game + ); + } + return amount + 2; + } + + @Override + public GoblinGatheringDynamicValue copy() { + return instance; + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "two plus the number of cards named Goblin Gathering in your graveyard"; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinGoliath.java b/Mage.Sets/src/mage/cards/g/GoblinGoliath.java new file mode 100644 index 0000000000..a6a7c02f60 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GoblinGoliath.java @@ -0,0 +1,105 @@ +package mage.cards.g; + +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.dynamicvalue.common.OpponentsCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.GoblinToken; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class GoblinGoliath extends CardImpl { + + public GoblinGoliath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}{R}"); + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.MUTANT); + + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // When Goblin Goliath enters the battlefield, create a number of 1/1 red Goblin creature tokens equal to the number of opponents you have. + Effect effect = new CreateTokenEffect(new GoblinToken(), OpponentsCount.instance); + effect.setText("create a number of 1/1 red Goblin creature tokens equal to the number of opponents you have"); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect)); + + // {3}{R}, {T}: If a source you control would deal damage to an opponent this turn, it deals double that damage to that player instead. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GoblinGoliathDamageEffect(), new ManaCostsImpl("{3}{R}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + public GoblinGoliath(final GoblinGoliath card) { + super(card); + } + + @Override + public GoblinGoliath copy() { + return new GoblinGoliath(this); + } +} + +class GoblinGoliathDamageEffect extends ReplacementEffectImpl { + + public GoblinGoliathDamageEffect() { + super(Duration.EndOfTurn, Outcome.Damage); + staticText = "If a source you control would deal damage to an opponent this turn, it deals double that damage to that player instead."; + } + + public GoblinGoliathDamageEffect(final GoblinGoliathDamageEffect effect) { + super(effect); + } + + @Override + public GoblinGoliathDamageEffect copy() { + return new GoblinGoliathDamageEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + UUID sourceControllerID = source.getControllerId(); + UUID damageControllerID = game.getControllerId(event.getSourceId()); + UUID damageTargetID = event.getTargetId(); + if (sourceControllerID != null && damageControllerID != null && damageTargetID != null) { + // our damage + if (damageControllerID.equals(sourceControllerID)) { + // to opponent only + if (game.getOpponents(sourceControllerID).contains(damageTargetID)) { + return true; + } + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), event.getAmount())); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GoblinGoon.java b/Mage.Sets/src/mage/cards/g/GoblinGoon.java index eff8408b09..c9f778653b 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinGoon.java +++ b/Mage.Sets/src/mage/cards/g/GoblinGoon.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,22 +7,23 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author emerald000 */ public final class GoblinGoon extends CardImpl { public GoblinGoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.MUTANT); this.power = new MageInt(6); @@ -32,7 +31,7 @@ public final class GoblinGoon extends CardImpl { // Goblin Goon can't attack unless you control more creatures than defending player. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GoblinGoonCantAttackEffect())); - + // Goblin Goon can't block unless you control more creatures than attacking player. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GoblinGoonCantBlockEffect())); } @@ -64,25 +63,26 @@ class GoblinGoonCantAttackEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + UUID defendingPlayerId; Player defender = game.getPlayer(defenderId); if (defender == null) { Permanent permanent = game.getPermanent(defenderId); if (permanent != null) { defendingPlayerId = permanent.getControllerId(); - } - else { + } else { return false; } - } - else { + } else { defendingPlayerId = defenderId; } if (defendingPlayerId != null) { return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), defendingPlayerId, game); - } - else { + } else { return true; } } @@ -110,7 +110,10 @@ class GoblinGoonCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } UUID attackingPlayerId = attacker.getControllerId(); if (attackingPlayerId != null) { return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), attackingPlayerId, game); diff --git a/Mage.Sets/src/mage/cards/g/GoblinGuide.java b/Mage.Sets/src/mage/cards/g/GoblinGuide.java index 78376fc3e6..836177e58d 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinGuide.java +++ b/Mage.Sets/src/mage/cards/g/GoblinGuide.java @@ -126,10 +126,9 @@ class GoblinGuideEffect extends OneShotEffect { Player defender = game.getPlayer(getTargetPointer().getFirst(game, source)); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && defender != null) { - Cards cards = new CardsImpl(); Card card = defender.getLibrary().getFromTop(game); if (card != null) { - cards.add(card); + Cards cards = new CardsImpl(card); defender.revealCards(sourceObject.getName(), cards, game); if (card.isLand()) { defender.moveCards(card, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/g/GoblinKaboomist.java b/Mage.Sets/src/mage/cards/g/GoblinKaboomist.java index 59f04faf76..2df939fa0d 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinKaboomist.java +++ b/Mage.Sets/src/mage/cards/g/GoblinKaboomist.java @@ -70,8 +70,8 @@ class GoblinKaboomistFlipCoinEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (player != null && permanent != null) { - if (!player.flipCoin(game)) { - String message = new StringBuilder(permanent.getLogName()).append(" deals 2 damage to itself").toString(); + if (!player.flipCoin(source, game, true)) { + String message = permanent.getLogName() + " deals 2 damage to itself"; game.informPlayers(message); permanent.damage(2, source.getSourceId(), game, false, true); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinKites.java b/Mage.Sets/src/mage/cards/g/GoblinKites.java index 1f3216e8e3..cc2e03fef0 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinKites.java +++ b/Mage.Sets/src/mage/cards/g/GoblinKites.java @@ -69,7 +69,7 @@ class GoblinKitesEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { return true; } else { new SacrificeSourceEffect().apply(game, source); diff --git a/Mage.Sets/src/mage/cards/g/GoblinLyre.java b/Mage.Sets/src/mage/cards/g/GoblinLyre.java index e06192a2a5..822f0633d1 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinLyre.java +++ b/Mage.Sets/src/mage/cards/g/GoblinLyre.java @@ -1,25 +1,23 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponentOrPlaneswalker; +import java.util.UUID; + /** - * * @author L_J */ public final class GoblinLyre extends CardImpl { @@ -65,8 +63,8 @@ class GoblinLyreEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayerOrPlaneswalkerController(getTargetPointer().getFirst(game, source)); if (controller != null) { - if (controller.flipCoin(game)) { - int damage = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()).calculate(game, source, this); + if (controller.flipCoin(source, game, true)) { + int damage = CreaturesYouControlCount.instance.calculate(game, source, this); if (opponent != null) { return game.damagePlayerOrPlaneswalker(source.getFirstTarget(), damage, source.getSourceId(), game, false, true) > 0; } diff --git a/Mage.Sets/src/mage/cards/g/GoblinMachinist.java b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java index 2e217d109b..8ff675b00e 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinMachinist.java +++ b/Mage.Sets/src/mage/cards/g/GoblinMachinist.java @@ -77,9 +77,9 @@ class GoblinMachinistEffect extends OneShotEffect { break; } } - controller.revealCards(source, cards, game); - controller.putCardsOnBottomOfLibrary(cards, game, source, true); } + controller.revealCards(source, cards, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/g/GoblinMutant.java b/Mage.Sets/src/mage/cards/g/GoblinMutant.java index 9bc7a1e266..aaa3865547 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinMutant.java +++ b/Mage.Sets/src/mage/cards/g/GoblinMutant.java @@ -30,7 +30,7 @@ public final class GoblinMutant extends CardImpl { static final private FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures with power 3 or greater"); static { - filter.add(Predicates.and(new PowerPredicate(ComparisonType.MORE_THAN, 2), Predicates.not(new TappedPredicate()))); + filter.add(Predicates.and(new PowerPredicate(ComparisonType.MORE_THAN, 2), Predicates.not(TappedPredicate.instance))); filter2.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinOffensive.java b/Mage.Sets/src/mage/cards/g/GoblinOffensive.java index 58cb3f35e5..326309a34a 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinOffensive.java +++ b/Mage.Sets/src/mage/cards/g/GoblinOffensive.java @@ -19,7 +19,7 @@ public final class GoblinOffensive extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{1}{R}{R}"); // create X 1/1 red Goblin creature tokens. - this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new GoblinToken(), ManacostVariableValue.instance)); } public GoblinOffensive(final GoblinOffensive card) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinPiledriver.java b/Mage.Sets/src/mage/cards/g/GoblinPiledriver.java index bdf0718476..1c355d9091 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinPiledriver.java +++ b/Mage.Sets/src/mage/cards/g/GoblinPiledriver.java @@ -28,7 +28,7 @@ public final class GoblinPiledriver extends CardImpl { static { filter.add(new SubtypePredicate(SubType.GOBLIN)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GoblinPiledriver(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java index 611aab051c..e249912519 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java +++ b/Mage.Sets/src/mage/cards/g/GoblinPsychopath.java @@ -60,7 +60,7 @@ class GoblinPsychopathEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); + this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java b/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java index 8c844215c6..813b051f72 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRabblemaster.java @@ -32,11 +32,11 @@ public final class GoblinRabblemaster extends CardImpl { private static final FilterCreaturePermanent attackingFilter = new FilterCreaturePermanent(SubType.GOBLIN, "other attacking Goblin"); static { - otherGoblinFilter.add(new AnotherPredicate()); + otherGoblinFilter.add(AnotherPredicate.instance); otherGoblinFilter.add(new ControllerPredicate(TargetController.YOU)); - attackingFilter.add(new AttackingPredicate()); - attackingFilter.add(new AnotherPredicate()); + attackingFilter.add(AttackingPredicate.instance); + attackingFilter.add(AnotherPredicate.instance); } public GoblinRabblemaster(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java b/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java index a4c3c44b11..c70dbf9aac 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRacketeer.java @@ -1,8 +1,6 @@ package mage.cards.g; -import java.util.UUID; - import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -12,16 +10,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author TheElk801 */ public final class GoblinRacketeer extends CardImpl { - private final UUID originalId; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } public GoblinRacketeer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); @@ -33,27 +36,12 @@ public final class GoblinRacketeer extends CardImpl { // Whenever Goblin Racketeer attacks, you may goad target creature defending player controls. Ability ability = new AttacksTriggeredAbility(new GoadTargetEffect(), true, "Whenever {this} attacks, you may goad target creature defending player controls"); - ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); - originalId = ability.getOriginalId(); + ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); } public GoblinRacketeer(final GoblinRacketeer card) { super(card); - this.originalId = card.originalId; - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); - filter.add(new ControllerIdPredicate(defenderId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(filter); - ability.addTarget(target); - } } @Override diff --git a/Mage.Sets/src/mage/cards/g/GoblinRockSled.java b/Mage.Sets/src/mage/cards/g/GoblinRockSled.java index fa2d9fd378..6c3defd224 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinRockSled.java +++ b/Mage.Sets/src/mage/cards/g/GoblinRockSled.java @@ -96,7 +96,7 @@ class DontUntapIfAttackedLastTurnSourceEffect extends ContinuousRuleModifyingEff && event.getTargetId().equals(source.getSourceId())) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null && permanent.isControlledBy(game.getActivePlayerId())) { - AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName()); + AttackedLastTurnWatcher watcher = game.getState().getWatcher(AttackedLastTurnWatcher.class); if (watcher != null) { Set attackingCreatures = watcher.getAttackedLastTurnCreatures(permanent.getControllerId()); MageObjectReference mor = new MageObjectReference(permanent, game); diff --git a/Mage.Sets/src/mage/cards/g/GoblinTrenches.java b/Mage.Sets/src/mage/cards/g/GoblinTrenches.java index 5b3e4dc944..1fa892e610 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinTrenches.java +++ b/Mage.Sets/src/mage/cards/g/GoblinTrenches.java @@ -22,7 +22,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class GoblinTrenches extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledLandPermanent("a land"); + static final FilterControlledPermanent filter = new FilterControlledLandPermanent("a land"); public GoblinTrenches(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{W}"); diff --git a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java index d4479c8475..1c31bdcf43 100644 --- a/Mage.Sets/src/mage/cards/g/GoblinWarCry.java +++ b/Mage.Sets/src/mage/cards/g/GoblinWarCry.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; @@ -19,8 +17,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 & L_J */ public final class GoblinWarCry extends CardImpl { @@ -83,7 +82,7 @@ class GoblinWarCryEffect extends OneShotEffect { } class GoblinWarCryRestrictionEffect extends RestrictionEffect { - + protected UUID targetId; public GoblinWarCryRestrictionEffect(UUID targetId) { @@ -103,17 +102,11 @@ class GoblinWarCryRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.isControlledBy(source.getFirstTarget())) { - return true; - } - return false; + return permanent.isControlledBy(source.getFirstTarget()); } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (targetId != null && blocker.getId().equals(targetId)) { - return true; - } - return false; + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return targetId != null && blocker.getId().equals(targetId); } } diff --git a/Mage.Sets/src/mage/cards/g/GodEternalBontu.java b/Mage.Sets/src/mage/cards/g/GodEternalBontu.java new file mode 100644 index 0000000000..ab11688724 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GodEternalBontu.java @@ -0,0 +1,101 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GodEternalDiesTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GodEternalBontu extends CardImpl { + + public GodEternalBontu(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.GOD); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // Menace + this.addAbility(new MenaceAbility()); + + // When God-Eternal Bontu enters the battlefield, sacrifice any number of other permanents, then draw that many cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GodEternalBontuEffect())); + + // When God-Eternal Bontu dies or is put into exile from the battlefield, you may put it into its owner's library third from the top. + this.addAbility(new GodEternalDiesTriggeredAbility()); + } + + private GodEternalBontu(final GodEternalBontu card) { + super(card); + } + + @Override + public GodEternalBontu copy() { + return new GodEternalBontu(this); + } +} + +class GodEternalBontuEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent("other permanents you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + GodEternalBontuEffect() { + super(Outcome.Benefit); + staticText = "sacrifice any number of other permanents, then draw that many cards."; + } + + private GodEternalBontuEffect(final GodEternalBontuEffect effect) { + super(effect); + } + + @Override + public GodEternalBontuEffect copy() { + return new GodEternalBontuEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + int counter = 0; + for (UUID permanentId : target.getTargets()) { + Permanent permanent = game.getPermanent(permanentId); + if (permanent != null && permanent.sacrifice(source.getSourceId(), game)) { + counter++; + } + } + return player.drawCards(counter, game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java b/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java new file mode 100644 index 0000000000..8e1ce4c277 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GodEternalKefnet.java @@ -0,0 +1,157 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.GodEternalDiesTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.hint.HintUtils; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.watchers.common.CardsAmountDrawnThisTurnWatcher; + +import java.awt.*; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class GodEternalKefnet extends CardImpl { + + public GodEternalKefnet(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.GOD); + + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // You may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant or sorcery card this way, + // copy that card and you may cast the copy. That copy costs {2} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GodEternalKefnetDrawCardReplacementEffect()), new CardsAmountDrawnThisTurnWatcher()); + + // When God-Eternal Kefnet dies or is put into exile from the battlefield, you may put it into its owner’s library third from the top. + this.addAbility(new GodEternalDiesTriggeredAbility()); + } + + public GodEternalKefnet(final GodEternalKefnet card) { + super(card); + } + + @Override + public GodEternalKefnet copy() { + return new GodEternalKefnet(this); + } +} + +class GodEternalKefnetDrawCardReplacementEffect extends ReplacementEffectImpl { + + public GodEternalKefnetDrawCardReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + this.staticText = "You may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant " + + "or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast"; + } + + public GodEternalKefnetDrawCardReplacementEffect(final GodEternalKefnetDrawCardReplacementEffect effect) { + super(effect); + } + + @Override + public GodEternalKefnetDrawCardReplacementEffect copy() { + return new GodEternalKefnetDrawCardReplacementEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + // reveal top card and drawn (return false to continue default draw) + Permanent god = game.getPermanent(source.getSourceId()); + Player you = game.getPlayer(source.getControllerId()); + if (god == null && you == null) { + return false; + } + + Card topCard = you.getLibrary().getTopCards(game, 1).iterator().next(); + if (topCard == null) { + return false; + } + + // reveal + you.setTopCardRevealed(true); + + // cast copy + if (topCard.isInstantOrSorcery() && you.chooseUse(outcome, "Would you like to copy " + topCard.getName() + + " and cast it {2} less?", source, game)) { + Card blueprint = topCard.copy(); + blueprint.addAbility(new SimpleStaticAbility(Zone.ALL, new SpellCostReductionSourceEffect(2))); + Card copiedCard = game.copyCard(blueprint, source, source.getControllerId()); + you.moveCardToHandWithInfo(copiedCard, source.getSourceId(), game, true); // The copy is created in and cast from your hand. + you.cast(copiedCard.getSpellAbility(), game, false, new MageObjectReference(source.getSourceObject(game), game)); + } + + // draw (return false for default draw) + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.DRAW_CARD; + } + + String getAppliedMark(Game game, Ability source) { + return source.getId() + "-applied-" + source.getControllerId() + "-" + game.getState().getTurnNum(); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!event.getPlayerId().equals(source.getControllerId())) { + return false; + } + + Permanent god = game.getPermanent(source.getSourceId()); + Player you = game.getPlayer(source.getControllerId()); + if (god == null && you == null) { + return false; + } + + Card topCard = you.getLibrary().getTopCards(game, 1).iterator().next(); + if (topCard == null) { + return false; + } + + // only first draw card + // if card casted on that turn or controlled changed then needs history from watcher + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); + if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) != 0) { + return false; + } + + // one time use (if multiple cards drawn) + String mark = getAppliedMark(game, source); + if (game.getState().getValue(mark) != null) { + return false; + } + game.getState().setValue(mark, true); + + // ask player to reveal top cards + String mes = topCard.getName() + ", " + (topCard.isInstantOrSorcery() + ? HintUtils.prepareText("you can copy it and cast {2} less", Color.green) + : HintUtils.prepareText("you can't copy it", Color.red)); + return you.chooseUse(Outcome.Benefit, "Would you like to reveal first drawn card (" + mes + ")?", source, game); + } + +} + diff --git a/Mage.Sets/src/mage/cards/g/GodEternalOketra.java b/Mage.Sets/src/mage/cards/g/GodEternalOketra.java new file mode 100644 index 0000000000..5e297e10a9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GodEternalOketra.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.GodEternalDiesTriggeredAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.DoubleStrikeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.GodEternalOketraToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GodEternalOketra extends CardImpl { + + public GodEternalOketra(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.GOD); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // Double strike + this.addAbility(DoubleStrikeAbility.getInstance()); + + // Whenever you cast a creature spell, create a 4/4 black Zombie Warrior creature token with vigilance. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new GodEternalOketraToken()), + StaticFilters.FILTER_SPELL_A_CREATURE, false + )); + + // When God-Eternal Oketra dies or is put into exile from the battlefield, you may put it into its owner's library third from the top. + this.addAbility(new GodEternalDiesTriggeredAbility()); + } + + private GodEternalOketra(final GodEternalOketra card) { + super(card); + } + + @Override + public GodEternalOketra copy() { + return new GodEternalOketra(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GodEternalRhonas.java b/Mage.Sets/src/mage/cards/g/GodEternalRhonas.java new file mode 100644 index 0000000000..6195751ad2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GodEternalRhonas.java @@ -0,0 +1,101 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.GodEternalDiesTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GodEternalRhonas extends CardImpl { + + public GodEternalRhonas(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.GOD); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // When God-Eternal Rhonas enters the battlefield, double the power of each other creature you control until end of turn. Those creatures gain vigilance until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GodEternalRhonasEffect())); + + // When God-Eternal Rhonas dies or is put into exile from the battlefield, you may put it into its owner's library third from the top. + this.addAbility(new GodEternalDiesTriggeredAbility()); + } + + private GodEternalRhonas(final GodEternalRhonas card) { + super(card); + } + + @Override + public GodEternalRhonas copy() { + return new GodEternalRhonas(this); + } +} + +class GodEternalRhonasEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + } + + GodEternalRhonasEffect() { + super(Outcome.Benefit); + staticText = "double the power of each other creature you control until end of turn. " + + "Those creatures gain vigilance until end of turn."; + } + + private GodEternalRhonasEffect(final GodEternalRhonasEffect effect) { + super(effect); + } + + @Override + public GodEternalRhonasEffect copy() { + return new GodEternalRhonasEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + if (permanent == null) { + continue; + } + ContinuousEffect effect = new BoostTargetEffect( + permanent.getPower().getValue(), + 0, Duration.EndOfTurn + ); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + game.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), + Duration.EndOfTurn, filter + ), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GodPharaohsStatue.java b/Mage.Sets/src/mage/cards/g/GodPharaohsStatue.java new file mode 100644 index 0000000000..2e2c67444d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GodPharaohsStatue.java @@ -0,0 +1,81 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GodPharaohsStatue extends CardImpl { + + public GodPharaohsStatue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); + + this.addSuperType(SuperType.LEGENDARY); + + // Spells your opponents cast cost {2} more to cast. + this.addAbility(new SimpleStaticAbility(new GodPharaohsStatueEffect())); + + // At the beginning of your end step, each opponent loses 1 life. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new LoseLifeOpponentsEffect(1), TargetController.YOU, false + )); + } + + private GodPharaohsStatue(final GodPharaohsStatue card) { + super(card); + } + + @Override + public GodPharaohsStatue copy() { + return new GodPharaohsStatue(this); + } +} + +class GodPharaohsStatueEffect extends CostModificationEffectImpl { + + private static final String effectText = "Spells your opponents cast cost {2} more to cast"; + + GodPharaohsStatueEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = effectText; + } + + private GodPharaohsStatueEffect(GodPharaohsStatueEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (abilityToModify instanceof SpellAbility) { + if (game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { + return true; + } + } + return false; + } + + @Override + public GodPharaohsStatueEffect copy() { + return new GodPharaohsStatueEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/g/GodheadOfAwe.java b/Mage.Sets/src/mage/cards/g/GodheadOfAwe.java index 153484a72d..44a6fde8fd 100644 --- a/Mage.Sets/src/mage/cards/g/GodheadOfAwe.java +++ b/Mage.Sets/src/mage/cards/g/GodheadOfAwe.java @@ -27,7 +27,7 @@ public final class GodheadOfAwe extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GodheadOfAwe(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GodhunterOctopus.java b/Mage.Sets/src/mage/cards/g/GodhunterOctopus.java index 1817d45021..b3b5bd14ec 100644 --- a/Mage.Sets/src/mage/cards/g/GodhunterOctopus.java +++ b/Mage.Sets/src/mage/cards/g/GodhunterOctopus.java @@ -26,7 +26,7 @@ public final class GodhunterOctopus extends CardImpl { static { filter.add(Predicates.or( new CardTypePredicate(CardType.ENCHANTMENT), - new EnchantedPredicate())); + EnchantedPredicate.instance)); } public GodhunterOctopus(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GodoBanditWarlord.java b/Mage.Sets/src/mage/cards/g/GodoBanditWarlord.java index e57e96692d..8087a50f4c 100644 --- a/Mage.Sets/src/mage/cards/g/GodoBanditWarlord.java +++ b/Mage.Sets/src/mage/cards/g/GodoBanditWarlord.java @@ -32,7 +32,7 @@ public final class GodoBanditWarlord extends CardImpl { static { filter.add(new SubtypePredicate(SubType.EQUIPMENT)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public GodoBanditWarlord(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GodsEyeGateToTheReikai.java b/Mage.Sets/src/mage/cards/g/GodsEyeGateToTheReikai.java index 675f616ec2..52055a07e1 100644 --- a/Mage.Sets/src/mage/cards/g/GodsEyeGateToTheReikai.java +++ b/Mage.Sets/src/mage/cards/g/GodsEyeGateToTheReikai.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.mana.ColorlessManaAbility; @@ -11,19 +9,22 @@ import mage.constants.CardType; import mage.constants.SuperType; import mage.game.permanent.token.SpiritToken; +import java.util.UUID; + /** - * * @author Loki */ public final class GodsEyeGateToTheReikai extends CardImpl { public GodsEyeGateToTheReikai(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); addSuperType(SuperType.LEGENDARY); + // {tap}: Add {C}. this.addAbility(new ColorlessManaAbility()); + // When Gods' Eye, Gate to the Reikai is put into a graveyard from the battlefield, create a 1/1 colorless Spirit creature token. - this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new CreateTokenEffect(new SpiritToken(), 1), false)); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new CreateTokenEffect(new SpiritToken(), 1))); } public GodsEyeGateToTheReikai(final GodsEyeGateToTheReikai card) { diff --git a/Mage.Sets/src/mage/cards/g/Godsend.java b/Mage.Sets/src/mage/cards/g/Godsend.java index cc052a44ce..0ccda6a339 100644 --- a/Mage.Sets/src/mage/cards/g/Godsend.java +++ b/Mage.Sets/src/mage/cards/g/Godsend.java @@ -112,7 +112,7 @@ class GodsendTriggeredAbility extends TriggeredAbilityImpl { this.getEffects().get(0).setTargetPointer(new FixedTarget(possibleTargets.iterator().next())); } else { this.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); - targetName = new StringBuilder(targetName).append("equipped by ").append(equipment.getName()).toString(); + targetName = targetName + " equipped by " + equipment.getName(); FilterCreaturePermanent filter = new FilterCreaturePermanent(targetName); List uuidPredicates = new ArrayList<>(); for (UUID creatureId : possibleTargets) { diff --git a/Mage.Sets/src/mage/cards/g/GoldenDemise.java b/Mage.Sets/src/mage/cards/g/GoldenDemise.java index fb6cc3f53d..91641ac77d 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenDemise.java +++ b/Mage.Sets/src/mage/cards/g/GoldenDemise.java @@ -1,11 +1,10 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.effects.keyword.AscendEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,8 +13,9 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GoldenDemise extends CardImpl { @@ -35,6 +35,7 @@ public final class GoldenDemise extends CardImpl { CitysBlessingCondition.instance, "All creatures get -2/-2 until end of turn. If you have the city's blessing, instead only creatures your opponents control get -2/-2 until end of turn" )); + this.getSpellAbility().addHint(CitysBlessingHint.instance); } public GoldenDemise(final GoldenDemise card) { diff --git a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java index c96c531112..3ec9d69dd6 100644 --- a/Mage.Sets/src/mage/cards/g/GoldenGuardian.java +++ b/Mage.Sets/src/mage/cards/g/GoldenGuardian.java @@ -38,7 +38,7 @@ public final class GoldenGuardian extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GoldenGuardian(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GoldnightRedeemer.java b/Mage.Sets/src/mage/cards/g/GoldnightRedeemer.java index 6291d17185..856e6dfbc3 100644 --- a/Mage.Sets/src/mage/cards/g/GoldnightRedeemer.java +++ b/Mage.Sets/src/mage/cards/g/GoldnightRedeemer.java @@ -24,7 +24,7 @@ public final class GoldnightRedeemer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GoldnightRedeemer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GolgariCharm.java b/Mage.Sets/src/mage/cards/g/GolgariCharm.java index b9d39e8860..780735c0ec 100644 --- a/Mage.Sets/src/mage/cards/g/GolgariCharm.java +++ b/Mage.Sets/src/mage/cards/g/GolgariCharm.java @@ -29,13 +29,13 @@ public final class GolgariCharm extends CardImpl { // or destroy target enchantment; Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetEnchantmentPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); // or regenerate each creature you control. mode = new Mode(); - mode.getEffects().add(new RegenerateAllEffect(new FilterControlledCreaturePermanent())); + mode.addEffect(new RegenerateAllEffect(new FilterControlledCreaturePermanent())); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GolgariGermination.java b/Mage.Sets/src/mage/cards/g/GolgariGermination.java index bbcfdc53ee..f6890106e6 100644 --- a/Mage.Sets/src/mage/cards/g/GolgariGermination.java +++ b/Mage.Sets/src/mage/cards/g/GolgariGermination.java @@ -24,7 +24,7 @@ public final class GolgariGermination extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public GolgariGermination(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GolgothianSylex.java b/Mage.Sets/src/mage/cards/g/GolgothianSylex.java index c2b9261d12..1bf1c09124 100644 --- a/Mage.Sets/src/mage/cards/g/GolgothianSylex.java +++ b/Mage.Sets/src/mage/cards/g/GolgothianSylex.java @@ -51,7 +51,7 @@ class GolgothianSylexEffect extends OneShotEffect { static { filter.add(Predicates.and( new ExpansionSetPredicate("ATQ"), - Predicates.not(new TokenPredicate()) + Predicates.not(TokenPredicate.instance) )); } diff --git a/Mage.Sets/src/mage/cards/g/Gomazoa.java b/Mage.Sets/src/mage/cards/g/Gomazoa.java index f609015e0f..fb217b8627 100644 --- a/Mage.Sets/src/mage/cards/g/Gomazoa.java +++ b/Mage.Sets/src/mage/cards/g/Gomazoa.java @@ -86,10 +86,9 @@ class GomazoaEffect extends OneShotEffect { players.add(gomazoa.getOwnerId()); } - BlockedByWatcher watcher = (BlockedByWatcher) game.getState().getWatchers().get(BlockedByWatcher.class.getSimpleName(), source.getSourceId()); - creaturesBlocked = watcher.blockedByWatcher; + BlockedByWatcher watcher = game.getState().getWatcher(BlockedByWatcher.class, source.getSourceId()); - for (UUID blockedById : creaturesBlocked) { + for (UUID blockedById : watcher.getBlockedByWatcher()) { Permanent blockedByGomazoa = game.getPermanent(blockedById); if (blockedByGomazoa != null && blockedByGomazoa.isAttacking()) { players.add(blockedByGomazoa.getOwnerId()); @@ -114,13 +113,17 @@ class GomazoaEffect extends OneShotEffect { class BlockedByWatcher extends Watcher { - public List blockedByWatcher = new ArrayList<>(); - - public BlockedByWatcher() { - super(BlockedByWatcher.class.getSimpleName(), WatcherScope.CARD); + public List getBlockedByWatcher() { + return blockedByWatcher; } - public BlockedByWatcher(final BlockedByWatcher watcher) { + private List blockedByWatcher = new ArrayList<>(); + + public BlockedByWatcher() { + super(WatcherScope.CARD); + } + + private BlockedByWatcher(final BlockedByWatcher watcher) { super(watcher); this.blockedByWatcher.addAll(watcher.blockedByWatcher); } diff --git a/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java b/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java index c40c107756..cae0b23530 100644 --- a/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java +++ b/Mage.Sets/src/mage/cards/g/GontiLordOfLuxury.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.HashSet; @@ -155,7 +154,8 @@ class GontiLordOfLuxuryCastFromExileEffect extends AsThoughEffectImpl { && affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(objectId); // TODO: Allow to cast Zoetic Cavern face down - return card != null && !card.isLand(); + return card != null + && !card.isLand(); } return false; } @@ -184,16 +184,15 @@ class GontiLordOfLuxurySpendAnyManaEffect extends AsThoughEffectImpl implements @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted this.discard(); @@ -230,13 +229,18 @@ class GontiLordOfLuxuryLookEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && game.getState().getZone(objectId) == Zone.EXILED) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards + if (affectedControllerId.equals(source.getControllerId()) + && game.getState().getZone(objectId) == Zone.EXILED) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { + if (controller != null + && sourceObject != null) { Card card = game.getCard(objectId); - if (card != null && card.isFaceDown(game)) { - Set exileZones = (Set) game.getState().getValue(GontiLordOfLuxury.VALUE_PREFIX + source.getSourceId().toString()); + if (card != null + && card.isFaceDown(game)) { + Set exileZones = (Set) game.getState().getValue( + GontiLordOfLuxury.VALUE_PREFIX + source.getSourceId().toString()); if (exileZones != null) { for (ExileZone exileZone : game.getExile().getExileZones()) { if (exileZone.contains(objectId)) { diff --git a/Mage.Sets/src/mage/cards/g/GontisMachinations.java b/Mage.Sets/src/mage/cards/g/GontisMachinations.java index 513d886712..c69a3692b4 100644 --- a/Mage.Sets/src/mage/cards/g/GontisMachinations.java +++ b/Mage.Sets/src/mage/cards/g/GontisMachinations.java @@ -1,4 +1,3 @@ - package mage.cards.g; import java.util.HashMap; @@ -19,6 +18,7 @@ import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; +import mage.players.Player; import mage.watchers.Watcher; /** @@ -30,10 +30,14 @@ public final class GontisMachinations extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // Whenever you lose life for the first time each turn, you get {E}. - this.addAbility(new GontisMachinationsTriggeredAbility(), new GontisMachinationsFirstLostLifeThisTurnWatcher()); + this.addAbility(new GontisMachinationsTriggeredAbility(), + new GontisMachinationsFirstLostLifeThisTurnWatcher()); // Pay {E}{E}, Sacrifice Gonti's Machinations: Each opponent loses 3 life. You gain life equal to the life lost this way. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GontisMachinationsEffect(), new PayEnergyCost(2)); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GontisMachinationsEffect(), + new PayEnergyCost(2)); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -68,8 +72,9 @@ class GontisMachinationsTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(getControllerId())) { GontisMachinationsFirstLostLifeThisTurnWatcher watcher - = (GontisMachinationsFirstLostLifeThisTurnWatcher) game.getState().getWatchers().get(GontisMachinationsFirstLostLifeThisTurnWatcher.class.getSimpleName()); - if (watcher != null && watcher.timesLostLifeThisTurn(event.getTargetId()) < 2) { + = game.getState().getWatcher(GontisMachinationsFirstLostLifeThisTurnWatcher.class); + if (watcher != null + && watcher.timesLostLifeThisTurn(event.getTargetId()) < 2) { return true; } } @@ -92,7 +97,7 @@ class GontisMachinationsFirstLostLifeThisTurnWatcher extends Watcher { private final Map playersLostLife = new HashMap<>(); public GontisMachinationsFirstLostLifeThisTurnWatcher() { - super(GontisMachinationsFirstLostLifeThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public GontisMachinationsFirstLostLifeThisTurnWatcher(final GontisMachinationsFirstLostLifeThisTurnWatcher watcher) { @@ -129,7 +134,7 @@ class GontisMachinationsFirstLostLifeThisTurnWatcher extends Watcher { class GontisMachinationsEffect extends OneShotEffect { public GontisMachinationsEffect() { - super(Outcome.Damage); + super(Outcome.GainLife); staticText = "Each opponent loses 3 life. You gain life equal to the life lost this way"; } @@ -139,12 +144,19 @@ class GontisMachinationsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int damage = 0; - for (UUID opponentId : game.getOpponents(source.getControllerId())) { - damage += game.getPlayer(opponentId).loseLife(3, game, false); + int totalLostLife = 0; + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + totalLostLife += game.getPlayer(opponentId).loseLife(3, game, false); + } + } + game.getPlayer(source.getControllerId()).gainLife(totalLostLife, game, source); + return true; } - game.getPlayer(source.getControllerId()).gainLife(damage, game, source); - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/g/GossamerChains.java b/Mage.Sets/src/mage/cards/g/GossamerChains.java index de7c0d7e2c..0d253b122b 100644 --- a/Mage.Sets/src/mage/cards/g/GossamerChains.java +++ b/Mage.Sets/src/mage/cards/g/GossamerChains.java @@ -24,7 +24,7 @@ public final class GossamerChains extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creature"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } public GossamerChains(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java b/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java index e49428ecb0..edf5a2ab8d 100644 --- a/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java +++ b/Mage.Sets/src/mage/cards/g/GovernTheGuildless.java @@ -23,7 +23,7 @@ public final class GovernTheGuildless extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("monocolored creature"); static { - filter.add(new MonocoloredPredicate()); + filter.add(MonocoloredPredicate.instance); } public GovernTheGuildless(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrabTheReins.java b/Mage.Sets/src/mage/cards/g/GrabTheReins.java index 6887c32aa9..b60430110d 100644 --- a/Mage.Sets/src/mage/cards/g/GrabTheReins.java +++ b/Mage.Sets/src/mage/cards/g/GrabTheReins.java @@ -48,10 +48,10 @@ public final class GrabTheReins extends CardImpl { this.getSpellAbility().addTarget(target); // or sacrifice a creature, then Grab the Reins deals damage equal to that creature's power to any target. Mode mode = new Mode(); - mode.getEffects().add(new GrabTheReinsEffect()); + mode.addEffect(new GrabTheReinsEffect()); TargetAnyTarget target2 = new TargetAnyTarget(); target2.setTargetName("a creature or player to damage"); - mode.getTargets().add(target2); + mode.addTarget(target2); this.getSpellAbility().getModes().addMode(mode); // Entwine {2}{R} diff --git a/Mage.Sets/src/mage/cards/g/GracefulAntelope.java b/Mage.Sets/src/mage/cards/g/GracefulAntelope.java index ec57976938..2269ccbcf6 100644 --- a/Mage.Sets/src/mage/cards/g/GracefulAntelope.java +++ b/Mage.Sets/src/mage/cards/g/GracefulAntelope.java @@ -1,6 +1,6 @@ - package mage.cards.g; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; @@ -11,11 +11,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.target.Target; import mage.target.common.TargetLandPermanent; -import java.util.UUID; - /** * * @author cbt33, Loki (Contaminated Ground), Plopman (Larceny) @@ -23,7 +20,7 @@ import java.util.UUID; public final class GracefulAntelope extends CardImpl { public GracefulAntelope(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); this.subtype.add(SubType.ANTELOPE); this.power = new MageInt(1); @@ -32,9 +29,8 @@ public final class GracefulAntelope extends CardImpl { // Plainswalk this.addAbility(new PlainswalkAbility()); // Whenever Graceful Antelope deals combat damage to a player, you may have target land become a Plains until Graceful Antelope leaves the battlefield. - Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new BecomesBasicLandTargetEffect(Duration.WhileOnBattlefield, SubType.PLAINS), true); - Target target = new TargetLandPermanent(); - ability.addTarget(target); + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new BecomesBasicLandTargetEffect(Duration.UntilSourceLeavesBattlefield, SubType.PLAINS), true); + ability.addTarget(new TargetLandPermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/g/GracefulReprieve.java b/Mage.Sets/src/mage/cards/g/GracefulReprieve.java index 8e891fc4da..99abc60e6b 100644 --- a/Mage.Sets/src/mage/cards/g/GracefulReprieve.java +++ b/Mage.Sets/src/mage/cards/g/GracefulReprieve.java @@ -93,7 +93,7 @@ class GracefulReprieveDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (target.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { getEffects().setTargetPointer(new FixedTarget(target.getSourceId())); return true; } diff --git a/Mage.Sets/src/mage/cards/g/GrandArchitect.java b/Mage.Sets/src/mage/cards/g/GrandArchitect.java index e599814dfc..3060d39137 100644 --- a/Mage.Sets/src/mage/cards/g/GrandArchitect.java +++ b/Mage.Sets/src/mage/cards/g/GrandArchitect.java @@ -105,7 +105,7 @@ class GrandArchitectManaAbility extends ActivatedManaAbilityImpl { static { filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } GrandArchitectManaAbility() { diff --git a/Mage.Sets/src/mage/cards/g/GrandWarlordRadha.java b/Mage.Sets/src/mage/cards/g/GrandWarlordRadha.java index 508844bc91..9eefb0a7f1 100644 --- a/Mage.Sets/src/mage/cards/g/GrandWarlordRadha.java +++ b/Mage.Sets/src/mage/cards/g/GrandWarlordRadha.java @@ -62,10 +62,10 @@ public final class GrandWarlordRadha extends CardImpl { class CreaturesAttackedWatcher extends Watcher { - public final Set attackedThisTurnCreatures = new HashSet<>(); + private final Set attackedThisTurnCreatures = new HashSet<>(); public CreaturesAttackedWatcher() { - super(CreaturesAttackedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CreaturesAttackedWatcher(final CreaturesAttackedWatcher watcher) { @@ -153,7 +153,7 @@ class GrandWarlordRadhaEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - CreaturesAttackedWatcher watcher = (CreaturesAttackedWatcher) game.getState().getWatchers().get(CreaturesAttackedWatcher.class.getSimpleName()); + CreaturesAttackedWatcher watcher = game.getState().getWatcher(CreaturesAttackedWatcher.class); if (watcher != null) { int attackingCreatures = 0; for (MageObjectReference attacker : watcher.getAttackedThisTurnCreatures()) { diff --git a/Mage.Sets/src/mage/cards/g/GraspOfFate.java b/Mage.Sets/src/mage/cards/g/GraspOfFate.java index 271b67e730..3fbb816904 100644 --- a/Mage.Sets/src/mage/cards/g/GraspOfFate.java +++ b/Mage.Sets/src/mage/cards/g/GraspOfFate.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; @@ -23,10 +22,12 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author fireshoes */ public final class GraspOfFate extends CardImpl { @@ -36,8 +37,8 @@ public final class GraspOfFate extends CardImpl { // When Grasp of Fate enters the battlefield, for each opponent, exile up to one target nonland permanent that player controls until Grasp of Fate leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new GraspOfFateExileEffect()); - ability.addTarget(new TargetPermanent()); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + ability.setTargetAdjuster(GraspOfFateAdjuster.instance); this.addAbility(ability); } @@ -45,29 +46,32 @@ public final class GraspOfFate extends CardImpl { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterPermanent filter = new FilterPermanent("nonland permanent from opponent " + opponent.getLogName()); - filter.add(new ControllerIdPredicate(opponentId)); - filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - TargetPermanent target = new TargetPermanent(0, 1, filter, false); - ability.addTarget(target); - } - } - } - } - @Override public GraspOfFate copy() { return new GraspOfFate(this); } } +enum GraspOfFateAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + FilterPermanent filter = new FilterPermanent("nonland permanent from opponent " + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponentId)); + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + TargetPermanent target = new TargetPermanent(0, 1, filter, false); + ability.addTarget(target); + } + } +} + class GraspOfFateExileEffect extends OneShotEffect { public GraspOfFateExileEffect() { diff --git a/Mage.Sets/src/mage/cards/g/GraspingCurrent.java b/Mage.Sets/src/mage/cards/g/GraspingCurrent.java index 7d37e336b0..bc0c171975 100644 --- a/Mage.Sets/src/mage/cards/g/GraspingCurrent.java +++ b/Mage.Sets/src/mage/cards/g/GraspingCurrent.java @@ -17,7 +17,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class GraspingCurrent extends CardImpl { - private final static FilterCard filter = new FilterCard("Jace, Ingenious Mind-Mage"); + private static final FilterCard filter = new FilterCard("Jace, Ingenious Mind-Mage"); static { filter.add(new NamePredicate("Jace, Ingenious Mind-Mage")); diff --git a/Mage.Sets/src/mage/cards/g/GraspingThrull.java b/Mage.Sets/src/mage/cards/g/GraspingThrull.java new file mode 100644 index 0000000000..c383888f51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GraspingThrull.java @@ -0,0 +1,48 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GraspingThrull extends CardImpl { + + public GraspingThrull(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{B}"); + + this.subtype.add(SubType.THRULL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Grasping Thrull enters the battlefield, it deals 2 damage to each opponent and you gain 2 life. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect( + 2, TargetController.OPPONENT, "it" + )); + ability.addEffect(new GainLifeEffect(2).setText("and you gain 2 life")); + this.addAbility(ability); + } + + private GraspingThrull(final GraspingThrull card) { + super(card); + } + + @Override + public GraspingThrull copy() { + return new GraspingThrull(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GratefulApparition.java b/Mage.Sets/src/mage/cards/g/GratefulApparition.java new file mode 100644 index 0000000000..5e96f199cb --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GratefulApparition.java @@ -0,0 +1,43 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.FlyingAbility; +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 GratefulApparition extends CardImpl { + + public GratefulApparition(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Grateful Apparition deals combat damage to a player or planeswalker, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new ProliferateEffect(), false + ).setOrPlaneswalker(true)); + } + + private GratefulApparition(final GratefulApparition card) { + super(card); + } + + @Override + public GratefulApparition copy() { + return new GratefulApparition(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GraveBetrayal.java b/Mage.Sets/src/mage/cards/g/GraveBetrayal.java index 888925283e..fb1ccc708a 100644 --- a/Mage.Sets/src/mage/cards/g/GraveBetrayal.java +++ b/Mage.Sets/src/mage/cards/g/GraveBetrayal.java @@ -162,7 +162,7 @@ class GraveBetrayalReplacementEffect extends ReplacementEffectImpl { ContinuousEffect effect = new BecomesBlackZombieAdditionEffect(); effect.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game) + 1)); game.addEffect(effect, source); - discard(); + //discard(); why? } return false; } diff --git a/Mage.Sets/src/mage/cards/g/GraveUpheaval.java b/Mage.Sets/src/mage/cards/g/GraveUpheaval.java index 9b2a0c33ec..94f5205e52 100644 --- a/Mage.Sets/src/mage/cards/g/GraveUpheaval.java +++ b/Mage.Sets/src/mage/cards/g/GraveUpheaval.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -33,7 +34,7 @@ public final class GraveUpheaval extends CardImpl { // Put target creature card from a graveyard onto the battlefield under your control. It gains haste. this.getSpellAbility().addEffect(new GraveUpheavalEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard()); + this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard())); // Basic landcycling {2} this.addAbility(new BasicLandcyclingAbility(new ManaCostsImpl("{2}"))); diff --git a/Mage.Sets/src/mage/cards/g/GravebaneZombie.java b/Mage.Sets/src/mage/cards/g/GravebaneZombie.java index 3cd58474ac..43d6a30779 100644 --- a/Mage.Sets/src/mage/cards/g/GravebaneZombie.java +++ b/Mage.Sets/src/mage/cards/g/GravebaneZombie.java @@ -62,7 +62,7 @@ class GravebaneZombieEffect extends ReplacementEffectImpl { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent != null) { if (permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true)) { - game.informPlayers(new StringBuilder(permanent.getName()).append(" was put on the top of its owner's library").toString()); + game.informPlayers(permanent.getName() + " was put on the top of its owner's library"); return true; } } diff --git a/Mage.Sets/src/mage/cards/g/GravelHideGoblin.java b/Mage.Sets/src/mage/cards/g/GravelHideGoblin.java new file mode 100644 index 0000000000..1d5f4f2e1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GravelHideGoblin.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +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 GravelHideGoblin extends CardImpl { + + public GravelHideGoblin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {3}{G}: Gravel-Hide Goblin gets +2/+2 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 2, Duration.EndOfTurn), new ManaCostsImpl("{3}{G}") + )); + } + + private GravelHideGoblin(final GravelHideGoblin card) { + super(card); + } + + @Override + public GravelHideGoblin copy() { + return new GravelHideGoblin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GravenAbomination.java b/Mage.Sets/src/mage/cards/g/GravenAbomination.java index c48c21d123..18f6730471 100644 --- a/Mage.Sets/src/mage/cards/g/GravenAbomination.java +++ b/Mage.Sets/src/mage/cards/g/GravenAbomination.java @@ -1,7 +1,6 @@ package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -11,20 +10,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.filter.FilterCard; -import mage.filter.predicate.other.OwnerIdPredicate; -import mage.game.Game; -import mage.players.Player; +import mage.filter.predicate.permanent.DefendingPlayerOwnsCardPredicate; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GravenAbomination extends CardImpl { - private final UUID originalId; + private static final String rule = "Whenever {this} attacks, exile target card from defending player's graveyard."; + private static final FilterCard filter = new FilterCard("card from defending player's graveyard"); - private final static String rule = "Whenever {this} attacks, exile target card from defending player's graveyard."; + static { + filter.add(new DefendingPlayerOwnsCardPredicate()); + } public GravenAbomination(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); @@ -35,30 +36,12 @@ public final class GravenAbomination extends CardImpl { // Whenever Graven Abomination attacks, exile target card from defending player's graveyard. Ability ability = new AttacksTriggeredAbility(new ExileTargetEffect(), false, rule); - ability.addTarget(new TargetCardInGraveyard()); + ability.addTarget(new TargetCardInGraveyard(filter)); this.addAbility(ability); - originalId = ability.getOriginalId(); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - UUID gravenAbominationId = ability.getSourceId(); - FilterCard filter = new FilterCard("target card from defending player's graveyard"); - if (ability.getOriginalId().equals(originalId)) { - UUID defendingPlayerId = game.getCombat().getDefendingPlayerId(gravenAbominationId, game); - Player defendingPlayer = game.getPlayer(defendingPlayerId); - if (defendingPlayer != null) { - filter.add(new OwnerIdPredicate(defendingPlayerId)); - ability.getTargets().clear(); - ability.getTargets().add(new TargetCardInGraveyard(filter)); - } - } } public GravenAbomination(final GravenAbomination card) { super(card); - this.originalId = card.originalId; } @Override diff --git a/Mage.Sets/src/mage/cards/g/GravenDominator.java b/Mage.Sets/src/mage/cards/g/GravenDominator.java index eb01ba0dee..39db2926a7 100644 --- a/Mage.Sets/src/mage/cards/g/GravenDominator.java +++ b/Mage.Sets/src/mage/cards/g/GravenDominator.java @@ -23,7 +23,7 @@ public final class GravenDominator extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each other creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GravenDominator(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java index 4a8f32c2c8..dad0cec4b6 100644 --- a/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java +++ b/Mage.Sets/src/mage/cards/g/GravespawnSovereign.java @@ -30,7 +30,7 @@ public final class GravespawnSovereign extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public GravespawnSovereign(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GravityNegator.java b/Mage.Sets/src/mage/cards/g/GravityNegator.java index 77632558d0..e96d7f465a 100644 --- a/Mage.Sets/src/mage/cards/g/GravityNegator.java +++ b/Mage.Sets/src/mage/cards/g/GravityNegator.java @@ -25,10 +25,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class GravityNegator extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GravityNegator(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GravitySphere.java b/Mage.Sets/src/mage/cards/g/GravitySphere.java index 97871089dc..e0fa620fd1 100644 --- a/Mage.Sets/src/mage/cards/g/GravitySphere.java +++ b/Mage.Sets/src/mage/cards/g/GravitySphere.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public final class GravitySphere extends CardImpl { - final static private FilterPermanent filter = new FilterPermanent("All creatures"); + static final private FilterPermanent filter = new FilterPermanent("All creatures"); static { filter.add(new CardTypePredicate(CardType.CREATURE)); diff --git a/Mage.Sets/src/mage/cards/g/GrayMerchantOfAsphodel.java b/Mage.Sets/src/mage/cards/g/GrayMerchantOfAsphodel.java index 9f6d51b100..eac3532fb0 100644 --- a/Mage.Sets/src/mage/cards/g/GrayMerchantOfAsphodel.java +++ b/Mage.Sets/src/mage/cards/g/GrayMerchantOfAsphodel.java @@ -30,7 +30,9 @@ public final class GrayMerchantOfAsphodel extends CardImpl { this.toughness = new MageInt(4); // When Gray Merchant of Asphodel enters the battlefield, each opponent loses X life, where X is your devotion to black. You gain life equal to the life lost this way. - this.addAbility(new EntersBattlefieldTriggeredAbility(new GrayMerchantOfAsphodelEffect(), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new GrayMerchantOfAsphodelEffect(), + false)); } public GrayMerchantOfAsphodel(final GrayMerchantOfAsphodel card) { @@ -46,8 +48,11 @@ public final class GrayMerchantOfAsphodel extends CardImpl { class GrayMerchantOfAsphodelEffect extends OneShotEffect { public GrayMerchantOfAsphodelEffect() { - super(Outcome.Benefit); - this.staticText = "each opponent loses X life, where X is your devotion to black. You gain life equal to the life lost this way. (Each {B} in the mana costs of permanents you control counts towards your devotion to black.)"; + super(Outcome.GainLife); + this.staticText = "each opponent loses X life, where X is your devotion to black. " + + "You gain life equal to the life lost this way. " + + "(Each {B} in the mana costs of permanents you control " + + "counts towards your devotion to black.)"; } public GrayMerchantOfAsphodelEffect(final GrayMerchantOfAsphodelEffect effect) { @@ -63,17 +68,17 @@ class GrayMerchantOfAsphodelEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - int lifeLost = 0; - int damage = new DevotionCount(ColoredManaSymbol.B).calculate(game, source, this); - if (damage > 0) { + int totalLifeLost = 0; + int lifeLost = new DevotionCount(ColoredManaSymbol.B).calculate(game, source, this); + if (lifeLost > 0) { for (UUID playerId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - lifeLost += opponent.loseLife(damage, game, false); + totalLifeLost += opponent.loseLife(lifeLost, game, false); } } } - controller.gainLife(lifeLost, game, source); + controller.gainLife(totalLifeLost, game, source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/g/GreatDefender.java b/Mage.Sets/src/mage/cards/g/GreatDefender.java index 44d18590fe..369c3eafd6 100644 --- a/Mage.Sets/src/mage/cards/g/GreatDefender.java +++ b/Mage.Sets/src/mage/cards/g/GreatDefender.java @@ -22,7 +22,7 @@ public final class GreatDefender extends CardImpl { // Target creature gets +0/+X until end of turn, where X is its converted mana cost. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BoostTargetEffect(new StaticValue(0), new TargetConvertedManaCost(), Duration.EndOfTurn, true) + this.getSpellAbility().addEffect(new BoostTargetEffect(new StaticValue(0), TargetConvertedManaCost.instance, Duration.EndOfTurn, true) .setText("Target creature gets +0/+X until end of turn, where X is its converted mana cost.") ); } diff --git a/Mage.Sets/src/mage/cards/g/GreatbowDoyen.java b/Mage.Sets/src/mage/cards/g/GreatbowDoyen.java index 0323b7d343..88be27c426 100644 --- a/Mage.Sets/src/mage/cards/g/GreatbowDoyen.java +++ b/Mage.Sets/src/mage/cards/g/GreatbowDoyen.java @@ -131,7 +131,7 @@ class GreatbowDoyenEffect extends OneShotEffect { Player player = game.getPlayer(controllerId); if (player != null) { player.damage(damageAmount, sourceOfDamage, game, false, true); - game.informPlayers(new StringBuilder(permanent.getName()).append(" deals ").append(damageAmount).append(" damage to ").append(player.getLogName()).toString()); + game.informPlayers(permanent.getName() + " deals " + damageAmount + " damage to " + player.getLogName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/g/GreaterAuramancy.java b/Mage.Sets/src/mage/cards/g/GreaterAuramancy.java index befbb73a1b..76c8afdeb8 100644 --- a/Mage.Sets/src/mage/cards/g/GreaterAuramancy.java +++ b/Mage.Sets/src/mage/cards/g/GreaterAuramancy.java @@ -31,7 +31,7 @@ public final class GreaterAuramancy extends CardImpl { filter.add(new CardTypePredicate(CardType.ENCHANTMENT)); filter2.add(new ControllerPredicate(TargetController.YOU)); filter2.add(new CardTypePredicate(CardType.CREATURE)); - filter2.add(new EnchantedPredicate()); + filter2.add(EnchantedPredicate.instance); } public GreaterAuramancy(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GreaterGood.java b/Mage.Sets/src/mage/cards/g/GreaterGood.java index 7aa69e4d2b..7fc94447bc 100644 --- a/Mage.Sets/src/mage/cards/g/GreaterGood.java +++ b/Mage.Sets/src/mage/cards/g/GreaterGood.java @@ -26,7 +26,7 @@ public final class GreaterGood extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); // Sacrifice a creature: Draw cards equal to the sacrificed creature's power, then discard three cards. - Effect effect = new DrawCardSourceControllerEffect(new SacrificeCostCreaturesPower()); + Effect effect = new DrawCardSourceControllerEffect(SacrificeCostCreaturesPower.instance); effect.setText("Draw cards equal to the sacrificed creature's power"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); diff --git a/Mage.Sets/src/mage/cards/g/GreelMindRaker.java b/Mage.Sets/src/mage/cards/g/GreelMindRaker.java index f3543a1950..bc79a60e01 100644 --- a/Mage.Sets/src/mage/cards/g/GreelMindRaker.java +++ b/Mage.Sets/src/mage/cards/g/GreelMindRaker.java @@ -36,7 +36,7 @@ public final class GreelMindRaker extends CardImpl { this.toughness = new MageInt(3); // {X}{B}, {tap}, Discard two cards: Target player discards X cards at random. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(new ManacostVariableValue(), true), new ManaCostsImpl("{X}{B}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DiscardTargetEffect(ManacostVariableValue.instance, true), new ManaCostsImpl("{X}{B}")); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, new FilterCard()))); ability.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/g/GreenManaBattery.java b/Mage.Sets/src/mage/cards/g/GreenManaBattery.java index d0bf8cdfc0..9669605db2 100644 --- a/Mage.Sets/src/mage/cards/g/GreenManaBattery.java +++ b/Mage.Sets/src/mage/cards/g/GreenManaBattery.java @@ -36,7 +36,7 @@ public final class GreenManaBattery extends CardImpl { // {tap}, Remove any number of charge counters from Green Mana Battery: Add {G}, then add an additional {G} for each charge counter removed this way. ability = new DynamicManaAbility( Mana.GreenMana(1), - new IntPlusDynamicValue(1, new RemovedCountersForCostValue()), + new IntPlusDynamicValue(1, RemovedCountersForCostValue.instance), new TapSourceCost(), "Add {G}, then add {G} for each charge counter removed this way", true, new CountersSourceCount(CounterType.CHARGE)); diff --git a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java index f416760744..1ebed78a46 100644 --- a/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java +++ b/Mage.Sets/src/mage/cards/g/GrenzoHavocRaiser.java @@ -60,7 +60,7 @@ public final class GrenzoHavocRaiser extends CardImpl { Ability ability = new GrenzoHavocRaiserTriggeredAbility(effect); //or Exile the top card of that player's library. Until end of turn, you may cast that card and you may spend mana as though it were mana of any color to cast it. Mode mode = new Mode(); - mode.getEffects().add(new GrenzoHavocRaiserEffect()); + mode.addEffect(new GrenzoHavocRaiserEffect()); ability.addMode(mode); this.addAbility(ability); } @@ -148,7 +148,7 @@ class GrenzoHavocRaiserEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); - if (card != null) { + if (card != null && sourceObject != null) { // move card to exile controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); // Add effects only if the card has a spellAbility (e.g. not for lands). diff --git a/Mage.Sets/src/mage/cards/g/GridMonitor.java b/Mage.Sets/src/mage/cards/g/GridMonitor.java index f14efbff1a..5462f1b8f3 100644 --- a/Mage.Sets/src/mage/cards/g/GridMonitor.java +++ b/Mage.Sets/src/mage/cards/g/GridMonitor.java @@ -68,7 +68,7 @@ class GridMonitorEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == GameEvent.EventType.CAST_SPELL && event.getPlayerId().equals(source.getControllerId())) { MageObject object = game.getObject(event.getSourceId()); - if (object.isCreature()) { + if (object != null && object.isCreature()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/g/Gridlock.java b/Mage.Sets/src/mage/cards/g/Gridlock.java index a94c6e7848..23c6be94f6 100644 --- a/Mage.Sets/src/mage/cards/g/Gridlock.java +++ b/Mage.Sets/src/mage/cards/g/Gridlock.java @@ -1,9 +1,7 @@ package mage.cards.g; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -11,41 +9,40 @@ import mage.constants.CardType; import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class Gridlock extends CardImpl { - private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanents"); public Gridlock(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); // Tap X target nonland permanents. - this.getSpellAbility().addEffect(new TapTargetEffect()); - // Correct number of targets will be set in adjustTargets - this.getSpellAbility().addTarget(new TargetPermanent(0, 1,filter, false)); - + this.getSpellAbility().addEffect(new TapTargetEffect("X target nonland permanents")); + this.getSpellAbility().setTargetAdjuster(GridlockAdjuster.instance); } public Gridlock(final Gridlock card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numberToTap = ability.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().count(filter, ability.getSourceId(), ability.getControllerId(), game), numberToTap); - ability.addTarget(new TargetPermanent(numberToTap, filter)); - } - } - @Override public Gridlock copy() { return new Gridlock(this); } } + +enum GridlockAdjuster implements TargetAdjuster { + instance; + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanents"); + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(ability.getManaCostsToPay().getX(), filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GrimAffliction.java b/Mage.Sets/src/mage/cards/g/GrimAffliction.java index 50a9830d2a..38adaf2ac6 100644 --- a/Mage.Sets/src/mage/cards/g/GrimAffliction.java +++ b/Mage.Sets/src/mage/cards/g/GrimAffliction.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; @@ -10,19 +8,20 @@ import mage.constants.CardType; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class GrimAffliction extends CardImpl { public GrimAffliction(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); - - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Put a -1/-1 counter on target creature, then proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.M1M1.createInstance())); - this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy(", then")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } public GrimAffliction(final GrimAffliction card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java index 9a1c49c102..f6be8e6c03 100644 --- a/Mage.Sets/src/mage/cards/g/GrimDiscovery.java +++ b/Mage.Sets/src/mage/cards/g/GrimDiscovery.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -11,8 +9,9 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterLandCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class GrimDiscovery extends CardImpl { @@ -27,11 +26,11 @@ public final class GrimDiscovery extends CardImpl { this.getSpellAbility().getModes().setMaxModes(2); // Return target creature card from your graveyard to your hand; this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); // and/or return target land card from your graveyard to your hand. Mode mode1 = new Mode(); - mode1.getEffects().add(new ReturnToHandTargetEffect()); - mode1.getTargets().add(new TargetCardInYourGraveyard(filterLandCard)); + mode1.addEffect(new ReturnToHandTargetEffect()); + mode1.addTarget(new TargetCardInYourGraveyard(filterLandCard).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/g/GrimFeast.java b/Mage.Sets/src/mage/cards/g/GrimFeast.java index ea2bc8f21c..277773cde9 100644 --- a/Mage.Sets/src/mage/cards/g/GrimFeast.java +++ b/Mage.Sets/src/mage/cards/g/GrimFeast.java @@ -91,7 +91,7 @@ class GrimFeastEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanentOrLKIBattlefield(source.getFirstTarget()); + Permanent creature = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (creature == null) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GrimFlayer.java b/Mage.Sets/src/mage/cards/g/GrimFlayer.java index 90bda82138..de4d208c74 100644 --- a/Mage.Sets/src/mage/cards/g/GrimFlayer.java +++ b/Mage.Sets/src/mage/cards/g/GrimFlayer.java @@ -1,7 +1,7 @@ - package mage.cards.g; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,6 +11,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -21,13 +22,12 @@ import mage.constants.Zone; import mage.filter.FilterCard; /** - * * @author fireshoes */ public final class GrimFlayer extends CardImpl { public GrimFlayer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); this.power = new MageInt(2); @@ -47,7 +47,8 @@ public final class GrimFlayer extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostSourceEffect(2, 2, Duration.WhileOnBattlefield), DeliriumCondition.instance, - "Delirium — {this} gets +2/+2 as long as there are four or more card types among cards in your graveyard"))); + "Delirium — {this} gets +2/+2 as long as there are four or more card types among cards in your graveyard")) + .addHint(DeliriumHint.instance)); } public GrimFlayer(final GrimFlayer card) { diff --git a/Mage.Sets/src/mage/cards/g/GrimHaruspex.java b/Mage.Sets/src/mage/cards/g/GrimHaruspex.java index 858cdc62df..bf0c9d478b 100644 --- a/Mage.Sets/src/mage/cards/g/GrimHaruspex.java +++ b/Mage.Sets/src/mage/cards/g/GrimHaruspex.java @@ -28,8 +28,8 @@ public final class GrimHaruspex extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public GrimHaruspex(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrimInitiate.java b/Mage.Sets/src/mage/cards/g/GrimInitiate.java new file mode 100644 index 0000000000..ac59582d80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrimInitiate.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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 GrimInitiate extends CardImpl { + + public GrimInitiate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // When Grim Initiate dies, amass 1. + this.addAbility(new DiesTriggeredAbility(new AmassEffect(1))); + } + + private GrimInitiate(final GrimInitiate card) { + super(card); + } + + @Override + public GrimInitiate copy() { + return new GrimInitiate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrimPoppet.java b/Mage.Sets/src/mage/cards/g/GrimPoppet.java index 4d2318472a..2e4004752c 100644 --- a/Mage.Sets/src/mage/cards/g/GrimPoppet.java +++ b/Mage.Sets/src/mage/cards/g/GrimPoppet.java @@ -28,7 +28,7 @@ public final class GrimPoppet extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GrimPoppet(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrimReminder.java b/Mage.Sets/src/mage/cards/g/GrimReminder.java index 3b1e8bf30c..b2c5af2216 100644 --- a/Mage.Sets/src/mage/cards/g/GrimReminder.java +++ b/Mage.Sets/src/mage/cards/g/GrimReminder.java @@ -87,13 +87,13 @@ class GrimReminderEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_NON_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { Cards cardsToReveal = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cardsToReveal, game); String cardName = card.getName(); - GrimReminderWatcher watcher = (GrimReminderWatcher) game.getState().getWatchers().get(GrimReminderWatcher.class.getSimpleName()); + GrimReminderWatcher watcher = game.getState().getWatcher(GrimReminderWatcher.class); if (watcher != null) { for (UUID playerId : watcher.getPlayersCastSpell(cardName)) { Player player = game.getPlayer(playerId); @@ -116,7 +116,7 @@ class GrimReminderWatcher extends Watcher { private final Map> playersCastSpell = new HashMap<>(); public GrimReminderWatcher() { - super(GrimReminderWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public GrimReminderWatcher(final GrimReminderWatcher watcher) { @@ -132,7 +132,7 @@ class GrimReminderWatcher extends Watcher { MageObject spell = game.getObject(event.getTargetId()); UUID playerId = event.getPlayerId(); if (playerId != null && spell != null) { - playersCastSpell.putIfAbsent(spell.getName(), new HashSet()); + playersCastSpell.putIfAbsent(spell.getName(), new HashSet<>()); playersCastSpell.get(spell.getName()).add(playerId); } } @@ -144,7 +144,7 @@ class GrimReminderWatcher extends Watcher { } public Set getPlayersCastSpell(String spellName) { - return playersCastSpell.getOrDefault(spellName, new HashSet()); + return playersCastSpell.getOrDefault(spellName, new HashSet<>()); } @Override diff --git a/Mage.Sets/src/mage/cards/g/GrimReturn.java b/Mage.Sets/src/mage/cards/g/GrimReturn.java index 19e46ebcaa..9fb55552e8 100644 --- a/Mage.Sets/src/mage/cards/g/GrimReturn.java +++ b/Mage.Sets/src/mage/cards/g/GrimReturn.java @@ -1,9 +1,6 @@ package mage.cards.g; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.effects.Effect; @@ -17,10 +14,14 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardIdPredicate; import mage.game.Game; import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.watchers.common.CardsPutIntoGraveyardWatcher; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class GrimReturn extends CardImpl { @@ -28,13 +29,13 @@ public final class GrimReturn extends CardImpl { private static final String textFilter = "creature card in a graveyard that was put there from the battlefield this turn"; public GrimReturn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); // Choose target creature card in a graveyard that was put there from the battlefield this turn. Put that card onto the battlefield under your control. Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setText("Choose target creature card in a graveyard that was put there from the battlefield this turn. Put that card onto the battlefield under your control"); this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard(textFilter))); + this.getSpellAbility().setTargetAdjuster(GrimReturnAdjuster.instance); this.getSpellAbility().addWatcher(new CardsPutIntoGraveyardWatcher()); } @@ -46,22 +47,27 @@ public final class GrimReturn extends CardImpl { public GrimReturn copy() { return new GrimReturn(this); } +} + +enum GrimReturnAdjuster implements TargetAdjuster { + instance; + private static final String textFilter = "creature card in a graveyard that was put there from the battlefield this turn"; @Override public void adjustTargets(Ability ability, Game game) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); - if (watcher != null) { - FilterCard filter = new FilterCreatureCard(textFilter); - List uuidPredicates = new ArrayList<>(); - for (MageObjectReference mor : watcher.getCardsPutToGraveyardFromBattlefield()) { - if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { - uuidPredicates.add(new CardIdPredicate(mor.getSourceId())); - } - } - filter.add(Predicates.or(uuidPredicates)); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInGraveyard(filter)); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); + if (watcher == null) { + return; } - + FilterCard filter = new FilterCreatureCard(textFilter); + List uuidPredicates = new ArrayList<>(); + for (MageObjectReference mor : watcher.getCardsPutToGraveyardFromBattlefield()) { + if (mor.zoneCounterIsCurrent(game)) { + uuidPredicates.add(new CardIdPredicate(mor.getSourceId())); + } + } + filter.add(Predicates.or(uuidPredicates)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInGraveyard(filter)); } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GrimStrider.java b/Mage.Sets/src/mage/cards/g/GrimStrider.java index 5202715167..816259aad6 100644 --- a/Mage.Sets/src/mage/cards/g/GrimStrider.java +++ b/Mage.Sets/src/mage/cards/g/GrimStrider.java @@ -29,7 +29,7 @@ public final class GrimStrider extends CardImpl { this.toughness = new MageInt(6); // Grim Strider gets -1/-1 for each card in your hand. - DynamicValue count = new SignInversionDynamicValue(new CardsInControllerHandCount()); + DynamicValue count = new SignInversionDynamicValue(CardsInControllerHandCount.instance); Effect effect = new BoostSourceEffect(count, count, Duration.WhileOnBattlefield); effect.setText("{this} gets -1/-1 for each card in your hand"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java b/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java index 26548048da..3fd572c471 100644 --- a/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java +++ b/Mage.Sets/src/mage/cards/g/GrimlockDinobotLeader.java @@ -38,7 +38,7 @@ public final class GrimlockDinobotLeader extends CardImpl{ static { filter2.add(Predicates.not(new SubtypePredicate(SubType.DINOSAUR))); filter2.add(Predicates.not(new SubtypePredicate(SubType.VEHICLE))); - filter2.add(Predicates.or(new AbilityPredicate(TransformAbility.class), new TransformedPredicate())); + filter2.add(Predicates.or(new AbilityPredicate(TransformAbility.class), TransformedPredicate.instance)); } public GrimlockDinobotLeader(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrimoireThief.java b/Mage.Sets/src/mage/cards/g/GrimoireThief.java index 9205d05f15..fb6e18edde 100644 --- a/Mage.Sets/src/mage/cards/g/GrimoireThief.java +++ b/Mage.Sets/src/mage/cards/g/GrimoireThief.java @@ -172,7 +172,7 @@ class GrimoireThiefCounterspellEffect extends OneShotEffect { Cards cards = new CardsImpl(); MageObject sourceObject = game.getObject(source.getSourceId()); Set exileZones = (Set) game.getState().getValue(GrimoireThief.VALUE_PREFIX + source.getSourceId().toString()); - if (exileZones != null) { + if (exileZones != null && sourceObject != null) { for (ExileZone exileZone : game.getExile().getExileZones()) { if (!exileZone.isEmpty()) { cards.addAll(exileZone.getCards(game)); diff --git a/Mage.Sets/src/mage/cards/g/GrindDust.java b/Mage.Sets/src/mage/cards/g/GrindDust.java index 28941ffe2c..f6ca8ccfa3 100644 --- a/Mage.Sets/src/mage/cards/g/GrindDust.java +++ b/Mage.Sets/src/mage/cards/g/GrindDust.java @@ -34,7 +34,7 @@ public final class GrindDust extends SplitCard { // Dust // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Exile any number of target creatures that have -1/-1 counters on them. getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that have -1/-1 counters on them"); diff --git a/Mage.Sets/src/mage/cards/g/GrinningTotem.java b/Mage.Sets/src/mage/cards/g/GrinningTotem.java index b2fa96eebf..041dc39da5 100644 --- a/Mage.Sets/src/mage/cards/g/GrinningTotem.java +++ b/Mage.Sets/src/mage/cards/g/GrinningTotem.java @@ -20,7 +20,6 @@ import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.turn.Step; import mage.players.Player; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; @@ -79,14 +78,14 @@ class GrinningTotemSearchAndExileEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); Player targetOpponent = game.getPlayer(source.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (you != null && targetOpponent != null) { + if (you != null && targetOpponent != null && sourceObject != null) { if (targetOpponent.getLibrary().hasCards()) { TargetCardInLibrary targetCard = new TargetCardInLibrary(); - if (you.searchLibrary(targetCard, game, targetOpponent.getId())) { + if (you.searchLibrary(targetCard, source, game, targetOpponent.getId())) { Card card = targetOpponent.getLibrary().remove(targetCard.getFirstTarget(), game); if (card != null) { UUID exileZoneId = CardUtil.getCardExileZoneId(game, source); - you.moveCardToExileWithInfo(card, exileZoneId, sourceObject != null ? sourceObject.getIdName() : "", source.getSourceId(), game, Zone.LIBRARY, true); + you.moveCardToExileWithInfo(card, exileZoneId, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); ContinuousEffect effect = new GrinningTotemMayPlayEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/g/GripOfChaos.java b/Mage.Sets/src/mage/cards/g/GripOfChaos.java index 3cbd36bc98..479a74548d 100644 --- a/Mage.Sets/src/mage/cards/g/GripOfChaos.java +++ b/Mage.Sets/src/mage/cards/g/GripOfChaos.java @@ -126,7 +126,10 @@ class GripOfChaosEffect extends OneShotEffect { Mode mode = stackObject.getStackAbility().getModes().get(modeId); for (Target target : mode.getTargets()) { UUID oldTargetId = target.getFirstTarget(); - Set possibleTargets = target.possibleTargets(stackObject.getSourceId(), stackObject.getControllerId(), game); + Set possibleTargets = target.possibleTargets(stackObject.getId(), stackObject.getControllerId(), game); + if (possibleTargets.contains(stackObject.getId())) { // The stackObject can't target itself + possibleTargets.remove(stackObject.getId()); + } if (!possibleTargets.isEmpty()) { int i = 0; int rnd = RandomUtil.nextInt(possibleTargets.size()); diff --git a/Mage.Sets/src/mage/cards/g/GrixisCharm.java b/Mage.Sets/src/mage/cards/g/GrixisCharm.java index fc2783a453..98c5d8a1bb 100644 --- a/Mage.Sets/src/mage/cards/g/GrixisCharm.java +++ b/Mage.Sets/src/mage/cards/g/GrixisCharm.java @@ -28,12 +28,12 @@ public final class GrixisCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent()); // or target creature gets -4/-4 until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-4, -4, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or creatures you control get +2/+0 until end of turn. mode = new Mode(); - mode.getEffects().add(new BoostControlledEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + mode.addEffect(new BoostControlledEffect(2, 0, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/g/GrixisGrimblade.java b/Mage.Sets/src/mage/cards/g/GrixisGrimblade.java index 3a6d2b65f7..9f47971b9b 100644 --- a/Mage.Sets/src/mage/cards/g/GrixisGrimblade.java +++ b/Mage.Sets/src/mage/cards/g/GrixisGrimblade.java @@ -29,8 +29,8 @@ public final class GrixisGrimblade extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another multicolor permanent"); static { - filter.add(new MulticoloredPredicate()); - filter.add(new AnotherPredicate()); + filter.add(MulticoloredPredicate.instance); + filter.add(AnotherPredicate.instance); } public GrixisGrimblade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java index 543b5807b1..b1715bac1f 100644 --- a/Mage.Sets/src/mage/cards/g/GrizzledAngler.java +++ b/Mage.Sets/src/mage/cards/g/GrizzledAngler.java @@ -55,7 +55,7 @@ class GrizzledAnglerEffect extends OneShotEffect { private static final FilterCreatureCard filter = new FilterCreatureCard("a colorless creature card in your graveyard"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public GrizzledAnglerEffect() { diff --git a/Mage.Sets/src/mage/cards/g/Grollub.java b/Mage.Sets/src/mage/cards/g/Grollub.java new file mode 100644 index 0000000000..45071e13b9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Grollub.java @@ -0,0 +1,73 @@ +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DealtDamageToSourceTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class Grollub extends CardImpl { + + public Grollub(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever Grollub is dealt damage, each opponent gains that much life. + this.addAbility(new DealtDamageToSourceTriggeredAbility( + Zone.BATTLEFIELD, + new EachOpponentGainsLifeEffect(), false, false, true)); + + } + + public Grollub(final Grollub card) { + super(card); + } + + @Override + public Grollub copy() { + return new Grollub(this); + } +} + +class EachOpponentGainsLifeEffect extends OneShotEffect { + + public EachOpponentGainsLifeEffect() { + super(Outcome.Neutral); + this.staticText = "each opponent gains that much life"; + } + + public EachOpponentGainsLifeEffect(final EachOpponentGainsLifeEffect effect) { + super(effect); + } + + @Override + public EachOpponentGainsLifeEffect copy() { + return new EachOpponentGainsLifeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getOpponents(source.getControllerId()).stream().map((opponentId) -> game.getPlayer(opponentId)).filter((opponent) -> (opponent != null)).forEachOrdered((opponent) -> { + int amount = (Integer) getValue("damage"); + if (amount > 0) { + opponent.gainLife(amount, game, source); + } + }); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrotesqueDemise.java b/Mage.Sets/src/mage/cards/g/GrotesqueDemise.java new file mode 100644 index 0000000000..8abc7e0bcf --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrotesqueDemise.java @@ -0,0 +1,42 @@ +package mage.cards.g; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrotesqueDemise extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 3 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public GrotesqueDemise(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Exile target creature with power 3 or less. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private GrotesqueDemise(final GrotesqueDemise card) { + super(card); + } + + @Override + public GrotesqueDemise copy() { + return new GrotesqueDemise(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrothamaAllDevouring.java b/Mage.Sets/src/mage/cards/g/GrothamaAllDevouring.java index 27a39841c3..21997da89a 100644 --- a/Mage.Sets/src/mage/cards/g/GrothamaAllDevouring.java +++ b/Mage.Sets/src/mage/cards/g/GrothamaAllDevouring.java @@ -49,7 +49,7 @@ public final class GrothamaAllDevouring extends CardImpl { this.addAbility(new LeavesBattlefieldTriggeredAbility(new GrothamaAllDevouringDrawCardsEffect(), false), new GrothamaAllDevouringWatcher()); } - public GrothamaAllDevouring(final GrothamaAllDevouring card) { + private GrothamaAllDevouring(final GrothamaAllDevouring card) { super(card); } @@ -61,16 +61,16 @@ public final class GrothamaAllDevouring extends CardImpl { class GrothamaAllDevouringGainAbilityEffect extends GainAbilityAllEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); + private static final FilterCreaturePermanent otherCreatureFilter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + otherCreatureFilter.add(AnotherPredicate.instance); } GrothamaAllDevouringGainAbilityEffect() { super(new AttacksTriggeredAbility( new GrothamaAllDevouringFightEffect(null, null), true - ), Duration.WhileOnBattlefield, filter); + ), Duration.WhileOnBattlefield, otherCreatureFilter); this.staticText = "Other creatures have \"Whenever this creature attacks, you may have it fight {this}.\""; } @@ -148,7 +148,7 @@ class GrothamaAllDevouringDrawCardsEffect extends OneShotEffect { if (controller == null) { return false; } - GrothamaAllDevouringWatcher watcher = (GrothamaAllDevouringWatcher) game.getState().getWatchers().get(GrothamaAllDevouringWatcher.class.getSimpleName()); + GrothamaAllDevouringWatcher watcher = game.getState().getWatcher(GrothamaAllDevouringWatcher.class); if (watcher == null) { return false; } @@ -168,10 +168,10 @@ class GrothamaAllDevouringDrawCardsEffect extends OneShotEffect { class GrothamaAllDevouringWatcher extends Watcher { - Map> damageMap = new HashMap<>(); + private Map> damageMap = new HashMap<>(); GrothamaAllDevouringWatcher() { - super(GrothamaAllDevouringWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } GrothamaAllDevouringWatcher(final GrothamaAllDevouringWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java b/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java index 8f6d13c9a4..76bbe39782 100644 --- a/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java +++ b/Mage.Sets/src/mage/cards/g/GroveOfTheBurnwillows.java @@ -59,7 +59,9 @@ class GroveOfTheBurnwillowsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (UUID playerId : game.getOpponents(source.getControllerId())) { Player player = game.getPlayer(playerId); - player.gainLife(1, game, source); + if(player != null) { + player.gainLife(1, game, source); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java b/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java index f5ae5cbfd9..d7c445de70 100644 --- a/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java +++ b/Mage.Sets/src/mage/cards/g/GroveOfTheGuardian.java @@ -33,7 +33,7 @@ public final class GroveOfTheGuardian extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public GroveOfTheGuardian(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GrowthChamberGuardian.java b/Mage.Sets/src/mage/cards/g/GrowthChamberGuardian.java new file mode 100644 index 0000000000..07e23ab62a --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrowthChamberGuardian.java @@ -0,0 +1,53 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.OneOrMoreCountersAddedTriggeredAbility; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrowthChamberGuardian extends CardImpl { + + private static final FilterCard filter + = new FilterCard("a card named Growth-Chamber Guardian"); + + static { + filter.add(new NamePredicate("Growth-Chamber Guardian")); + } + + public GrowthChamberGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.CRAB); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}{G}: Adapt 2. + this.addAbility(new AdaptAbility(2, "{2}{G}")); + + // Whenever one or more +1/+1 counters are put on Growth-Chamber Guardian, you may search your library for a card named Growth-Chamber Guardian, reveal it, put it into your hand, then shuffle your library. + this.addAbility(new OneOrMoreCountersAddedTriggeredAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true)); + } + + private GrowthChamberGuardian(final GrowthChamberGuardian card) { + super(card); + } + + @Override + public GrowthChamberGuardian copy() { + return new GrowthChamberGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GrowthSpiral.java b/Mage.Sets/src/mage/cards/g/GrowthSpiral.java new file mode 100644 index 0000000000..1168e1cfa3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GrowthSpiral.java @@ -0,0 +1,33 @@ +package mage.cards.g; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GrowthSpiral extends CardImpl { + + public GrowthSpiral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}"); + + // Draw a card. You may put a land card from your hand onto the battlefield. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); + this.getSpellAbility().addEffect(new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A)); + } + + public GrowthSpiral(final GrowthSpiral card) { + super(card); + } + + @Override + public GrowthSpiral copy() { + return new GrowthSpiral(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/Grozoth.java b/Mage.Sets/src/mage/cards/g/Grozoth.java index e2d18a0432..b16f1a9844 100644 --- a/Mage.Sets/src/mage/cards/g/Grozoth.java +++ b/Mage.Sets/src/mage/cards/g/Grozoth.java @@ -88,7 +88,7 @@ class GrozothEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null && player != null && player.searchLibrary(target, game)) { + if (sourceCard != null && player != null && player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/g/GruesomeFate.java b/Mage.Sets/src/mage/cards/g/GruesomeFate.java index 4b85e2f8c6..77dcdc8adf 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeFate.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeFate.java @@ -8,6 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -21,12 +22,10 @@ public final class GruesomeFate extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); // Each opponent loses 1 life for each creature you control. - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - filter.add(new ControllerPredicate(TargetController.YOU)); - this.getSpellAbility().addEffect(new LoseLifeOpponentsEffect(new PermanentsOnBattlefieldCount(filter))); + this.getSpellAbility().addEffect(new LoseLifeOpponentsEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED))); } - public GruesomeFate(final GruesomeFate card) { + private GruesomeFate(final GruesomeFate card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java index 6f90713868..b2ca5e6751 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeMenagerie.java @@ -84,6 +84,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { Cards cards = new CardsImpl(); Target target; target = new TargetCardInYourGraveyard(filter1); + target.setNotTarget(true); if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { @@ -91,6 +92,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { } } target = new TargetCardInYourGraveyard(filter2); + target.setNotTarget(true); if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { @@ -98,6 +100,7 @@ class GruesomeMenagerieEffect extends OneShotEffect { } } target = new TargetCardInYourGraveyard(filter3); + target.setNotTarget(true); if (player.choose(outcome, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/g/GruesomeSlaughter.java b/Mage.Sets/src/mage/cards/g/GruesomeSlaughter.java index 9e7c23ffee..944d82dd9d 100644 --- a/Mage.Sets/src/mage/cards/g/GruesomeSlaughter.java +++ b/Mage.Sets/src/mage/cards/g/GruesomeSlaughter.java @@ -27,7 +27,7 @@ public final class GruesomeSlaughter extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creatures you control"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public GruesomeSlaughter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GruulBeastmaster.java b/Mage.Sets/src/mage/cards/g/GruulBeastmaster.java new file mode 100644 index 0000000000..c0e203c35b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GruulBeastmaster.java @@ -0,0 +1,64 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.SourcePermanentPowerCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GruulBeastmaster extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + private static final DynamicValue xValue = new SourcePermanentPowerCount(false); + + public GruulBeastmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Riot + this.addAbility(new RiotAbility()); + + // Whenever Gruul Beastmaster attacks, another target creature you control gets +X/+0 until end of turn, where X is Gruul Beastmaster's power. + Ability ability = new AttacksTriggeredAbility(new BoostTargetEffect( + xValue, StaticValue.getZeroValue(), Duration.EndOfTurn, true + ), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private GruulBeastmaster(final GruulBeastmaster card) { + super(card); + } + + @Override + public GruulBeastmaster copy() { + return new GruulBeastmaster(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruulCharm.java b/Mage.Sets/src/mage/cards/g/GruulCharm.java index 1619d04689..592a8760d6 100644 --- a/Mage.Sets/src/mage/cards/g/GruulCharm.java +++ b/Mage.Sets/src/mage/cards/g/GruulCharm.java @@ -43,12 +43,12 @@ public final class GruulCharm extends CardImpl { // or gain control of all permanents you own; Mode mode = new Mode(); - mode.getEffects().add(new GainControlAllEffect(Duration.EndOfGame, filter2)); + mode.addEffect(new GainControlAllEffect(Duration.EndOfGame, filter2)); this.getSpellAbility().addMode(mode); // or Gruul Charm deals 3 damage to each creature with flying. Mode mode2 = new Mode(); - mode2.getEffects().add(new DamageAllEffect(3, filter3)); + mode2.addEffect(new DamageAllEffect(3, filter3)); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/g/GruulLocket.java b/Mage.Sets/src/mage/cards/g/GruulLocket.java new file mode 100644 index 0000000000..465cbb52f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GruulLocket.java @@ -0,0 +1,45 @@ +package mage.cards.g; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class GruulLocket extends CardImpl { + + public GruulLocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add {R} or {G}. + this.addAbility(new RedManaAbility()); + this.addAbility(new GreenManaAbility()); + + // {R/G}{R/G}{R/G}{R/G}, {T}, Sacrifice Gruul Locket: Draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{R/G}{R/G}{R/G}{R/G}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public GruulLocket(final GruulLocket card) { + super(card); + } + + @Override + public GruulLocket copy() { + return new GruulLocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java b/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java new file mode 100644 index 0000000000..399e17078b --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GruulSpellbreaker.java @@ -0,0 +1,68 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.keyword.RiotAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GruulSpellbreaker extends CardImpl { + + public GruulSpellbreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Riot + this.addAbility(new RiotAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // As long as it's your turn, you and Gruul Spellbreaker have hexproof. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilityControllerEffect( + HexproofAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, "As long as it's your turn, you and" + ) + ); + ability.addEffect(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + HexproofAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, "{this} have hexproof." + )); + this.addAbility(ability); + } + + public GruulSpellbreaker(final GruulSpellbreaker card) { + super(card); + } + + @Override + public GruulSpellbreaker copy() { + return new GruulSpellbreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GruulWarChant.java b/Mage.Sets/src/mage/cards/g/GruulWarChant.java index ca508dd10c..d403a4a367 100644 --- a/Mage.Sets/src/mage/cards/g/GruulWarChant.java +++ b/Mage.Sets/src/mage/cards/g/GruulWarChant.java @@ -26,7 +26,7 @@ public final class GruulWarChant extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creatures you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public GruulWarChant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GuanYus1000LiMarch.java b/Mage.Sets/src/mage/cards/g/GuanYus1000LiMarch.java index 6a5e9d1f59..5d4d4adb66 100644 --- a/Mage.Sets/src/mage/cards/g/GuanYus1000LiMarch.java +++ b/Mage.Sets/src/mage/cards/g/GuanYus1000LiMarch.java @@ -18,7 +18,7 @@ public final class GuanYus1000LiMarch extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creatures"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public GuanYus1000LiMarch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GuardDogs.java b/Mage.Sets/src/mage/cards/g/GuardDogs.java new file mode 100644 index 0000000000..6101684b23 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuardDogs.java @@ -0,0 +1,100 @@ + +package mage.cards.g; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author L_J + */ +public final class GuardDogs extends CardImpl { + + public GuardDogs(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + this.subtype.add(SubType.HOUND); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {2}{W}, {T}: Choose a permanent you control. Prevent all combat damage target creature would deal this turn if it shares a color with that permanent. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GuardDogsEffect(), new ManaCostsImpl("{2}{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public GuardDogs(final GuardDogs card) { + super(card); + } + + @Override + public GuardDogs copy() { + return new GuardDogs(this); + } +} + +class GuardDogsEffect extends PreventionEffectImpl { + + private TargetControlledPermanent controlledTarget; + + public GuardDogsEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, true); + this.staticText = "Choose a permanent you control. Prevent all combat damage target creature would deal this turn if it shares a color with that permanent"; + } + + public GuardDogsEffect(final GuardDogsEffect effect) { + super(effect); + } + + + @Override + public void init(Ability source, Game game) { + this.controlledTarget = new TargetControlledPermanent(); + this.controlledTarget.setNotTarget(true); + this.controlledTarget.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + super.init(source, game); + } + + + @Override + public GuardDogsEffect copy() { + return new GuardDogsEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (!this.used && super.applies(event, source, game)) { + MageObject mageObject = game.getObject(event.getSourceId()); + if (mageObject != null + && controlledTarget.getFirstTarget() != null) { + Permanent permanent = game.getPermanentOrLKIBattlefield(controlledTarget.getFirstTarget()); + Permanent targetPermanent = game.getPermanentOrLKIBattlefield(this.getTargetPointer().getFirst(game, source)); + if (permanent != null + && targetPermanent != null + && this.getTargetPointer().getTargets(game, source).contains(event.getSourceId()) + && permanent.getColor(game).shares(targetPermanent.getColor(game))) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GuardianOfTheGuildpact.java b/Mage.Sets/src/mage/cards/g/GuardianOfTheGuildpact.java index e70bbd7cd5..d912fe3518 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianOfTheGuildpact.java +++ b/Mage.Sets/src/mage/cards/g/GuardianOfTheGuildpact.java @@ -20,7 +20,7 @@ public final class GuardianOfTheGuildpact extends CardImpl { private static final FilterCard filter = new FilterCard("monocolored"); static { - filter.add(new MonocoloredPredicate()); + filter.add(MonocoloredPredicate.instance); } public GuardianOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GuardianProject.java b/Mage.Sets/src/mage/cards/g/GuardianProject.java new file mode 100644 index 0000000000..dd4dcd85a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuardianProject.java @@ -0,0 +1,153 @@ +package mage.cards.g; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.other.OwnerIdPredicate; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuardianProject extends CardImpl { + + public GuardianProject(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // Whenever a nontoken creature enters the battlefield under your control, if that creature does not have the same name as another creature you control or a creature card in your graveyard, draw a card. + this.addAbility(new GuardianProjectTriggeredAbility()); + } + + private GuardianProject(final GuardianProject card) { + super(card); + } + + @Override + public GuardianProject copy() { + return new GuardianProject(this); + } +} + +class GuardianProjectTriggeredAbility extends EntersBattlefieldAllTriggeredAbility { + + public static final FilterPermanent filterNonTokenControlledCreature = new FilterControlledCreaturePermanent(); + + static { + filterNonTokenControlledCreature.add(Predicates.not(TokenPredicate.instance)); + } + + GuardianProjectTriggeredAbility() { + super(new GuardianProjectEffect(null), filterNonTokenControlledCreature); + } + + private GuardianProjectTriggeredAbility(final GuardianProjectTriggeredAbility ability) { + super(ability); + } + + @Override + public GuardianProjectTriggeredAbility copy() { + return new GuardianProjectTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); + if (!filter.match(permanent, sourceId, controllerId, game)) { + return false; + } + + if (checkCondition(permanent, controllerId, game)) { + this.getEffects().clear(); + this.addEffect(new GuardianProjectEffect(new MageObjectReference(permanent, game))); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever a nontoken creature enters the battlefield under your control, " + + "if that creature does not have the same name as another creature you control " + + "or a creature card in your graveyard, draw a card."; + } + + // This is needed as checkInterveningIfClause can't access trigger event information + static boolean checkCondition(Permanent permanent, UUID controllerId, Game game) { + Player player = game.getPlayer(controllerId); + if (player == null) { + return false; + } + if (!permanent.getName().isEmpty()) { + FilterCard filterCard = new FilterCard(); + filterCard.add(new NamePredicate(permanent.getName())); + filterCard.add(new OwnerIdPredicate(controllerId)); + if (player.getGraveyard().count(filterCard, game) > 0) { + return false; + } + } + FilterPermanent filterPermanent = new FilterCreaturePermanent(); + filterPermanent.add(new NamePredicate(permanent.getName())); + filterPermanent.add(Predicates.not(new CardIdPredicate(permanent.getId()))); + filterPermanent.add(new ControllerIdPredicate(controllerId)); + if (!game.getBattlefield().getActivePermanents(filterPermanent, controllerId, game).isEmpty()) { + return false; + } + return true; + } +} + +class GuardianProjectEffect extends OneShotEffect { + + private final MageObjectReference mor; + + GuardianProjectEffect(MageObjectReference mor) { + super(Outcome.Benefit); + this.mor = mor; + } + + private GuardianProjectEffect(final GuardianProjectEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public GuardianProjectEffect copy() { + return new GuardianProjectEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (GuardianProjectTriggeredAbility.checkCondition( + mor.getPermanentOrLKIBattlefield(game), source.getControllerId(), game) + ) { + player.drawCards(1, game); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java index b880b36706..944497e356 100644 --- a/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java +++ b/Mage.Sets/src/mage/cards/g/GuardianShieldBearer.java @@ -26,7 +26,7 @@ public final class GuardianShieldBearer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public GuardianShieldBearer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GuardiansMagemark.java b/Mage.Sets/src/mage/cards/g/GuardiansMagemark.java index e3f44eb59d..b16ee18b66 100644 --- a/Mage.Sets/src/mage/cards/g/GuardiansMagemark.java +++ b/Mage.Sets/src/mage/cards/g/GuardiansMagemark.java @@ -25,7 +25,7 @@ public final class GuardiansMagemark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control that are enchanted"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java b/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java index 792cbaca87..01d08304a5 100644 --- a/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java +++ b/Mage.Sets/src/mage/cards/g/GuardiansOfKoilos.java @@ -26,8 +26,8 @@ public final class GuardiansOfKoilos extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another historic permanent you control"); static { - filter.add(new AnotherPredicate()); - filter.add(new HistoricPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(HistoricPredicate.instance); } public GuardiansOfKoilos(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GuidingSpirit.java b/Mage.Sets/src/mage/cards/g/GuidingSpirit.java new file mode 100644 index 0000000000..657366f43f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuidingSpirit.java @@ -0,0 +1,83 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +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.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuidingSpirit extends CardImpl { + + public GuidingSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); + + this.subtype.add(SubType.ANGEL); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {tap}: If the top card of target player's graveyard is a creature card, put that card on top of that player's library. + Ability ability = new SimpleActivatedAbility(new GuidingSpiritEffect(), new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private GuidingSpirit(final GuidingSpirit card) { + super(card); + } + + @Override + public GuidingSpirit copy() { + return new GuidingSpirit(this); + } +} + +class GuidingSpiritEffect extends OneShotEffect { + + GuidingSpiritEffect() { + super(Outcome.Benefit); + staticText = "If the top card of target player's graveyard is a creature card, " + + "put that card on top of that player's library."; + } + + private GuidingSpiritEffect(final GuidingSpiritEffect effect) { + super(effect); + } + + @Override + public GuidingSpiritEffect copy() { + return new GuidingSpiritEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + if (player == null) { + return false; + } + Card card = player.getGraveyard().getTopCard(game); + if (card != null && card.isCreature()) { + player.putCardsOnTopOfLibrary(new CardsImpl(card), game, source, false); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GuildGlobe.java b/Mage.Sets/src/mage/cards/g/GuildGlobe.java new file mode 100644 index 0000000000..199b438439 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuildGlobe.java @@ -0,0 +1,116 @@ +package mage.cards.g; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GuildGlobe extends CardImpl { + + public GuildGlobe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // When Guild Globe enters the battlefield, draw a card. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1))); + + // {2}, {T}, Sacrifice Guild Globe: Add two mana of different colors. + Ability ability = new SimpleManaAbility( + Zone.BATTLEFIELD, new GuildGlobeManaEffect(), new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private GuildGlobe(final GuildGlobe card) { + super(card); + } + + @Override + public GuildGlobe copy() { + return new GuildGlobe(this); + } +} + +class GuildGlobeManaEffect extends ManaEffect { + + GuildGlobeManaEffect() { + super(); + staticText = "Add two mana of different colors."; + } + + private GuildGlobeManaEffect(final GuildGlobeManaEffect effect) { + super(effect); + } + + @Override + public Mana produceMana(boolean netMana, Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return null; + } + + ChoiceColor color1 = new ChoiceColor(true, "Choose color 1"); + if (!player.choose(outcome, color1, game) || color1.getColor() == null) { + return null; + } + + ChoiceColor color2 = new ChoiceColor(true, "Choose color 2"); + color2.removeColorFromChoices(color1.getChoice()); + if (!player.choose(outcome, color2, game) || color2.getColor() == null) { + return null; + } + + if (color1.getColor().equals(color2.getColor())) { + game.informPlayers("Player " + player.getName() + " is cheating with mana choices."); + return null; + } + + Mana mana = new Mana(); + mana.add(color1.getMana(1)); + mana.add(color2.getMana(1)); + return mana; + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + checkToFirePossibleEvents(getMana(game, source), game, source); + player.getManaPool().addMana(getMana(game, source), game, source); + return true; + } + return false; + } + + @Override + public List getNetMana(Game game, Ability source) { + ArrayList netMana = new ArrayList<>(); + netMana.add(new Mana(0, 0, 0, 0, 0, 0, 2, 0)); + return netMana; + } + + @Override + public GuildGlobeManaEffect copy() { + return new GuildGlobeManaEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GuildSummit.java b/Mage.Sets/src/mage/cards/g/GuildSummit.java index a6d18e5a06..5f66810b15 100644 --- a/Mage.Sets/src/mage/cards/g/GuildSummit.java +++ b/Mage.Sets/src/mage/cards/g/GuildSummit.java @@ -64,7 +64,7 @@ class GuildSummitEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.GATE)); } diff --git a/Mage.Sets/src/mage/cards/g/GuildmagesForum.java b/Mage.Sets/src/mage/cards/g/GuildmagesForum.java index 1a1792352e..f13e1700f9 100644 --- a/Mage.Sets/src/mage/cards/g/GuildmagesForum.java +++ b/Mage.Sets/src/mage/cards/g/GuildmagesForum.java @@ -58,7 +58,7 @@ class GuildmagesForumWatcher extends Watcher { private final Ability source; GuildmagesForumWatcher(Ability source) { - super("GuildmagesForumWatcher", WatcherScope.CARD); + super(WatcherScope.CARD); this.source = source; } @@ -88,11 +88,6 @@ class GuildmagesForumWatcher extends Watcher { } } - @Override - public void reset() { - super.reset(); - } - } class GuildmagesForumEntersBattlefieldEffect extends ReplacementEffectImpl { diff --git a/Mage.Sets/src/mage/cards/g/GuildpactInformant.java b/Mage.Sets/src/mage/cards/g/GuildpactInformant.java new file mode 100644 index 0000000000..47d833255f --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GuildpactInformant.java @@ -0,0 +1,44 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.FlyingAbility; +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 GuildpactInformant extends CardImpl { + + public GuildpactInformant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.FAERIE); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Guildpact Informant deals combat damage to a player or planeswalker, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new ProliferateEffect(), false + ).setOrPlaneswalker(true)); + } + + private GuildpactInformant(final GuildpactInformant card) { + super(card); + } + + @Override + public GuildpactInformant copy() { + return new GuildpactInformant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GuildscornWard.java b/Mage.Sets/src/mage/cards/g/GuildscornWard.java index d5b36ac2c5..926493ff83 100644 --- a/Mage.Sets/src/mage/cards/g/GuildscornWard.java +++ b/Mage.Sets/src/mage/cards/g/GuildscornWard.java @@ -24,7 +24,7 @@ public final class GuildscornWard extends CardImpl { private static final FilterObject filter = new FilterObject("multicolored"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public GuildscornWard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/g/GusthasScepter.java b/Mage.Sets/src/mage/cards/g/GusthasScepter.java new file mode 100644 index 0000000000..15ba334632 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GusthasScepter.java @@ -0,0 +1,285 @@ +package mage.cards.g; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.AsThoughEffectType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.game.ExileZone; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetCardInExile; +import mage.target.common.TargetCardInHand; + +/** + * + * @author LevelX2, jeffwadsworth & L_J + */ +public final class GusthasScepter extends CardImpl { + + public GusthasScepter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{0}"); + + // {T}: Exile a card from your hand face down. You may look at it for as long as it remains exiled. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new GusthasScepterExileEffect(), new TapSourceCost())); + + // {T}: Return a card you own exiled with Gustha’s Scepter to your hand. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new TapSourceCost()); + ability.addTarget(new TargetCardInGusthasScepterExile(this.getId())); + this.addAbility(ability); + + // When you lose control of Gustha’s Scepter, put all cards exiled with Gustha’s Scepter into their owner’s graveyard. + this.addAbility(new GusthasScepterLoseControlAbility()); + + } + + public GusthasScepter(final GusthasScepter card) { + super(card); + } + + @Override + public GusthasScepter copy() { + return new GusthasScepter(this); + } +} + +class GusthasScepterExileEffect extends OneShotEffect { + + public GusthasScepterExileEffect() { + super(Outcome.DrawCard); + staticText = "Exile a card from your hand face down. You may look at it for as long as it remains exiled"; + } + + public GusthasScepterExileEffect(final GusthasScepterExileEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Target target = new TargetCardInHand(new FilterCard("card to exile")); + if (controller.chooseTarget(outcome, target, source, game)) { + Card card = game.getCard(target.getFirstTarget()); + MageObject sourceObject = game.getObject(source.getSourceId()); + if (card != null && sourceObject != null) { + UUID exileId = source.getSourceId(); + if (card.moveToExile(exileId, + sourceObject.getIdName(), + source.getSourceId(), + game)) { + card.setFaceDown(true, game); + game.addEffect(new GusthasScepterLookAtCardEffect(card.getId()), source); + return true; + } + } + } + } + return false; + } + + @Override + public GusthasScepterExileEffect copy() { + return new GusthasScepterExileEffect(this); + } +} + +class TargetCardInGusthasScepterExile extends TargetCardInExile { + + public TargetCardInGusthasScepterExile(UUID cardId) { + super(1, 1, new FilterCard("card exiled with Gustha's Scepter"), null); + } + + public TargetCardInGusthasScepterExile(final TargetCardInGusthasScepterExile target) { + super(target); + } + + @Override + public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { + Set possibleTargets = new HashSet<>(); + Card sourceCard = game.getCard(sourceId); + if (sourceCard != null) { + UUID exileId = sourceId; + ExileZone exile = game.getExile().getExileZone(exileId); + if (exile != null && !exile.isEmpty()) { + possibleTargets.addAll(exile); + } + } + return possibleTargets; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + Card sourceCard = game.getCard(sourceId); + if (sourceCard != null) { + UUID exileId = sourceId; + ExileZone exile = game.getExile().getExileZone(exileId); + if (exile != null && !exile.isEmpty()) { + return true; + } + } + return false; + } + + @Override + public boolean canTarget(UUID id, Ability source, Game game) { + Card card = game.getCard(id); + if (card != null + && game.getState().getZone(card.getId()) == Zone.EXILED) { + ExileZone exile = null; + Card sourceCard = game.getCard(source.getSourceId()); + if (sourceCard != null) { + UUID exileId = source.getSourceId(); + exile = game.getExile().getExileZone(exileId); + } + if (exile != null + && exile.contains(id)) { + return filter.match(card, source.getControllerId(), game); + } + } + return false; + } + + @Override + public TargetCardInGusthasScepterExile copy() { + return new TargetCardInGusthasScepterExile(this); + } +} + +class GusthasScepterLookAtCardEffect extends AsThoughEffectImpl { + + private final UUID cardId; + + public GusthasScepterLookAtCardEffect(UUID cardId) { + super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); + this.cardId = cardId; + staticText = "You may look at it for as long as it remains exiled"; + } + + public GusthasScepterLookAtCardEffect(final GusthasScepterLookAtCardEffect effect) { + super(effect); + this.cardId = effect.cardId; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public GusthasScepterLookAtCardEffect copy() { + return new GusthasScepterLookAtCardEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (objectId.equals(cardId) && affectedControllerId.equals(source.getControllerId())) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject != null) { + UUID exileId = source.getSourceId(); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null + && exileZone.contains(cardId)) { + Player controller = game.getPlayer(source.getControllerId()); + Card card = game.getCard(cardId); + if (controller != null + && card != null + && game.getState().getZone(cardId) == Zone.EXILED) { + return true; + } + } else { + discard(); + } + } + } + return false; + } +} + +class GusthasScepterLoseControlAbility extends DelayedTriggeredAbility { + + public GusthasScepterLoseControlAbility() { + super(new GusthasScepterPutExiledCardsInOwnersGraveyard(), Duration.EndOfGame, false); + } + + public GusthasScepterLoseControlAbility(final GusthasScepterLoseControlAbility ability) { + super(ability); + } + + @Override + public GusthasScepterLoseControlAbility copy() { + return new GusthasScepterLoseControlAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LOST_CONTROL + || event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.LOST_CONTROL) { + return event.getPlayerId().equals(controllerId) + && event.getTargetId().equals(this.getSourceId()); + } else if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + if (event.getTargetId().equals(this.getSourceId())) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return (zEvent.getFromZone() == Zone.BATTLEFIELD); + } + } + return false; + } + + @Override + public String getRule() { + return "When you lose control of {this}, put all cards exiled with {this} into their owner's graveyard."; + } +} + +class GusthasScepterPutExiledCardsInOwnersGraveyard extends OneShotEffect { + + public GusthasScepterPutExiledCardsInOwnersGraveyard() { + super(Outcome.Neutral); + staticText = " put all cards exiled with {this} into their owner's graveyard"; + } + + public GusthasScepterPutExiledCardsInOwnersGraveyard(final GusthasScepterPutExiledCardsInOwnersGraveyard effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + UUID exileId = source.getSourceId(); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null) { + return controller.moveCards(exileZone.getCards(game), Zone.GRAVEYARD, source, game); + } + } + return false; + } + + @Override + public GusthasScepterPutExiledCardsInOwnersGraveyard copy() { + return new GusthasScepterPutExiledCardsInOwnersGraveyard(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GutterGrime.java b/Mage.Sets/src/mage/cards/g/GutterGrime.java index 28fa9508b3..beacf87f74 100644 --- a/Mage.Sets/src/mage/cards/g/GutterGrime.java +++ b/Mage.Sets/src/mage/cards/g/GutterGrime.java @@ -72,7 +72,7 @@ class GutterGrimeTriggeredAbility extends TriggeredAbilityImpl { if (card instanceof Permanent && !(card instanceof PermanentToken)) { Permanent permanent = (Permanent) card; ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD + if (zEvent.isDiesEvent() && permanent.isControlledBy(this.controllerId) && (targetId.equals(this.getSourceId()) || (permanent.isCreature() diff --git a/Mage.Sets/src/mage/cards/g/Gutterbones.java b/Mage.Sets/src/mage/cards/g/Gutterbones.java new file mode 100644 index 0000000000..fe3aefee96 --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/Gutterbones.java @@ -0,0 +1,69 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.watchers.common.PlayerLostLifeWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Gutterbones extends CardImpl { + + public Gutterbones(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.SKELETON); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Gutterbones enters the battlefield tapped. + this.addAbility(new EntersBattlefieldTappedAbility()); + + // {1}{B}: Return Gutterbones from your graveyard to your hand. Activate this ability only during your turn and only if an opponent lost life this turn. + this.addAbility(new ConditionalActivatedAbility( + Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), + new ManaCostsImpl("{1}{B}"), GutterbonesCondition.instance + )); + } + + private Gutterbones(final Gutterbones card) { + super(card); + } + + @Override + public Gutterbones copy() { + return new Gutterbones(this); + } +} + +enum GutterbonesCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (game.isActivePlayer(source.getControllerId())) { + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); + return watcher != null && watcher.getAllOppLifeLost(source.getControllerId(), game) > 0; + } + return false; + } + + @Override + public String toString() { + return "during your turn and only if an opponent lost life this turn"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java b/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java index db44fb6468..4368890ee0 100644 --- a/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java +++ b/Mage.Sets/src/mage/cards/g/GwafaHazidProfiteer.java @@ -1,7 +1,5 @@ - package mage.cards.g; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -21,20 +19,21 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class GwafaHazidProfiteer extends CardImpl { - + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); - + static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } public GwafaHazidProfiteer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); @@ -47,10 +46,10 @@ public final class GwafaHazidProfiteer extends CardImpl { ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); - + // Creatures with bribery counters on them can't attack or block. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GwafaHazidProfiteerEffect2())); - + } public GwafaHazidProfiteer(final GwafaHazidProfiteer card) { @@ -64,7 +63,7 @@ public final class GwafaHazidProfiteer extends CardImpl { } class GwafaHazidProfiteerEffect1 extends OneShotEffect { - + GwafaHazidProfiteerEffect1() { super(Outcome.Detriment); staticText = "Put a bribery counter on target creature you don't control. Its controller draws a card"; @@ -113,12 +112,12 @@ class GwafaHazidProfiteerEffect2 extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } - + @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/g/GyreEngineer.java b/Mage.Sets/src/mage/cards/g/GyreEngineer.java new file mode 100644 index 0000000000..94ee946a7d --- /dev/null +++ b/Mage.Sets/src/mage/cards/g/GyreEngineer.java @@ -0,0 +1,40 @@ +package mage.cards.g; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class GyreEngineer extends CardImpl { + + public GyreEngineer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {T}: Add {G}{U}. + this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new Mana(0, 1, 1, 0, 0, 0, 0, 0), new TapSourceCost())); + } + + private GyreEngineer(final GyreEngineer card) { + super(card); + } + + @Override + public GyreEngineer copy() { + return new GyreEngineer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java index b7224b4424..298ef39c25 100644 --- a/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java +++ b/Mage.Sets/src/mage/cards/g/GyrusWakerOfCorpses.java @@ -57,7 +57,7 @@ public final class GyrusWakerOfCorpses extends CardImpl { this.toughness = new MageInt(0); // Gyrus, Walker of Corpses enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it. - Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new ManaSpentToCastCount(), true); + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), ManaSpentToCastCount.instance, true); effect.setText("with a number of +1/+1 counters on it equal to the amount of mana spent to cast it"); this.addAbility(new EntersBattlefieldAbility(effect)); diff --git a/Mage.Sets/src/mage/cards/h/HaazdaOfficer.java b/Mage.Sets/src/mage/cards/h/HaazdaOfficer.java new file mode 100644 index 0000000000..1f65721304 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HaazdaOfficer.java @@ -0,0 +1,42 @@ +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.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HaazdaOfficer extends CardImpl { + + public HaazdaOfficer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Haazda Officer enters the battlefield, target creature you control gets +1/+1 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(1, 1)); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private HaazdaOfficer(final HaazdaOfficer card) { + super(card); + } + + @Override + public HaazdaOfficer copy() { + return new HaazdaOfficer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/Hackrobat.java b/Mage.Sets/src/mage/cards/h/Hackrobat.java new file mode 100644 index 0000000000..c2ad3229d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Hackrobat.java @@ -0,0 +1,58 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Hackrobat extends CardImpl { + + public Hackrobat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Spectacle {B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{B}{R}"))); + + // {B}: Hackrobat gains deathtouch until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), + Duration.EndOfTurn + ), new ColoredManaCost(ColoredManaSymbol.B) + )); + + // {R}: Hackrobat gets +2/-2 until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(2, -2, Duration.EndOfTurn), + new ColoredManaCost(ColoredManaSymbol.R) + )); + } + + private Hackrobat(final Hackrobat card) { + super(card); + } + + @Override + public Hackrobat copy() { + return new Hackrobat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java index ccbc85ed30..b7cd8bee85 100644 --- a/Mage.Sets/src/mage/cards/h/HagHedgeMage.java +++ b/Mage.Sets/src/mage/cards/h/HagHedgeMage.java @@ -26,8 +26,8 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class HagHedgeMage extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent(); - private final static FilterLandPermanent filter2 = new FilterLandPermanent(); + private static final FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterLandPermanent filter2 = new FilterLandPermanent(); static { filter.add(new SubtypePredicate(SubType.SWAMP)); diff --git a/Mage.Sets/src/mage/cards/h/HailOfArrows.java b/Mage.Sets/src/mage/cards/h/HailOfArrows.java index 6fadd26e16..90020cd2c2 100644 --- a/Mage.Sets/src/mage/cards/h/HailOfArrows.java +++ b/Mage.Sets/src/mage/cards/h/HailOfArrows.java @@ -20,8 +20,8 @@ public final class HailOfArrows extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}"); // Hail of Arrows deals X damage divided as you choose among any number of target attacking creatures. - this.getSpellAbility().addEffect(new DamageMultiEffect(new ManacostVariableValue())); - this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(new ManacostVariableValue(), new FilterAttackingCreature())); + this.getSpellAbility().addEffect(new DamageMultiEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(ManacostVariableValue.instance, new FilterAttackingCreature())); } public HailOfArrows(final HailOfArrows card) { diff --git a/Mage.Sets/src/mage/cards/h/HailStorm.java b/Mage.Sets/src/mage/cards/h/HailStorm.java index 53b8b32718..2d4a81f290 100644 --- a/Mage.Sets/src/mage/cards/h/HailStorm.java +++ b/Mage.Sets/src/mage/cards/h/HailStorm.java @@ -8,6 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -18,21 +19,16 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class HailStorm extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } - public HailStorm(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}{G}"); // Hail Storm deals 2 damage to each attacking creature and 1 damage to you and each creature you control. this.getSpellAbility().addEffect(new DamageAllEffect(2, new FilterAttackingCreature())); this.getSpellAbility().addEffect(new DamageControllerEffect(1).setText("and 1 damage to you ")); - this.getSpellAbility().addEffect(new DamageAllEffect(1, filter).setText("and each creature you control.")); + this.getSpellAbility().addEffect(new DamageAllEffect(1, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED).setText("and each creature you control.")); } - public HailStorm(final HailStorm card) { + private HailStorm(final HailStorm card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/h/HairStrungKoto.java b/Mage.Sets/src/mage/cards/h/HairStrungKoto.java index 9851b3a7a6..461113571c 100644 --- a/Mage.Sets/src/mage/cards/h/HairStrungKoto.java +++ b/Mage.Sets/src/mage/cards/h/HairStrungKoto.java @@ -52,7 +52,7 @@ public final class HairStrungKoto extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public HairStrungKoto (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/Halfdane.java b/Mage.Sets/src/mage/cards/h/Halfdane.java index 9c0972d611..d837c5c9b7 100644 --- a/Mage.Sets/src/mage/cards/h/Halfdane.java +++ b/Mage.Sets/src/mage/cards/h/Halfdane.java @@ -27,7 +27,7 @@ public final class Halfdane extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature other than Halfdane"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Halfdane(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HallOfGemstone.java b/Mage.Sets/src/mage/cards/h/HallOfGemstone.java index 0f825dd8ef..ea53e84b9c 100644 --- a/Mage.Sets/src/mage/cards/h/HallOfGemstone.java +++ b/Mage.Sets/src/mage/cards/h/HallOfGemstone.java @@ -70,7 +70,7 @@ class HallOfGemstoneEffect extends ReplacementEffectImpl { public void init(Ability source, Game game) { super.init(source, game); Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - MageObject mageObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent mageObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (player != null && mageObject != null) { ChoiceColor choice = new ChoiceColor(); if (!player.choose(outcome, choice, game)) { @@ -81,9 +81,7 @@ class HallOfGemstoneEffect extends ReplacementEffectImpl { game.informPlayers(mageObject.getLogName() + ": " + player.getLogName() + " has chosen " + choice.getChoice()); } game.getState().setValue(mageObject.getId() + "_color", choice.getColor()); - if (mageObject instanceof Permanent) { - ((Permanent) mageObject).addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); - } + mageObject.addInfo("chosen color", CardUtil.addToolTipMarkTags("Chosen color: " + choice.getChoice()), game); } } diff --git a/Mage.Sets/src/mage/cards/h/HallOfTheBanditLord.java b/Mage.Sets/src/mage/cards/h/HallOfTheBanditLord.java index 3ab7d488b2..067ac1c399 100644 --- a/Mage.Sets/src/mage/cards/h/HallOfTheBanditLord.java +++ b/Mage.Sets/src/mage/cards/h/HallOfTheBanditLord.java @@ -66,7 +66,7 @@ class HallOfTheBanditLordWatcher extends Watcher { private final List creatures = new ArrayList<>(); HallOfTheBanditLordWatcher(Ability source) { - super("HallOfTheBanditLordWatcher", WatcherScope.CARD); + super(WatcherScope.CARD); this.source = source; } diff --git a/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java b/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java index 90ccbbcf02..4665df8897 100644 --- a/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java +++ b/Mage.Sets/src/mage/cards/h/HallowedMoonlight.java @@ -83,7 +83,7 @@ class HallowedMoonlightEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { EntersTheBattlefieldEvent entersTheBattlefieldEvent = (EntersTheBattlefieldEvent) event; if (entersTheBattlefieldEvent.getTarget().isCreature()) { - CreatureWasCastWatcher watcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName()); + CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class); if (watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId())) { return true; } diff --git a/Mage.Sets/src/mage/cards/h/HallsOfMist.java b/Mage.Sets/src/mage/cards/h/HallsOfMist.java index 1896bc612a..a92f8621d6 100644 --- a/Mage.Sets/src/mage/cards/h/HallsOfMist.java +++ b/Mage.Sets/src/mage/cards/h/HallsOfMist.java @@ -1,8 +1,5 @@ - package mage.cards.h; -import java.util.Set; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -18,8 +15,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.AttackedLastTurnWatcher; +import java.util.Set; +import java.util.UUID; + /** - * * @author L_J */ public final class HallsOfMist extends CardImpl { @@ -61,14 +60,12 @@ class CantAttackIfAttackedLastTurnAllEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { - AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName()); + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + AttackedLastTurnWatcher watcher = game.getState().getWatcher(AttackedLastTurnWatcher.class); if (watcher != null) { Set attackingCreatures = watcher.getAttackedLastTurnCreatures(attacker.getControllerId()); MageObjectReference mor = new MageObjectReference(attacker, game); - if (attackingCreatures.contains(mor)) { - return false; - } + return !attackingCreatures.contains(mor); } return true; } diff --git a/Mage.Sets/src/mage/cards/h/HammerOfNazahn.java b/Mage.Sets/src/mage/cards/h/HammerOfNazahn.java index 686f5165e3..a973a49601 100644 --- a/Mage.Sets/src/mage/cards/h/HammerOfNazahn.java +++ b/Mage.Sets/src/mage/cards/h/HammerOfNazahn.java @@ -33,7 +33,7 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public final class HammerOfNazahn extends CardImpl { - private final static FilterEquipmentPermanent filter = new FilterEquipmentPermanent("{this} or another Equipment"); + private static final FilterEquipmentPermanent filter = new FilterEquipmentPermanent("{this} or another Equipment"); public HammerOfNazahn(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); diff --git a/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java b/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java index 4fcedfed34..c24bc7ef69 100644 --- a/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java +++ b/Mage.Sets/src/mage/cards/h/HammerheadCorvette.java @@ -28,7 +28,7 @@ public final class HammerheadCorvette extends CardImpl { static { filter.add(new SubtypePredicate(SubType.STARSHIP)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public HammerheadCorvette(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java b/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java index 9508f8e318..27a9248089 100644 --- a/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java +++ b/Mage.Sets/src/mage/cards/h/HanSoloScrumrat.java @@ -31,7 +31,7 @@ public final class HanSoloScrumrat extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HanSoloScrumrat(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HandOfJustice.java b/Mage.Sets/src/mage/cards/h/HandOfJustice.java index 31dceaa783..cb8f234b8a 100644 --- a/Mage.Sets/src/mage/cards/h/HandOfJustice.java +++ b/Mage.Sets/src/mage/cards/h/HandOfJustice.java @@ -31,7 +31,7 @@ public final class HandOfJustice extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public HandOfJustice(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HandToHand.java b/Mage.Sets/src/mage/cards/h/HandToHand.java index 0804212ce3..001df4208c 100644 --- a/Mage.Sets/src/mage/cards/h/HandToHand.java +++ b/Mage.Sets/src/mage/cards/h/HandToHand.java @@ -72,7 +72,7 @@ class HandToHandEffect extends ContinuousRuleModifyingEffectImpl { if (game.getPhase().getType() == TurnPhase.COMBAT) { MageObject object = game.getObject(event.getSourceId()); if (event.getType() == GameEvent.EventType.CAST_SPELL) { - if (object.isInstant()) { + if (object != null && object.isInstant()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/h/HarbingerOfTheHunt.java b/Mage.Sets/src/mage/cards/h/HarbingerOfTheHunt.java index 48abb7cf9a..59df8b1227 100644 --- a/Mage.Sets/src/mage/cards/h/HarbingerOfTheHunt.java +++ b/Mage.Sets/src/mage/cards/h/HarbingerOfTheHunt.java @@ -29,7 +29,7 @@ public final class HarbingerOfTheHunt extends CardImpl { static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); filter2.add(new AbilityPredicate(FlyingAbility.class)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public HarbingerOfTheHunt(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java b/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java index c2f3051f35..b88edd61b7 100644 --- a/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java +++ b/Mage.Sets/src/mage/cards/h/HarbingerOfTheTides.java @@ -24,10 +24,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class HarbingerOfTheTides extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature an opponent controls"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/h/HarborSerpent.java b/Mage.Sets/src/mage/cards/h/HarborSerpent.java index c91eead8d5..80fb23b637 100644 --- a/Mage.Sets/src/mage/cards/h/HarborSerpent.java +++ b/Mage.Sets/src/mage/cards/h/HarborSerpent.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -17,15 +15,16 @@ import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com * @author North */ public final class HarborSerpent extends CardImpl { public HarborSerpent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.SERPENT); this.power = new MageInt(5); @@ -67,13 +66,13 @@ class HarborSerpentEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()) && + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()) && game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) < 5; } } diff --git a/Mage.Sets/src/mage/cards/h/HardenedBerserker.java b/Mage.Sets/src/mage/cards/h/HardenedBerserker.java index 5793f80ee1..dbcc074bfb 100644 --- a/Mage.Sets/src/mage/cards/h/HardenedBerserker.java +++ b/Mage.Sets/src/mage/cards/h/HardenedBerserker.java @@ -62,7 +62,7 @@ class HardenedBerserkerSpellsCostReductionEffect extends CostModificationEffectI @Override public void init(Ability source, Game game) { super.init(source, game); - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); } @@ -76,7 +76,7 @@ class HardenedBerserkerSpellsCostReductionEffect extends CostModificationEffectI @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) > spellsCast) { discard(); // only one use diff --git a/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java b/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java index 6a7f17e1d4..33bcb4b7a7 100644 --- a/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java +++ b/Mage.Sets/src/mage/cards/h/HarmonyOfNature.java @@ -49,7 +49,7 @@ class HarmonyOfNatureEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public HarmonyOfNatureEffect() { diff --git a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java index 165ef34ebb..d7eb201d29 100644 --- a/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java +++ b/Mage.Sets/src/mage/cards/h/HarnessTheStorm.java @@ -61,7 +61,7 @@ class HarnessTheStormTriggeredAbility extends SpellCastControllerTriggeredAbilit @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - CastFromHandWatcher watcher = (CastFromHandWatcher) game.getState().getWatchers().get(CastFromHandWatcher.class.getSimpleName()); + CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); if (watcher != null && watcher.spellWasCastFromHand(event.getSourceId())) { Spell spell = game.getState().getStack().getSpell(event.getSourceId()); if (spell != null) { diff --git a/Mage.Sets/src/mage/cards/h/HarshDeceiver.java b/Mage.Sets/src/mage/cards/h/HarshDeceiver.java index 28b06ac89f..b078a5b6ef 100644 --- a/Mage.Sets/src/mage/cards/h/HarshDeceiver.java +++ b/Mage.Sets/src/mage/cards/h/HarshDeceiver.java @@ -77,10 +77,9 @@ class HarshDeceiverEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); if (card != null) { - cards.add(card); + Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game); if (card.isLand()) { new UntapSourceEffect().apply(game, source); diff --git a/Mage.Sets/src/mage/cards/h/HarshJustice.java b/Mage.Sets/src/mage/cards/h/HarshJustice.java index 6f763f7f43..b65e020c9b 100644 --- a/Mage.Sets/src/mage/cards/h/HarshJustice.java +++ b/Mage.Sets/src/mage/cards/h/HarshJustice.java @@ -63,7 +63,7 @@ class HarshJusticeTriggeredAbility extends DelayedTriggeredAbility { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public HarshJusticeTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/h/HarshMentor.java b/Mage.Sets/src/mage/cards/h/HarshMentor.java index 44fe93aa0a..7a01484d2a 100644 --- a/Mage.Sets/src/mage/cards/h/HarshMentor.java +++ b/Mage.Sets/src/mage/cards/h/HarshMentor.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.dynamicvalue.common.StaticValue; @@ -20,8 +18,9 @@ import mage.game.events.GameEvent.EventType; import mage.game.stack.StackAbility; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author spjspj */ public final class HarshMentor extends CardImpl { @@ -51,7 +50,7 @@ public final class HarshMentor extends CardImpl { class HarshMentorTriggeredAbility extends TriggeredAbilityImpl { HarshMentorTriggeredAbility() { - super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(2), false, "that player", true)); + super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(2), true, "that player", true)); } HarshMentorTriggeredAbility(final HarshMentorTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/h/HarshMercy.java b/Mage.Sets/src/mage/cards/h/HarshMercy.java index d511cacc88..748c75d06c 100644 --- a/Mage.Sets/src/mage/cards/h/HarshMercy.java +++ b/Mage.Sets/src/mage/cards/h/HarshMercy.java @@ -71,7 +71,7 @@ class HarshMercyEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (!player.choose(Outcome.DestroyPermanent, typeChoice, game)) { + if (player != null && !player.choose(Outcome.DestroyPermanent, typeChoice, game)) { continue PlayerIteration; } String chosenType = typeChoice.getChoice(); diff --git a/Mage.Sets/src/mage/cards/h/HarshSustenance.java b/Mage.Sets/src/mage/cards/h/HarshSustenance.java index 45fee5cd27..3f9cfd9000 100644 --- a/Mage.Sets/src/mage/cards/h/HarshSustenance.java +++ b/Mage.Sets/src/mage/cards/h/HarshSustenance.java @@ -1,36 +1,34 @@ - package mage.cards.h; -import java.util.UUID; -import mage.abilities.dynamicvalue.DynamicValue; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HarshSustenance extends CardImpl { public HarshSustenance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{W}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}{B}"); // Harsh Sustenance deals X damage to any target and you gain X life, where X is the number of creatures you control. - DynamicValue xValue = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); - Effect effect = new DamageTargetEffect(xValue); + Effect effect = new DamageTargetEffect(CreaturesYouControlCount.instance); effect.setText("{this} deals X damage to any target"); getSpellAbility().addEffect(effect); getSpellAbility().addTarget(new TargetAnyTarget()); - effect = new GainLifeEffect(xValue); + effect = new GainLifeEffect(CreaturesYouControlCount.instance); effect.setText("and you gain X life, where X is the number of creatures you control"); getSpellAbility().addEffect(effect); + getSpellAbility().addHint(CreaturesYouControlHint.instance); } public HarshSustenance(final HarshSustenance card) { diff --git a/Mage.Sets/src/mage/cards/h/HarvestPyre.java b/Mage.Sets/src/mage/cards/h/HarvestPyre.java index 859ec2c132..1c4f36caec 100644 --- a/Mage.Sets/src/mage/cards/h/HarvestPyre.java +++ b/Mage.Sets/src/mage/cards/h/HarvestPyre.java @@ -26,7 +26,7 @@ public final class HarvestPyre extends CardImpl { // Harvest Pyre deals X damage to target creature. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new DamageTargetEffect(new GetXValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance)); } public HarvestPyre(final HarvestPyre card) { diff --git a/Mage.Sets/src/mage/cards/h/HarvestSeason.java b/Mage.Sets/src/mage/cards/h/HarvestSeason.java index f0652a5db1..73e8e20a8f 100644 --- a/Mage.Sets/src/mage/cards/h/HarvestSeason.java +++ b/Mage.Sets/src/mage/cards/h/HarvestSeason.java @@ -13,7 +13,6 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; -import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.permanent.TappedPredicate; import mage.game.Game; @@ -50,7 +49,7 @@ class HarvestSeasonEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("tapped creature you control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } HarvestSeasonEffect() { @@ -73,7 +72,7 @@ class HarvestSeasonEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, new PermanentsOnBattlefieldCount(filter).calculate(game, source, this), StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/h/HarvesterOfSouls.java b/Mage.Sets/src/mage/cards/h/HarvesterOfSouls.java index 92bf69c0b2..487f203ec7 100644 --- a/Mage.Sets/src/mage/cards/h/HarvesterOfSouls.java +++ b/Mage.Sets/src/mage/cards/h/HarvesterOfSouls.java @@ -23,8 +23,8 @@ public final class HarvesterOfSouls extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); } public HarvesterOfSouls(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HatchingPlans.java b/Mage.Sets/src/mage/cards/h/HatchingPlans.java index 586b5f0db6..ce66f5a131 100644 --- a/Mage.Sets/src/mage/cards/h/HatchingPlans.java +++ b/Mage.Sets/src/mage/cards/h/HatchingPlans.java @@ -1,27 +1,26 @@ - - package mage.cards.h; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author Loki */ public final class HatchingPlans extends CardImpl { - public HatchingPlans (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + public HatchingPlans(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + // When Hatching Plans is put into a graveyard from the battlefield, draw three cards. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DrawCardSourceControllerEffect(3))); } - public HatchingPlans (final HatchingPlans card) { + public HatchingPlans(final HatchingPlans card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/h/Hatred.java b/Mage.Sets/src/mage/cards/h/Hatred.java index fd01727fbd..1d096e1cb6 100644 --- a/Mage.Sets/src/mage/cards/h/Hatred.java +++ b/Mage.Sets/src/mage/cards/h/Hatred.java @@ -26,7 +26,7 @@ public final class Hatred extends CardImpl { this.getSpellAbility().addCost(new PayVariableLifeCost(true)); // Target creature gets +X/+0 until end of turn. - DynamicValue xValue = new GetXValue(); + DynamicValue xValue = GetXValue.instance; this.getSpellAbility().addEffect(new BoostTargetEffect(xValue, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/h/HauntingEchoes.java b/Mage.Sets/src/mage/cards/h/HauntingEchoes.java index 35434189da..c3e2e60bb4 100644 --- a/Mage.Sets/src/mage/cards/h/HauntingEchoes.java +++ b/Mage.Sets/src/mage/cards/h/HauntingEchoes.java @@ -58,7 +58,7 @@ class HauntingEchoesEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - if (targetPlayer != null) { + if (targetPlayer != null && player != null) { for (Card card : targetPlayer.getGraveyard().getCards(game)) { if (!StaticFilters.FILTER_CARD_BASIC_LAND.match(card, game)) { card.moveToExile(null, "", source.getSourceId(), game); @@ -69,7 +69,7 @@ class HauntingEchoesEffect extends OneShotEffect { int count = targetPlayer.getLibrary().count(filterCard, game); TargetCardInLibrary target = new TargetCardInLibrary(count, count, filterCard); - player.searchLibrary(target, game, targetPlayer.getId()); + player.searchLibrary(target, source, game, targetPlayer.getId()); List targets = target.getTargets(); for (UUID cardId : targets) { Card libraryCard = game.getCard(cardId); diff --git a/Mage.Sets/src/mage/cards/h/HauntingHymn.java b/Mage.Sets/src/mage/cards/h/HauntingHymn.java index a4f09875fb..4ab5f76652 100644 --- a/Mage.Sets/src/mage/cards/h/HauntingHymn.java +++ b/Mage.Sets/src/mage/cards/h/HauntingHymn.java @@ -2,7 +2,7 @@ package mage.cards.h; import java.util.UUID; -import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.condition.common.AddendumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; import mage.cards.CardImpl; @@ -23,7 +23,7 @@ public final class HauntingHymn extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DiscardTargetEffect(4), new DiscardTargetEffect(2), - MyMainPhaseCondition.instance, + AddendumCondition.instance, "Target player discards two cards. If you cast this spell during your main phase, that player discards four cards instead")); this.getSpellAbility().addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/h/HauntingMisery.java b/Mage.Sets/src/mage/cards/h/HauntingMisery.java index aa4f0f4de2..a6a2d25197 100644 --- a/Mage.Sets/src/mage/cards/h/HauntingMisery.java +++ b/Mage.Sets/src/mage/cards/h/HauntingMisery.java @@ -24,7 +24,7 @@ public final class HauntingMisery extends CardImpl { this.getSpellAbility().addCost(new ExileXFromYourGraveCost(new FilterCreatureCard())); // Haunting Misery deals X damage to target player. this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); - this.getSpellAbility().addEffect(new DamageTargetEffect(new GetXValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(GetXValue.instance)); } public HauntingMisery(final HauntingMisery card) { diff --git a/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java b/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java index 8233253bd2..5259cb2d73 100644 --- a/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/h/HavenOfTheSpiritDragon.java @@ -99,7 +99,7 @@ class HavenOfTheSpiritManaCondition extends CreatureCastManaCondition { public boolean apply(Game game, Ability source, UUID manaProducer, Cost costToPay) { if (super.apply(game, source)) { MageObject object = game.getObject(source.getSourceId()); - if (object.hasSubtype(SubType.DRAGON, game) + if (object != null && object.hasSubtype(SubType.DRAGON, game) && object.isCreature()) { return true; } diff --git a/Mage.Sets/src/mage/cards/h/HavengulSkaab.java b/Mage.Sets/src/mage/cards/h/HavengulSkaab.java index 6953a576d7..7cd46a2b7c 100644 --- a/Mage.Sets/src/mage/cards/h/HavengulSkaab.java +++ b/Mage.Sets/src/mage/cards/h/HavengulSkaab.java @@ -50,7 +50,7 @@ class HavengulSkaabAbility extends TriggeredAbilityImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HavengulSkaabAbility() { diff --git a/Mage.Sets/src/mage/cards/h/Havoc.java b/Mage.Sets/src/mage/cards/h/Havoc.java index 36f247a89d..705d130dfd 100644 --- a/Mage.Sets/src/mage/cards/h/Havoc.java +++ b/Mage.Sets/src/mage/cards/h/Havoc.java @@ -20,7 +20,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class Havoc extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a white spell"); + private static final FilterSpell filter = new FilterSpell("a white spell"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); diff --git a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java index da4bc9daf0..9c6f84ce5b 100644 --- a/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java +++ b/Mage.Sets/src/mage/cards/h/HazoretsUndyingFury.java @@ -60,7 +60,7 @@ public final class HazoretsUndyingFury extends CardImpl { class HazoretsUndyingFuryEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("nonland cards with converted mana cost 5 or less"); + private static final FilterCard filter = new FilterCard("nonland cards with converted mana cost 5 or less"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); diff --git a/Mage.Sets/src/mage/cards/h/HazyHomunculus.java b/Mage.Sets/src/mage/cards/h/HazyHomunculus.java index 6a7ad243d6..67e4877ae4 100644 --- a/Mage.Sets/src/mage/cards/h/HazyHomunculus.java +++ b/Mage.Sets/src/mage/cards/h/HazyHomunculus.java @@ -27,7 +27,7 @@ public final class HazyHomunculus extends CardImpl { private static final FilterPermanent filter = new FilterLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public HazyHomunculus(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HeadstrongBrute.java b/Mage.Sets/src/mage/cards/h/HeadstrongBrute.java index e2cf1d102d..d04c6920f6 100644 --- a/Mage.Sets/src/mage/cards/h/HeadstrongBrute.java +++ b/Mage.Sets/src/mage/cards/h/HeadstrongBrute.java @@ -29,7 +29,7 @@ public final class HeadstrongBrute extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PIRATE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HeadstrongBrute(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HealingLeaves.java b/Mage.Sets/src/mage/cards/h/HealingLeaves.java index b651a40580..d13d4ae134 100644 --- a/Mage.Sets/src/mage/cards/h/HealingLeaves.java +++ b/Mage.Sets/src/mage/cards/h/HealingLeaves.java @@ -25,8 +25,8 @@ public final class HealingLeaves extends CardImpl { this.getSpellAbility().addEffect(new GainLifeTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayer()); Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HealingSalve.java b/Mage.Sets/src/mage/cards/h/HealingSalve.java index 8aaf06388e..d5dc9a4d84 100644 --- a/Mage.Sets/src/mage/cards/h/HealingSalve.java +++ b/Mage.Sets/src/mage/cards/h/HealingSalve.java @@ -27,8 +27,8 @@ public final class HealingSalve extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 3)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HeartWolf.java b/Mage.Sets/src/mage/cards/h/HeartWolf.java index 7409660149..3c88995a5b 100644 --- a/Mage.Sets/src/mage/cards/h/HeartWolf.java +++ b/Mage.Sets/src/mage/cards/h/HeartWolf.java @@ -33,7 +33,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class HeartWolf extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new SubtypePredicate(SubType.DWARF)); diff --git a/Mage.Sets/src/mage/cards/h/Heartfire.java b/Mage.Sets/src/mage/cards/h/Heartfire.java new file mode 100644 index 0000000000..c264508af1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Heartfire.java @@ -0,0 +1,50 @@ +package mage.cards.h; + +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Heartfire extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("a creature or planeswalker"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.CREATURE) + )); + } + + public Heartfire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // As an additional cost to cast this spell, sacrifice a creature or planeswalker. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + + // Heartfire deals 4 damage to any target. + this.getSpellAbility().addEffect(new DamageTargetEffect(4)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + } + + private Heartfire(final Heartfire card) { + super(card); + } + + @Override + public Heartfire copy() { + return new Heartfire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HearthCharm.java b/Mage.Sets/src/mage/cards/h/HearthCharm.java index f8c673bfaa..af7d92eea0 100644 --- a/Mage.Sets/src/mage/cards/h/HearthCharm.java +++ b/Mage.Sets/src/mage/cards/h/HearthCharm.java @@ -28,7 +28,7 @@ public final class HearthCharm extends CardImpl { private static final FilterCreaturePermanent filter3 = new FilterCreaturePermanent("creature with power 2 or less"); static { filter1.add(new CardTypePredicate(CardType.ARTIFACT)); - filter2.add(new AttackingPredicate()); + filter2.add(AttackingPredicate.instance); filter3.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); } @@ -40,12 +40,12 @@ public final class HearthCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter1)); // or attacking creatures get +1/+0 until end of turn Mode mode = new Mode(); - mode.getEffects().add(new BoostAllEffect(1, 0, Duration.EndOfTurn, filter2, false)); + mode.addEffect(new BoostAllEffect(1, 0, Duration.EndOfTurn, filter2, false)); this.getSpellAbility().addMode(mode); // or target creature with power 2 or less is unblockable this turn. mode = new Mode(); - mode.getEffects().add(new CantBeBlockedTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filter3)); + mode.addEffect(new CantBeBlockedTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(filter3)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/Heartmender.java b/Mage.Sets/src/mage/cards/h/Heartmender.java index 653ead86e2..7e1249294a 100644 --- a/Mage.Sets/src/mage/cards/h/Heartmender.java +++ b/Mage.Sets/src/mage/cards/h/Heartmender.java @@ -75,8 +75,8 @@ class HeartmenderEffect extends OneShotEffect { if (creature != null && creature.getCounters(game).getCount(counter.getName()) >= counter.getCount()) { creature.removeCounters(counter.getName(), counter.getCount(), game); - game.informPlayers(new StringBuilder("Removed ").append(counter.getCount()).append(' ').append(counter.getName()) - .append(" counter from ").append(creature.getName()).toString()); + game.informPlayers("Removed " + counter.getCount() + ' ' + counter.getName() + + " counter from " + creature.getName()); applied = true; } } diff --git a/Mage.Sets/src/mage/cards/h/HeartwarmingRedemption.java b/Mage.Sets/src/mage/cards/h/HeartwarmingRedemption.java new file mode 100644 index 0000000000..80dd636e95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeartwarmingRedemption.java @@ -0,0 +1,65 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HeartwarmingRedemption extends CardImpl { + + public HeartwarmingRedemption(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{W}"); + + // Discard all the cards in your hand, then draw that many cards plus one. You gain life equal to the number of cards in your hand. + this.getSpellAbility().addEffect(new HeartwarmingRedemptionEffect()); + } + + private HeartwarmingRedemption(final HeartwarmingRedemption card) { + super(card); + } + + @Override + public HeartwarmingRedemption copy() { + return new HeartwarmingRedemption(this); + } +} + +class HeartwarmingRedemptionEffect extends OneShotEffect { + + HeartwarmingRedemptionEffect() { + super(Outcome.Benefit); + staticText = "Discard all the cards in your hand, then draw that many cards plus one. " + + "You gain life equal to the number of cards in your hand."; + } + + private HeartwarmingRedemptionEffect(final HeartwarmingRedemptionEffect effect) { + super(effect); + } + + @Override + public HeartwarmingRedemptionEffect copy() { + return new HeartwarmingRedemptionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int discarded = player.discard(player.getHand().size(), false, source, game).size(); + player.drawCards(discarded + 1, game); + player.gainLife(player.getHand().size(), game, source); + return true; + } +} +// Good night, sweet prince :( \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/h/HeatRay.java b/Mage.Sets/src/mage/cards/h/HeatRay.java index d05f13cf84..571dcae460 100644 --- a/Mage.Sets/src/mage/cards/h/HeatRay.java +++ b/Mage.Sets/src/mage/cards/h/HeatRay.java @@ -19,7 +19,7 @@ public final class HeatRay extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{R}"); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/h/HeatStroke.java b/Mage.Sets/src/mage/cards/h/HeatStroke.java index 130b465e31..6d4a1982bc 100644 --- a/Mage.Sets/src/mage/cards/h/HeatStroke.java +++ b/Mage.Sets/src/mage/cards/h/HeatStroke.java @@ -66,8 +66,9 @@ class HeatStrokeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - BlockedThisTurnWatcher blockedWatcher = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); - WasBlockedThisTurnWatcher wasBlockedThisTurnWatcher = (WasBlockedThisTurnWatcher) game.getState().getWatchers().get(WasBlockedThisTurnWatcher.class.getSimpleName()); + BlockedThisTurnWatcher blockedWatcher = game.getState().getWatcher(BlockedThisTurnWatcher.class); + WasBlockedThisTurnWatcher wasBlockedThisTurnWatcher = game.getState().getWatcher(WasBlockedThisTurnWatcher.class); + Set inROI = new HashSet<>(game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)); boolean toRet = false; Set toDestroy = new HashSet<>(); diff --git a/Mage.Sets/src/mage/cards/h/HeavenEarth.java b/Mage.Sets/src/mage/cards/h/HeavenEarth.java index 86dfdf57f5..51dad694db 100644 --- a/Mage.Sets/src/mage/cards/h/HeavenEarth.java +++ b/Mage.Sets/src/mage/cards/h/HeavenEarth.java @@ -33,13 +33,13 @@ public final class HeavenEarth extends SplitCard { // Falling // Falling deals X damage to each creature with flying. - getLeftHalfCard().getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filterFlying)); + getLeftHalfCard().getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filterFlying)); // to // Earth // Earth deals X damage to each creature without flying. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); - getRightHalfCard().getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filterWithouFlying)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filterWithouFlying)); } public HeavenEarth(final HeavenEarth card) { diff --git a/Mage.Sets/src/mage/cards/h/HeavenlyQilin.java b/Mage.Sets/src/mage/cards/h/HeavenlyQilin.java index 853fb730b8..1f3f0386ce 100644 --- a/Mage.Sets/src/mage/cards/h/HeavenlyQilin.java +++ b/Mage.Sets/src/mage/cards/h/HeavenlyQilin.java @@ -24,7 +24,7 @@ public final class HeavenlyQilin extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HeavenlyQilin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/Hecatomb.java b/Mage.Sets/src/mage/cards/h/Hecatomb.java index 30efd3863b..ed9b77932c 100644 --- a/Mage.Sets/src/mage/cards/h/Hecatomb.java +++ b/Mage.Sets/src/mage/cards/h/Hecatomb.java @@ -32,7 +32,7 @@ public final class Hecatomb extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SWAMP)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Hecatomb(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HedronAlignment.java b/Mage.Sets/src/mage/cards/h/HedronAlignment.java index 6a8f16e8a3..15cc1101d3 100644 --- a/Mage.Sets/src/mage/cards/h/HedronAlignment.java +++ b/Mage.Sets/src/mage/cards/h/HedronAlignment.java @@ -54,8 +54,8 @@ public final class HedronAlignment extends CardImpl { class HedronAlignmentEffect extends OneShotEffect { - private final static FilterPermanent filterPermanent = new FilterPermanent(); - private final static FilterCard filterCard = new FilterCard(); + private static final FilterPermanent filterPermanent = new FilterPermanent(); + private static final FilterCard filterCard = new FilterCard(); static { filterPermanent.add(new NamePredicate("Hedron Alignment")); diff --git a/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java b/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java index 83b21abffc..9f575ad13e 100644 --- a/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/h/HeirOfTheWilds.java @@ -1,28 +1,28 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class HeirOfTheWilds extends CardImpl { public HeirOfTheWilds(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -33,10 +33,11 @@ public final class HeirOfTheWilds extends CardImpl { this.addAbility(DeathtouchAbility.getInstance()); // Ferocious - Whenever Heir of the Wilds attacks, if you control a creature with power 4 or greater, Heir of the Wilds gets +1/+1 until end of turn. Ability ability = new ConditionalInterveningIfTriggeredAbility( - new AttacksTriggeredAbility(new BoostSourceEffect(1,1,Duration.EndOfTurn), false), + new AttacksTriggeredAbility(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false), FerociousCondition.instance, "Ferocious — Whenever {this} attacks, if you control a creature with power 4 or greater, {this} gets +1/+1 until end of turn." ); + ability.addHint(FerociousHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HelixPinnacle.java b/Mage.Sets/src/mage/cards/h/HelixPinnacle.java index dc62fe1377..268d7f125b 100644 --- a/Mage.Sets/src/mage/cards/h/HelixPinnacle.java +++ b/Mage.Sets/src/mage/cards/h/HelixPinnacle.java @@ -34,7 +34,7 @@ public final class HelixPinnacle extends CardImpl { // {X}: Put X tower counters on Helix Pinnacle. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.TOWER.createInstance(), new ManacostVariableValue(), true), + new AddCountersSourceEffect(CounterType.TOWER.createInstance(), ManacostVariableValue.instance, true), new ManaCostsImpl("{X}"))); // At the beginning of your upkeep, if there are 100 or more tower counters on Helix Pinnacle, you win the game. diff --git a/Mage.Sets/src/mage/cards/h/Helldozer.java b/Mage.Sets/src/mage/cards/h/Helldozer.java index 71f73bb478..b1f5860b86 100644 --- a/Mage.Sets/src/mage/cards/h/Helldozer.java +++ b/Mage.Sets/src/mage/cards/h/Helldozer.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -33,7 +32,10 @@ public final class Helldozer extends CardImpl { this.toughness = new MageInt(5); // {B}{B}{B}, {tap}: Destroy target land. If that land was nonbasic, untap Helldozer. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HelldozerEffect(), new ManaCostsImpl("{B}{B}{B}")); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new HelldozerEffect(), + new ManaCostsImpl("{B}{B}{B}")); ability.addTarget(new TargetLandPermanent()); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -70,13 +72,13 @@ class HelldozerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent helldozer = game.getPermanent(source.getSourceId()); Permanent landTarget = game.getPermanent(source.getFirstTarget()); - if (landTarget == null) { - return false; - } - boolean wasNonBasic = !landTarget.isBasic(); - landTarget.destroy(id, game, false); - if (wasNonBasic && helldozer != null) { - return helldozer.untap(game); + if (landTarget != null) { + boolean wasNonBasic = !landTarget.isBasic(); + landTarget.destroy(source.getSourceId(), game, false); + if (wasNonBasic + && helldozer != null) { + return helldozer.untap(game); + } } return false; } diff --git a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java index 14f5824c2b..b28d4e75f6 100644 --- a/Mage.Sets/src/mage/cards/h/HellfireMongrel.java +++ b/Mage.Sets/src/mage/cards/h/HellfireMongrel.java @@ -3,19 +3,18 @@ package mage.cards.h; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; /** * @@ -34,7 +33,7 @@ public final class HellfireMongrel extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Hellfire Mongrel deals 2 damage to him or her. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), TargetController.OPPONENT, false, true), - new CardsInActivePlayersHandCondition(), + (Condition)new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, null, TargetController.ACTIVE), "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 2 damage to him or her." )); } @@ -48,12 +47,3 @@ public final class HellfireMongrel extends CardImpl { return new HellfireMongrel(this); } } - -class CardsInActivePlayersHandCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - return player != null && player.getHand().size() <= 2; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java b/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java index 3baa8970d3..902555e718 100644 --- a/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java +++ b/Mage.Sets/src/mage/cards/h/HellkiteWhelp.java @@ -25,7 +25,7 @@ public final class HellkiteWhelp extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public HellkiteWhelp(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HelmOfObedience.java b/Mage.Sets/src/mage/cards/h/HelmOfObedience.java index 4221686f3a..bad8be2592 100644 --- a/Mage.Sets/src/mage/cards/h/HelmOfObedience.java +++ b/Mage.Sets/src/mage/cards/h/HelmOfObedience.java @@ -49,7 +49,7 @@ public final class HelmOfObedience extends CardImpl { class HelmOfObedienceEffect extends OneShotEffect { - private static final ManacostVariableValue amount = new ManacostVariableValue(); + private static final ManacostVariableValue amount = ManacostVariableValue.instance; public HelmOfObedienceEffect() { super(Outcome.Detriment); diff --git a/Mage.Sets/src/mage/cards/h/HematiteTalisman.java b/Mage.Sets/src/mage/cards/h/HematiteTalisman.java index bde61499bd..9671fbf4f3 100644 --- a/Mage.Sets/src/mage/cards/h/HematiteTalisman.java +++ b/Mage.Sets/src/mage/cards/h/HematiteTalisman.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class HematiteTalisman extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a red spell"); + private static final FilterSpell filter = new FilterSpell("a red spell"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfDromoka.java b/Mage.Sets/src/mage/cards/h/HeraldOfDromoka.java index a5308cf18d..8e2fe33826 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfDromoka.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfDromoka.java @@ -28,7 +28,7 @@ public final class HeraldOfDromoka extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(new SubtypePredicate(SubType.WARRIOR)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HeraldOfDromoka(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfKozilek.java b/Mage.Sets/src/mage/cards/h/HeraldOfKozilek.java index c83c25f0aa..eb589cc5f7 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldOfKozilek.java +++ b/Mage.Sets/src/mage/cards/h/HeraldOfKozilek.java @@ -23,7 +23,7 @@ public final class HeraldOfKozilek extends CardImpl { private static final FilterCard filter = new FilterCard("Colorless spells"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public HeraldOfKozilek(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HeraldOfTheDreadhorde.java b/Mage.Sets/src/mage/cards/h/HeraldOfTheDreadhorde.java new file mode 100644 index 0000000000..ef383f86e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeraldOfTheDreadhorde.java @@ -0,0 +1,38 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.keyword.AmassEffect; +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 HeraldOfTheDreadhorde extends CardImpl { + + public HeraldOfTheDreadhorde(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Herald of the Dreadhorde dies, amass 2. + this.addAbility(new DiesTriggeredAbility(new AmassEffect(2))); + } + + private HeraldOfTheDreadhorde(final HeraldOfTheDreadhorde card) { + super(card); + } + + @Override + public HeraldOfTheDreadhorde copy() { + return new HeraldOfTheDreadhorde(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java index 1dfbd2b6ec..2224de65e8 100644 --- a/Mage.Sets/src/mage/cards/h/HeraldsHorn.java +++ b/Mage.Sets/src/mage/cards/h/HeraldsHorn.java @@ -13,10 +13,11 @@ import mage.abilities.effects.common.cost.SpellsCostReductionAllOfChosenSubtypeE import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; -import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; @@ -72,22 +73,25 @@ class HeraldsHornEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); // Look at the top card of your library. - if (controller.getLibrary().hasCards()) { + if (controller != null && controller.getLibrary().hasCards() && sourceObject != null) { Card card = controller.getLibrary().getFromTop(game); Cards cards = new CardsImpl(card); controller.lookAtCards(sourceObject.getIdName(), cards, game); // If it's a creature card of the chosen type, you may reveal it and put it into your hand. FilterCreatureCard filter = new FilterCreatureCard("creature card of the chosen type"); - filter.add(new ChosenSubtypePredicate()); + SubType subtype = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); + filter.add(new SubtypePredicate(subtype)); String message = "Reveal the top card of your library and put that card into your hand?"; if (card != null) { - if (filter.match(card, game) && controller.chooseUse(Outcome.Benefit, message, source, game)) { + if (filter.match(card, game) + && controller.chooseUse(Outcome.Benefit, message, source, game)) { controller.moveCards(card, Zone.HAND, source, game); controller.revealCards(sourceObject.getIdName() + " put into hand", cards, game); + return true; } } } - return true; + return false; } } diff --git a/Mage.Sets/src/mage/cards/h/HerdGnarr.java b/Mage.Sets/src/mage/cards/h/HerdGnarr.java index 4bc79e2edc..8fe90b62c8 100644 --- a/Mage.Sets/src/mage/cards/h/HerdGnarr.java +++ b/Mage.Sets/src/mage/cards/h/HerdGnarr.java @@ -23,7 +23,7 @@ public final class HerdGnarr extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HerdGnarr(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java b/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java index 3f41bf6ec2..b8970974f3 100644 --- a/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java +++ b/Mage.Sets/src/mage/cards/h/HerdchaserDragon.java @@ -27,7 +27,7 @@ public final class HerdchaserDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other Dragon creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/h/HeritageDruid.java b/Mage.Sets/src/mage/cards/h/HeritageDruid.java index 546f91ed03..01419463c6 100644 --- a/Mage.Sets/src/mage/cards/h/HeritageDruid.java +++ b/Mage.Sets/src/mage/cards/h/HeritageDruid.java @@ -25,7 +25,7 @@ public final class HeritageDruid extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Elves you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/h/HeroOfOxidRidge.java b/Mage.Sets/src/mage/cards/h/HeroOfOxidRidge.java index f3dc94dc89..ea6e7ce9ac 100644 --- a/Mage.Sets/src/mage/cards/h/HeroOfOxidRidge.java +++ b/Mage.Sets/src/mage/cards/h/HeroOfOxidRidge.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -11,19 +9,20 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class HeroOfOxidRidge extends CardImpl { public HeroOfOxidRidge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.KNIGHT); @@ -68,7 +67,7 @@ class HeroOfOxidRidgeEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/h/HeroOfPrecinctOne.java b/Mage.Sets/src/mage/cards/h/HeroOfPrecinctOne.java new file mode 100644 index 0000000000..925e811c20 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HeroOfPrecinctOne.java @@ -0,0 +1,42 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HeroOfPrecinctOne extends CardImpl { + + public HeroOfPrecinctOne(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a multicolored spell, create a 1/1 white Human creature token. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new HumanToken()), StaticFilters.FILTER_SPELL_A_MULTICOLORED, false + )); + } + + private HeroOfPrecinctOne(final HeroOfPrecinctOne card) { + super(card); + } + + @Override + public HeroOfPrecinctOne copy() { + return new HeroOfPrecinctOne(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HeroesPodium.java b/Mage.Sets/src/mage/cards/h/HeroesPodium.java index f3c89f0f54..0c77aab946 100644 --- a/Mage.Sets/src/mage/cards/h/HeroesPodium.java +++ b/Mage.Sets/src/mage/cards/h/HeroesPodium.java @@ -123,8 +123,7 @@ class HeroesPodiumEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, source.getManaCostsToPay().getX())); boolean legendaryIncluded = cards.count(filter, game) > 0; controller.lookAtCards(sourceObject.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/h/Heroism.java b/Mage.Sets/src/mage/cards/h/Heroism.java index ab66fa071d..85b7e04162 100644 --- a/Mage.Sets/src/mage/cards/h/Heroism.java +++ b/Mage.Sets/src/mage/cards/h/Heroism.java @@ -1,9 +1,6 @@ package mage.cards.h; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -28,8 +25,11 @@ import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author L_J */ public final class Heroism extends CardImpl { @@ -81,7 +81,6 @@ class HeroismEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - game.getPlayerList(); Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Player player = game.getPlayer(game.getActivePlayerId()); @@ -90,17 +89,19 @@ class HeroismEffect extends OneShotEffect { for (Permanent permanent : game.getState().getBattlefield().getAllActivePermanents(filter, game.getActivePlayerId(), game)) { cost.clearPaid(); String message = "Pay " + cost.getText() + "? If you don't, " + permanent.getLogName() + "'s combat damage will be prevented this turn."; - if (player != null && player.chooseUse(Outcome.Neutral, message, source, game)) { - if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { - game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName()); - continue; - } else { + if (player != null) { + if (player.chooseUse(Outcome.Neutral, message, source, game)) { + if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + game.informPlayers(player.getLogName() + " paid " + cost.getText() + " for " + permanent.getLogName()); + + } else { + game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName()); + permanentsToPrevent.add(permanent); + } + } else{ game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName()); permanentsToPrevent.add(permanent); } - } else { - game.informPlayers(player.getLogName() + " didn't pay " + cost.getText() + " for " + permanent.getLogName()); - permanentsToPrevent.add(permanent); } } diff --git a/Mage.Sets/src/mage/cards/h/HiddenPredators.java b/Mage.Sets/src/mage/cards/h/HiddenPredators.java new file mode 100644 index 0000000000..9ddb3d2003 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiddenPredators.java @@ -0,0 +1,134 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class HiddenPredators extends CardImpl { + + public HiddenPredators(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); + + // When an opponent controls a creature with power 4 or greater, if Hidden Predators is an enchantment, Hidden Predators becomes a 4/4 Beast creature. + this.addAbility(new HiddenPredatorsStateTriggeredAbility()); + } + + public HiddenPredators(final HiddenPredators card) { + super(card); + } + + @Override + public HiddenPredators copy() { + return new HiddenPredators(this); + } +} + +class HiddenPredatorsStateTriggeredAbility extends StateTriggeredAbility { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public HiddenPredatorsStateTriggeredAbility() { + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new HiddenPredatorsToken(), "", Duration.Custom, true, false)); + } + + public HiddenPredatorsStateTriggeredAbility(final HiddenPredatorsStateTriggeredAbility ability) { + super(ability); + } + + @Override + public HiddenPredatorsStateTriggeredAbility copy() { + return new HiddenPredatorsStateTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return !game.getBattlefield().getAllActivePermanents(filter, game).isEmpty(); + } + + @Override + public boolean checkInterveningIfClause(Game game) { + if (getSourcePermanentIfItStillExists(game) != null) { + return getSourcePermanentIfItStillExists(game).isEnchantment(); + } + return false; + } + + @Override + public boolean canTrigger(Game game) { + //20100716 - 603.8 + Boolean triggered = (Boolean) game.getState().getValue(getSourceId().toString() + "triggered"); + if (triggered == null) { + triggered = Boolean.FALSE; + } + return !triggered; + } + + @Override + public void trigger(Game game, UUID controllerId) { + //20100716 - 603.8 + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE); + super.trigger(game, controllerId); + } + + @Override + public boolean resolve(Game game) { + //20100716 - 603.8 + boolean result = super.resolve(game); + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + return result; + } + + @Override + public void counter(Game game) { + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + } + + @Override + public String getRule() { + return "When an opponent controls a creature with 4 or greater power, if {this} is an enchantment, " + super.getRule(); + } + +} + +class HiddenPredatorsToken extends TokenImpl { + + public HiddenPredatorsToken() { + super("Beast", "4/4 Beast creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.BEAST); + power = new MageInt(4); + toughness = new MageInt(4); + } + + public HiddenPredatorsToken(final HiddenPredatorsToken token) { + super(token); + } + + public HiddenPredatorsToken copy() { + return new HiddenPredatorsToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HiddenRetreat.java b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java new file mode 100644 index 0000000000..9569a11ab6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiddenRetreat.java @@ -0,0 +1,76 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.PutCardFromHandOnTopOfLibraryCost; +import mage.abilities.effects.PreventionEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author bunchOfDevs + */ +public class HiddenRetreat extends CardImpl { + + public HiddenRetreat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + //Put a card from your hand on top of your library: Prevent all damage that would be dealt by target instant or sorcery spell this turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HiddenRetreatEffect(), new PutCardFromHandOnTopOfLibraryCost()); + ability.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); + this.addAbility(ability); + + } + + public HiddenRetreat(final HiddenRetreat hiddenRetreat) { + super(hiddenRetreat); + } + + @Override + public HiddenRetreat copy() { + return new HiddenRetreat(this); + } +} + +class HiddenRetreatEffect extends PreventionEffectImpl { + + public HiddenRetreatEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); + this.staticText = "Prevent all damage that would be dealt by target instant or sorcery spell this turn."; + } + + public HiddenRetreatEffect(final HiddenRetreatEffect effect) { + super(effect); + } + + @Override + public HiddenRetreatEffect copy() { + return new HiddenRetreatEffect(this); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return (super.applies(event, source, game) + && event instanceof DamageEvent + && event.getAmount() > 0 + && game.getObject(source.getFirstTarget()) != null + && game.getObject(event.getSourceId()) != null + && game.getObject(source.getFirstTarget()).equals(game.getObject(event.getSourceId())) + && game.getObject(source.getFirstTarget()).isInstantOrSorcery()); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HiddenStag.java b/Mage.Sets/src/mage/cards/h/HiddenStag.java new file mode 100644 index 0000000000..6083cbaf30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HiddenStag.java @@ -0,0 +1,73 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.ControllerPlaysLandTriggeredAbility; +import mage.abilities.common.OpponentPlaysLandTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.effects.common.continuous.BecomesEnchantmentSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class HiddenStag extends CardImpl { + + public HiddenStag(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + // Whenever an opponent plays a land, if Hidden Stag is an enchantment, Hidden Stag becomes a 3/2 Elk Beast creature. + Effect effect = new BecomesCreatureSourceEffect(new ElkBeastToken(), "", Duration.WhileOnBattlefield, true, false); + TriggeredAbility ability = new OpponentPlaysLandTriggeredAbility(Zone.BATTLEFIELD, effect, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever an opponent plays a land, if Hidden Stag is an enchantment, Hidden Stag becomes a 3/2 Elk Beast creature.")); + + // Whenever you play a land, if Hidden Stag is a creature, Hidden Stag becomes an enchantment. + Effect effect2 = new BecomesEnchantmentSourceEffect(); + TriggeredAbility ability2 = new ControllerPlaysLandTriggeredAbility(Zone.BATTLEFIELD, effect2, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability2, new SourceMatchesFilterCondition(StaticFilters.FILTER_PERMANENT_CREATURE), + "Whenever you play a land, if Hidden Stag is a creature, Hidden Stag becomes an enchantment.")); + + } + + public HiddenStag(final HiddenStag card) { + super(card); + } + + @Override + public HiddenStag copy() { + return new HiddenStag(this); + } +} + +class ElkBeastToken extends TokenImpl { + + public ElkBeastToken() { + super("Elk Beast", "3/2 Elk Beast creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.ELK); + subtype.add(SubType.BEAST); + power = new MageInt(3); + toughness = new MageInt(2); + } + + public ElkBeastToken(final ElkBeastToken token) { + super(token); + } + + public ElkBeastToken copy() { + return new ElkBeastToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HiddenStrings.java b/Mage.Sets/src/mage/cards/h/HiddenStrings.java index 692e40bb32..f4f9fcc463 100644 --- a/Mage.Sets/src/mage/cards/h/HiddenStrings.java +++ b/Mage.Sets/src/mage/cards/h/HiddenStrings.java @@ -71,11 +71,11 @@ class HiddenStringsEffect extends OneShotEffect { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { if (permanent.isTapped()) { - if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append('?').toString(), source, game)) { + if (player.chooseUse(Outcome.Untap, "Untap " + permanent.getName() + '?', source, game)) { permanent.untap(game); } } else { - if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append('?').toString(), source, game)) { + if (player.chooseUse(Outcome.Tap, "Tap " + permanent.getName() + '?', source, game)) { permanent.tap(game); } } diff --git a/Mage.Sets/src/mage/cards/h/HideSeek.java b/Mage.Sets/src/mage/cards/h/HideSeek.java index c39fa9f144..89ccbd290b 100644 --- a/Mage.Sets/src/mage/cards/h/HideSeek.java +++ b/Mage.Sets/src/mage/cards/h/HideSeek.java @@ -74,7 +74,7 @@ class SeekEffect extends OneShotEffect { if (player != null && opponent != null) { if (opponent.getLibrary().hasCards()) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, game, opponent.getId())) { + if (player.searchLibrary(target, source, game, opponent.getId())) { UUID targetId = target.getFirstTarget(); Card card = opponent.getLibrary().remove(targetId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/h/HieromancersCage.java b/Mage.Sets/src/mage/cards/h/HieromancersCage.java index 500f420a1f..55c0c5366d 100644 --- a/Mage.Sets/src/mage/cards/h/HieromancersCage.java +++ b/Mage.Sets/src/mage/cards/h/HieromancersCage.java @@ -20,7 +20,7 @@ import mage.target.TargetPermanent; */ public final class HieromancersCage extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/h/HighAlert.java b/Mage.Sets/src/mage/cards/h/HighAlert.java new file mode 100644 index 0000000000..c846241de8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HighAlert.java @@ -0,0 +1,60 @@ +package mage.cards.h; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderAllEffect; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HighAlert extends CardImpl { + + public HighAlert(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}"); + + + // Each creature you control assigns combat damage equal to its toughness rather than its power. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new CombatDamageByToughnessEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, true + ) + )); + + // Creatures you control can attack as though they didn't have defender. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new CanAttackAsThoughItDidntHaveDefenderAllEffect( + Duration.WhileOnBattlefield, + StaticFilters.FILTER_CONTROLLED_CREATURES + ) + )); + + // {2}{W}{U}: Untap target creature. + Ability ability = new SimpleActivatedAbility(new UntapTargetEffect(), new ManaCostsImpl("{2}{W}{U}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private HighAlert(final HighAlert card) { + super(card); + } + + @Override + public HighAlert copy() { + return new HighAlert(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HighSentinelsOfArashin.java b/Mage.Sets/src/mage/cards/h/HighSentinelsOfArashin.java index 9f9da60260..44a2ab4072 100644 --- a/Mage.Sets/src/mage/cards/h/HighSentinelsOfArashin.java +++ b/Mage.Sets/src/mage/cards/h/HighSentinelsOfArashin.java @@ -32,7 +32,7 @@ public final class HighSentinelsOfArashin extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creature you control with a +1/+1 counter on it"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CounterPredicate(CounterType.P1P1)); } diff --git a/Mage.Sets/src/mage/cards/h/HintOfInsanity.java b/Mage.Sets/src/mage/cards/h/HintOfInsanity.java index 745149db0b..1d29958721 100644 --- a/Mage.Sets/src/mage/cards/h/HintOfInsanity.java +++ b/Mage.Sets/src/mage/cards/h/HintOfInsanity.java @@ -1,14 +1,8 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -16,9 +10,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class HintOfInsanity extends CardImpl { @@ -26,7 +22,7 @@ public final class HintOfInsanity extends CardImpl { public HintOfInsanity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); - // Target player reveals his or her hand. That player discards all nonland cards with the same name as another card in his or her hand. + // Target player reveals their hand. That player discards all nonland cards with the same name as another card in their hand. this.getSpellAbility().addEffect(new HintOfInsanityEffect()); this.getSpellAbility().addTarget(new TargetPlayer()); @@ -62,7 +58,6 @@ class HintOfInsanityEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { FilterCard filter = new FilterCard("card from your hand"); Player targetPlayer = game.getPlayer(source.getFirstTarget()); - String nameOfChosenCard; Card chosenCard; if (targetPlayer != null) { TargetCardInHand targetCard = new TargetCardInHand(filter); @@ -73,10 +68,8 @@ class HintOfInsanityEffect extends OneShotEffect { if (!cardsInHand.isEmpty() && targetPlayer.choose(Outcome.Discard, targetCard, source.getSourceId(), game)) { chosenCard = game.getCard(targetCard.getFirstTarget()); - nameOfChosenCard = chosenCard.getName(); for (Card card : cardsInHand.getCards(game)) { - if (card.getName().equals(nameOfChosenCard) - && !card.isLand()) { + if (CardUtil.haveSameNames(card, chosenCard) && !card.isLand()) { targetPlayer.discard(card, source, game); } } diff --git a/Mage.Sets/src/mage/cards/h/HiredGiant.java b/Mage.Sets/src/mage/cards/h/HiredGiant.java index c98dbcec74..ff87f5a7d4 100644 --- a/Mage.Sets/src/mage/cards/h/HiredGiant.java +++ b/Mage.Sets/src/mage/cards/h/HiredGiant.java @@ -72,7 +72,7 @@ class HiredGiantEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null && player.chooseUse(Outcome.PutCreatureInPlay, "Search your library for a land card and put it onto the battlefield?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard()); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card targetCard = player.getLibrary().getCard(target.getFirstTarget(), game); if (targetCard != null) { player.moveCards(targetCard, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java b/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java index a8452b08ec..c137a7de62 100644 --- a/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java +++ b/Mage.Sets/src/mage/cards/h/HisokaMinamoSensei.java @@ -75,13 +75,15 @@ class HisokaMinamoSenseiDiscardTargetCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); - for (UUID targetId: targets.get(0).getTargets()) { - card = player.getHand().get(targetId, game); - if (card == null) { - return false; - } - paid |= player.discard(card, null, game); + if(player != null) { + for (UUID targetId : targets.get(0).getTargets()) { + card = player.getHand().get(targetId, game); + if (card == null) { + return false; + } + paid |= player.discard(card, null, game); + } } } return paid; diff --git a/Mage.Sets/src/mage/cards/h/HisokasGuard.java b/Mage.Sets/src/mage/cards/h/HisokasGuard.java index c8479a741a..0d11887e2a 100644 --- a/Mage.Sets/src/mage/cards/h/HisokasGuard.java +++ b/Mage.Sets/src/mage/cards/h/HisokasGuard.java @@ -45,7 +45,7 @@ public final class HisokasGuard extends CardImpl { // {1}{U}, {T}: Target creature you control other than Hisoka's Guard has shroud for as long as Hisoka's Guard remains tapped. (It can't be the target of spells or abilities.) FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new HisokasGuardGainAbilityTargetEffect(), new ManaCostsImpl("{1}{U}")); ability.addCost(new TapSourceCost()); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); diff --git a/Mage.Sets/src/mage/cards/h/HiveMind.java b/Mage.Sets/src/mage/cards/h/HiveMind.java index 179a64073b..4dd5514662 100644 --- a/Mage.Sets/src/mage/cards/h/HiveMind.java +++ b/Mage.Sets/src/mage/cards/h/HiveMind.java @@ -68,7 +68,7 @@ class HiveMindTriggeredAbility extends TriggeredAbilityImpl { || spell.isSorcery())) { for (Effect effect : getEffects()) { if (effect instanceof HiveMindEffect) { - ((HiveMindEffect) effect).setTargetPointer(new FixedTarget(spell.getId())); + effect.setTargetPointer(new FixedTarget(spell.getId())); } } return true; diff --git a/Mage.Sets/src/mage/cards/h/Hivestone.java b/Mage.Sets/src/mage/cards/h/Hivestone.java index 8f8831507c..4617132c44 100644 --- a/Mage.Sets/src/mage/cards/h/Hivestone.java +++ b/Mage.Sets/src/mage/cards/h/Hivestone.java @@ -17,7 +17,7 @@ import mage.util.SubTypeList; */ public final class Hivestone extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/h/HivisOfTheScale.java b/Mage.Sets/src/mage/cards/h/HivisOfTheScale.java index 6e4b9110a0..70b093b32b 100644 --- a/Mage.Sets/src/mage/cards/h/HivisOfTheScale.java +++ b/Mage.Sets/src/mage/cards/h/HivisOfTheScale.java @@ -37,7 +37,7 @@ public final class HivisOfTheScale extends CardImpl { private static final String rule = "Gain control of target Dragon for as long as you control Hivis and Hivis remains tapped."; static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); filterDragon.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/h/HoardingDragon.java b/Mage.Sets/src/mage/cards/h/HoardingDragon.java index 1d1e2ae51e..a5a5b394b6 100644 --- a/Mage.Sets/src/mage/cards/h/HoardingDragon.java +++ b/Mage.Sets/src/mage/cards/h/HoardingDragon.java @@ -79,7 +79,7 @@ class HoardingDragonEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterArtifactCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/h/HoldTheGates.java b/Mage.Sets/src/mage/cards/h/HoldTheGates.java index 583c79e1b3..4efa8b303a 100644 --- a/Mage.Sets/src/mage/cards/h/HoldTheGates.java +++ b/Mage.Sets/src/mage/cards/h/HoldTheGates.java @@ -1,46 +1,37 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.GateYouControlCount; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.hint.common.GateYouControlHint; 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 mage.constants.Zone; -import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; -import mage.filter.common.FilterControlledPermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class HoldTheGates extends CardImpl { - private static final FilterPermanent filter = new FilterControlledPermanent(); - - static { - filter.add(new SubtypePredicate(SubType.GATE)); - } - public HoldTheGates(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); // Creatures you control get +0/+1 for each Gate you control and have vigilance. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, - new BoostControlledEffect(new StaticValue(0),new PermanentsOnBattlefieldCount(filter), Duration.WhileOnBattlefield)); + new BoostControlledEffect(new StaticValue(0), GateYouControlCount.instance, Duration.WhileOnBattlefield)); ability.addEffect(new GainAbilityControlledEffect(VigilanceAbility.getInstance(), Duration.WhileOnBattlefield, new FilterControlledCreaturePermanent("Creatures")) .setText("Creatures you control get +0/+1 for each Gate you control and have vigilance")); + ability.addHint(GateYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HoldoutSettlement.java b/Mage.Sets/src/mage/cards/h/HoldoutSettlement.java index 89f2c60b91..cbf0f1ea91 100644 --- a/Mage.Sets/src/mage/cards/h/HoldoutSettlement.java +++ b/Mage.Sets/src/mage/cards/h/HoldoutSettlement.java @@ -23,7 +23,7 @@ public final class HoldoutSettlement extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public HoldoutSettlement(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HollowOne.java b/Mage.Sets/src/mage/cards/h/HollowOne.java index 6796e8ad3b..495f14dd6f 100644 --- a/Mage.Sets/src/mage/cards/h/HollowOne.java +++ b/Mage.Sets/src/mage/cards/h/HollowOne.java @@ -66,7 +66,7 @@ class HollowOneReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - CardsCycledOrDiscardedThisTurnWatcher watcher = (CardsCycledOrDiscardedThisTurnWatcher) game.getState().getWatchers().get(CardsCycledOrDiscardedThisTurnWatcher.class.getSimpleName()); + CardsCycledOrDiscardedThisTurnWatcher watcher = game.getState().getWatcher(CardsCycledOrDiscardedThisTurnWatcher.class); if (watcher != null) { CardUtil.reduceCost(abilityToModify, watcher.getNumberOfCardsCycledOrDiscardedThisTurn(source.getControllerId()) * 2); return true; diff --git a/Mage.Sets/src/mage/cards/h/HollowTrees.java b/Mage.Sets/src/mage/cards/h/HollowTrees.java index 8213814aa0..9922ba6e36 100644 --- a/Mage.Sets/src/mage/cards/h/HollowTrees.java +++ b/Mage.Sets/src/mage/cards/h/HollowTrees.java @@ -44,7 +44,7 @@ public final class HollowTrees extends CardImpl { // {tap}, Remove any number of storage counters from Hollow Trees: Add {G} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.GreenMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {G} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/h/HollowWarrior.java b/Mage.Sets/src/mage/cards/h/HollowWarrior.java index d6a60e3112..66164064af 100644 --- a/Mage.Sets/src/mage/cards/h/HollowWarrior.java +++ b/Mage.Sets/src/mage/cards/h/HollowWarrior.java @@ -55,9 +55,9 @@ class HollowWarriorCostToAttackBlockEffect extends PayCostToAttackBlockEffectImp private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control not declared as an attacking or blocking creature"); static { - filter.add(Predicates.not(new AttackingPredicate())); - filter.add(Predicates.not(new BlockingPredicate())); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(AttackingPredicate.instance)); + filter.add(Predicates.not(BlockingPredicate.instance)); + filter.add(Predicates.not(TappedPredicate.instance)); } HollowWarriorCostToAttackBlockEffect() { diff --git a/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java b/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java index 887bd3203e..d278fc3e99 100644 --- a/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java +++ b/Mage.Sets/src/mage/cards/h/HollowbornBarghest.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -11,6 +10,7 @@ import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -23,6 +23,7 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; /** * @@ -33,7 +34,7 @@ public final class HollowbornBarghest extends CardImpl { private static final String rule = "At the beginning of your upkeep, if you have no cards in hand, each opponent loses 2 life."; public HollowbornBarghest(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); this.subtype.add(SubType.DEMON); this.subtype.add(SubType.HOUND); @@ -42,8 +43,14 @@ public final class HollowbornBarghest extends CardImpl { // At the beginning of your upkeep, if you have no cards in hand, each opponent loses 2 life. Condition condition = new CardsInHandCondition(ComparisonType.EQUAL_TO, 0); - TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(new HollowbornBarghestEffect(), TargetController.YOU, false); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, rule)); + TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility( + new HollowbornBarghestEffect(), + TargetController.YOU, + false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + ability, + condition, + rule)); // At the beginning of each opponent's upkeep, if that player has no cards in hand, he or she loses 2 life. this.addAbility(new HollowbornBarghestTriggeredAbility()); @@ -62,7 +69,7 @@ public final class HollowbornBarghest extends CardImpl { class HollowbornBarghestEffect extends OneShotEffect { public HollowbornBarghestEffect() { - super(Outcome.Damage); + super(Outcome.Benefit); staticText = "Each opponent loses 2 life"; } @@ -73,7 +80,10 @@ class HollowbornBarghestEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { - game.getPlayer(opponentId).loseLife(2, game, false); + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + game.getPlayer(opponentId).loseLife(2, game, false); + } } return true; } @@ -88,7 +98,7 @@ class HollowbornBarghestEffect extends OneShotEffect { class HollowbornBarghestTriggeredAbility extends TriggeredAbilityImpl { public HollowbornBarghestTriggeredAbility() { - super(Zone.BATTLEFIELD, null); + super(Zone.BATTLEFIELD, new LoseLifeTargetEffect(2)); } public HollowbornBarghestTriggeredAbility(final HollowbornBarghestTriggeredAbility ability) { @@ -102,17 +112,17 @@ class HollowbornBarghestTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.UPKEEP_STEP_PRE; + return event.getType() == EventType.UPKEEP_STEP_PRE + && game.getOpponents(controllerId).contains(event.getPlayerId()); } @Override public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - Player opponent = game.getPlayer(event.getPlayerId()); - if (opponent != null && opponent.getHand().isEmpty()) { - opponent.loseLife(2, game, false); - return true; - } + Player opponent = game.getPlayer(event.getPlayerId()); + if (opponent != null + && opponent.getHand().isEmpty()) { + this.getEffects().get(0).setTargetPointer(new FixedTarget(opponent.getId())); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/h/HomicidalBrute.java b/Mage.Sets/src/mage/cards/h/HomicidalBrute.java index 2575371fa1..cfd0e44201 100644 --- a/Mage.Sets/src/mage/cards/h/HomicidalBrute.java +++ b/Mage.Sets/src/mage/cards/h/HomicidalBrute.java @@ -10,6 +10,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.WatcherScope; import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; @@ -73,7 +74,7 @@ class HomicidalBruteTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(this.controllerId)) { - Watcher watcher = game.getState().getWatchers().get("HomicidalBruteWatcher", sourceId); + Watcher watcher = game.getState().getWatcher(HomicidalBruteWatcher.class, sourceId); if (watcher == null || !watcher.conditionMet()) { return true; } @@ -87,3 +88,5 @@ class HomicidalBruteTriggeredAbility extends TriggeredAbilityImpl { } } + + diff --git a/Mage.Sets/src/mage/cards/h/HomicidalBruteWatcher.java b/Mage.Sets/src/mage/cards/h/HomicidalBruteWatcher.java new file mode 100644 index 0000000000..944a748140 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HomicidalBruteWatcher.java @@ -0,0 +1,32 @@ +package mage.cards.h; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.Watcher; + +public class HomicidalBruteWatcher extends Watcher { + + public HomicidalBruteWatcher() { + super(WatcherScope.CARD); + } + + public HomicidalBruteWatcher(final HomicidalBruteWatcher watcher) { + super(watcher); + } + + @Override + public HomicidalBruteWatcher copy() { + return new HomicidalBruteWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (condition) { + return; + } + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED && event.getSourceId().equals(sourceId)) { + condition = true; + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/h/HomingLightning.java b/Mage.Sets/src/mage/cards/h/HomingLightning.java index db04b8b8ac..9e73c445f2 100644 --- a/Mage.Sets/src/mage/cards/h/HomingLightning.java +++ b/Mage.Sets/src/mage/cards/h/HomingLightning.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -14,15 +12,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class HomingLightning extends CardImpl { public HomingLightning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{R}"); // Homing Lightning deals 4 damage to target creature and each other creature with the same name as that creature. @@ -58,7 +58,7 @@ class HomingLightningEffect extends OneShotEffect { return false; } FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java b/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java index 153452b993..008c3899ef 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfCleansingFire.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class HondenOfCleansingFire extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); static { filter.add(new SubtypePredicate(SubType.SHRINE)); diff --git a/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java b/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java index cb15e6262a..e543cfea2c 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfInfiniteRage.java @@ -24,7 +24,7 @@ import java.util.UUID; */ public final class HondenOfInfiniteRage extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); static { filter.add(new SubtypePredicate(SubType.SHRINE)); diff --git a/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java b/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java index 9fb8e848a7..82dd9e4721 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfLifesWeb.java @@ -22,7 +22,7 @@ import java.util.UUID; */ public final class HondenOfLifesWeb extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); static { filter.add(new SubtypePredicate(SubType.SHRINE)); diff --git a/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java b/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java index 57a394f638..74f72e34c9 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfNightsReach.java @@ -23,7 +23,7 @@ import java.util.UUID; */ public final class HondenOfNightsReach extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); static { filter.add(new SubtypePredicate(SubType.SHRINE)); diff --git a/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java b/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java index 97f4974fd4..d4954be5bb 100644 --- a/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java +++ b/Mage.Sets/src/mage/cards/h/HondenOfSeeingWinds.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class HondenOfSeeingWinds extends CardImpl { - final static FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); + static final FilterControlledPermanent filter = new FilterControlledPermanent("Shrine"); static { filter.add(new SubtypePredicate(SubType.SHRINE)); diff --git a/Mage.Sets/src/mage/cards/h/HonorTheGodPharaoh.java b/Mage.Sets/src/mage/cards/h/HonorTheGodPharaoh.java new file mode 100644 index 0000000000..654318e1ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HonorTheGodPharaoh.java @@ -0,0 +1,35 @@ +package mage.cards.h; + +import java.util.UUID; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * @author TheElk801 + */ +public final class HonorTheGodPharaoh extends CardImpl { + + public HonorTheGodPharaoh(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // As an additional cost to cast this spell, discard a card. + this.getSpellAbility().addCost(new DiscardCardCost(false)); + + // Draw two cards. Amass 1. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).setText("draw two cards")); + this.getSpellAbility().addEffect(new AmassEffect(1)); + } + + private HonorTheGodPharaoh(final HonorTheGodPharaoh card) { + super(card); + } + + @Override + public HonorTheGodPharaoh copy() { + return new HonorTheGodPharaoh(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HonorWornShaku.java b/Mage.Sets/src/mage/cards/h/HonorWornShaku.java index bcd3f9aca5..b47eb2533a 100644 --- a/Mage.Sets/src/mage/cards/h/HonorWornShaku.java +++ b/Mage.Sets/src/mage/cards/h/HonorWornShaku.java @@ -27,7 +27,7 @@ public final class HonorWornShaku extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped legendary permanent"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SupertypePredicate(SuperType.LEGENDARY)); } diff --git a/Mage.Sets/src/mage/cards/h/HoodedAssassin.java b/Mage.Sets/src/mage/cards/h/HoodedAssassin.java index b36e831fdd..45b6f8dc6c 100644 --- a/Mage.Sets/src/mage/cards/h/HoodedAssassin.java +++ b/Mage.Sets/src/mage/cards/h/HoodedAssassin.java @@ -41,8 +41,8 @@ public final class HoodedAssassin extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); // * Destroy target creature that was dealt damage this turn. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(filter)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HoodedHorror.java b/Mage.Sets/src/mage/cards/h/HoodedHorror.java index fdf79b4f14..fff5d7ee07 100644 --- a/Mage.Sets/src/mage/cards/h/HoodedHorror.java +++ b/Mage.Sets/src/mage/cards/h/HoodedHorror.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleEvasionAbility; @@ -9,28 +7,29 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HoodedHorror extends CardImpl { public HoodedHorror(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(4); this.toughness = new MageInt(4); // Hooded Horror can't be blocked as long as defending player controls the most creatures or is tied for the most. - this.addAbility(new SimpleEvasionAbility(new HoodedHorrorCantBeBlockedEffect())); + this.addAbility(new SimpleEvasionAbility(new HoodedHorrorCantBeBlockedEffect())); } public HoodedHorror(final HoodedHorror card) { @@ -45,7 +44,7 @@ public final class HoodedHorror extends CardImpl { class HoodedHorrorCantBeBlockedEffect extends RestrictionEffect { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); public HoodedHorrorCantBeBlockedEffect() { super(Duration.WhileOnBattlefield); @@ -58,28 +57,23 @@ class HoodedHorrorCantBeBlockedEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId()) && permanent.isAttacking()) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()) && permanent.isAttacking(); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int maxCreatures = 0; UUID playerIdWithMax = null; for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { int creatures = game.getBattlefield().countAll(filter, playerId, game); - if (creatures > maxCreatures || (creatures == maxCreatures && playerId.equals(blocker.getControllerId())) ) { + if (creatures > maxCreatures || (creatures == maxCreatures && playerId.equals(blocker.getControllerId()))) { maxCreatures = creatures; playerIdWithMax = playerId; } } - if (playerIdWithMax != null && playerIdWithMax.equals(blocker.getControllerId())) { - return false; - } + return playerIdWithMax == null || !playerIdWithMax.equals(blocker.getControllerId()); } return true; } diff --git a/Mage.Sets/src/mage/cards/h/HopeCharm.java b/Mage.Sets/src/mage/cards/h/HopeCharm.java index 484bf6c34d..7dc8185e84 100644 --- a/Mage.Sets/src/mage/cards/h/HopeCharm.java +++ b/Mage.Sets/src/mage/cards/h/HopeCharm.java @@ -38,13 +38,13 @@ public final class HopeCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target player gains 2 life Mode mode = new Mode(); - mode.getEffects().add(new GainLifeTargetEffect(2)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new GainLifeTargetEffect(2)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); // or destroy target Aura. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java index 5df2aeefb8..c20236e8c1 100644 --- a/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java +++ b/Mage.Sets/src/mage/cards/h/HopeOfGhirapur.java @@ -1,10 +1,8 @@ package mage.cards.h; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; + import mage.MageInt; import mage.MageObject; import mage.MageObjectReference; @@ -128,7 +126,7 @@ class HopeOfGhirapurPlayerLostLifePredicate implements ObjectSourcePlayerPredica if (targetPlayer == null) { return false; } - HopeOfGhirapurCombatDamageWatcher watcher = (HopeOfGhirapurCombatDamageWatcher) game.getState().getWatchers().get(HopeOfGhirapurCombatDamageWatcher.class.getSimpleName()); + HopeOfGhirapurCombatDamageWatcher watcher = game.getState().getWatcher(HopeOfGhirapurCombatDamageWatcher.class); if (watcher != null) { return watcher.playerGotCombatDamage(input.getSourceId(), input.getObject().getId(), game); } @@ -138,10 +136,10 @@ class HopeOfGhirapurPlayerLostLifePredicate implements ObjectSourcePlayerPredica class HopeOfGhirapurCombatDamageWatcher extends Watcher { - private final HashMap> combatDamagedPlayers = new HashMap<>(); + private final Map> combatDamagedPlayers = new HashMap<>(); public HopeOfGhirapurCombatDamageWatcher() { - super(HopeOfGhirapurCombatDamageWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public HopeOfGhirapurCombatDamageWatcher(final HopeOfGhirapurCombatDamageWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/h/HordeAmbusher.java b/Mage.Sets/src/mage/cards/h/HordeAmbusher.java index 2f33326dbc..74e88895dc 100644 --- a/Mage.Sets/src/mage/cards/h/HordeAmbusher.java +++ b/Mage.Sets/src/mage/cards/h/HordeAmbusher.java @@ -28,7 +28,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class HordeAmbusher extends CardImpl { - private final static FilterCard filter = new FilterCard("a red card in your hand"); + private static final FilterCard filter = new FilterCard("a red card in your hand"); static { filter.add(new ColorPredicate(ObjectColor.RED)); } diff --git a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java index a1f81ada04..c532a8636e 100644 --- a/Mage.Sets/src/mage/cards/h/HordeOfNotions.java +++ b/Mage.Sets/src/mage/cards/h/HordeOfNotions.java @@ -27,7 +27,7 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class HordeOfNotions extends CardImpl { - private final static FilterCard filter = new FilterCard("Elemental card from your graveyard"); + private static final FilterCard filter = new FilterCard("Elemental card from your graveyard"); static { filter.add(new SubtypePredicate(SubType.ELEMENTAL)); diff --git a/Mage.Sets/src/mage/cards/h/HornOfPlenty.java b/Mage.Sets/src/mage/cards/h/HornOfPlenty.java index a890e48177..0854b5f70c 100644 --- a/Mage.Sets/src/mage/cards/h/HornOfPlenty.java +++ b/Mage.Sets/src/mage/cards/h/HornOfPlenty.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -9,7 +8,6 @@ import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.DrawCardTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -29,7 +27,7 @@ import mage.target.targetpointer.FixedTarget; public final class HornOfPlenty extends CardImpl { public HornOfPlenty(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // Whenever a player casts a spell, he or she may pay {1}. If that player does, he or she draws a card at the beginning of the next end step. this.addAbility(new SpellCastAllTriggeredAbility(new HornOfPlentyEffect(), new FilterSpell("a spell"), false, SetTargetPointer.PLAYER)); @@ -70,10 +68,10 @@ class HornOfPlentyEffect extends OneShotEffect { if (cost.pay(source, game, source.getSourceId(), caster.getId(), false, null)) { Effect effect = new DrawCardTargetEffect(1); effect.setTargetPointer(new FixedTarget(caster.getId())); - return new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY)).apply(game, source); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect, TargetController.ANY), source); + return true; } } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/h/HostageTaker.java b/Mage.Sets/src/mage/cards/h/HostageTaker.java index 9a5c0a2969..fd60803464 100644 --- a/Mage.Sets/src/mage/cards/h/HostageTaker.java +++ b/Mage.Sets/src/mage/cards/h/HostageTaker.java @@ -1,4 +1,3 @@ - package mage.cards.h; import java.util.UUID; @@ -38,10 +37,10 @@ import mage.util.CardUtil; */ public final class HostageTaker extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("another target artifact or creature"); + private static final FilterPermanent filter = new FilterPermanent("another target artifact or creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE))); @@ -174,16 +173,15 @@ class HostageTakerSpendAnyManaEffect extends AsThoughEffectImpl implements AsTho @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else { if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted diff --git a/Mage.Sets/src/mage/cards/h/HotheadedGiant.java b/Mage.Sets/src/mage/cards/h/HotheadedGiant.java index 10100831b6..e475b41aad 100644 --- a/Mage.Sets/src/mage/cards/h/HotheadedGiant.java +++ b/Mage.Sets/src/mage/cards/h/HotheadedGiant.java @@ -62,7 +62,7 @@ class CastRedSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - HotHeadedGiantWatcher watcher = (HotHeadedGiantWatcher) game.getState().getWatchers().get(HotHeadedGiantWatcher.class.getSimpleName(), source.getControllerId()); + HotHeadedGiantWatcher watcher = game.getState().getWatcher(HotHeadedGiantWatcher.class, source.getControllerId()); if (watcher != null) { return watcher.conditionMet(); } @@ -81,7 +81,7 @@ class HotHeadedGiantWatcher extends Watcher { private UUID cardId; public HotHeadedGiantWatcher(UUID cardId) { - super(HotHeadedGiantWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); this.cardId = cardId; } diff --git a/Mage.Sets/src/mage/cards/h/HoundOfTheFarbogs.java b/Mage.Sets/src/mage/cards/h/HoundOfTheFarbogs.java index 27be329e5d..9206adf00f 100644 --- a/Mage.Sets/src/mage/cards/h/HoundOfTheFarbogs.java +++ b/Mage.Sets/src/mage/cards/h/HoundOfTheFarbogs.java @@ -1,13 +1,14 @@ - package mage.cards.h; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,15 +19,14 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class HoundOfTheFarbogs extends CardImpl { - final static private String RULE = "{this} has menace as long as there are four or more card types among cards in your graveyard"; + static final private String RULE = "{this} has menace as long as there are four or more card types among cards in your graveyard"; public HoundOfTheFarbogs(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HOUND); this.power = new MageInt(5); @@ -36,6 +36,7 @@ public final class HoundOfTheFarbogs extends CardImpl { Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(new MenaceAbility(), Duration.WhileOnBattlefield), DeliriumCondition.instance, RULE)); ability.setAbilityWord(AbilityWord.DELIRIUM); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/h/HourOfEternity.java b/Mage.Sets/src/mage/cards/h/HourOfEternity.java index 0d7d499544..918d40620d 100644 --- a/Mage.Sets/src/mage/cards/h/HourOfEternity.java +++ b/Mage.Sets/src/mage/cards/h/HourOfEternity.java @@ -1,12 +1,8 @@ package mage.cards.h; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -21,10 +17,14 @@ import mage.game.permanent.token.EmptyToken; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author emerald000 */ public final class HourOfEternity extends CardImpl { @@ -34,17 +34,7 @@ public final class HourOfEternity extends CardImpl { // Exile X target creature cards from your graveyard. For each card exiled this way, create a token that's a copy of that card, except it's a 4/4 black Zombie. this.getSpellAbility().addEffect(new HourOfEternityEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard"))); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? " creature cards" : "creature card").append(" from your graveyard").toString())); - ability.addTarget(target); - } + this.getSpellAbility().setTargetAdjuster(HourOfEternityAdjuster.instance); } public HourOfEternity(final HourOfEternity card) { @@ -57,11 +47,25 @@ public final class HourOfEternity extends CardImpl { } } +enum HourOfEternityAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard((xValue != 1 ? " creature cards" : "creature card") + " from your graveyard")); + ability.addTarget(target); + } +} + class HourOfEternityEffect extends OneShotEffect { HourOfEternityEffect() { super(Outcome.PutCreatureInPlay); - this.staticText = "Exile X target creature cards from your graveyard. For each card exiled this way, create a token that's a copy of that card, except it's a 4/4 black Zombie"; + this.staticText = "Exile X target creature cards from your graveyard. " + + "For each card exiled this way, create a token that's a copy of that card, " + + "except it's a 4/4 black Zombie"; } HourOfEternityEffect(final HourOfEternityEffect effect) { diff --git a/Mage.Sets/src/mage/cards/h/HourOfReckoning.java b/Mage.Sets/src/mage/cards/h/HourOfReckoning.java index 9287b5b8fc..aca3d75b13 100644 --- a/Mage.Sets/src/mage/cards/h/HourOfReckoning.java +++ b/Mage.Sets/src/mage/cards/h/HourOfReckoning.java @@ -20,7 +20,7 @@ public final class HourOfReckoning extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creatures"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public HourOfReckoning(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HowlFromBeyond.java b/Mage.Sets/src/mage/cards/h/HowlFromBeyond.java index b580479cfb..ec2c6e9dd4 100644 --- a/Mage.Sets/src/mage/cards/h/HowlFromBeyond.java +++ b/Mage.Sets/src/mage/cards/h/HowlFromBeyond.java @@ -23,7 +23,7 @@ public final class HowlFromBeyond extends CardImpl { // Target creature gets +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/h/HowlpackWolf.java b/Mage.Sets/src/mage/cards/h/HowlpackWolf.java index 9adf3013f0..4f9376a4ff 100644 --- a/Mage.Sets/src/mage/cards/h/HowlpackWolf.java +++ b/Mage.Sets/src/mage/cards/h/HowlpackWolf.java @@ -25,7 +25,7 @@ public final class HowlpackWolf extends CardImpl { static { filter.add(Predicates.or(new SubtypePredicate(SubType.WOLF), new SubtypePredicate(SubType.WEREWOLF))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public HowlpackWolf(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java b/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java index d873f78870..adc5c9483b 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java +++ b/Mage.Sets/src/mage/cards/h/HuatliRadiantChampion.java @@ -1,13 +1,12 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -19,8 +18,9 @@ import mage.filter.StaticFilters; import mage.game.command.emblems.HuatliRadiantChampionEmblem; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HuatliRadiantChampion extends CardImpl { @@ -41,6 +41,7 @@ public final class HuatliRadiantChampion extends CardImpl { LoyaltyAbility ability2 = new LoyaltyAbility(new BoostTargetEffect(amount, amount, Duration.EndOfTurn, true) .setText("Target creature gets +X/+X until end of turn, where X is the number of creatures you control"), -1); ability2.addTarget(new TargetCreaturePermanent()); + ability2.addHint(CreaturesYouControlHint.instance); this.addAbility(ability2); // -8: You get an emblem with "Whenever a creature enters the battlefield under your control, you may draw a card." diff --git a/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java b/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java new file mode 100644 index 0000000000..89336f6c2a --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HuatliTheSunsHeart.java @@ -0,0 +1,50 @@ +package mage.cards.h; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.GreatestToughnessAmongControlledCreaturesValue; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ruleModifying.CombatDamageByToughnessEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HuatliTheSunsHeart extends CardImpl { + + public HuatliTheSunsHeart(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G/W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUATLI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + + // Each creature you control assigns combat damage equal to its toughness rather than its power. + this.addAbility(new SimpleStaticAbility(new CombatDamageByToughnessEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, true + ))); + + // -3: You gain life equal to the greatest toughness among creatures you control. + this.addAbility(new LoyaltyAbility(new GainLifeEffect( + GreatestToughnessAmongControlledCreaturesValue.instance, + "You gain life equal to the greatest power among creatures you control" + ), -3)); + } + + private HuatliTheSunsHeart(final HuatliTheSunsHeart card) { + super(card); + } + + @Override + public HuatliTheSunsHeart copy() { + return new HuatliTheSunsHeart(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java b/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java index 2cc5bf6d79..7d3ec36556 100644 --- a/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java +++ b/Mage.Sets/src/mage/cards/h/HuatliWarriorPoet.java @@ -1,7 +1,5 @@ - package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.Mode; @@ -18,11 +16,7 @@ import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.DinosaurToken; @@ -30,8 +24,9 @@ import mage.target.Target; import mage.target.common.TargetCreaturePermanentAmount; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class HuatliWarriorPoet extends CardImpl { @@ -45,18 +40,21 @@ public final class HuatliWarriorPoet extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); // +2: You gain life equal to the greatest power among creatures you control. - this.addAbility(new LoyaltyAbility(new GainLifeEffect(new GreatestPowerAmongControlledCreaturesValue(), "You gain life equal to the greatest power among creatures you control"), 2)); + this.addAbility(new LoyaltyAbility(new GainLifeEffect( + GreatestPowerAmongControlledCreaturesValue.instance, + "You gain life equal to the greatest power among creatures you control" + ), 2)); // 0: Create a 3/3 green Dinosaur creature token with trample. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DinosaurToken()), 0)); // -X: Huatli, Warrior Poet deals X damage divided as you choose among any number of target creatures. Creatures dealt damage this way can't block this turn. - Ability ability = new LoyaltyAbility(new HuatliWarriorPoetDamageEffect(new HuatliXValue())); - ability.addTarget(new TargetCreaturePermanentAmount(new HuatliXValue())); + Ability ability = new LoyaltyAbility(new HuatliWarriorPoetDamageEffect(HuatliXValue.instance)); + ability.addTarget(new TargetCreaturePermanentAmount(HuatliXValue.instance)); this.addAbility(ability); } - public HuatliWarriorPoet(final HuatliWarriorPoet card) { + private HuatliWarriorPoet(final HuatliWarriorPoet card) { super(card); } @@ -66,9 +64,8 @@ public final class HuatliWarriorPoet extends CardImpl { } } -class HuatliXValue implements DynamicValue { - - private static final HuatliXValue defaultValue = new HuatliXValue(); +enum HuatliXValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -82,7 +79,7 @@ class HuatliXValue implements DynamicValue { @Override public DynamicValue copy() { - return defaultValue; + return instance; } @Override @@ -96,7 +93,7 @@ class HuatliXValue implements DynamicValue { } public static HuatliXValue getDefault() { - return defaultValue; + return instance; } } @@ -104,12 +101,12 @@ class HuatliWarriorPoetDamageEffect extends OneShotEffect { protected DynamicValue amount; - public HuatliWarriorPoetDamageEffect(DynamicValue amount) { + HuatliWarriorPoetDamageEffect(DynamicValue amount) { super(Outcome.Damage); this.amount = amount; } - public HuatliWarriorPoetDamageEffect(final HuatliWarriorPoetDamageEffect effect) { + private HuatliWarriorPoetDamageEffect(final HuatliWarriorPoetDamageEffect effect) { super(effect); this.amount = effect.amount; } diff --git a/Mage.Sets/src/mage/cards/h/HuatlisRaptor.java b/Mage.Sets/src/mage/cards/h/HuatlisRaptor.java new file mode 100644 index 0000000000..886fccf0d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HuatlisRaptor.java @@ -0,0 +1,41 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +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 HuatlisRaptor extends CardImpl { + + public HuatlisRaptor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{W}"); + + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Huatli's Raptor enters the battlefield, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new EntersBattlefieldTriggeredAbility(new ProliferateEffect())); + } + + private HuatlisRaptor(final HuatlisRaptor card) { + super(card); + } + + @Override + public HuatlisRaptor copy() { + return new HuatlisRaptor(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HullBreach.java b/Mage.Sets/src/mage/cards/h/HullBreach.java index ef415f23c3..cd01d31605 100644 --- a/Mage.Sets/src/mage/cards/h/HullBreach.java +++ b/Mage.Sets/src/mage/cards/h/HullBreach.java @@ -27,17 +27,17 @@ public final class HullBreach extends CardImpl { this.getSpellAbility().addTarget(target); // or destroy target enchantment; Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); + mode.addEffect(new DestroyTargetEffect()); target = new TargetEnchantmentPermanent(); - mode.getTargets().add(target); + mode.addTarget(target); this.getSpellAbility().addMode(mode); // or destroy target artifact and target enchantment. mode = new Mode(); Effect effect = new DestroyTargetEffect(false, true); effect.setText("destroy target artifact and target enchantment"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetArtifactPermanent()); - mode.getTargets().add(new TargetEnchantmentPermanent()); + mode.addEffect(effect); + mode.addTarget(new TargetArtifactPermanent()); + mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/Humongulus.java b/Mage.Sets/src/mage/cards/h/Humongulus.java new file mode 100644 index 0000000000..63ffdadc36 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/Humongulus.java @@ -0,0 +1,36 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.keyword.HexproofAbility; +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 Humongulus extends CardImpl { + + public Humongulus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.HOMUNCULUS); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + } + + private Humongulus(final Humongulus card) { + super(card); + } + + @Override + public Humongulus copy() { + return new Humongulus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java b/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java index 9b0d2ccff8..f208a57298 100644 --- a/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java +++ b/Mage.Sets/src/mage/cards/h/HundredTalonStrike.java @@ -30,7 +30,7 @@ public final class HundredTalonStrike extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ColorPredicate(ObjectColor.WHITE)); } diff --git a/Mage.Sets/src/mage/cards/h/HungryLynx.java b/Mage.Sets/src/mage/cards/h/HungryLynx.java index fcd7a42ad1..510456806f 100644 --- a/Mage.Sets/src/mage/cards/h/HungryLynx.java +++ b/Mage.Sets/src/mage/cards/h/HungryLynx.java @@ -33,7 +33,7 @@ import mage.target.common.TargetOpponent; */ public final class HungryLynx extends CardImpl { - private final static FilterControlledCreaturePermanent filterCat = new FilterControlledCreaturePermanent("Cats"); + private static final FilterControlledCreaturePermanent filterCat = new FilterControlledCreaturePermanent("Cats"); static { filterCat.add(new SubtypePredicate(SubType.CAT)); } @@ -43,7 +43,7 @@ public final class HungryLynx extends CardImpl { filterProRat.add(new SubtypePredicate(SubType.RAT)); } - private final static FilterCreaturePermanent filterRat = new FilterCreaturePermanent("a Rat"); + private static final FilterCreaturePermanent filterRat = new FilterCreaturePermanent("a Rat"); static { filterRat.add(new SubtypePredicate(SubType.RAT)); } diff --git a/Mage.Sets/src/mage/cards/h/HuntDown.java b/Mage.Sets/src/mage/cards/h/HuntDown.java index f03e5c2107..419db8da28 100644 --- a/Mage.Sets/src/mage/cards/h/HuntDown.java +++ b/Mage.Sets/src/mage/cards/h/HuntDown.java @@ -68,9 +68,9 @@ class HuntDownEffect extends RequirementEffect { Permanent blocker = game.getPermanent(source.getTargets().get(0).getFirstTarget()); if (blocker != null && blocker.canBlock(source.getTargets().get(1).getFirstTarget(), game)) { - Permanent attacker = (Permanent) game.getPermanent(source.getTargets().get(1).getFirstTarget()); + Permanent attacker = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (attacker != null) { - BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher blockedAttackerWatcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) { // has already blocked this turn, so no need to do again diff --git a/Mage.Sets/src/mage/cards/h/HuntToExtinction.java b/Mage.Sets/src/mage/cards/h/HuntToExtinction.java index 33ba56f400..772bd5dce9 100644 --- a/Mage.Sets/src/mage/cards/h/HuntToExtinction.java +++ b/Mage.Sets/src/mage/cards/h/HuntToExtinction.java @@ -34,10 +34,10 @@ public final class HuntToExtinction extends CardImpl { this.getSpellAbility().addTarget(new TargetOpponentsCreaturePermanent(0, 1)); // Hunt to Extinction deals X damage to each creature. - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, new FilterCreaturePermanent())); // Hunt to Exctinction deals an additional X damage to each creature with a bounty counter on it. - Effect effect = new DamageAllEffect(new ManacostVariableValue(), new FilterCreaturePermanent(filter)); + Effect effect = new DamageAllEffect(ManacostVariableValue.instance, new FilterCreaturePermanent(filter)); effect.setText("Hunt to Exctinction deals an additional X damage to each creature with a bounty counter on it"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java b/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java index 48a36abe11..4b1b6ccae2 100644 --- a/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java +++ b/Mage.Sets/src/mage/cards/h/HunterOfEyeblights.java @@ -33,7 +33,7 @@ public final class HunterOfEyeblights extends CardImpl { static { filter1.add(new ControllerPredicate(TargetController.NOT_YOU)); - filter2.add(new CounterAnyPredicate()); + filter2.add(CounterAnyPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/h/HuntingKavu.java b/Mage.Sets/src/mage/cards/h/HuntingKavu.java index 011ceed8fc..10d6a9e987 100644 --- a/Mage.Sets/src/mage/cards/h/HuntingKavu.java +++ b/Mage.Sets/src/mage/cards/h/HuntingKavu.java @@ -17,7 +17,7 @@ import mage.constants.SubType; import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/h/HurkylsRecall.java b/Mage.Sets/src/mage/cards/h/HurkylsRecall.java index ebe6db7e91..384f5c6ec3 100644 --- a/Mage.Sets/src/mage/cards/h/HurkylsRecall.java +++ b/Mage.Sets/src/mage/cards/h/HurkylsRecall.java @@ -1,22 +1,22 @@ package mage.cards.h; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandFromBattlefieldAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactPermanent; import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class HurkylsRecall extends CardImpl { @@ -29,7 +29,7 @@ public final class HurkylsRecall extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); } - public HurkylsRecall(final HurkylsRecall card) { + private HurkylsRecall(final HurkylsRecall card) { super(card); } @@ -41,24 +41,21 @@ public final class HurkylsRecall extends CardImpl { class HurkylsRecallReturnToHandEffect extends OneShotEffect { - public HurkylsRecallReturnToHandEffect() { + HurkylsRecallReturnToHandEffect() { super(Outcome.ReturnToHand); staticText = "Return all artifacts target player owns to their hand"; } - public HurkylsRecallReturnToHandEffect(final HurkylsRecallReturnToHandEffect effect) { + private HurkylsRecallReturnToHandEffect(final HurkylsRecallReturnToHandEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { if (targetPointer.getFirst(game, source) != null) { - FilterArtifactPermanent filter = new FilterArtifactPermanent(); + FilterPermanent filter = new FilterArtifactPermanent(); filter.add(new OwnerIdPredicate(targetPointer.getFirst(game, source))); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - permanent.moveToZone(Zone.HAND, source.getSourceId(), game, true); - } - return true; + return new ReturnToHandFromBattlefieldAllEffect(filter).apply(game, source); } return false; } diff --git a/Mage.Sets/src/mage/cards/h/HurlyBurly.java b/Mage.Sets/src/mage/cards/h/HurlyBurly.java index a7cba49893..128c5c74a6 100644 --- a/Mage.Sets/src/mage/cards/h/HurlyBurly.java +++ b/Mage.Sets/src/mage/cards/h/HurlyBurly.java @@ -31,7 +31,7 @@ public final class HurlyBurly extends CardImpl { this.getSpellAbility().addEffect(new DamageAllEffect(1, filterWithFlying)); Mode mode = new Mode(); - mode.getEffects().add(new DamageAllEffect(1, filterWithoutFlying)); + mode.addEffect(new DamageAllEffect(1, filterWithoutFlying)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/Hurricane.java b/Mage.Sets/src/mage/cards/h/Hurricane.java index cc1418ce23..b6630989b2 100644 --- a/Mage.Sets/src/mage/cards/h/Hurricane.java +++ b/Mage.Sets/src/mage/cards/h/Hurricane.java @@ -28,7 +28,7 @@ public final class Hurricane extends CardImpl { // Hurricane deals X damage to each creature with flying and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageEverythingEffect(ManacostVariableValue.instance, filter)); } public Hurricane(final Hurricane card) { diff --git a/Mage.Sets/src/mage/cards/h/Hydradoodle.java b/Mage.Sets/src/mage/cards/h/Hydradoodle.java index f5f5afffbd..75fc85bff8 100644 --- a/Mage.Sets/src/mage/cards/h/Hydradoodle.java +++ b/Mage.Sets/src/mage/cards/h/Hydradoodle.java @@ -84,7 +84,7 @@ class HydradoodleEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - if (permanent != null) { + if (permanent != null && controller != null) { SpellAbility spellAbility = (SpellAbility) getValue(EntersBattlefieldEffect.SOURCE_CAST_SPELL_ABILITY); if (spellAbility != null && spellAbility.getSourceId().equals(source.getSourceId()) diff --git a/Mage.Sets/src/mage/cards/h/Hydroblast.java b/Mage.Sets/src/mage/cards/h/Hydroblast.java index e76b9d5287..53da9f524d 100644 --- a/Mage.Sets/src/mage/cards/h/Hydroblast.java +++ b/Mage.Sets/src/mage/cards/h/Hydroblast.java @@ -30,8 +30,8 @@ public final class Hydroblast extends CardImpl { // or destroy target permanent if it's red. Mode mode = new Mode(); - mode.getEffects().add(new HydroblastDestroyEffect()); - mode.getTargets().add(new TargetPermanent()); + mode.addEffect(new HydroblastDestroyEffect()); + mode.addTarget(new TargetPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/h/HydroidKrasis.java b/Mage.Sets/src/mage/cards/h/HydroidKrasis.java new file mode 100644 index 0000000000..85012dac51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HydroidKrasis.java @@ -0,0 +1,93 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +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.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class HydroidKrasis extends CardImpl { + + public HydroidKrasis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}{G}{U}"); + + this.subtype.add(SubType.JELLYFISH); + this.subtype.add(SubType.HYDRA); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // When you cast this spell, you gain half X life and draw half X cards. Round down each time. + this.addAbility(new CastSourceTriggeredAbility(new HydroidKrasisEffect(), false)); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Hydroid Krasis enters the battlefield with X +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility( + new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()) + )); + } + + private HydroidKrasis(final HydroidKrasis card) { + super(card); + } + + @Override + public HydroidKrasis copy() { + return new HydroidKrasis(this); + } +} + +class HydroidKrasisEffect extends OneShotEffect { + + HydroidKrasisEffect() { + super(Outcome.Benefit); + staticText = "you gain half X life and draw half X cards. Round down each time."; + } + + private HydroidKrasisEffect(final HydroidKrasisEffect effect) { + super(effect); + } + + @Override + public HydroidKrasisEffect copy() { + return new HydroidKrasisEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Object obj = getValue(CastSourceTriggeredAbility.SOURCE_CAST_SPELL_ABILITY); + if (!(obj instanceof SpellAbility)) { + return false; + } + int halfCost = Math.floorDiv(((SpellAbility) obj).getManaCostsToPay().getX(), 2); + player.drawCards(halfCost, game); + player.gainLife(halfCost, game, source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/h/HydromorphGuardian.java b/Mage.Sets/src/mage/cards/h/HydromorphGuardian.java index e2e0ce0be0..4ed1b891f7 100644 --- a/Mage.Sets/src/mage/cards/h/HydromorphGuardian.java +++ b/Mage.Sets/src/mage/cards/h/HydromorphGuardian.java @@ -25,7 +25,7 @@ import mage.target.TargetSpell; */ public final class HydromorphGuardian extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); + private static final FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); static { filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/h/HydromorphGull.java b/Mage.Sets/src/mage/cards/h/HydromorphGull.java index 999873891c..8ad0d29c44 100644 --- a/Mage.Sets/src/mage/cards/h/HydromorphGull.java +++ b/Mage.Sets/src/mage/cards/h/HydromorphGull.java @@ -26,7 +26,7 @@ import mage.target.TargetSpell; */ public final class HydromorphGull extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); + private static final FilterSpell filter = new FilterSpell("spell that targets one or more creatures you control"); static { filter.add(new TargetsPermanentPredicate(new FilterControlledCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java b/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java index 9f710caeca..eaf0a24a51 100644 --- a/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java +++ b/Mage.Sets/src/mage/cards/i/IbHalfheartGoblinTactician.java @@ -37,7 +37,7 @@ public final class IbHalfheartGoblinTactician extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MOUNTAIN)); filterGoblin.add(new SubtypePredicate(SubType.GOBLIN)); - filterGoblin.add(new AnotherPredicate()); + filterGoblin.add(AnotherPredicate.instance); filterGoblin.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/i/IcatianStore.java b/Mage.Sets/src/mage/cards/i/IcatianStore.java index 6e9aa33546..91a3dfecb2 100644 --- a/Mage.Sets/src/mage/cards/i/IcatianStore.java +++ b/Mage.Sets/src/mage/cards/i/IcatianStore.java @@ -44,7 +44,7 @@ public final class IcatianStore extends CardImpl { // {tap}, Remove any number of storage counters from Icatian Store: Add {W} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.WhiteMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {W} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/i/IceFloe.java b/Mage.Sets/src/mage/cards/i/IceFloe.java index 030b3a9076..9b101c88f4 100644 --- a/Mage.Sets/src/mage/cards/i/IceFloe.java +++ b/Mage.Sets/src/mage/cards/i/IceFloe.java @@ -15,7 +15,7 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/i/IcefallRegent.java b/Mage.Sets/src/mage/cards/i/IcefallRegent.java index 8e21b7bf10..ec71d65553 100644 --- a/Mage.Sets/src/mage/cards/i/IcefallRegent.java +++ b/Mage.Sets/src/mage/cards/i/IcefallRegent.java @@ -143,7 +143,7 @@ class IcefallRegentEffect extends ContinuousRuleModifyingEffectImpl { class IcefallRegentWatcher extends Watcher { IcefallRegentWatcher() { - super("ControlLost", WatcherScope.CARD); + super(WatcherScope.CARD); } IcefallRegentWatcher(IcefallRegentWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java index 215d29b039..faec12790b 100644 --- a/Mage.Sets/src/mage/cards/i/IcefeatherAven.java +++ b/Mage.Sets/src/mage/cards/i/IcefeatherAven.java @@ -26,7 +26,7 @@ public final class IcefeatherAven extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public IcefeatherAven(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/Icequake.java b/Mage.Sets/src/mage/cards/i/Icequake.java index cad1b47cd1..70399b40e7 100644 --- a/Mage.Sets/src/mage/cards/i/Icequake.java +++ b/Mage.Sets/src/mage/cards/i/Icequake.java @@ -59,14 +59,16 @@ class IcequakeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null && controller != null) { - permanent.destroy(source.getSourceId(), game, false); - if (permanent.isSnow()) { - controller.damage(1, source.getSourceId(), game, false, true); + if (permanent != null) { + Player controller = game.getPlayer(permanent.getControllerId()); + if(controller != null) { + permanent.destroy(source.getSourceId(), game, false); + if (permanent.isSnow()) { + controller.damage(1, source.getSourceId(), game, false, true); + } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/i/IchneumonDruid.java b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java new file mode 100644 index 0000000000..0e878b9815 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IchneumonDruid.java @@ -0,0 +1,135 @@ + +package mage.cards.i; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.stack.Spell; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; + +/** + * + * @author L_J + */ +public final class IchneumonDruid extends CardImpl { + + public IchneumonDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{G}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, Ichneumon Druid deals 4 damage to that player. + this.addAbility(new IchneumonDruidAbility(), new IchneumonDruidWatcher()); + } + + public IchneumonDruid(final IchneumonDruid card) { + super(card); + } + + @Override + public IchneumonDruid copy() { + return new IchneumonDruid(this); + } +} + +class IchneumonDruidAbility extends TriggeredAbilityImpl { + + public IchneumonDruidAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(4), false, "that player", true)); + } + + public IchneumonDruidAbility(final IchneumonDruidAbility ability) { + super(ability); + } + + @Override + public IchneumonDruidAbility copy() { + return new IchneumonDruidAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.SPELL_CAST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getPlayerId().equals(controllerId)) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isInstant()) { + IchneumonDruidWatcher watcher = game.getState().getWatcher(IchneumonDruidWatcher.class); + if (watcher != null && watcher.moreThanTwoInstantsCast(event.getPlayerId(), game)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + } + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent casts an instant spell other than the first instant spell that player casts each turn, {this} deals 4 damage to that player."; + } +} + +class IchneumonDruidWatcher extends Watcher { + + private final Map playerInstantCount = new HashMap<>(); + + public IchneumonDruidWatcher() { + super(WatcherScope.GAME); + } + + public IchneumonDruidWatcher(final IchneumonDruidWatcher watcher) { + super(watcher); + for (Map.Entry entry : watcher.playerInstantCount.entrySet()) { + playerInstantCount.put(entry.getKey(), entry.getValue()); + } + } + + @Override + public IchneumonDruidWatcher copy() { + return new IchneumonDruidWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.SPELL_CAST) { + UUID playerId = event.getPlayerId(); + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.isInstant()) { + playerInstantCount.putIfAbsent(event.getPlayerId(), 0); + playerInstantCount.compute(playerId, (k, v) -> v + 1); + } + } + } + + public boolean moreThanTwoInstantsCast(UUID playerId, Game game) { + return playerInstantCount.get(playerId) > 1; + } + + @Override + public void reset() { + playerInstantCount.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IcyBlast.java b/Mage.Sets/src/mage/cards/i/IcyBlast.java index cd37dd0a74..2d9034b5a1 100644 --- a/Mage.Sets/src/mage/cards/i/IcyBlast.java +++ b/Mage.Sets/src/mage/cards/i/IcyBlast.java @@ -1,24 +1,23 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author emerald000 */ public final class IcyBlast extends CardImpl { @@ -28,7 +27,6 @@ public final class IcyBlast extends CardImpl { // Tap X target creatures. this.getSpellAbility().addEffect(new TapTargetEffect("X target creatures")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false)); // Ferocious — If you control a creature with power 4 or greater, those creatures don't untap during their controllers' next untap steps. Effect effect = new ConditionalContinuousRuleModifyingEffect( @@ -36,24 +34,26 @@ public final class IcyBlast extends CardImpl { new LockedInCondition(FerociousCondition.instance)); effect.setText("
    Ferocious — If you control a creature with power 4 or greater, those creatures don't untap during their controllers' next untap steps"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(IcyBlastAdjuster.instance); + this.getSpellAbility().addHint(FerociousHint.instance); } public IcyBlast(final IcyBlast card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numberToTap = ability.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, ability.getSourceId(), ability.getControllerId(), game), numberToTap); - ability.addTarget(new TargetCreaturePermanent(numberToTap)); - } - } - @Override public IcyBlast copy() { return new IcyBlast(this); } } + +enum IcyBlastAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/IdentityThief.java b/Mage.Sets/src/mage/cards/i/IdentityThief.java index 61d182b21b..7003539065 100644 --- a/Mage.Sets/src/mage/cards/i/IdentityThief.java +++ b/Mage.Sets/src/mage/cards/i/IdentityThief.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -12,11 +10,7 @@ import mage.abilities.effects.common.CopyEffect; import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TokenPredicate; @@ -28,16 +22,17 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author spjspj */ public final class IdentityThief extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("target nontoken creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public IdentityThief(UUID ownerId, CardSetInfo setInfo) { @@ -87,7 +82,7 @@ class IdentityThiefAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever {this} attacks, ").append(super.getRule()).toString(); + return "Whenever {this} attacks, " + super.getRule(); } @Override @@ -114,11 +109,7 @@ class IdentityThiefEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && permanent != null && sourcePermanent != null) { - Permanent permanentReset = permanent.copy(); - permanentReset.getCounters(game).clear(); - permanentReset.getPower().resetToBaseValue(); - permanentReset.getToughness().resetToBaseValue(); - CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, permanentReset, source.getSourceId()); + CopyEffect copyEffect = new CopyEffect(Duration.EndOfTurn, permanent, source.getSourceId()); if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { // Copy exiled permanent game.addEffect(copyEffect, source); diff --git a/Mage.Sets/src/mage/cards/i/IgniteTheBeacon.java b/Mage.Sets/src/mage/cards/i/IgniteTheBeacon.java new file mode 100644 index 0000000000..edd5644ff2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IgniteTheBeacon.java @@ -0,0 +1,37 @@ +package mage.cards.i; + +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPlaneswalkerCard; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IgniteTheBeacon extends CardImpl { + + private static final FilterCard filter = new FilterPlaneswalkerCard("planeswalker cards"); + + public IgniteTheBeacon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{W}"); + + // Search your library for up to to two planeswalker cards, reveal them, put them into your hand, then shuffle your library. + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(0, 2, filter), true + )); + } + + private IgniteTheBeacon(final IgniteTheBeacon card) { + super(card); + } + + @Override + public IgniteTheBeacon copy() { + return new IgniteTheBeacon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IgnitionTeam.java b/Mage.Sets/src/mage/cards/i/IgnitionTeam.java index bc10230d9d..2272e352a4 100644 --- a/Mage.Sets/src/mage/cards/i/IgnitionTeam.java +++ b/Mage.Sets/src/mage/cards/i/IgnitionTeam.java @@ -73,7 +73,7 @@ class TappedLandsCount implements DynamicValue { public int calculate(Game game, Ability sourceAbility, Effect effect) { if (sourceAbility != null) { FilterLandPermanent filter = new FilterLandPermanent("tapped lands on the battlefield"); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); } return 0; diff --git a/Mage.Sets/src/mage/cards/i/IlhargTheRazeBoar.java b/Mage.Sets/src/mage/cards/i/IlhargTheRazeBoar.java new file mode 100644 index 0000000000..b17883fd8a --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IlhargTheRazeBoar.java @@ -0,0 +1,103 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.GodEternalDiesTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.TrampleAbility; +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.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInHand; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IlhargTheRazeBoar extends CardImpl { + + public IlhargTheRazeBoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.BOAR); + this.subtype.add(SubType.GOD); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Ilharg, the Raze-Boar attacks, you may put a creature card from your hand onto the battlefield tapped and attacking. Return that creature to your hand at the beginning of the next end step. + this.addAbility(new AttacksTriggeredAbility(new IlhargTheRazeBoarEffect(), true)); + + // When Ilharg, the Raze-Boar dies or is put into exile from the battlefield, you may put it into its owner's library third from the top. + this.addAbility(new GodEternalDiesTriggeredAbility()); + } + + private IlhargTheRazeBoar(final IlhargTheRazeBoar card) { + super(card); + } + + @Override + public IlhargTheRazeBoar copy() { + return new IlhargTheRazeBoar(this); + } +} + +class IlhargTheRazeBoarEffect extends OneShotEffect { + + IlhargTheRazeBoarEffect() { + super(Outcome.Benefit); + staticText = "you may put a creature card from your hand onto the battlefield tapped and attacking. " + + "Return that creature to your hand at the beginning of the next end step."; + } + + private IlhargTheRazeBoarEffect(final IlhargTheRazeBoarEffect effect) { + super(effect); + } + + @Override + public IlhargTheRazeBoarEffect copy() { + return new IlhargTheRazeBoarEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInHand(0, 1, StaticFilters.FILTER_CARD_CREATURE); + if (!player.choose(outcome, player.getHand(), target, game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; + } + player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, true, null); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + game.getCombat().addAttackingCreature(permanent.getId(), game); + Effect effect = new ReturnToHandTargetEffect(); + effect.setText("return {this} to its owner's hand"); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IllGottenInheritance.java b/Mage.Sets/src/mage/cards/i/IllGottenInheritance.java new file mode 100644 index 0000000000..1c01c6a3c7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IllGottenInheritance.java @@ -0,0 +1,54 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IllGottenInheritance extends CardImpl { + + public IllGottenInheritance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); + + // At the beginning of your upkeep, Ill-Gotten Inheritance deals 1 damage to each opponent and you gain 1 life. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), + TargetController.YOU, false + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + + // {5}{B}, Sacrifice Ill-Gotten Inheritance: It deals 4 damage to target opponent and you gain 4 life. + ability = new SimpleActivatedAbility( + new DamageTargetEffect(4, "it"), + new ManaCostsImpl("{5}{B}") + ); + ability.addEffect(new GainLifeEffect(4).concatBy("and")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private IllGottenInheritance(final IllGottenInheritance card) { + super(card); + } + + @Override + public IllGottenInheritance copy() { + return new IllGottenInheritance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IllnessInTheRanks.java b/Mage.Sets/src/mage/cards/i/IllnessInTheRanks.java index b33417778b..9ac0a172bd 100644 --- a/Mage.Sets/src/mage/cards/i/IllnessInTheRanks.java +++ b/Mage.Sets/src/mage/cards/i/IllnessInTheRanks.java @@ -20,7 +20,7 @@ public final class IllnessInTheRanks extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public IllnessInTheRanks(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/Illuminate.java b/Mage.Sets/src/mage/cards/i/Illuminate.java index 642379fd37..558226bcf1 100644 --- a/Mage.Sets/src/mage/cards/i/Illuminate.java +++ b/Mage.Sets/src/mage/cards/i/Illuminate.java @@ -28,14 +28,14 @@ public final class Illuminate extends CardImpl { kickerAbility.addKickerCost("{3}{U}"); this.addAbility(kickerAbility); // Illuminate deals X damage to target creature. If Illuminate was kicked with its {2}{R} kicker, it deals X damage to that creature's controller. If Illuminate was kicked with its {3}{U} kicker, you draw X cards. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DamageTargetControllerEffect(new ManacostVariableValue()), + new DamageTargetControllerEffect(ManacostVariableValue.instance), new KickedCostCondition("{2}{R}"), "if this spell was kicked with its {2}{R} kicker, it deals X damage to that creature's controller.")); this.getSpellAbility().addEffect(new ConditionalOneShotEffect( - new DrawCardSourceControllerEffect(new ManacostVariableValue()), + new DrawCardSourceControllerEffect(ManacostVariableValue.instance), new KickedCostCondition("{3}{U}"), " if this spell was kicked with its {3}{U} kicker, you draw X cards.")); diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java b/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java new file mode 100644 index 0000000000..b8adf4654f --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IllusionaryPresence.java @@ -0,0 +1,111 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.constants.SubType; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ChooseBasicLandTypeEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.abilities.keyword.ForestwalkAbility; +import mage.abilities.keyword.IslandwalkAbility; +import mage.abilities.keyword.MountainwalkAbility; +import mage.abilities.keyword.PlainswalkAbility; +import mage.abilities.keyword.SwampwalkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; + +/** + * + * @author jeffwadsworth + */ +public final class IllusionaryPresence extends CardImpl { + + public IllusionaryPresence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Cumulative upkeep {U} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{U}"))); + + // At the beginning of your upkeep, choose a land type. Illusionary Presence gains landwalk of the chosen type until end of turn. + Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ChooseBasicLandTypeEffect(Outcome.Neutral), TargetController.YOU, false); + ability.addEffect(new IllusionaryPresenceEffect()); + this.addAbility(ability); + + } + + private IllusionaryPresence(final IllusionaryPresence card) { + super(card); + } + + @Override + public IllusionaryPresence copy() { + return new IllusionaryPresence(this); + } +} + +class IllusionaryPresenceEffect extends OneShotEffect { + + Ability gainedAbility; + + public IllusionaryPresenceEffect() { + super(Outcome.Benefit); + this.staticText = "{this} gains landwalk of the chosen type until end of turn"; + } + + public IllusionaryPresenceEffect(final IllusionaryPresenceEffect effect) { + super(effect); + } + + @Override + public IllusionaryPresenceEffect copy() { + return new IllusionaryPresenceEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + SubType landTypeChoice = SubType.byDescription((String) game.getState().getValue(mageObject.getId().toString() + "BasicLandType")); + if (landTypeChoice != null) { + switch (landTypeChoice) { + case PLAINS: + gainedAbility = new PlainswalkAbility(); + break; + case FOREST: + gainedAbility = new ForestwalkAbility(); + break; + case SWAMP: + gainedAbility = new SwampwalkAbility(); + break; + case ISLAND: + gainedAbility = new IslandwalkAbility(); + break; + case MOUNTAIN: + gainedAbility = new MountainwalkAbility(); + break; + } + if (gainedAbility != null) { + GainAbilitySourceEffect effect = new GainAbilitySourceEffect(gainedAbility, Duration.EndOfTurn); + game.addEffect(effect, source); + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java new file mode 100644 index 0000000000..d61f2916e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IllusionaryTerrain.java @@ -0,0 +1,202 @@ +package mage.cards.i; + +import java.util.List; +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceBasicLandType; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public final class IllusionaryTerrain extends CardImpl { + + public IllusionaryTerrain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}"); + + // Cumulative upkeep {2} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{2}"))); + + // As Illusionary Terrain enters the battlefield, choose two basic land types. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseTwoBasicLandTypesEffect(Outcome.Neutral))); + + // Basic lands of the first chosen type are the second chosen type. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new IllusionaryTerrainEffect())); + + } + + private IllusionaryTerrain(final IllusionaryTerrain card) { + super(card); + } + + @Override + public IllusionaryTerrain copy() { + return new IllusionaryTerrain(this); + } +} + +class IllusionaryTerrainEffect extends ContinuousEffectImpl { + + public IllusionaryTerrainEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "Basic lands of the first chosen type are the second chosen type"; + } + + public IllusionaryTerrainEffect(final IllusionaryTerrainEffect effect) { + super(effect); + } + + @Override + public IllusionaryTerrainEffect copy() { + return new IllusionaryTerrainEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + SubType firstChoice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "firstChoice")); + SubType secondChoice = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "secondChoice")); + List lands = game.getBattlefield().getAllActivePermanents(CardType.LAND); + if (controller != null + && firstChoice != null + && secondChoice != null) { + for (Permanent land : lands) { + if (land.isBasic()) { + switch (layer) { + case TypeChangingEffects_4: + if (land.getSubtype(game).contains(firstChoice)) { + land.getSubtype(game).clear(); + land.getSubtype(game).add(secondChoice); + game.getState().setValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game), + "true"); + } + break; + case AbilityAddingRemovingEffects_6: + if (game.getState().getValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)) != null + && game.getState().getValue("illusionaryTerrain" + + source.getId() + + land.getId() + + land.getZoneChangeCounter(game)).equals("true")) { + land.removeAllAbilities(source.getSourceId(), game); + if (land.getSubtype(game).contains(SubType.FOREST)) { + land.addAbility(new GreenManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.PLAINS)) { + land.addAbility(new WhiteManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.MOUNTAIN)) { + land.addAbility(new RedManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.ISLAND)) { + land.addAbility(new BlueManaAbility(), source.getSourceId(), game); + } + if (land.getSubtype(game).contains(SubType.SWAMP)) { + land.addAbility(new BlackManaAbility(), source.getSourceId(), game); + } + break; + } + } + } + } + return true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4 + || layer == Layer.AbilityAddingRemovingEffects_6; + + } +} + +class ChooseTwoBasicLandTypesEffect extends OneShotEffect { + + String choiceOne; + String choiceTwo; + + public ChooseTwoBasicLandTypesEffect(Outcome outcome) { + super(outcome); + this.staticText = "choose two basic land types"; + } + + public ChooseTwoBasicLandTypesEffect(final ChooseTwoBasicLandTypesEffect effect) { + super(effect); + } + + @Override + public ChooseTwoBasicLandTypesEffect copy() { + return new ChooseTwoBasicLandTypesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject mageObject = game.getPermanentEntering(source.getSourceId()); + if (mageObject == null) { + mageObject = game.getObject(source.getSourceId()); + } + if (controller != null + && mageObject != null) { + ChoiceImpl choices = new ChoiceBasicLandType(); + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getName() + ": First chosen basic land type is " + choices.getChoice()); + game.getState().setValue(mageObject.getId().toString() + "firstChoice", choices.getChoice()); + choiceOne = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "firstChoice")).getDescription(); + } + if (controller.choose(Outcome.Neutral, choices, game)) { + game.informPlayers(mageObject.getName() + ": Second chosen basic land type is " + choices.getChoice()); + game.getState().setValue(mageObject.getId().toString() + "secondChoice", choices.getChoice()); + choiceTwo = SubType.byDescription((String) game.getState().getValue(source.getSourceId().toString() + "secondChoice")).getDescription(); + if (mageObject instanceof Permanent + && choiceOne != null + && choiceTwo != null) { + ((Permanent) mageObject).addInfo("Chosen Types", CardUtil.addToolTipMarkTags("First chosen basic land type: " + choiceOne + + "\n Second chosen basic land type: " + choiceTwo), game); + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IllusionistsBracers.java b/Mage.Sets/src/mage/cards/i/IllusionistsBracers.java index 389d705645..257ca55ff2 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionistsBracers.java +++ b/Mage.Sets/src/mage/cards/i/IllusionistsBracers.java @@ -112,7 +112,7 @@ class CopyActivatedAbilityEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (ability != null && controller != null && sourcePermanent != null) { ability.createCopyOnStack(game, source, source.getControllerId(), true); - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); + game.informPlayers(sourcePermanent.getName() + ": " + controller.getLogName() + " copied activated ability"); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/i/IllusionistsGambit.java b/Mage.Sets/src/mage/cards/i/IllusionistsGambit.java index b624891e7a..d2e8fe2243 100644 --- a/Mage.Sets/src/mage/cards/i/IllusionistsGambit.java +++ b/Mage.Sets/src/mage/cards/i/IllusionistsGambit.java @@ -1,9 +1,5 @@ - package mage.cards.i; -import java.util.List; -import java.util.Objects; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.condition.common.OnOpponentsTurnCondition; @@ -13,24 +9,23 @@ import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.TurnPhase; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.turn.Phase; import mage.game.turn.TurnMod; +import java.util.List; +import java.util.Objects; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class IllusionistsGambit extends CardImpl { public IllusionistsGambit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); // Cast Illusionist's Gambit only during the declare blockers step on an opponent's turn. this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(PhaseStep.DECLARE_BLOCKERS, OnOpponentsTurnCondition.instance)); @@ -122,9 +117,7 @@ class IllusionistsGambitRequirementEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { if (game.getTurn().getStepType() == PhaseStep.END_COMBAT) { - if (!Objects.equals(game.getTurn().getPhase(), phase)) { - return true; - } + return !Objects.equals(game.getTurn().getPhase(), phase); } return false; } @@ -166,25 +159,23 @@ class IllusionistsGambitRestrictionEffect extends RestrictionEffect { @Override public boolean isInactive(Ability source, Game game) { if (game.getTurn().getStepType() == PhaseStep.END_COMBAT) { - if (!Objects.equals(game.getTurn().getPhase(), phase)) { - return true; - } + return !Objects.equals(game.getTurn().getPhase(), phase); } return false; } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } if (defenderId.equals(source.getControllerId())) { return false; } // planeswalker Permanent permanent = game.getPermanent(defenderId); - if (permanent != null && permanent.isControlledBy(source.getControllerId()) - && permanent.isPlaneswalker()) { - return false; - } - return true; + return permanent == null || !permanent.isControlledBy(source.getControllerId()) + || !permanent.isPlaneswalker(); } @Override diff --git a/Mage.Sets/src/mage/cards/i/ImmobilizerEldrazi.java b/Mage.Sets/src/mage/cards/i/ImmobilizerEldrazi.java index 80720c49bc..3ddded171c 100644 --- a/Mage.Sets/src/mage/cards/i/ImmobilizerEldrazi.java +++ b/Mage.Sets/src/mage/cards/i/ImmobilizerEldrazi.java @@ -25,7 +25,7 @@ import mage.game.Game; */ public final class ImmobilizerEldrazi extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature with toughness greater than its power"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature with toughness greater than its power"); static { filter.add(new ImmobilizerEldraziPredicate()); diff --git a/Mage.Sets/src/mage/cards/i/ImmolationShaman.java b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java new file mode 100644 index 0000000000..a4eddb6286 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImmolationShaman.java @@ -0,0 +1,111 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.stack.StackAbility; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ImmolationShaman extends CardImpl { + + public ImmolationShaman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Whenever an opponent activates an ability of an artifact, creature, or land that isn't a mana ability, Immolation Shaman deals 1 damage to that player. + this.addAbility(new ImmolationShamanTriggeredAbility()); + + // {3}{R}{R}: Immolation Shaman gets +3/+3 and gains menace until end of turn. + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect( + 3, 3, Duration.EndOfTurn + ).setText("{this} gets +3/+3"), + new ManaCostsImpl("{3}{R}{R}") + ); + ability.addEffect(new GainAbilitySourceEffect( + new MenaceAbility(), Duration.EndOfTurn + ).setText("and gains menace until end of turn")); + this.addAbility(ability); + } + + private ImmolationShaman(final ImmolationShaman card) { + super(card); + } + + @Override + public ImmolationShaman copy() { + return new ImmolationShaman(this); + } +} + +class ImmolationShamanTriggeredAbility extends TriggeredAbilityImpl { + + ImmolationShamanTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(new StaticValue(1), true, "that player", true)); + } + + private ImmolationShamanTriggeredAbility(final ImmolationShamanTriggeredAbility ability) { + super(ability); + } + + @Override + public ImmolationShamanTriggeredAbility copy() { + return new ImmolationShamanTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ACTIVATED_ABILITY; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!event.getPlayerId().equals(getControllerId())) { + Card source = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (source != null && (source.isArtifact() || source.isCreature() || source.isLand())) { + StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); + if (!(stackAbility.getStackAbility() instanceof ActivatedManaAbilityImpl)) { + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + } + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent activates an ability of an artifact, creature, or land on the battlefield, " + + "if it isn't a mana ability, {this} deals 1 damage to that player."; + } +} diff --git a/Mage.Sets/src/mage/cards/i/ImpactResonance.java b/Mage.Sets/src/mage/cards/i/ImpactResonance.java index 3f445d2613..2706a61606 100644 --- a/Mage.Sets/src/mage/cards/i/ImpactResonance.java +++ b/Mage.Sets/src/mage/cards/i/ImpactResonance.java @@ -62,7 +62,7 @@ enum GreatestAmountOfDamageDealtValue implements DynamicValue, MageSingleton { } public int calculate(Game game, UUID controllerId) { - GreatestAmountOfDamageWatcher watcher = (GreatestAmountOfDamageWatcher) game.getState().getWatchers().get(GreatestAmountOfDamageWatcher.class.getSimpleName()); + GreatestAmountOfDamageWatcher watcher = game.getState().getWatcher(GreatestAmountOfDamageWatcher.class); if (watcher != null) { return watcher.getGreatestAmountOfDamage(); } @@ -90,7 +90,7 @@ class GreatestAmountOfDamageWatcher extends Watcher { private int damageAmount; public GreatestAmountOfDamageWatcher() { - super(GreatestAmountOfDamageWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public GreatestAmountOfDamageWatcher(final GreatestAmountOfDamageWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/i/ImpassionedOrator.java b/Mage.Sets/src/mage/cards/i/ImpassionedOrator.java new file mode 100644 index 0000000000..ef1a2f0991 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImpassionedOrator.java @@ -0,0 +1,48 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ImpassionedOrator extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public ImpassionedOrator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever another creature enters the battlefield under your control, you gain 1 life. + this.addAbility(new EntersBattlefieldAllTriggeredAbility(new GainLifeEffect(1), filter)); + } + + private ImpassionedOrator(final ImpassionedOrator card) { + super(card); + } + + @Override + public ImpassionedOrator copy() { + return new ImpassionedOrator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/Impatience.java b/Mage.Sets/src/mage/cards/i/Impatience.java index 7e40923e11..6b15719662 100644 --- a/Mage.Sets/src/mage/cards/i/Impatience.java +++ b/Mage.Sets/src/mage/cards/i/Impatience.java @@ -46,8 +46,8 @@ class ImpatienceCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); - return watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(game.getActivePlayerId()) == 0; + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(game.getActivePlayerId()) == 0; } public String toString() { diff --git a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java index 0cbe3db956..0baf4fff2c 100644 --- a/Mage.Sets/src/mage/cards/i/ImpelledGiant.java +++ b/Mage.Sets/src/mage/cards/i/ImpelledGiant.java @@ -39,9 +39,9 @@ public final class ImpelledGiant extends CardImpl { static final private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped red creature you control other than Impelled Giant"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ImpelledGiant(UUID ownerId, CardSetInfo setInfo) { @@ -87,7 +87,7 @@ class ImpelledGiantCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { - for (UUID targetId: (List)target.getTargets()) { + for (UUID targetId: target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) return false; diff --git a/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java b/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java index 448afcc630..1353a50288 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java +++ b/Mage.Sets/src/mage/cards/i/ImperialAerosaur.java @@ -29,7 +29,7 @@ public final class ImperialAerosaur extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ImperialAerosaur(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/ImperialMask.java b/Mage.Sets/src/mage/cards/i/ImperialMask.java index 11b2f5b0a1..0052e61402 100644 --- a/Mage.Sets/src/mage/cards/i/ImperialMask.java +++ b/Mage.Sets/src/mage/cards/i/ImperialMask.java @@ -26,7 +26,7 @@ public final class ImperialMask extends CardImpl { private static final FilterPermanent filter = new FilterPermanent(); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public ImperialMask(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java b/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java new file mode 100644 index 0000000000..0a4a81eb5f --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/ImperiousOligarch.java @@ -0,0 +1,41 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +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 ImperiousOligarch extends CardImpl { + + public ImperiousOligarch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + public ImperiousOligarch(final ImperiousOligarch card) { + super(card); + } + + @Override + public ImperiousOligarch copy() { + return new ImperiousOligarch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java b/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java index a87a5545b9..eb774710b5 100644 --- a/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java +++ b/Mage.Sets/src/mage/cards/i/ImpetuousProtege.java @@ -57,7 +57,7 @@ class ImpetuousProtegeEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/i/Imprison.java b/Mage.Sets/src/mage/cards/i/Imprison.java index 6d094bdb9d..7f1b8c062b 100644 --- a/Mage.Sets/src/mage/cards/i/Imprison.java +++ b/Mage.Sets/src/mage/cards/i/Imprison.java @@ -145,7 +145,7 @@ class ImprisonUnblockEffect extends OneShotEffect { effect.apply(game, source); // Make blocked creatures unblocked - BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName()); + BlockedByOnlyOneCreatureThisCombatWatcher watcher = game.getState().getWatcher(BlockedByOnlyOneCreatureThisCombatWatcher.class); if (watcher != null) { Set combatGroups = watcher.getBlockedOnlyByCreature(permanent.getId()); if (combatGroups != null) { diff --git a/Mage.Sets/src/mage/cards/i/ImprisonedInTheMoon.java b/Mage.Sets/src/mage/cards/i/ImprisonedInTheMoon.java index cc32c91944..1df48d031c 100644 --- a/Mage.Sets/src/mage/cards/i/ImprisonedInTheMoon.java +++ b/Mage.Sets/src/mage/cards/i/ImprisonedInTheMoon.java @@ -1,4 +1,3 @@ - package mage.cards.i; import java.util.UUID; @@ -39,7 +38,7 @@ public final class ImprisonedInTheMoon extends CardImpl { } public ImprisonedInTheMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.subtype.add(SubType.AURA); // Enchant creature, land, or planeswalker @@ -87,10 +86,18 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { + if (enchantment != null + && enchantment.getAttachedTo() != null) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); if (permanent != null) { switch (layer) { + case TypeChangingEffects_4: + // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects + // So the ability removing has to be done before Layer 6 + permanent.removeAllAbilities(source.getSourceId(), game); + permanent.getCardType().clear(); + permanent.addCardType(CardType.LAND); + break; case ColorChangingEffects_5: permanent.getColor(game).setWhite(false); permanent.getColor(game).setGreen(false); @@ -102,14 +109,6 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl { permanent.removeAllAbilities(source.getSourceId(), game); permanent.addAbility(new ColorlessManaAbility(), source.getSourceId(), game); break; - case TypeChangingEffects_4: - boolean isLand = permanent.isLand(); - permanent.getCardType().clear(); - permanent.addCardType(CardType.LAND); - if (!isLand) { - permanent.getSubtype(game).clear(); - } - break; } return true; } @@ -119,6 +118,8 @@ class BecomesColorlessLandEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.ColorChangingEffects_5 + || layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java b/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java index abb7e8a6e0..07f90385a1 100644 --- a/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java +++ b/Mage.Sets/src/mage/cards/i/ImpromptuRaid.java @@ -82,8 +82,8 @@ class ImpromptuRaidEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { Card card = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); if (card != null) { + Cards cards = new CardsImpl(); cards.add(card); controller.revealCards(sourceObject.getName(), cards, game); if (filterPutInGraveyard.match(card, source.getSourceId(), source.getControllerId(), game)) { diff --git a/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java index 9f243cf845..1e2ec98a84 100644 --- a/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java +++ b/Mage.Sets/src/mage/cards/i/ImpulsiveManeuvers.java @@ -6,8 +6,6 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksAllTriggeredAbility; import mage.abilities.effects.PreventionEffectImpl; -import mage.abilities.effects.common.PreventDamageBySourceEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,9 +14,7 @@ import mage.constants.SetTargetPointer; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.filter.StaticFilters; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.players.Player; import mage.util.CardUtil; @@ -61,7 +57,7 @@ class ImpulsiveManeuversEffect extends PreventionEffectImpl { @Override public void init(Ability source, Game game) { - this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(game); + this.wonFlip = game.getPlayer(source.getControllerId()).flipCoin(source, game, true); super.init(source, game); } diff --git a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java index 418cb142f6..be50ef6f7a 100644 --- a/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java +++ b/Mage.Sets/src/mage/cards/i/InallaArchmageRitualist.java @@ -49,10 +49,10 @@ public final class InallaArchmageRitualist extends CardImpl { static { filter.add(new SubtypePredicate(SubType.WIZARD)); - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); filter2.add(new SubtypePredicate(SubType.WIZARD)); - filter2.add(Predicates.not(new TappedPredicate())); + filter2.add(Predicates.not(TappedPredicate.instance)); } public InallaArchmageRitualist(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/InameDeathAspect.java b/Mage.Sets/src/mage/cards/i/InameDeathAspect.java index e2778335b8..7d9584467c 100644 --- a/Mage.Sets/src/mage/cards/i/InameDeathAspect.java +++ b/Mage.Sets/src/mage/cards/i/InameDeathAspect.java @@ -67,7 +67,7 @@ class InameDeathAspectEffect extends SearchEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.searchLibrary(target, game)) { + if (player != null && player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { player.moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); } diff --git a/Mage.Sets/src/mage/cards/i/Incendiary.java b/Mage.Sets/src/mage/cards/i/Incendiary.java new file mode 100644 index 0000000000..f5987a4793 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/Incendiary.java @@ -0,0 +1,65 @@ +package mage.cards.i; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreatureOrPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class Incendiary extends CardImpl { + + private static final String rule = "{this} deals X damage to any target, where X is the number of fuse counters on {this}."; + + public Incendiary(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of your upkeep, you may put a fuse counter on Incendiary. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.FUSE.createInstance(), true), TargetController.YOU, true)); + + // When enchanted creature dies, Incendiary deals X damage to any target, where X is the number of fuse counters on Incendiary. + Effect effect = new DamageTargetEffect(new CountersSourceCount(CounterType.FUSE)).setText(rule); + Ability ability2 = new DiesAttachedTriggeredAbility(effect, "enchanted creature"); + ability.addTarget(new TargetCreatureOrPlayer()); + this.addAbility(ability2); + + } + + public Incendiary(final Incendiary card) { + super(card); + } + + @Override + public Incendiary copy() { + return new Incendiary(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java b/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java index 09c0a32b17..6fc1a4aaa8 100644 --- a/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java +++ b/Mage.Sets/src/mage/cards/i/IncendiaryCommand.java @@ -37,16 +37,16 @@ public final class IncendiaryCommand extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); // or Incendiary Command deals 2 damage to each creature; Mode mode = new Mode(); - mode.getEffects().add(new DamageAllEffect(2, new FilterCreaturePermanent())); + mode.addEffect(new DamageAllEffect(2, new FilterCreaturePermanent())); this.getSpellAbility().getModes().addMode(mode); // or destroy target nonbasic land; mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetNonBasicLandPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetNonBasicLandPermanent()); this.getSpellAbility().getModes().addMode(mode); // or each player discards all the cards in their hand, then draws that many cards. mode = new Mode(); - mode.getEffects().add(new IncendiaryCommandDrawEffect()); + mode.addEffect(new IncendiaryCommandDrawEffect()); this.getSpellAbility().getModes().addMode(mode); } @@ -92,10 +92,10 @@ class IncendiaryCommandDrawEffect extends OneShotEffect { } } } - for (UUID playerId : cardsToDraw.keySet()) { - Player player = game.getPlayer(playerId); + for (Map.Entry toDrawByPlayer : cardsToDraw.entrySet()) { + Player player = game.getPlayer(toDrawByPlayer.getKey()); if (player != null) { - player.drawCards(cardsToDraw.get(playerId), game); + player.drawCards(toDrawByPlayer.getValue(), game); } } return true; diff --git a/Mage.Sets/src/mage/cards/i/Incinerate.java b/Mage.Sets/src/mage/cards/i/Incinerate.java index 0fa3368ffb..4a0a926243 100644 --- a/Mage.Sets/src/mage/cards/i/Incinerate.java +++ b/Mage.Sets/src/mage/cards/i/Incinerate.java @@ -70,7 +70,7 @@ class IncinerateEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(event.getTargetId(), game); } diff --git a/Mage.Sets/src/mage/cards/i/InciteWar.java b/Mage.Sets/src/mage/cards/i/InciteWar.java index 6a1b2835ca..efdbf9c83a 100644 --- a/Mage.Sets/src/mage/cards/i/InciteWar.java +++ b/Mage.Sets/src/mage/cards/i/InciteWar.java @@ -46,7 +46,7 @@ public final class InciteWar extends CardImpl { // or creatures you control gain first strike until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter)); + mode.addEffect(new GainAbilityAllEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn, filter)); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/i/Incoming.java b/Mage.Sets/src/mage/cards/i/Incoming.java index f20b1cd4da..49296f8deb 100644 --- a/Mage.Sets/src/mage/cards/i/Incoming.java +++ b/Mage.Sets/src/mage/cards/i/Incoming.java @@ -74,7 +74,7 @@ class IncomingEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); player.shuffleLibrary(source, game); } diff --git a/Mage.Sets/src/mage/cards/i/IncreasingAmbition.java b/Mage.Sets/src/mage/cards/i/IncreasingAmbition.java index fc62cc74c3..7a9ccd4a2c 100644 --- a/Mage.Sets/src/mage/cards/i/IncreasingAmbition.java +++ b/Mage.Sets/src/mage/cards/i/IncreasingAmbition.java @@ -1,7 +1,6 @@ package mage.cards.i; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; @@ -75,9 +74,9 @@ class IncreasingAmbitionEffect extends SearchEffect { else { target = new TargetCardInLibrary(); } - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { - for (UUID cardId: (List)target.getTargets()) { + for (UUID cardId: target.getTargets()) { Card card = player.getLibrary().remove(cardId, game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/i/IncreasingVengeance.java b/Mage.Sets/src/mage/cards/i/IncreasingVengeance.java index 11e1d70dbb..34392a641b 100644 --- a/Mage.Sets/src/mage/cards/i/IncreasingVengeance.java +++ b/Mage.Sets/src/mage/cards/i/IncreasingVengeance.java @@ -76,7 +76,7 @@ class IncreasingVengeanceEffect extends OneShotEffect { if (spell != null) { StackObject stackObjectCopy = spell.createCopyOnStack(game, source, source.getControllerId(), true); if (stackObjectCopy instanceof Spell) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(((Spell) stackObjectCopy).getActivatedMessage(game)).toString()); + game.informPlayers(controller.getLogName() + ((Spell) stackObjectCopy).getActivatedMessage(game)); } Spell sourceSpell = (Spell) game.getStack().getStackObject(source.getSourceId()); if (sourceSpell != null) { diff --git a/Mage.Sets/src/mage/cards/i/IncubationDruid.java b/Mage.Sets/src/mage/cards/i/IncubationDruid.java new file mode 100644 index 0000000000..1dc49717df --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IncubationDruid.java @@ -0,0 +1,218 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Abilities; +import mage.abilities.Ability; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.ManaEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.mana.ActivatedManaAbilityImpl; +import mage.abilities.mana.SimpleManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IncubationDruid extends CardImpl { + + public IncubationDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(0); + this.toughness = new MageInt(2); + + // {T}: Add one mana of any type that a land you control could produce. If Incubation Druid has a +1/+1 counter on it, add three mana of that type instead. + this.addAbility(new SimpleManaAbility( + Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(), new TapSourceCost() + )); + + // {3}{G}{G}: Adapt 3. + this.addAbility(new AdaptAbility(3, "{3}{G}{G}")); + } + + private IncubationDruid(final IncubationDruid card) { + super(card); + } + + @Override + public IncubationDruid copy() { + return new IncubationDruid(this); + } +} + +class AnyColorLandsProduceManaEffect extends ManaEffect { + + private boolean inManaTypeCalculation = false; + + AnyColorLandsProduceManaEffect() { + super(); + staticText = "Add one mana of any type that a land you control could produce. " + + "If {this} has a +1/+1 counter on it, add three mana of that type instead."; + } + + private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + checkToFirePossibleEvents(getMana(game, source), game, source); + controller.getManaPool().addMana(getMana(game, source), game, source); + return true; + } + return false; + } + + @Override + public Mana produceMana(boolean netMana, Game game, Ability source) { + int manaAmount = getManaAmount(game, source); + Mana mana = new Mana(); + Mana types = getManaTypes(game, source); + Choice choice = new ChoiceColor(true); + choice.getChoices().clear(); + choice.setMessage("Pick a mana color"); + if (types.getBlack() > 0) { + choice.getChoices().add("Black"); + } + if (types.getRed() > 0) { + choice.getChoices().add("Red"); + } + if (types.getBlue() > 0) { + choice.getChoices().add("Blue"); + } + if (types.getGreen() > 0) { + choice.getChoices().add("Green"); + } + if (types.getWhite() > 0) { + choice.getChoices().add("White"); + } + if (types.getColorless() > 0) { + choice.getChoices().add("Colorless"); + } + if (types.getAny() > 0) { + choice.getChoices().add("Black"); + choice.getChoices().add("Red"); + choice.getChoices().add("Blue"); + choice.getChoices().add("Green"); + choice.getChoices().add("White"); + choice.getChoices().add("Colorless"); + } + if (!choice.getChoices().isEmpty()) { + Player player = game.getPlayer(source.getControllerId()); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else if (player == null || !player.choose(outcome, choice, game)) { + return null; + } + if (choice.getChoice() != null) { + switch (choice.getChoice()) { + case "Black": + mana.setBlack(manaAmount); + break; + case "Blue": + mana.setBlue(manaAmount); + break; + case "Red": + mana.setRed(manaAmount); + break; + case "Green": + mana.setGreen(manaAmount); + break; + case "White": + mana.setWhite(manaAmount); + break; + case "Colorless": + mana.setColorless(manaAmount); + break; + } + } + } + return mana; + } + + @Override + public List getNetMana(Game game, Ability source) { + int manaAmount = getManaAmount(game, source); + List netManas = new ArrayList<>(); + Mana types = getManaTypes(game, source); + if (types.getRed() > 0) { + netManas.add(new Mana(manaAmount, 0, 0, 0, 0, 0, 0, 0)); + } + if (types.getGreen() > 0) { + netManas.add(new Mana(0, manaAmount, 0, 0, 0, 0, 0, 0)); + } + if (types.getBlue() > 0) { + netManas.add(new Mana(0, 0, manaAmount, 0, 0, 0, 0, 0)); + } + if (types.getWhite() > 0) { + netManas.add(new Mana(0, 0, 0, manaAmount, 0, 0, 0, 0)); + } + if (types.getBlack() > 0) { + netManas.add(new Mana(0, 0, 0, 0, manaAmount, 0, 0, 0)); + } + if (types.getColorless() > 0) { + netManas.add(new Mana(0, 0, 0, 0, 0, 0, 0, manaAmount)); + } + if (types.getAny() > 0) { + netManas.add(new Mana(0, 0, 0, 0, 0, 0, manaAmount, 0)); + } + return netManas; + } + + @Override + public AnyColorLandsProduceManaEffect copy() { + return new AnyColorLandsProduceManaEffect(this); + } + + private int getManaAmount(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null && permanent.getCounters(game).getCount(CounterType.P1P1) > 0) { + return 3; + } + return 1; + } + + private Mana getManaTypes(Game game, Ability source) { + Mana types = new Mana(); + if (game == null || game.getPhase() == null) { + return types; + } + if (inManaTypeCalculation) { + return types; + } + inManaTypeCalculation = true; + List lands = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, source.getControllerId(), source.getSourceId(), game); + for (Permanent land : lands) { + Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); + for (ActivatedManaAbilityImpl ability : mana) { + if (!ability.equals(source) && ability.definesMana(game)) { + for (Mana netMana : ability.getNetMana(game)) { + types.add(netMana); + } + } + } + } + inManaTypeCalculation = false; + return types; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java new file mode 100644 index 0000000000..7604c2ab92 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IncubationIncongruity.java @@ -0,0 +1,81 @@ +package mage.cards.i; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.FrogLizardToken; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class IncubationIncongruity extends SplitCard { + + public IncubationIncongruity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, new CardType[]{CardType.INSTANT}, "{G/U}", "{1}{G}{U}", SpellAbilityType.SPLIT); + + // Incubation + // Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.getLeftHalfCard().getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(5), false, + new StaticValue(1), StaticFilters.FILTER_CARD_CREATURE_A, + Zone.LIBRARY, false, true, false, + Zone.HAND, false, false, false + ).setBackInRandomOrder(true)); + + // Incongruity + // Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token. + this.getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); + this.getRightHalfCard().getSpellAbility().addEffect(new IncongruityEffect()); + } + + private IncubationIncongruity(final IncubationIncongruity card) { + super(card); + } + + @Override + public IncubationIncongruity copy() { + return new IncubationIncongruity(this); + } +} + +class IncongruityEffect extends OneShotEffect { + + public IncongruityEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "That creature's controller creates a 3/3 green Frog Lizard creature token"; + } + + public IncongruityEffect(final IncongruityEffect effect) { + super(effect); + } + + @Override + public IncongruityEffect copy() { + return new IncongruityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if (permanent != null) { + FrogLizardToken token = new FrogLizardToken(); + token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/i/IncursionSpecialist.java b/Mage.Sets/src/mage/cards/i/IncursionSpecialist.java index 756b250d11..77df46b955 100644 --- a/Mage.Sets/src/mage/cards/i/IncursionSpecialist.java +++ b/Mage.Sets/src/mage/cards/i/IncursionSpecialist.java @@ -69,7 +69,7 @@ class IncursionTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { return true; } diff --git a/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java b/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java index cc65732992..dd20946857 100644 --- a/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java +++ b/Mage.Sets/src/mage/cards/i/IndomitableCreativity.java @@ -2,7 +2,6 @@ package mage.cards.i; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.*; import mage.constants.CardType; @@ -16,53 +15,64 @@ import mage.game.permanent.Permanent; import mage.players.Library; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; -import java.util.*; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** - * * @author LevelX2 */ public final class IndomitableCreativity extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifacts and/or creatures"); - - static { - filter.add(Predicates.or(new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE))); - } public IndomitableCreativity(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}{R}"); // Destroy X target artifacts and/or creatures. For each permanent destroyed this way, its controller reveals cards from the top of their library until an artifact or creature card is revealed and exiles that card. Those players put the exiled card onto the battlefield, then shuffle their libraries. - getSpellAbility().addEffect(new IndomitableCreativityEffect()); - this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addEffect(new IndomitableCreativityEffect()); + this.getSpellAbility().setTargetAdjuster(IndomitableCreativityAdjuster.instance); } public IndomitableCreativity(final IndomitableCreativity card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetPermanent(xValue, xValue, filter, false)); - } - } - @Override public IndomitableCreativity copy() { return new IndomitableCreativity(this); } } +enum IndomitableCreativityAdjuster implements TargetAdjuster { + instance; + private static final FilterPermanent filter = new FilterPermanent("artifacts and/or creatures"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE) + )); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetPermanent(xValue, xValue, filter, false)); + } +} + class IndomitableCreativityEffect extends OneShotEffect { public IndomitableCreativityEffect() { super(Outcome.Benefit); - this.staticText = "Destroy X target artifacts and/or creatures. For each permanent destroyed this way, its controller reveals cards from the top of their library until an artifact or creature card is revealed and exiles that card. Those players put the exiled card onto the battlefield, then shuffle their libraries"; + this.staticText = "Destroy X target artifacts and/or creatures. " + + "For each permanent destroyed this way, " + + "its controller reveals cards from the top of their library" + + " until an artifact or creature card is revealed and exiles that card. " + + "Those players put the exiled card onto the battlefield, then shuffle their libraries"; } public IndomitableCreativityEffect(final IndomitableCreativityEffect effect) { diff --git a/Mage.Sets/src/mage/cards/i/InexorableBlob.java b/Mage.Sets/src/mage/cards/i/InexorableBlob.java index 2d2a1d64ef..2e733c9c92 100644 --- a/Mage.Sets/src/mage/cards/i/InexorableBlob.java +++ b/Mage.Sets/src/mage/cards/i/InexorableBlob.java @@ -1,12 +1,13 @@ - package mage.cards.i; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,7 +15,6 @@ import mage.constants.SubType; import mage.game.permanent.token.InexorableBlobOozeToken; /** - * * @author fireshoes */ public final class InexorableBlob extends CardImpl { @@ -30,7 +30,8 @@ public final class InexorableBlob extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility(new CreateTokenEffect(new InexorableBlobOozeToken(), 1, true, true), false), DeliriumCondition.instance, "Delirium — Whenever {this} attacks and there are at least four card types among cards in your graveyard, " - + "create a 3/3 green Ooze creature token tapped and attacking.")); + + "create a 3/3 green Ooze creature token tapped and attacking.") + .addHint(DeliriumHint.instance)); } public InexorableBlob(final InexorableBlob card) { diff --git a/Mage.Sets/src/mage/cards/i/InexorableTide.java b/Mage.Sets/src/mage/cards/i/InexorableTide.java index 066b4b53d5..48bfa92cf5 100644 --- a/Mage.Sets/src/mage/cards/i/InexorableTide.java +++ b/Mage.Sets/src/mage/cards/i/InexorableTide.java @@ -1,28 +1,26 @@ - - package mage.cards.i; -import java.util.UUID; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author Loki, North */ public final class InexorableTide extends CardImpl { - public InexorableTide (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{U}{U}"); - + public InexorableTide(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); + // Whenever you cast a spell, proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.addAbility(new SpellCastControllerTriggeredAbility(new ProliferateEffect(), false)); } - public InexorableTide (final InexorableTide card) { + public InexorableTide(final InexorableTide card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/i/InfernalReckoning.java b/Mage.Sets/src/mage/cards/i/InfernalReckoning.java index 6c2a214602..1d1cc6ded2 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalReckoning.java +++ b/Mage.Sets/src/mage/cards/i/InfernalReckoning.java @@ -23,7 +23,7 @@ public final class InfernalReckoning extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public InfernalReckoning(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java b/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java new file mode 100644 index 0000000000..c346be1d1a --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InfernalSpawnOfEvil.java @@ -0,0 +1,104 @@ + +package mage.cards.i; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.CompositeCost; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.RevealSourceFromYourHandCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponentOrPlaneswalker; + +/** + * + * @author Ketsuban + */ +public final class InfernalSpawnOfEvil extends CardImpl { + + public InfernalSpawnOfEvil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{6}{B}{B}{B}"); + this.subtype.add(SubType.BEAST); + + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // 1B, Reveal Infernal Spawn of Evil from your hand, Say "It's coming!": + // Infernal Spawn of Evil deals 1 damage to target opponent or planeswalker. + // Activate this ability only during your upkeep and only once each turn. + Ability ability = new LimitedTimesPerTurnActivatedAbility(Zone.HAND, new DamageTargetEffect(1), + new CompositeCost( + new ManaCostsImpl("{1}{B}"), + new CompositeCost( + new RevealSourceFromYourHandCost(), + new SayCost("It's coming!"), + "Reveal {this} from your hand, Say \"It's coming!\""), + "{1}{B}, Reveal {this} from your hand, Say \"It's coming!\""), + 1, new IsStepCondition(PhaseStep.UPKEEP, true)); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + public InfernalSpawnOfEvil(final InfernalSpawnOfEvil card) { + super(card); + } + + @Override + public InfernalSpawnOfEvil copy() { + return new InfernalSpawnOfEvil(this); + } +} + +class SayCost extends CostImpl { + + private String message; + + public SayCost(String message) { + this.message = message; + } + + public SayCost(SayCost cost) { + super(cost); + this.message = cost.message; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + return true; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + game.informPlayers(controller.getLogName() + ": " + message); + return true; + } + + @Override + public Cost copy() { + return new SayCost(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InfernalTribute.java b/Mage.Sets/src/mage/cards/i/InfernalTribute.java index 028994e191..5402c969ab 100644 --- a/Mage.Sets/src/mage/cards/i/InfernalTribute.java +++ b/Mage.Sets/src/mage/cards/i/InfernalTribute.java @@ -22,10 +22,10 @@ import mage.target.common.TargetControlledPermanent; */ public final class InfernalTribute extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("a nontoken permanent"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("a nontoken permanent"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public InfernalTribute(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/InfernoHellion.java b/Mage.Sets/src/mage/cards/i/InfernoHellion.java index ed2b3254f7..859049b4c3 100644 --- a/Mage.Sets/src/mage/cards/i/InfernoHellion.java +++ b/Mage.Sets/src/mage/cards/i/InfernoHellion.java @@ -66,8 +66,8 @@ enum InfernoHellionCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcherAttacked = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - BlockedThisTurnWatcher watcherBlocked = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcherAttacked = game.getState().getWatcher(AttackedThisTurnWatcher.class); + BlockedThisTurnWatcher watcherBlocked = game.getState().getWatcher(BlockedThisTurnWatcher.class); MageObjectReference mor = new MageObjectReference(source.getSourceId(), game); if (watcherAttacked == null || watcherBlocked == null) { return false; diff --git a/Mage.Sets/src/mage/cards/i/InfernoTrap.java b/Mage.Sets/src/mage/cards/i/InfernoTrap.java index 8ac6aa5364..f2fcc17d1c 100644 --- a/Mage.Sets/src/mage/cards/i/InfernoTrap.java +++ b/Mage.Sets/src/mage/cards/i/InfernoTrap.java @@ -53,7 +53,7 @@ enum InfernoTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - InfernoTrapWatcher watcher = (InfernoTrapWatcher) game.getState().getWatchers().get(InfernoTrapWatcher.class.getSimpleName()); + InfernoTrapWatcher watcher = game.getState().getWatcher(InfernoTrapWatcher.class); if (watcher != null) { Set damagingCreatures = watcher.getDamagingCreatures(source.getControllerId()); return damagingCreatures.size() > 1; @@ -69,10 +69,10 @@ enum InfernoTrapCondition implements Condition { class InfernoTrapWatcher extends Watcher { - Map> playerDamagedByCreature = new HashMap<>(); + private Map> playerDamagedByCreature = new HashMap<>(); public InfernoTrapWatcher() { - super(InfernoTrapWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public InfernoTrapWatcher(final InfernoTrapWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/i/InfestedRoothold.java b/Mage.Sets/src/mage/cards/i/InfestedRoothold.java index c916d6075f..fd3c10075c 100644 --- a/Mage.Sets/src/mage/cards/i/InfestedRoothold.java +++ b/Mage.Sets/src/mage/cards/i/InfestedRoothold.java @@ -1,7 +1,6 @@ package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; @@ -11,22 +10,21 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.filter.FilterCard; import mage.filter.FilterSpell; import mage.filter.common.FilterArtifactCard; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.common.FilterArtifactSpell; import mage.game.permanent.token.InsectToken; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class InfestedRoothold extends CardImpl { - private final static FilterSpell filter = new FilterSpell("an artifact spell"); - - static { - filter.add(new CardTypePredicate(CardType.ARTIFACT)); - } + private static final FilterCard filter = new FilterArtifactCard("artifacts"); + private static final FilterSpell filter2 = new FilterArtifactSpell("an artifact spell"); public InfestedRoothold(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); @@ -39,10 +37,12 @@ public final class InfestedRoothold extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // Protection from artifacts - this.addAbility(new ProtectionAbility(new FilterArtifactCard("artifacts"))); + this.addAbility(new ProtectionAbility(filter)); // Whenever an opponent casts an artifact spell, you may create a 1/1 green Insect creature token. - this.addAbility(new SpellCastOpponentTriggeredAbility(new CreateTokenEffect(new InsectToken()), filter, true)); + this.addAbility(new SpellCastOpponentTriggeredAbility( + new CreateTokenEffect(new InsectToken()), filter2, true) + ); } diff --git a/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java b/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java index 66291875c5..1395f0085c 100644 --- a/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java +++ b/Mage.Sets/src/mage/cards/i/InfiltratorsMagemark.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.Effect; @@ -12,12 +10,7 @@ import mage.abilities.keyword.DefenderAbility; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -27,20 +20,22 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class InfiltratorsMagemark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control that are enchanted"); + static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } public InfiltratorsMagemark(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); this.subtype.add(SubType.AURA); @@ -51,7 +46,7 @@ public final class InfiltratorsMagemark extends CardImpl { Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); // Creatures you control that are enchanted get +1/+1 and can't be blocked except by creatures with defender. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1,1, Duration.WhileOnBattlefield, filter, false)); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false)); Effect effect = new InfiltratorsMagemarkCantBeBlockedAllEffect(filter, Duration.WhileOnBattlefield); ability.addEffect(effect); this.addAbility(ability); @@ -88,7 +83,7 @@ class InfiltratorsMagemarkCantBeBlockedAllEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().contains(DefenderAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java b/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java new file mode 100644 index 0000000000..b5155d9a87 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InfiniteAuthority.java @@ -0,0 +1,148 @@ + +package mage.cards.i; + +import java.util.Objects; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.common.delayed.AtTheEndOfCombatDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth & L_J + */ +public final class InfiniteAuthority extends CardImpl { + + public InfiniteAuthority(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{W}{W}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature. + this.addAbility(new InfiniteAuthorityTriggeredAbility()); + } + + public InfiniteAuthority(final InfiniteAuthority card) { + super(card); + } + + @Override + public InfiniteAuthority copy() { + return new InfiniteAuthority(this); + } +} + +class InfiniteAuthorityTriggeredAbility extends TriggeredAbilityImpl { + + InfiniteAuthorityTriggeredAbility() { + super(Zone.BATTLEFIELD, new CreateDelayedTriggeredAbilityEffect(new AtTheEndOfCombatDelayedTriggeredAbility(new InfiniteAuthorityEffect()))); + } + + InfiniteAuthorityTriggeredAbility(final InfiniteAuthorityTriggeredAbility ability) { + super(ability); + } + + @Override + public InfiniteAuthorityTriggeredAbility copy() { + return new InfiniteAuthorityTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent aura = game.getPermanentOrLKIBattlefield(sourceId); + if (aura != null) { + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(aura.getAttachedTo()); + if (enchantedCreature != null) { + Permanent blocker = game.getPermanent(event.getSourceId()); + Permanent blocked = game.getPermanent(event.getTargetId()); + Effect effect = this.getEffects().get(0); + if (blocker != null + && Objects.equals(blocked, enchantedCreature) + && blocker.getToughness().getValue() <= 3) { + effect.setTargetPointer(new FixedTarget(blocker.getId())); + return true; + } + if (blocked != null + && Objects.equals(blocker, enchantedCreature) + && blocked.getToughness().getValue() <= 3) { + effect.setTargetPointer(new FixedTarget(blocked.getId())); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever enchanted creature blocks or becomes blocked by a creature with toughness 3 or less, " + super.getRule(); + } +} + +class InfiniteAuthorityEffect extends OneShotEffect { + + InfiniteAuthorityEffect() { + super(Outcome.Detriment); + staticText = "destroy the other creature at end of combat. At the beginning of the next end step, if that creature was destroyed this way, put a +1/+1 counter on the first creature"; + } + + InfiniteAuthorityEffect(final InfiniteAuthorityEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (aura != null) { + Permanent enchantedCreature = game.getPermanentOrLKIBattlefield(aura.getAttachedTo()); + if (enchantedCreature != null) { + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (permanent.destroy(source.getSourceId(), game, false)) { + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + delayedAbility.getEffects().get(0).setTargetPointer(new FixedTarget(enchantedCreature, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); + } + return true; + } + } + } + return false; + } + + @Override + public InfiniteAuthorityEffect copy() { + return new InfiniteAuthorityEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InfusedArrows.java b/Mage.Sets/src/mage/cards/i/InfusedArrows.java index 5975fdc4fa..904cde8954 100644 --- a/Mage.Sets/src/mage/cards/i/InfusedArrows.java +++ b/Mage.Sets/src/mage/cards/i/InfusedArrows.java @@ -32,7 +32,7 @@ public final class InfusedArrows extends CardImpl { // Sunburst this.addAbility(new SunburstAbility(this)); // {tap}, Remove X charge counters from Infused Arrows: Target creature gets -X/-X until end of turn. - DynamicValue value = new SignInversionDynamicValue(new RemovedCountersForCostValue()); + DynamicValue value = new SignInversionDynamicValue(RemovedCountersForCostValue.instance); Effect effect = new BoostTargetEffect(value, value, Duration.EndOfTurn); effect.setText("Target creature gets -X/-X until end of turn"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/i/InkfathomWitch.java b/Mage.Sets/src/mage/cards/i/InkfathomWitch.java index 384933ba5b..aaeb94fa17 100644 --- a/Mage.Sets/src/mage/cards/i/InkfathomWitch.java +++ b/Mage.Sets/src/mage/cards/i/InkfathomWitch.java @@ -24,7 +24,7 @@ public final class InkfathomWitch extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each unblocked creature"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } public InkfathomWitch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/InnerCalmOuterStrength.java b/Mage.Sets/src/mage/cards/i/InnerCalmOuterStrength.java index 90e6f848e8..7dbf40bb73 100644 --- a/Mage.Sets/src/mage/cards/i/InnerCalmOuterStrength.java +++ b/Mage.Sets/src/mage/cards/i/InnerCalmOuterStrength.java @@ -25,7 +25,7 @@ public final class InnerCalmOuterStrength extends CardImpl { this.subtype.add(SubType.ARCANE); // Target creature gets +X/+X until end of turn, where X is the number of cards in your hand. - DynamicValue xValue= new CardsInControllerHandCount(); + DynamicValue xValue= CardsInControllerHandCount.instance; Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true); effect.setText("Target creature gets +X/+X until end of turn, where X is the number of cards in your hand"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/i/InnerFire.java b/Mage.Sets/src/mage/cards/i/InnerFire.java index d7f2671f73..42a4da2dd4 100644 --- a/Mage.Sets/src/mage/cards/i/InnerFire.java +++ b/Mage.Sets/src/mage/cards/i/InnerFire.java @@ -20,7 +20,7 @@ public final class InnerFire extends CardImpl { // Add {R} for each card in your hand. - this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), new CardsInControllerHandCount())); + this.getSpellAbility().addEffect(new DynamicManaEffect(Mana.RedMana(1), CardsInControllerHandCount.instance)); } public InnerFire(final InnerFire card) { diff --git a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java index 99e56fa80d..600e14d21f 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorExarch.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorExarch.java @@ -29,8 +29,8 @@ public final class InquisitorExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2)); Mode mode = new Mode(); - mode.getEffects().add(new LoseLifeTargetEffect(2)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new LoseLifeTargetEffect(2)); + mode.addTarget(new TargetPlayer()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/InquisitorsOx.java b/Mage.Sets/src/mage/cards/i/InquisitorsOx.java index be222161c9..7f78acaae8 100644 --- a/Mage.Sets/src/mage/cards/i/InquisitorsOx.java +++ b/Mage.Sets/src/mage/cards/i/InquisitorsOx.java @@ -1,7 +1,7 @@ - package mage.cards.i; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,13 +19,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class InquisitorsOx extends CardImpl { public InquisitorsOx(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.OX); this.power = new MageInt(2); this.toughness = new MageInt(5); @@ -34,6 +34,7 @@ public final class InquisitorsOx extends CardImpl { ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} gets +1/+0"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(VigilanceAbility.getInstance()), DeliriumCondition.instance, "and has vigilance as long as there are four or more card types among cards in your graveyard.")); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/InsatiableRakghoul.java b/Mage.Sets/src/mage/cards/i/InsatiableRakghoul.java index e62ce559f3..37b3660d76 100644 --- a/Mage.Sets/src/mage/cards/i/InsatiableRakghoul.java +++ b/Mage.Sets/src/mage/cards/i/InsatiableRakghoul.java @@ -62,7 +62,7 @@ class InsatiableRakghoulEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - NonArtifactCreaturesDiedWatcher watcher = (NonArtifactCreaturesDiedWatcher) game.getState().getWatchers().get(NonArtifactCreaturesDiedWatcher.class.getSimpleName()); + NonArtifactCreaturesDiedWatcher watcher = game.getState().getWatcher(NonArtifactCreaturesDiedWatcher.class); if (watcher != null && watcher.conditionMet()) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { @@ -83,7 +83,7 @@ class InsatiableRakghoulEffect extends OneShotEffect { class NonArtifactCreaturesDiedWatcher extends Watcher { public NonArtifactCreaturesDiedWatcher() { - super(NonArtifactCreaturesDiedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public NonArtifactCreaturesDiedWatcher(final NonArtifactCreaturesDiedWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/i/InsidiousDreams.java b/Mage.Sets/src/mage/cards/i/InsidiousDreams.java index 43047ff972..fecfde77a6 100644 --- a/Mage.Sets/src/mage/cards/i/InsidiousDreams.java +++ b/Mage.Sets/src/mage/cards/i/InsidiousDreams.java @@ -1,7 +1,6 @@ package mage.cards.i; -import java.util.List; import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; @@ -74,13 +73,13 @@ class InsidiousDreamsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - int amount = new GetXValue().calculate(game, source, this); + int amount = GetXValue.instance.calculate(game, source, this); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Cards chosen = new CardsImpl(); - for (UUID cardId : (List) target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().remove(cardId, game); chosen.add(card); } diff --git a/Mage.Sets/src/mage/cards/i/InsidiousWill.java b/Mage.Sets/src/mage/cards/i/InsidiousWill.java index 48904be376..6d62b408f7 100644 --- a/Mage.Sets/src/mage/cards/i/InsidiousWill.java +++ b/Mage.Sets/src/mage/cards/i/InsidiousWill.java @@ -31,14 +31,14 @@ public final class InsidiousWill extends CardImpl { // You may choose new targets for target spell.; Mode mode = new Mode(); - mode.getEffects().add(new ChooseNewTargetsTargetEffect()); - mode.getTargets().add(new TargetSpell()); + mode.addEffect(new ChooseNewTargetsTargetEffect()); + mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); // Copy target instant or sorcery spell. You may choose new targets for the copy. mode = new Mode(); - mode.getEffects().add(new CopyTargetSpellEffect()); - mode.getTargets().add(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); + mode.addEffect(new CopyTargetSpellEffect()); + mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/Insist.java b/Mage.Sets/src/mage/cards/i/Insist.java index 5c79086b5e..8d2f4d559b 100644 --- a/Mage.Sets/src/mage/cards/i/Insist.java +++ b/Mage.Sets/src/mage/cards/i/Insist.java @@ -65,7 +65,7 @@ class InsistEffect extends ContinuousRuleModifyingEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - InsistWatcher watcher = (InsistWatcher) game.getState().getWatchers().get(InsistWatcher.class.getSimpleName(), source.getControllerId()); + InsistWatcher watcher = game.getState().getWatcher(InsistWatcher.class, source.getControllerId()); if (watcher != null) { watcher.setReady(); } @@ -93,7 +93,7 @@ class InsistEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - InsistWatcher watcher = (InsistWatcher) game.getState().getWatchers().get(InsistWatcher.class.getSimpleName(), source.getControllerId()); + InsistWatcher watcher = game.getState().getWatcher(InsistWatcher.class, source.getControllerId()); return spell != null && watcher != null && watcher.isUncounterable(spell.getId()); } } @@ -104,7 +104,7 @@ class InsistWatcher extends Watcher { protected UUID uncounterableSpell; InsistWatcher() { - super(InsistWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } InsistWatcher(final InsistWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/i/InspiredSphinx.java b/Mage.Sets/src/mage/cards/i/InspiredSphinx.java new file mode 100644 index 0000000000..22e2f94442 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiredSphinx.java @@ -0,0 +1,51 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.OpponentsCount; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.ThopterColorlessToken; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class InspiredSphinx extends CardImpl { + + public InspiredSphinx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Inspired Sphinx enters the battlefield, draw cards equal to the number of opponents you have. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(OpponentsCount.instance).setText("draw cards equal to the number of opponents you have") + )); + + // {3}{U}: Create a colorless 1/1 Thopter artifact creature token with flying. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new ThopterColorlessToken()), new ManaCostsImpl<>("{3}{U}"))); + } + + public InspiredSphinx(final InspiredSphinx card) { + super(card); + } + + @Override + public InspiredSphinx copy() { + return new InspiredSphinx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InspiringCommander.java b/Mage.Sets/src/mage/cards/i/InspiringCommander.java new file mode 100644 index 0000000000..073076f25e --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InspiringCommander.java @@ -0,0 +1,59 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class InspiringCommander extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature with power 2 or less"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public InspiringCommander(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Whenever another creature with power 2 or less enters the battlefield under your control, you gain 1 life and draw a card. + Effect effect1 = new GainLifeEffect(1); + Effect effect2 = new DrawCardSourceControllerEffect(1); + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, effect1, filter, false); + ability.addEffect(effect2.setText("and draw a card")); + this.addAbility(ability); + } + + public InspiringCommander(final InspiringCommander card) { + super(card); + } + + @Override + public InspiringCommander copy() { + return new InspiringCommander(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InsultInjury.java b/Mage.Sets/src/mage/cards/i/InsultInjury.java index 43f13ffdce..5250fa9ba3 100644 --- a/Mage.Sets/src/mage/cards/i/InsultInjury.java +++ b/Mage.Sets/src/mage/cards/i/InsultInjury.java @@ -38,7 +38,7 @@ public final class InsultInjury extends SplitCard { // to // Injury // Injury deals 2 damage to target creature and 2 damage to target player. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); getRightHalfCard().getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); getRightHalfCard().getSpellAbility().addEffect(new InjuryEffect()); diff --git a/Mage.Sets/src/mage/cards/i/IntangibleVirtue.java b/Mage.Sets/src/mage/cards/i/IntangibleVirtue.java index 7ac02d6658..8bc764d587 100644 --- a/Mage.Sets/src/mage/cards/i/IntangibleVirtue.java +++ b/Mage.Sets/src/mage/cards/i/IntangibleVirtue.java @@ -23,7 +23,7 @@ public final class IntangibleVirtue extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public IntangibleVirtue(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/Interdict.java b/Mage.Sets/src/mage/cards/i/Interdict.java index 0e590cd6d3..6f81bc53b5 100644 --- a/Mage.Sets/src/mage/cards/i/Interdict.java +++ b/Mage.Sets/src/mage/cards/i/Interdict.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -20,11 +18,11 @@ import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; import mage.game.stack.StackObject; import mage.target.common.TargetActivatedAbility; -import mage.target.common.TargetActivatedOrTriggeredAbility; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Interdict extends CardImpl { @@ -126,7 +124,7 @@ class InterdictCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/i/InterplanarBeacon.java b/Mage.Sets/src/mage/cards/i/InterplanarBeacon.java new file mode 100644 index 0000000000..7c4b9483b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InterplanarBeacon.java @@ -0,0 +1,95 @@ +package mage.cards.i; + +import mage.ConditionalMana; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.abilities.mana.ConditionalAnyColorManaAbility; +import mage.abilities.mana.builder.ConditionalManaBuilder; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.stack.Spell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InterplanarBeacon extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a planeswalker spell"); + + static { + filter.add(new CardTypePredicate(CardType.PLANESWALKER)); + } + + public InterplanarBeacon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Whenever you cast a planeswalker spell, you gain 1 life. + this.addAbility(new SpellCastControllerTriggeredAbility( + new GainLifeEffect(1), filter, false + )); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {1}, {T}: Add two mana of different colors. Spend this mana only to cast planeswalker spells. + Ability ability = new ConditionalAnyColorManaAbility( + new GenericManaCost(1), 2, + new InterplanarBeaconManaBuilder() + ); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private InterplanarBeacon(final InterplanarBeacon card) { + super(card); + } + + @Override + public InterplanarBeacon copy() { + return new InterplanarBeacon(this); + } +} + +class InterplanarBeaconManaBuilder extends ConditionalManaBuilder { + + @Override + public ConditionalMana build(Object... options) { + return new InterplanarBeaconConditionalMana(this.mana); + } + + @Override + public String getRule() { + return "Spend this mana only to cast planeswalker spells"; + } +} + +class InterplanarBeaconConditionalMana extends ConditionalMana { + + InterplanarBeaconConditionalMana(Mana mana) { + super(mana); + this.staticText = "Spend this mana only to cast planeswalker spells"; + addCondition(new InterplanarBeaconManaCondition()); + } +} + +class InterplanarBeaconManaCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + MageObject object = source.getSourceObject(game); + return object instanceof Spell && object.isPlaneswalker(); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/i/Intervene.java b/Mage.Sets/src/mage/cards/i/Intervene.java index e4585a019e..7fc9a864cc 100644 --- a/Mage.Sets/src/mage/cards/i/Intervene.java +++ b/Mage.Sets/src/mage/cards/i/Intervene.java @@ -17,7 +17,7 @@ import mage.target.TargetSpell; */ public final class Intervene extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a creature"); + private static final FilterSpell filter = new FilterSpell("spell that targets a creature"); static { filter.add(new TargetsPermanentPredicate(new FilterCreaturePermanent())); diff --git a/Mage.Sets/src/mage/cards/i/IntetTheDreamer.java b/Mage.Sets/src/mage/cards/i/IntetTheDreamer.java index 1073af6244..dad56547b8 100644 --- a/Mage.Sets/src/mage/cards/i/IntetTheDreamer.java +++ b/Mage.Sets/src/mage/cards/i/IntetTheDreamer.java @@ -1,8 +1,5 @@ - package mage.cards.i; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; import mage.MageInt; import mage.MageObject; @@ -40,13 +37,17 @@ public final class IntetTheDreamer extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); + // Whenever Intet, the Dreamer deals combat damage to a player, you may pay {2}{U}. If you do, exile the top card of your library face down. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new DoIfCostPaid(new IntetTheDreamerExileEffect(), new ManaCostsImpl("{2}{U}")), false, true)); + // You may look at that card for as long as it remains exiled. this.addAbility(new SimpleStaticAbility(Zone.ALL, new IntetTheDreamerLookEffect())); + // You may play that card without paying its mana cost for as long as Intet remains on the battlefield. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new IntetTheDreamerCastEffect())); + } public IntetTheDreamer(final IntetTheDreamer card) { @@ -76,17 +77,20 @@ class IntetTheDreamerExileEffect extends OneShotEffect { if (controller != null) { Card card = controller.getLibrary().getFromTop(game); MageObject sourceObject = source.getSourceObject(game); - if (card != null && sourceObject != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + if (card != null + && sourceObject != null) { card.setFaceDown(true, game); - controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); + controller.moveCardsToExile( + card, + source, + game, + false, + CardUtil.getExileZoneId(game, + source.getSourceId(), + sourceObject.getZoneChangeCounter(game)), // sourceObject must be used due to source not working correctly + sourceObject.getIdName()); card.setFaceDown(true, game); - Set exileZones = (Set) game.getState().getValue(IntetTheDreamer.VALUE_PREFIX + source.getSourceId().toString()); - if (exileZones == null) { - exileZones = new HashSet<>(); - game.getState().setValue(IntetTheDreamer.VALUE_PREFIX + source.getSourceId().toString(), exileZones); - } - exileZones.add(exileZoneId); + game.getState().setValue("Exiled_IntetTheDreamer" + card.getId(), Boolean.TRUE); return true; } } @@ -122,20 +126,29 @@ class IntetTheDreamerCastEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && game.getState().getZone(objectId) == Zone.EXILED) { + if (affectedControllerId.equals(source.getControllerId())) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { + if (controller != null + && sourceObject != null) { Card card = game.getCard(objectId); - if (card != null && card.isFaceDown(game)) { - ExileZone zone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); - if (zone != null && zone.contains(card.getId())/* && CardUtil.cardCanBePlayedNow(card, controller.getId(), game)*/) { + if (card != null + && card.isFaceDown(game)) { + ExileZone zone = game.getExile().getExileZone( + CardUtil.getExileZoneId(game, + source.getSourceId(), + sourceObject.getZoneChangeCounter(game))); // sourceObject must be used due to source not working correctly + if (zone != null + && zone.contains(card.getId())) { if (card.isLand()) { - if (game.canPlaySorcery(controller.getId()) && game.getPlayer(controller.getId()).canPlayLand()) { + if (game.canPlaySorcery(controller.getId()) + && game.getPlayer(controller.getId()).canPlayLand()) { return controller.chooseUse(outcome, "Play " + card.getIdName() + '?', source, game); } } else { - controller.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); + controller.setCastSourceIdWithAlternateMana(objectId, + null, + card.getSpellAbility().getCosts()); return true; } } @@ -170,24 +183,14 @@ class IntetTheDreamerLookEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && game.getState().getZone(objectId) == Zone.EXILED) { + if (affectedControllerId.equals(source.getControllerId())) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { + if (controller != null) { Card card = game.getCard(objectId); - if (card != null && card.isFaceDown(game)) { - Set exileZones = (Set) game.getState().getValue(IntetTheDreamer.VALUE_PREFIX + source.getSourceId().toString()); - if (exileZones != null) { - for (ExileZone exileZone : game.getExile().getExileZones()) { - if (exileZone.contains(objectId)) { - if (!exileZones.contains(exileZone.getId())) { - return false; - } - } - } - return true; - } - } + return (card != null + && card.isFaceDown(game) + && game.getExile().containsId(card.getId(), game) + && (Boolean) game.getState().getValue("Exiled_IntetTheDreamer" + card.getId())); } } return false; diff --git a/Mage.Sets/src/mage/cards/i/IntimidationBolt.java b/Mage.Sets/src/mage/cards/i/IntimidationBolt.java index e101c287a0..da02123903 100644 --- a/Mage.Sets/src/mage/cards/i/IntimidationBolt.java +++ b/Mage.Sets/src/mage/cards/i/IntimidationBolt.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.DamageTargetEffect; @@ -13,23 +11,22 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class IntimidationBolt extends CardImpl { public IntimidationBolt(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}{W}"); - - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{W}"); // Intimidation Bolt deals 3 damage to target creature. Other creatures can't attack this turn. this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addEffect(new IntimidationEffect(Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + } public IntimidationBolt(final IntimidationBolt card) { @@ -55,14 +52,11 @@ class IntimidationEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (!permanent.getId().equals(source.getFirstTarget())) { - return true; - } - return false; + return !permanent.getId().equals(source.getFirstTarget()); } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/i/IntrepidProvisioner.java b/Mage.Sets/src/mage/cards/i/IntrepidProvisioner.java index e7c88c0416..35baafc5e9 100644 --- a/Mage.Sets/src/mage/cards/i/IntrepidProvisioner.java +++ b/Mage.Sets/src/mage/cards/i/IntrepidProvisioner.java @@ -25,7 +25,7 @@ public final class IntrepidProvisioner extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.HUMAN, "another target Human you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public IntrepidProvisioner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/Intuition.java b/Mage.Sets/src/mage/cards/i/Intuition.java index f4146f636d..35c8571b42 100644 --- a/Mage.Sets/src/mage/cards/i/Intuition.java +++ b/Mage.Sets/src/mage/cards/i/Intuition.java @@ -3,6 +3,7 @@ package mage.cards.i; import java.util.List; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.SearchEffect; import mage.cards.Card; @@ -21,13 +22,12 @@ import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; /** - * * @author Plopman */ public final class Intuition extends CardImpl { public Intuition(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Search your library for three cards and reveal them. Target opponent chooses one. Put that card into your hand and the rest into your graveyard. Then shuffle your library. @@ -47,7 +47,6 @@ public final class Intuition extends CardImpl { class IntuitionEffect extends SearchEffect { - public IntuitionEffect() { super(new TargetCardInLibrary(3, new FilterCard()), Outcome.Benefit); @@ -70,22 +69,22 @@ class IntuitionEffect extends SearchEffect { Player opponent = game.getPlayer(source.getFirstTarget()); if (controller == null || opponent == null) return false; - - if (controller.getLibrary().size() >= 3 && controller.searchLibrary(target, game)) { - + + if (controller.getLibrary().size() >= 3 && controller.searchLibrary(target, source, game)) { + if (target.getTargets().size() == 3) { Cards cards = new CardsImpl(); - for (UUID cardId: (List)target.getTargets()) { + for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); if (card != null) { cards.add(card); } } controller.revealCards("Reveal", cards, game); - + TargetCard targetCard = new TargetCard(Zone.LIBRARY, new FilterCard()); - - while(!opponent.choose(Outcome.Neutral, cards, targetCard, game)) { + + while (!opponent.choose(Outcome.Neutral, cards, targetCard, game)) { if (!opponent.canRespond()) { return false; } @@ -100,7 +99,7 @@ class IntuitionEffect extends SearchEffect { controller.shuffleLibrary(source, game); return true; } - + controller.shuffleLibrary(source, game); return false; } diff --git a/Mage.Sets/src/mage/cards/i/InvadeTheCity.java b/Mage.Sets/src/mage/cards/i/InvadeTheCity.java new file mode 100644 index 0000000000..5f66f9a070 --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvadeTheCity.java @@ -0,0 +1,35 @@ +package mage.cards.i; + +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterInstantOrSorceryCard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class InvadeTheCity extends CardImpl { + + public static final FilterInstantOrSorceryCard filter + = new FilterInstantOrSorceryCard("instant and sorcery cards"); + + public InvadeTheCity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}{R}"); + + // Amass X, where X is the number of instant and sorcery cards in your graveyard. + this.getSpellAbility().addEffect(new AmassEffect(new CardsInControllerGraveyardCount(filter))); + } + + private InvadeTheCity(final InvadeTheCity card) { + super(card); + } + + @Override + public InvadeTheCity copy() { + return new InvadeTheCity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvadingManticore.java b/Mage.Sets/src/mage/cards/i/InvadingManticore.java new file mode 100644 index 0000000000..ced90dd8ec --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/InvadingManticore.java @@ -0,0 +1,38 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.AmassEffect; +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 InvadingManticore extends CardImpl { + + public InvadingManticore(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.MANTICORE); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Invading Manticore enters the battlefield, amass 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(2))); + } + + private InvadingManticore(final InvadingManticore card) { + super(card); + } + + @Override + public InvadingManticore copy() { + return new InvadingManticore(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/InvasiveSpecies.java b/Mage.Sets/src/mage/cards/i/InvasiveSpecies.java index 193d45dbd9..3a2302b937 100644 --- a/Mage.Sets/src/mage/cards/i/InvasiveSpecies.java +++ b/Mage.Sets/src/mage/cards/i/InvasiveSpecies.java @@ -21,7 +21,7 @@ public final class InvasiveSpecies extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another permanent you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public InvasiveSpecies(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java b/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java index b9e404d48c..f071d97989 100644 --- a/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java +++ b/Mage.Sets/src/mage/cards/i/InvasiveSurgery.java @@ -1,12 +1,13 @@ - package mage.cards.i; import java.util.UUID; + import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,25 +20,24 @@ import mage.players.Player; import mage.target.TargetSpell; /** - * * @author LevelX2 */ public final class InvasiveSurgery extends CardImpl { - private final static FilterSpell filter = new FilterSpell("sorcery spell"); + private static final FilterSpell filter = new FilterSpell("sorcery spell"); static { filter.add(new CardTypePredicate(CardType.SORCERY)); } public InvasiveSurgery(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Counter target sorcery spell. // Delirium — If there are four or more card types among cards in your graveyard, search the graveyard, hand, and library of that spell's controller for any number of cards with the same name as that spell, exile those cards, then that player shuffles their library. this.getSpellAbility().addEffect(new InvasiveSurgeryEffect()); this.getSpellAbility().addTarget(new TargetSpell(filter)); - + this.getSpellAbility().addHint(DeliriumHint.instance); } public InvasiveSurgery(final InvasiveSurgery card) { diff --git a/Mage.Sets/src/mage/cards/i/InvertInvent.java b/Mage.Sets/src/mage/cards/i/InvertInvent.java index fbeccdf652..787a79d070 100644 --- a/Mage.Sets/src/mage/cards/i/InvertInvent.java +++ b/Mage.Sets/src/mage/cards/i/InvertInvent.java @@ -114,14 +114,14 @@ class InventEffect extends OneShotEffect { } Cards cards = new CardsImpl(); TargetCardInLibrary target = new TargetCardInLibrary(filter1); - if (player.searchLibrary(target, game, false)) { + if (player.searchLibrary(target, source, game, false)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.add(card); } } target = new TargetCardInLibrary(filter2); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { cards.add(card); diff --git a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java index d28ed87d4a..2f36ea7217 100644 --- a/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java +++ b/Mage.Sets/src/mage/cards/i/InvigoratedRampage.java @@ -36,11 +36,11 @@ public final class InvigoratedRampage extends CardImpl { Mode mode = new Mode(); effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); effect.setText("Two target creatures each get +2/+0"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gain trample until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(2)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java b/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java index 5576aff06b..a61d8a4d1f 100644 --- a/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java +++ b/Mage.Sets/src/mage/cards/i/InvokeTheFiremind.java @@ -21,10 +21,10 @@ public final class InvokeTheFiremind extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}{R}"); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.instance)); Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(new ManacostVariableValue())); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IridescentDrake.java b/Mage.Sets/src/mage/cards/i/IridescentDrake.java index 348549ee27..d9f08f524a 100644 --- a/Mage.Sets/src/mage/cards/i/IridescentDrake.java +++ b/Mage.Sets/src/mage/cards/i/IridescentDrake.java @@ -14,6 +14,8 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.other.AuraCardCanAttachToPermanentId; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,6 +28,12 @@ import mage.target.common.TargetCardInGraveyard; * @author TheElk801 */ public final class IridescentDrake extends CardImpl { + + private static final FilterCard filter = new FilterCard("Aura from a graveyard"); + + static { + filter.add(new SubtypePredicate(SubType.AURA)); + } public IridescentDrake(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); @@ -39,7 +47,7 @@ public final class IridescentDrake extends CardImpl { // When Iridescent Drake enters the battlefield, put target Aura card from a graveyard onto the battlefield under your control attached to Iridescent Drake. Ability ability = new EntersBattlefieldTriggeredAbility(new IridescentDrakeEffect()); - ability.addTarget(new TargetCardInGraveyard()); + ability.addTarget(new TargetCardInGraveyard(filter)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IroasGodOfVictory.java b/Mage.Sets/src/mage/cards/i/IroasGodOfVictory.java index d152a61be4..b964156ea1 100644 --- a/Mage.Sets/src/mage/cards/i/IroasGodOfVictory.java +++ b/Mage.Sets/src/mage/cards/i/IroasGodOfVictory.java @@ -29,7 +29,7 @@ public final class IroasGodOfVictory extends CardImpl { private static final FilterControlledCreatureInPlay filterAttacking = new FilterControlledCreatureInPlay("attacking creatures you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filterAttacking.getCreatureFilter().add(new AttackingPredicate()); + filterAttacking.getCreatureFilter().add(AttackingPredicate.instance); } public IroasGodOfVictory(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/IronBully.java b/Mage.Sets/src/mage/cards/i/IronBully.java new file mode 100644 index 0000000000..ca3d101cfc --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IronBully.java @@ -0,0 +1,48 @@ +package mage.cards.i; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.MenaceAbility; +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 IronBully extends CardImpl { + + public IronBully(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); + + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Menace + this.addAbility(new MenaceAbility()); + + // When Iron Bully enters the battlefield, put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private IronBully(final IronBully card) { + super(card); + } + + @Override + public IronBully copy() { + return new IronBully(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IroncladKrovod.java b/Mage.Sets/src/mage/cards/i/IroncladKrovod.java new file mode 100644 index 0000000000..040cf4347c --- /dev/null +++ b/Mage.Sets/src/mage/cards/i/IroncladKrovod.java @@ -0,0 +1,32 @@ +package mage.cards.i; + +import mage.MageInt; +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 IroncladKrovod extends CardImpl { + + public IroncladKrovod(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + } + + private IroncladKrovod(final IroncladKrovod card) { + super(card); + } + + @Override + public IroncladKrovod copy() { + return new IroncladKrovod(this); + } +} diff --git a/Mage.Sets/src/mage/cards/i/IroncladSlayer.java b/Mage.Sets/src/mage/cards/i/IroncladSlayer.java index 7bd1a2382c..2a020c3865 100644 --- a/Mage.Sets/src/mage/cards/i/IroncladSlayer.java +++ b/Mage.Sets/src/mage/cards/i/IroncladSlayer.java @@ -22,7 +22,7 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class IroncladSlayer extends CardImpl { - private final static FilterCard filter = new FilterCard("Aura or Equipment card from your graveyard"); + private static final FilterCard filter = new FilterCard("Aura or Equipment card from your graveyard"); static { filter.add(Predicates.or(new SubtypePredicate(SubType.AURA), new SubtypePredicate(SubType.EQUIPMENT))); diff --git a/Mage.Sets/src/mage/cards/i/IronclawCurse.java b/Mage.Sets/src/mage/cards/i/IronclawCurse.java index 93d16b6851..9e8309490f 100644 --- a/Mage.Sets/src/mage/cards/i/IronclawCurse.java +++ b/Mage.Sets/src/mage/cards/i/IronclawCurse.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -10,19 +8,15 @@ import mage.abilities.effects.common.continuous.BoostEnchantedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class IronclawCurse extends CardImpl { @@ -72,7 +66,10 @@ class IronclawCurseEffect extends CantBlockAttachedEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (enchantment == null) { return false; diff --git a/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java b/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java index c130b759ab..0dd3df0283 100644 --- a/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java +++ b/Mage.Sets/src/mage/cards/i/IshkanahGrafwidow.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,6 +10,8 @@ import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.hint.ValueHint; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -24,8 +24,9 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.permanent.token.SpiderToken; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class IshkanahGrafwidow extends CardImpl { @@ -37,7 +38,7 @@ public final class IshkanahGrafwidow extends CardImpl { } public IshkanahGrafwidow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SPIDER); this.power = new MageInt(3); @@ -52,13 +53,15 @@ public final class IshkanahGrafwidow extends CardImpl { new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new SpiderToken(), 3), false), DeliriumCondition.instance, "Delirium — When {this} enters the battlefield, if there are four or more card types among cards in your graveyard, " - + "create three 1/2 green Spider creature tokens with reach."); + + "create three 1/2 green Spider creature tokens with reach."); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); // {5}{B}: Target opponent loses 1 life for each Spider you control. PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter); ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeTargetEffect(count), new ManaCostsImpl("{6}{B}")); ability.addTarget(new TargetOpponent()); + ability.addHint(new ValueHint("Spiders you control", count)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/i/IslandSanctuary.java b/Mage.Sets/src/mage/cards/i/IslandSanctuary.java index aabf94d689..b5effdc0e1 100644 --- a/Mage.Sets/src/mage/cards/i/IslandSanctuary.java +++ b/Mage.Sets/src/mage/cards/i/IslandSanctuary.java @@ -47,7 +47,7 @@ public final class IslandSanctuary extends CardImpl { class IslandSanctuaryEffect extends ReplacementEffectImpl { - private final static FilterCreaturePermanent notFlyingorIslandwalkCreatures = new FilterCreaturePermanent("except by creatures with flying and/or islandwalk"); + private static final FilterCreaturePermanent notFlyingorIslandwalkCreatures = new FilterCreaturePermanent("except by creatures with flying and/or islandwalk"); static { notFlyingorIslandwalkCreatures.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); diff --git a/Mage.Sets/src/mage/cards/i/IsochronScepter.java b/Mage.Sets/src/mage/cards/i/IsochronScepter.java index b23831f56b..832952667c 100644 --- a/Mage.Sets/src/mage/cards/i/IsochronScepter.java +++ b/Mage.Sets/src/mage/cards/i/IsochronScepter.java @@ -130,7 +130,7 @@ class IsochronScepterCopyEffect extends OneShotEffect { if (scepter != null && scepter.getImprinted() != null && !scepter.getImprinted().isEmpty()) { Card imprintedInstant = game.getCard(scepter.getImprinted().get(0)); if (imprintedInstant != null && game.getState().getZone(imprintedInstant.getId()) == Zone.EXILED) { - if (controller.chooseUse(outcome, new StringBuilder("Create a copy of ").append(imprintedInstant.getName()).append('?').toString(), source, game)) { + if (controller.chooseUse(outcome, "Create a copy of " + imprintedInstant.getName() + '?', source, game)) { Card copiedCard = game.copyCard(imprintedInstant, source, source.getControllerId()); if (copiedCard != null) { game.getExile().add(source.getSourceId(), "", copiedCard); diff --git a/Mage.Sets/src/mage/cards/i/IsolationCell.java b/Mage.Sets/src/mage/cards/i/IsolationCell.java index edff565497..29db787d7e 100644 --- a/Mage.Sets/src/mage/cards/i/IsolationCell.java +++ b/Mage.Sets/src/mage/cards/i/IsolationCell.java @@ -64,7 +64,8 @@ class IsolationCellTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(controllerId).contains(event.getPlayerId())) { Card card = game.getCard(event.getSourceId()); - if (card != null && card.isCreature()) { + if (card != null + && card.isCreature()) { this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } @@ -100,7 +101,7 @@ class IsolationCellEffect extends OneShotEffect { if (player != null) { GenericManaCost cost = new GenericManaCost(2); if (!cost.pay(source, game, player.getId(), player.getId(), false)) { - player.damage(2, source.getSourceId(), game, false, true); + player.loseLife(2, game, false); } return true; } diff --git a/Mage.Sets/src/mage/cards/i/IsolationZone.java b/Mage.Sets/src/mage/cards/i/IsolationZone.java index 3867b799b9..3ae0ee0781 100644 --- a/Mage.Sets/src/mage/cards/i/IsolationZone.java +++ b/Mage.Sets/src/mage/cards/i/IsolationZone.java @@ -28,7 +28,7 @@ import mage.util.CardUtil; */ public final class IsolationZone extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("creature or enchantment an opponent controls"); + private static final FilterPermanent filter = new FilterPermanent("creature or enchantment an opponent controls"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), diff --git a/Mage.Sets/src/mage/cards/i/IsperiaTheInscrutable.java b/Mage.Sets/src/mage/cards/i/IsperiaTheInscrutable.java index e417bed22c..25d5ee7a91 100644 --- a/Mage.Sets/src/mage/cards/i/IsperiaTheInscrutable.java +++ b/Mage.Sets/src/mage/cards/i/IsperiaTheInscrutable.java @@ -79,7 +79,7 @@ class IsperiaTheInscrutableEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - Object object = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + Object object = game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (player != null && object instanceof String) { player.revealCards(player.getLogName() + " hand", player.getHand(), game, true); String namedCard = (String) object; diff --git a/Mage.Sets/src/mage/cards/i/ItThatBetrays.java b/Mage.Sets/src/mage/cards/i/ItThatBetrays.java index fda419264f..e559bed72e 100644 --- a/Mage.Sets/src/mage/cards/i/ItThatBetrays.java +++ b/Mage.Sets/src/mage/cards/i/ItThatBetrays.java @@ -23,7 +23,7 @@ public final class ItThatBetrays extends CardImpl { private static final FilterPermanent FILTER = new FilterPermanent("nontoken permanent"); static { - FILTER.add(Predicates.not(new TokenPredicate())); + FILTER.add(Predicates.not(TokenPredicate.instance)); } public ItThatBetrays(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java b/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java index 4c5bdf205f..b7ab2b0a63 100644 --- a/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java +++ b/Mage.Sets/src/mage/cards/i/ItlimocCradleOfTheSun.java @@ -11,6 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SuperType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -20,11 +21,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public final class ItlimocCradleOfTheSun extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("creature you control"); - static { - filter.add(new CardTypePredicate(CardType.CREATURE)); - } public ItlimocCradleOfTheSun(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); @@ -38,7 +35,7 @@ public final class ItlimocCradleOfTheSun extends CardImpl { this.addAbility(new GreenManaAbility()); // {T}: Add {G} for each creature you control. - this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), new PermanentsOnBattlefieldCount(filter))); + this.addAbility(new DynamicManaAbility(Mana.GreenMana(1), new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED))); } public ItlimocCradleOfTheSun(final ItlimocCradleOfTheSun card) { diff --git a/Mage.Sets/src/mage/cards/i/IvoryCharm.java b/Mage.Sets/src/mage/cards/i/IvoryCharm.java index 6a98c5c041..90a62baf27 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryCharm.java +++ b/Mage.Sets/src/mage/cards/i/IvoryCharm.java @@ -26,13 +26,13 @@ public final class IvoryCharm extends CardImpl { this.getSpellAbility().addEffect(new BoostAllEffect(-2, 0, Duration.EndOfTurn)); // or tap target creature Mode mode = new Mode(); - mode.getEffects().add(new TapTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new TapTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or prevent the next 1 damage that would be dealt to any target this turn. mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 1)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IvoryGuardians.java b/Mage.Sets/src/mage/cards/i/IvoryGuardians.java index 8bbb182421..5298e44ca4 100644 --- a/Mage.Sets/src/mage/cards/i/IvoryGuardians.java +++ b/Mage.Sets/src/mage/cards/i/IvoryGuardians.java @@ -33,7 +33,7 @@ public final class IvoryGuardians extends CardImpl { static { controlFilter.add(new ColorPredicate(ObjectColor.RED)); - controlFilter.add(Predicates.not(new TokenPredicate())); + controlFilter.add(Predicates.not(TokenPredicate.instance)); boostFilter.add(new NamePredicate("Ivory Guardians")); } diff --git a/Mage.Sets/src/mage/cards/i/IvyLaneDenizen.java b/Mage.Sets/src/mage/cards/i/IvyLaneDenizen.java index 56e556a59e..b914b2dc36 100644 --- a/Mage.Sets/src/mage/cards/i/IvyLaneDenizen.java +++ b/Mage.Sets/src/mage/cards/i/IvyLaneDenizen.java @@ -27,7 +27,7 @@ public final class IvyLaneDenizen extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another green creature"); static { filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public IvyLaneDenizen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/IxalansBinding.java b/Mage.Sets/src/mage/cards/i/IxalansBinding.java index 471a3ada5c..a1424f478f 100644 --- a/Mage.Sets/src/mage/cards/i/IxalansBinding.java +++ b/Mage.Sets/src/mage/cards/i/IxalansBinding.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -12,11 +10,7 @@ import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterNonlandPermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.ExileZone; @@ -26,13 +20,14 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class IxalansBinding extends CardImpl { - private final static FilterNonlandPermanent filter = new FilterNonlandPermanent(); + private static final FilterNonlandPermanent filter = new FilterNonlandPermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -80,10 +75,10 @@ class IxalansBindingReplacementEffect extends ContinuousRuleModifyingEffectImpl @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - Card card = game.getCard(event.getSourceId()); - if(event.getPlayerId().equals(source.getControllerId())){ + if (event.getPlayerId().equals(source.getControllerId())) { return false; } + Card card = game.getCard(event.getSourceId()); if (sourcePermanent != null && card != null) { UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (exileZone != null) { diff --git a/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java b/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java index 8871c562f0..615e564691 100644 --- a/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java +++ b/Mage.Sets/src/mage/cards/i/IxidorRealitySculptor.java @@ -26,8 +26,8 @@ public final class IxidorRealitySculptor extends CardImpl { private static final FilterCreaturePermanent filterTarget = new FilterCreaturePermanent("face-down creature"); static { - filter.add(new FaceDownPredicate()); - filterTarget.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); + filterTarget.add(FaceDownPredicate.instance); } public IxidorRealitySculptor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/Ixidron.java b/Mage.Sets/src/mage/cards/i/Ixidron.java index 89fbe73855..a84f448357 100644 --- a/Mage.Sets/src/mage/cards/i/Ixidron.java +++ b/Mage.Sets/src/mage/cards/i/Ixidron.java @@ -31,9 +31,9 @@ public final class Ixidron extends CardImpl { private static final FilterCreaturePermanent filterTurnFaceDown = new FilterCreaturePermanent("other nontoken creatures"); static { - filter.add(new FaceDownPredicate()); - filterTurnFaceDown.add(new AnotherPredicate()); - filterTurnFaceDown.add(Predicates.not(new TokenPredicate())); + filter.add(FaceDownPredicate.instance); + filterTurnFaceDown.add(AnotherPredicate.instance); + filterTurnFaceDown.add(Predicates.not(TokenPredicate.instance)); } public Ixidron(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/i/IzzetCharm.java b/Mage.Sets/src/mage/cards/i/IzzetCharm.java index d21d500d66..92f255d6c8 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetCharm.java +++ b/Mage.Sets/src/mage/cards/i/IzzetCharm.java @@ -37,13 +37,13 @@ public final class IzzetCharm extends CardImpl { // or Izzet Charm deals 2 damage to target creature; Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(2)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new DamageTargetEffect(2)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or draw two cards, then discard two cards. mode = new Mode(); - mode.getEffects().add(new DrawDiscardControllerEffect(2, 2)); + mode.addEffect(new DrawDiscardControllerEffect(2, 2)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java index ee90f7d8f8..84f9257a7f 100644 --- a/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java +++ b/Mage.Sets/src/mage/cards/i/IzzetStaticaster.java @@ -1,7 +1,5 @@ - package mage.cards.i; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,8 +10,8 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.NamePredicate; @@ -21,15 +19,17 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class IzzetStaticaster extends CardImpl { public IzzetStaticaster(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -79,7 +79,7 @@ class IzzetStaticasterDamageEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java new file mode 100644 index 0000000000..bbaeeef62d --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JaceArcaneStrategist.java @@ -0,0 +1,108 @@ +package mage.cards.j; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.combat.CantBeBlockedAllEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JaceArcaneStrategist extends CardImpl { + + public JaceArcaneStrategist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.JACE); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control. + this.addAbility(new JaceArcaneStrategistTriggeredAbility()); + + // +1: Draw a card. + this.addAbility(new LoyaltyAbility(new DrawCardSourceControllerEffect(1), 1)); + + // -7: Creatures you control can't be blocked this turn. + this.addAbility(new LoyaltyAbility(new CantBeBlockedAllEffect( + StaticFilters.FILTER_CONTROLLED_CREATURE, Duration.EndOfTurn + ), -7)); + } + + private JaceArcaneStrategist(final JaceArcaneStrategist card) { + super(card); + } + + @Override + public JaceArcaneStrategist copy() { + return new JaceArcaneStrategist(this); + } +} + +class JaceArcaneStrategistTriggeredAbility extends TriggeredAbilityImpl { + + private boolean triggeredOnce = false; + private boolean triggeredTwice = false; + + JaceArcaneStrategistTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); + this.addTarget(new TargetControlledCreaturePermanent()); + } + + private JaceArcaneStrategistTriggeredAbility(final JaceArcaneStrategistTriggeredAbility ability) { + super(ability); + this.triggeredOnce = ability.triggeredOnce; + this.triggeredTwice = ability.triggeredTwice; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DREW_CARD + || event.getType() == GameEvent.EventType.END_PHASE_POST; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.END_PHASE_POST) { + triggeredOnce = triggeredTwice = false; + return false; + } + if (event.getType() == GameEvent.EventType.DREW_CARD + && event.getPlayerId().equals(controllerId)) { + if (triggeredOnce) { + if (triggeredTwice) { + return false; + } else { + triggeredTwice = true; + return true; + } + } else { + triggeredOnce = true; + return false; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control."; + } + + @Override + public JaceArcaneStrategistTriggeredAbility copy() { + return new JaceArcaneStrategistTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java index 09ebb7644e..f4030e7148 100644 --- a/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java +++ b/Mage.Sets/src/mage/cards/j/JaceArchitectOfThought.java @@ -1,7 +1,8 @@ - package mage.cards.j; import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; import java.util.Set; import java.util.UUID; import mage.MageObjectReference; @@ -9,7 +10,6 @@ import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.Card; @@ -24,7 +24,10 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.FilterPlayer; import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.other.PlayerIdPredicate; import mage.game.ExileZone; import mage.game.Game; import mage.game.events.GameEvent; @@ -32,6 +35,7 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetCard; +import mage.target.TargetPlayer; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; @@ -119,9 +123,9 @@ class JaceArchitectOfThoughtDelayedTriggeredAbility extends DelayedTriggeredAbil @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(getControllerId()).contains(event.getPlayerId())) { - for (Effect effect : getEffects()) { + getEffects().forEach((effect) -> { effect.setTargetPointer(new FixedTarget(event.getSourceId())); - } + }); return true; } return false; @@ -180,7 +184,6 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { if (opponent == null) { opponent = game.getPlayer(opponents.iterator().next()); } - TargetCard target = new TargetCard(0, allCards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); target.setNotTarget(true); opponent.choose(Outcome.Neutral, allCards, target, game); @@ -195,7 +198,7 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { boolean pileChoice = player.choosePile(Outcome.Neutral, "Choose a pile to to put into your hand.", new ArrayList<>(pile1.getCards(game)), - new ArrayList<>(allCards.getCards(game)), game); + new ArrayList<>(pile2.getCards(game)), game); game.informPlayers(player.getLogName() + " chose pile" + (pileChoice ? "1" : "2")); player.moveCards(pileChoice ? pile1 : pile2, Zone.HAND, source, game); player.putCardsOnBottomOfLibrary(pileChoice ? pile2 : pile1, game, source, true); @@ -206,9 +209,9 @@ class JaceArchitectOfThoughtEffect2 extends OneShotEffect { private void postPileToLog(String pileName, Set cards, Game game) { StringBuilder message = new StringBuilder(pileName).append(": "); - for (Card card : cards) { + cards.forEach((card) -> { message.append(card.getName()).append(' '); - } + }); if (cards.isEmpty()) { message.append(" (empty)"); } @@ -239,30 +242,65 @@ class JaceArchitectOfThoughtEffect3 extends OneShotEffect { if (controller == null || sourcePermanent == null) { return false; } - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - String playerName = new StringBuilder(player.getLogName()).append("'s").toString(); - if (source.isControlledBy(player.getId())) { - playerName = "your"; - } - TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard(new StringBuilder("nonland card from ").append(playerName).append(" library").toString())); - if (controller.searchLibrary(target, game, playerId)) { - UUID targetId = target.getFirstTarget(); - Card card = player.getLibrary().remove(targetId, game); - if (card != null) { - controller.moveCardToExileWithInfo(card, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); - } - } - player.shuffleLibrary(source, game); + if (controller.chooseUse(Outcome.Benefit, "Look at all players' libraries before card select?", null, game)) { + game.informPlayers(controller.getLogName() + " is looking at all players' libraries."); + controller.lookAtAllLibraries(source, game); } - + List playerList = new ArrayList<>(); + playerList.addAll(game.getState().getPlayersInRange(controller.getId(), game)); + Set checkList = new HashSet<>(); + while (!playerList.isEmpty()) { + FilterPlayer filter = new FilterPlayer(); + List playerPredicates = new ArrayList<>(); + playerList.forEach((playerId) -> { + playerPredicates.add(new PlayerIdPredicate(playerId)); + }); + filter.add(Predicates.or(playerPredicates)); + TargetPlayer targetPlayer = new TargetPlayer(1, 1, true, filter); + targetPlayer.setRequired(!checkList.containsAll(playerList)); + if (controller.chooseTarget(outcome, targetPlayer, source, game)) { + UUID playerId = targetPlayer.getFirstTarget(); + Player player = game.getPlayer(playerId); + if (player != null) { + String playerName = player.getLogName() + "'s"; + if (source.isControlledBy(player.getId())) { + playerName = "your"; + } + TargetCardInLibrary target = new TargetCardInLibrary(new FilterNonlandCard("nonland card from " + playerName + " library")); + if (controller.searchLibrary(target, source, game, playerId, !checkList.contains(playerId))) { + checkList.add(playerId); + UUID targetId = target.getFirstTarget(); + Card card = player.getLibrary().remove(targetId, game); + if (card != null) { + controller.moveCardsToExile(card, source, game, true, CardUtil.getCardExileZoneId(game, source), sourcePermanent.getName()); + playerList.remove(playerId); + } + } else { + playerList.remove(playerId); + } + } else { + playerList.remove(playerId); + } + } else { + break; + } + playerList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player == null + || !player.canRespond())).forEachOrdered((player) -> { + playerList.remove(player.getId()); + }); + } + checkList.stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> { + player.shuffleLibrary(source, game); + }); ExileZone jaceExileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); if (jaceExileZone == null) { return true; } FilterCard filter = new FilterCard("card to cast without mana costs"); TargetCardInExile target = new TargetCardInExile(filter, source.getSourceId()); - while (jaceExileZone.count(filter, game) > 0 && controller.choose(Outcome.PlayForFree, jaceExileZone, target, game)) { + while (jaceExileZone.count(filter, game) > 0 + && controller.chooseUse(Outcome.Benefit, "Cast another spell from exile zone for free?", source, game)) { + controller.choose(Outcome.PlayForFree, jaceExileZone, target, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { if (controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game))) { diff --git a/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java b/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java index 089eb70003..762da47ab1 100644 --- a/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java +++ b/Mage.Sets/src/mage/cards/j/JaceTheLivingGuildpact.java @@ -30,7 +30,7 @@ public final class JaceTheLivingGuildpact extends CardImpl { private static final FilterPermanent filter = new FilterNonlandPermanent("another target nonland permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JaceTheLivingGuildpact(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java b/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java index a823f6d030..0476ec9d8a 100644 --- a/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java +++ b/Mage.Sets/src/mage/cards/j/JaceTheMindSculptor.java @@ -90,8 +90,7 @@ class JaceTheMindSculptorEffect1 extends OneShotEffect { if (controller != null && player != null) { Card card = player.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("Jace, the Mind Sculptor", cards, game); if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", source, game)) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); diff --git a/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java b/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java new file mode 100644 index 0000000000..e6feb931d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JaceWielderOfMysteries.java @@ -0,0 +1,136 @@ +package mage.cards.j; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +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.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class JaceWielderOfMysteries extends CardImpl { + + public JaceWielderOfMysteries(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.JACE); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // If you would draw a card while your library has no cards in it, you win the game instead. + this.addAbility(new SimpleStaticAbility(new JaceWielderOfMysteriesContinuousEffect())); + + // +1 Target player puts the top two cards of their library into their graveyard. Draw a card. + Ability ability = new LoyaltyAbility(new PutLibraryIntoGraveTargetEffect(2), 1); + ability.addTarget(new TargetPlayer()); + ability.addEffect(new DrawCardSourceControllerEffect(1)); + this.addAbility(ability); + + // -8: Draw seven cards. Then if your library has no cards in it, you win the game. + this.addAbility(new LoyaltyAbility(new JaceWielderOfMysteriesEffect(), -8)); + } + + private JaceWielderOfMysteries(final JaceWielderOfMysteries card) { + super(card); + } + + @Override + public JaceWielderOfMysteries copy() { + return new JaceWielderOfMysteries(this); + } +} + +class JaceWielderOfMysteriesContinuousEffect extends ReplacementEffectImpl { + + JaceWielderOfMysteriesContinuousEffect() { + super(Duration.WhileOnBattlefield, Benefit); + staticText = "If you would draw a card while your library has no cards in it, you win the game instead"; + } + + private JaceWielderOfMysteriesContinuousEffect(final JaceWielderOfMysteriesContinuousEffect effect) { + super(effect); + } + + @Override + public JaceWielderOfMysteriesContinuousEffect copy() { + return new JaceWielderOfMysteriesContinuousEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(event.getPlayerId()); + if (player != null) { + player.won(game); + } + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.EMPTY_DRAW; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getPlayerId().equals(source.getControllerId())) { + Player player = game.getPlayer(event.getPlayerId()); + if (player != null && !player.hasLost() && player.isEmptyDraw()) { + return true; + } + } + return false; + } +} + +class JaceWielderOfMysteriesEffect extends OneShotEffect { + + JaceWielderOfMysteriesEffect() { + super(Benefit); + staticText = "Draw seven cards. Then if your library has no cards in it, you win the game."; + } + + private JaceWielderOfMysteriesEffect(final JaceWielderOfMysteriesEffect effect) { + super(effect); + } + + @Override + public JaceWielderOfMysteriesEffect copy() { + return new JaceWielderOfMysteriesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(7, game); + if (!player.getLibrary().hasCards()) { + player.won(game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/JacesArchivist.java b/Mage.Sets/src/mage/cards/j/JacesArchivist.java index 525800c3c7..a6934dd862 100644 --- a/Mage.Sets/src/mage/cards/j/JacesArchivist.java +++ b/Mage.Sets/src/mage/cards/j/JacesArchivist.java @@ -10,6 +10,7 @@ import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.ColoredManaSymbol; @@ -62,23 +63,24 @@ class JacesArchivistEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { int maxDiscarded = 0; Player controller = game.getPlayer(source.getControllerId()); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int discarded = player.getHand().size(); - player.discard(discarded, false, source, game); - if (discarded > maxDiscarded) { - maxDiscarded = discarded; + if(controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Cards discardedCards = player.discard(player.getHand().size(), false, source, game); + if (discardedCards.size() > maxDiscarded) { + maxDiscarded = discardedCards.size(); + } + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.drawCards(maxDiscarded, game); } } } - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.drawCards(maxDiscarded, game); - } - } - return true; } diff --git a/Mage.Sets/src/mage/cards/j/JacesProjection.java b/Mage.Sets/src/mage/cards/j/JacesProjection.java new file mode 100644 index 0000000000..e81b392100 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JacesProjection.java @@ -0,0 +1,57 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DrawCardControllerTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +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.filter.FilterPermanent; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JacesProjection extends CardImpl { + + private static final FilterPermanent filter = new FilterPlaneswalkerPermanent(SubType.JACE); + + public JacesProjection(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.WIZARD); + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you draw a card, put a +1/+1 counter on Jace's Projection. + this.addAbility(new DrawCardControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false + )); + + // {3}{U}: Put a loyalty counter on target Jace planeswalker. + Ability ability = new SimpleActivatedAbility( + new AddCountersTargetEffect(CounterType.LOYALTY.createInstance()), new ManaCostsImpl("{3}{U}") + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private JacesProjection(final JacesProjection card) { + super(card); + } + + @Override + public JacesProjection copy() { + return new JacesProjection(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JacesRuse.java b/Mage.Sets/src/mage/cards/j/JacesRuse.java new file mode 100644 index 0000000000..42a1eea4b0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JacesRuse.java @@ -0,0 +1,42 @@ +package mage.cards.j; + +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryGraveyardPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JacesRuse extends CardImpl { + + private static final FilterCard filter = new FilterCard("Jace, Arcane Strategist"); + + static { + filter.add(new NamePredicate("Jace, Arcane Strategist")); + } + + public JacesRuse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{U}"); + + // Return up to two target creatures to their owner's hand. You may search your library and/or graveyard for a card named Jace, Arcane Strategist, reveal it, and put it into your hand. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new SearchLibraryGraveyardPutInHandEffect(filter, false, true)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + private JacesRuse(final JacesRuse card) { + super(card); + } + + @Override + public JacesRuse copy() { + return new JacesRuse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JacesTriumph.java b/Mage.Sets/src/mage/cards/j/JacesTriumph.java new file mode 100644 index 0000000000..12ea23dd71 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JacesTriumph.java @@ -0,0 +1,42 @@ +package mage.cards.j; + +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JacesTriumph extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent(SubType.JACE); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public JacesTriumph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); + + // Draw two cards. If you control a Jace planeswalker, draw three cards instead. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DrawCardSourceControllerEffect(3), new DrawCardSourceControllerEffect(2), + condition, "Draw two cards. If you control a Jace planeswalker, draw three cards instead." + )); + } + + private JacesTriumph(final JacesTriumph card) { + super(card); + } + + @Override + public JacesTriumph copy() { + return new JacesTriumph(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java index 5048c5792b..ea713bf87d 100644 --- a/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java +++ b/Mage.Sets/src/mage/cards/j/JaddiLifestrider.java @@ -53,7 +53,7 @@ class JaddiLifestriderEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public JaddiLifestriderEffect() { @@ -78,7 +78,7 @@ class JaddiLifestriderEffect extends OneShotEffect { } } } - if (tappedAmount > 0) { + if (tappedAmount > 0 && you != null) { you.gainLife(tappedAmount * 2, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/j/JadeBearer.java b/Mage.Sets/src/mage/cards/j/JadeBearer.java index 9401aac3d9..422df6fc88 100644 --- a/Mage.Sets/src/mage/cards/j/JadeBearer.java +++ b/Mage.Sets/src/mage/cards/j/JadeBearer.java @@ -24,7 +24,7 @@ public final class JadeBearer extends CardImpl { private static final FilterCreaturePermanent filterYourAnotherMerfolk = new FilterCreaturePermanent(); static { - filterYourAnotherMerfolk.add(new AnotherPredicate()); + filterYourAnotherMerfolk.add(AnotherPredicate.instance); filterYourAnotherMerfolk.add(new SubtypePredicate(SubType.MERFOLK)); filterYourAnotherMerfolk.add(new ControllerPredicate(TargetController.YOU)); filterYourAnotherMerfolk.setMessage("another " + SubType.MERFOLK.toString() + " you control"); diff --git a/Mage.Sets/src/mage/cards/j/JadeMonolith.java b/Mage.Sets/src/mage/cards/j/JadeMonolith.java index ba66a726d2..91cec8c1ba 100644 --- a/Mage.Sets/src/mage/cards/j/JadeMonolith.java +++ b/Mage.Sets/src/mage/cards/j/JadeMonolith.java @@ -79,9 +79,9 @@ class JadeMonolithRedirectionEffect extends ReplacementEffectImpl { Permanent targetCreature = game.getPermanent(source.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); DamageEvent damageEvent = (DamageEvent) event; - if (controller != null && targetCreature != null) { + if (controller != null && targetCreature != null && sourceObject != null) { controller.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); - StringBuilder sb = new StringBuilder(sourceObject != null ? sourceObject.getLogName() : ""); + StringBuilder sb = new StringBuilder(sourceObject.getLogName()); sb.append(": ").append(damageEvent.getAmount()).append(" damage redirected from ").append(targetCreature.getLogName()); sb.append(" to ").append(controller.getLogName()); game.informPlayers(sb.toString()); diff --git a/Mage.Sets/src/mage/cards/j/JandorsRing.java b/Mage.Sets/src/mage/cards/j/JandorsRing.java index 58d2326103..eab1ac4cfb 100644 --- a/Mage.Sets/src/mage/cards/j/JandorsRing.java +++ b/Mage.Sets/src/mage/cards/j/JandorsRing.java @@ -71,7 +71,7 @@ class JandorsRingEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - JandorsRingWatcher watcher = (JandorsRingWatcher) game.getState().getWatchers().get(JandorsRingWatcher.class.getSimpleName()); + JandorsRingWatcher watcher = game.getState().getWatcher(JandorsRingWatcher.class); if (watcher != null) { UUID cardId = watcher.getLastDrewCard(source.getControllerId()); Card card = game.getCard(cardId); @@ -81,7 +81,9 @@ class JandorsRingEffect extends OneShotEffect { DiscardCardYouChooseTargetEffect effect = new DiscardCardYouChooseTargetEffect(filter, TargetController.YOU); if (effect.apply(game, source)) {//Conditional was already checked, card should be in hand, but if for some weird reason it fails, the card won't be drawn, although the cost will already be paid Player controller = game.getPlayer(source.getControllerId()); - controller.drawCards(1, game); + if(controller != null) { + controller.drawCards(1, game); + } } } return true; @@ -92,10 +94,10 @@ class JandorsRingEffect extends OneShotEffect { class JandorsRingWatcher extends Watcher { - Map lastDrawnCards = new HashMap<>(); + private Map lastDrawnCards = new HashMap<>(); public JandorsRingWatcher() { - super(JandorsRingWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public JandorsRingWatcher(final JandorsRingWatcher watcher) { @@ -132,10 +134,10 @@ enum WatchedCardInHandCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - JandorsRingWatcher watcher = (JandorsRingWatcher) game.getState().getWatchers().get(JandorsRingWatcher.class.getSimpleName()); + JandorsRingWatcher watcher = game.getState().getWatcher(JandorsRingWatcher.class); return watcher != null - && watcher.lastDrawnCards != null && game.getPlayer(source.getControllerId()).getHand().contains(watcher.getLastDrewCard(source.getControllerId())); + && game.getPlayer(source.getControllerId()).getHand().contains(watcher.getLastDrewCard(source.getControllerId())); } @Override diff --git a/Mage.Sets/src/mage/cards/j/JangoFett.java b/Mage.Sets/src/mage/cards/j/JangoFett.java index 92b5523080..fef5ecd781 100644 --- a/Mage.Sets/src/mage/cards/j/JangoFett.java +++ b/Mage.Sets/src/mage/cards/j/JangoFett.java @@ -1,37 +1,30 @@ - package mage.cards.j; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.HasteAbility; import mage.abilities.keyword.MenaceAbility; 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.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.CounterPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.TargetPermanent; import mage.target.common.TargetOpponentsCreaturePermanent; +import java.util.UUID; + /** - * * @author Styxo/spjspj */ public final class JangoFett extends CardImpl { @@ -55,7 +48,7 @@ public final class JangoFett extends CardImpl { ability.addTarget(new TargetOpponentsCreaturePermanent()); this.addAbility(ability); - // Whenever Jango Fett attacks, it deals X damage to defending player and target creature he or she controls, where X is the number of creatures defending player controls with a bounty counter on them. + // Whenever Jango Fett attacks, it gets +X/+0, where X is the number of creatures defending player controls with a bounty counter on them this.addAbility(new JangoFettTriggeredAbility(new JangoFettEffect(), false)); } @@ -97,11 +90,6 @@ class JangoFettTriggeredAbility extends TriggeredAbilityImpl { if (event.getSourceId().equals(this.getSourceId())) { UUID defenderId = game.getCombat().getDefendingPlayerId(getSourceId(), game); if (defenderId != null) { - this.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("target creature defending player controls"); - filter.add(new ControllerIdPredicate(defenderId)); - TargetPermanent target = new TargetPermanent(filter); - this.addTarget(target); return true; } } @@ -125,8 +113,8 @@ class JangoFettTriggeredAbility extends TriggeredAbilityImpl { class JangoFettEffect extends OneShotEffect { public JangoFettEffect() { - super(Outcome.Damage); - this.staticText = "it deals X damage to defending player and target creature he or she controls, where X is the number of creatures defending player controls with a bounty counter on them"; + super(Outcome.BoostCreature); + this.staticText = "it gets +X/+0, where X is the number of creatures defending player controls with a bounty counter on them"; } public JangoFettEffect(final JangoFettEffect ability) { @@ -158,14 +146,7 @@ class JangoFettEffect extends OneShotEffect { return false; } - Permanent targetCreature = game.getPermanent(source.getFirstTarget()); - if (targetCreature != null) { - targetCreature.damage(count, source.getSourceId(), game, false, true); - } - Player defender = game.getPlayer(defenderId); - defender.damage(count, source.getSourceId(), game, false, true); - + game.addEffect(new BoostSourceEffect(count, 0, Duration.WhileOnBattlefield), source); return true; } - } diff --git a/Mage.Sets/src/mage/cards/j/JarJarBinks.java b/Mage.Sets/src/mage/cards/j/JarJarBinks.java index 242ca0f019..d9fb62510e 100644 --- a/Mage.Sets/src/mage/cards/j/JarJarBinks.java +++ b/Mage.Sets/src/mage/cards/j/JarJarBinks.java @@ -163,7 +163,7 @@ class JarJarBinksTapEffect extends OneShotEffect { } } if (permanentToTap != null) { - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(" chosen creature: ").append(permanentToTap.getName()).toString()); + game.informPlayers(sourcePermanent.getName() + " chosen creature: " + permanentToTap.getName()); return permanentToTap.tap(game); } return true; diff --git a/Mage.Sets/src/mage/cards/j/JaradGolgariLichLord.java b/Mage.Sets/src/mage/cards/j/JaradGolgariLichLord.java index f3226b5564..e895731ea5 100644 --- a/Mage.Sets/src/mage/cards/j/JaradGolgariLichLord.java +++ b/Mage.Sets/src/mage/cards/j/JaradGolgariLichLord.java @@ -53,7 +53,7 @@ public final class JaradGolgariLichLord extends CardImpl { this.addAbility(ability); // {1}{B}{G}, Sacrifice another creature: Each opponent loses life equal to the sacrificed creature's power. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(new SacrificeCostCreaturesPower()), new ManaCostsImpl("{1}{B}{G}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(SacrificeCostCreaturesPower.instance), new ManaCostsImpl("{1}{B}{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, false))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/j/JaradsOrders.java b/Mage.Sets/src/mage/cards/j/JaradsOrders.java index 4f3d01ef3f..bbee2a378b 100644 --- a/Mage.Sets/src/mage/cards/j/JaradsOrders.java +++ b/Mage.Sets/src/mage/cards/j/JaradsOrders.java @@ -1,7 +1,6 @@ package mage.cards.j; -import java.util.List; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -65,10 +64,10 @@ class JaradsOrdersEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 2, new FilterCreatureCard("creature cards")); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); - for (UUID cardId: (List)target.getTargets()) { + for (UUID cardId: target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); revealed.add(card); } diff --git a/Mage.Sets/src/mage/cards/j/JayaBallardTaskMage.java b/Mage.Sets/src/mage/cards/j/JayaBallardTaskMage.java index c6198ccf28..2939117b8b 100644 --- a/Mage.Sets/src/mage/cards/j/JayaBallardTaskMage.java +++ b/Mage.Sets/src/mage/cards/j/JayaBallardTaskMage.java @@ -103,7 +103,7 @@ class CantRegenerateEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getType() == EventType.REGENERATE) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(event.getTargetId(), game); } diff --git a/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java b/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java new file mode 100644 index 0000000000..9a38e5d761 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JayaVeneratedFiremage.java @@ -0,0 +1,108 @@ +package mage.cards.j; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JayaVeneratedFiremage extends CardImpl { + + public JayaVeneratedFiremage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.JAYA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // If another red source you control would deal damage to a permanent or player, it deals that much damage plus 1 to that permanent or player instead. + this.addAbility(new SimpleStaticAbility(new JayaVeneratedFiremageEffect())); + + // -2: Jaya, Venerated Firemage deals 2 damage tot any target. + Ability ability = new LoyaltyAbility(new DamageTargetEffect(2), -2); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private JayaVeneratedFiremage(final JayaVeneratedFiremage card) { + super(card); + } + + @Override + public JayaVeneratedFiremage copy() { + return new JayaVeneratedFiremage(this); + } +} + +class JayaVeneratedFiremageEffect extends ReplacementEffectImpl { + + JayaVeneratedFiremageEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If another red source you control would deal damage to a permanent or player, " + + "it deals that much damage plus 1 to that permanent or player instead."; + } + + private JayaVeneratedFiremageEffect(final JayaVeneratedFiremageEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + switch (event.getType()) { + case DAMAGE_CREATURE: + case DAMAGE_PLANESWALKER: + case DAMAGE_PLAYER: + return true; + default: + return false; + } + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (source.isControlledBy(game.getControllerId(event.getSourceId()))) { + MageObject sourceObject; + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); + if (sourcePermanent == null) { + sourceObject = game.getObject(event.getSourceId()); + } else { + sourceObject = sourcePermanent; + } + return sourceObject != null && sourceObject.getColor(game).isRed() + && !sourceObject.getId().equals(source.getSourceId()); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(CardUtil.addWithOverflowCheck(event.getAmount(), 1)); + return false; + } + + @Override + public JayaVeneratedFiremageEffect copy() { + return new JayaVeneratedFiremageEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/j/JayasGreeting.java b/Mage.Sets/src/mage/cards/j/JayasGreeting.java new file mode 100644 index 0000000000..12cf5687a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JayasGreeting.java @@ -0,0 +1,34 @@ +package mage.cards.j; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JayasGreeting extends CardImpl { + + public JayasGreeting(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Jaya's Greeting deals 3 damage to target creature. Scry 1. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private JayasGreeting(final JayasGreeting card) { + super(card); + } + + @Override + public JayasGreeting copy() { + return new JayasGreeting(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java b/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java index b1e6320f94..7f04db0559 100644 --- a/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java +++ b/Mage.Sets/src/mage/cards/j/JayasImmolatingInferno.java @@ -25,7 +25,7 @@ public final class JayasImmolatingInferno extends CardImpl { this.addAbility(new LegendarySpellAbility()); // Jaya's Immolating Inferno deals X damage to each of up to three targets. - Effect effect = new DamageTargetEffect(new ManacostVariableValue()); + Effect effect = new DamageTargetEffect(ManacostVariableValue.instance); effect.setText("{this} deals X damage to each of up to three targets"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTarget(1, 3)); diff --git a/Mage.Sets/src/mage/cards/j/JediInstructor.java b/Mage.Sets/src/mage/cards/j/JediInstructor.java index 4665dabb37..bcdfd16169 100644 --- a/Mage.Sets/src/mage/cards/j/JediInstructor.java +++ b/Mage.Sets/src/mage/cards/j/JediInstructor.java @@ -25,7 +25,7 @@ public final class JediInstructor extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JediInstructor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JediSentinel.java b/Mage.Sets/src/mage/cards/j/JediSentinel.java index 6fd1a7eda8..95eeddae9f 100644 --- a/Mage.Sets/src/mage/cards/j/JediSentinel.java +++ b/Mage.Sets/src/mage/cards/j/JediSentinel.java @@ -30,7 +30,7 @@ public final class JediSentinel extends CardImpl { private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creature you don't control"); static { - filter1.add(new AnotherPredicate()); + filter1.add(AnotherPredicate.instance); filter2.add(new ControllerPredicate(TargetController.NOT_YOU)); } diff --git a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java index d0c8ab237b..1e76e9844c 100644 --- a/Mage.Sets/src/mage/cards/j/JeeringInstigator.java +++ b/Mage.Sets/src/mage/cards/j/JeeringInstigator.java @@ -31,7 +31,7 @@ public final class JeeringInstigator extends CardImpl { static final private FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JeeringInstigator(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java index d4d7341f1a..4dc59ed8f2 100644 --- a/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java +++ b/Mage.Sets/src/mage/cards/j/JelevaNephaliasScourge.java @@ -1,4 +1,3 @@ - package mage.cards.j; import java.util.HashMap; @@ -85,14 +84,13 @@ class JelevaNephaliasScourgeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - JelevaNephaliasWatcher watcher = (JelevaNephaliasWatcher) game.getState().getWatchers().get(JelevaNephaliasWatcher.class.getSimpleName()); + JelevaNephaliasWatcher watcher = game.getState().getWatcher(JelevaNephaliasWatcher.class); if (controller != null && sourceObject != null && watcher != null) { int xValue = watcher.getManaSpentToCastLastTime(sourceObject.getId(), sourceObject.getZoneChangeCounter(game) - 1); if (xValue > 0) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - // player.moveCardsToExile(player.getLibrary().getTopCards(game, xValue), source, game, true, CardUtil.getCardExileZoneId(game, source), sourceObject.getIdName()); } } @@ -130,7 +128,7 @@ class JelevaNephaliasCastEffect extends OneShotEffect { if (controller.choose(Outcome.PlayForFree, exileZone, target, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); + return controller.playCard(card, game, true, false, new MageObjectReference(source.getSourceId(), game)); } } } @@ -146,7 +144,7 @@ class JelevaNephaliasWatcher extends Watcher { private final Map manaSpendToCast = new HashMap<>(); // cast public JelevaNephaliasWatcher() { - super(JelevaNephaliasWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public JelevaNephaliasWatcher(final JelevaNephaliasWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java b/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java index fa0dc3dfe6..061d5edb64 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiBarricade.java @@ -27,7 +27,7 @@ public final class JeskaiBarricade extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/j/JeskaiCharm.java b/Mage.Sets/src/mage/cards/j/JeskaiCharm.java index 3e1fba2eff..76ec93b06a 100644 --- a/Mage.Sets/src/mage/cards/j/JeskaiCharm.java +++ b/Mage.Sets/src/mage/cards/j/JeskaiCharm.java @@ -32,17 +32,17 @@ public final class JeskaiCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // - Jeskai Charm deals 4 damage to target opponent. Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(4)); - mode.getTargets().add(new TargetOpponentOrPlaneswalker()); + mode.addEffect(new DamageTargetEffect(4)); + mode.addTarget(new TargetOpponentOrPlaneswalker()); this.getSpellAbility().addMode(mode); // - Creatures you control get +1/+1 and gain lifelink until end of turn. mode = new Mode(); Effect effect = new BoostControlledEffect(1, 1, Duration.EndOfTurn); effect.setText("Creatures you control get +1/+1"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent()); effect.setText("and gain lifelink until end of turn"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/j/JestersCap.java b/Mage.Sets/src/mage/cards/j/JestersCap.java index b2637f6ffb..3a7c5223fb 100644 --- a/Mage.Sets/src/mage/cards/j/JestersCap.java +++ b/Mage.Sets/src/mage/cards/j/JestersCap.java @@ -70,7 +70,7 @@ class JestersCapEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && targetPlayer != null) { TargetCardInLibrary target = new TargetCardInLibrary(3, 3, new FilterCard()); - player.searchLibrary(target, game, targetPlayer.getId()); + player.searchLibrary(target, source, game, targetPlayer.getId()); for (UUID cardId : target.getTargets()) { final Card targetCard = game.getCard(cardId); if (targetCard != null) { diff --git a/Mage.Sets/src/mage/cards/j/JestersScepter.java b/Mage.Sets/src/mage/cards/j/JestersScepter.java index 0744b9ea62..c67505242e 100644 --- a/Mage.Sets/src/mage/cards/j/JestersScepter.java +++ b/Mage.Sets/src/mage/cards/j/JestersScepter.java @@ -92,7 +92,7 @@ class JestersScepterEffect extends OneShotEffect { if (targetedPlayer.getLibrary().hasCards()) { Set cardsToExile = targetedPlayer.getLibrary().getTopCards(game, 5); for (Card card : cardsToExile) { - if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), new StringBuilder(sourceObject.getName()).toString(), source.getSourceId(), game)) { + if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceObject.getName(), source.getSourceId(), game)) { card.setFaceDown(true, game); } } diff --git a/Mage.Sets/src/mage/cards/j/JeweledTorque.java b/Mage.Sets/src/mage/cards/j/JeweledTorque.java new file mode 100644 index 0000000000..2d3e25c715 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JeweledTorque.java @@ -0,0 +1,71 @@ +package mage.cards.j; + +import mage.MageObject; +import mage.ObjectColor; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SpellCastAllTriggeredAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ChooseColorEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterSpell; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JeweledTorque extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("a spell of the chosen color"); + + static { + filter.add(JeweledTorquePredicate.instance); + } + + public JeweledTorque(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // As Jeweled Torque enters the battlefield, choose a color. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseColorEffect(Outcome.Benefit))); + + // Whenever a player casts a spell of the chosen color, you may pay {2}. If you do, you gain 2 life. + this.addAbility(new SpellCastAllTriggeredAbility( + new DoIfCostPaid( + new GainLifeEffect(2), + new GenericManaCost(2) + ), filter, false + )); + } + + private JeweledTorque(final JeweledTorque card) { + super(card); + } + + @Override + public JeweledTorque copy() { + return new JeweledTorque(this); + } +} + +enum JeweledTorquePredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent permanent = game.getPermanent(input.getSourceId()); + if (permanent == null) { + return false; + } + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + return color != null && input.getObject().getColor(game).shares(color); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/JhoiraOfTheGhitu.java b/Mage.Sets/src/mage/cards/j/JhoiraOfTheGhitu.java index 4211de5922..bc09e9f0d0 100644 --- a/Mage.Sets/src/mage/cards/j/JhoiraOfTheGhitu.java +++ b/Mage.Sets/src/mage/cards/j/JhoiraOfTheGhitu.java @@ -1,9 +1,5 @@ - package mage.cards.j; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -17,25 +13,24 @@ import mage.abilities.keyword.SuspendAbility; import mage.cards.Card; 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.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class JhoiraOfTheGhitu extends CardImpl { public JhoiraOfTheGhitu(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{R}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -83,13 +78,17 @@ class JhoiraOfTheGhituSuspendEffect extends OneShotEffect { return false; } List cards = new ArrayList<>(); - for (Cost cost: source.getCosts()) { + for (Cost cost : source.getCosts()) { if (cost instanceof ExileFromHandCost) { cards = ((ExileFromHandCost) cost).getCards(); } } if (cards != null && !cards.isEmpty()) { + // always one card to exile Card card = game.getCard(cards.get(0).getId()); + if (card == null) { + return false; + } boolean hasSuspend = card.getAbilities().containsClass(SuspendAbility.class); UUID exileId = SuspendAbility.getSuspendExileId(controller.getId(), game); diff --git a/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java b/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java new file mode 100644 index 0000000000..a48a815d5d --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JiangYangguWildcrafter.java @@ -0,0 +1,64 @@ +package mage.cards.j; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.AnyColorManaAbility; +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.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JiangYangguWildcrafter extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("Each creature you control with a +1/+1 counter on it"); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + } + + public JiangYangguWildcrafter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.YANGGU); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // Each creature you control with a +1/+1 counter on it has "{T}: Add one mana of any color." + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + new AnyColorManaAbility(), Duration.WhileOnBattlefield, filter + ))); + + // -1: Put a +1/+1 counter on target creature. + Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance() + ), -1); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private JiangYangguWildcrafter(final JiangYangguWildcrafter card) { + super(card); + } + + @Override + public JiangYangguWildcrafter copy() { + return new JiangYangguWildcrafter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/Jihad.java b/Mage.Sets/src/mage/cards/j/Jihad.java index 68035106ca..12ac240734 100644 --- a/Mage.Sets/src/mage/cards/j/Jihad.java +++ b/Mage.Sets/src/mage/cards/j/Jihad.java @@ -84,7 +84,7 @@ class JihadTriggeredAbility extends StateTriggeredAbility { UUID chosenOpponent = (UUID) game.getState().getValue(getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(getSourceId() + "_color"))); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); return game.getBattlefield().countAll(filter, chosenOpponent, game) == 0; } @@ -101,7 +101,7 @@ class JihadOpponentCondition implements Condition { UUID chosenOpponent = (UUID) game.getState().getValue(source.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(source.getSourceId() + "_color"))); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); return game.getBattlefield().countAll(filter, chosenOpponent, game) > 0; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/Jilt.java b/Mage.Sets/src/mage/cards/j/Jilt.java index f1ab8a2f69..a66b94bdde 100644 --- a/Mage.Sets/src/mage/cards/j/Jilt.java +++ b/Mage.Sets/src/mage/cards/j/Jilt.java @@ -1,9 +1,7 @@ - package mage.cards.j; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.Effect; @@ -18,6 +16,7 @@ import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.SecondTargetPointer; /** @@ -43,18 +42,7 @@ public final class Jilt extends CardImpl { Target target = new TargetCreaturePermanent(); target.setTargetTag(1); this.getSpellAbility().addTarget(target); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility && KickedCondition.instance.apply(game, ability)) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("Another creature: Damaged"); - filter.add(new AnotherTargetPredicate(2)); - Target target = new TargetCreaturePermanent(filter); - target.setTargetTag(2); - ability.addTarget(target); - } - + this.getSpellAbility().setTargetAdjuster(JiltAdjuster.instance); } public Jilt(final Jilt card) { @@ -66,3 +54,20 @@ public final class Jilt extends CardImpl { return new Jilt(this); } } + +enum JiltAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (!KickedCondition.instance.apply(game, ability)) { + return; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent("Another creature: Damaged"); + filter.add(new AnotherTargetPredicate(2)); + Target target = new TargetCreaturePermanent(filter); + target.setTargetTag(2); + ability.addTarget(target); + } + +} diff --git a/Mage.Sets/src/mage/cards/j/JinxedRing.java b/Mage.Sets/src/mage/cards/j/JinxedRing.java index c2f58dd8e8..ead7bf52e4 100644 --- a/Mage.Sets/src/mage/cards/j/JinxedRing.java +++ b/Mage.Sets/src/mage/cards/j/JinxedRing.java @@ -34,7 +34,7 @@ public final class JinxedRing extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public JinxedRing(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java b/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java index fb3d834a8e..e72e7debbf 100644 --- a/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java +++ b/Mage.Sets/src/mage/cards/j/JiwariTheEarthAflame.java @@ -44,13 +44,13 @@ public final class JiwariTheEarthAflame extends CardImpl { this.toughness = new MageInt(3); // {X}{R}, {tap}: Jiwari, the Earth Aflame deals X damage to target creature without flying. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{R}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(ability); // Channel - {X}{R}{R}{R}, Discard Jiwari: Jiwari deals X damage to each creature without flying. - this.addAbility(new ChannelAbility("{X}{R}{R}{R}", new DamageAllEffect(new ManacostVariableValue(), filter))); + this.addAbility(new ChannelAbility("{X}{R}{R}{R}", new DamageAllEffect(ManacostVariableValue.instance, filter))); } public JiwariTheEarthAflame(final JiwariTheEarthAflame card) { diff --git a/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java b/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java index 9ee16402ee..7c888ff6bd 100644 --- a/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java +++ b/Mage.Sets/src/mage/cards/j/JoragaAuxiliary.java @@ -25,7 +25,7 @@ public final class JoragaAuxiliary extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other target creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JoragaAuxiliary(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java b/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java index 6b89b86a4b..ca2464b658 100644 --- a/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java +++ b/Mage.Sets/src/mage/cards/j/JoragaWarcaller.java @@ -32,7 +32,7 @@ public final class JoragaWarcaller extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new SubtypePredicate(SubType.ELF)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JoragaWarcaller(UUID ownerId, CardSetInfo setInfo) { @@ -48,7 +48,7 @@ public final class JoragaWarcaller extends CardImpl { // Joraga Warcaller enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true), "with a +1/+1 counter on it for each time it was kicked")); diff --git a/Mage.Sets/src/mage/cards/j/JoriEnRuinDiver.java b/Mage.Sets/src/mage/cards/j/JoriEnRuinDiver.java index 5d81780199..dd11de050f 100644 --- a/Mage.Sets/src/mage/cards/j/JoriEnRuinDiver.java +++ b/Mage.Sets/src/mage/cards/j/JoriEnRuinDiver.java @@ -67,7 +67,7 @@ class JoriEnTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { return true; } diff --git a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java index 9b3d6d4fa1..7866dcfe79 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java +++ b/Mage.Sets/src/mage/cards/j/JourneyForTheElixir.java @@ -99,7 +99,7 @@ class JourneyForTheElixirEffect extends OneShotEffect { if (!walkerFound || !landFound) { TargetCardInLibrary targetWalker = new TargetCardInLibrary(0, 1, filter); targetWalker.setNotTarget(true); - if (!walkerFound && player.searchLibrary(targetWalker, game, false)) { + if (!walkerFound && player.searchLibrary(targetWalker, source, game, false)) { Card card = game.getCard(targetWalker.getFirstTarget()); if (card != null) { cardsToHand.add(card); @@ -107,7 +107,7 @@ class JourneyForTheElixirEffect extends OneShotEffect { } TargetCardInLibrary targetLand = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_BASIC_LAND_A); targetLand.setNotTarget(true); - if (!landFound && player.searchLibrary(targetLand, game, false)) { + if (!landFound && player.searchLibrary(targetLand, source, game, false)) { Card card = game.getCard(targetLand.getFirstTarget()); if (card != null) { cardsToHand.add(card); diff --git a/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java b/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java index 60316b7c9f..6c9a3df535 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java +++ b/Mage.Sets/src/mage/cards/j/JourneyOfDiscovery.java @@ -28,7 +28,7 @@ public final class JourneyOfDiscovery extends CardImpl { // or you may play up to two additional lands this turn. Mode mode = new Mode(); - mode.getEffects().add(new PlayAdditionalLandsControllerEffect(2, Duration.EndOfTurn)); + mode.addEffect(new PlayAdditionalLandsControllerEffect(2, Duration.EndOfTurn)); this.getSpellAbility().getModes().addMode(mode); // Entwine {2}{G} diff --git a/Mage.Sets/src/mage/cards/j/JourneyToNowhere.java b/Mage.Sets/src/mage/cards/j/JourneyToNowhere.java index d0253e3bde..c10249f3ec 100644 --- a/Mage.Sets/src/mage/cards/j/JourneyToNowhere.java +++ b/Mage.Sets/src/mage/cards/j/JourneyToNowhere.java @@ -27,7 +27,7 @@ public final class JourneyToNowhere extends CardImpl { // When Journey to Nowhere enters the battlefield, exile target creature. FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); Ability ability1 = new EntersBattlefieldTriggeredAbility(new ExileTargetForSourceEffect(), false); Target target = new TargetPermanent(filter); ability1.addTarget(target); diff --git a/Mage.Sets/src/mage/cards/j/JovensFerrets.java b/Mage.Sets/src/mage/cards/j/JovensFerrets.java index a4df82c443..8454e04811 100644 --- a/Mage.Sets/src/mage/cards/j/JovensFerrets.java +++ b/Mage.Sets/src/mage/cards/j/JovensFerrets.java @@ -82,7 +82,7 @@ class JovensFerretsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && sourcePermanent != null) { - BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toTap = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/cards/j/JubilantMascot.java b/Mage.Sets/src/mage/cards/j/JubilantMascot.java index 5e7df4e049..299f93ea3d 100644 --- a/Mage.Sets/src/mage/cards/j/JubilantMascot.java +++ b/Mage.Sets/src/mage/cards/j/JubilantMascot.java @@ -27,7 +27,7 @@ public final class JubilantMascot extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other target creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JubilantMascot(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JudithTheScourgeDiva.java b/Mage.Sets/src/mage/cards/j/JudithTheScourgeDiva.java new file mode 100644 index 0000000000..8495a10b95 --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JudithTheScourgeDiva.java @@ -0,0 +1,62 @@ +package mage.cards.j; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JudithTheScourgeDiva extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("nontoken creature you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public JudithTheScourgeDiva(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Other creatures you control get +1/+0. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, true) + )); + + // Whenever a nontoken creature you control dies, Judith, the Scourge Diva deals 1 damage to any target. + Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(1), false, filter); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + private JudithTheScourgeDiva(final JudithTheScourgeDiva card) { + super(card); + } + + @Override + public JudithTheScourgeDiva copy() { + return new JudithTheScourgeDiva(this); + } +} diff --git a/Mage.Sets/src/mage/cards/j/JundCharm.java b/Mage.Sets/src/mage/cards/j/JundCharm.java index 6328baa49a..2dbc88e7a3 100644 --- a/Mage.Sets/src/mage/cards/j/JundCharm.java +++ b/Mage.Sets/src/mage/cards/j/JundCharm.java @@ -30,12 +30,12 @@ public final class JundCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // or Jund Charm deals 2 damage to each creature; Mode mode = new Mode(); - mode.getEffects().add(new DamageAllEffect(2, new FilterCreaturePermanent())); + mode.addEffect(new DamageAllEffect(2, new FilterCreaturePermanent())); this.getSpellAbility().addMode(mode); // or put two +1/+1 counters on target creature. mode = new Mode(); - mode.getEffects().add(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2), Outcome.BoostCreature)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/j/JundHackblade.java b/Mage.Sets/src/mage/cards/j/JundHackblade.java index 21427f6d9f..c8c3620989 100644 --- a/Mage.Sets/src/mage/cards/j/JundHackblade.java +++ b/Mage.Sets/src/mage/cards/j/JundHackblade.java @@ -29,8 +29,8 @@ public final class JundHackblade extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another multicolor permanent"); static { - filter.add(new MulticoloredPredicate()); - filter.add(new AnotherPredicate()); + filter.add(MulticoloredPredicate.instance); + filter.add(AnotherPredicate.instance); } public JundHackblade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JungleBasin.java b/Mage.Sets/src/mage/cards/j/JungleBasin.java index c486b5dce3..e2ceca75b6 100644 --- a/Mage.Sets/src/mage/cards/j/JungleBasin.java +++ b/Mage.Sets/src/mage/cards/j/JungleBasin.java @@ -30,7 +30,7 @@ public final class JungleBasin extends CardImpl { static { filter.add(new SubtypePredicate(SubType.FOREST)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public JungleBasin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JunglePatrol.java b/Mage.Sets/src/mage/cards/j/JunglePatrol.java index db42b08508..31e9ecade3 100644 --- a/Mage.Sets/src/mage/cards/j/JunglePatrol.java +++ b/Mage.Sets/src/mage/cards/j/JunglePatrol.java @@ -32,7 +32,7 @@ public final class JunglePatrol extends CardImpl { static { filter.add(new NamePredicate("Wood")); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public JunglePatrol(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JungleWayfinder.java b/Mage.Sets/src/mage/cards/j/JungleWayfinder.java index b459702934..48d123ceee 100644 --- a/Mage.Sets/src/mage/cards/j/JungleWayfinder.java +++ b/Mage.Sets/src/mage/cards/j/JungleWayfinder.java @@ -72,7 +72,7 @@ class JungleWayfinderEffect extends OneShotEffect { if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_BASIC_LAND); if (player.chooseUse(Outcome.Benefit, "Search your library for a card to put into your hand?", source, game)) { - player.searchLibrary(target, game); + player.searchLibrary(target, source, game); for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/j/JuniperOrderRanger.java b/Mage.Sets/src/mage/cards/j/JuniperOrderRanger.java index f6efdbf90d..4c343d6b5f 100644 --- a/Mage.Sets/src/mage/cards/j/JuniperOrderRanger.java +++ b/Mage.Sets/src/mage/cards/j/JuniperOrderRanger.java @@ -25,7 +25,7 @@ public final class JuniperOrderRanger extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public JuniperOrderRanger(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/j/JunkyoBell.java b/Mage.Sets/src/mage/cards/j/JunkyoBell.java index 8b0cc736cb..d1130ab462 100644 --- a/Mage.Sets/src/mage/cards/j/JunkyoBell.java +++ b/Mage.Sets/src/mage/cards/j/JunkyoBell.java @@ -1,27 +1,27 @@ - package mage.cards.j; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.TargetController; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * @author LevelX */ @@ -32,10 +32,13 @@ public final class JunkyoBell extends CardImpl { // At the beginning of your upkeep, you may have target creature you control get +X/+X until end of turn, // where X is the number of creatures you control. If you do, sacrifice that creature at the beginning of the next end step. - PermanentsOnBattlefieldCount amount = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); - Ability ability = new BeginningOfUpkeepTriggeredAbility(new BoostTargetEffect(amount, amount, Duration.EndOfTurn, true), TargetController.YOU, true); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new BoostTargetEffect(CreaturesYouControlCount.instance, CreaturesYouControlCount.instance, Duration.EndOfTurn, true), + TargetController.YOU, + true); ability.addTarget(new TargetControlledCreaturePermanent()); ability.addEffect(new JunkyoBellSacrificeEffect()); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/j/JushiApprentice.java b/Mage.Sets/src/mage/cards/j/JushiApprentice.java index 88ac5754ba..c6f19a2652 100644 --- a/Mage.Sets/src/mage/cards/j/JushiApprentice.java +++ b/Mage.Sets/src/mage/cards/j/JushiApprentice.java @@ -71,7 +71,7 @@ class TomoyaTheRevealer extends TokenImpl { toughness = new MageInt(3); // {3}{U}{U},{T} : Target player draws X cards, where X is the number of cards in your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardTargetEffect(new CardsInControllerHandCount()), new ManaCostsImpl("{3}{U}{U}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardTargetEffect(CardsInControllerHandCount.instance), new ManaCostsImpl("{3}{U}{U}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/j/Justice.java b/Mage.Sets/src/mage/cards/j/Justice.java index 311609dfbd..9828d5340b 100644 --- a/Mage.Sets/src/mage/cards/j/Justice.java +++ b/Mage.Sets/src/mage/cards/j/Justice.java @@ -76,7 +76,7 @@ class JusticeTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { MageObject sourceObject = game.getObject(event.getSourceId()); - if (sourceObject.getColor(game).isRed()) { + if (sourceObject != null && sourceObject.getColor(game).isRed()) { if (sourceObject instanceof Permanent && sourceObject.isCreature() || sourceObject instanceof Spell) { this.getEffects().get(0).setValue("damageAmount", event.getAmount()); diff --git a/Mage.Sets/src/mage/cards/j/JusticeStrike.java b/Mage.Sets/src/mage/cards/j/JusticeStrike.java index db01871ddb..f992cd7c4a 100644 --- a/Mage.Sets/src/mage/cards/j/JusticeStrike.java +++ b/Mage.Sets/src/mage/cards/j/JusticeStrike.java @@ -38,7 +38,7 @@ public final class JusticeStrike extends CardImpl { class JusticeStrikeEffect extends OneShotEffect { public JusticeStrikeEffect() { - super(Outcome.Benefit); + super(Outcome.Damage); this.staticText = "Target creature deals damage to itself equal to its power."; } diff --git a/Mage.Sets/src/mage/cards/j/JusticiarsPortal.java b/Mage.Sets/src/mage/cards/j/JusticiarsPortal.java new file mode 100644 index 0000000000..7dfc2956ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/j/JusticiarsPortal.java @@ -0,0 +1,71 @@ +package mage.cards.j; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetForSourceEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class JusticiarsPortal extends CardImpl { + + public JusticiarsPortal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Exile target creature you control, then return that card to the battlefield under its owner's control. It gains first strike until end of turn. + this.getSpellAbility().addEffect(new JusticiarsPortalEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private JusticiarsPortal(final JusticiarsPortal card) { + super(card); + } + + @Override + public JusticiarsPortal copy() { + return new JusticiarsPortal(this); + } +} + +class JusticiarsPortalEffect extends OneShotEffect { + + JusticiarsPortalEffect() { + super(Outcome.Benefit); + staticText = "Exile target creature you control, then return that card to the battlefield " + + "under its owner's control. It gains first strike until end of turn."; + } + + private JusticiarsPortalEffect(final JusticiarsPortalEffect effect) { + super(effect); + } + + @Override + public JusticiarsPortalEffect copy() { + return new JusticiarsPortalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + UUID targetId = source.getFirstTarget(); + new ExileTargetForSourceEffect().apply(game, source); + new ReturnToBattlefieldUnderYourControlTargetEffect(true).apply(game, source); + ContinuousEffect effect = new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(targetId, game)); + game.addEffect(effect, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/j/Juxtapose.java b/Mage.Sets/src/mage/cards/j/Juxtapose.java index ecc6700268..a5464c16ed 100644 --- a/Mage.Sets/src/mage/cards/j/Juxtapose.java +++ b/Mage.Sets/src/mage/cards/j/Juxtapose.java @@ -1,13 +1,5 @@ - package mage.cards.j; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; @@ -15,12 +7,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.StaticFilters; @@ -31,8 +18,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.TargetPlayer; +import java.util.*; + /** - * * @author Quercitron */ public final class Juxtapose extends CardImpl { @@ -89,7 +77,6 @@ class JuxtaposeEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { Player you = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); - MageObject sourceObject = game.getCard(source.getSourceId()); if (you != null && targetPlayer != null) { Permanent permanent1 = chooseOnePermanentsWithTheHighestCMC(game, you, filter); @@ -109,9 +96,10 @@ class JuxtaposeEffect extends ContinuousEffectImpl { permanent1.changeControllerId(targetPlayer.getId(), game); permanent2.changeControllerId(you.getId(), game); - game.informPlayers(new StringBuilder(sourceObject != null ? sourceObject.getLogName() : "").append(": ").append(you.getLogName()) - .append(" and ").append(targetPlayer.getLogName()).append(" exchange control of ").append(permanent1.getLogName()) - .append(" and ").append(permanent2.getName()).toString()); + MageObject sourceObject = game.getCard(source.getSourceId()); + game.informPlayers((sourceObject != null ? sourceObject.getLogName() : "") + ": " + you.getLogName() + + " and " + targetPlayer.getLogName() + " exchange control of " + permanent1.getLogName() + + " and " + permanent2.getName()); } else { // discard if there are less than 2 permanents discard(); diff --git a/Mage.Sets/src/mage/cards/j/JwariShapeshifter.java b/Mage.Sets/src/mage/cards/j/JwariShapeshifter.java index e742dfd1ac..7eb7db49eb 100644 --- a/Mage.Sets/src/mage/cards/j/JwariShapeshifter.java +++ b/Mage.Sets/src/mage/cards/j/JwariShapeshifter.java @@ -25,7 +25,7 @@ public final class JwariShapeshifter extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new AnotherPredicate()); // needed because during enters_the_battlefield event the creature is already targetable although it shouldn't + filter.add(AnotherPredicate.instance); // needed because during enters_the_battlefield event the creature is already targetable although it shouldn't } public JwariShapeshifter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KaerveksPurge.java b/Mage.Sets/src/mage/cards/k/KaerveksPurge.java index 591f109a1b..077111812a 100644 --- a/Mage.Sets/src/mage/cards/k/KaerveksPurge.java +++ b/Mage.Sets/src/mage/cards/k/KaerveksPurge.java @@ -1,9 +1,7 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,9 +15,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author sinsedrix */ public final class KaerveksPurge extends CardImpl { @@ -28,19 +28,8 @@ public final class KaerveksPurge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{R}"); // Destroy target creature with converted mana cost X. If that creature dies this way, Kaervek's Purge deals damage equal to the creature's power to the creature's controller. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with converted mana cost X"))); this.getSpellAbility().addEffect(new KaerveksPurgeEffect()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetCreaturePermanent(filter)); - } + this.getSpellAbility().setTargetAdjuster(KaerveksPurgeAdjuster.instance); } public KaerveksPurge(final KaerveksPurge card) { @@ -53,11 +42,27 @@ public final class KaerveksPurge extends CardImpl { } } +enum KaerveksPurgeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} + class KaerveksPurgeEffect extends OneShotEffect { public KaerveksPurgeEffect() { super(Outcome.DestroyPermanent); - this.staticText = "Destroy target creature with converted mana cost X. If that creature dies this way, {this} deals damage equal to the creature's power to the creature's controller"; + this.staticText = "Destroy target creature with converted mana cost X. " + + "If that creature dies this way, " + + "{this} deals damage equal to the creature's power" + + " to the creature's controller"; } public KaerveksPurgeEffect(final KaerveksPurgeEffect effect) { diff --git a/Mage.Sets/src/mage/cards/k/KaerveksTorch.java b/Mage.Sets/src/mage/cards/k/KaerveksTorch.java index 9c299f3f2d..f003c59625 100644 --- a/Mage.Sets/src/mage/cards/k/KaerveksTorch.java +++ b/Mage.Sets/src/mage/cards/k/KaerveksTorch.java @@ -34,7 +34,7 @@ public final class KaerveksTorch extends CardImpl { // As long as Kaervek's Torch is on the stack, spells that target it cost {2} more to cast. this.addAbility(new SimpleStaticAbility(Zone.STACK, new KaerveksTorchCostIncreaseEffect())); // Kaervek's Torch deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/k/KagemaroFirstToSuffer.java b/Mage.Sets/src/mage/cards/k/KagemaroFirstToSuffer.java index a8249cef2d..06e5e8d550 100644 --- a/Mage.Sets/src/mage/cards/k/KagemaroFirstToSuffer.java +++ b/Mage.Sets/src/mage/cards/k/KagemaroFirstToSuffer.java @@ -37,7 +37,7 @@ public final class KagemaroFirstToSuffer extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(0); - DynamicValue xValue = new CardsInControllerHandCount(); + DynamicValue xValue = CardsInControllerHandCount.instance; // Kagemaro, First to Suffer's power and toughness are each equal to the number of cards in your hand. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame))); // {B}, Sacrifice Kagemaro: All creatures get -X/-X until end of turn, where X is the number of cards in your hand. diff --git a/Mage.Sets/src/mage/cards/k/KagemarosClutch.java b/Mage.Sets/src/mage/cards/k/KagemarosClutch.java index 1736f8cd3e..679f3bfc1a 100644 --- a/Mage.Sets/src/mage/cards/k/KagemarosClutch.java +++ b/Mage.Sets/src/mage/cards/k/KagemarosClutch.java @@ -40,7 +40,7 @@ public final class KagemarosClutch extends CardImpl { this.addAbility(ability); // Enchanted creature gets -X/-X, where X is the number of cards in your hand. - DynamicValue xMinusValue = new SignInversionDynamicValue(new CardsInControllerHandCount()); + DynamicValue xMinusValue = new SignInversionDynamicValue(CardsInControllerHandCount.instance); Effect effect = new BoostEnchantedEffect(xMinusValue, xMinusValue, Duration.WhileOnBattlefield); effect.setText("Enchanted creature gets -X/-X, where X is the number of cards in your hand"); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); diff --git a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java index 7dda8d0fb4..cc3c297d34 100644 --- a/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java +++ b/Mage.Sets/src/mage/cards/k/KahoMinamoHistorian.java @@ -88,7 +88,7 @@ class KahoMinamoHistorianEffect extends SearchEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { UUID exileZone = CardUtil.getCardExileZoneId(game, source); if (!target.getTargets().isEmpty()) { controller.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileZone, sourceObject.getIdName()); diff --git a/Mage.Sets/src/mage/cards/k/KalitasTraitorOfGhet.java b/Mage.Sets/src/mage/cards/k/KalitasTraitorOfGhet.java index ff0708de28..a8dc5ad756 100644 --- a/Mage.Sets/src/mage/cards/k/KalitasTraitorOfGhet.java +++ b/Mage.Sets/src/mage/cards/k/KalitasTraitorOfGhet.java @@ -37,7 +37,7 @@ public final class KalitasTraitorOfGhet extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Vampire or Zombie"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.or(new SubtypePredicate(SubType.VAMPIRE), (new SubtypePredicate(SubType.ZOMBIE)))); } diff --git a/Mage.Sets/src/mage/cards/k/KalonianTwingrove.java b/Mage.Sets/src/mage/cards/k/KalonianTwingrove.java index f30969c279..e4628b3045 100644 --- a/Mage.Sets/src/mage/cards/k/KalonianTwingrove.java +++ b/Mage.Sets/src/mage/cards/k/KalonianTwingrove.java @@ -26,7 +26,7 @@ import mage.game.permanent.token.KalonianTwingroveTreefolkWarriorToken; */ public final class KalonianTwingrove extends CardImpl { - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); diff --git a/Mage.Sets/src/mage/cards/k/KamahlsSummons.java b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java index cdfd4fb8c4..b1d2ae7501 100644 --- a/Mage.Sets/src/mage/cards/k/KamahlsSummons.java +++ b/Mage.Sets/src/mage/cards/k/KamahlsSummons.java @@ -83,10 +83,10 @@ class KamahlsSummonsEffect extends OneShotEffect { } } Token token = new BearToken(); - for (UUID playerId : revealedCards.keySet()) { - int value = revealedCards.get(playerId); + for (Map.Entry revealedCardsByPlayer: revealedCards.entrySet()) { + int value = revealedCardsByPlayer.getValue(); if (value > 0) { - token.putOntoBattlefield(value, game, source.getSourceId(), playerId); + token.putOntoBattlefield(value, game, source.getSourceId(), revealedCardsByPlayer.getKey()); } } return true; diff --git a/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java b/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java index fcc5372b8c..cdf9e48aaf 100644 --- a/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java +++ b/Mage.Sets/src/mage/cards/k/KangeeAerieKeeper.java @@ -36,7 +36,7 @@ public final class KangeeAerieKeeper extends CardImpl { static { filter.add(new SubtypePredicate(SubType.BIRD)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public KangeeAerieKeeper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java b/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java index aba7458be3..1ea6ab2fe6 100644 --- a/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java +++ b/Mage.Sets/src/mage/cards/k/KaradorGhostChieftain.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.UUID; @@ -39,10 +38,13 @@ public final class KaradorGhostChieftain extends CardImpl { this.toughness = new MageInt(4); // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.STACK, new KaradorGhostChieftainCostReductionEffect())); + this.addAbility(new SimpleStaticAbility(Zone.STACK, + new KaradorGhostChieftainCostReductionEffect())); // During each of your turns, you may cast one creature card from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KaradorGhostChieftainContinuousEffect()), new KaradorGhostChieftainWatcher()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new KaradorGhostChieftainContinuousEffect()), + new KaradorGhostChieftainWatcher()); } public KaradorGhostChieftain(final KaradorGhostChieftain card) { @@ -79,7 +81,8 @@ class KaradorGhostChieftainCostReductionEffect extends CostModificationEffectImp @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - if ((abilityToModify instanceof SpellAbility) && abilityToModify.getSourceId().equals(source.getSourceId())) { + if ((abilityToModify instanceof SpellAbility) + && abilityToModify.getSourceId().equals(source.getSourceId())) { return game.getCard(abilityToModify.getSourceId()) != null; } return false; @@ -111,7 +114,8 @@ class KaradorGhostChieftainContinuousEffect extends ContinuousEffectImpl { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (game.getActivePlayerId() == null || !game.isActivePlayer(player.getId())) { + if (game.getActivePlayerId() == null + || !game.isActivePlayer(player.getId())) { return false; } for (Card card : player.getGraveyard().getCards(new FilterCreatureCard(), game)) { @@ -148,10 +152,18 @@ class KaradorGhostChieftainCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(getTargetPointer().getFirst(game, source))) { + Card objectCard = game.getCard(objectId); + if (objectCard != null + && objectCard.getId().equals(getTargetPointer().getFirst(game, source)) + && objectCard.isCreature() + && objectCard.getSpellAbility() != null + && affectedControllerId != null + && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(affectedControllerId, game)) { if (affectedControllerId.equals(source.getControllerId())) { - KaradorGhostChieftainWatcher watcher = (KaradorGhostChieftainWatcher) game.getState().getWatchers().get(KaradorGhostChieftainWatcher.class.getSimpleName(), source.getSourceId()); - return !watcher.isAbilityUsed(); + KaradorGhostChieftainWatcher watcher = + game.getState().getWatcher(KaradorGhostChieftainWatcher.class, source.getSourceId()); + return watcher != null + && !watcher.isAbilityUsed(); } } return false; @@ -160,10 +172,10 @@ class KaradorGhostChieftainCastFromGraveyardEffect extends AsThoughEffectImpl { class KaradorGhostChieftainWatcher extends Watcher { - boolean abilityUsed = false; + private boolean abilityUsed = false; KaradorGhostChieftainWatcher() { - super(KaradorGhostChieftainWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } KaradorGhostChieftainWatcher(final KaradorGhostChieftainWatcher watcher) { @@ -173,7 +185,8 @@ class KaradorGhostChieftainWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.GRAVEYARD) { + if (event.getType() == GameEvent.EventType.SPELL_CAST + && event.getZone() == Zone.GRAVEYARD) { Spell spell = (Spell) game.getObject(event.getTargetId()); if (spell.isCreature()) { abilityUsed = true; diff --git a/Mage.Sets/src/mage/cards/k/KarametraGodOfHarvests.java b/Mage.Sets/src/mage/cards/k/KarametraGodOfHarvests.java index 2325c45a86..6ccd4c9f3b 100644 --- a/Mage.Sets/src/mage/cards/k/KarametraGodOfHarvests.java +++ b/Mage.Sets/src/mage/cards/k/KarametraGodOfHarvests.java @@ -25,7 +25,7 @@ import mage.target.common.TargetCardInLibrary; */ public final class KarametraGodOfHarvests extends CardImpl { - private static final FilterCard filter = new FilterCard("a Forest or Plains card"); + private static final FilterCard filter = new FilterCard("Forest or Plains card"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/k/KarnLiberated.java b/Mage.Sets/src/mage/cards/k/KarnLiberated.java index 2cecf73c70..1c3779d9e4 100644 --- a/Mage.Sets/src/mage/cards/k/KarnLiberated.java +++ b/Mage.Sets/src/mage/cards/k/KarnLiberated.java @@ -1,9 +1,5 @@ - package mage.cards.k; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -11,18 +7,11 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileTargetForSourceEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.cards.*; +import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; +import mage.game.GameImpl; import mage.game.command.Commander; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -34,8 +23,11 @@ import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author bunchOfDevs */ public final class KarnLiberated extends CardImpl { @@ -102,6 +94,9 @@ class KarnLiberatedEffect extends OneShotEffect { } } game.getState().clear(); + // default watchers init, TODO: remove all restart/init code to game + ((GameImpl) game).initGameDefaultWatchers(); + for (Card card : game.getCards()) { game.getState().addCard(card); } @@ -122,6 +117,7 @@ class KarnLiberatedEffect extends OneShotEffect { } } } + ((GameImpl) game).initPlayerDefaultWatchers(player.getId()); player.init(game); } } @@ -195,8 +191,7 @@ class KarnLiberatedDelayedEffect extends OneShotEffect { if (exile != null) { // Creatures put onto the battlefield due to Karn's ability will have been under their controller's control continuously // since the beginning of the first turn. They can attack and their activated abilities with {T} in the cost can be activated. - Cards cards = new CardsImpl(); // needed because putOntoTheBattlefield removes from exile - cards.addAll(exile); + Cards cards = new CardsImpl(exile); // needed because putOntoTheBattlefield removes from exile if (!cards.isEmpty()) { controller.moveCards(cards, Zone.BATTLEFIELD, source, game); for (Card card : cards.getCards(game)) { diff --git a/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java b/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java index c0a7719c65..c013d9e03f 100644 --- a/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java +++ b/Mage.Sets/src/mage/cards/k/KarnScionOfUrza.java @@ -89,8 +89,7 @@ class KarnPlus1Effect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 2)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); if (!cards.isEmpty()) { controller.revealCards(staticText, cards, game); diff --git a/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java b/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java new file mode 100644 index 0000000000..c4fdb5ccef --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KarnTheGreatCreator.java @@ -0,0 +1,146 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.WishEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KarnTheGreatCreator extends CardImpl { + + private static final FilterPermanent filter + = new FilterArtifactPermanent("noncreature artifact"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + } + + public KarnTheGreatCreator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KARN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Activated abilities of artifacts your opponents control can't be activated. + this.addAbility(new SimpleStaticAbility(new KarnTheGreatCreatorCantActivateEffect())); + + // +1: Until your next turn, up to one target noncreature artifact becomes an artifact creature with power and toughness equal to its converted mana cost. + Ability ability = new LoyaltyAbility(new KarnTheGreatCreatorAnimateEffect(), 1); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + this.addAbility(ability); + + // -2: You may choose an artifact card you own from outside the game or in exile, reveal that card, and put it into your hand. + this.addAbility(new LoyaltyAbility(new WishEffect( + StaticFilters.FILTER_CARD_ARTIFACT_AN, true, true + ), -2)); + } + + private KarnTheGreatCreator(final KarnTheGreatCreator card) { + super(card); + } + + @Override + public KarnTheGreatCreator copy() { + return new KarnTheGreatCreator(this); + } +} + +class KarnTheGreatCreatorCantActivateEffect extends RestrictionEffect { + + KarnTheGreatCreatorCantActivateEffect() { + super(Duration.WhileOnBattlefield); + staticText = "Activated abilities of artifacts your opponents control can't be activated"; + } + + private KarnTheGreatCreatorCantActivateEffect(final KarnTheGreatCreatorCantActivateEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.isArtifact() && game.getOpponents(source.getControllerId()).contains(permanent.getControllerId()); + } + + @Override + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public KarnTheGreatCreatorCantActivateEffect copy() { + return new KarnTheGreatCreatorCantActivateEffect(this); + } +} + +class KarnTheGreatCreatorAnimateEffect extends ContinuousEffectImpl { + + KarnTheGreatCreatorAnimateEffect() { + super(Duration.UntilYourNextTurn, Outcome.BecomeCreature); + staticText = "Until your next turn, up to one target noncreature artifact becomes " + + "an artifact creature with power and toughness each equal to its converted mana cost."; + } + + private KarnTheGreatCreatorAnimateEffect(final KarnTheGreatCreatorAnimateEffect effect) { + super(effect); + } + + @Override + public KarnTheGreatCreatorAnimateEffect copy() { + return new KarnTheGreatCreatorAnimateEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent artifact = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (artifact == null) { + return false; + } + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + if (!artifact.isCreature()) { + artifact.addCardType(CardType.CREATURE); + } + } + break; + + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + int cmc = artifact.getConvertedManaCost(); + artifact.getPower().setValue(cmc); + artifact.getToughness().setValue(cmc); + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 || layer == Layer.TypeChangingEffects_4; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KarnsBastion.java b/Mage.Sets/src/mage/cards/k/KarnsBastion.java new file mode 100644 index 0000000000..4b5269cd16 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KarnsBastion.java @@ -0,0 +1,40 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KarnsBastion extends CardImpl { + + public KarnsBastion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {4}, {T}: Proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + Ability ability = new SimpleActivatedAbility(new ProliferateEffect(), new GenericManaCost(4)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private KarnsBastion(final KarnsBastion card) { + super(card); + } + + @Override + public KarnsBastion copy() { + return new KarnsBastion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java b/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java index 01b2b24c50..2fae89966e 100644 --- a/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java +++ b/Mage.Sets/src/mage/cards/k/KarnsTemporalSundering.java @@ -70,8 +70,12 @@ class KarnsTemporalSunderingEffect extends OneShotEffect { if (returnPermanent != null) { Card returnCard = returnPermanent.getMainCard(); - Player cardOwner = game.getPlayer(returnCard.getOwnerId()); - cardOwner.moveCards(returnCard, Zone.HAND, source, game); + if(returnCard != null) { + Player cardOwner = game.getPlayer(returnCard.getOwnerId()); + if (cardOwner != null) { + cardOwner.moveCards(returnCard, Zone.HAND, source, game); + } + } } return true; diff --git a/Mage.Sets/src/mage/cards/k/Karoo.java b/Mage.Sets/src/mage/cards/k/Karoo.java index f9b95d496d..61cb7560d3 100644 --- a/Mage.Sets/src/mage/cards/k/Karoo.java +++ b/Mage.Sets/src/mage/cards/k/Karoo.java @@ -30,7 +30,7 @@ public final class Karoo extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PLAINS)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Karoo(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KarplusanGiant.java b/Mage.Sets/src/mage/cards/k/KarplusanGiant.java index 8d2b1424c3..9c1caee816 100644 --- a/Mage.Sets/src/mage/cards/k/KarplusanGiant.java +++ b/Mage.Sets/src/mage/cards/k/KarplusanGiant.java @@ -27,7 +27,7 @@ public final class KarplusanGiant extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("untapped snow land you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SupertypePredicate(SuperType.SNOW)); } diff --git a/Mage.Sets/src/mage/cards/k/KarplusanMinotaur.java b/Mage.Sets/src/mage/cards/k/KarplusanMinotaur.java index eda2fdad62..922fd7146f 100644 --- a/Mage.Sets/src/mage/cards/k/KarplusanMinotaur.java +++ b/Mage.Sets/src/mage/cards/k/KarplusanMinotaur.java @@ -1,12 +1,11 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.keyword.CumulativeUpkeepAbility; import mage.cards.CardImpl; @@ -16,14 +15,17 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.CoinFlippedEvent; import mage.game.events.GameEvent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetAnyTarget; import mage.target.common.TargetOpponent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author L_J */ public final class KarplusanMinotaur extends CardImpl { @@ -39,36 +41,10 @@ public final class KarplusanMinotaur extends CardImpl { this.addAbility(new CumulativeUpkeepAbility(new KarplusanMinotaurCost())); // Whenever you win a coin flip, Karplusan Minotaur deals 1 damage to any target. - Ability abilityWin = new KarplusanMinotaurFlipWinTriggeredAbility(); - abilityWin.addTarget(new TargetAnyTarget()); - this.addAbility(abilityWin); + this.addAbility(new KarplusanMinotaurFlipWinTriggeredAbility()); - //TODO: Make ability properly copiable // Whenever you lose a coin flip, Karplusan Minotaur deals 1 damage to any target of an opponent's choice. - Ability abilityLose = new KarplusanMinotaurFlipLoseTriggeredAbility(); - abilityLose.addTarget(new TargetAnyTarget()); - this.addAbility(abilityLose); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof KarplusanMinotaurFlipLoseTriggeredAbility) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - UUID opponentId = null; - if (game.getOpponents(controller.getId()).size() > 1) { - Target target = new TargetOpponent(true); - if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) { - opponentId = target.getFirstTarget(); - } - } else { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } - if (opponentId != null) { - ability.getTargets().get(0).setTargetController(opponentId); - } - } - } + this.addAbility(new KarplusanMinotaurFlipLoseTriggeredAbility()); } public KarplusanMinotaur(final KarplusanMinotaur card) { @@ -85,6 +61,7 @@ class KarplusanMinotaurFlipWinTriggeredAbility extends TriggeredAbilityImpl { public KarplusanMinotaurFlipWinTriggeredAbility() { super(Zone.BATTLEFIELD, new DamageTargetEffect(1), false); + this.addTarget(new TargetAnyTarget()); } public KarplusanMinotaurFlipWinTriggeredAbility(final KarplusanMinotaurFlipWinTriggeredAbility ability) { @@ -103,7 +80,10 @@ class KarplusanMinotaurFlipWinTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return this.isControlledBy(event.getPlayerId()) && event.getFlag(); + CoinFlippedEvent flipEvent = (CoinFlippedEvent) event; + return flipEvent.getPlayerId().equals(controllerId) + && flipEvent.isWinnable() + && (flipEvent.getChosen() == flipEvent.getResult()); } @Override @@ -116,6 +96,8 @@ class KarplusanMinotaurFlipLoseTriggeredAbility extends TriggeredAbilityImpl { public KarplusanMinotaurFlipLoseTriggeredAbility() { super(Zone.BATTLEFIELD, new DamageTargetEffect(1), false); + this.addTarget(new TargetAnyTarget()); + targetAdjuster = KarplusanMinotaurAdjuster.instance; } public KarplusanMinotaurFlipLoseTriggeredAbility(final KarplusanMinotaurFlipLoseTriggeredAbility ability) { @@ -134,7 +116,10 @@ class KarplusanMinotaurFlipLoseTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return this.isControlledBy(event.getPlayerId()) && !event.getFlag(); + CoinFlippedEvent flipEvent = (CoinFlippedEvent) event; + return flipEvent.getPlayerId().equals(controllerId) + && flipEvent.isWinnable() + && (flipEvent.getChosen() != flipEvent.getResult()); } @Override @@ -153,7 +138,7 @@ class KarplusanMinotaurCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { Player controller = game.getPlayer(controllerId); if (controller != null) { - controller.flipCoin(game); + controller.flipCoin(ability, game, true); this.paid = true; return true; } @@ -176,3 +161,27 @@ class KarplusanMinotaurCost extends CostImpl { return new KarplusanMinotaurCost(); } } + +enum KarplusanMinotaurAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller == null) { + return; + } + UUID opponentId = null; + if (game.getOpponents(controller.getId()).size() > 1) { + Target target = new TargetOpponent(true); + if (controller.chooseTarget(Outcome.Neutral, target, ability, game)) { + opponentId = target.getFirstTarget(); + } + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + if (opponentId != null) { + ability.getTargets().get(0).setTargetController(opponentId); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KarrthusTyrantOfJund.java b/Mage.Sets/src/mage/cards/k/KarrthusTyrantOfJund.java index d11a4fd48b..949e636e44 100644 --- a/Mage.Sets/src/mage/cards/k/KarrthusTyrantOfJund.java +++ b/Mage.Sets/src/mage/cards/k/KarrthusTyrantOfJund.java @@ -33,7 +33,7 @@ public final class KarrthusTyrantOfJund extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Dragon creatures you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java b/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java new file mode 100644 index 0000000000..21db376b54 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KasminaEnigmaticMentor.java @@ -0,0 +1,101 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.Mode; +import mage.abilities.SpellAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.WizardToken; +import mage.target.Target; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KasminaEnigmaticMentor extends CardImpl { + + public KasminaEnigmaticMentor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KASMINA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast. + this.addAbility(new SimpleStaticAbility(new KasminaEnigmaticMentorCostReductionEffect())); + + // -2: Create a 2/2 blue Wizard creature token. Draw a card, then discard a card. + Ability ability = new LoyaltyAbility(new CreateTokenEffect(new WizardToken()), -2); + ability.addEffect(new DrawDiscardControllerEffect( + 1, 1 + ).setText("Draw a card, then discard a card.")); + this.addAbility(ability); + } + + private KasminaEnigmaticMentor(final KasminaEnigmaticMentor card) { + super(card); + } + + @Override + public KasminaEnigmaticMentor copy() { + return new KasminaEnigmaticMentor(this); + } +} + +class KasminaEnigmaticMentorCostReductionEffect extends CostModificationEffectImpl { + + KasminaEnigmaticMentorCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast"; + } + + private KasminaEnigmaticMentorCostReductionEffect(KasminaEnigmaticMentorCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (abilityToModify.getAbilityType() != AbilityType.SPELL + || !game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId())) { + return false; + } + for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { + Mode mode = abilityToModify.getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetUUID : target.getTargets()) { + Permanent permanent = game.getPermanent(targetUUID); + if (permanent != null + && (permanent.isCreature() || permanent.isPlaneswalker()) + && permanent.isControlledBy(source.getControllerId())) { + return true; + } + } + } + } + return false; + } + + @Override + public KasminaEnigmaticMentorCostReductionEffect copy() { + return new KasminaEnigmaticMentorCostReductionEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KasminasTransmutation.java b/Mage.Sets/src/mage/cards/k/KasminasTransmutation.java new file mode 100644 index 0000000000..5288591433 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KasminasTransmutation.java @@ -0,0 +1,73 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KasminasTransmutation extends CardImpl { + + public KasminasTransmutation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature loses all abilities and has base power and toughness 1/1. + this.addAbility(new SimpleStaticAbility(new BecomesCreatureAttachedEffect( + new KasminasTransmutationToken(), "Enchanted creature loses all abilities " + + "and has base power and toughness 1/1", Duration.WhileOnBattlefield, + BecomesCreatureAttachedEffect.LoseType.ABILITIES + ))); + } + + private KasminasTransmutation(final KasminasTransmutation card) { + super(card); + } + + @Override + public KasminasTransmutation copy() { + return new KasminasTransmutation(this); + } +} + +class KasminasTransmutationToken extends TokenImpl { + + KasminasTransmutationToken() { + super("", "loses all abilities and has base power and toughness 1/1"); + cardType.add(CardType.CREATURE); + power = new MageInt(1); + toughness = new MageInt(1); + } + + private KasminasTransmutationToken(final KasminasTransmutationToken token) { + super(token); + } + + public KasminasTransmutationToken copy() { + return new KasminasTransmutationToken(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/k/KatabaticWinds.java b/Mage.Sets/src/mage/cards/k/KatabaticWinds.java index bb9cd0297d..847459cd0f 100644 --- a/Mage.Sets/src/mage/cards/k/KatabaticWinds.java +++ b/Mage.Sets/src/mage/cards/k/KatabaticWinds.java @@ -1,4 +1,3 @@ - package mage.cards.k; import mage.MageObject; @@ -25,7 +24,6 @@ import java.util.Optional; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class KatabaticWinds extends CardImpl { @@ -76,12 +74,12 @@ class KatabaticWindsRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @@ -126,9 +124,7 @@ class KatabaticWindsRuleModifyingEffect extends ContinuousRuleModifyingEffectImp && object.isCreature() && object.getAbilities().contains(FlyingAbility.getInstance()) && game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId())) { - if (ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost))) { - return true; - } + return ability.get().getCosts().stream().anyMatch((cost) -> (cost instanceof TapSourceCost)); } return false; } diff --git a/Mage.Sets/src/mage/cards/k/KavuMauler.java b/Mage.Sets/src/mage/cards/k/KavuMauler.java index ddfc95785e..5b949f2284 100644 --- a/Mage.Sets/src/mage/cards/k/KavuMauler.java +++ b/Mage.Sets/src/mage/cards/k/KavuMauler.java @@ -26,7 +26,7 @@ public final class KavuMauler extends CardImpl { static { filter.add(new SubtypePredicate(SubType.KAVU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public KavuMauler(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KavuMonarch.java b/Mage.Sets/src/mage/cards/k/KavuMonarch.java index 9221978de6..0aebfe4a2c 100644 --- a/Mage.Sets/src/mage/cards/k/KavuMonarch.java +++ b/Mage.Sets/src/mage/cards/k/KavuMonarch.java @@ -31,7 +31,7 @@ public final class KavuMonarch extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.KAVU)); filter2.add(new SubtypePredicate(SubType.KAVU)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public KavuMonarch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KavuPredator.java b/Mage.Sets/src/mage/cards/k/KavuPredator.java index f1818217a8..5bf6feeb58 100644 --- a/Mage.Sets/src/mage/cards/k/KavuPredator.java +++ b/Mage.Sets/src/mage/cards/k/KavuPredator.java @@ -72,7 +72,7 @@ class KavuPredatorTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(this.controllerId).contains(event.getPlayerId())) { - this.getEffects().get(0).setValue("gainedLife", new Integer(event.getAmount())); + this.getEffects().get(0).setValue("gainedLife", event.getAmount()); return true; } return false; @@ -106,10 +106,10 @@ class KavuPredatorEffect extends OneShotEffect { if (permanent != null) { Integer gainedLife = (Integer) this.getValue("gainedLife"); if (gainedLife != null) { - permanent.addCounters(CounterType.P1P1.createInstance(gainedLife.intValue()), source, game); + permanent.addCounters(CounterType.P1P1.createInstance(gainedLife), source, game); Player player = game.getPlayer(source.getControllerId()); if (player != null) { - game.informPlayers(new StringBuilder(player.getLogName()).append(" puts ").append(gainedLife).append(" +1/+1 counter on ").append(permanent.getName()).toString()); + game.informPlayers(player.getLogName() + " puts " + gainedLife + " +1/+1 counter on " + permanent.getName()); } } return true; diff --git a/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java b/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java new file mode 100644 index 0000000000..13ab5564c8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayaBaneOfTheDead.java @@ -0,0 +1,85 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KayaBaneOfTheDead extends CardImpl { + + public KayaBaneOfTheDead(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W/B}{W/B}{W/B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KAYA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + + // Your opponents and permanents your opponents control with hexproof can be the target of spells and abilities you control as though they didn't have hexproof. + this.addAbility(new SimpleStaticAbility(new KayaBaneOfTheDeadEffect())); + + // -3: Exile target creature. + Ability ability = new LoyaltyAbility(new ExileTargetEffect(), -3); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private KayaBaneOfTheDead(final KayaBaneOfTheDead card) { + super(card); + } + + @Override + public KayaBaneOfTheDead copy() { + return new KayaBaneOfTheDead(this); + } +} + +class KayaBaneOfTheDeadEffect extends AsThoughEffectImpl { + + KayaBaneOfTheDeadEffect() { + super(AsThoughEffectType.HEXPROOF, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "your opponents and creatures with hexproof they control " + + "can be the targets of spells and abilities you control as though they didn't have hexproof"; + } + + private KayaBaneOfTheDeadEffect(final KayaBaneOfTheDeadEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public KayaBaneOfTheDeadEffect copy() { + return new KayaBaneOfTheDeadEffect(this); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + if (affectedControllerId.equals(source.getControllerId())) { + if (game.getOpponents(source.getControllerId()).contains(sourceId)) { + return true; + } + Permanent creature = game.getPermanent(sourceId); + if (creature != null + && game.getOpponents(source.getControllerId()).contains(creature.getControllerId())) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java b/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java new file mode 100644 index 0000000000..31b447b6e1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayaOrzhovUsurper.java @@ -0,0 +1,145 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterNonlandPermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInASingleGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KayaOrzhovUsurper extends CardImpl { + + private static final FilterPermanent filter + = new FilterNonlandPermanent("nonland permanent with converted mana cost 1 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 2)); + } + + public KayaOrzhovUsurper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{W}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KAYA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); + + // +1: Exile up to two target cards from a single graveyard. You gain 2 life if at least one creature card was exiled this way. + Ability ability = new LoyaltyAbility(new KayaOrzhovUsurperExileEffect(), 1); + ability.addTarget(new TargetCardInASingleGraveyard(0, 2, StaticFilters.FILTER_CARD)); + this.addAbility(ability); + + // -1: Exile target nonland permanent with converted mana cost 1 or less. + ability = new LoyaltyAbility(new ExileTargetEffect(), -1); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // -5: Kaya, Orzhov Usurper deals damage to target player equal to the number of cards that player owns in exile and you gain that much life. + ability = new LoyaltyAbility(new KayaOrzhovUsurperDamageEffect(), -5); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private KayaOrzhovUsurper(final KayaOrzhovUsurper card) { + super(card); + } + + @Override + public KayaOrzhovUsurper copy() { + return new KayaOrzhovUsurper(this); + } +} + +class KayaOrzhovUsurperExileEffect extends OneShotEffect { + + KayaOrzhovUsurperExileEffect() { + super(Outcome.Benefit); + staticText = "Exile up to two target cards from a single graveyard. " + + "You gain 2 life if at least one creature card was exiled this way."; + } + + private KayaOrzhovUsurperExileEffect(final KayaOrzhovUsurperExileEffect effect) { + super(effect); + } + + @Override + public KayaOrzhovUsurperExileEffect copy() { + return new KayaOrzhovUsurperExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + for (Target target : source.getTargets()) { + for (UUID targetId : target.getTargets()) { + Card card = game.getCard(targetId); + if (card != null) { + cards.add(card); + } + } + } + player.moveCards(cards, Zone.EXILED, source, game); + for (Card card : cards.getCards(game)) { + if (card != null && card.isCreature()) { + player.gainLife(2, game, source); + break; + } + } + return false; + } +} + +class KayaOrzhovUsurperDamageEffect extends OneShotEffect { + + KayaOrzhovUsurperDamageEffect() { + super(Outcome.Benefit); + staticText = "{this} deals damage to target player equal to the number of cards " + + "that player owns in exile and you gain that much life."; + } + + private KayaOrzhovUsurperDamageEffect(final KayaOrzhovUsurperDamageEffect effect) { + super(effect); + } + + @Override + public KayaOrzhovUsurperDamageEffect copy() { + return new KayaOrzhovUsurperDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + int count = 0; + for (Card card : game.getExile().getAllCards(game)) { + if (card != null && card.getOwnerId().equals(player.getId())) { + count += 1; + } + } + player.damage(count, source.getSourceId(), game, false, true); + controller.gainLife(count, game, source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KayasGhostform.java b/Mage.Sets/src/mage/cards/k/KayasGhostform.java new file mode 100644 index 0000000000..84a9b05f39 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayasGhostform.java @@ -0,0 +1,114 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KayasGhostform extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker you control"); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public KayasGhostform(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature or planeswalker you control + TargetPermanent auraTarget = new TargetPermanent(filter); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted permanent dies or is put into exile, return that card to the battlefield under your control. + this.addAbility(new KayasGhostformTriggeredAbility()); + } + + private KayasGhostform(final KayasGhostform card) { + super(card); + } + + @Override + public KayasGhostform copy() { + return new KayasGhostform(this); + } +} + +class KayasGhostformTriggeredAbility extends TriggeredAbilityImpl { + + KayasGhostformTriggeredAbility() { + super(Zone.ALL, new ReturnToBattlefieldUnderYourControlAttachedEffect(), false); + } + + private KayasGhostformTriggeredAbility(final KayasGhostformTriggeredAbility ability) { + super(ability); + } + + @Override + public KayasGhostformTriggeredAbility copy() { + return new KayasGhostformTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() != Zone.BATTLEFIELD + || !(zEvent.getToZone() == Zone.GRAVEYARD || zEvent.getToZone() == Zone.EXILED)) { + return false; + } + if (zEvent.getTarget() != null && zEvent.getTarget().getAttachments() != null + && zEvent.getTarget().getAttachments().contains(this.getSourceId())) { + getEffects().get(0).setValue("attachedTo", zEvent.getTarget()); + return true; + } else { + // If both (attachment and attached went to graveyard at the same time, the attachemnets can be already removed from the attached object.) + // So check here with the LKI of the enchantment + Permanent attachment = game.getPermanentOrLKIBattlefield(getSourceId()); + if (attachment != null + && zEvent.getTargetId() != null && attachment.getAttachedTo() != null + && zEvent.getTargetId().equals(attachment.getAttachedTo())) { + Permanent attachedTo = game.getPermanentOrLKIBattlefield(attachment.getAttachedTo()); + if (attachedTo != null + && attachment.getAttachedToZoneChangeCounter() == attachedTo.getZoneChangeCounter(game)) { // zoneChangeCounter is stored in Permanent + getEffects().get(0).setValue("attachedTo", attachedTo); + return true; + } + } + } + return false; + } + + @Override + public String getRule() { + return "When enchanted permanent dies or is put into exile, " + + "return that card to the battlefield under your control."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KayasWrath.java b/Mage.Sets/src/mage/cards/k/KayasWrath.java new file mode 100644 index 0000000000..d09c9904cd --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KayasWrath.java @@ -0,0 +1,73 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KayasWrath extends CardImpl { + + public KayasWrath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}{W}{B}{B}"); + + // Destroy all creatures. You gain life equal to the number of creatures you controlled that were destroyed this way. + this.getSpellAbility().addEffect(new KayasWrathEffect()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); + } + + private KayasWrath(final KayasWrath card) { + super(card); + } + + @Override + public KayasWrath copy() { + return new KayasWrath(this); + } +} + +class KayasWrathEffect extends OneShotEffect { + + KayasWrathEffect() { + super(Outcome.Benefit); + staticText = "Destroy all creatures. You gain life equal to the number of " + + "creatures you controlled that were destroyed this way."; + } + + private KayasWrathEffect(final KayasWrathEffect effect) { + super(effect); + } + + @Override + public KayasWrathEffect copy() { + return new KayasWrathEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int counter = 0; + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, + source.getControllerId(), source.getSourceId(), game + )) { + if (permanent != null) { + boolean isMine = permanent.isControlledBy(source.getControllerId()); + if (permanent.destroy(source.getSourceId(), game, false) && isMine) { + counter++; + } + } + } + return new GainLifeEffect(counter).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KederektLeviathan.java b/Mage.Sets/src/mage/cards/k/KederektLeviathan.java index cf0e32d9b9..b394b26e44 100644 --- a/Mage.Sets/src/mage/cards/k/KederektLeviathan.java +++ b/Mage.Sets/src/mage/cards/k/KederektLeviathan.java @@ -22,7 +22,7 @@ public final class KederektLeviathan extends CardImpl { private static final FilterNonlandPermanent filter = new FilterNonlandPermanent("all other nonland permanents"); static{ - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public KederektLeviathan(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java index cc4ccc8fcd..6c3e7c0a38 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheBeasts.java @@ -84,7 +84,7 @@ class KeeperOfTheBeastsTarget extends TargetPlayer { int count = 0; MageObject targetSource = game.getObject(sourceId); Player controller = game.getPlayer(sourceControllerId); - if (controller != null) { + if (controller != null && targetSource != null) { for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java new file mode 100644 index 0000000000..9c1bcdd170 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheFlame.java @@ -0,0 +1,79 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterOpponent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class KeeperOfTheFlame extends CardImpl { + + private static final FilterOpponent filter = new FilterOpponent(); + + static { + filter.add(new KeeperOfTheFlamePredicate()); + } + + public KeeperOfTheFlame(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {R}, {tap}: Choose target opponent who had more life than you did as you activated this ability. Keeper of the Flame deals 2 damage to him or her. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2).setText("Choose target opponent who had more life than you did as you activated this ability. {this} deals 2 damage to him or her"), + new ManaCostsImpl("{R}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer(1, 1, false, filter)); + this.addAbility(ability); + + } + + public KeeperOfTheFlame(final KeeperOfTheFlame card) { + super(card); + } + + @Override + public KeeperOfTheFlame copy() { + return new KeeperOfTheFlame(this); + } +} + +class KeeperOfTheFlamePredicate implements ObjectSourcePlayerPredicate> { + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Player targetOpponent = input.getObject(); + Player controller = game.getPlayer(input.getPlayerId()); + if (targetOpponent == null + || controller == null + || !controller.hasOpponent(targetOpponent.getId(), game)) { + return false; + } + return targetOpponent.getLife() > controller.getLife(); + } + + @Override + public String toString() { + return "opponent who had more life than you did as you activated this ability"; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java index bffa37ce84..dde0b01b32 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheLens.java @@ -53,7 +53,7 @@ class KeeperOfTheLensLookFaceDownAbility extends ActivatedAbilityImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature you don't control"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } @@ -101,8 +101,7 @@ class KeeperOfTheLensLookFaceDownEffect extends OneShotEffect { if (faceDownCreature != null) { Permanent copyFaceDown = faceDownCreature.copy(); copyFaceDown.setFaceDown(false, game); - Cards cards = new CardsImpl(); - cards.add(copyFaceDown); + Cards cards = new CardsImpl(copyFaceDown); Player player = game.getPlayer(faceDownCreature.getControllerId()); controller.lookAtCards("face down card - " + mageObject.getName(), cards, game); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java index 080bdc1360..538cd5c2f7 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheLight.java @@ -88,7 +88,7 @@ class KeeperOfTheLightTarget extends TargetPlayer { int count = 0; MageObject targetSource = game.getObject(sourceId); Player controller = game.getPlayer(sourceControllerId); - if (controller != null) { + if (controller != null && targetSource != null) { for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java index 087fe044f6..eda3e048b1 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheMind.java @@ -27,7 +27,6 @@ */ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -35,32 +34,25 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterOpponent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; -import mage.target.common.TargetOpponent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public class KeeperOfTheMind extends CardImpl { - public final UUID originalId; - private static final FilterOpponent filter = new FilterOpponent(); - - static { - filter.add(new KeeperOfTheMindPredicate()); - } - - public KeeperOfTheMind(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}"); @@ -74,28 +66,12 @@ public class KeeperOfTheMind extends CardImpl { effect.setText("Choose target opponent who had at least two more cards in hand than you did as you activated this ability. Draw a card."); Ability ability = new SimpleActivatedAbility(effect, new ManaCostsImpl("{U}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetOpponent()); + ability.setTargetAdjuster(KeeperOfTheMindAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, filter); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public KeeperOfTheMind(final KeeperOfTheMind card) { super(card); - this.originalId = card.originalId; } @Override @@ -104,6 +80,28 @@ public class KeeperOfTheMind extends CardImpl { } } +enum KeeperOfTheMindAdjuster implements TargetAdjuster { + instance; + + private static final FilterOpponent filter = new FilterOpponent(); + + static { + filter.add(new KeeperOfTheMindPredicate()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer == null) { + return; + } + ability.getTargets().clear(); + TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); + ability.addTarget(target); + } +} + class KeeperOfTheMindPredicate implements ObjectSourcePlayerPredicate> { @Override diff --git a/Mage.Sets/src/mage/cards/k/KeeperOfTheNineGales.java b/Mage.Sets/src/mage/cards/k/KeeperOfTheNineGales.java index 6fd6128be8..9ced360768 100644 --- a/Mage.Sets/src/mage/cards/k/KeeperOfTheNineGales.java +++ b/Mage.Sets/src/mage/cards/k/KeeperOfTheNineGales.java @@ -30,7 +30,7 @@ public final class KeeperOfTheNineGales extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Birds you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.BIRD)); } diff --git a/Mage.Sets/src/mage/cards/k/KefnetTheMindful.java b/Mage.Sets/src/mage/cards/k/KefnetTheMindful.java index ab34bc9627..27b76ce5d5 100644 --- a/Mage.Sets/src/mage/cards/k/KefnetTheMindful.java +++ b/Mage.Sets/src/mage/cards/k/KefnetTheMindful.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -15,20 +13,16 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class KefnetTheMindful extends CardImpl { @@ -83,12 +77,12 @@ class KefnetTheMindfulRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KeldonArsonist.java b/Mage.Sets/src/mage/cards/k/KeldonArsonist.java index 7ad5b48034..0508a19cc9 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonArsonist.java +++ b/Mage.Sets/src/mage/cards/k/KeldonArsonist.java @@ -33,7 +33,9 @@ public final class KeldonArsonist extends CardImpl { // {1}, Sacrifice two lands: Destroy target land. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(), new GenericManaCost(1)); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("two lands"), true))); - ability.addTarget(new TargetLandPermanent()); + TargetLandPermanent target = new TargetLandPermanent(); + target.setTargetName("land (to destroy)"); + ability.addTarget(target); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java index 65455f5a3f..091a1b3292 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java +++ b/Mage.Sets/src/mage/cards/k/KeldonBattlewagon.java @@ -40,7 +40,7 @@ public final class KeldonBattlewagon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public KeldonBattlewagon(UUID ownerId, CardSetInfo setInfo) { @@ -90,7 +90,7 @@ class KeldonBattlewagonCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { - for (UUID targetId: (List)target.getTargets()) { + for (UUID targetId: target.getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent == null) return false; diff --git a/Mage.Sets/src/mage/cards/k/KeldonBerserker.java b/Mage.Sets/src/mage/cards/k/KeldonBerserker.java index f2cf9c195c..62b80407f0 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonBerserker.java +++ b/Mage.Sets/src/mage/cards/k/KeldonBerserker.java @@ -26,7 +26,7 @@ public final class KeldonBerserker extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("untapped lands"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public KeldonBerserker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KeldonTwilight.java b/Mage.Sets/src/mage/cards/k/KeldonTwilight.java index 2931cd6845..e5a6468735 100644 --- a/Mage.Sets/src/mage/cards/k/KeldonTwilight.java +++ b/Mage.Sets/src/mage/cards/k/KeldonTwilight.java @@ -54,7 +54,7 @@ class KeldonTwilightCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null) { return watcher.getAttackedThisTurnCreatures().isEmpty(); } diff --git a/Mage.Sets/src/mage/cards/k/KeranosGodOfStorms.java b/Mage.Sets/src/mage/cards/k/KeranosGodOfStorms.java index 3590d94123..fbcec941d2 100644 --- a/Mage.Sets/src/mage/cards/k/KeranosGodOfStorms.java +++ b/Mage.Sets/src/mage/cards/k/KeranosGodOfStorms.java @@ -94,7 +94,7 @@ class KeranosGodOfStormsTriggeredAbility extends TriggeredAbilityImpl { if (event.getPlayerId().equals(this.getControllerId())) { if (game.isActivePlayer(this.getControllerId())) { CardsAmountDrawnThisTurnWatcher watcher = - (CardsAmountDrawnThisTurnWatcher) game.getState().getWatchers().get(CardsAmountDrawnThisTurnWatcher.class.getSimpleName()); + game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) != 1) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KessDissidentMage.java b/Mage.Sets/src/mage/cards/k/KessDissidentMage.java index bc3cc94473..3e4e88f607 100644 --- a/Mage.Sets/src/mage/cards/k/KessDissidentMage.java +++ b/Mage.Sets/src/mage/cards/k/KessDissidentMage.java @@ -1,14 +1,15 @@ - package mage.cards.k; -import java.util.Optional; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; import java.util.UUID; import mage.MageInt; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffect; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.FlashbackAbility; import mage.abilities.keyword.FlyingAbility; @@ -18,22 +19,16 @@ import mage.cards.CardSetInfo; import mage.constants.AsThoughEffectType; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.Layer; import mage.constants.Outcome; -import mage.constants.SubLayer; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.WatcherScope; import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; /** @@ -55,7 +50,10 @@ public final class KessDissidentMage extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard this turn, exile it instead. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KessDissidentMageContinuousEffect()), new KessDissidentMageWatcher()); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new KessDissidentMageCastFromGraveyardEffect()); + ability.addEffect(new KessDissidentMageReplacementEffect()); + this.addAbility(ability, new KessDissidentMageWatcher()); } public KessDissidentMage(final KessDissidentMage card) { @@ -68,56 +66,11 @@ public final class KessDissidentMage extends CardImpl { } } -class KessDissidentMageContinuousEffect extends ContinuousEffectImpl { - - private static final FilterCard filter = new FilterCard("Instant or sorcery spell"); - - static { - filter.add(Predicates.or( - new CardTypePredicate(CardType.INSTANT), - new CardTypePredicate(CardType.SORCERY) - )); - } - - KessDissidentMageContinuousEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "During each of your turns, you may cast an instant or sorcery card from your graveyard. If a card cast this way would be put into your graveyard, exile it instead"; - } - - KessDissidentMageContinuousEffect(final KessDissidentMageContinuousEffect effect) { - super(effect); - } - - @Override - public KessDissidentMageContinuousEffect copy() { - return new KessDissidentMageContinuousEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - if (!game.isActivePlayer(player.getId())) { - return false; - } - for (Card card : player.getGraveyard().getCards(filter, game)) { - ContinuousEffect effect = new KessDissidentMageCastFromGraveyardEffect(); - effect.setTargetPointer(new FixedTarget(card.getId())); - game.addEffect(effect, source); - effect = new KessDissidentMageReplacementEffect(card.getId()); - game.addEffect(effect, source); - } - return true; - } - return false; - } -} - class KessDissidentMageCastFromGraveyardEffect extends AsThoughEffectImpl { KessDissidentMageCastFromGraveyardEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may cast an instant or sorcery card from your graveyard"; + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "During each of your turns, you may cast an instant or sorcery card from your graveyard"; } KessDissidentMageCastFromGraveyardEffect(final KessDissidentMageCastFromGraveyardEffect effect) { @@ -136,14 +89,18 @@ class KessDissidentMageCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (objectId.equals(getTargetPointer().getFirst(game, source))) { - if (affectedControllerId.equals(source.getControllerId())) { - if (game.isActivePlayer(source.getControllerId())) { - KessDissidentMageWatcher watcher = (KessDissidentMageWatcher) game.getState().getWatchers().get(KessDissidentMageWatcher.class.getSimpleName(), source.getSourceId()); - if (!(source instanceof FlashbackAbility)) { - return !watcher.isAbilityUsed(); - } - } + if (!(source instanceof FlashbackAbility) + && affectedControllerId.equals(source.getControllerId()) + && game.isActivePlayer(source.getControllerId())) { + Card card = game.getCard(objectId); + if (card != null + && (card.isInstant() + || card.isSorcery()) + && game.getState().getZone(objectId).equals(Zone.GRAVEYARD)) { + // check if not already a card was cast this turn with this ability + KessDissidentMageWatcher watcher = game.getState().getWatcher(KessDissidentMageWatcher.class); + return watcher != null + && !watcher.isAbilityUsed(new MageObjectReference(source.getSourceId(), game)); } } return false; @@ -152,17 +109,13 @@ class KessDissidentMageCastFromGraveyardEffect extends AsThoughEffectImpl { class KessDissidentMageReplacementEffect extends ReplacementEffectImpl { - private final UUID cardId; - - KessDissidentMageReplacementEffect(UUID cardId) { - super(Duration.EndOfTurn, Outcome.Exile); - this.cardId = cardId; + KessDissidentMageReplacementEffect() { + super(Duration.EndOfGame, Outcome.Exile); staticText = "If a card cast this way would be put into your graveyard, exile it instead"; } KessDissidentMageReplacementEffect(final KessDissidentMageReplacementEffect effect) { super(effect); - this.cardId = effect.cardId; } @Override @@ -173,10 +126,10 @@ class KessDissidentMageReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - Card card = game.getCard(this.cardId); - if (controller != null && card != null) { - controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.STACK, true); - return true; + Card card = game.getCard(event.getTargetId()); + if (controller != null + && card != null) { + return controller.moveCards(card, Zone.EXILED, source, game); } return false; } @@ -189,31 +142,44 @@ class KessDissidentMageReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - return zEvent.getToZone() == Zone.GRAVEYARD - && zEvent.getTargetId().equals(this.cardId); + if (zEvent.getToZone() == Zone.GRAVEYARD) { + KessDissidentMageWatcher watcher = game.getState().getWatcher(KessDissidentMageWatcher.class); + return (watcher != null + && source.getSourceId().equals(watcher.spellCastWasAllowedBy( + new MageObjectReference(event.getTargetId(), game)))); + } + return false; } } class KessDissidentMageWatcher extends Watcher { - boolean abilityUsed = false; + // Which kess object did cast which spell from graveyard + private final Set allowingObjects = new HashSet<>(); + private final Map castSpells = new HashMap<>(); KessDissidentMageWatcher() { - super(KessDissidentMageWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.GAME); } - KessDissidentMageWatcher(final KessDissidentMageWatcher watcher) { + private KessDissidentMageWatcher(final KessDissidentMageWatcher watcher) { super(watcher); - this.abilityUsed = watcher.abilityUsed; + this.allowingObjects.addAll(watcher.allowingObjects); + this.castSpells.putAll(watcher.castSpells); } @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST && event.getZone() == Zone.GRAVEYARD) { + if (event.getType() == GameEvent.EventType.SPELL_CAST + && event.getZone() == Zone.GRAVEYARD) { Spell spell = (Spell) game.getObject(event.getTargetId()); - if (spell.isInstant() || spell.isSorcery()) { - Optional source = game.getAbility(event.getSourceId(), event.getSourceId()); - abilityUsed = true; + if (event.getAdditionalReference() != null + && event.getAdditionalReference().getSourceId() != null + && (spell.isInstant() + || spell.isSorcery())) { + allowingObjects.add(event.getAdditionalReference()); + castSpells.put(new MageObjectReference(spell.getSourceId(), game), + event.getAdditionalReference().getSourceId()); } } } @@ -226,10 +192,15 @@ class KessDissidentMageWatcher extends Watcher { @Override public void reset() { super.reset(); - abilityUsed = false; + allowingObjects.clear(); } - public boolean isAbilityUsed() { - return abilityUsed; + public boolean isAbilityUsed(MageObjectReference mor) { + return allowingObjects.contains(mor); } + + public UUID spellCastWasAllowedBy(MageObjectReference mor) { + return castSpells.getOrDefault(mor, null); + } + } diff --git a/Mage.Sets/src/mage/cards/k/KessigDireSwine.java b/Mage.Sets/src/mage/cards/k/KessigDireSwine.java index 8817eb2d2f..1ae9339127 100644 --- a/Mage.Sets/src/mage/cards/k/KessigDireSwine.java +++ b/Mage.Sets/src/mage/cards/k/KessigDireSwine.java @@ -1,12 +1,13 @@ - package mage.cards.k; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -16,13 +17,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class KessigDireSwine extends CardImpl { public KessigDireSwine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}{G}"); this.subtype.add(SubType.BOAR); this.subtype.add(SubType.HORROR); this.power = new MageInt(6); @@ -31,7 +31,8 @@ public final class KessigDireSwine extends CardImpl { // Delirium — Kessig Dire Swine has trample as long as there are four or more card types among cards in your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new GainAbilitySourceEffect(TrampleAbility.getInstance(), Duration.WhileOnBattlefield), - DeliriumCondition.instance, "Delirium — {this} has trample as long as there are four or more card types among cards in your graveyard"))); + DeliriumCondition.instance, "Delirium — {this} has trample as long as there are four or more card types among cards in your graveyard")) + .addHint(DeliriumHint.instance)); } public KessigDireSwine(final KessigDireSwine card) { diff --git a/Mage.Sets/src/mage/cards/k/KessigWolfRun.java b/Mage.Sets/src/mage/cards/k/KessigWolfRun.java index 87a7e9e7dd..3dfb9a59d9 100644 --- a/Mage.Sets/src/mage/cards/k/KessigWolfRun.java +++ b/Mage.Sets/src/mage/cards/k/KessigWolfRun.java @@ -33,7 +33,7 @@ public final class KessigWolfRun extends CardImpl { // {X}{R}{G}, {T}: Target creature gets +X/+0 and gains trample until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new ManaCostsImpl("{X}{R}{G}")); ability.addCost(new TapSourceCost()); - ability.addEffect(new BoostTargetEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + ability.addEffect(new BoostTargetEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java b/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java index 18f4dfcdc3..ab0b2b932a 100644 --- a/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java +++ b/Mage.Sets/src/mage/cards/k/KestiaTheCultivator.java @@ -33,7 +33,7 @@ public final class KestiaTheCultivator extends CardImpl { static { filter.add(Predicates.or( - new EnchantedPredicate(), + EnchantedPredicate.instance, new CardTypePredicate(CardType.ENCHANTMENT) )); filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/k/KhabalGhoul.java b/Mage.Sets/src/mage/cards/k/KhabalGhoul.java index 28fc328823..06a0fe4e25 100644 --- a/Mage.Sets/src/mage/cards/k/KhabalGhoul.java +++ b/Mage.Sets/src/mage/cards/k/KhabalGhoul.java @@ -28,7 +28,7 @@ public final class KhabalGhoul extends CardImpl { // At the beginning of each end step, put a +1/+1 counter on Khabal Ghoul for each creature that died this turn. this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance(), - new CreaturesDiedThisTurnCount(), true), TargetController.ANY, false), new CreaturesDiedWatcher()); + CreaturesDiedThisTurnCount.instance, true), TargetController.ANY, false), new CreaturesDiedWatcher()); } public KhabalGhoul(final KhabalGhoul card) { diff --git a/Mage.Sets/src/mage/cards/k/KheruDreadmaw.java b/Mage.Sets/src/mage/cards/k/KheruDreadmaw.java index 270eaeacf4..2c5328e31a 100644 --- a/Mage.Sets/src/mage/cards/k/KheruDreadmaw.java +++ b/Mage.Sets/src/mage/cards/k/KheruDreadmaw.java @@ -37,7 +37,7 @@ public final class KheruDreadmaw extends CardImpl { this.addAbility(DefenderAbility.getInstance()); // {1}{G}, Sacrifice another creature: You gain life equal to the sacrificed creature's toughness. - Effect effect = new GainLifeEffect(new SacrificeCostCreaturesToughness()); + Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance); effect.setText("You gain life equal to the sacrificed creature's toughness"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("{1}{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE))); diff --git a/Mage.Sets/src/mage/cards/k/KheruLichLord.java b/Mage.Sets/src/mage/cards/k/KheruLichLord.java index 3e0a7a49fb..b0c9890804 100644 --- a/Mage.Sets/src/mage/cards/k/KheruLichLord.java +++ b/Mage.Sets/src/mage/cards/k/KheruLichLord.java @@ -85,8 +85,7 @@ class KheruLichLordEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getGraveyard().getCards(new FilterCreatureCard(), source.getSourceId(), source.getControllerId(), game)); + Cards cards = new CardsImpl(controller.getGraveyard().getCards(new FilterCreatureCard(), source.getSourceId(), source.getControllerId(), game)); Card card = cards.getRandom(game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java index 1576cc697b..f6779f259a 100644 --- a/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java +++ b/Mage.Sets/src/mage/cards/k/KheruSpellsnatcher.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -14,28 +12,24 @@ import mage.abilities.keyword.MorphAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.constants.ZoneDetail; +import mage.constants.*; import mage.game.Game; import mage.game.stack.Spell; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.TargetSpell; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author emerald000 */ public final class KheruSpellsnatcher extends CardImpl { public KheruSpellsnatcher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.NAGA); this.subtype.add(SubType.WIZARD); @@ -85,10 +79,11 @@ class KheruSpellsnatcherEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(objectId); if (stackObject != null && game.getStack().counter(targetPointer.getFirst(game, source), source.getSourceId(), game, Zone.EXILED, false, ZoneDetail.NONE)) { - if (!((Spell) stackObject).isCopiedSpell()) { + if (!stackObject.isCopy()) { MageObject card = game.getObject(stackObject.getSourceId()); if (card instanceof Card) { - ((Card) card).moveToZone(Zone.EXILED, sourceId, game, true); + UUID exileId = CardUtil.getCardExileZoneId(game, sourceId); + ((Card) card).moveToExile(exileId, "Kheru Spellsnatcher - cast without mana cost", sourceId, game); ContinuousEffect effect = new KheruSpellsnatcherCastFromExileEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); game.addEffect(effect, source); @@ -133,8 +128,10 @@ class KheruSpellsnatcherCastFromExileEffect extends AsThoughEffectImpl { if (card != null) { if (game.getState().getZone(sourceId) == Zone.EXILED) { Player player = game.getPlayer(affectedControllerId); - player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); - return true; + if(player != null) { + player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); + return true; + } } else { this.discard(); } diff --git a/Mage.Sets/src/mage/cards/k/KiAdiMundi.java b/Mage.Sets/src/mage/cards/k/KiAdiMundi.java index 6640a43112..63d42793a7 100644 --- a/Mage.Sets/src/mage/cards/k/KiAdiMundi.java +++ b/Mage.Sets/src/mage/cards/k/KiAdiMundi.java @@ -27,7 +27,7 @@ public final class KiAdiMundi extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/k/KillSwitch.java b/Mage.Sets/src/mage/cards/k/KillSwitch.java index 928d3f91e7..7c3d8248b8 100644 --- a/Mage.Sets/src/mage/cards/k/KillSwitch.java +++ b/Mage.Sets/src/mage/cards/k/KillSwitch.java @@ -29,7 +29,7 @@ public final class KillSwitch extends CardImpl { //static { - // filter.add(new AnotherPredicate()); + // filter.add(AnotherPredicate.instance); // } public KillSwitch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KillingGlare.java b/Mage.Sets/src/mage/cards/k/KillingGlare.java index 11de68c5b0..16704117ad 100644 --- a/Mage.Sets/src/mage/cards/k/KillingGlare.java +++ b/Mage.Sets/src/mage/cards/k/KillingGlare.java @@ -1,9 +1,7 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -13,21 +11,21 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class KillingGlare extends CardImpl { - public KillingGlare (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{B}"); - + public KillingGlare(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}"); // Destroy target creature with power X or less. - this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature with power X or less"))); - + this.getSpellAbility().addEffect(new DestroyTargetEffect("destroy target creature with power X or less")); + this.getSpellAbility().setTargetAdjuster(KillingGlareAdjuster.instance); } public KillingGlare(final KillingGlare card) { @@ -35,19 +33,20 @@ public final class KillingGlare extends CardImpl { } @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - FilterCreaturePermanent filter = new FilterCreaturePermanent(new StringBuilder("creature with power ").append(xValue).append(" or less").toString()); - filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } - - - @Override - public KillingGlare copy() { + public KillingGlare copy() { return new KillingGlare(this); } } + +enum KillingGlareAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with power " + xValue + " or less"); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KillingWave.java b/Mage.Sets/src/mage/cards/k/KillingWave.java index 9027d41357..0f146aac56 100644 --- a/Mage.Sets/src/mage/cards/k/KillingWave.java +++ b/Mage.Sets/src/mage/cards/k/KillingWave.java @@ -61,7 +61,7 @@ class KillingWaveEffect extends OneShotEffect { return false; } - int amount = (new ManacostVariableValue()).calculate(game, source, this); + int amount = (ManacostVariableValue.instance).calculate(game, source, this); if (amount > 0) { List sacrifices = new LinkedList<>(); Map lifePaidAmounts = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/k/KindlyStranger.java b/Mage.Sets/src/mage/cards/k/KindlyStranger.java index 5a738cd6c2..637a0e7a83 100644 --- a/Mage.Sets/src/mage/cards/k/KindlyStranger.java +++ b/Mage.Sets/src/mage/cards/k/KindlyStranger.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.UUID; @@ -8,6 +7,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.TransformSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -32,7 +32,8 @@ public final class KindlyStranger extends CardImpl { // Delirium — {2}{B}: Transform Kindly Stranger. Activate this ability only if there are four or more card types among cards in your graveyard. this.addAbility(new TransformAbility()); this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, - new TransformSourceEffect(true), new ManaCostsImpl<>("{2}{B}"), DeliriumCondition.instance)); + new TransformSourceEffect(true), new ManaCostsImpl<>("{2}{B}"), DeliriumCondition.instance) + .addHint(DeliriumHint.instance)); } public KindlyStranger(final KindlyStranger card) { diff --git a/Mage.Sets/src/mage/cards/k/KindredSummons.java b/Mage.Sets/src/mage/cards/k/KindredSummons.java index 7854b94e6a..f263284c18 100644 --- a/Mage.Sets/src/mage/cards/k/KindredSummons.java +++ b/Mage.Sets/src/mage/cards/k/KindredSummons.java @@ -1,4 +1,3 @@ - package mage.cards.k; import java.util.LinkedHashSet; @@ -16,8 +15,8 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureCard; -import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.players.Player; @@ -74,7 +73,7 @@ class KindredSummonsEffect extends OneShotEffect { if (subType == null) { return false; } - FilterCreaturePermanent filterPermanent = new FilterCreaturePermanent("creature you control of the chosen type"); + FilterControlledCreaturePermanent filterPermanent = new FilterControlledCreaturePermanent("creature you control of the chosen type"); filterPermanent.add(new SubtypePredicate(subType)); int numberOfCards = game.getBattlefield().countAll(filterPermanent, source.getControllerId(), game); Cards revealed = new CardsImpl(); @@ -82,9 +81,14 @@ class KindredSummonsEffect extends OneShotEffect { Cards otherCards = new CardsImpl(); FilterCreatureCard filterCard = new FilterCreatureCard("creature card of the chosen type"); filterCard.add(new SubtypePredicate(subType)); + if (numberOfCards == 0) { // no matches so nothing is revealed + game.informPlayers("There are 0 creature cards of the chosen type in " + controller.getName() + "'s library."); + return true; + } for (Card card : controller.getLibrary().getCards(game)) { revealed.add(card); - if (card != null && filterCard.match(card, game)) { + if (card != null + && filterCard.match(card, game)) { chosenSubtypeCreatureCards.add(card); if (chosenSubtypeCreatureCards.size() == numberOfCards) { break; diff --git a/Mage.Sets/src/mage/cards/k/KingsAssassin.java b/Mage.Sets/src/mage/cards/k/KingsAssassin.java index 7651353f16..52dff0cd15 100644 --- a/Mage.Sets/src/mage/cards/k/KingsAssassin.java +++ b/Mage.Sets/src/mage/cards/k/KingsAssassin.java @@ -26,7 +26,7 @@ public final class KingsAssassin extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public KingsAssassin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java new file mode 100644 index 0000000000..4e2483500a --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KioraBehemothBeckoner.java @@ -0,0 +1,57 @@ +package mage.cards.k; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KioraBehemothBeckoner extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("a creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public KioraBehemothBeckoner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G/U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.KIORA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(7)); + + // Whenever a creature with power 4 or greater enters the battlefield under your control, draw a card. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), filter, false + )); + + // -1: Untap target permanent. + Ability ability = new LoyaltyAbility(new UntapTargetEffect(), -1); + ability.addTarget(new TargetPermanent()); + this.addAbility(ability); + } + + private KioraBehemothBeckoner(final KioraBehemothBeckoner card) { + super(card); + } + + @Override + public KioraBehemothBeckoner copy() { + return new KioraBehemothBeckoner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java b/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java index d42bd45c4a..2c4b8060eb 100644 --- a/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java +++ b/Mage.Sets/src/mage/cards/k/KioraMasterOfTheDepths.java @@ -124,8 +124,7 @@ class KioraRevealEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); boolean creatureCardFound = false; boolean landCardFound = false; for (UUID cardId : cards) { diff --git a/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java b/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java index 9e80d8f280..e5a92f4eaa 100644 --- a/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java +++ b/Mage.Sets/src/mage/cards/k/KioraTheCrashingWave.java @@ -97,7 +97,7 @@ class KioraPreventionEffect extends PreventionEffectImpl { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(), CardUtil.addToolTipMarkTags("All damage that would be dealt to and dealt by this permanent is prevented."), game); + permanent.addInfo("kioraPrevention" + getId(), CardUtil.addToolTipMarkTags("All damage that would be dealt to and dealt by this permanent is prevented."), game); } } } @@ -120,7 +120,7 @@ class KioraPreventionEffect extends PreventionEffectImpl { for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - permanent.addInfo(new StringBuilder("kioraPrevention").append(getId()).toString(), "", game); + permanent.addInfo("kioraPrevention" + getId(), "", game); } } return true; diff --git a/Mage.Sets/src/mage/cards/k/KiorasDambreaker.java b/Mage.Sets/src/mage/cards/k/KiorasDambreaker.java new file mode 100644 index 0000000000..0dcf40c3cc --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KiorasDambreaker.java @@ -0,0 +1,37 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +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 KiorasDambreaker extends CardImpl { + + public KiorasDambreaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); + + this.subtype.add(SubType.LEVIATHAN); + this.power = new MageInt(5); + this.toughness = new MageInt(6); + + // When Kiora's Dreammaker enters the battlefield, proliferate. (Choose any number of permanents and/or players, then give each a counter of each kind already there.) + this.addAbility(new EntersBattlefieldTriggeredAbility(new ProliferateEffect())); + } + + private KiorasDambreaker(final KiorasDambreaker card) { + super(card); + } + + @Override + public KiorasDambreaker copy() { + return new KiorasDambreaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KiorasFollower.java b/Mage.Sets/src/mage/cards/k/KiorasFollower.java index 05417a3b96..d6a0b2eb13 100644 --- a/Mage.Sets/src/mage/cards/k/KiorasFollower.java +++ b/Mage.Sets/src/mage/cards/k/KiorasFollower.java @@ -25,7 +25,7 @@ public final class KiorasFollower extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public KiorasFollower(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}{U}"); diff --git a/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java b/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java index 97a195a7a9..246e39bfe4 100644 --- a/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java +++ b/Mage.Sets/src/mage/cards/k/KiraGreatGlassSpinner.java @@ -82,7 +82,7 @@ class KiraGreatGlassSpinnerAbility extends TriggeredAbilityImpl { if (event.getTargetId().equals(this.getSourceId())) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isCreature()) { - NumberOfTimesPermanentTargetedATurnWatcher watcher = (NumberOfTimesPermanentTargetedATurnWatcher) game.getState().getWatchers().get(NumberOfTimesPermanentTargetedATurnWatcher.class.getSimpleName()); + NumberOfTimesPermanentTargetedATurnWatcher watcher = game.getState().getWatcher(NumberOfTimesPermanentTargetedATurnWatcher.class); if (watcher != null && watcher.notMoreThanOnceTargetedThisTurn(permanent, game)) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getSourceId())); diff --git a/Mage.Sets/src/mage/cards/k/KithkinArmor.java b/Mage.Sets/src/mage/cards/k/KithkinArmor.java new file mode 100644 index 0000000000..1a43c262fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KithkinArmor.java @@ -0,0 +1,174 @@ +package mage.cards.k; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamageCreatureEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetSource; + +/** + * + * @author jeffwadsworth + */ +public final class KithkinArmor extends CardImpl { + + public KithkinArmor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature can't be blocked by creatures with power 3 or greater. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KithkinArmorRestrictionEffect())); + + // Sacrifice Kithkin Armor: The next time a source of your choice would deal damage to enchanted creature this turn, prevent that damage. + Ability protectionAbility = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new KithkinArmorPreventionEffect(), + new KithkinArmorCost()); + protectionAbility.addTarget(new TargetSource()); + this.addAbility(protectionAbility); + + } + + private KithkinArmor(final KithkinArmor card) { + super(card); + } + + @Override + public KithkinArmor copy() { + return new KithkinArmor(this); + } +} + +class KithkinArmorCost extends CostImpl { + + public KithkinArmorCost() { + this.text = "sacrifice {this}"; + } + + public KithkinArmorCost(KithkinArmorCost cost) { + super(cost); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Permanent permanent = game.getPermanent(sourceId); + if (permanent != null) { + // store attached to information due to getLastInfo being completely fubared + game.getState().setValue(ability.getSourceId().toString() + "attachedToPermanent", permanent.getAttachedTo()); + paid = permanent.sacrifice(sourceId, game); + if (!paid) { + game.getState().setValue(ability.getSourceId().toString() + "attachedToPermanent", null); + } + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Permanent permanent = game.getPermanent(sourceId); + return permanent != null + && game.getPlayer(controllerId).canPaySacrificeCost(permanent, sourceId, controllerId, game); + } + + @Override + public KithkinArmorCost copy() { + return new KithkinArmorCost(this); + } +} + +class KithkinArmorRestrictionEffect extends RestrictionEffect { + + public KithkinArmorRestrictionEffect() { + super(Duration.WhileOnBattlefield); + staticText = "Enchanted creature can't be blocked by creatures with power 3 or greater"; + } + + public KithkinArmorRestrictionEffect(final KithkinArmorRestrictionEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null + && enchantment.getAttachedTo() != null) { + Permanent enchantedPermanent = game.getPermanent(enchantment.getAttachedTo()); + return enchantedPermanent != null + && permanent.getId().equals(enchantedPermanent.getId()); + } + return false; + } + + @Override + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return blocker.getPower().getValue() < 3; + } + + @Override + public KithkinArmorRestrictionEffect copy() { + return new KithkinArmorRestrictionEffect(this); + } +} + +class KithkinArmorPreventionEffect extends PreventionEffectImpl { + + KithkinArmorPreventionEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + staticText = "The next time a source of your choice would deal damage to enchanted creature this turn, prevent that damage"; + } + + KithkinArmorPreventionEffect(final KithkinArmorPreventionEffect effect) { + super(effect); + } + + @Override + public KithkinArmorPreventionEffect copy() { + return new KithkinArmorPreventionEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game) + && event instanceof DamageCreatureEvent + && event.getAmount() > 0 + && !this.used) { + UUID enchantedCreatureId = (UUID) game.getState().getValue(source.getSourceId().toString() + "attachedToPermanent"); + DamageCreatureEvent damageEvent = (DamageCreatureEvent) event; + if (enchantedCreatureId != null + && event.getTargetId().equals(enchantedCreatureId) + && damageEvent.getSourceId().equals(source.getFirstTarget())) { + this.used = true; + this.discard(); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KitsuneLoreweaver.java b/Mage.Sets/src/mage/cards/k/KitsuneLoreweaver.java index 8724a8582e..0b71aea401 100644 --- a/Mage.Sets/src/mage/cards/k/KitsuneLoreweaver.java +++ b/Mage.Sets/src/mage/cards/k/KitsuneLoreweaver.java @@ -30,7 +30,7 @@ public final class KitsuneLoreweaver extends CardImpl { this.toughness = new MageInt(1); // {1}{W}: Kitsune Loreweaver gets +0/+X until end of turn, where X is the number of cards in your hand. - Effect effect = new BoostSourceEffect(new StaticValue(0), new CardsInControllerHandCount(), Duration.EndOfTurn, true); + Effect effect = new BoostSourceEffect(new StaticValue(0), CardsInControllerHandCount.instance, Duration.EndOfTurn, true); effect.setText("{this} gets +0/+X until end of turn, where X is the number of cards in your hand"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{W}"))); } diff --git a/Mage.Sets/src/mage/cards/k/KiyomaroFirstToStand.java b/Mage.Sets/src/mage/cards/k/KiyomaroFirstToStand.java index f352b99623..0349e3bd19 100644 --- a/Mage.Sets/src/mage/cards/k/KiyomaroFirstToStand.java +++ b/Mage.Sets/src/mage/cards/k/KiyomaroFirstToStand.java @@ -43,7 +43,7 @@ public final class KiyomaroFirstToStand extends CardImpl { this.toughness = new MageInt(0); // Kiyomaro, First to Stand's power and toughness are each equal to the number of cards in your hand. - DynamicValue xValue= new CardsInControllerHandCount(); + DynamicValue xValue= CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame))); // As long as you have four or more cards in hand, Kiyomaro has vigilance. diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranPride.java b/Mage.Sets/src/mage/cards/k/KjeldoranPride.java new file mode 100644 index 0000000000..d946ed77e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KjeldoranPride.java @@ -0,0 +1,64 @@ + +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherEnchantedPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Ketsuban + */ +public final class KjeldoranPride extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than enchanted creature"); + + static { + filter.add(new AnotherEnchantedPredicate()); + } + + public KjeldoranPride(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.ENCHANTMENT }, "{1}{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Benefit)); + Ability enchantAbility = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(enchantAbility); + + // Enchanted creature gets +1/+2. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 2))); + + // 2U: Attach Kjeldoran Pride to target creature other than enchanted creature. + Ability ability = new SimpleActivatedAbility(new AttachEffect(Outcome.Benefit), new ManaCostsImpl<>("{2}{U}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + public KjeldoranPride(final KjeldoranPride card) { + super(card); + } + + @Override + public KjeldoranPride copy() { + return new KjeldoranPride(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java index fc7d7bbaa5..36c340c81c 100644 --- a/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java +++ b/Mage.Sets/src/mage/cards/k/KjeldoranRoyalGuard.java @@ -55,7 +55,7 @@ class KjeldoranRoyalGuardEffect extends ReplacementEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creatures"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } KjeldoranRoyalGuardEffect() { diff --git a/Mage.Sets/src/mage/cards/k/KnightExemplar.java b/Mage.Sets/src/mage/cards/k/KnightExemplar.java index 17b9e9f765..9c069322b6 100644 --- a/Mage.Sets/src/mage/cards/k/KnightExemplar.java +++ b/Mage.Sets/src/mage/cards/k/KnightExemplar.java @@ -43,7 +43,7 @@ public final class KnightExemplar extends CardImpl { // Other Knight creatures you control get +1/+1 and are indestructible. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); FilterCreaturePermanent indestructibleFilter = filter.copy(); - indestructibleFilter.add(new AnotherPredicate()); + indestructibleFilter.add(AnotherPredicate.instance); indestructibleFilter.add(new ControllerPredicate(TargetController.YOU)); indestructibleFilter.setMessage("Other Knight creatures you control"); Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, indestructibleFilter, false); diff --git a/Mage.Sets/src/mage/cards/k/KnightOfNewAlara.java b/Mage.Sets/src/mage/cards/k/KnightOfNewAlara.java index 85348bfd94..09567e7620 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfNewAlara.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfNewAlara.java @@ -55,7 +55,7 @@ class KnightOfNewAlaraEffect extends ContinuousEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public KnightOfNewAlaraEffect() { diff --git a/Mage.Sets/src/mage/cards/k/KnightOfSorrows.java b/Mage.Sets/src/mage/cards/k/KnightOfSorrows.java new file mode 100644 index 0000000000..7bf0cabd44 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfSorrows.java @@ -0,0 +1,42 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.combat.CanBlockAdditionalCreatureEffect; +import mage.abilities.keyword.AfterlifeAbility; +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 KnightOfSorrows extends CardImpl { + + public KnightOfSorrows(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Knight of Sorrows can block an additional creature each combat. + this.addAbility(new SimpleStaticAbility(new CanBlockAdditionalCreatureEffect())); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + private KnightOfSorrows(final KnightOfSorrows card) { + super(card); + } + + @Override + public KnightOfSorrows copy() { + return new KnightOfSorrows(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java b/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java new file mode 100644 index 0000000000..5ac5c3ea80 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheLastBreath.java @@ -0,0 +1,64 @@ +package mage.cards.k; + +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.CreateTokenEffect; +import mage.abilities.keyword.AfterlifeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.permanent.token.WhiteBlackSpiritToken; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KnightOfTheLastBreath extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("another nontoken creature"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public KnightOfTheLastBreath(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{B}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {3}, Sacrifice another nontoken creature: Create a 1/1 white and black spirit creature token with flying. + Ability ability = new SimpleActivatedAbility( + new CreateTokenEffect(new WhiteBlackSpiritToken()), new GenericManaCost(3) + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + + // Afterlife 3 + this.addAbility(new AfterlifeAbility(3)); + } + + private KnightOfTheLastBreath(final KnightOfTheLastBreath card) { + super(card); + } + + @Override + public KnightOfTheLastBreath copy() { + return new KnightOfTheLastBreath(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java b/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java index f2eb1cd069..5490deae5d 100644 --- a/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java +++ b/Mage.Sets/src/mage/cards/k/KnightOfTheMists.java @@ -1,37 +1,30 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; -import mage.constants.SubType; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.InfoEffect; import mage.abilities.keyword.FlankingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class KnightOfTheMists extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Knight"); - - static { - filter.add(new SubtypePredicate(SubType.KNIGHT)); - } + private static final FilterPermanent filter = new FilterCreaturePermanent(SubType.KNIGHT, "Knight"); public KnightOfTheMists(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); @@ -45,12 +38,14 @@ public final class KnightOfTheMists extends CardImpl { this.addAbility(new FlankingAbility()); // When Knight of the Mists enters the battlefield, you may pay {U}. If you don't, destroy target Knight and it can't be regenerated. - Ability ability = new EntersBattlefieldTriggeredAbility(new KnightOfTheMistsEffect()); - ability.addTarget(new TargetCreaturePermanent(filter)); + Ability ability = new EntersBattlefieldTriggeredAbility(new DoIfCostPaid( + new InfoEffect(""), new DestroyTargetEffect(true), new ManaCostsImpl("{U}") + ).setText("you may pay {U}. If you don't, destroy target Knight and it can't be regenerated.")); + ability.addTarget(new TargetPermanent(filter)); addAbility(ability); } - public KnightOfTheMists(final KnightOfTheMists card) { + private KnightOfTheMists(final KnightOfTheMists card) { super(card); } @@ -59,35 +54,3 @@ public final class KnightOfTheMists extends CardImpl { return new KnightOfTheMists(this); } } - -class KnightOfTheMistsEffect extends OneShotEffect { - - KnightOfTheMistsEffect() { - super(Outcome.Neutral); - this.staticText = "When {this} enters the battlefield, you may pay {U}. If you don't, destroy target Knight and it can't be regenerated."; - } - - KnightOfTheMistsEffect(final KnightOfTheMistsEffect effect) { - super(effect); - } - - @Override - public KnightOfTheMistsEffect copy() { - return new KnightOfTheMistsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getSourceId()); - if (player == null) { - return false; - } - Cost cost = new ManaCostsImpl("{U}"); - if (!(cost.canPay(source, source.getSourceId(), player.getId(), game) - && player.chooseUse(outcome, "Pay {U}?", source, game) - && cost.pay(source, game, source.getSourceId(), player.getId(), false))) { - return new DestroyTargetEffect(true).apply(game, source); - } - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/k/KnightsOfTheBlackRose.java b/Mage.Sets/src/mage/cards/k/KnightsOfTheBlackRose.java index 482ed9506d..7d0f2532e8 100644 --- a/Mage.Sets/src/mage/cards/k/KnightsOfTheBlackRose.java +++ b/Mage.Sets/src/mage/cards/k/KnightsOfTheBlackRose.java @@ -85,7 +85,7 @@ class BecomesMonarchTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkInterveningIfClause(Game game) { - MonarchAtTurnStartWatcher watcher = (MonarchAtTurnStartWatcher) game.getState().getWatchers().get(MonarchAtTurnStartWatcher.class.getSimpleName()); + MonarchAtTurnStartWatcher watcher = game.getState().getWatcher(MonarchAtTurnStartWatcher.class); return watcher != null && isControlledBy(watcher.getMonarchIdAtTurnStart()); } @@ -105,7 +105,7 @@ class MonarchAtTurnStartWatcher extends Watcher { private UUID monarchIdAtTurnStart; public MonarchAtTurnStartWatcher() { - super(MonarchAtTurnStartWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MonarchAtTurnStartWatcher(final MonarchAtTurnStartWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/k/KnollspineDragon.java b/Mage.Sets/src/mage/cards/k/KnollspineDragon.java index b1a35e8e06..10124eefd8 100644 --- a/Mage.Sets/src/mage/cards/k/KnollspineDragon.java +++ b/Mage.Sets/src/mage/cards/k/KnollspineDragon.java @@ -68,7 +68,7 @@ class KnollspineDragonEffect extends OneShotEffect { if (controller != null) { new DiscardHandControllerEffect().apply(game, source); if (targetOpponent != null) { - AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = (AmountOfDamageAPlayerReceivedThisTurnWatcher) game.getState().getWatchers().get(AmountOfDamageAPlayerReceivedThisTurnWatcher.class.getSimpleName()); + AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class); if (watcher != null) { int drawAmount = watcher.getAmountOfDamageReceivedThisTurn(targetOpponent.getId()); controller.drawCards(drawAmount, game); diff --git a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java index 7da7179e69..8b2a45c4c3 100644 --- a/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java +++ b/Mage.Sets/src/mage/cards/k/KnollspineInvocation.java @@ -32,7 +32,7 @@ public final class KnollspineInvocation extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}{R}"); // {X}, Discard a card with converted mana cost X: Knollspine Invocation deals X damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue(), true), new ManaCostsImpl<>("{X}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance, true), new ManaCostsImpl<>("{X}")); ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java b/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java index 7ec1c739e3..2973651050 100644 --- a/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java +++ b/Mage.Sets/src/mage/cards/k/KnotvinePaladin.java @@ -23,7 +23,7 @@ public final class KnotvinePaladin extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java index 9c12f9d0ed..577861370b 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgeExploitation.java @@ -68,7 +68,7 @@ class KnowledgeExploitationEffect extends OneShotEffect { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (controller != null && opponent != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, new FilterInstantOrSorceryCard()); - if (controller.searchLibrary(target, game, opponent.getId())) { + if (controller.searchLibrary(target, source, game, opponent.getId())) { Card card = opponent.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeVault.java b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java new file mode 100644 index 0000000000..9cb731ba9b --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java @@ -0,0 +1,120 @@ + +package mage.cards.k; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.abilities.effects.common.discard.DiscardHandControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.util.CardUtil; + +/** + * + * @author emerald000 & L_J + */ +public final class KnowledgeVault extends CardImpl { + + public KnowledgeVault(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {2}, {T}: Exile the top card of your library face down. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultExileEffect(), new GenericManaCost(2))); + + // {0}: Sacrifice Knowledge Vault. If you do, discard your hand, then put all cards exiled with Knowledge Vault into their owner’s hand. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultReturnEffect(), new GenericManaCost(0))); + + // When Knowledge Vault leaves the battlefield, put all cards exiled with Knowledge Vault into their owner’s graveyard. + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD), false)); + } + + public KnowledgeVault(final KnowledgeVault card) { + super(card); + } + + @Override + public KnowledgeVault copy() { + return new KnowledgeVault(this); + } +} + +class KnowledgeVaultExileEffect extends OneShotEffect { + + KnowledgeVaultExileEffect() { + super(Outcome.Exile); + this.staticText = "exile the top card of your library face down"; + } + + KnowledgeVaultExileEffect(final KnowledgeVaultExileEffect effect) { + super(effect); + } + + @Override + public KnowledgeVaultExileEffect copy() { + return new KnowledgeVaultExileEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + if (controller != null && sourceObject != null) { + Card card = controller.getLibrary().getFromTop(game); + if (card != null) { + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + card.setFaceDown(true, game); + controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); + card.setFaceDown(true, game); + return true; + } + } + return false; + } +} + +class KnowledgeVaultReturnEffect extends OneShotEffect { + + KnowledgeVaultReturnEffect() { + super(Outcome.DrawCard); + this.staticText = "Sacrifice {this}. If you do, discard your hand, then put all cards exiled with {this} into their owners' hands"; + } + + KnowledgeVaultReturnEffect(final KnowledgeVaultReturnEffect effect) { + super(effect); + } + + @Override + public KnowledgeVaultReturnEffect copy() { + return new KnowledgeVaultReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanent(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (sourcePermanent != null && controller != null) { + if (sourcePermanent.sacrifice(source.getSourceId(), game)) { + new DiscardHandControllerEffect().apply(game, source); + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); + if (exileZone != null) { + controller.moveCards(exileZone, Zone.HAND, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KodamasReach.java b/Mage.Sets/src/mage/cards/k/KodamasReach.java index 762c9303b9..853fd0da29 100644 --- a/Mage.Sets/src/mage/cards/k/KodamasReach.java +++ b/Mage.Sets/src/mage/cards/k/KodamasReach.java @@ -68,7 +68,7 @@ class KodamasReachEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java b/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java index f43b8dece3..6fe1524aa3 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java +++ b/Mage.Sets/src/mage/cards/k/KolaghanForerunners.java @@ -1,30 +1,30 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.DashAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KolaghanForerunners extends CardImpl { public KolaghanForerunners(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.BERSERKER); this.power = new MageInt(0); @@ -35,7 +35,7 @@ public final class KolaghanForerunners extends CardImpl { // Kolaghan Forerunners' power is equal to the number of creatures you control. Effect effect = new SetPowerSourceEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creatures you control")), Duration.EndOfGame); - this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); + this.addAbility(new SimpleStaticAbility(Zone.ALL, effect).addHint(CreaturesYouControlHint.instance)); // Dash {2}{R} this.addAbility(new DashAbility(this, "{2}{R}")); diff --git a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java index ea2fd1ab06..9229d1a77f 100644 --- a/Mage.Sets/src/mage/cards/k/KolaghansCommand.java +++ b/Mage.Sets/src/mage/cards/k/KolaghansCommand.java @@ -43,20 +43,20 @@ public final class KolaghansCommand extends CardImpl { // or Target player discards a card; Mode mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(1)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new DiscardTargetEffect(1)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // or Destroy target artifact; mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().getModes().addMode(mode); // or Kolaghan's Command deals 2 damage to any target. mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(2)); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new DamageTargetEffect(2)); + mode.addTarget(new TargetAnyTarget()); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/k/KorEntanglers.java b/Mage.Sets/src/mage/cards/k/KorEntanglers.java index 30a2b08e5e..68281bfe4b 100644 --- a/Mage.Sets/src/mage/cards/k/KorEntanglers.java +++ b/Mage.Sets/src/mage/cards/k/KorEntanglers.java @@ -21,7 +21,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class KorEntanglers extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java b/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java index 4959961c93..872488a84d 100644 --- a/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java +++ b/Mage.Sets/src/mage/cards/k/KorozdaGuildmage.java @@ -34,7 +34,7 @@ public final class KorozdaGuildmage extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public KorozdaGuildmage(UUID ownerId, CardSetInfo setInfo) { @@ -53,7 +53,7 @@ public final class KorozdaGuildmage extends CardImpl { this.addAbility(ability); // {2}{B}{G}, Sacrifice a nontoken creature: create X 1/1 green Saproling creature tokens, where X is the sacrificed creature's toughness. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SaprolingToken(),new SacrificeCostCreaturesToughness()),new ManaCostsImpl("{2}{B}{G}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new SaprolingToken(),SacrificeCostCreaturesToughness.instance),new ManaCostsImpl("{2}{B}{G}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1,1,filter, true))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/k/KoskunFalls.java b/Mage.Sets/src/mage/cards/k/KoskunFalls.java index 70d378577a..d285532a0f 100644 --- a/Mage.Sets/src/mage/cards/k/KoskunFalls.java +++ b/Mage.Sets/src/mage/cards/k/KoskunFalls.java @@ -29,7 +29,7 @@ public final class KoskunFalls extends CardImpl { private static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filterCreature.add(Predicates.not(new TappedPredicate())); + filterCreature.add(Predicates.not(TappedPredicate.instance)); } public KoskunFalls(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java b/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java index bb9df93824..2b3d30d85f 100644 --- a/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java +++ b/Mage.Sets/src/mage/cards/k/KothophedSoulHoarder.java @@ -31,7 +31,7 @@ import mage.players.Player; */ public final class KothophedSoulHoarder extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent(); static { filter.add(new OwnerPredicate(TargetController.NOT_YOU)); diff --git a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java index 693c957fee..9f97442b73 100644 --- a/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java +++ b/Mage.Sets/src/mage/cards/k/KozilekTheGreatDistortion.java @@ -154,9 +154,11 @@ class KozilekDiscardCost extends CostImpl { } } Player controller = game.getPlayer(ability.getControllerId()); - for (Card card : controller.getHand().getCards(game)) { - if (stackCMC.contains(card.getConvertedManaCost())) { - return true; + if(controller != null) { + for (Card card : controller.getHand().getCards(game)) { + if (stackCMC.contains(card.getConvertedManaCost())) { + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/k/KozileksSentinel.java b/Mage.Sets/src/mage/cards/k/KozileksSentinel.java index 4cbaef9e8f..9399ec74d2 100644 --- a/Mage.Sets/src/mage/cards/k/KozileksSentinel.java +++ b/Mage.Sets/src/mage/cards/k/KozileksSentinel.java @@ -23,7 +23,7 @@ public final class KozileksSentinel extends CardImpl { private static final FilterSpell filterSpell = new FilterSpell("a colorless spell"); static { - filterSpell.add(new ColorlessPredicate()); + filterSpell.add(ColorlessPredicate.instance); } public KozileksSentinel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KrakenOfTheStraits.java b/Mage.Sets/src/mage/cards/k/KrakenOfTheStraits.java index 45fdccb381..eaf75f6b6c 100644 --- a/Mage.Sets/src/mage/cards/k/KrakenOfTheStraits.java +++ b/Mage.Sets/src/mage/cards/k/KrakenOfTheStraits.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -19,21 +17,22 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KrakenOfTheStraits extends CardImpl { public KrakenOfTheStraits(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{U}"); this.subtype.add(SubType.KRAKEN); this.power = new MageInt(6); this.toughness = new MageInt(6); // Creatures with power less than the number of Islands you control can't block Kraken of the Straits. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByCreaturesWithLessPowerEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeBlockedByCreaturesWithLessPowerEffect())); } public KrakenOfTheStraits(final KrakenOfTheStraits card) { @@ -49,13 +48,13 @@ public final class KrakenOfTheStraits extends CardImpl { class CantBeBlockedByCreaturesWithLessPowerEffect extends RestrictionEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("Islands"); - + static { filter.add(new SubtypePredicate(SubType.ISLAND)); } - + private final DynamicValue dynamicValue = new PermanentsOnBattlefieldCount(filter); - + public CantBeBlockedByCreaturesWithLessPowerEffect() { super(Duration.WhileOnBattlefield); staticText = "Creatures with power less than the number of Islands you control can't block {this}"; @@ -71,7 +70,7 @@ class CantBeBlockedByCreaturesWithLessPowerEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getPower().getValue() >= dynamicValue.calculate(game, source, this); } diff --git a/Mage.Sets/src/mage/cards/k/KrarksThumb.java b/Mage.Sets/src/mage/cards/k/KrarksThumb.java index 3acb3bde5a..09f0427eb2 100644 --- a/Mage.Sets/src/mage/cards/k/KrarksThumb.java +++ b/Mage.Sets/src/mage/cards/k/KrarksThumb.java @@ -1,33 +1,35 @@ package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SuperType; import mage.game.Game; +import mage.game.events.FlipCoinEvent; import mage.game.events.GameEvent; -import mage.players.Player; -import mage.util.RandomUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class KrarksThumb extends CardImpl { public KrarksThumb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); addSuperType(SuperType.LEGENDARY); // If you would flip a coin, instead flip two coins and ignore one. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KrarksThumbEffect())); + this.addAbility(new SimpleStaticAbility(new KrarksThumbEffect())); } - public KrarksThumb(final KrarksThumb card) { + private KrarksThumb(final KrarksThumb card) { super(card); } @@ -41,29 +43,22 @@ class KrarksThumbEffect extends ReplacementEffectImpl { KrarksThumbEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "If you would flip a coin, instead flip two coins and ignore one"; + staticText = "If you would flip a coin, instead flip two coins and ignore one."; } - KrarksThumbEffect(final KrarksThumbEffect effect) { + private KrarksThumbEffect(final KrarksThumbEffect effect) { super(effect); } + @Override + public KrarksThumbEffect copy() { + return new KrarksThumbEffect(this); + } + @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null) { - // because second flip is ignored it may not be done by the player method - boolean secondCoinFlip = RandomUtil.nextBoolean(); - if (!game.isSimulation()) { - game.informPlayers("[Flip a coin] " + player.getLogName() + (secondCoinFlip ? " won (head)." : " lost (tail).")); - } - if (player.chooseUse(outcome, "Ignore the first coin flip?", source, game)) { - event.setFlag(secondCoinFlip); - game.informPlayers(player.getLogName() + " ignores the first coin flip."); - } else { - game.informPlayers(player.getLogName() + " ignores the second coin flip."); - } - } + FlipCoinEvent flipCoinEvent = (FlipCoinEvent) event; + flipCoinEvent.setFlipCount(2 * flipCoinEvent.getFlipCount()); return false; } @@ -81,9 +76,4 @@ class KrarksThumbEffect extends ReplacementEffectImpl { public boolean apply(Game game, Ability source) { return false; } - - @Override - public KrarksThumbEffect copy() { - return new KrarksThumbEffect(this); - } } diff --git a/Mage.Sets/src/mage/cards/k/KraulStinger.java b/Mage.Sets/src/mage/cards/k/KraulStinger.java new file mode 100644 index 0000000000..5b0e9299d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KraulStinger.java @@ -0,0 +1,37 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +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 KraulStinger extends CardImpl { + + public KraulStinger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.INSECT); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private KraulStinger(final KraulStinger card) { + super(card); + } + + @Override + public KraulStinger copy() { + return new KraulStinger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java b/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java index bf8957318a..c02cf364fa 100644 --- a/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java +++ b/Mage.Sets/src/mage/cards/k/KraumLudevicsOpus.java @@ -80,7 +80,7 @@ class KraumLudevicsOpusTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { return true; } diff --git a/Mage.Sets/src/mage/cards/k/KravTheUnredeemed.java b/Mage.Sets/src/mage/cards/k/KravTheUnredeemed.java index 8a08d9630d..136033ed40 100644 --- a/Mage.Sets/src/mage/cards/k/KravTheUnredeemed.java +++ b/Mage.Sets/src/mage/cards/k/KravTheUnredeemed.java @@ -76,7 +76,7 @@ class KravTheUnredeemedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int xValue = new GetXValue().calculate(game, source, this); + int xValue = GetXValue.instance.calculate(game, source, this); new DrawCardTargetEffect(xValue).apply(game, source); new GainLifeTargetEffect(xValue).apply(game, source); new AddCountersSourceEffect(CounterType.P1P1.createInstance(xValue)).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/k/KrenkoTinStreetKingpin.java b/Mage.Sets/src/mage/cards/k/KrenkoTinStreetKingpin.java new file mode 100644 index 0000000000..7ba8079a32 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KrenkoTinStreetKingpin.java @@ -0,0 +1,77 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.GoblinToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KrenkoTinStreetKingpin extends CardImpl { + + public KrenkoTinStreetKingpin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Whenever Krenko, Tin Street Kingpin attacks, put a +1/+1 counter on it, then create a number of 1/1 red Goblin creature tokens equal to Krenko's power. + this.addAbility(new AttacksTriggeredAbility(new KrenkoTinStreetKingpinEffect(), false)); + } + + private KrenkoTinStreetKingpin(final KrenkoTinStreetKingpin card) { + super(card); + } + + @Override + public KrenkoTinStreetKingpin copy() { + return new KrenkoTinStreetKingpin(this); + } +} + +class KrenkoTinStreetKingpinEffect extends OneShotEffect { + + KrenkoTinStreetKingpinEffect() { + super(Outcome.Benefit); + staticText = "put a +1/+1 counter on it, " + + "then create a number of 1/1 red Goblin creature tokens equal to {this}'s power."; + } + + private KrenkoTinStreetKingpinEffect(final KrenkoTinStreetKingpinEffect effect) { + super(effect); + } + + @Override + public KrenkoTinStreetKingpinEffect copy() { + return new KrenkoTinStreetKingpinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (permanent == null) { + return false; + } + new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); + game.applyEffects(); + int xValue = permanent.getPower().getValue(); + return new CreateTokenEffect(new GoblinToken("WAR"), xValue).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KronchWrangler.java b/Mage.Sets/src/mage/cards/k/KronchWrangler.java new file mode 100644 index 0000000000..32c97eae43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KronchWrangler.java @@ -0,0 +1,56 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class KronchWrangler extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("a creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public KronchWrangler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever a creature with power 4 or greater enters the battlefield under your control, put a +1/+1 counter on Kronch Wrangler. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter + )); + } + + private KronchWrangler(final KronchWrangler card) { + super(card); + } + + @Override + public KronchWrangler copy() { + return new KronchWrangler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KrovikanPlague.java b/Mage.Sets/src/mage/cards/k/KrovikanPlague.java index 8bc9f49f3d..835ac9ee08 100644 --- a/Mage.Sets/src/mage/cards/k/KrovikanPlague.java +++ b/Mage.Sets/src/mage/cards/k/KrovikanPlague.java @@ -46,7 +46,7 @@ public final class KrovikanPlague extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("enchanted creature is untapped"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public KrovikanPlague(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KrovikanVampire.java b/Mage.Sets/src/mage/cards/k/KrovikanVampire.java new file mode 100644 index 0000000000..47197080a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KrovikanVampire.java @@ -0,0 +1,260 @@ +package mage.cards.k; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.watchers.Watcher; + +/** + * + * @author jeffwadsworth + */ +public final class KrovikanVampire extends CardImpl { + + public KrovikanVampire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // At the beginning of each end step, if a creature dealt damage by Krovikan Vampire this turn died, put that card onto the battlefield under your control. Sacrifice it when you lose control of Krovikan Vampire. + Ability ability = new BeginningOfEndStepTriggeredAbility( + Zone.BATTLEFIELD, + new KrovikanVampireEffect(), + TargetController.ANY, + new KrovikanVampireInterveningIfCondition(), + false); + ability.addWatcher(new KrovikanVampireCreaturesDamagedWatcher()); + ability.addWatcher(new KrovikanVampireCreaturesDiedWatcher()); + this.addAbility(ability); + } + + public KrovikanVampire(final KrovikanVampire card) { + super(card); + } + + @Override + public KrovikanVampire copy() { + return new KrovikanVampire(this); + } +} + +class KrovikanVampireEffect extends OneShotEffect { + + Set creaturesAffected = new HashSet<>(); + + KrovikanVampireEffect() { + super(Outcome.Neutral); + staticText = "put that card onto the battlefield under your control. Sacrifice it when you lose control of {this}"; + } + + KrovikanVampireEffect(KrovikanVampireEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent krovikanVampire = game.getPermanent(source.getSourceId()); + creaturesAffected = (Set) game.getState().getValue(source.getSourceId() + "creatureToGainControl"); + if (creaturesAffected != null + && controller != null + && krovikanVampire != null) { + creaturesAffected.stream().map((creatureId) -> { + controller.moveCards(game.getCard(creatureId), Zone.BATTLEFIELD, source, game, false, false, false, null); + return creatureId; + }).map((creatureId) -> { + OneShotEffect effect = new SacrificeTargetEffect(); + effect.setText("Sacrifice this if Krovikan Vampire leaves the battlefield or its current controller loses control of it."); + effect.setTargetPointer(new FixedTarget(creatureId)); + return effect; + }).map((effect) -> new KrovikanVampireDelayedTriggeredAbility(effect, krovikanVampire.getId())).forEachOrdered((dTA) -> { + game.addDelayedTriggeredAbility(dTA, source); + }); + creaturesAffected.clear(); + return true; + } + return false; + } + + @Override + public KrovikanVampireEffect copy() { + return new KrovikanVampireEffect(this); + } +} + +class KrovikanVampireInterveningIfCondition implements Condition { + + Set creaturesAffected = new HashSet<>(); + + @Override + public boolean apply(Game game, Ability source) { + KrovikanVampireCreaturesDiedWatcher watcherDied = game.getState().getWatcher(KrovikanVampireCreaturesDiedWatcher.class); + KrovikanVampireCreaturesDamagedWatcher watcherDamaged = game.getState().getWatcher(KrovikanVampireCreaturesDamagedWatcher.class); + if (watcherDied != null) { + Set creaturesThatDiedThisTurn = watcherDied.getDiedThisTurn(); + creaturesThatDiedThisTurn.stream().filter((mor) -> (watcherDamaged != null)).forEachOrdered((mor) -> { + watcherDamaged.getDamagedBySource().stream().filter((mor2) -> (mor2 != null + && mor == mor2)).forEachOrdered((_item) -> { + creaturesAffected.add(mor); + }); + }); + if (creaturesAffected != null + && creaturesAffected.size() > 0) { + game.getState().setValue(source.getSourceId() + "creatureToGainControl", creaturesAffected); + return true; + } + } + return false; + } + + @Override + public String toString() { + return "if a creature dealt damage by Krovikan Vampire this turn died"; + } +} + +class KrovikanVampireCreaturesDamagedWatcher extends Watcher { + + private final Set damagedBySource = new HashSet<>(); + + public KrovikanVampireCreaturesDamagedWatcher() { + super(WatcherScope.GAME); + } + + public KrovikanVampireCreaturesDamagedWatcher(final KrovikanVampireCreaturesDamagedWatcher watcher) { + super(watcher); + this.damagedBySource.addAll(watcher.damagedBySource); + } + + @Override + public KrovikanVampireCreaturesDamagedWatcher copy() { + return new KrovikanVampireCreaturesDamagedWatcher(this); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == EventType.DAMAGED_CREATURE + && sourceId.equals(event.getSourceId())) { + damagedBySource.add(event.getTargetId()); + } + } + + public Set getDamagedBySource() { + return this.damagedBySource; + } + + @Override + public void reset() { + damagedBySource.clear(); + } +} + +class KrovikanVampireCreaturesDiedWatcher extends Watcher { + + private final Set diedThisTurn = new HashSet<>(); + + public KrovikanVampireCreaturesDiedWatcher() { + super(WatcherScope.GAME); + } + + public KrovikanVampireCreaturesDiedWatcher(final KrovikanVampireCreaturesDiedWatcher watcher) { + super(watcher); + this.diedThisTurn.addAll(watcher.diedThisTurn); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.isDiesEvent() + && zEvent.getTarget() != null + && zEvent.getTarget().isCreature()) { + diedThisTurn.add(zEvent.getTargetId()); + } + } + } + + @Override + public void reset() { + diedThisTurn.clear(); + } + + public Set getDiedThisTurn() { + return this.diedThisTurn; + } + + @Override + public KrovikanVampireCreaturesDiedWatcher copy() { + return new KrovikanVampireCreaturesDiedWatcher(this); + } +} + +class KrovikanVampireDelayedTriggeredAbility extends DelayedTriggeredAbility { + + UUID krovikanVampire; + + KrovikanVampireDelayedTriggeredAbility(Effect effect, UUID krovikanVampire) { + super(effect, Duration.EndOfGame, true); + this.krovikanVampire = krovikanVampire; + } + + KrovikanVampireDelayedTriggeredAbility(KrovikanVampireDelayedTriggeredAbility ability) { + super(ability); + this.krovikanVampire = ability.krovikanVampire; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.LOST_CONTROL + || event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.LOST_CONTROL + && event.getSourceId().equals(krovikanVampire)) { + return true; + } + if (event.getType() == EventType.ZONE_CHANGE + && event.getTargetId().equals(krovikanVampire)) { + return true; + } + return false; + } + + @Override + public KrovikanVampireDelayedTriggeredAbility copy() { + return new KrovikanVampireDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Control of Krovikan Vampire lost"; + } +} diff --git a/Mage.Sets/src/mage/cards/k/KryShield.java b/Mage.Sets/src/mage/cards/k/KryShield.java new file mode 100644 index 0000000000..eb321f215e --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KryShield.java @@ -0,0 +1,49 @@ + +package mage.cards.k; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.TargetConvertedManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.target.common.TargetControlledCreaturePermanent; + +/** + * + * @author L_J + */ +public final class KryShield extends CardImpl { + + public KryShield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {2}, {T}: Prevent all damage that would be dealt this turn by target creature you control. That creature gets +0/+X until end of turn, where X is its converted mana cost. + Effect effect = new PreventDamageByTargetEffect(Duration.EndOfTurn); + effect.setText("Prevent all damage that would be dealt this turn by target creature you control"); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); + ability.addEffect(new BoostTargetEffect(new StaticValue(0), TargetConvertedManaCost.instance, Duration.EndOfTurn, true) + .setText("That creature gets +0/+X until end of turn, where X is its converted mana cost")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + public KryShield(final KryShield card) { + super(card); + } + + @Override + public KryShield copy() { + return new KryShield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/Kudzu.java b/Mage.Sets/src/mage/cards/k/Kudzu.java index 37e3b35540..0c8f9cb857 100644 --- a/Mage.Sets/src/mage/cards/k/Kudzu.java +++ b/Mage.Sets/src/mage/cards/k/Kudzu.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BecomesTappedAttachedTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -21,8 +19,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class Kudzu extends CardImpl { @@ -73,7 +72,6 @@ class KudzuEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent kudzu = game.getPermanentOrLKIBattlefield(source.getSourceId()); - Card kudzuCard = game.getCard(source.getSourceId()); if (kudzu != null) { Permanent enchantedLand = game.getPermanentOrLKIBattlefield(kudzu.getAttachedTo()); Player controller = game.getPlayer(source.getControllerId()); @@ -86,8 +84,8 @@ class KudzuEffect extends OneShotEffect { if (!game.getBattlefield().getAllActivePermanents(CardType.LAND).isEmpty()) { //lands are available on the battlefield Target target = new TargetLandPermanent(); target.setNotTarget(true); //not a target, it is chosen - if (kudzuCard != null - && landsController != null) { + Card kudzuCard = game.getCard(source.getSourceId()); + if (kudzuCard != null && landsController != null) { if (landsController.choose(Outcome.Detriment, target, source.getId(), game)) { if (target.getFirstTarget() != null) { Permanent landChosen = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/k/KukemssaPirates.java b/Mage.Sets/src/mage/cards/k/KukemssaPirates.java index 5464da339d..3371ea8a14 100644 --- a/Mage.Sets/src/mage/cards/k/KukemssaPirates.java +++ b/Mage.Sets/src/mage/cards/k/KukemssaPirates.java @@ -1,29 +1,32 @@ package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksAndIsNotBlockedTriggeredAbility; import mage.abilities.effects.common.continuous.AssignNoCombatDamageSourceEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.common.FilterArtifactPermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; import mage.target.common.TargetArtifactPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class KukemssaPirates extends CardImpl { - private final UUID originalId; + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact defending player controls"); + + static { + filter.add(DefendingPlayerControlsPredicate.instance); + } public KukemssaPirates(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); @@ -36,26 +39,12 @@ public final class KukemssaPirates extends CardImpl { // Whenever Kukemssa Pirates attacks and isn't blocked, you may gain control of target artifact defending player controls. If you do, Kukemssa Pirates assigns no combat damage this turn. Ability ability = new AttacksAndIsNotBlockedTriggeredAbility(new GainControlTargetEffect(Duration.Custom), true); ability.addEffect(new AssignNoCombatDamageSourceEffect(Duration.EndOfTurn, true)); - ability.addTarget(new TargetArtifactPermanent(new FilterArtifactPermanent("artifact defending player controls"))); - originalId = ability.getOriginalId(); + ability.addTarget(new TargetArtifactPermanent(filter)); this.addAbility(ability); } public KukemssaPirates(final KukemssaPirates card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - FilterArtifactPermanent filter = new FilterArtifactPermanent("artifact defending player controls"); - UUID defenderId = game.getCombat().getDefenderId(ability.getSourceId()); - filter.add(new ControllerIdPredicate(defenderId)); - TargetArtifactPermanent target = new TargetArtifactPermanent(filter); - ability.addTarget(target); - } } @Override diff --git a/Mage.Sets/src/mage/cards/k/KulrathKnight.java b/Mage.Sets/src/mage/cards/k/KulrathKnight.java index a4ad1cc07c..44df6d1a19 100644 --- a/Mage.Sets/src/mage/cards/k/KulrathKnight.java +++ b/Mage.Sets/src/mage/cards/k/KulrathKnight.java @@ -1,7 +1,5 @@ - package mage.cards.k; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,25 +8,22 @@ import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.WitherAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.CounterAnyPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class KulrathKnight extends CardImpl { public KulrathKnight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B/R}{B/R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B/R}{B/R}"); this.subtype.add(SubType.ELEMENTAL); this.subtype.add(SubType.KNIGHT); this.power = new MageInt(3); @@ -61,7 +56,7 @@ class KulrathKnightRestrictionEffect extends RestrictionEffect { static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(new CounterAnyPredicate()); + filter.add(CounterAnyPredicate.instance); } public KulrathKnightRestrictionEffect() { @@ -79,12 +74,12 @@ class KulrathKnightRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/k/KumanosBlessing.java b/Mage.Sets/src/mage/cards/k/KumanosBlessing.java index c745c6fd9c..675c8c6973 100644 --- a/Mage.Sets/src/mage/cards/k/KumanosBlessing.java +++ b/Mage.Sets/src/mage/cards/k/KumanosBlessing.java @@ -94,7 +94,7 @@ class KumanosBlessingEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zce = (ZoneChangeEvent) event; if (zce.isDiesEvent()) { - DamagedByEnchantedWatcher watcher = (DamagedByEnchantedWatcher) game.getState().getWatchers().get(DamagedByEnchantedWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByEnchantedWatcher watcher = game.getState().getWatcher(DamagedByEnchantedWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(zce.getTarget(), game); } @@ -109,7 +109,7 @@ class DamagedByEnchantedWatcher extends Watcher { private final Set damagedCreatures = new HashSet<>(); public DamagedByEnchantedWatcher() { - super(DamagedByEnchantedWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } public DamagedByEnchantedWatcher(final DamagedByEnchantedWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java b/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java index 1750aaad30..620c839d28 100644 --- a/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java +++ b/Mage.Sets/src/mage/cards/k/KumenaTyrantOfOrazca.java @@ -34,12 +34,12 @@ public final class KumenaTyrantOfOrazca extends CardImpl { private static final FilterControlledPermanent filterAll = new FilterControlledPermanent("Merfolk you control"); static { - filterAnotherNotTapped.add(new AnotherPredicate()); + filterAnotherNotTapped.add(AnotherPredicate.instance); filterAnotherNotTapped.add(new SubtypePredicate(SubType.MERFOLK)); - filterAnotherNotTapped.add(Predicates.not(new TappedPredicate())); + filterAnotherNotTapped.add(Predicates.not(TappedPredicate.instance)); filterNotTapped.add(new SubtypePredicate(SubType.MERFOLK)); - filterNotTapped.add(Predicates.not(new TappedPredicate())); + filterNotTapped.add(Predicates.not(TappedPredicate.instance)); filterAll.add(new SubtypePredicate(SubType.MERFOLK)); } diff --git a/Mage.Sets/src/mage/cards/k/KumenasAwakening.java b/Mage.Sets/src/mage/cards/k/KumenasAwakening.java index 0dfc5df142..a154eee7ba 100644 --- a/Mage.Sets/src/mage/cards/k/KumenasAwakening.java +++ b/Mage.Sets/src/mage/cards/k/KumenasAwakening.java @@ -1,20 +1,20 @@ - package mage.cards.k; -import java.util.UUID; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardAllEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.TargetController; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class KumenasAwakening extends CardImpl { @@ -29,7 +29,8 @@ public final class KumenasAwakening extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility( new ConditionalOneShotEffect(new DrawCardSourceControllerEffect(1), new DrawCardAllEffect(1), CitysBlessingCondition.instance, "each player draws a card. If you have the city's blessing, instead only you draw a card"), - TargetController.YOU, false)); + TargetController.YOU, false) + .addHint(CitysBlessingHint.instance)); } public KumenasAwakening(final KumenasAwakening card) { diff --git a/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java b/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java index 90981f9019..58cc2dd777 100644 --- a/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java +++ b/Mage.Sets/src/mage/cards/k/KumenasSpeaker.java @@ -24,7 +24,7 @@ public final class KumenasSpeaker extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another Merfolk or an Island"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.or( new SubtypePredicate(SubType.ISLAND), new SubtypePredicate(SubType.MERFOLK))); diff --git a/Mage.Sets/src/mage/cards/k/KuonOgreAscendant.java b/Mage.Sets/src/mage/cards/k/KuonOgreAscendant.java index ee72d2a3c9..cf6d508436 100644 --- a/Mage.Sets/src/mage/cards/k/KuonOgreAscendant.java +++ b/Mage.Sets/src/mage/cards/k/KuonOgreAscendant.java @@ -89,7 +89,7 @@ enum KuonOgreAscendantCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CreaturesDiedWatcher watcher = (CreaturesDiedWatcher) game.getState().getWatchers().get(CreaturesDiedWatcher.class.getSimpleName()); + CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class); if (watcher != null) { return watcher.getAmountOfCreaturesDiedThisTurn() > 2; } diff --git a/Mage.Sets/src/mage/cards/k/KurkeshOnakkeAncient.java b/Mage.Sets/src/mage/cards/k/KurkeshOnakkeAncient.java index 7fbd372ea5..27be72c109 100644 --- a/Mage.Sets/src/mage/cards/k/KurkeshOnakkeAncient.java +++ b/Mage.Sets/src/mage/cards/k/KurkeshOnakkeAncient.java @@ -119,7 +119,7 @@ class KurkeshOnakkeAncientEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (ability != null && controller != null) { ability.createCopyOnStack(game, source, source.getControllerId(), true); - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(": ").append(controller.getLogName()).append(" copied activated ability").toString()); + game.informPlayers(sourcePermanent.getName() + ": " + controller.getLogName() + " copied activated ability"); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/k/KydeleChosenOfKruphix.java b/Mage.Sets/src/mage/cards/k/KydeleChosenOfKruphix.java index ba654daf77..2bd53139c8 100644 --- a/Mage.Sets/src/mage/cards/k/KydeleChosenOfKruphix.java +++ b/Mage.Sets/src/mage/cards/k/KydeleChosenOfKruphix.java @@ -57,8 +57,11 @@ class CardsDrawnThisTurnDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - KydeleCardsDrawnThisTurnWatcher watcher = (KydeleCardsDrawnThisTurnWatcher) game.getState().getWatchers().get(KydeleCardsDrawnThisTurnWatcher.class.getSimpleName()); - return watcher.getCardsDrawnThisTurn(sourceAbility.getControllerId()); + KydeleCardsDrawnThisTurnWatcher watcher = game.getState().getWatcher(KydeleCardsDrawnThisTurnWatcher.class); + if(watcher != null) { + return watcher.getCardsDrawnThisTurn(sourceAbility.getControllerId()); + } + return 0; } @Override @@ -82,7 +85,7 @@ class KydeleCardsDrawnThisTurnWatcher extends Watcher { private final Map cardsDrawnThisTurn = new HashMap<>(); public KydeleCardsDrawnThisTurnWatcher() { - super(KydeleCardsDrawnThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public KydeleCardsDrawnThisTurnWatcher(final KydeleCardsDrawnThisTurnWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/k/KyloRen.java b/Mage.Sets/src/mage/cards/k/KyloRen.java index 19326d1925..eab9b02ff1 100644 --- a/Mage.Sets/src/mage/cards/k/KyloRen.java +++ b/Mage.Sets/src/mage/cards/k/KyloRen.java @@ -39,7 +39,7 @@ public final class KyloRen extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public KyloRen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java b/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java index f21e9a828e..e9af826e1a 100644 --- a/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java +++ b/Mage.Sets/src/mage/cards/k/KyrenNegotiations.java @@ -24,7 +24,7 @@ public final class KyrenNegotiations extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public KyrenNegotiations(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/k/KyscuDrake.java b/Mage.Sets/src/mage/cards/k/KyscuDrake.java new file mode 100644 index 0000000000..709edbfb9a --- /dev/null +++ b/Mage.Sets/src/mage/cards/k/KyscuDrake.java @@ -0,0 +1,67 @@ +package mage.cards.k; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * + * @author jmharmon + */ + +public final class KyscuDrake extends CardImpl { + + private static final FilterCard filter = new FilterCard("card named Viashivan Dragon"); + private static final FilterControlledCreaturePermanent filterSpitting = new FilterControlledCreaturePermanent("creature named Spitting Drake"); + static { + filter.add(new NamePredicate("Viashivan Dragon")); + filterSpitting.add(new NamePredicate("Spitting Drake")); + } + + public KyscuDrake(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.subtype.add(SubType.DRAKE); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {G}: Kyscu Drake gets +0/+1 until end of turn. Activate this ability only once each turn. + this.addAbility(new LimitedTimesPerTurnActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(0, 1, Duration.EndOfTurn), new ManaCostsImpl("{G}"))); + + // Sacrifice Kyscu Drake and a creature named Spitting Drake: Search your library for a card named Viashivan Dragon and put that card onto the battlefield. Then shuffle your library. + TargetCardInLibrary target = new TargetCardInLibrary(1, 1, new FilterCard(filter)); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SearchLibraryPutInPlayEffect(target,true,true, Outcome.PutCardInPlay), new SacrificeSourceCost()); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filterSpitting, false))); + this.addAbility(ability); + + } + + public KyscuDrake(final KyscuDrake card) { + super(card); + } + + @Override + public KyscuDrake copy() { + return new KyscuDrake(this); + } +} diff --git a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java index d420ff39a6..4e36e7bd8d 100644 --- a/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java +++ b/Mage.Sets/src/mage/cards/k/KytheonHeroOfAkros.java @@ -71,7 +71,7 @@ class KytheonHeroOfAkrosCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent sourceObject = game.getPermanent(source.getSourceId()); if (sourceObject != null) { - AttackedOrBlockedThisCombatWatcher watcher = (AttackedOrBlockedThisCombatWatcher) game.getState().getWatchers().get(AttackedOrBlockedThisCombatWatcher.class.getSimpleName()); + AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class); if (watcher != null) { boolean sourceFound = false; int number = 0; diff --git a/Mage.Sets/src/mage/cards/l/LadySun.java b/Mage.Sets/src/mage/cards/l/LadySun.java index 8d9ca4863d..255c43bbd8 100644 --- a/Mage.Sets/src/mage/cards/l/LadySun.java +++ b/Mage.Sets/src/mage/cards/l/LadySun.java @@ -28,7 +28,7 @@ public final class LadySun extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public LadySun(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java index b811c781ff..f4e6f76628 100644 --- a/Mage.Sets/src/mage/cards/l/LambholtPacifist.java +++ b/Mage.Sets/src/mage/cards/l/LambholtPacifist.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbility; @@ -14,25 +12,21 @@ import mage.abilities.effects.common.TransformSourceEffect; import mage.abilities.keyword.TransformAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class LambholtPacifist extends CardImpl { public LambholtPacifist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); this.subtype.add(SubType.WEREWOLF); @@ -84,17 +78,14 @@ class LambholtPacifistEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (game.getBattlefield().countAll(filter, source.getControllerId(), game) > 0) { - return false; - } - return true; + return game.getBattlefield().countAll(filter, source.getControllerId(), game) <= 0; } // do not apply to other creatures. return false; } diff --git a/Mage.Sets/src/mage/cards/l/LammastideWeave.java b/Mage.Sets/src/mage/cards/l/LammastideWeave.java index a67cac4585..9cd195c43b 100644 --- a/Mage.Sets/src/mage/cards/l/LammastideWeave.java +++ b/Mage.Sets/src/mage/cards/l/LammastideWeave.java @@ -1,10 +1,9 @@ package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,9 +13,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Styxo */ public final class LammastideWeave extends CardImpl { @@ -70,7 +71,7 @@ class LammastideWeaveEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { controller.gainLife(card.getConvertedManaCost(), game, source); } } diff --git a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java index 20fcc00fcb..b3930a952c 100644 --- a/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java +++ b/Mage.Sets/src/mage/cards/l/LamplighterOfSelhoff.java @@ -26,7 +26,7 @@ public final class LamplighterOfSelhoff extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Zombie"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ZOMBIE)); } diff --git a/Mage.Sets/src/mage/cards/l/LapisLazuliTalisman.java b/Mage.Sets/src/mage/cards/l/LapisLazuliTalisman.java index 5a54db01e4..f94965c1a7 100644 --- a/Mage.Sets/src/mage/cards/l/LapisLazuliTalisman.java +++ b/Mage.Sets/src/mage/cards/l/LapisLazuliTalisman.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class LapisLazuliTalisman extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a blue spell"); + private static final FilterSpell filter = new FilterSpell("a blue spell"); static { filter.add(new ColorPredicate(ObjectColor.BLUE)); diff --git a/Mage.Sets/src/mage/cards/l/LaquatussCreativity.java b/Mage.Sets/src/mage/cards/l/LaquatussCreativity.java index 15dd0d3026..b2f75203a9 100644 --- a/Mage.Sets/src/mage/cards/l/LaquatussCreativity.java +++ b/Mage.Sets/src/mage/cards/l/LaquatussCreativity.java @@ -57,9 +57,11 @@ class LaquatussCreativityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getFirstTarget()); - int handCount = player.getHand().count(new FilterCard(), game); - player.drawCards(handCount, game); - player.discard(handCount, false, source, game); + if(player != null) { + int handCount = player.getHand().count(new FilterCard(), game); + player.drawCards(handCount, game); + player.discard(handCount, false, source, game); + } return false; } } diff --git a/Mage.Sets/src/mage/cards/l/Lashknife.java b/Mage.Sets/src/mage/cards/l/Lashknife.java index c0f5db91da..a99bf8d117 100644 --- a/Mage.Sets/src/mage/cards/l/Lashknife.java +++ b/Mage.Sets/src/mage/cards/l/Lashknife.java @@ -38,7 +38,7 @@ public final class Lashknife extends CardImpl { static { plainsFilter.add(new SubtypePredicate(SubType.PLAINS)); - creatureFilter.add(Predicates.not(new TappedPredicate())); + creatureFilter.add(Predicates.not(TappedPredicate.instance)); } public Lashknife(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LastLaugh.java b/Mage.Sets/src/mage/cards/l/LastLaugh.java index 4dd8091503..14c712bfa3 100644 --- a/Mage.Sets/src/mage/cards/l/LastLaugh.java +++ b/Mage.Sets/src/mage/cards/l/LastLaugh.java @@ -27,7 +27,7 @@ public final class LastLaugh extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("a permanent other than Last Laugh"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public LastLaugh(UUID ownerId, CardSetInfo setInfo) { @@ -73,7 +73,7 @@ class LastLaughStateTriggeredAbility extends StateTriggeredAbility { @Override public String getRule() { - return new StringBuilder("When no creatures are on the battlefield, ").append(super.getRule()).toString() ; + return "When no creatures are on the battlefield, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/l/LatNamsLegacy.java b/Mage.Sets/src/mage/cards/l/LatNamsLegacy.java index ba6f8740f5..bb16820bff 100644 --- a/Mage.Sets/src/mage/cards/l/LatNamsLegacy.java +++ b/Mage.Sets/src/mage/cards/l/LatNamsLegacy.java @@ -55,7 +55,7 @@ class LatNamsLegacyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (!controller.getHand().isEmpty()) { + if (controller != null && !controller.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, new FilterCard("card to shuffle into your library")); controller.choose(Outcome.Detriment, controller.getHand(), target, game); Card card = controller.getHand().get(target.getFirstTarget(), game); diff --git a/Mage.Sets/src/mage/cards/l/LathlissDragonQueen.java b/Mage.Sets/src/mage/cards/l/LathlissDragonQueen.java index bdb34d6533..e93fb4b01d 100644 --- a/Mage.Sets/src/mage/cards/l/LathlissDragonQueen.java +++ b/Mage.Sets/src/mage/cards/l/LathlissDragonQueen.java @@ -34,8 +34,8 @@ public final class LathlissDragonQueen extends CardImpl { static { filter.add(new SubtypePredicate(SubType.DRAGON)); - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); filter2.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/l/LatullaKeldonOverseer.java b/Mage.Sets/src/mage/cards/l/LatullaKeldonOverseer.java index 7c86ccbe4f..30171595ff 100644 --- a/Mage.Sets/src/mage/cards/l/LatullaKeldonOverseer.java +++ b/Mage.Sets/src/mage/cards/l/LatullaKeldonOverseer.java @@ -35,7 +35,7 @@ public final class LatullaKeldonOverseer extends CardImpl { this.toughness = new MageInt(3); // {X}{R}, {tap}, Discard two cards: Latulla, Keldon Overseer deals X damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{R}")); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardTargetCost(new TargetCardInHand(2, 2, new FilterCard("two cards")))); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/l/Launch.java b/Mage.Sets/src/mage/cards/l/Launch.java index 9c3c984cd9..3e0518ed3d 100644 --- a/Mage.Sets/src/mage/cards/l/Launch.java +++ b/Mage.Sets/src/mage/cards/l/Launch.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -11,22 +9,18 @@ import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Derpthemeus */ public final class Launch extends CardImpl { public Launch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -34,8 +28,10 @@ public final class Launch extends CardImpl { this.getSpellAbility().addTarget(auraTarget); this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + // Enchanted creature has flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield))); + // When Launch is put into a graveyard from the battlefield, return Launch to its owner's hand. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ReturnToHandSourceEffect())); diff --git a/Mage.Sets/src/mage/cards/l/LavaStorm.java b/Mage.Sets/src/mage/cards/l/LavaStorm.java new file mode 100644 index 0000000000..74d34536a4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LavaStorm.java @@ -0,0 +1,79 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AttackingPredicate; +import mage.filter.predicate.permanent.BlockingPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LavaStorm extends CardImpl { + + public LavaStorm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}{R}"); + + // Lava Storm deals 2 damage to each attacking creature or Lava Storm deals 2 damage to each blocking creature. + this.getSpellAbility().addEffect(new LavaStormEffect()); + } + + private LavaStorm(final LavaStorm card) { + super(card); + } + + @Override + public LavaStorm copy() { + return new LavaStorm(this); + } +} + +class LavaStormEffect extends OneShotEffect { + private static final FilterPermanent filter = new FilterCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterCreaturePermanent(); + + static { + filter.add(AttackingPredicate.instance); + filter2.add(BlockingPredicate.instance); + } + + LavaStormEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 2 damage to each attacking creature " + + "or {this} deals 2 damage to each blocking creature."; + } + + private LavaStormEffect(final LavaStormEffect effect) { + super(effect); + } + + @Override + public LavaStormEffect copy() { + return new LavaStormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (player.chooseUse( + Outcome.Benefit, "Deal 2 damage to all attacking creatures or all blocking creatures?", + null, "Attackers", "Blockers", source, game) + ) { + return new DamageAllEffect(2, filter).apply(game, source); + } + return new DamageAllEffect(2, filter2).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LavaballTrap.java b/Mage.Sets/src/mage/cards/l/LavaballTrap.java index 745a056dc8..df7428ffb6 100644 --- a/Mage.Sets/src/mage/cards/l/LavaballTrap.java +++ b/Mage.Sets/src/mage/cards/l/LavaballTrap.java @@ -57,7 +57,7 @@ enum LavaballTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List permanents = watcher.getThisTurnEnteringPermanents(opponentId); diff --git a/Mage.Sets/src/mage/cards/l/LavabornMuse.java b/Mage.Sets/src/mage/cards/l/LavabornMuse.java index 79d6e154bd..c43fa87603 100644 --- a/Mage.Sets/src/mage/cards/l/LavabornMuse.java +++ b/Mage.Sets/src/mage/cards/l/LavabornMuse.java @@ -3,19 +3,18 @@ package mage.cards.l; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.ComparisonType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; /** * @@ -32,7 +31,7 @@ public final class LavabornMuse extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Lavaborn Muse deals 3 damage to him or her. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(3), TargetController.OPPONENT, false, true), - new CardsInActivePlayersHandCondition(), + (Condition)new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, null, TargetController.ACTIVE), "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 3 damage to him or her.")); } @@ -45,14 +44,3 @@ public final class LavabornMuse extends CardImpl { return new LavabornMuse(this); } } - -// TODO: Figure out CardsInHandCondition parameters and use that instead of rewriting this -// TODO: Update HellfireMongrel, ShriekingAffliction to use the CardsInHandCondition? -class CardsInActivePlayersHandCondition implements Condition { - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(game.getActivePlayerId()); - return player != null && player.getHand().size() <= 2; - } -} diff --git a/Mage.Sets/src/mage/cards/l/LavaclawReaches.java b/Mage.Sets/src/mage/cards/l/LavaclawReaches.java index e1c3f7b6fd..9988c05f7d 100644 --- a/Mage.Sets/src/mage/cards/l/LavaclawReaches.java +++ b/Mage.Sets/src/mage/cards/l/LavaclawReaches.java @@ -60,7 +60,7 @@ class LavaclawReachesToken extends TokenImpl { color.setBlack(true); power = new MageInt(2); toughness = new MageInt(2); - addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn), new ManaCostsImpl("{X}"))); + addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn), new ManaCostsImpl("{X}"))); } public LavaclawReachesToken(final LavaclawReachesToken token) { super(token); diff --git a/Mage.Sets/src/mage/cards/l/Lavalanche.java b/Mage.Sets/src/mage/cards/l/Lavalanche.java index bbb74ff71d..231134ea21 100644 --- a/Mage.Sets/src/mage/cards/l/Lavalanche.java +++ b/Mage.Sets/src/mage/cards/l/Lavalanche.java @@ -29,7 +29,7 @@ public final class Lavalanche extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{R}{G}"); // Lavalanche deals X damage to target player and each creature he or she controls. - this.getSpellAbility().addEffect(new LavalancheEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new LavalancheEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); } diff --git a/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java new file mode 100644 index 0000000000..4276ebfd59 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LaviniaAzoriusRenegade.java @@ -0,0 +1,159 @@ + +package mage.cards.l; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.targetpointer.FixedTarget; + +import java.util.List; +import java.util.UUID; + +/** + * + * @author NinthWorld + */ +public final class LaviniaAzoriusRenegade extends CardImpl { + + public LaviniaAzoriusRenegade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{U}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.addSuperType(SuperType.LEGENDARY); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Each opponent can't cast noncreature spells with converted mana cost greater than the number of lands that player controls. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LaviniaAzoriusRenegadeReplacementEffect())); + + // Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell. + this.addAbility(new LaviniaAzoriusRenegadeTriggeredAbility()); + } + + public LaviniaAzoriusRenegade(final LaviniaAzoriusRenegade card) { + super(card); + } + + @Override + public LaviniaAzoriusRenegade copy() { + return new LaviniaAzoriusRenegade(this); + } +} + +class LaviniaAzoriusRenegadeReplacementEffect extends ContinuousRuleModifyingEffectImpl { + + LaviniaAzoriusRenegadeReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Each opponent can't cast noncreature spells with converted mana cost greater than the number of lands that player controls."; + } + + LaviniaAzoriusRenegadeReplacementEffect(final LaviniaAzoriusRenegadeReplacementEffect effect) { + super(effect); + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't cast noncreature spells with converted mana cost greater than " + getLandCount(source, event, game) + " (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (game.getPlayer(source.getControllerId()).hasOpponent(event.getPlayerId(), game)) { + FilterCard filter = new FilterCard(); + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, getLandCount(source, event, game))); + + Card card = game.getCard(event.getSourceId()); + return card != null && filter.match(card, game); + } + return false; + } + + private int getLandCount(Ability source, GameEvent event, Game game) { + int landCount = 0; + UUID playerId = event.getPlayerId(); + if(playerId != null) { + List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_LAND, playerId, source.getSourceId(), game); + for (Permanent permanent : permanents) { + if (permanent.isControlledBy(playerId)) { + landCount++; + } + } + } + return landCount; + } + + @Override + public LaviniaAzoriusRenegadeReplacementEffect copy() { + return new LaviniaAzoriusRenegadeReplacementEffect(this); + } +} + + +class LaviniaAzoriusRenegadeTriggeredAbility extends TriggeredAbilityImpl { + + public LaviniaAzoriusRenegadeTriggeredAbility() { + super(Zone.BATTLEFIELD, new CounterTargetEffect(), false); + } + + public LaviniaAzoriusRenegadeTriggeredAbility(final LaviniaAzoriusRenegadeTriggeredAbility ability) { + super(ability); + } + + @Override + public LaviniaAzoriusRenegadeTriggeredAbility copy() { + return new LaviniaAzoriusRenegadeTriggeredAbility(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 (game.getPlayer(this.getControllerId()).hasOpponent(event.getPlayerId(), game)) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && spell.getStackAbility().getManaCostsToPay().getPayment().count() == 0) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LawRuneEnforcer.java b/Mage.Sets/src/mage/cards/l/LawRuneEnforcer.java new file mode 100644 index 0000000000..1105305a9c --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LawRuneEnforcer.java @@ -0,0 +1,56 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +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.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LawRuneEnforcer extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with converted mana cost 2 or greater"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 1)); + } + + public LawRuneEnforcer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {1}, {T}: Tap target creature with converted mana cost 2 or greater. + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private LawRuneEnforcer(final LawRuneEnforcer card) { + super(card); + } + + @Override + public LawRuneEnforcer copy() { + return new LawRuneEnforcer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LawmagesBinding.java b/Mage.Sets/src/mage/cards/l/LawmagesBinding.java new file mode 100644 index 0000000000..f5d89ce814 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LawmagesBinding.java @@ -0,0 +1,52 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.combat.CantBlockAttackActivateAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LawmagesBinding extends CardImpl { + + public LawmagesBinding(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}{U}"); + + 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)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature can't attack or block, and its activate abilities can't be activated. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBlockAttackActivateAttachedEffect())); + } + + private LawmagesBinding(final LawmagesBinding card) { + super(card); + } + + @Override + public LawmagesBinding copy() { + return new LawmagesBinding(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LayBare.java b/Mage.Sets/src/mage/cards/l/LayBare.java index c65533fe61..14e5802710 100644 --- a/Mage.Sets/src/mage/cards/l/LayBare.java +++ b/Mage.Sets/src/mage/cards/l/LayBare.java @@ -58,7 +58,7 @@ class LayBareEffect extends OneShotEffect { Card target = (Card) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK); if (target != null) { Player controller = game.getPlayer(target.getOwnerId()); - if (controller != null) { + if (controller != null && player != null) { player.lookAtCards("Lay Bare", controller.getHand(), game); return true; } diff --git a/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java b/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java index fcb2eca5f2..71cdf748fe 100644 --- a/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java +++ b/Mage.Sets/src/mage/cards/l/LazavDimirMastermind.java @@ -80,7 +80,7 @@ class LazavDimirMastermindEffect extends OneShotEffect { && lazavDimirMastermind != null) { Card copyFromCard = game.getCard(((FixedTarget) getTargetPointer()).getTarget()); if (copyFromCard != null) { - newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game); + newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); newBluePrint.assignNewId(); ApplyToPermanent applier = new LazavDimirMastermindApplier(); applier.apply(game, newBluePrint, source, lazavDimirMastermind.getId()); diff --git a/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java b/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java index a8bf016ec6..5ee5f63379 100644 --- a/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java +++ b/Mage.Sets/src/mage/cards/l/LazavTheMultifarious.java @@ -110,7 +110,7 @@ class LazavTheMultifariousEffect extends OneShotEffect { && lazavTheMultifarious != null) { Card copyFromCard = game.getCard(source.getFirstTarget()); if (copyFromCard != null) { - newBluePrint = new PermanentCard((Card) copyFromCard, source.getControllerId(), game); + newBluePrint = new PermanentCard(copyFromCard, source.getControllerId(), game); newBluePrint.assignNewId(); ApplyToPermanent applier = new LazavTheMultifariousApplier(); applier.apply(game, newBluePrint, source, lazavTheMultifarious.getId()); diff --git a/Mage.Sets/src/mage/cards/l/LazotepBehemoth.java b/Mage.Sets/src/mage/cards/l/LazotepBehemoth.java new file mode 100644 index 0000000000..fa80feb27b --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LazotepBehemoth.java @@ -0,0 +1,33 @@ +package mage.cards.l; + +import mage.MageInt; +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 LazotepBehemoth extends CardImpl { + + public LazotepBehemoth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.HIPPO); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + } + + private LazotepBehemoth(final LazotepBehemoth card) { + super(card); + } + + @Override + public LazotepBehemoth copy() { + return new LazotepBehemoth(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LazotepPlating.java b/Mage.Sets/src/mage/cards/l/LazotepPlating.java new file mode 100644 index 0000000000..71964e7e32 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LazotepPlating.java @@ -0,0 +1,47 @@ +package mage.cards.l; + +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; + +import java.util.UUID; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; + +/** + * @author TheElk801 + */ +public final class LazotepPlating extends CardImpl { + + public LazotepPlating(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Amass 1. + this.getSpellAbility().addEffect(new AmassEffect(1)); + + // You and permanents you control gain hexproof until end of turn. + Effect effect = new GainAbilityControllerEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn + ); + Effect effect2 = new GainAbilityControlledEffect( + HexproofAbility.getInstance(), Duration.EndOfTurn + ); + effect.setText("You and permanents you control gain hexproof until end of turn."); + effect2.setText(""); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(effect2); + } + + private LazotepPlating(final LazotepPlating card) { + super(card); + } + + @Override + public LazotepPlating copy() { + return new LazotepPlating(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LazotepReaver.java b/Mage.Sets/src/mage/cards/l/LazotepReaver.java new file mode 100644 index 0000000000..6ba8493db3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LazotepReaver.java @@ -0,0 +1,38 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.AmassEffect; +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 LazotepReaver extends CardImpl { + + public LazotepReaver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Lazotep Reaver enters the battlefield, amass 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(1))); + } + + private LazotepReaver(final LazotepReaver card) { + super(card); + } + + @Override + public LazotepReaver copy() { + return new LazotepReaver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/Leapfrog.java b/Mage.Sets/src/mage/cards/l/Leapfrog.java index 8e1006f697..f71d344ce0 100644 --- a/Mage.Sets/src/mage/cards/l/Leapfrog.java +++ b/Mage.Sets/src/mage/cards/l/Leapfrog.java @@ -62,8 +62,8 @@ enum LeapfrogCondition implements Condition { @Override public boolean apply(Game game, Ability source) { SpellsCastWatcher watcher - = (SpellsCastWatcher) game.getState().getWatchers().get( - SpellsCastWatcher.class.getSimpleName() + = game.getState().getWatcher( + SpellsCastWatcher.class ); if (watcher == null) { return false; diff --git a/Mage.Sets/src/mage/cards/l/LeaveChance.java b/Mage.Sets/src/mage/cards/l/LeaveChance.java index 09d06d1ce1..366f9ea901 100644 --- a/Mage.Sets/src/mage/cards/l/LeaveChance.java +++ b/Mage.Sets/src/mage/cards/l/LeaveChance.java @@ -42,7 +42,7 @@ public final class LeaveChance extends SplitCard { // Chance // Sorcery // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Discard any number of cards, then draw that many cards. getRightHalfCard().getSpellAbility().addEffect(new ChanceEffect()); diff --git a/Mage.Sets/src/mage/cards/l/LedevChampion.java b/Mage.Sets/src/mage/cards/l/LedevChampion.java index 8c5d59ecae..babd14a4eb 100644 --- a/Mage.Sets/src/mage/cards/l/LedevChampion.java +++ b/Mage.Sets/src/mage/cards/l/LedevChampion.java @@ -68,7 +68,7 @@ class LedevChampionEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LedevChampionEffect() { diff --git a/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java b/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java index 3dfbf128f0..a8231f8003 100644 --- a/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java +++ b/Mage.Sets/src/mage/cards/l/LeechriddenSwamp.java @@ -1,7 +1,7 @@ - package mage.cards.l; import java.util.UUID; + import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; @@ -23,22 +23,21 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.ColorPredicate; import mage.game.Game; import mage.players.Player; -import mage.players.Players; /** - * * @author jeffwadsworth */ public final class LeechriddenSwamp extends CardImpl { - private static final FilterControlledPermanent filter = new FilterControlledPermanent("you control two or more black permanents"); + private static final FilterControlledPermanent filter = + new FilterControlledPermanent("you control two or more black permanents"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } public LeechriddenSwamp(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); this.subtype.add(SubType.SWAMP); // ({tap}: Add {B}.) @@ -48,10 +47,14 @@ public final class LeechriddenSwamp extends CardImpl { this.addAbility(new EntersBattlefieldTappedAbility()); // {B}, {tap}: Each opponent loses 1 life. Activate this ability only if you control two or more black permanents. - Ability ability = new ActivateIfConditionActivatedAbility(Zone.BATTLEFIELD, + Ability ability = new ActivateIfConditionActivatedAbility( + Zone.BATTLEFIELD, new LeechriddenSwampLoseLifeEffect(), new ManaCostsImpl("{B}"), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1)); + new PermanentsOnTheBattlefieldCondition( + filter, + ComparisonType.MORE_THAN, + 1)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -68,30 +71,32 @@ public final class LeechriddenSwamp extends CardImpl { class LeechriddenSwampLoseLifeEffect extends OneShotEffect { - private static final String effectText = "each opponent loses 1 life"; - - LeechriddenSwampLoseLifeEffect ( ) { - super(Outcome.Damage); - staticText = effectText; + LeechriddenSwampLoseLifeEffect() { + super(Outcome.Benefit); + staticText = "each opponent loses 1 life"; } - LeechriddenSwampLoseLifeEffect ( LeechriddenSwampLoseLifeEffect effect ) { - super(effect); + LeechriddenSwampLoseLifeEffect(LeechriddenSwampLoseLifeEffect effect) { + super(effect); } @Override public boolean apply(Game game, Ability source) { - Players players = game.getPlayers(); - for ( Player player : players.values() ) { - if ( !player.getId().equals(source.getControllerId()) ) { - player.loseLife(1, game, false); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID opponentId : game.getOpponents(controller.getId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + opponent.loseLife(1, game, false); + } } - } - return true; + return true; + } + return false; } @Override public LeechriddenSwampLoseLifeEffect copy() { - return new LeechriddenSwampLoseLifeEffect(this); + return new LeechriddenSwampLoseLifeEffect(this); } } diff --git a/Mage.Sets/src/mage/cards/l/LegacyOfTheBeloved.java b/Mage.Sets/src/mage/cards/l/LegacyOfTheBeloved.java index 33e44bb526..512f24085c 100644 --- a/Mage.Sets/src/mage/cards/l/LegacyOfTheBeloved.java +++ b/Mage.Sets/src/mage/cards/l/LegacyOfTheBeloved.java @@ -77,7 +77,7 @@ class LegacyOfTheBelovedEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, p.getConvertedManaCost())); TargetCardInLibrary target = new TargetCardInLibrary(0, 2, filter); Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.searchLibrary(target, game)) { + if (player != null && player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, false, false, false, null); player.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/l/LegionGuildmage.java b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java index f0ef468537..93dbb3cad0 100644 --- a/Mage.Sets/src/mage/cards/l/LegionGuildmage.java +++ b/Mage.Sets/src/mage/cards/l/LegionGuildmage.java @@ -27,7 +27,7 @@ public final class LegionGuildmage extends CardImpl { = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public LegionGuildmage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LegionLoyalist.java b/Mage.Sets/src/mage/cards/l/LegionLoyalist.java index ca675bf756..e1b7071e98 100644 --- a/Mage.Sets/src/mage/cards/l/LegionLoyalist.java +++ b/Mage.Sets/src/mage/cards/l/LegionLoyalist.java @@ -1,6 +1,5 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -20,8 +19,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; +import java.util.UUID; + /** - * * @author Plopman */ public final class LegionLoyalist extends CardImpl { @@ -75,18 +75,12 @@ class CantBeBlockedByTokenEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (affectedObjectList.contains(new MageObjectReference(permanent, game))) { - return true; - } - return false; + return affectedObjectList.contains(new MageObjectReference(permanent, game)); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (blocker instanceof PermanentToken) { - return false; - } - return true; + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return !(blocker instanceof PermanentToken); } @Override diff --git a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java index 05038cb183..8f209d80b3 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsInitiative.java +++ b/Mage.Sets/src/mage/cards/l/LegionsInitiative.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,11 +15,7 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -32,8 +26,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LegionsInitiative extends CardImpl { @@ -47,7 +42,7 @@ public final class LegionsInitiative extends CardImpl { } public LegionsInitiative(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}{W}"); // Red creatures you control get +1/+0. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(1, 0, Duration.WhileOnBattlefield, filterRedCreature))); @@ -136,12 +131,14 @@ class LegionsInitiativeReturnFromExileEffect extends OneShotEffect { exile = exile.copy(); for (UUID cardId : exile) { Card card = game.getCard(cardId); - card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); - Permanent returnedCreature = game.getPermanent(cardId); - if (returnedCreature != null) { - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(returnedCreature.getId())); - game.addEffect(effect, source); + if (card != null) { + card.moveToZone(Zone.BATTLEFIELD, source.getSourceId(), game, false); + Permanent returnedCreature = game.getPermanent(cardId); + if (returnedCreature != null) { + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(returnedCreature.getId())); + game.addEffect(effect, source); + } } } game.getExile().getExileZone(source.getSourceId()).clear(); diff --git a/Mage.Sets/src/mage/cards/l/LegionsLanding.java b/Mage.Sets/src/mage/cards/l/LegionsLanding.java index 669ac8942f..d8b6c593da 100644 --- a/Mage.Sets/src/mage/cards/l/LegionsLanding.java +++ b/Mage.Sets/src/mage/cards/l/LegionsLanding.java @@ -76,6 +76,6 @@ class LegionsLandingTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("When you attack with three or more creatures, ").append(super.getRule()).toString(); + return "When you attack with three or more creatures, " + super.getRule(); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LenaSelflessChampion.java b/Mage.Sets/src/mage/cards/l/LenaSelflessChampion.java index e86a571963..b3fbdbf3ec 100644 --- a/Mage.Sets/src/mage/cards/l/LenaSelflessChampion.java +++ b/Mage.Sets/src/mage/cards/l/LenaSelflessChampion.java @@ -38,7 +38,7 @@ public final class LenaSelflessChampion extends CardImpl { = new FilterControlledCreaturePermanent("nontoken creature you control"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public LenaSelflessChampion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LensOfClarity.java b/Mage.Sets/src/mage/cards/l/LensOfClarity.java index c958c1d375..1f0ac79046 100644 --- a/Mage.Sets/src/mage/cards/l/LensOfClarity.java +++ b/Mage.Sets/src/mage/cards/l/LensOfClarity.java @@ -93,8 +93,7 @@ class LensOfClarityLookLibraryEffect extends OneShotEffect { Card card = controller.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("top card of library - " + controller.getName(), cards, game); game.informPlayers(controller.getLogName() + " looks at the top card of their library"); } else { @@ -110,7 +109,7 @@ class LensOfClarityLookFaceDownAbility extends ActivatedAbilityImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature you don't control"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } @@ -158,8 +157,7 @@ class LensOfClarityLookFaceDownEffect extends OneShotEffect { if (faceDownCreature != null) { Permanent copyFaceDown = faceDownCreature.copy(); copyFaceDown.setFaceDown(false, game); - Cards cards = new CardsImpl(); - cards.add(copyFaceDown); + Cards cards = new CardsImpl(copyFaceDown); Player player = game.getPlayer(faceDownCreature.getControllerId()); controller.lookAtCards("face down card - " + mageObject.getName(), cards, game); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/l/LeoninBladetrap.java b/Mage.Sets/src/mage/cards/l/LeoninBladetrap.java index 007da60f6a..0bc2e9ff71 100644 --- a/Mage.Sets/src/mage/cards/l/LeoninBladetrap.java +++ b/Mage.Sets/src/mage/cards/l/LeoninBladetrap.java @@ -26,7 +26,7 @@ public final class LeoninBladetrap extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature without flying"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } diff --git a/Mage.Sets/src/mage/cards/l/LeovoldEmissaryOfTrest.java b/Mage.Sets/src/mage/cards/l/LeovoldEmissaryOfTrest.java index 270e050053..675371692d 100644 --- a/Mage.Sets/src/mage/cards/l/LeovoldEmissaryOfTrest.java +++ b/Mage.Sets/src/mage/cards/l/LeovoldEmissaryOfTrest.java @@ -71,7 +71,7 @@ class LeovoldEmissaryOfTrestEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - CardsAmountDrawnThisTurnWatcher watcher = (CardsAmountDrawnThisTurnWatcher) game.getState().getWatchers().get(CardsAmountDrawnThisTurnWatcher.class.getSimpleName()); + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); Player controller = game.getPlayer(source.getControllerId()); return watcher != null && controller != null && watcher.getAmountCardsDrawn(event.getPlayerId()) >= 1 && game.isOpponent(controller, event.getPlayerId()); diff --git a/Mage.Sets/src/mage/cards/l/LesserWerewolf.java b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java new file mode 100644 index 0000000000..84d836b950 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LesserWerewolf.java @@ -0,0 +1,93 @@ + +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +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.constants.Duration; +import mage.constants.Outcome; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.BoostCounter; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class LesserWerewolf extends CardImpl { + + public LesserWerewolf(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + this.subtype.add(SubType.WEREWOLF); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {B}: If Lesser Werewolf’s power is 1 or more, it gets -1/-0 until end of turn and put a -0/-1 counter on target creature blocking or blocked by Lesser Werewolf. Activate this ability only during the declare blockers step. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new LesserWerewolfEffect(), new ManaCostsImpl("{B}"), new IsStepCondition(PhaseStep.DECLARE_BLOCKERS, false)); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by Lesser Werewolf"); + filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), + new BlockingAttackerIdPredicate(this.getId()))); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + + } + + public LesserWerewolf(final LesserWerewolf card) { + super(card); + } + + @Override + public LesserWerewolf copy() { + return new LesserWerewolf(this); + } +} + +class LesserWerewolfEffect extends OneShotEffect { + + public LesserWerewolfEffect() { + super(Outcome.Detriment); + this.staticText = "If {this}’s power is 1 or more, it gets -1/-0 until end of turn and put a -0/-1 counter on target creature blocking or blocked by {this}"; + } + + public LesserWerewolfEffect(final LesserWerewolfEffect effect) { + super(effect); + } + + @Override + public LesserWerewolfEffect copy() { + return new LesserWerewolfEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent targetPermanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if (controller != null && sourcePermanent != null && targetPermanent != null) { + if (sourcePermanent.getPower().getValue() >= 1) { + game.addEffect(new BoostSourceEffect(-1, 0, Duration.EndOfTurn), source); + new AddCountersTargetEffect(new BoostCounter(0, -1), outcome).apply(game, source); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LethargyTrap.java b/Mage.Sets/src/mage/cards/l/LethargyTrap.java index d06efc253c..ecad496447 100644 --- a/Mage.Sets/src/mage/cards/l/LethargyTrap.java +++ b/Mage.Sets/src/mage/cards/l/LethargyTrap.java @@ -26,7 +26,7 @@ public final class LethargyTrap extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creatures"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public LethargyTrap(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/Leveler.java b/Mage.Sets/src/mage/cards/l/Leveler.java index c1bd153050..4fe4a55d2e 100644 --- a/Mage.Sets/src/mage/cards/l/Leveler.java +++ b/Mage.Sets/src/mage/cards/l/Leveler.java @@ -60,8 +60,7 @@ class LevelerExileLibraryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int count = controller.getLibrary().size(); - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, count)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, count)); controller.moveCards(cards, Zone.EXILED, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/l/LeylineOfVitality.java b/Mage.Sets/src/mage/cards/l/LeylineOfVitality.java index 42be613481..8808969cec 100644 --- a/Mage.Sets/src/mage/cards/l/LeylineOfVitality.java +++ b/Mage.Sets/src/mage/cards/l/LeylineOfVitality.java @@ -1,8 +1,7 @@ package mage.cards.l; -import java.util.UUID; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; @@ -14,8 +13,9 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class LeylineOfVitality extends CardImpl { @@ -23,10 +23,19 @@ public final class LeylineOfVitality extends CardImpl { public LeylineOfVitality(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); + // If Leyline of Vitality is in your opening hand, you may begin the game with it on the battlefield. this.addAbility(LeylineAbility.getInstance()); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false))); - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new GainLifeEffect(1), true)); + // Creatures you control get +0/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostControlledEffect(0, 1, Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURES, false))); + + // Whenever a creature enters the battlefield under your control, you may gain 1 life. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new GainLifeEffect(1), + StaticFilters.FILTER_PERMANENT_CREATURE_A, + true) + ); } public LeylineOfVitality(final LeylineOfVitality card) { diff --git a/Mage.Sets/src/mage/cards/l/LeylineProwler.java b/Mage.Sets/src/mage/cards/l/LeylineProwler.java new file mode 100644 index 0000000000..0a5e003aac --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LeylineProwler.java @@ -0,0 +1,45 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.mana.AnyColorManaAbility; +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 LeylineProwler extends CardImpl { + + public LeylineProwler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); + + this.subtype.add(SubType.NIGHTMARE); + this.subtype.add(SubType.BEAST); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private LeylineProwler(final LeylineProwler card) { + super(card); + } + + @Override + public LeylineProwler copy() { + return new LeylineProwler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/Liability.java b/Mage.Sets/src/mage/cards/l/Liability.java index 6973291332..0c1930b7ed 100644 --- a/Mage.Sets/src/mage/cards/l/Liability.java +++ b/Mage.Sets/src/mage/cards/l/Liability.java @@ -1,11 +1,8 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,20 +15,21 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author L_J */ public final class Liability extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("a nontoken permanent"); - + static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } - + public Liability(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); // Whenever a nontoken permanent is put into a player's graveyard from the battlefield, that player loses 1 life. this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new LiabilityEffect(), false, filter, true)); diff --git a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java index 5163fdcb7f..bf86998ce4 100644 --- a/Mage.Sets/src/mage/cards/l/LiarsPendulum.java +++ b/Mage.Sets/src/mage/cards/l/LiarsPendulum.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; @@ -20,9 +18,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class LiarsPendulum extends CardImpl { @@ -93,7 +93,7 @@ class LiarsPendulumEffect extends OneShotEffect { rightGuess = opponentGuess; } } - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { rightGuess = opponentGuess; } } diff --git a/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java b/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java index 3594272808..339bdf95df 100644 --- a/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java +++ b/Mage.Sets/src/mage/cards/l/LiberatingCombustion.java @@ -17,7 +17,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class LiberatingCombustion extends CardImpl { - private final static FilterCard filter = new FilterCard("Chandra, Pyrogenius"); + private static final FilterCard filter = new FilterCard("Chandra, Pyrogenius"); static { filter.add(new NamePredicate("Chandra, Pyrogenius")); diff --git a/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java b/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java index fd997f407c..5a53390751 100644 --- a/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java +++ b/Mage.Sets/src/mage/cards/l/LibraryOfLatNam.java @@ -31,7 +31,7 @@ public final class LibraryOfLatNam extends CardImpl { Mode mode = new Mode(); Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(), false, true); //effect.setText("you search your library for a card, put that card into your hand, then shuffle your library"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/l/Lich.java b/Mage.Sets/src/mage/cards/l/Lich.java index 523d67acc0..e77d1031f5 100644 --- a/Mage.Sets/src/mage/cards/l/Lich.java +++ b/Mage.Sets/src/mage/cards/l/Lich.java @@ -41,7 +41,7 @@ public final class Lich extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{B}{B}{B}"); // As Lich enters the battlefield, you lose life equal to your life total. - this.addAbility(new EntersBattlefieldAbility(new LoseLifeSourceControllerEffect(new ControllerLifeCount()), null, "As Lich enters the battlefield, you lose life equal to your life total.", null)); + this.addAbility(new EntersBattlefieldAbility(new LoseLifeSourceControllerEffect(ControllerLifeCount.instance), null, "As Lich enters the battlefield, you lose life equal to your life total.", null)); // You don't lose the game for having 0 or less life. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DontLoseByZeroOrLessLifeEffect(Duration.WhileOnBattlefield))); @@ -145,7 +145,7 @@ class LichDamageEffect extends OneShotEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("nontoken permanent"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } private int amount = 0; diff --git a/Mage.Sets/src/mage/cards/l/LiciaSanguineTribune.java b/Mage.Sets/src/mage/cards/l/LiciaSanguineTribune.java index 05adae4187..599139b73f 100644 --- a/Mage.Sets/src/mage/cards/l/LiciaSanguineTribune.java +++ b/Mage.Sets/src/mage/cards/l/LiciaSanguineTribune.java @@ -112,9 +112,9 @@ class YouGainLifeCount implements DynamicValue { } public int calculate(Game game, UUID controllerId) { - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getSimpleName()); + PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); if (watcher != null) { - return watcher.getLiveGained(controllerId); + return watcher.getLifeGained(controllerId); } return 0; } diff --git a/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java b/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java index e3d9eea26e..7e63ce8903 100644 --- a/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java +++ b/Mage.Sets/src/mage/cards/l/LiegeOfThePit.java @@ -86,7 +86,7 @@ class LiegeOfThePitEffect extends OneShotEffect { } FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature other than " + sourcePermanent.getName()); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); if (target.canChoose(source.getSourceId(), player.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/l/LifeMatrix.java b/Mage.Sets/src/mage/cards/l/LifeMatrix.java new file mode 100644 index 0000000000..09bb4c904e --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LifeMatrix.java @@ -0,0 +1,51 @@ + +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.RemoveCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class LifeMatrix extends CardImpl { + + public LifeMatrix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + // {4}, {T}: Put a matrix counter on target creature and that creature gains “Remove a matrix counter from this creature: Regenerate this creature.” Activate this ability only during your upkeep. + Ability ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.MATRIX.createInstance()), new GenericManaCost(4), + new IsStepCondition(PhaseStep.UPKEEP), null); + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new RemoveCountersSourceCost(CounterType.MATRIX.createInstance())); + ability.addEffect(new GainAbilityTargetEffect(ability2, Duration.Custom)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public LifeMatrix(final LifeMatrix card) { + super(card); + } + + @Override + public LifeMatrix copy() { + return new LifeMatrix(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java b/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java index 7aabdf3f90..a6ff60b501 100644 --- a/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java +++ b/Mage.Sets/src/mage/cards/l/LifecraftAwakening.java @@ -39,7 +39,7 @@ public final class LifecraftAwakening extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); // Put X +1/+1 counters on target artifact you control. If it isn't a creature or Vehicle, it becomes a 0/0 Construct artifact creature. - ManacostVariableValue manaX = new ManacostVariableValue(); + ManacostVariableValue manaX = ManacostVariableValue.instance; getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(), manaX)); getSpellAbility().addTarget(new TargetArtifactPermanent(filter)); getSpellAbility().addEffect(new LifecraftAwakeningEffect()); diff --git a/Mage.Sets/src/mage/cards/l/LifesFinale.java b/Mage.Sets/src/mage/cards/l/LifesFinale.java index e0c208d7a2..5c8d83a138 100644 --- a/Mage.Sets/src/mage/cards/l/LifesFinale.java +++ b/Mage.Sets/src/mage/cards/l/LifesFinale.java @@ -70,7 +70,7 @@ class LifesFinaleEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && opponent != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 3, new FilterCreatureCard("creature cards from his library to put in his graveyard")); - if (player.searchLibrary(target, game, opponent.getId())) { + if (player.searchLibrary(target, source, game, opponent.getId())) { player.moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); } opponent.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/l/LightUpTheStage.java b/Mage.Sets/src/mage/cards/l/LightUpTheStage.java new file mode 100644 index 0000000000..21aa8ff2b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LightUpTheStage.java @@ -0,0 +1,125 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 and jeffwadsworth + */ +public final class LightUpTheStage extends CardImpl { + + public LightUpTheStage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Exile the top two cards of your library. Until the end of your next turn, you may play those cards. + this.getSpellAbility().addEffect(new LightUpTheStageEffect()); + + // Spectacle {R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{R}"))); + } + + public LightUpTheStage(final LightUpTheStage card) { + super(card); + } + + @Override + public LightUpTheStage copy() { + return new LightUpTheStage(this); + } +} + +class LightUpTheStageEffect extends OneShotEffect { + + LightUpTheStageEffect() { + super(Outcome.PlayForFree); + this.staticText = "Exile the top two cards of your library. Until the end of your next turn, you may play those cards"; + } + + private LightUpTheStageEffect(final LightUpTheStageEffect effect) { + super(effect); + } + + @Override + public LightUpTheStageEffect copy() { + return new LightUpTheStageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Set cards = controller.getLibrary().getTopCards(game, 2); + Card sourceCard = game.getCard(source.getSourceId()); + controller.moveCardsToExile(cards, source, game, true, CardUtil.getCardExileZoneId(game, source), sourceCard != null ? sourceCard.getIdName() : ""); + + for (Card card : cards) { + ContinuousEffect effect = new LightUpTheStageMayPlayEffect(); + effect.setTargetPointer(new FixedTarget(card.getId())); + game.addEffect(effect, source); + } + + return true; + } + return false; + } +} + +class LightUpTheStageMayPlayEffect extends AsThoughEffectImpl { + + private int castOnTurn = 0; + + LightUpTheStageMayPlayEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.staticText = "Until the end of your next turn, you may play that card."; + } + + private LightUpTheStageMayPlayEffect(final LightUpTheStageMayPlayEffect effect) { + super(effect); + castOnTurn = effect.castOnTurn; + } + + @Override + public LightUpTheStageMayPlayEffect copy() { + return new LightUpTheStageMayPlayEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + castOnTurn = game.getTurnNum(); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (castOnTurn != game.getTurnNum() && game.getPhase().getStep().getType() == PhaseStep.END_TURN) { + return game.isActivePlayer(source.getControllerId()); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + return source.isControlledBy(affectedControllerId) + && getTargetPointer().getTargets(game, source).contains(sourceId); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LightkeeperOfEmeria.java b/Mage.Sets/src/mage/cards/l/LightkeeperOfEmeria.java index 05cad39bf7..2b3be08030 100644 --- a/Mage.Sets/src/mage/cards/l/LightkeeperOfEmeria.java +++ b/Mage.Sets/src/mage/cards/l/LightkeeperOfEmeria.java @@ -35,7 +35,7 @@ public final class LightkeeperOfEmeria extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Lightkeeper of Emeria enters the battlefield, you gain 2 life for each time it was kicked. - Effect effect = new GainLifeEffect(new MultipliedValue(new MultikickerCount(), 2)); + Effect effect = new GainLifeEffect(new MultipliedValue(MultikickerCount.instance, 2)); effect.setText("you gain 2 life for each time it was kicked"); this.addAbility(new EntersBattlefieldTriggeredAbility(effect, false)); } diff --git a/Mage.Sets/src/mage/cards/l/LightningCloud.java b/Mage.Sets/src/mage/cards/l/LightningCloud.java index ddd5835798..d3aa563ea6 100644 --- a/Mage.Sets/src/mage/cards/l/LightningCloud.java +++ b/Mage.Sets/src/mage/cards/l/LightningCloud.java @@ -21,7 +21,7 @@ import mage.target.common.TargetAnyTarget; */ public final class LightningCloud extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a red spell"); + private static final FilterSpell filter = new FilterSpell("a red spell"); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/l/LightningCoils.java b/Mage.Sets/src/mage/cards/l/LightningCoils.java index 22885e7b29..9b290065a0 100644 --- a/Mage.Sets/src/mage/cards/l/LightningCoils.java +++ b/Mage.Sets/src/mage/cards/l/LightningCoils.java @@ -32,7 +32,7 @@ public final class LightningCoils extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public LightningCoils(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java index f6a0956905..f4db5ab2b7 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaDefiantNecromancer.java @@ -1,4 +1,3 @@ - package mage.cards.l; import java.util.UUID; @@ -21,6 +20,7 @@ import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.game.command.emblems.LilianaDefiantNecromancerEmblem; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -28,14 +28,12 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class LilianaDefiantNecromancer extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature with converted mana cost X from your graveyard"); + protected static final FilterCreatureCard filter = new FilterCreatureCard("nonlegendary creature with converted mana cost X from your graveyard"); static { filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); } - UUID ability2Id; - public LilianaDefiantNecromancer(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, ""); this.addSuperType(SuperType.LEGENDARY); @@ -49,36 +47,18 @@ public final class LilianaDefiantNecromancer extends CardImpl { // +2: Each player discards a card. this.addAbility(new LoyaltyAbility(new DiscardEachPlayerEffect(1, false), 2)); - //TODO: Make ability properly copiable // -X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield. Ability ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect()); - ability2Id = ability.getOriginalId(); ability.addTarget(new TargetCardInYourGraveyard(filter)); + ability.setTargetAdjuster(LilianaDefiantNecromancerAdjuster.instance); this.addAbility(ability); //-8: You get an emblem with "Whenever a creature dies, return it to the battlefield under your control at the beginning of the next end step."; this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new LilianaDefiantNecromancerEmblem()), -8)); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(ability2Id)) { - int cmc = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof PayVariableLoyaltyCost) { - cmc = ((PayVariableLoyaltyCost) cost).getAmount(); - } - } - FilterCard newFilter = filter.copy(); - newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(newFilter)); - } - } - public LilianaDefiantNecromancer(final LilianaDefiantNecromancer card) { super(card); - this.ability2Id = card.ability2Id; } @Override @@ -86,3 +66,21 @@ public final class LilianaDefiantNecromancer extends CardImpl { return new LilianaDefiantNecromancer(this); } } + +enum LilianaDefiantNecromancerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int cmc = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + cmc = ((PayVariableLoyaltyCost) cost).getAmount(); + } + } + FilterCard newFilter = LilianaDefiantNecromancer.filter.copy(); + newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(newFilter)); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java b/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java new file mode 100644 index 0000000000..ba46e4fa66 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LilianaDreadhordeGeneral.java @@ -0,0 +1,119 @@ +package mage.cards.l; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.SacrificeAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardIdPredicate; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieToken; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LilianaDreadhordeGeneral extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("creatures"); + + public LilianaDreadhordeGeneral(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.LILIANA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + + // Whenever a creature you control dies, draw a card. + this.addAbility(new DiesCreatureTriggeredAbility( + new DrawCardSourceControllerEffect(1), false, + StaticFilters.FILTER_CONTROLLED_A_CREATURE + )); + + // +1: Create a 2/2 black Zombie creature token. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new ZombieToken()), 1)); + + // -4: Each player sacrifices two creatures. + this.addAbility(new LoyaltyAbility(new SacrificeAllEffect(2, filter), -4)); + + // -9: Each opponent chooses a permanent they control of each permanent type and sacrifices the rest. + this.addAbility(new LoyaltyAbility(new LilianaDreadhordeGeneralEffect(), -9)); + } + + private LilianaDreadhordeGeneral(final LilianaDreadhordeGeneral card) { + super(card); + } + + @Override + public LilianaDreadhordeGeneral copy() { + return new LilianaDreadhordeGeneral(this); + } +} + +class LilianaDreadhordeGeneralEffect extends OneShotEffect { + + LilianaDreadhordeGeneralEffect() { + super(Outcome.Benefit); + staticText = "Each opponent chooses a permanent they control of each permanent type and sacrifices the rest."; + } + + private LilianaDreadhordeGeneralEffect(final LilianaDreadhordeGeneralEffect effect) { + super(effect); + } + + @Override + public LilianaDreadhordeGeneralEffect copy() { + return new LilianaDreadhordeGeneralEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent keepFilter = new FilterPermanent(); + keepFilter.add(new ControllerPredicate(TargetController.OPPONENT)); + for (UUID opponentId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null || !opponent.hasOpponent(source.getControllerId(), game)) { + continue; + } + for (CardType cardType : CardType.values()) { + if (!cardType.isPermanentType()) { + continue; + } + FilterControlledPermanent filter = new FilterControlledPermanent( + "a " + cardType.toString() + " you control " + + "(everything you don't choose will be sacrificed)" + ); + filter.add(new CardTypePredicate(cardType)); + Target target = new TargetControlledPermanent(filter); + target.setNotTarget(true); + if (opponent.choose(outcome, target, source.getSourceId(), game)) { + keepFilter.add(Predicates.not(new CardIdPredicate(target.getFirstTarget()))); + } + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (keepFilter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + permanent.sacrifice(source.getSourceId(), game); + } + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java b/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java index c0ad532fb8..990e7a7b2e 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java +++ b/Mage.Sets/src/mage/cards/l/LilianaHereticalHealer.java @@ -32,8 +32,8 @@ public final class LilianaHereticalHealer extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public LilianaHereticalHealer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LilianasContract.java b/Mage.Sets/src/mage/cards/l/LilianasContract.java index 68ca809240..52b275fd31 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasContract.java +++ b/Mage.Sets/src/mage/cards/l/LilianasContract.java @@ -67,7 +67,7 @@ enum LilianasContractCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Set demonNames = new HashSet(); + Set demonNames = new HashSet<>(); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { if (permanent == null || !permanent.isControlledBy(source.getControllerId()) diff --git a/Mage.Sets/src/mage/cards/l/LilianasInfluence.java b/Mage.Sets/src/mage/cards/l/LilianasInfluence.java index a9876a6855..7ba1d7345a 100644 --- a/Mage.Sets/src/mage/cards/l/LilianasInfluence.java +++ b/Mage.Sets/src/mage/cards/l/LilianasInfluence.java @@ -20,8 +20,8 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class LilianasInfluence extends CardImpl { - private final static FilterCard filter = new FilterCard("Liliana, Death Wielder"); - private final static FilterCreaturePermanent filterCreatures = new FilterCreaturePermanent("creature you don't control"); + private static final FilterCard filter = new FilterCard("Liliana, Death Wielder"); + private static final FilterCreaturePermanent filterCreatures = new FilterCreaturePermanent("creature you don't control"); static { filter.add(new NamePredicate("Liliana, Death Wielder")); diff --git a/Mage.Sets/src/mage/cards/l/LilianasTriumph.java b/Mage.Sets/src/mage/cards/l/LilianasTriumph.java new file mode 100644 index 0000000000..5cb8a89ec4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LilianasTriumph.java @@ -0,0 +1,50 @@ +package mage.cards.l; + +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.SacrificeOpponentsEffect; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LilianasTriumph extends CardImpl { + + private static final FilterControlledPlaneswalkerPermanent filter + = new FilterControlledPlaneswalkerPermanent(SubType.LILIANA); + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + + public LilianasTriumph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Each opponent sacrifices a creature. If you control a Liliana planeswalker, each opponent also discards a card. + this.getSpellAbility().addEffect(new SacrificeOpponentsEffect( + StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT + )); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new DiscardEachPlayerEffect( + new StaticValue(1), false, TargetController.OPPONENT + ), condition, "If you control a Liliana planeswalker, each opponent also discards a card." + )); + } + + private LilianasTriumph(final LilianasTriumph card) { + super(card); + } + + @Override + public LilianasTriumph copy() { + return new LilianasTriumph(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LimDulsCohort.java b/Mage.Sets/src/mage/cards/l/LimDulsCohort.java new file mode 100644 index 0000000000..fee4085bbd --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LimDulsCohort.java @@ -0,0 +1,45 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.BlocksOrBecomesBlockedTriggeredAbility; +import mage.abilities.effects.common.CantBeRegeneratedTargetEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class LimDulsCohort extends CardImpl { + + public LimDulsCohort(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Lim-Dûl's Cohort blocks or becomes blocked by a creature, that creature can't be regenerated this turn. + this.addAbility(new BlocksOrBecomesBlockedTriggeredAbility( + new CantBeRegeneratedTargetEffect(Duration.EndOfTurn), + new FilterCreaturePermanent(), + false, + "Whenever {this} blocks or becomes blocked by a creature, that creature can't be regenerated this turn.", + true)); + + } + + private LimDulsCohort(final LimDulsCohort card) { + super(card); + } + + @Override + public LimDulsCohort copy() { + return new LimDulsCohort(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LimitedResources.java b/Mage.Sets/src/mage/cards/l/LimitedResources.java new file mode 100644 index 0000000000..fc97e01423 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LimitedResources.java @@ -0,0 +1,124 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.common.TargetLandPermanent; + +/** + * + * @author jeffwadsworth + */ +public final class LimitedResources extends CardImpl { + + public LimitedResources(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // When Limited Resources enters the battlefield, each player chooses five lands he or she controls and sacrifices the rest. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LimitedResourcesEffect(), false)); + + // Players can't play lands as long as ten or more lands are on the battlefield. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousRuleModifyingEffect( + new CantPlayLandEffect(), + new PermanentsOnTheBattlefieldCondition( + new FilterLandPermanent(), + ComparisonType.MORE_THAN, 9)))); + + } + + public LimitedResources(final LimitedResources card) { + super(card); + } + + @Override + public LimitedResources copy() { + return new LimitedResources(this); + } +} + +class LimitedResourcesEffect extends OneShotEffect { + + public LimitedResourcesEffect() { + super(Outcome.Benefit); + this.staticText = "each player chooses five lands he or she controls and sacrifices the rest"; + } + + public LimitedResourcesEffect(final LimitedResourcesEffect effect) { + super(effect); + } + + @Override + public LimitedResourcesEffect copy() { + return new LimitedResourcesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.getState().getPlayersInRange(source.getControllerId(), game).forEach((playerId) -> { + Player player = game.getPlayer(playerId); + if (player != null) { + int lands = game.getBattlefield().countAll(new FilterControlledLandPermanent(), playerId, game); + TargetLandPermanent target = new TargetLandPermanent(Integer.min(5, lands)); + target.setNotTarget(true); + target.setRequired(true); + player.chooseTarget(outcome.Benefit, target, source, game); + game.getBattlefield().getAllActivePermanents(new FilterControlledLandPermanent(), playerId, game).stream().filter((land) -> (!target.getTargets().contains(land.getId()))).forEachOrdered((land) -> { + land.sacrifice(source.getSourceId(), game); + }); + } + }); + return true; + } +} + +class CantPlayLandEffect extends ContinuousRuleModifyingEffectImpl { + + public CantPlayLandEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "Players can't play lands as long as ten or more lands are on the battlefield"; + } + + public CantPlayLandEffect(final CantPlayLandEffect effect) { + super(effect); + } + + @Override + public CantPlayLandEffect copy() { + return new CantPlayLandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/l/LinSivviDefiantHero.java b/Mage.Sets/src/mage/cards/l/LinSivviDefiantHero.java index 9651f38dd5..c9ec6edc26 100644 --- a/Mage.Sets/src/mage/cards/l/LinSivviDefiantHero.java +++ b/Mage.Sets/src/mage/cards/l/LinSivviDefiantHero.java @@ -95,12 +95,12 @@ class LinSivviDefiantHeroEffect extends OneShotEffect { int xCost = source.getManaCostsToPay().getX(); - FilterPermanentCard filter = new FilterPermanentCard(new StringBuilder("Rebel permanent card with converted mana cost ").append(xCost).append(" or less").toString()); + FilterPermanentCard filter = new FilterPermanentCard("Rebel permanent card with converted mana cost " + xCost + " or less"); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xCost + 1)); filter.add(new SubtypePredicate(SubType.REBEL)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/l/LingeringPhantom.java b/Mage.Sets/src/mage/cards/l/LingeringPhantom.java index 380cfca809..1a16edbbbd 100644 --- a/Mage.Sets/src/mage/cards/l/LingeringPhantom.java +++ b/Mage.Sets/src/mage/cards/l/LingeringPhantom.java @@ -24,7 +24,7 @@ public final class LingeringPhantom extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public LingeringPhantom(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LinvalaKeeperOfSilence.java b/Mage.Sets/src/mage/cards/l/LinvalaKeeperOfSilence.java index fc7ea70a13..04f7e6d73c 100644 --- a/Mage.Sets/src/mage/cards/l/LinvalaKeeperOfSilence.java +++ b/Mage.Sets/src/mage/cards/l/LinvalaKeeperOfSilence.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,16 +7,13 @@ import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Loki */ public final class LinvalaKeeperOfSilence extends CardImpl { @@ -66,7 +61,7 @@ class LinvalaKeeperOfSilenceCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LiquidFire.java b/Mage.Sets/src/mage/cards/l/LiquidFire.java index 04b40d1413..32737ce082 100644 --- a/Mage.Sets/src/mage/cards/l/LiquidFire.java +++ b/Mage.Sets/src/mage/cards/l/LiquidFire.java @@ -30,7 +30,7 @@ public final class LiquidFire extends CardImpl { // As an additional cost to cast Liquid Fire, choose a number between 0 and 5. this.getSpellAbility().addCost(new LiquidFireCost()); // Liquid Fire deals X damage to target creature and 5 minus X damage to that creature's controller, where X is the chosen number. - DynamicValue choiceValue = new GetXValue(); + DynamicValue choiceValue = GetXValue.instance; this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new LiquidFireEffect(choiceValue)); diff --git a/Mage.Sets/src/mage/cards/l/LivingDeath.java b/Mage.Sets/src/mage/cards/l/LivingDeath.java index 9a67de26d3..032aa651d8 100644 --- a/Mage.Sets/src/mage/cards/l/LivingDeath.java +++ b/Mage.Sets/src/mage/cards/l/LivingDeath.java @@ -2,6 +2,7 @@ package mage.cards.l; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -65,7 +66,9 @@ class LivingDeathEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { Map> exiledCards = new HashMap<>(); - // move creature cards from graveyard to exile + + // Move creature cards from graveyard to exile + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { @@ -77,21 +80,28 @@ class LivingDeathEffect extends OneShotEffect { } } game.applyEffects(); - // sacrifice all creatures + + // Sacrifice all creatures + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game)) { permanent.sacrifice(source.getSourceId(), game); } game.applyEffects(); - // put exiled cards to battlefield + + // Exiled cards are put onto the battlefield at the same time under their owner's control + + Set cardsToReturnFromExile = new HashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { Set cardsPlayer = exiledCards.get(playerId); - if (cardsPlayer != null && !cardsPlayer.isEmpty()) { - player.moveCards(cardsPlayer, Zone.BATTLEFIELD, source, game, false, false, false, null); + if (cardsPlayer != null + && !cardsPlayer.isEmpty()) { + cardsToReturnFromExile.addAll(cardsPlayer); } } } + controller.moveCards(cardsToReturnFromExile, Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/l/LivingInferno.java b/Mage.Sets/src/mage/cards/l/LivingInferno.java index 5d8992a61e..50e31e7471 100644 --- a/Mage.Sets/src/mage/cards/l/LivingInferno.java +++ b/Mage.Sets/src/mage/cards/l/LivingInferno.java @@ -1,9 +1,6 @@ package mage.cards.l; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,50 +9,38 @@ 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.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetCreaturePermanentAmount; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author LevelX2 & L_J */ public final class LivingInferno extends CardImpl { - private final UUID originalId; - public LivingInferno(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{R}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(8); this.toughness = new MageInt(5); // {T}: Living Inferno deals damage equal to its power divided as you choose among any number of target creatures. Each of those creatures deals damage equal to its power to Living Inferno. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LivingInfernoEffect(), new TapSourceCost()); - ability.addTarget(new TargetCreaturePermanentAmount(1)); + ability.setTargetAdjuster(LivingInfernoAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); - if (sourcePermanent != null) { - int xValue = sourcePermanent.getPower().getValue(); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanentAmount(xValue)); - } - } } public LivingInferno(final LivingInferno card) { super(card); - this.originalId = card.originalId; } @Override @@ -64,11 +49,26 @@ public final class LivingInferno extends CardImpl { } } +enum LivingInfernoAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(ability.getSourceId()); + if (sourcePermanent != null) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanentAmount(sourcePermanent.getPower().getValue())); + } + } +} + class LivingInfernoEffect extends OneShotEffect { public LivingInfernoEffect() { super(Outcome.Benefit); - this.staticText = "{this} deals damage equal to its power divided as you choose among any number of target creatures. Each of those creatures deals damage equal to its power to {this}"; + this.staticText = "{this} deals damage equal to its power " + + "divided as you choose among any number of target creatures. " + + "Each of those creatures deals damage equal to its power to {this}"; } public LivingInfernoEffect(final LivingInfernoEffect effect) { diff --git a/Mage.Sets/src/mage/cards/l/LivingLore.java b/Mage.Sets/src/mage/cards/l/LivingLore.java index 7438a74bc3..85b5d1144f 100644 --- a/Mage.Sets/src/mage/cards/l/LivingLore.java +++ b/Mage.Sets/src/mage/cards/l/LivingLore.java @@ -14,12 +14,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.ExileZone; import mage.game.Game; @@ -36,7 +31,7 @@ public final class LivingLore extends CardImpl { public LivingLore(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); - this.subtype.add("Avatar"); + this.subtype.add(SubType.AVATAR); this.power = new MageInt(0); this.toughness = new MageInt(0); diff --git a/Mage.Sets/src/mage/cards/l/LivingTotem.java b/Mage.Sets/src/mage/cards/l/LivingTotem.java index 1f1eb84004..7c63adb3c5 100644 --- a/Mage.Sets/src/mage/cards/l/LivingTotem.java +++ b/Mage.Sets/src/mage/cards/l/LivingTotem.java @@ -25,7 +25,7 @@ public final class LivingTotem extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public LivingTotem(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LivingTwister.java b/Mage.Sets/src/mage/cards/l/LivingTwister.java new file mode 100644 index 0000000000..11518351d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LivingTwister.java @@ -0,0 +1,64 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ReturnToHandChosenControlledPermanentEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LivingTwister extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledLandPermanent("a tapped land you control"); + + static { + filter.add(TappedPredicate.instance); + } + + public LivingTwister(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}{G}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(2); + this.toughness = new MageInt(5); + + // {1}{R}, Discard a land card: Living Twister deals 2 damage to any target. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2), new ManaCostsImpl("{1}{R}") + ); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_LAND_A))); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + + // {G}: Return a tapped land you control to its owner's hand. + this.addAbility(new SimpleActivatedAbility( + new ReturnToHandChosenControlledPermanentEffect(filter), new ManaCostsImpl("{G}") + )); + } + + private LivingTwister(final LivingTwister card) { + super(card); + } + + @Override + public LivingTwister copy() { + return new LivingTwister(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java b/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java index f0a0228414..2757f292e6 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarBehemoth.java @@ -25,7 +25,7 @@ public final class LlanowarBehemoth extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LlanowarBehemoth(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java b/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java index e4544ab727..6cf148a651 100644 --- a/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java +++ b/Mage.Sets/src/mage/cards/l/LlanowarEmpath.java @@ -73,9 +73,9 @@ class LlanowarEmpathEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); if (card != null) { + Cards cards = new CardsImpl(); cards.add(card); controller.revealCards(sourceObject.getName(), cards, game); if (card.isCreature()) { diff --git a/Mage.Sets/src/mage/cards/l/LoamDryad.java b/Mage.Sets/src/mage/cards/l/LoamDryad.java index d4e1f9d8eb..b2940609ab 100644 --- a/Mage.Sets/src/mage/cards/l/LoamDryad.java +++ b/Mage.Sets/src/mage/cards/l/LoamDryad.java @@ -24,7 +24,7 @@ public final class LoamDryad extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LoamDryad(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/Lobotomy.java b/Mage.Sets/src/mage/cards/l/Lobotomy.java index 9471944381..c3decfd979 100644 --- a/Mage.Sets/src/mage/cards/l/Lobotomy.java +++ b/Mage.Sets/src/mage/cards/l/Lobotomy.java @@ -114,7 +114,7 @@ class LobotomyEffect extends OneShotEffect { // If the player has no nonland cards in their hand, you can still search that player's library and have him or her shuffle it. if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", source, game)) { TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); - controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); + controller.searchLibrary(targetCardsLibrary, source, game, targetPlayer.getId()); for (UUID cardId : targetCardsLibrary.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/l/LodestoneMyr.java b/Mage.Sets/src/mage/cards/l/LodestoneMyr.java index 274faad42e..fcbd7bf7e8 100644 --- a/Mage.Sets/src/mage/cards/l/LodestoneMyr.java +++ b/Mage.Sets/src/mage/cards/l/LodestoneMyr.java @@ -26,7 +26,7 @@ public final class LodestoneMyr extends CardImpl { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("untapped artifact you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LodestoneMyr(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LogicKnot.java b/Mage.Sets/src/mage/cards/l/LogicKnot.java index 49b6eaff91..daa6d03ee1 100644 --- a/Mage.Sets/src/mage/cards/l/LogicKnot.java +++ b/Mage.Sets/src/mage/cards/l/LogicKnot.java @@ -24,7 +24,7 @@ public final class LogicKnot extends CardImpl { this.addAbility(new DelveAbility()); // Counter target spell unless its controller pays {X}. - this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetSpell()); } diff --git a/Mage.Sets/src/mage/cards/l/LongTermPlans.java b/Mage.Sets/src/mage/cards/l/LongTermPlans.java index ee0b6f05c9..3f2b2b33e7 100644 --- a/Mage.Sets/src/mage/cards/l/LongTermPlans.java +++ b/Mage.Sets/src/mage/cards/l/LongTermPlans.java @@ -57,7 +57,7 @@ class LongTermPlansEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { player.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/l/LordOfAtlantis.java b/Mage.Sets/src/mage/cards/l/LordOfAtlantis.java index cc1f2124e8..b2e8fb06f0 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfAtlantis.java +++ b/Mage.Sets/src/mage/cards/l/LordOfAtlantis.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -16,22 +15,18 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; /** - * * @author jonubuu */ public final class LordOfAtlantis extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Merfolk creatures"); - - static { - filter.add(new SubtypePredicate(SubType.MERFOLK)); - } + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.MERFOLK, "Merfolk"); public LordOfAtlantis(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}"); this.subtype.add(SubType.MERFOLK); this.power = new MageInt(2); @@ -39,7 +34,7 @@ public final class LordOfAtlantis extends CardImpl { // Other Merfolk creatures get +1/+1 and have islandwalk. Effect effect = new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true); - effect.setText("Other Merfolk creatures get +1/+1"); + effect.setText("Other Merfolk get +1/+1"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); effect = new GainAbilityAllEffect(new IslandwalkAbility(), Duration.WhileOnBattlefield, filter, true); effect.setText("and have islandwalk"); diff --git a/Mage.Sets/src/mage/cards/l/LordOfThePit.java b/Mage.Sets/src/mage/cards/l/LordOfThePit.java index 53a3a56b39..e957943c5a 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfThePit.java +++ b/Mage.Sets/src/mage/cards/l/LordOfThePit.java @@ -78,7 +78,7 @@ class LordOfThePitEffect extends OneShotEffect { } FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature other than " + sourcePermanent.getName()); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); if (target.canChoose(source.getSourceId(), player.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/l/LordOfTheVoid.java b/Mage.Sets/src/mage/cards/l/LordOfTheVoid.java index be1fe956e5..85b62e4715 100644 --- a/Mage.Sets/src/mage/cards/l/LordOfTheVoid.java +++ b/Mage.Sets/src/mage/cards/l/LordOfTheVoid.java @@ -74,8 +74,7 @@ class LordOfTheVoidEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(player.getLibrary().getTopCards(game, 7)); + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 7)); controller.moveCards(cards, Zone.EXILED, source, game); if (!cards.getCards(new FilterCreatureCard(), game).isEmpty()) { TargetCard target = new TargetCard(Zone.EXILED, new FilterCreatureCard()); diff --git a/Mage.Sets/src/mage/cards/l/LordWindgrace.java b/Mage.Sets/src/mage/cards/l/LordWindgrace.java index a4126678c5..517407e888 100644 --- a/Mage.Sets/src/mage/cards/l/LordWindgrace.java +++ b/Mage.Sets/src/mage/cards/l/LordWindgrace.java @@ -10,19 +10,20 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.Card; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterLandCard; import mage.filter.predicate.other.OwnerPredicate; import mage.game.Game; import mage.game.permanent.token.CatWarriorToken; import mage.players.Player; -import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetNonlandPermanent; /** @@ -49,9 +50,9 @@ public final class LordWindgrace extends CardImpl { // -3: Return up to two target land cards from your graveyard to the battlefield. Ability ability = new LoyaltyAbility( - new ReturnFromGraveyardToBattlefieldTargetEffect(), -3 + new ReturnFromGraveyardToBattlefieldTargetEffect().setText("return up to two target land cards from your graveyard to the battlefield"), -3 ); - ability.addTarget(new TargetCardInASingleGraveyard(0, 2, filter)); + ability.addTarget(new TargetCardInYourGraveyard(0, 2, filter)); this.addAbility(ability); // -11: Destroy up to six target nonland permanents, then create six 2/2 green Cat Warrior creature tokens with forestwalk. @@ -61,7 +62,7 @@ public final class LordWindgrace extends CardImpl { .setText(", then create six 2/2 green Cat Warrior " + "creature tokens with forestwalk") ); - ability.addTarget(new TargetNonlandPermanent(0, 6, false)); + ability.addTarget(new TargetNonlandPermanent(0, 6, StaticFilters.FILTER_PERMANENTS_NON_LAND, false)); this.addAbility(ability); // Lord Windgrace can be your commander. diff --git a/Mage.Sets/src/mage/cards/l/LoreseekersStone.java b/Mage.Sets/src/mage/cards/l/LoreseekersStone.java index 091e5a49c3..784b468a7d 100644 --- a/Mage.Sets/src/mage/cards/l/LoreseekersStone.java +++ b/Mage.Sets/src/mage/cards/l/LoreseekersStone.java @@ -1,28 +1,22 @@ - package mage.cards.l; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.CostModificationType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class LoreseekersStone extends CardImpl { @@ -31,17 +25,11 @@ public final class LoreseekersStone extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // {3}, {T}: Draw three cards. This ability costs {1} more to activate for each card in your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(3), new GenericManaCost(3)); - ability.addCost(new TapSourceCost()); - for (Effect effect : ability.getEffects()) { - effect.setText("Draw three cards. This ability costs {1} more to activate for each card in your hand"); - } - this.addAbility(ability); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new LoreseekersStoneCostIncreasingEffect(ability.getOriginalId()))); - + this.addAbility(new LoreseekersStoneActivatedAbility()); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new LoreseekersStoneCostIncreasingEffect())); } - public LoreseekersStone(final LoreseekersStone card) { + private LoreseekersStone(final LoreseekersStone card) { super(card); } @@ -51,18 +39,34 @@ public final class LoreseekersStone extends CardImpl { } } -class LoreseekersStoneCostIncreasingEffect extends CostModificationEffectImpl { +class LoreseekersStoneActivatedAbility extends SimpleActivatedAbility { - private final UUID originalId; - - LoreseekersStoneCostIncreasingEffect(UUID originalId) { - super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.INCREASE_COST); - this.originalId = originalId; + public LoreseekersStoneActivatedAbility() { + super(Zone.BATTLEFIELD, + new DrawCardSourceControllerEffect(3) + .setText("Draw three cards. This ability costs {1} more to activate for each card in your hand"), + new GenericManaCost(3)); + this.addCost(new TapSourceCost()); } - LoreseekersStoneCostIncreasingEffect(final LoreseekersStoneCostIncreasingEffect effect) { + private LoreseekersStoneActivatedAbility(final LoreseekersStoneActivatedAbility ability) { + super(ability); + } + + @Override + public LoreseekersStoneActivatedAbility copy() { + return new LoreseekersStoneActivatedAbility(this); + } +} + +class LoreseekersStoneCostIncreasingEffect extends CostModificationEffectImpl { + + LoreseekersStoneCostIncreasingEffect() { + super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.INCREASE_COST); + } + + private LoreseekersStoneCostIncreasingEffect(final LoreseekersStoneCostIncreasingEffect effect) { super(effect); - this.originalId = effect.originalId; } @Override @@ -76,12 +80,11 @@ class LoreseekersStoneCostIncreasingEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - return abilityToModify.getOriginalId().equals(originalId); + return (abilityToModify instanceof LoreseekersStoneActivatedAbility) && abilityToModify.getSourceId().equals(source.getSourceId()); } @Override public LoreseekersStoneCostIncreasingEffect copy() { return new LoreseekersStoneCostIncreasingEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/l/LostInTheWoods.java b/Mage.Sets/src/mage/cards/l/LostInTheWoods.java index 63edddda06..05f3076189 100644 --- a/Mage.Sets/src/mage/cards/l/LostInTheWoods.java +++ b/Mage.Sets/src/mage/cards/l/LostInTheWoods.java @@ -57,8 +57,7 @@ class LostInTheWoodsEffect extends OneShotEffect { } if (controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getName(), cards, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java b/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java new file mode 100644 index 0000000000..012b523cc4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LostOrderOfJarkeld.java @@ -0,0 +1,78 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ChooseOpponentEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LostOrderOfJarkeld extends CardImpl { + + public LostOrderOfJarkeld(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // As Lost Order of Jarkeld enters the battlefield, choose an opponent. + this.addAbility(new AsEntersBattlefieldAbility(new ChooseOpponentEffect(Outcome.Detriment))); + + // Lost Order of Jarkeld's power and toughness are each equal to 1 plus the number of creatures the chosen player controls. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, + new SetPowerToughnessSourceEffect( + LostOrderOfJarkeldValue.instance, Duration.Custom, SubLayer.CharacteristicDefining_7a + ) + )); + } + + private LostOrderOfJarkeld(final LostOrderOfJarkeld card) { + super(card); + } + + @Override + public LostOrderOfJarkeld copy() { + return new LostOrderOfJarkeld(this); + } +} + +enum LostOrderOfJarkeldValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + if (game.getPermanent(sourceAbility.getSourceId()) == null) { + return 1; + } + Object obj = game.getState().getValue(sourceAbility.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY); + if (!(obj instanceof UUID)) { + return 1; + } + return 1 + game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, (UUID) obj, game).size(); + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return "1 plus the number of creatures the chosen player controls."; + } +} diff --git a/Mage.Sets/src/mage/cards/l/LotusVale.java b/Mage.Sets/src/mage/cards/l/LotusVale.java index 1d13d07a89..052c1c11eb 100644 --- a/Mage.Sets/src/mage/cards/l/LotusVale.java +++ b/Mage.Sets/src/mage/cards/l/LotusVale.java @@ -26,7 +26,7 @@ public final class LotusVale extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("two untapped lands"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LotusVale(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LoxodonHierarch.java b/Mage.Sets/src/mage/cards/l/LoxodonHierarch.java index f1e1846ab9..fc03a6ce2e 100644 --- a/Mage.Sets/src/mage/cards/l/LoxodonHierarch.java +++ b/Mage.Sets/src/mage/cards/l/LoxodonHierarch.java @@ -16,6 +16,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -25,11 +26,6 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class LoxodonHierarch extends CardImpl { - private static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } public LoxodonHierarch(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{W}"); @@ -43,12 +39,12 @@ public final class LoxodonHierarch extends CardImpl { Ability etbAbility = new EntersBattlefieldTriggeredAbility(new GainLifeEffect(4)); this.addAbility(etbAbility); // {G}{W}, Sacrifice Loxodon Hierarch: Regenerate each creature you control. - Ability activated = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateAllEffect(filter), new ManaCostsImpl("{G}{W}")); + Ability activated = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateAllEffect(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED), new ManaCostsImpl("{G}{W}")); activated.addCost(new SacrificeSourceCost()); this.addAbility(activated); } - public LoxodonHierarch(final LoxodonHierarch card) { + private LoxodonHierarch(final LoxodonHierarch card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/l/LoxodonSergeant.java b/Mage.Sets/src/mage/cards/l/LoxodonSergeant.java new file mode 100644 index 0000000000..b94b6ef5e2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LoxodonSergeant.java @@ -0,0 +1,47 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +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 mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class LoxodonSergeant extends CardImpl { + + public LoxodonSergeant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.ELEPHANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Loxodon Sergeant enters the battlefield, other creatures you control gain vigilance until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES, true + ))); + } + + private LoxodonSergeant(final LoxodonSergeant card) { + super(card); + } + + @Override + public LoxodonSergeant copy() { + return new LoxodonSergeant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LudevicNecroAlchemist.java b/Mage.Sets/src/mage/cards/l/LudevicNecroAlchemist.java index 9499bda49e..0dfd90b3e2 100644 --- a/Mage.Sets/src/mage/cards/l/LudevicNecroAlchemist.java +++ b/Mage.Sets/src/mage/cards/l/LudevicNecroAlchemist.java @@ -1,6 +1,5 @@ package mage.cards.l; -import java.util.Objects; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; @@ -13,7 +12,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.players.Player; -import mage.players.PlayerList; import mage.watchers.common.PlayerLostLifeWatcher; /** @@ -32,8 +30,12 @@ public final class LudevicNecroAlchemist extends CardImpl { this.toughness = new MageInt(4); // At the beginning of each player's end step, that player may draw a card if a player other than you lost life this turn. - this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, - new LudevicNecroAlchemistEffect(), TargetController.EACH_PLAYER, new LudevicNecroAlchemistCondition(), false)); + this.addAbility(new BeginningOfEndStepTriggeredAbility( + Zone.BATTLEFIELD, + new LudevicNecroAlchemistEffect(), + TargetController.EACH_PLAYER, + new LudevicNecroAlchemistCondition(), + false)); // Partner this.addAbility(PartnerAbility.getInstance()); @@ -53,25 +55,16 @@ class LudevicNecroAlchemistCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); - PlayerList playerList = game.getState().getPlayerList().copy(); - Player currentPlayer; - UUID sourcePlayerId = source.getControllerId(); - Player firstPlayer; - if (playerList == null) { - return false; - } - firstPlayer = playerList.getCurrent(game); - currentPlayer = playerList.getNext(game); - - while (watcher != null && currentPlayer != null) { - if (!Objects.equals(currentPlayer.getId(), sourcePlayerId) && watcher.getLiveLost(currentPlayer.getId()) > 0) { - return true; + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && watcher != null + && watcher.getLifeLost(controller.getId()) == 0) { + for (UUID playerId : controller.getInRange()) { + if (watcher.getLifeLost(playerId) > 0) { + return true; + } } - if (Objects.equals(currentPlayer, firstPlayer)) { - return false; - } - currentPlayer = playerList.getNext(game); } return false; } @@ -100,13 +93,11 @@ class LudevicNecroAlchemistEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID playerId = game.getActivePlayerId(); - if (playerId != null) { - Player player = game.getPlayer(playerId); - if (player != null && player.chooseUse(outcome, "Draw a card?", source, game)) { - player.drawCards(1, game); - return true; - } + Player player = game.getPlayer(game.getActivePlayerId()); + if (player != null + && player.chooseUse(Outcome.DrawCard, "Draw a card?", source, game)) { + player.drawCards(1, game); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/l/LullmageMentor.java b/Mage.Sets/src/mage/cards/l/LullmageMentor.java index eebcda5ac9..7262f0752c 100644 --- a/Mage.Sets/src/mage/cards/l/LullmageMentor.java +++ b/Mage.Sets/src/mage/cards/l/LullmageMentor.java @@ -32,7 +32,7 @@ public final class LullmageMentor extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MERFOLK)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public LullmageMentor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/l/LumberingBattlement.java b/Mage.Sets/src/mage/cards/l/LumberingBattlement.java new file mode 100644 index 0000000000..83e2c4925d --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LumberingBattlement.java @@ -0,0 +1,164 @@ +package mage.cards.l; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.ExileZone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class LumberingBattlement extends CardImpl { + + public LumberingBattlement(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // When Lumbering Battlement enters the battlefield, exile any number of other nontoken creatures you control until it leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility(new LumberingBattlementEffect()); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + this.addAbility(ability); + + // Lumbering Battlement gets +2/+2 for each card exiled with it. + this.addAbility(new SimpleStaticAbility(new BoostSourceEffect( + LumberingBattlementValue.instance, + LumberingBattlementValue.instance, + Duration.WhileOnBattlefield + ).setText("{this} gets +2/+2 for each card exiled with it."))); + } + + private LumberingBattlement(final LumberingBattlement card) { + super(card); + } + + @Override + public LumberingBattlement copy() { + return new LumberingBattlement(this); + } +} + +class LumberingBattlementEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("other nontoken creatures"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); + } + + LumberingBattlementEffect() { + super(Benefit); + staticText = "exile any number of other nontoken creatures you control until it leaves the battlefield"; + } + + private LumberingBattlementEffect(final LumberingBattlementEffect effect) { + super(effect); + } + + @Override + public LumberingBattlementEffect copy() { + return new LumberingBattlementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent sourcePerm = source.getSourcePermanentIfItStillExists(game); + if (player == null || sourcePerm == null) { + return false; + } + Target target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + if (!player.choose(Outcome.Neutral, target, source.getSourceId(), game)) { + return false; + } + Set cards = new HashSet<>(); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + cards.add(permanent); + } + } + return player.moveCardsToExile( + cards, source, game, true, + CardUtil.getCardExileZoneId(game, source), sourcePerm.getIdName() + ); + } +} + +enum LumberingBattlementValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + if (sourceAbility == null) { + return 0; + } + ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId( + game, sourceAbility.getSourceId(), + sourceAbility.getSourceObjectZoneChangeCounter() + )); + if (exileZone == null) { + exileZone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, sourceAbility)); + } + if (exileZone == null) { + return 0; + } + int counter = 0; + for (UUID cardId : exileZone) { + Card card = game.getCard(cardId); + if (card != null) { + counter++; + } + } + return 2 * counter; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/l/LuminarchAscension.java b/Mage.Sets/src/mage/cards/l/LuminarchAscension.java index b2710993d1..e0382cabbb 100644 --- a/Mage.Sets/src/mage/cards/l/LuminarchAscension.java +++ b/Mage.Sets/src/mage/cards/l/LuminarchAscension.java @@ -29,7 +29,7 @@ import mage.watchers.common.PlayerLostLifeWatcher; */ public final class LuminarchAscension extends CardImpl { - private String rule = "At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on {this}. (Damage causes loss of life.)"; + private static final String rule = "At the beginning of each opponent's end step, if you didn't lose life this turn, you may put a quest counter on {this}. (Damage causes loss of life.)"; public LuminarchAscension(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); @@ -119,9 +119,9 @@ enum YouLostNoLifeThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { - return (watcher.getLiveLost(source.getControllerId()) == 0); + return (watcher.getLifeLost(source.getControllerId()) == 0); } return false; } diff --git a/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java b/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java index ce678715e6..e35a5c6b04 100644 --- a/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java +++ b/Mage.Sets/src/mage/cards/l/LuminatePrimordial.java @@ -1,7 +1,6 @@ package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -10,8 +9,8 @@ import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -19,15 +18,17 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class LuminatePrimordial extends CardImpl { public LuminatePrimordial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(4); @@ -38,23 +39,9 @@ public final class LuminatePrimordial extends CardImpl { // When Luminate Primordial enters the battlefield, for each opponent, exile up to one target creature // that player controls and that player gains life equal to its power. - this.addAbility(new EntersBattlefieldTriggeredAbility(new LuminatePrimordialEffect(),false)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for(UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()); - filter.add(new ControllerIdPredicate(opponentId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0,1, filter,false); - ability.addTarget(target); - } - } - } + Ability ability = new EntersBattlefieldTriggeredAbility(new LuminatePrimordialEffect(), false); + ability.setTargetAdjuster(LuminatePrimordialAdjuster.instance); + this.addAbility(ability); } public LuminatePrimordial(final LuminatePrimordial card) { @@ -67,6 +54,24 @@ public final class LuminatePrimordial extends CardImpl { } } +enum LuminatePrimordialAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); + ability.addTarget(target); + } + } + } +} + class LuminatePrimordialEffect extends OneShotEffect { public LuminatePrimordialEffect() { @@ -85,7 +90,7 @@ class LuminatePrimordialEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetCreaturePermanent) { Permanent targetCreature = game.getPermanent(target.getFirstTarget()); if (targetCreature != null && !targetCreature.isControlledBy(source.getControllerId())) { diff --git a/Mage.Sets/src/mage/cards/l/LupinePrototype.java b/Mage.Sets/src/mage/cards/l/LupinePrototype.java index 66f0c5320f..26a817bdb2 100644 --- a/Mage.Sets/src/mage/cards/l/LupinePrototype.java +++ b/Mage.Sets/src/mage/cards/l/LupinePrototype.java @@ -1,7 +1,5 @@ - package mage.cards.l; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,21 +7,22 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author fireshoes */ public final class LupinePrototype extends CardImpl { public LupinePrototype(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); this.subtype.add(SubType.WOLF); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(5); @@ -69,12 +68,12 @@ class LupinePrototypeEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/l/LureOfPrey.java b/Mage.Sets/src/mage/cards/l/LureOfPrey.java index c6b81a46c8..7189a59a68 100644 --- a/Mage.Sets/src/mage/cards/l/LureOfPrey.java +++ b/Mage.Sets/src/mage/cards/l/LureOfPrey.java @@ -69,7 +69,7 @@ class LureOfPreyRestrictionEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getSourceId().equals(source.getSourceId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { for (UUID playerId : game.getOpponents(source.getControllerId())) { if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(playerId) != 0) { diff --git a/Mage.Sets/src/mage/cards/l/LurkingJackals.java b/Mage.Sets/src/mage/cards/l/LurkingJackals.java new file mode 100644 index 0000000000..92057b60fd --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LurkingJackals.java @@ -0,0 +1,130 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class LurkingJackals extends CardImpl { + + public LurkingJackals(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); + + // When an opponent has 10 or less life, if Lurking Jackals is an enchantment, it becomes a 3/2 Hound creature. + this.addAbility(new LurkingJackalsStateTriggeredAbility()); + } + + public LurkingJackals(final LurkingJackals card) { + super(card); + } + + @Override + public LurkingJackals copy() { + return new LurkingJackals(this); + } +} + +class LurkingJackalsStateTriggeredAbility extends StateTriggeredAbility { + + public LurkingJackalsStateTriggeredAbility() { + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new LurkingJackalsToken(), "", Duration.Custom, true, false)); + } + + public LurkingJackalsStateTriggeredAbility(final LurkingJackalsStateTriggeredAbility ability) { + super(ability); + } + + @Override + public LurkingJackalsStateTriggeredAbility copy() { + return new LurkingJackalsStateTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.getOpponents(getControllerId()) != null) { + for (UUID opponentId : game.getOpponents(getControllerId())) { + if (game.getPlayer(opponentId).getLife() <= 10) { + return true; + } + } + } + return false; + } + + @Override + public boolean checkInterveningIfClause(Game game) { + if (getSourcePermanentIfItStillExists(game) != null) { + return getSourcePermanentIfItStillExists(game).isEnchantment(); + } + return false; + } + + @Override + public boolean canTrigger(Game game) { + //20100716 - 603.8 + Boolean triggered = (Boolean) game.getState().getValue(getSourceId().toString() + "triggered"); + if (triggered == null) { + triggered = Boolean.FALSE; + } + return !triggered; + } + + @Override + public void trigger(Game game, UUID controllerId) { + //20100716 - 603.8 + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE); + super.trigger(game, controllerId); + } + + @Override + public boolean resolve(Game game) { + //20100716 - 603.8 + boolean result = super.resolve(game); + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + return result; + } + + @Override + public void counter(Game game) { + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + } + + @Override + public String getRule() { + return "When an opponent has 10 or less life, if {this} is an enchantment, " + super.getRule(); + } + +} + +class LurkingJackalsToken extends TokenImpl { + + public LurkingJackalsToken() { + super("Hound", "3/2 Hound creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.HOUND); + power = new MageInt(3); + toughness = new MageInt(2); + } + + public LurkingJackalsToken(final LurkingJackalsToken token) { + super(token); + } + + @Override + public LurkingJackalsToken copy() { + return new LurkingJackalsToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/l/LurkingSkirge.java b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java new file mode 100644 index 0000000000..8829e559b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/l/LurkingSkirge.java @@ -0,0 +1,71 @@ +package mage.cards.l; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +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.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class LurkingSkirge extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new OwnerPredicate(TargetController.OPPONENT)); + } + + public LurkingSkirge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); + + // When a creature is put into an opponent's graveyard from the battlefield, if Lurking Skirge is an enchantment, Lurking Skirge becomes a 3/2 Imp creature with flying. + TriggeredAbility ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(new BecomesCreatureSourceEffect(new LurkingSkirgeToken(), "", Duration.WhileOnBattlefield, true, false), false, filter, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "When a creature is put into an opponent's graveyard from the battlefield, if {this} is an enchantment, {this} becomes a 3/2 Imp creature with flying.")); + } + + public LurkingSkirge(final LurkingSkirge card) { + super(card); + } + + @Override + public LurkingSkirge copy() { + return new LurkingSkirge(this); + } +} + +class LurkingSkirgeToken extends TokenImpl { + + public LurkingSkirgeToken() { + super("Imp", "3/2 Imp with flying."); + cardType.add(CardType.CREATURE); + subtype.add(SubType.IMP); + power = new MageInt(3); + toughness = new MageInt(2); + this.addAbility(FlyingAbility.getInstance()); + } + + public LurkingSkirgeToken(final LurkingSkirgeToken token) { + super(token); + } + + public LurkingSkirgeToken copy() { + return new LurkingSkirgeToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MacabreMockery.java b/Mage.Sets/src/mage/cards/m/MacabreMockery.java new file mode 100644 index 0000000000..d33b140b12 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MacabreMockery.java @@ -0,0 +1,93 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MacabreMockery extends CardImpl { + + public MacabreMockery(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}{R}"); + + // Put target creature card from an opponent's graveyard onto the battlefield under your control. It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step. + this.getSpellAbility().addEffect(new MacabreMockeryEffect()); + this.getSpellAbility().addTarget(new TargetCardInOpponentsGraveyard(StaticFilters.FILTER_CARD_CREATURE)); + } + + private MacabreMockery(final MacabreMockery card) { + super(card); + } + + @Override + public MacabreMockery copy() { + return new MacabreMockery(this); + } +} + +class MacabreMockeryEffect extends OneShotEffect { + + MacabreMockeryEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "Put target creature card from an opponent's graveyard onto the battlefield under your control. " + + "It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step."; + } + + private MacabreMockeryEffect(final MacabreMockeryEffect effect) { + super(effect); + } + + @Override + public MacabreMockeryEffect copy() { + return new MacabreMockeryEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = game.getCard(getTargetPointer().getFirst(game, source)); + if (card == null) { + return false; + } + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + effect = new BoostTargetEffect(2, 0, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + Effect sacrificeEffect = new SacrificeTargetEffect("sacrifice " + permanent.getLogName(), controller.getId()); + sacrificeEffect.setTargetPointer(new FixedTarget(permanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrificeEffect), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MacabreWaltz.java b/Mage.Sets/src/mage/cards/m/MacabreWaltz.java index a37c9811ae..c1623e6f2b 100644 --- a/Mage.Sets/src/mage/cards/m/MacabreWaltz.java +++ b/Mage.Sets/src/mage/cards/m/MacabreWaltz.java @@ -2,29 +2,31 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.discard.DiscardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.target.common.TargetCardInYourGraveyard; -/** - * - * @author LoneFox +import java.util.UUID; +/** + * @author LoneFox */ public final class MacabreWaltz extends CardImpl { + private static final FilterCard filter = new FilterCreatureCard("creature cards from your graveyard"); + public MacabreWaltz(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Return up to two target creature cards from your graveyard to your hand, then discard a card. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, new FilterCreatureCard("creature cards from your graveyard"))); - this.getSpellAbility().addEffect(new DiscardControllerEffect(1)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, filter)); + this.getSpellAbility().addEffect(new DiscardControllerEffect(1).setText(", then discard a card")); } public MacabreWaltz(final MacabreWaltz card) { diff --git a/Mage.Sets/src/mage/cards/m/Machinate.java b/Mage.Sets/src/mage/cards/m/Machinate.java index dbb2094a56..b1039219f0 100644 --- a/Mage.Sets/src/mage/cards/m/Machinate.java +++ b/Mage.Sets/src/mage/cards/m/Machinate.java @@ -30,7 +30,9 @@ public final class Machinate extends CardImpl { // Look at the top X cards of your library, where X is the number of artifacts you control. Put one of those cards into your hand and the rest on the bottom of your library in any order. DynamicValue artifactsOnControl = new PermanentsOnBattlefieldCount(filter); - this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect(artifactsOnControl, false, new StaticValue(1), new FilterCard(), Zone.LIBRARY, false, false)); + LookLibraryAndPickControllerEffect effect = new LookLibraryAndPickControllerEffect(artifactsOnControl, false, new StaticValue(1), new FilterCard(), Zone.LIBRARY, false, false); + effect.setText("Look at the top X cards of your library, where X is the number of artifacts you control. Put one of those cards into your hand and the rest on the bottom of your library in any order."); + this.getSpellAbility().addEffect(effect); } public Machinate(final Machinate card) { diff --git a/Mage.Sets/src/mage/cards/m/MadAuntie.java b/Mage.Sets/src/mage/cards/m/MadAuntie.java index 465facd99c..8e3f29ce38 100644 --- a/Mage.Sets/src/mage/cards/m/MadAuntie.java +++ b/Mage.Sets/src/mage/cards/m/MadAuntie.java @@ -31,7 +31,7 @@ public final class MadAuntie extends CardImpl { static { filter1.add(new SubtypePredicate(SubType.GOBLIN)); - filter1.add(new AnotherPredicate()); + filter1.add(AnotherPredicate.instance); } public MadAuntie(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MadDog.java b/Mage.Sets/src/mage/cards/m/MadDog.java index f9206d7ec0..17254366cd 100644 --- a/Mage.Sets/src/mage/cards/m/MadDog.java +++ b/Mage.Sets/src/mage/cards/m/MadDog.java @@ -58,18 +58,18 @@ enum MadDogCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent madDog = game.getPermanent(source.getSourceId()); - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); - AttackedThisTurnWatcher watcher2 = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); + AttackedThisTurnWatcher watcher2 = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null && watcher2 != null && madDog != null) { // For some reason, compare did not work when checking the lists. Thus the interation. List permanents = watcher.getThisTurnEnteringPermanents(source.getControllerId()); - if (!permanents.stream().noneMatch((p) -> (p.getId().equals(madDog.getId())))) { + if (permanents.stream().anyMatch((p) -> (p.getId().equals(madDog.getId())))) { return false; } Set mor = watcher2.getAttackedThisTurnCreatures(); - if (!mor.stream().noneMatch((m) -> (m.getPermanent(game).equals(madDog)))) { + if (mor.stream().anyMatch((m) -> (m.getPermanent(game).equals(madDog)))) { return false; } return true; // Mad Dog did not come into play this turn nor did he attack this turn. Sacrifice the hound. diff --git a/Mage.Sets/src/mage/cards/m/MaddeningImp.java b/Mage.Sets/src/mage/cards/m/MaddeningImp.java index 72cda096ce..e76411ba6a 100644 --- a/Mage.Sets/src/mage/cards/m/MaddeningImp.java +++ b/Mage.Sets/src/mage/cards/m/MaddeningImp.java @@ -160,7 +160,7 @@ class MaddeningImpDelayedDestroyEffect extends OneShotEffect { continue; } // Creatures that attacked are safe. - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(mor)) { continue; } diff --git a/Mage.Sets/src/mage/cards/m/MaelstromNexus.java b/Mage.Sets/src/mage/cards/m/MaelstromNexus.java index c88f8d523c..e1b2c2bde2 100644 --- a/Mage.Sets/src/mage/cards/m/MaelstromNexus.java +++ b/Mage.Sets/src/mage/cards/m/MaelstromNexus.java @@ -69,7 +69,7 @@ class MaelstromNexusGainCascadeFirstSpellEffect extends ContinuousEffectImpl { // only spells cast, so no copies of spells if ((stackObject instanceof Spell) && !stackObject.isCopy() && stackObject.isControlledBy(source.getControllerId())) { Spell spell = (Spell) stackObject; - FirstSpellCastThisTurnWatcher watcher = (FirstSpellCastThisTurnWatcher) game.getState().getWatchers().get(FirstSpellCastThisTurnWatcher.class.getSimpleName()); + FirstSpellCastThisTurnWatcher watcher = game.getState().getWatcher(FirstSpellCastThisTurnWatcher.class); if (watcher != null && spell.getId().equals(watcher.getIdOfFirstCastSpell(source.getControllerId()))) { game.getState().addOtherAbility(spell.getCard(), cascadeAbility); } diff --git a/Mage.Sets/src/mage/cards/m/MageRingNetwork.java b/Mage.Sets/src/mage/cards/m/MageRingNetwork.java index 3edaf7279c..21506a8bec 100644 --- a/Mage.Sets/src/mage/cards/m/MageRingNetwork.java +++ b/Mage.Sets/src/mage/cards/m/MageRingNetwork.java @@ -39,7 +39,7 @@ public final class MageRingNetwork extends CardImpl { // {T}, Remove any number of storage counters from Mage-Ring Network: Add {C} for each storage counter removed this way. ability = new DynamicManaAbility( Mana.ColorlessMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {C} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/m/MagetaTheLion.java b/Mage.Sets/src/mage/cards/m/MagetaTheLion.java index 1a665bf335..ac3636dcf5 100644 --- a/Mage.Sets/src/mage/cards/m/MagetaTheLion.java +++ b/Mage.Sets/src/mage/cards/m/MagetaTheLion.java @@ -31,7 +31,7 @@ public final class MagetaTheLion extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MagetaTheLion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java b/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java index 289c129445..4a0067ac5c 100644 --- a/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java +++ b/Mage.Sets/src/mage/cards/m/MagisterOfWorth.java @@ -92,7 +92,7 @@ class MagisterOfWorthVoteEffect extends OneShotEffect { new MagisterOfWorthReturnFromGraveyardEffect().apply(game, source); } else { FilterPermanent filter = new FilterCreaturePermanent("creatures other than {this}"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); new DestroyAllEffect(filter).apply(game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MagmaBurst.java b/Mage.Sets/src/mage/cards/m/MagmaBurst.java index 761e9fd419..5d81a3b4bd 100644 --- a/Mage.Sets/src/mage/cards/m/MagmaBurst.java +++ b/Mage.Sets/src/mage/cards/m/MagmaBurst.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.common.SacrificeTargetCost; @@ -13,18 +12,17 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; -import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetControlledPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox - * */ public final class MagmaBurst extends CardImpl { - private final UUID originalId; - public MagmaBurst(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{R}"); @@ -32,21 +30,13 @@ public final class MagmaBurst extends CardImpl { this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, new FilterControlledLandPermanent("two lands"), true)))); // Magma Burst deals 3 damage to any target. If Magma Burst was kicked, it deals 3 damage to another any target. Effect effect = new DamageTargetEffect(3); - effect.setText("{this} deals 3 damage to any target. if this spell was kicked, it deals 3 damage to another target."); + effect.setText("{this} deals 3 damage to any target. If this spell was kicked, it deals 3 damage to another target."); this.getSpellAbility().addEffect(effect); - originalId = this.getSpellAbility().getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.addTarget(new TargetAnyTarget(KickedCondition.instance.apply(game, ability) ? 2 : 1)); - } + this.getSpellAbility().setTargetAdjuster(MagmaBurstAdjuster.instance); } public MagmaBurst(final MagmaBurst card) { super(card); - this.originalId = card.originalId; } @Override @@ -54,3 +44,12 @@ public final class MagmaBurst extends CardImpl { return new MagmaBurst(this); } } + +enum MagmaBurstAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.addTarget(new TargetAnyTarget(KickedCondition.instance.apply(game, ability) ? 2 : 1)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/Magmaquake.java b/Mage.Sets/src/mage/cards/m/Magmaquake.java index 98e00ba168..4522a2d70b 100644 --- a/Mage.Sets/src/mage/cards/m/Magmaquake.java +++ b/Mage.Sets/src/mage/cards/m/Magmaquake.java @@ -34,7 +34,7 @@ public final class Magmaquake extends CardImpl { // Magmaquake deals X damage to each creature without flying and each planeswalker. - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filter)); } public Magmaquake(final Magmaquake card) { diff --git a/Mage.Sets/src/mage/cards/m/MagneticMine.java b/Mage.Sets/src/mage/cards/m/MagneticMine.java index 204bf02472..36dad78e35 100644 --- a/Mage.Sets/src/mage/cards/m/MagneticMine.java +++ b/Mage.Sets/src/mage/cards/m/MagneticMine.java @@ -58,8 +58,7 @@ class MagneticMineTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD - && zEvent.getToZone() == Zone.GRAVEYARD + if (zEvent.isDiesEvent() && zEvent.getTarget().isArtifact() && !Objects.equals(zEvent.getTarget().getId(), this.getSourceId())) { this.getTargets().get(0).add(zEvent.getTarget().getControllerId(), game); diff --git a/Mage.Sets/src/mage/cards/m/MagneticMountain.java b/Mage.Sets/src/mage/cards/m/MagneticMountain.java index 5cb79401b8..92f9b30194 100644 --- a/Mage.Sets/src/mage/cards/m/MagneticMountain.java +++ b/Mage.Sets/src/mage/cards/m/MagneticMountain.java @@ -65,7 +65,7 @@ class MagneticMountainEffect extends OneShotEffect { static { filter2.add(new ColorPredicate(ObjectColor.BLUE)); - filter2.add(new TappedPredicate()); + filter2.add(TappedPredicate.instance); } MagneticMountainEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheMind.java b/Mage.Sets/src/mage/cards/m/MagusOfTheMind.java index ba06aae643..26a6b6e3e2 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheMind.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheMind.java @@ -78,9 +78,11 @@ class MagusOfTheMindEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if(watcher == null){ + return false; + } int stormCount = watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn() + 1; - System.out.println(stormCount); if (controller != null && sourceObject != null) { controller.shuffleLibrary(source, game); if (controller.getLibrary().hasCards()) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java b/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java index 07f2a9abae..d4f08962f3 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheMoon.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -16,8 +14,9 @@ import mage.filter.predicate.mageobject.SupertypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MagusOfTheMoon extends CardImpl { @@ -29,7 +28,7 @@ public final class MagusOfTheMoon extends CardImpl { } public MagusOfTheMoon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -79,7 +78,7 @@ public final class MagusOfTheMoon extends CardImpl { // 305.7 Note that this doesn't remove any abilities that were granted to the land by other effects // So the ability removing has to be done before Layer 6 land.removeAllAbilities(source.getSourceId(), game); - land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + land.getSubtype(game).removeAll(SubType.getLandTypes()); land.getSubtype(game).add(SubType.MOUNTAIN); break; case AbilityAddingRemovingEffects_6: diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java index cc23294d28..c5d0627c37 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheScroll.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -10,11 +8,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; @@ -23,9 +17,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MagusOfTheScroll extends CardImpl { @@ -80,7 +76,7 @@ class MagusOfTheScrollEffect extends OneShotEffect { } revealed.add(card); you.revealCards(sourceObject.getName(), revealed, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); if (creature != null) { creature.damage(2, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/m/MajesticHeliopterus.java b/Mage.Sets/src/mage/cards/m/MajesticHeliopterus.java index 3ce444d6cf..a302dcb0e5 100644 --- a/Mage.Sets/src/mage/cards/m/MajesticHeliopterus.java +++ b/Mage.Sets/src/mage/cards/m/MajesticHeliopterus.java @@ -27,7 +27,7 @@ public final class MajesticHeliopterus extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target Dinosaur you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DINOSAUR)); } public MajesticHeliopterus(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java b/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java index 7224e608d1..6bf725d945 100644 --- a/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java +++ b/Mage.Sets/src/mage/cards/m/MajesticMyriarch.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfCombatTriggeredAbility; @@ -13,32 +11,17 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.MenaceAbility; -import mage.abilities.keyword.ReachAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.AbilityPredicate; import mage.game.Game; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MajesticMyriarch extends CardImpl { @@ -51,7 +34,7 @@ public final class MajesticMyriarch extends CardImpl { this.toughness = new MageInt(0); // Majestic Myriarch's power and toughness are each equal to twice the number of creatures you control. - DynamicValue xValue= new MultipliedValue(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), 2); + DynamicValue xValue = new MultipliedValue(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), 2); Effect effect = new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame); effect.setText("{this}'s power and toughness are each equal to twice the number of creatures you control"); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); @@ -104,7 +87,7 @@ class MajesticMyriarchEffect extends OneShotEffect { MajesticMyriarchEffect() { super(Outcome.BoostCreature); this.staticText = "if you control a creature with flying, Majestic Myriarch gains flying until end of turn. " + - "The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance."; + "The same is true for first strike, double strike, deathtouch, haste, hexproof, indestructible, lifelink, menace, reach, trample, and vigilance."; } MajesticMyriarchEffect(final MajesticMyriarchEffect effect) { diff --git a/Mage.Sets/src/mage/cards/m/MakeshiftBattalion.java b/Mage.Sets/src/mage/cards/m/MakeshiftBattalion.java new file mode 100644 index 0000000000..ad51165bb3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MakeshiftBattalion.java @@ -0,0 +1,75 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +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.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MakeshiftBattalion extends CardImpl { + + public MakeshiftBattalion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever Makeshift Battalion and at least two other creatures attack, put a +1/+1 counter on Makeshift Battalion. + this.addAbility(new MakeshiftBattalionTriggeredAbility()); + } + + private MakeshiftBattalion(final MakeshiftBattalion card) { + super(card); + } + + @Override + public MakeshiftBattalion copy() { + return new MakeshiftBattalion(this); + } +} + +class MakeshiftBattalionTriggeredAbility extends TriggeredAbilityImpl { + + MakeshiftBattalionTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private MakeshiftBattalionTriggeredAbility(final MakeshiftBattalionTriggeredAbility ability) { + super(ability); + } + + @Override + public MakeshiftBattalionTriggeredAbility copy() { + return new MakeshiftBattalionTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getCombat().getAttackers().size() >= 3 + && game.getCombat().getAttackers().contains(this.sourceId); + } + + @Override + public String getRule() { + return "Whenever {this} and at least two other creatures attack, " + + "put a +1/+1 counter on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MalachiteTalisman.java b/Mage.Sets/src/mage/cards/m/MalachiteTalisman.java index 35e2289a12..fb71ecab76 100644 --- a/Mage.Sets/src/mage/cards/m/MalachiteTalisman.java +++ b/Mage.Sets/src/mage/cards/m/MalachiteTalisman.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class MalachiteTalisman extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a green spell"); + private static final FilterSpell filter = new FilterSpell("a green spell"); static { filter.add(new ColorPredicate(ObjectColor.GREEN)); diff --git a/Mage.Sets/src/mage/cards/m/MalakirSoothsayer.java b/Mage.Sets/src/mage/cards/m/MalakirSoothsayer.java index a53374fa6e..e55d840ec1 100644 --- a/Mage.Sets/src/mage/cards/m/MalakirSoothsayer.java +++ b/Mage.Sets/src/mage/cards/m/MalakirSoothsayer.java @@ -31,7 +31,7 @@ public final class MalakirSoothsayer extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MalakirSoothsayer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MaliciousAdvice.java b/Mage.Sets/src/mage/cards/m/MaliciousAdvice.java index 610edcb589..b75bb70a68 100644 --- a/Mage.Sets/src/mage/cards/m/MaliciousAdvice.java +++ b/Mage.Sets/src/mage/cards/m/MaliciousAdvice.java @@ -1,9 +1,7 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; @@ -16,38 +14,24 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox */ public final class MaliciousAdvice extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("artifacts, creatures, and/or lands"); - - static { - filter.add(Predicates.or( - new CardTypePredicate(CardType.ARTIFACT), - new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.LAND))); - } - public MaliciousAdvice(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}{B}"); // Tap X target artifacts, creatures, and/or lands. You lose X life. Effect effect = new TapTargetEffect(); - effect.setText("X target artifacts, creatures, and/or lands"); + effect.setText("X target artifacts, creatures, and/or lands."); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(new ManacostVariableValue())); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - ability.addTarget(new TargetPermanent(ability.getManaCostsToPay().getX(), filter)); - } + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(ManacostVariableValue.instance)); + this.getSpellAbility().setTargetAdjuster(MaliciousAdviceAdjuster.instance); } public MaliciousAdvice(final MaliciousAdvice card) { @@ -59,3 +43,22 @@ public final class MaliciousAdvice extends CardImpl { return new MaliciousAdvice(this); } } + +enum MaliciousAdviceAdjuster implements TargetAdjuster { + instance; + private static final FilterPermanent filter = new FilterPermanent("artifacts, creatures, and/or lands"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND) + )); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(ability.getManaCostsToPay().getX(), filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MalignantGrowth.java b/Mage.Sets/src/mage/cards/m/MalignantGrowth.java new file mode 100644 index 0000000000..85edc354d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MalignantGrowth.java @@ -0,0 +1,85 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfDrawTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MalignantGrowth extends CardImpl { + + public MalignantGrowth(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}{U}"); + + // Cumulative upkeep {1} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); + + // At the beginning of your upkeep, put a growth counter on Malignant Growth. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new AddCountersSourceEffect(CounterType.GROWTH.createInstance()), + TargetController.YOU, false + )); + + // At the beginning of each opponent's draw step, that player draws an additional card for each growth counter on Malignant Growth, then Malignant Growth deals damage to the player equal to the number of cards he or she drew this way. + this.addAbility(new BeginningOfDrawTriggeredAbility( + new MalignantGrowthEffect(), TargetController.OPPONENT, false + )); + } + + private MalignantGrowth(final MalignantGrowth card) { + super(card); + } + + @Override + public MalignantGrowth copy() { + return new MalignantGrowth(this); + } +} + +class MalignantGrowthEffect extends OneShotEffect { + + MalignantGrowthEffect() { + super(Outcome.Benefit); + staticText = "that player draws an additional card for each growth counter on {this}, " + + "then {this} deals damage to the player equal to the number of cards they drew this way."; + } + + private MalignantGrowthEffect(final MalignantGrowthEffect effect) { + super(effect); + } + + @Override + public MalignantGrowthEffect copy() { + return new MalignantGrowthEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (player == null || permanent == null) { + return false; + } + int counters = permanent.getCounters(game).getCount(CounterType.GROWTH); + if (counters == 0) { + return true; + } + return player.damage(player.drawCards(counters, game), source.getSourceId(), game) > 0; + } +} diff --git a/Mage.Sets/src/mage/cards/m/Malignus.java b/Mage.Sets/src/mage/cards/m/Malignus.java index 7db5312754..156ede533c 100644 --- a/Mage.Sets/src/mage/cards/m/Malignus.java +++ b/Mage.Sets/src/mage/cards/m/Malignus.java @@ -74,7 +74,7 @@ class HighestLifeTotalAmongOpponentsCount implements DynamicValue { @Override public DynamicValue copy() { - return new CardsInControllerHandCount(); + return CardsInControllerHandCount.instance; } @Override diff --git a/Mage.Sets/src/mage/cards/m/MammothUmbra.java b/Mage.Sets/src/mage/cards/m/MammothUmbra.java index 4b67b0e72c..1734366642 100644 --- a/Mage.Sets/src/mage/cards/m/MammothUmbra.java +++ b/Mage.Sets/src/mage/cards/m/MammothUmbra.java @@ -2,6 +2,7 @@ package mage.cards.m; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.AttachEffect; @@ -17,13 +18,12 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author Loki */ public final class MammothUmbra extends CardImpl { public MammothUmbra(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{W}"); this.subtype.add(SubType.AURA); @@ -33,9 +33,12 @@ public final class MammothUmbra extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature gets +3/+3 and has vigilance. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(3, 3, Duration.WhileOnBattlefield))); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(VigilanceAbility.getInstance(), AttachmentType.AURA))); + + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage.Sets/src/mage/cards/m/ManaCache.java b/Mage.Sets/src/mage/cards/m/ManaCache.java index 75437573ac..54cb19a0ba 100644 --- a/Mage.Sets/src/mage/cards/m/ManaCache.java +++ b/Mage.Sets/src/mage/cards/m/ManaCache.java @@ -59,7 +59,7 @@ class ManaCacheEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ManaCacheEffect() { diff --git a/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java b/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java index 33a76756d7..60ff355349 100644 --- a/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java +++ b/Mage.Sets/src/mage/cards/m/ManaChargedDragon.java @@ -80,7 +80,7 @@ class ManaChargedDragonEffect extends OneShotEffect { payed = true; } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}."); return xValue; } diff --git a/Mage.Sets/src/mage/cards/m/ManaClash.java b/Mage.Sets/src/mage/cards/m/ManaClash.java index 4c8fe0ee5c..af3dba45bc 100644 --- a/Mage.Sets/src/mage/cards/m/ManaClash.java +++ b/Mage.Sets/src/mage/cards/m/ManaClash.java @@ -62,8 +62,8 @@ class ManaClashEffect extends OneShotEffect { if (!targetOpponent.canRespond() || !controller.canRespond()) { return false; } - boolean controllerFlip = controller.flipCoin(game); - boolean opponentFlip = targetOpponent.flipCoin(game); + boolean controllerFlip = controller.flipCoin(source, game, false); + boolean opponentFlip = targetOpponent.flipCoin(source, game, false); if (controllerFlip && opponentFlip) { bothHeads = true; } diff --git a/Mage.Sets/src/mage/cards/m/ManaCrypt.java b/Mage.Sets/src/mage/cards/m/ManaCrypt.java index 90535e37a6..51c09adc93 100644 --- a/Mage.Sets/src/mage/cards/m/ManaCrypt.java +++ b/Mage.Sets/src/mage/cards/m/ManaCrypt.java @@ -58,7 +58,7 @@ class ManaCryptEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { player.damage(3, source.getSourceId(), game, false, true); } return true; diff --git a/Mage.Sets/src/mage/cards/m/ManaGeode.java b/Mage.Sets/src/mage/cards/m/ManaGeode.java new file mode 100644 index 0000000000..60edeadc52 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/ManaGeode.java @@ -0,0 +1,35 @@ +package mage.cards.m; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ManaGeode extends CardImpl { + + public ManaGeode(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // When Mana Geode enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private ManaGeode(final ManaGeode card) { + super(card); + } + + @Override + public ManaGeode copy() { + return new ManaGeode(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/ManaGeyser.java b/Mage.Sets/src/mage/cards/m/ManaGeyser.java index 7e752d2ee9..1069b45520 100644 --- a/Mage.Sets/src/mage/cards/m/ManaGeyser.java +++ b/Mage.Sets/src/mage/cards/m/ManaGeyser.java @@ -21,7 +21,7 @@ public final class ManaGeyser extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("tapped land your opponents control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } public ManaGeyser(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/ManaMaze.java b/Mage.Sets/src/mage/cards/m/ManaMaze.java index 29502df744..3d3504a2b4 100644 --- a/Mage.Sets/src/mage/cards/m/ManaMaze.java +++ b/Mage.Sets/src/mage/cards/m/ManaMaze.java @@ -63,9 +63,9 @@ class ManaMazeEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { Card card = game.getCard(event.getSourceId()); if (card != null) { - LastSpellCastWatcher watcher = (LastSpellCastWatcher) game.getState().getWatchers().get(LastSpellCastWatcher.class.getSimpleName()); - if (watcher != null && watcher.lastSpellCast != null) { - return !card.getColor(game).intersection(watcher.lastSpellCast.getColor(game)).isColorless(); + LastSpellCastWatcher watcher = game.getState().getWatcher(LastSpellCastWatcher.class); + if (watcher != null && watcher.getLastSpellCast() != null) { + return !card.getColor(game).intersection(watcher.getLastSpellCast().getColor(game)).isColorless(); } } return false; @@ -84,15 +84,15 @@ class ManaMazeEffect extends ContinuousRuleModifyingEffectImpl { class LastSpellCastWatcher extends Watcher { - Spell lastSpellCast = null; + private Spell lastSpellCast = null; public LastSpellCastWatcher() { - super(LastSpellCastWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public LastSpellCastWatcher(final LastSpellCastWatcher watcher) { super(watcher); - this.lastSpellCast = watcher.lastSpellCast; + this.lastSpellCast = watcher.getLastSpellCast(); } @Override @@ -121,4 +121,8 @@ class LastSpellCastWatcher extends Watcher { super.reset(); lastSpellCast = null; } + + public Spell getLastSpellCast() { + return lastSpellCast; + } } diff --git a/Mage.Sets/src/mage/cards/m/ManaScrew.java b/Mage.Sets/src/mage/cards/m/ManaScrew.java index f2228b428b..24b3514c9e 100644 --- a/Mage.Sets/src/mage/cards/m/ManaScrew.java +++ b/Mage.Sets/src/mage/cards/m/ManaScrew.java @@ -88,7 +88,7 @@ class ManaScrewEffect extends BasicManaEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null && player.flipCoin(game)) { + if (player != null && player.flipCoin(source, game, true)) { player.getManaPool().addMana(getMana(game, source), game, source); } return true; diff --git a/Mage.Sets/src/mage/cards/m/ManaSeverance.java b/Mage.Sets/src/mage/cards/m/ManaSeverance.java index df991bad93..673b7f2e3a 100644 --- a/Mage.Sets/src/mage/cards/m/ManaSeverance.java +++ b/Mage.Sets/src/mage/cards/m/ManaSeverance.java @@ -64,7 +64,7 @@ class ManaSeveranceEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); diff --git a/Mage.Sets/src/mage/cards/m/ManaVortex.java b/Mage.Sets/src/mage/cards/m/ManaVortex.java index 9123e0c6c5..efb49fa3d8 100644 --- a/Mage.Sets/src/mage/cards/m/ManaVortex.java +++ b/Mage.Sets/src/mage/cards/m/ManaVortex.java @@ -82,7 +82,7 @@ class CounterSourceEffect extends OneShotEffect { } if(spell != null){ Player controller = game.getPlayer(source.getControllerId()); - if(controller.chooseUse(Outcome.Detriment, "Sacrifice a land to not counter " + spell.getName() + '?', source, game)){ + if(controller != null && controller.chooseUse(Outcome.Detriment, "Sacrifice a land to not counter " + spell.getName() + '?', source, game)){ SacrificeTargetCost cost = new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent())); if(cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)){ game.informPlayers(controller.getLogName() + " sacrifices a land to not counter " + spell.getName() + '.'); @@ -128,7 +128,7 @@ class ManaVortexStateTriggeredAbility extends StateTriggeredAbility { @Override public String getRule() { - return new StringBuilder("When there are no lands on the battlefield, ").append(super.getRule()).toString() ; + return "When there are no lands on the battlefield, " + super.getRule(); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/ManaWeb.java b/Mage.Sets/src/mage/cards/m/ManaWeb.java index 20c06c5a7f..5fce3c5d7b 100644 --- a/Mage.Sets/src/mage/cards/m/ManaWeb.java +++ b/Mage.Sets/src/mage/cards/m/ManaWeb.java @@ -85,7 +85,7 @@ class ManaWebTriggeredAbility extends TriggeredAbilityImpl { class ManaWebeffect extends OneShotEffect { - private final static FilterLandPermanent filter = new FilterLandPermanent("an opponent taps a land"); + private static final FilterLandPermanent filter = new FilterLandPermanent("an opponent taps a land"); public ManaWebeffect() { super(Outcome.Tap); diff --git a/Mage.Sets/src/mage/cards/m/MangarasTome.java b/Mage.Sets/src/mage/cards/m/MangarasTome.java index c46179ffc4..78c7e296ef 100644 --- a/Mage.Sets/src/mage/cards/m/MangarasTome.java +++ b/Mage.Sets/src/mage/cards/m/MangarasTome.java @@ -73,7 +73,7 @@ class MangarasTomeSearchEffect extends OneShotEffect { Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && permanent != null) { TargetCardInLibrary target = new TargetCardInLibrary(5, new FilterCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { for (UUID targetId : target.getTargets()) { Card card = controller.getLibrary().getCard(targetId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/m/ManicScribe.java b/Mage.Sets/src/mage/cards/m/ManicScribe.java index d97181341d..26db45a69d 100644 --- a/Mage.Sets/src/mage/cards/m/ManicScribe.java +++ b/Mage.Sets/src/mage/cards/m/ManicScribe.java @@ -1,7 +1,7 @@ - package mage.cards.m; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveEachPlayerEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,13 +18,12 @@ import mage.constants.TargetController; import mage.constants.Zone; /** - * * @author fireshoes */ public final class ManicScribe extends CardImpl { public ManicScribe(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(0); @@ -38,7 +38,8 @@ public final class ManicScribe extends CardImpl { new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new PutTopCardOfLibraryIntoGraveTargetEffect(3), TargetController.OPPONENT, false, true), DeliriumCondition.instance, "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " - + "that player puts the top three cards of their library into their graveyard.")); + + "that player puts the top three cards of their library into their graveyard.") + .addHint(DeliriumHint.instance)); } public ManicScribe(final ManicScribe card) { diff --git a/Mage.Sets/src/mage/cards/m/ManipulateFate.java b/Mage.Sets/src/mage/cards/m/ManipulateFate.java index 853220f6fe..72f87eca90 100644 --- a/Mage.Sets/src/mage/cards/m/ManipulateFate.java +++ b/Mage.Sets/src/mage/cards/m/ManipulateFate.java @@ -66,16 +66,18 @@ class ManipulateFateEffect extends SearchEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player.searchLibrary(target, game)) { - for (UUID targetId : getTargets()) { - Card card = player.getLibrary().getCard(targetId, game); - if (card != null) { - card.moveToExile(null, null, targetId, game); + if(player != null) { + if (player.searchLibrary(target, source, game)) { + for (UUID targetId : getTargets()) { + Card card = player.getLibrary().getCard(targetId, game); + if (card != null) { + card.moveToExile(null, null, targetId, game); + } } + return true; } - return true; + player.shuffleLibrary(source, game); } - player.shuffleLibrary(source, game); return false; } diff --git a/Mage.Sets/src/mage/cards/m/MantellianSavrip.java b/Mage.Sets/src/mage/cards/m/MantellianSavrip.java index a2d8af400a..b9cc8e1884 100644 --- a/Mage.Sets/src/mage/cards/m/MantellianSavrip.java +++ b/Mage.Sets/src/mage/cards/m/MantellianSavrip.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,14 +8,15 @@ import mage.abilities.keyword.MonstrosityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class MantellianSavrip extends CardImpl { @@ -64,7 +63,7 @@ class MantellianSavripRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return (blocker.getPower().getValue() >= attacker.getPower().getValue()); } diff --git a/Mage.Sets/src/mage/cards/m/MaralenOfTheMornsong.java b/Mage.Sets/src/mage/cards/m/MaralenOfTheMornsong.java index f3f4a63f04..7167294fbf 100644 --- a/Mage.Sets/src/mage/cards/m/MaralenOfTheMornsong.java +++ b/Mage.Sets/src/mage/cards/m/MaralenOfTheMornsong.java @@ -100,7 +100,7 @@ class MaralenOfTheMornsongEffect2 extends OneShotEffect { if (player != null) { player.loseLife(3, game, false); TargetCardInLibrary target = new TargetCardInLibrary(); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()), Zone.HAND, source, game); } player.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java index 376f6f8ac4..866ab25de7 100644 --- a/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java +++ b/Mage.Sets/src/mage/cards/m/MarathWillOfTheWild.java @@ -52,12 +52,12 @@ public final class MarathWillOfTheWild extends CardImpl { this.toughness = new MageInt(0); // Marath, Will of the Wild enters the battlefield with a number of +1/+1 counters on it equal to the amount of mana spent to cast it. - Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new ManaSpentToCastCount(), true); + Effect effect = new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), ManaSpentToCastCount.instance, true); effect.setText("with a number of +1/+1 counters on it equal to the amount of mana spent to cast it"); this.addAbility(new EntersBattlefieldAbility(effect)); // {X}, Remove X +1/+1 counters from Marath: Choose one - Put X +1/+1 counters on target creature; - effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(0), new ManacostVariableValue()); + effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(0), ManacostVariableValue.instance); effect.setText("Put X +1/+1 counters on target creature"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); ability.addCost(new MarathWillOfTheWildRemoveCountersCost()); @@ -65,13 +65,13 @@ public final class MarathWillOfTheWild extends CardImpl { // or Marath deals X damage to any target; Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(new ManacostVariableValue())); - mode.getTargets().add(new TargetAnyTarget()); + mode.addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + mode.addTarget(new TargetAnyTarget()); ability.addMode(mode); // or create an X/X green Elemental creature token. mode = new Mode(); - mode.getEffects().add(new MarathWillOfTheWildCreateTokenEffect()); + mode.addEffect(new MarathWillOfTheWildCreateTokenEffect()); ability.addMode(mode); // X can't be 0. @@ -132,7 +132,7 @@ class MarathWillOfTheWildCreateTokenEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - int amount = new ManacostVariableValue().calculate(game, source, this); + int amount = ManacostVariableValue.instance.calculate(game, source, this); Token token = new MarathWillOfTheWildElementalToken(); token.getPower().modifyBaseValue(amount); token.getToughness().modifyBaseValue(amount); @@ -165,7 +165,7 @@ class MarathWillOfTheWildRemoveCountersCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { - int amount = new ManacostVariableValue().calculate(game, ability, null); + int amount = ManacostVariableValue.instance.calculate(game, ability, null); Permanent permanent = game.getPermanent(sourceId); if (permanent != null && permanent.getCounters(game).getCount(CounterType.P1P1) >= amount) { permanent.removeCounters(CounterType.P1P1.getName(), amount, game); diff --git a/Mage.Sets/src/mage/cards/m/MaraudingBoneslasher.java b/Mage.Sets/src/mage/cards/m/MaraudingBoneslasher.java index dfe8f33807..63ce40b3c2 100644 --- a/Mage.Sets/src/mage/cards/m/MaraudingBoneslasher.java +++ b/Mage.Sets/src/mage/cards/m/MaraudingBoneslasher.java @@ -24,7 +24,7 @@ public final class MaraudingBoneslasher extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MaraudingBoneslasher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MaraudingMaulhorn.java b/Mage.Sets/src/mage/cards/m/MaraudingMaulhorn.java index 389a96dd0f..2aaf0d5408 100644 --- a/Mage.Sets/src/mage/cards/m/MaraudingMaulhorn.java +++ b/Mage.Sets/src/mage/cards/m/MaraudingMaulhorn.java @@ -20,7 +20,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class MaraudingMaulhorn extends CardImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature named Advocate of the Beast"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature named Advocate of the Beast"); static { filter.add(new NamePredicate("Advocate of the Beast")); diff --git a/Mage.Sets/src/mage/cards/m/MaraxusOfKeld.java b/Mage.Sets/src/mage/cards/m/MaraxusOfKeld.java index 3619d29b3f..9d560a6bb0 100644 --- a/Mage.Sets/src/mage/cards/m/MaraxusOfKeld.java +++ b/Mage.Sets/src/mage/cards/m/MaraxusOfKeld.java @@ -27,7 +27,7 @@ public final class MaraxusOfKeld extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped artifacts, creatures, and lands you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), diff --git a/Mage.Sets/src/mage/cards/m/MarchOfSouls.java b/Mage.Sets/src/mage/cards/m/MarchOfSouls.java index e8b392c6f7..803b8b85b9 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfSouls.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfSouls.java @@ -13,19 +13,16 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.SpiritWhiteToken; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.UUID; /** - * * @author LoneFox - */ public final class MarchOfSouls extends CardImpl { public MarchOfSouls(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); // Destroy all creatures. They can't be regenerated. For each creature destroyed this way, its controller creates a 1/1 white Spirit creature token with flying. this.getSpellAbility().addEffect(new MarchOfSoulsEffect()); @@ -59,23 +56,19 @@ class MarchOfSoulsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List creatures = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, - source.getControllerId(), source.getSourceId(), game); Map playersWithCreatures = new HashMap<>(); - for(Permanent p : creatures) { + for (Permanent p : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURES, + source.getControllerId(), source.getSourceId(), game + )) { UUID controllerId = p.getControllerId(); - if(p.destroy(source.getSourceId(), game, true)) { - if(playersWithCreatures.containsKey(controllerId)) { - playersWithCreatures.put(controllerId, playersWithCreatures.get(controllerId) + 1); - } - else { - playersWithCreatures.put(controllerId, 1); - } + if (p.destroy(source.getSourceId(), game, true)) { + playersWithCreatures.put(controllerId, playersWithCreatures.getOrDefault(controllerId, 0) + 1); } } SpiritWhiteToken token = new SpiritWhiteToken(); - for(UUID playerId : playersWithCreatures.keySet()) { - token.putOntoBattlefield(playersWithCreatures.get(playerId), game, source.getSourceId(), playerId); + for (Map.Entry destroyedCreaturePerPlayer : playersWithCreatures.entrySet()) { + token.putOntoBattlefield(destroyedCreaturePerPlayer.getValue(), game, source.getSourceId(), destroyedCreaturePerPlayer.getKey()); } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java index 07fb0af7a6..0ddede3205 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheDrowned.java @@ -34,8 +34,8 @@ public final class MarchOfTheDrowned extends CardImpl { this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); // &bull; Return two target Pirate cards from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(2, filter)); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(2, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MarchOfTheMultitudes.java b/Mage.Sets/src/mage/cards/m/MarchOfTheMultitudes.java index b15c38640f..1f6f9fe5a4 100644 --- a/Mage.Sets/src/mage/cards/m/MarchOfTheMultitudes.java +++ b/Mage.Sets/src/mage/cards/m/MarchOfTheMultitudes.java @@ -24,7 +24,7 @@ public final class MarchOfTheMultitudes extends CardImpl { // Create X 1/1 white Soldier creature tokens with lifelink. this.getSpellAbility().addEffect(new CreateTokenEffect( new SoldierLifelinkToken(), - new ManacostVariableValue() + ManacostVariableValue.instance )); } diff --git a/Mage.Sets/src/mage/cards/m/MarduAscendancy.java b/Mage.Sets/src/mage/cards/m/MarduAscendancy.java index f7e370116c..d821628d15 100644 --- a/Mage.Sets/src/mage/cards/m/MarduAscendancy.java +++ b/Mage.Sets/src/mage/cards/m/MarduAscendancy.java @@ -30,7 +30,7 @@ public final class MarduAscendancy extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); static { - attackFilter.add(Predicates.not(new TokenPredicate())); + attackFilter.add(Predicates.not(TokenPredicate.instance)); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/m/MarduCharm.java b/Mage.Sets/src/mage/cards/m/MarduCharm.java index 50a4c9a412..9872d5acac 100644 --- a/Mage.Sets/src/mage/cards/m/MarduCharm.java +++ b/Mage.Sets/src/mage/cards/m/MarduCharm.java @@ -51,13 +51,13 @@ public final class MarduCharm extends CardImpl { // * Create two 1/1 white Warrior creature tokens. They gain first strike until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new MarduCharmCreateTokenEffect()); + mode.addEffect(new MarduCharmCreateTokenEffect()); this.getSpellAbility().addMode(mode); // * Target opponent reveals their hand. You choose a noncreature, nonland card from it. That player discards that card. mode = new Mode(); - mode.getEffects().add(new DiscardCardYouChooseTargetEffect(filter)); - mode.getTargets().add(new TargetOpponent()); + mode.addEffect(new DiscardCardYouChooseTargetEffect(filter)); + mode.addTarget(new TargetOpponent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MarkovCrusader.java b/Mage.Sets/src/mage/cards/m/MarkovCrusader.java index 9df87e68fc..328a6f715f 100644 --- a/Mage.Sets/src/mage/cards/m/MarkovCrusader.java +++ b/Mage.Sets/src/mage/cards/m/MarkovCrusader.java @@ -29,7 +29,7 @@ public final class MarkovCrusader extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Vampire"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/m/Maro.java b/Mage.Sets/src/mage/cards/m/Maro.java index e611397388..68bd5c1faf 100644 --- a/Mage.Sets/src/mage/cards/m/Maro.java +++ b/Mage.Sets/src/mage/cards/m/Maro.java @@ -27,7 +27,7 @@ public final class Maro extends CardImpl { this.toughness = new MageInt(0); // Maro's power and toughness are each equal to the number of cards in your hand. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInControllerHandCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame))); } public Maro(final Maro card) { diff --git a/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java b/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java index 5f4a56391f..ac37de8471 100644 --- a/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java +++ b/Mage.Sets/src/mage/cards/m/MarshalingTheTroops.java @@ -49,7 +49,7 @@ class MarshalingTheTroopsEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MarshalingTheTroopsEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MarshalsAnthem.java b/Mage.Sets/src/mage/cards/m/MarshalsAnthem.java index 39c3a3503d..9fc03f6d55 100644 --- a/Mage.Sets/src/mage/cards/m/MarshalsAnthem.java +++ b/Mage.Sets/src/mage/cards/m/MarshalsAnthem.java @@ -1,80 +1,55 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; -import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.keyword.MultikickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author jeffwadsworth - * */ public final class MarshalsAnthem extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); - private static final FilterCard filterCard = new FilterCard("creature card in your graveyard"); - - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - filterCard.add(new CardTypePredicate(CardType.CREATURE)); - } - - private final UUID originalId; + private static final String rule = "return up to X target creature cards from your graveyard to the battlefield, " + + "where X is the number of times {this} was kicked"; public MarshalsAnthem(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); // Multikicker {1}{W} this.addAbility(new MultikickerAbility("{1}{W}")); // Creatures you control get +1/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false))); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield) + )); // When Marshal's Anthem enters the battlefield, return up to X target creature cards from your graveyard to the battlefield, where X is the number of times Marshal's Anthem was kicked. - //TODO this should always trigger, even if it wasn't kicked - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect(), false), - KickedCondition.instance, - "When {this} enters the battlefield, return up to X target creature cards from your graveyard to the battlefield, where X is the number of times {this} was kicked."); - originalId = ability.getOriginalId(); + Ability ability = new EntersBattlefieldTriggeredAbility( + new ReturnFromGraveyardToBattlefieldTargetEffect().setText(rule), false + ); + ability.setTargetAdjuster(MarshalsAnthemAdjuster.instance); this.addAbility(ability); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - int numbTargets = new MultikickerCount().calculate(game, ability, null); - if (numbTargets > 0) { - ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, filterCard)); - } - } } public MarshalsAnthem(final MarshalsAnthem card) { super(card); - this.originalId = card.originalId; } @Override @@ -82,3 +57,17 @@ public final class MarshalsAnthem extends CardImpl { return new MarshalsAnthem(this); } } + +enum MarshalsAnthemAdjuster implements TargetAdjuster { + instance; + private static final FilterCard filter = new FilterCreatureCard("creature card in your graveyard"); + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = MultikickerCount.instance.calculate(game, ability, null); + if (numbTargets > 0) { + ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, filter)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MartonStromgald.java b/Mage.Sets/src/mage/cards/m/MartonStromgald.java index bc3a6cee4e..1bfecf2a85 100644 --- a/Mage.Sets/src/mage/cards/m/MartonStromgald.java +++ b/Mage.Sets/src/mage/cards/m/MartonStromgald.java @@ -27,8 +27,8 @@ public final class MartonStromgald extends CardImpl { private static final FilterBlockingCreature blockingFilter = new FilterBlockingCreature("blocking creature other than {this}"); static { - attackingFilter.add(new AnotherPredicate()); - blockingFilter.add(new AnotherPredicate()); + attackingFilter.add(AnotherPredicate.instance); + blockingFilter.add(AnotherPredicate.instance); } public MartonStromgald(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MartyrForTheCause.java b/Mage.Sets/src/mage/cards/m/MartyrForTheCause.java new file mode 100644 index 0000000000..19a17d1ec8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MartyrForTheCause.java @@ -0,0 +1,38 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.counter.ProliferateEffect; +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 MartyrForTheCause extends CardImpl { + + public MartyrForTheCause(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Martyr for the Cause dies, proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new DiesTriggeredAbility(new ProliferateEffect())); + } + + private MartyrForTheCause(final MartyrForTheCause card) { + super(card); + } + + @Override + public MartyrForTheCause copy() { + return new MartyrForTheCause(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java b/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java index 9a99586b08..c43c8a45e2 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfAshes.java @@ -48,7 +48,7 @@ public final class MartyrOfAshes extends CardImpl { this.toughness = new MageInt(1); // {2}, Reveal X red cards from your hand, Sacrifice Martyr of Ashes: Martyr of Ashes deals X damage to each creature without flying. - Effect effect = new DamageAllEffect(new RevealTargetFromHandCostCount(), filterCreature); + Effect effect = new DamageAllEffect(RevealTargetFromHandCostCount.instance, filterCreature); effect.setText("Martyr of Ashes deals X damage to each creature without flying."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filterHand))); diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfBones.java b/Mage.Sets/src/mage/cards/m/MartyrOfBones.java index 8a0bbb5d0b..a90e986f1b 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfBones.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfBones.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -25,17 +24,17 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInASingleGraveyard; import mage.target.common.TargetCardInHand; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author emerald000 */ public final class MartyrOfBones extends CardImpl { - private final UUID originalId; - public MartyrOfBones(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -49,27 +48,12 @@ public final class MartyrOfBones extends CardImpl { ability.addCost(new RevealVariableBlackCardsFromHandCost()); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInASingleGraveyard(0, 1, new FilterCard("cards in a single graveyard"))); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(MartyrOfBonesAdjuster.instance); this.addAbility(ability); } public MartyrOfBones(final MartyrOfBones card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - int amount = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof RevealVariableBlackCardsFromHandCost) { - amount = ((VariableCost) cost).getAmount(); - } - } - ability.getTargets().clear(); - ability.addTarget(new TargetCardInASingleGraveyard(0, amount, new FilterCard())); - } } @Override @@ -78,6 +62,22 @@ public final class MartyrOfBones extends CardImpl { } } +enum MartyrOfBonesAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int amount = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof RevealVariableBlackCardsFromHandCost) { + amount = ((VariableCost) cost).getAmount(); + } + } + ability.getTargets().clear(); + ability.addTarget(new TargetCardInASingleGraveyard(0, amount, new FilterCard())); + } +} + class RevealVariableBlackCardsFromHandCost extends VariableCostImpl { private static final FilterCard filter = new FilterCard("X black cards from your hand"); @@ -88,7 +88,7 @@ class RevealVariableBlackCardsFromHandCost extends VariableCostImpl { RevealVariableBlackCardsFromHandCost() { super("black cards to reveal"); - this.text = new StringBuilder("Reveal ").append(xText).append(" black cards from {this}").toString(); + this.text = "Reveal " + xText + " black cards from {this}"; } RevealVariableBlackCardsFromHandCost(final RevealVariableBlackCardsFromHandCost cost) { diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfFrost.java b/Mage.Sets/src/mage/cards/m/MartyrOfFrost.java index 44e48efe62..5ec56acb5a 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfFrost.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfFrost.java @@ -42,7 +42,7 @@ public final class MartyrOfFrost extends CardImpl { this.toughness = new MageInt(1); // {2}, Reveal X blue cards from your hand, Sacrifice Martyr of Frost: Counter target spell unless its controller pays {X}. - Effect effect = new CounterUnlessPaysEffect(new RevealTargetFromHandCostCount()); + Effect effect = new CounterUnlessPaysEffect(RevealTargetFromHandCostCount.instance); effect.setText("Counter target spell unless its controller pays {X}."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filter))); diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfSands.java b/Mage.Sets/src/mage/cards/m/MartyrOfSands.java index 5076f87b2f..d6c7baa463 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfSands.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfSands.java @@ -43,7 +43,7 @@ public final class MartyrOfSands extends CardImpl { this.toughness = new MageInt(1); // {1}, Reveal X white cards from your hand, Sacrifice Martyr of Sands: You gain three times X life. - Effect effect = new GainLifeEffect(new MultipliedValue(new RevealTargetFromHandCostCount(), 3)); + Effect effect = new GainLifeEffect(new MultipliedValue(RevealTargetFromHandCostCount.instance, 3)); effect.setText("You gain three times X life."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}")); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filter))); diff --git a/Mage.Sets/src/mage/cards/m/MartyrOfSpores.java b/Mage.Sets/src/mage/cards/m/MartyrOfSpores.java index 160441a376..4bb1335d44 100644 --- a/Mage.Sets/src/mage/cards/m/MartyrOfSpores.java +++ b/Mage.Sets/src/mage/cards/m/MartyrOfSpores.java @@ -43,7 +43,7 @@ public final class MartyrOfSpores extends CardImpl { this.toughness = new MageInt(1); // {1}, Reveal X green cards from your hand, Sacrifice Martyr of Spores: Target creature gets +X/+X until end of turn. - Effect effect = new BoostTargetEffect(new RevealTargetFromHandCostCount(), new RevealTargetFromHandCostCount(), Duration.EndOfTurn, true); + Effect effect = new BoostTargetEffect(RevealTargetFromHandCostCount.instance, RevealTargetFromHandCostCount.instance, Duration.EndOfTurn, true); effect.setText("Target creature gets +X/+X until end of turn."); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(1)); ability.addCost(new RevealTargetFromHandCost(new TargetCardInHand(0, Integer.MAX_VALUE, filter))); diff --git a/Mage.Sets/src/mage/cards/m/Martyrdom.java b/Mage.Sets/src/mage/cards/m/Martyrdom.java index b684ec48b7..067ad07278 100644 --- a/Mage.Sets/src/mage/cards/m/Martyrdom.java +++ b/Mage.Sets/src/mage/cards/m/Martyrdom.java @@ -94,11 +94,6 @@ class MartyrdomActivatedAbility extends ActivatedAbilityImpl { this.caster = ability.caster; } - @Override - public Effects getEffects(Game game, EffectType effectType) { - return super.getEffects(game, effectType); - } - @Override public ActivationStatus canActivate(UUID playerId, Game game) { if (playerId.equals(caster)) { diff --git a/Mage.Sets/src/mage/cards/m/MarwynTheNurturer.java b/Mage.Sets/src/mage/cards/m/MarwynTheNurturer.java index 8a237ea879..353450b982 100644 --- a/Mage.Sets/src/mage/cards/m/MarwynTheNurturer.java +++ b/Mage.Sets/src/mage/cards/m/MarwynTheNurturer.java @@ -25,7 +25,7 @@ public final class MarwynTheNurturer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Elf"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java index f13d5931d5..776aa88b33 100644 --- a/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java +++ b/Mage.Sets/src/mage/cards/m/MaskOfTheMimic.java @@ -31,7 +31,7 @@ public final class MaskOfTheMimic extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public MaskOfTheMimic(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MassManipulation.java b/Mage.Sets/src/mage/cards/m/MassManipulation.java new file mode 100644 index 0000000000..61104d45bb --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MassManipulation.java @@ -0,0 +1,50 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.game.Game; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MassManipulation extends CardImpl { + + public MassManipulation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{U}{U}{U}{U}"); + + // Gain control of X target creatures and/or planeswalkers. + this.getSpellAbility().addEffect( + new GainControlTargetEffect(Duration.Custom, true) + .setText("Gain control of X target creatures and/or planeswalkers.") + ); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + this.getSpellAbility().setTargetAdjuster(MassManipulationAdjuster.instance); + } + + private MassManipulation(final MassManipulation card) { + super(card); + } + + @Override + public MassManipulation copy() { + return new MassManipulation(this); + } +} + +enum MassManipulationAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreatureOrPlaneswalker(ability.getManaCostsToPay().getX())); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MassMutiny.java b/Mage.Sets/src/mage/cards/m/MassMutiny.java index 10a9549d8b..1ca9b18e39 100644 --- a/Mage.Sets/src/mage/cards/m/MassMutiny.java +++ b/Mage.Sets/src/mage/cards/m/MassMutiny.java @@ -1,9 +1,7 @@ - package mage.cards.m; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; @@ -21,6 +19,7 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; /** @@ -34,22 +33,7 @@ public final class MassMutiny extends CardImpl { // For each opponent, gain control of up to one target creature that player controls until end of turn. Untap those creatures. They gain haste until end of turn. this.getSpellAbility().addEffect(new MassMutinyEffect()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getName()); - filter.add(new ControllerIdPredicate(opponentId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); - ability.addTarget(target); - } - } - } + this.getSpellAbility().setTargetAdjuster(MassMutinyAdjuster.instance); } public MassMutiny(final MassMutiny card) { @@ -62,6 +46,24 @@ public final class MassMutiny extends CardImpl { } } +enum MassMutinyAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); + ability.addTarget(target); + } + } + } +} + class MassMutinyEffect extends OneShotEffect { public MassMutinyEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MassacreGirl.java b/Mage.Sets/src/mage/cards/m/MassacreGirl.java new file mode 100644 index 0000000000..593f96b51d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MassacreGirl.java @@ -0,0 +1,106 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MassacreGirl extends CardImpl { + + public MassacreGirl(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Menace + this.addAbility(new MenaceAbility()); + + // When Massacre Girl enters the battlefield, each other creature gets -1/-1 until end of turn. Whenever a creature dies this turn, each creature other than Massacre Girl gets -1/-1 until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MassacreGirlEffect())); + } + + private MassacreGirl(final MassacreGirl card) { + super(card); + } + + @Override + public MassacreGirl copy() { + return new MassacreGirl(this); + } +} + +class MassacreGirlEffect extends OneShotEffect { + + MassacreGirlEffect() { + super(Outcome.Benefit); + staticText = "each other creature gets -1/-1 until end of turn. " + + "Whenever a creature dies this turn, " + + "each creature other than {this} gets -1/-1 until end of turn."; + } + + private MassacreGirlEffect(final MassacreGirlEffect effect) { + super(effect); + } + + @Override + public MassacreGirlEffect copy() { + return new MassacreGirlEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + game.addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn, true), source); + game.addDelayedTriggeredAbility(new MassacreGirlDelayedTriggeredAbility(), source); + return true; + } +} + +class MassacreGirlDelayedTriggeredAbility extends DelayedTriggeredAbility { + + MassacreGirlDelayedTriggeredAbility() { + super(new BoostAllEffect(-1, -1, Duration.EndOfTurn, true), Duration.EndOfTurn, false); + } + + private MassacreGirlDelayedTriggeredAbility(final MassacreGirlDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.isDiesEvent() && zEvent.getTarget().isCreature(); + } + + @Override + public MassacreGirlDelayedTriggeredAbility copy() { + return new MassacreGirlDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a creature dies this turn, each creature other than {this} gets -1/-1 until end of turn"; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MassiveRaid.java b/Mage.Sets/src/mage/cards/m/MassiveRaid.java index 02504c5141..15a636332a 100644 --- a/Mage.Sets/src/mage/cards/m/MassiveRaid.java +++ b/Mage.Sets/src/mage/cards/m/MassiveRaid.java @@ -1,28 +1,27 @@ - package mage.cards.m; -import java.util.UUID; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MassiveRaid extends CardImpl { public MassiveRaid(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}{R}"); // Massive Raid deals damage to any target equal to the number of creatures you control. - this.getSpellAbility().addEffect(new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()))); + this.getSpellAbility().addEffect(new DamageTargetEffect(CreaturesYouControlCount.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); } public MassiveRaid(final MassiveRaid card) { diff --git a/Mage.Sets/src/mage/cards/m/MasterApothecary.java b/Mage.Sets/src/mage/cards/m/MasterApothecary.java index c7e02a7431..bb44e92b0d 100644 --- a/Mage.Sets/src/mage/cards/m/MasterApothecary.java +++ b/Mage.Sets/src/mage/cards/m/MasterApothecary.java @@ -30,7 +30,7 @@ public final class MasterApothecary extends CardImpl { static { filter.add(new SubtypePredicate(SubType.CLERIC)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MasterApothecary(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MasterBiomancer.java b/Mage.Sets/src/mage/cards/m/MasterBiomancer.java index 79f1c60538..b810e3965c 100644 --- a/Mage.Sets/src/mage/cards/m/MasterBiomancer.java +++ b/Mage.Sets/src/mage/cards/m/MasterBiomancer.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,7 +9,10 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.continuous.AddCardSubTypeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.EntersTheBattlefieldEvent; @@ -19,14 +21,15 @@ import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MasterBiomancer extends CardImpl { public MasterBiomancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WIZARD); @@ -34,10 +37,10 @@ public final class MasterBiomancer extends CardImpl { this.toughness = new MageInt(4); // Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MasterBiomancerEntersBattlefieldEffect())); + this.addAbility(new SimpleStaticAbility(new MasterBiomancerEntersBattlefieldEffect())); } - public MasterBiomancer(final MasterBiomancer card) { + private MasterBiomancer(final MasterBiomancer card) { super(card); } @@ -49,12 +52,12 @@ public final class MasterBiomancer extends CardImpl { class MasterBiomancerEntersBattlefieldEffect extends ReplacementEffectImpl { - public MasterBiomancerEntersBattlefieldEffect() { + MasterBiomancerEntersBattlefieldEffect() { super(Duration.WhileOnBattlefield, Outcome.BoostCreature); - staticText = "Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to Master Biomancer's power and as a Mutant in addition to its other types"; + staticText = "Each other creature you control enters the battlefield with a number of additional +1/+1 counters on it equal to {this}'s power and as a Mutant in addition to its other types"; } - public MasterBiomancerEntersBattlefieldEffect(MasterBiomancerEntersBattlefieldEffect effect) { + private MasterBiomancerEntersBattlefieldEffect(MasterBiomancerEntersBattlefieldEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java b/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java index 00e6affcea..f54b0f4c50 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfDiversion.java @@ -22,7 +22,7 @@ public final class MasterOfDiversion extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public MasterOfDiversion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java b/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java new file mode 100644 index 0000000000..32ea8a44b5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheHunt.java @@ -0,0 +1,40 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.WolvesOfTheHuntToken; + +/** + * @author L_J + */ +public final class MasterOfTheHunt extends CardImpl { + + public MasterOfTheHunt(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Create a 1/1 green Wolf creature token named Wolves of the Hunt. It has “bands with other creatures named Wolves of the Hunt.” + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(new WolvesOfTheHuntToken()), new ManaCostsImpl("{2}{G}{G}"))); + } + + public MasterOfTheHunt(final MasterOfTheHunt card) { + super(card); + } + + @Override + public MasterOfTheHunt copy() { + return new MasterOfTheHunt(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java b/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java index c3b9f96e9e..ec5f5d5fc5 100644 --- a/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java +++ b/Mage.Sets/src/mage/cards/m/MasterOfTheWildHunt.java @@ -69,7 +69,7 @@ class MasterOfTheWildHuntEffect extends OneShotEffect { static { filter.add(new SubtypePredicate(SubType.WOLF)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MasterOfTheWildHuntEffect() { @@ -97,8 +97,10 @@ class MasterOfTheWildHuntEffect extends OneShotEffect { wolves.add(permanent.getId()); } Player player = game.getPlayer(target.getControllerId()); - player.assignDamage(target.getPower().getValue(), wolves, "Wolf", target.getId(), game); - return true; + if(player != null) { + player.assignDamage(target.getPower().getValue(), wolves, "Wolf", target.getId(), game); + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MasterTheWay.java b/Mage.Sets/src/mage/cards/m/MasterTheWay.java index 9325793aa8..e3fc9243cf 100644 --- a/Mage.Sets/src/mage/cards/m/MasterTheWay.java +++ b/Mage.Sets/src/mage/cards/m/MasterTheWay.java @@ -23,7 +23,7 @@ public final class MasterTheWay extends CardImpl { // Draw a card. Master the Way deals damage to any target equal to the number of cards in your hand. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); - Effect effect = new DamageTargetEffect(new CardsInControllerHandCount()); + Effect effect = new DamageTargetEffect(CardsInControllerHandCount.instance); effect.setText("{this} deals damage to any target equal to the number of cards in your hand"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java index a5861363c5..4889ff1da7 100644 --- a/Mage.Sets/src/mage/cards/m/MasterWarcraft.java +++ b/Mage.Sets/src/mage/cards/m/MasterWarcraft.java @@ -79,7 +79,7 @@ public final class MasterWarcraft extends CardImpl { @Override public boolean apply(Game game, Ability source) { - MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName()); + MasterWarcraftCastWatcher watcher = game.getState().getWatcher(MasterWarcraftCastWatcher.class); if (watcher != null) { watcher.increment(); return true; @@ -105,7 +105,7 @@ public final class MasterWarcraft extends CardImpl { @Override public boolean apply(Game game, Ability source) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); if (watcher != null) { watcher.increment(); return true; @@ -153,7 +153,10 @@ class MasterWarcraftChooseAttackersEffect extends ContinuousRuleModifyingEffectI @Override public boolean applies(GameEvent event, Ability source, Game game) { - MasterWarcraftCastWatcher watcher = (MasterWarcraftCastWatcher) game.getState().getWatchers().get(MasterWarcraftCastWatcher.class.getSimpleName()); + MasterWarcraftCastWatcher watcher = game.getState().getWatcher(MasterWarcraftCastWatcher.class); + if(watcher == null){ + return false; + } watcher.decrement(); if (watcher.copyCountApply > 0) { game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); @@ -226,7 +229,10 @@ class MasterWarcraftChooseBlockersEffect extends ContinuousRuleModifyingEffectIm @Override public boolean applies(GameEvent event, Ability source, Game game) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); + if(watcher == null){ + return false; + } watcher.decrement(); if (watcher.copyCountApply > 0) { game.informPlayers(source.getSourceObject(game).getIdName() + " didn't apply"); @@ -248,7 +254,7 @@ class MasterWarcraftCastWatcher extends Watcher { public int copyCountApply = 0; public MasterWarcraftCastWatcher() { - super(MasterWarcraftCastWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MasterWarcraftCastWatcher(final MasterWarcraftCastWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/m/MastermindsAcquisition.java b/Mage.Sets/src/mage/cards/m/MastermindsAcquisition.java index f0917ed5f8..5806886955 100644 --- a/Mage.Sets/src/mage/cards/m/MastermindsAcquisition.java +++ b/Mage.Sets/src/mage/cards/m/MastermindsAcquisition.java @@ -26,7 +26,7 @@ public final class MastermindsAcquisition extends CardImpl { // Choose a card you own from outside the game and put it into your hand. Mode mode = new Mode(); - mode.getEffects().add(new WishEffect(new FilterCard(), false)); + mode.addEffect(new WishEffect(new FilterCard(), false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MasteryOfTheUnseen.java b/Mage.Sets/src/mage/cards/m/MasteryOfTheUnseen.java index 998060e9eb..fd31f8c868 100644 --- a/Mage.Sets/src/mage/cards/m/MasteryOfTheUnseen.java +++ b/Mage.Sets/src/mage/cards/m/MasteryOfTheUnseen.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.TurnedFaceUpAllTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -12,23 +10,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MasteryOfTheUnseen extends CardImpl { public MasteryOfTheUnseen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // Whenever a permanent you control is turned face up, you gain 1 life for each creature you control. this.addAbility(new TurnedFaceUpAllTriggeredAbility( - new GainLifeEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent())), + new GainLifeEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE)), new FilterControlledPermanent("a permanent you control"))); - + // {3}{W}: Manifest the top card of your library. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ManifestEffect(1), new ManaCostsImpl("{3}{W}"))); } diff --git a/Mage.Sets/src/mage/cards/m/MasumaroFirstToLive.java b/Mage.Sets/src/mage/cards/m/MasumaroFirstToLive.java index e7721a06a8..3e67265849 100644 --- a/Mage.Sets/src/mage/cards/m/MasumaroFirstToLive.java +++ b/Mage.Sets/src/mage/cards/m/MasumaroFirstToLive.java @@ -32,7 +32,7 @@ public final class MasumaroFirstToLive extends CardImpl { this.toughness = new MageInt(0); // Masumaro, First to Live's power and toughness are each equal to twice the number of cards in your hand. - DynamicValue xValue= new MultipliedValue(new CardsInControllerHandCount(), 2); + DynamicValue xValue= new MultipliedValue(CardsInControllerHandCount.instance, 2); Effect effect = new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame); effect.setText("{this}'s power and toughness are each equal to twice the number of cards in your hand"); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); diff --git a/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java b/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java index 45ab9cb632..e1e100f8d9 100644 --- a/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java +++ b/Mage.Sets/src/mage/cards/m/MausoleumHarpy.java @@ -1,12 +1,11 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -19,16 +18,17 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MausoleumHarpy extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } @@ -49,7 +49,8 @@ public final class MausoleumHarpy extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility( new DiesCreatureTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false, filter), CitysBlessingCondition.instance, - "Whenever another creature you control dies, if you have the city's blessing, put a +1/+1 counter on {this}. ")); + "Whenever another creature you control dies, if you have the city's blessing, put a +1/+1 counter on {this}. ") + .addHint(CitysBlessingHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/m/MausoleumWanderer.java b/Mage.Sets/src/mage/cards/m/MausoleumWanderer.java index a77aef89b9..b37f3779c8 100644 --- a/Mage.Sets/src/mage/cards/m/MausoleumWanderer.java +++ b/Mage.Sets/src/mage/cards/m/MausoleumWanderer.java @@ -31,7 +31,7 @@ public final class MausoleumWanderer extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.SPIRIT)); } diff --git a/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java b/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java index a0b101ebcb..98fe12b17d 100644 --- a/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java +++ b/Mage.Sets/src/mage/cards/m/MavrenFeinDuskApostle.java @@ -57,7 +57,7 @@ class MavrenFeinDuskApostleTriggeredAbility extends TriggeredAbilityImpl { static { filter.add(new SubtypePredicate(SubType.VAMPIRE)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/m/MayhemDevil.java b/Mage.Sets/src/mage/cards/m/MayhemDevil.java new file mode 100644 index 0000000000..0e4a5fa480 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MayhemDevil.java @@ -0,0 +1,73 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MayhemDevil extends CardImpl { + + public MayhemDevil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.subtype.add(SubType.DEVIL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Whenever a player sacrifices a permanent, Mayhem Devil deals 1 damage to any target. + this.addAbility(new MayhemDevilTriggeredAbility()); + } + + private MayhemDevil(final MayhemDevil card) { + super(card); + } + + @Override + public MayhemDevil copy() { + return new MayhemDevil(this); + } +} + +class MayhemDevilTriggeredAbility extends TriggeredAbilityImpl { + + MayhemDevilTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(1)); + this.addTarget(new TargetAnyTarget()); + } + + private MayhemDevilTriggeredAbility(final MayhemDevilTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SACRIFICED_PERMANENT; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return true; + } + + @Override + public MayhemDevilTriggeredAbility copy() { + return new MayhemDevilTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a player sacrifices a permanent, {this} deals 1 damage to any target."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MazeAbomination.java b/Mage.Sets/src/mage/cards/m/MazeAbomination.java index 7168099bec..751d9ee3fa 100644 --- a/Mage.Sets/src/mage/cards/m/MazeAbomination.java +++ b/Mage.Sets/src/mage/cards/m/MazeAbomination.java @@ -26,7 +26,7 @@ public final class MazeAbomination extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Multicolored creatures you control"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public MazeAbomination (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MazeBehemoth.java b/Mage.Sets/src/mage/cards/m/MazeBehemoth.java index ddeb6ec6f2..a9b69d81d1 100644 --- a/Mage.Sets/src/mage/cards/m/MazeBehemoth.java +++ b/Mage.Sets/src/mage/cards/m/MazeBehemoth.java @@ -26,7 +26,7 @@ public final class MazeBehemoth extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Multicolored creatures you control"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public MazeBehemoth (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MazeGlider.java b/Mage.Sets/src/mage/cards/m/MazeGlider.java index 1e58b2d741..b39b8301ba 100644 --- a/Mage.Sets/src/mage/cards/m/MazeGlider.java +++ b/Mage.Sets/src/mage/cards/m/MazeGlider.java @@ -26,7 +26,7 @@ public final class MazeGlider extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Multicolored creatures you control"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public MazeGlider (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MazeRusher.java b/Mage.Sets/src/mage/cards/m/MazeRusher.java index 995e865c6e..aed3e120bb 100644 --- a/Mage.Sets/src/mage/cards/m/MazeRusher.java +++ b/Mage.Sets/src/mage/cards/m/MazeRusher.java @@ -26,7 +26,7 @@ public final class MazeRusher extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Multicolored creatures you control"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public MazeRusher (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MazeSentinel.java b/Mage.Sets/src/mage/cards/m/MazeSentinel.java index 11218b098a..357af8a398 100644 --- a/Mage.Sets/src/mage/cards/m/MazeSentinel.java +++ b/Mage.Sets/src/mage/cards/m/MazeSentinel.java @@ -26,7 +26,7 @@ public final class MazeSentinel extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("Multicolored creatures you control"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public MazeSentinel (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MazesEnd.java b/Mage.Sets/src/mage/cards/m/MazesEnd.java index d76dbd7271..c575930d28 100644 --- a/Mage.Sets/src/mage/cards/m/MazesEnd.java +++ b/Mage.Sets/src/mage/cards/m/MazesEnd.java @@ -1,18 +1,16 @@ - - package mage.cards.m; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ReturnToHandFromBattlefieldSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.hint.ValueHint; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -27,20 +25,24 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MazesEnd extends CardImpl { private static final FilterCard filterCard = new FilterCard("Gate card"); + static { filterCard.add(new SubtypePredicate(SubType.GATE)); } public MazesEnd(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Maze's End enters the battlefield tapped. @@ -54,8 +56,8 @@ public final class MazesEnd extends CardImpl { ability.addEffect(new MazesEndEffect()); ability.addCost(new TapSourceCost()); ability.addCost(new ReturnToHandFromBattlefieldSourceCost()); + ability.addHint(new ValueHint("Gates with different names you control", GatesWithDifferentNamesYouControlCount.instance)); this.addAbility(ability); - } public MazesEnd(final MazesEnd card) { @@ -68,6 +70,40 @@ public final class MazesEnd extends CardImpl { } } +enum GatesWithDifferentNamesYouControlCount implements DynamicValue { + + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + List names = new ArrayList<>(); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(sourceAbility.getControllerId())) { + if (permanent.hasSubtype(SubType.GATE, game)) { + if (!names.contains(permanent.getName())) { + names.add(permanent.getName()); + } + } + } + return names.size(); + } + + @Override + public GatesWithDifferentNamesYouControlCount copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "Gates with different names you control"; + } +} + + class MazesEndEffect extends OneShotEffect { public MazesEndEffect() { @@ -86,15 +122,8 @@ class MazesEndEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List names = new ArrayList<>(); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { - if (permanent.hasSubtype(SubType.GATE, game)) { - if (!names.contains(permanent.getName())) { - names.add(permanent.getName()); - } - } - } - if (names.size() >= 10) { + int count = GatesWithDifferentNamesYouControlCount.instance.calculate(game, source, this); + if (count >= 10) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.won(game); @@ -102,5 +131,4 @@ class MazesEndEffect extends OneShotEffect { } return false; } - } diff --git a/Mage.Sets/src/mage/cards/m/MechanizedProduction.java b/Mage.Sets/src/mage/cards/m/MechanizedProduction.java index 5e2a63b90d..1ed9da08de 100644 --- a/Mage.Sets/src/mage/cards/m/MechanizedProduction.java +++ b/Mage.Sets/src/mage/cards/m/MechanizedProduction.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -27,7 +28,6 @@ import mage.target.common.TargetControlledPermanent; import mage.util.CardUtil; /** - * * @author LevelX2 */ public final class MechanizedProduction extends CardImpl { @@ -86,15 +86,17 @@ class MechanizedProductionEffect extends OneShotEffect { } Map countNames = new HashMap<>(); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), source.getControllerId(), game)) { - int counter = countNames.getOrDefault(permanent.getName(),0); + int counter = countNames.getOrDefault(permanent.getName(), 0); countNames.put(permanent.getName(), counter + 1); } for (Entry entry : countNames.entrySet()) { if (entry.getValue() > 7) { Player controller = game.getPlayer(source.getControllerId()); - game.informPlayers(controller.getLogName() + " controls eight or more artifacts with the same name as one another (" + entry.getKey() + ")."); - controller.won(game); - return true; + if (controller != null) { + game.informPlayers(controller.getLogName() + " controls eight or more artifacts with the same name as one another (" + entry.getKey() + ")."); + controller.won(game); + return true; + } } } return true; diff --git a/Mage.Sets/src/mage/cards/m/MeishinTheMindCage.java b/Mage.Sets/src/mage/cards/m/MeishinTheMindCage.java index 2d29f4215a..a88e657705 100644 --- a/Mage.Sets/src/mage/cards/m/MeishinTheMindCage.java +++ b/Mage.Sets/src/mage/cards/m/MeishinTheMindCage.java @@ -26,7 +26,7 @@ public final class MeishinTheMindCage extends CardImpl { addSuperType(SuperType.LEGENDARY); // All creatures get -X/-0, where X is the number of cards in your hand. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(new SignInversionDynamicValue(new CardsInControllerHandCount()), new StaticValue(0), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false, "All creatures get -X/-0, where X is the number of cards in your hand"))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(new SignInversionDynamicValue(CardsInControllerHandCount.instance), new StaticValue(0), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENT_CREATURE, false, "All creatures get -X/-0, where X is the number of cards in your hand"))); } public MeishinTheMindCage(final MeishinTheMindCage card) { diff --git a/Mage.Sets/src/mage/cards/m/Melee.java b/Mage.Sets/src/mage/cards/m/Melee.java index 3031c15e64..4fe220c027 100644 --- a/Mage.Sets/src/mage/cards/m/Melee.java +++ b/Mage.Sets/src/mage/cards/m/Melee.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; @@ -17,19 +16,21 @@ import mage.abilities.effects.common.RemoveFromCombatTargetEffect; import mage.abilities.effects.common.UntapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TurnPhase; import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; -import mage.watchers.Watcher; import mage.watchers.common.ChooseBlockersRedundancyWatcher; +import java.util.UUID; + /** - * * @author L_J */ public final class Melee extends CardImpl { @@ -61,27 +62,27 @@ public final class Melee extends CardImpl { public Melee copy() { return new Melee(this); } - + private class ChooseBlockersRedundancyWatcherIncrementEffect extends OneShotEffect { - + ChooseBlockersRedundancyWatcherIncrementEffect() { super(Outcome.Neutral); } - + ChooseBlockersRedundancyWatcherIncrementEffect(final ChooseBlockersRedundancyWatcherIncrementEffect effect) { super(effect); } - + @Override public boolean apply(Game game, Ability source) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); if (watcher != null) { watcher.increment(); return true; } return false; } - + @Override public ChooseBlockersRedundancyWatcherIncrementEffect copy() { return new ChooseBlockersRedundancyWatcherIncrementEffect(this); @@ -117,7 +118,10 @@ class MeleeChooseBlockersEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); + if (watcher == null) { + return false; + } watcher.decrement(); watcher.copyCount--; if (watcher.copyCountApply > 0) { diff --git a/Mage.Sets/src/mage/cards/m/MemorialToUnity.java b/Mage.Sets/src/mage/cards/m/MemorialToUnity.java index 7b28940640..4a60ce8a17 100644 --- a/Mage.Sets/src/mage/cards/m/MemorialToUnity.java +++ b/Mage.Sets/src/mage/cards/m/MemorialToUnity.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -18,6 +17,8 @@ import mage.constants.CardType; import mage.constants.Zone; import mage.filter.common.FilterCreatureCard; +import java.util.UUID; + /** * @author Rystan */ @@ -34,7 +35,7 @@ public final class MemorialToUnity extends CardImpl { // {2}{G}, {T}, Sacrifice Memorial to Unity: Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Then put the rest on the bottom of your library in a random order. Effect effect = new LookLibraryAndPickControllerEffect( new StaticValue(5), false, new StaticValue(1), new FilterCreatureCard("a creature card"), false, true - ); + ).setBackInRandomOrder(true); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{G}")); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/m/MemoryCrystal.java b/Mage.Sets/src/mage/cards/m/MemoryCrystal.java index 2da9818be4..00d1411e83 100644 --- a/Mage.Sets/src/mage/cards/m/MemoryCrystal.java +++ b/Mage.Sets/src/mage/cards/m/MemoryCrystal.java @@ -61,7 +61,7 @@ class MemoryCrystalSpellsCostReductionEffect extends CostModificationEffectImpl if (card != null) { for (Ability ability : card.getAbilities()) { if (ability instanceof BuybackAbility) { - if (((BuybackAbility) ability).isActivated()) { + if (ability.isActivated()) { int amountToReduce = ((BuybackAbility) ability).reduceCost(2); CardUtil.reduceCost(abilityToModify, amountToReduce); } diff --git a/Mage.Sets/src/mage/cards/m/MentorOfTheMeek.java b/Mage.Sets/src/mage/cards/m/MentorOfTheMeek.java index 116cd617b6..7e007dec24 100644 --- a/Mage.Sets/src/mage/cards/m/MentorOfTheMeek.java +++ b/Mage.Sets/src/mage/cards/m/MentorOfTheMeek.java @@ -28,7 +28,7 @@ public final class MentorOfTheMeek extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another creature with power 2 or less"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); } diff --git a/Mage.Sets/src/mage/cards/m/MercadianAtlas.java b/Mage.Sets/src/mage/cards/m/MercadianAtlas.java index c2d980a6ed..5fb9e90c5a 100644 --- a/Mage.Sets/src/mage/cards/m/MercadianAtlas.java +++ b/Mage.Sets/src/mage/cards/m/MercadianAtlas.java @@ -49,7 +49,7 @@ enum MercadianAtlasCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayLandWatcher watcher = (PlayLandWatcher) game.getState().getWatchers().get(PlayLandWatcher.class.getSimpleName()); + PlayLandWatcher watcher = game.getState().getWatcher(PlayLandWatcher.class); if (watcher != null) { return !watcher.landPlayed(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/m/MercadianBazaar.java b/Mage.Sets/src/mage/cards/m/MercadianBazaar.java index dc03c83a53..aadd3bbe45 100644 --- a/Mage.Sets/src/mage/cards/m/MercadianBazaar.java +++ b/Mage.Sets/src/mage/cards/m/MercadianBazaar.java @@ -34,7 +34,7 @@ public final class MercadianBazaar extends CardImpl { // {tap}, Remove any number of storage counters from Mercadian Bazaar: Add {R} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.RedMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {R} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/m/MercadianLift.java b/Mage.Sets/src/mage/cards/m/MercadianLift.java new file mode 100644 index 0000000000..486b01d41f --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MercadianLift.java @@ -0,0 +1,101 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.RemoveVariableCountersSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class MercadianLift extends CardImpl { + + public MercadianLift(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {1}, {tap}: Put a winch counter on Mercadian Lift. + Ability ability = new SimpleActivatedAbility(new AddCountersSourceEffect(CounterType.WINCH.createInstance()), new ManaCostsImpl("{1}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + + // {tap}, Remove X winch counters from Mercadian Lift: You may put a creature card with converted mana cost X from your hand onto the battlefield. + Ability ability2 = new SimpleActivatedAbility(new MercadianLiftEffect(), new TapSourceCost()); + ability2.addCost(new RemoveVariableCountersSourceCost(CounterType.WINCH.createInstance(1))); + this.addAbility(ability2); + + } + + private MercadianLift(final MercadianLift card) { + super(card); + } + + @Override + public MercadianLift copy() { + return new MercadianLift(this); + } +} + +class MercadianLiftEffect extends OneShotEffect { + + public MercadianLiftEffect() { + super(Outcome.PutCardInPlay); + staticText = "You may put a creature card with converted mana cost X from your hand onto the battlefield"; + } + + public MercadianLiftEffect(final MercadianLiftEffect effect) { + super(effect); + } + + @Override + public MercadianLiftEffect copy() { + return new MercadianLiftEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int numberOfCounters = 0; + for (Cost cost : source.getCosts()) { + if (cost instanceof RemoveVariableCountersSourceCost) { + numberOfCounters = ((RemoveVariableCountersSourceCost) cost).getAmount(); + } + } + System.out.println("The number is " + numberOfCounters); + FilterCreatureCard filter = new FilterCreatureCard(); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, numberOfCounters)); + filter.setMessage("creature card with converted mana cost " + numberOfCounters); + TargetCardInHand target = new TargetCardInHand(filter); + if (target.canChoose(controller.getId(), game) + && controller.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game) + && controller.choose(Outcome.PutCardInPlay, target, source.getSourceId(), game)) { + target.setRequired(false); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + return controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MercenaryInformer.java b/Mage.Sets/src/mage/cards/m/MercenaryInformer.java index 44cb9245b4..e50658d5fa 100644 --- a/Mage.Sets/src/mage/cards/m/MercenaryInformer.java +++ b/Mage.Sets/src/mage/cards/m/MercenaryInformer.java @@ -36,7 +36,7 @@ public final class MercenaryInformer extends CardImpl { static { filterBlack.add(new ColorPredicate(ObjectColor.BLACK)); - filterMercenary.add(Predicates.not(new TokenPredicate())); + filterMercenary.add(Predicates.not(TokenPredicate.instance)); filterMercenary.add(new SubtypePredicate(SubType.MERCENARY)); } diff --git a/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java b/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java index 2c59d904fc..e6f65a9075 100644 --- a/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java +++ b/Mage.Sets/src/mage/cards/m/MerchantsDockhand.java @@ -93,8 +93,7 @@ class MerchantsDockhandEffect extends OneShotEffect { } } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, xValue)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); controller.lookAtCards(sourceObject.getIdName(), cards, game); TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into your hand")); @@ -113,10 +112,10 @@ class MerchantsDockhandEffect extends OneShotEffect { class TapXTargetCost extends VariableCostImpl { - final static FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("untapped artifacts you control"); + static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("untapped artifacts you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public TapXTargetCost() { diff --git a/Mage.Sets/src/mage/cards/m/MercilessEviction.java b/Mage.Sets/src/mage/cards/m/MercilessEviction.java index e275be01bd..b71a9d1a17 100644 --- a/Mage.Sets/src/mage/cards/m/MercilessEviction.java +++ b/Mage.Sets/src/mage/cards/m/MercilessEviction.java @@ -25,15 +25,15 @@ public final class MercilessEviction extends CardImpl { this.getSpellAbility().addEffect(new ExileAllEffect(new FilterArtifactPermanent("artifacts"))); // or exile all creatures Mode mode = new Mode(); - mode.getEffects().add(new ExileAllEffect(FILTER_PERMANENT_CREATURES)); + mode.addEffect(new ExileAllEffect(FILTER_PERMANENT_CREATURES)); this.getSpellAbility().addMode(mode); // or exile all enchantments Mode mode2 = new Mode(); - mode2.getEffects().add(new ExileAllEffect(new FilterEnchantmentPermanent("enchantments"))); + mode2.addEffect(new ExileAllEffect(new FilterEnchantmentPermanent("enchantments"))); this.getSpellAbility().addMode(mode2); // or exile all planeswalkers. Mode mode3 = new Mode(); - mode3.getEffects().add(new ExileAllEffect(new FilterPlaneswalkerPermanent("planeswalkers"))); + mode3.addEffect(new ExileAllEffect(new FilterPlaneswalkerPermanent("planeswalkers"))); this.getSpellAbility().addMode(mode3); } diff --git a/Mage.Sets/src/mage/cards/m/MercurialChemister.java b/Mage.Sets/src/mage/cards/m/MercurialChemister.java index 9365da620d..b3390f455e 100644 --- a/Mage.Sets/src/mage/cards/m/MercurialChemister.java +++ b/Mage.Sets/src/mage/cards/m/MercurialChemister.java @@ -39,7 +39,7 @@ public final class MercurialChemister extends CardImpl { this.addAbility(ability); // {R}, {T}, Discard a card: Mercurial Chemister deals damage to target creature equal to the discarded card's converted mana cost. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new DiscardCostCardConvertedMana()), new ManaCostsImpl("{R}")); + ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(DiscardCostCardConvertedMana.instance), new ManaCostsImpl("{R}")); ability.addTarget(new TargetCreaturePermanent()); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardCardCost()); diff --git a/Mage.Sets/src/mage/cards/m/MercurialGeists.java b/Mage.Sets/src/mage/cards/m/MercurialGeists.java index 4842ee0827..f074914007 100644 --- a/Mage.Sets/src/mage/cards/m/MercurialGeists.java +++ b/Mage.Sets/src/mage/cards/m/MercurialGeists.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; @@ -9,18 +7,19 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MercurialGeists extends CardImpl { public MercurialGeists(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{R}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -29,7 +28,7 @@ public final class MercurialGeists extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Whenever you cast an instant or sorcery spell, Mercurial Geists gets +3/+0 until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(3, 0, Duration.EndOfTurn), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false)); } public MercurialGeists(final MercurialGeists card) { diff --git a/Mage.Sets/src/mage/cards/m/MerenOfClanNelToth.java b/Mage.Sets/src/mage/cards/m/MerenOfClanNelToth.java index b3862d6f0c..0e1dfd36cb 100644 --- a/Mage.Sets/src/mage/cards/m/MerenOfClanNelToth.java +++ b/Mage.Sets/src/mage/cards/m/MerenOfClanNelToth.java @@ -32,7 +32,7 @@ public final class MerenOfClanNelToth extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } @@ -97,7 +97,7 @@ class MerenOfClanNelTothEffect extends OneShotEffect { text = " put onto battlefield for "; } card.moveToZone(targetZone, source.getSourceId(), game, false); - game.informPlayers(new StringBuilder("Meren of Clan Nel Toth: ").append(card.getName()).append(text).append(player.getLogName()).toString()); + game.informPlayers("Meren of Clan Nel Toth: " + card.getName() + text + player.getLogName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MerfolkSkydiver.java b/Mage.Sets/src/mage/cards/m/MerfolkSkydiver.java new file mode 100644 index 0000000000..cd2952e5a4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MerfolkSkydiver.java @@ -0,0 +1,55 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.FlyingAbility; +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 MerfolkSkydiver extends CardImpl { + + public MerfolkSkydiver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{U}"); + + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Merfolk Skydiver enters the battlefield, put a +1/+1 counter on target creature you control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + + // {3}{G}{U}: Proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + this.addAbility(new SimpleActivatedAbility(new ProliferateEffect(), new ManaCostsImpl("{3}{G}{U}"))); + } + + private MerfolkSkydiver(final MerfolkSkydiver card) { + super(card); + } + + @Override + public MerfolkSkydiver copy() { + return new MerfolkSkydiver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MerrowBonegnawer.java b/Mage.Sets/src/mage/cards/m/MerrowBonegnawer.java index 0b533c9260..f274496308 100644 --- a/Mage.Sets/src/mage/cards/m/MerrowBonegnawer.java +++ b/Mage.Sets/src/mage/cards/m/MerrowBonegnawer.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -20,14 +19,13 @@ import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MerrowBonegnawer extends CardImpl { - private UUID exileId = UUID.randomUUID(); - private static final FilterSpell filter = new FilterSpell("a black spell"); static { @@ -43,7 +41,7 @@ public final class MerrowBonegnawer extends CardImpl { this.toughness = new MageInt(1); // {tap}: Target player exiles a card from their graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, exileId, getIdName(), new FilterCard()), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, null, getIdName(), new FilterCard()), new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/m/Merseine.java b/Mage.Sets/src/mage/cards/m/Merseine.java index 836365c850..cec4a052dc 100644 --- a/Mage.Sets/src/mage/cards/m/Merseine.java +++ b/Mage.Sets/src/mage/cards/m/Merseine.java @@ -77,11 +77,6 @@ class MerseineActivatedAbility extends SimpleActivatedAbility { super(ability); } - @Override - public Effects getEffects(Game game, EffectType effectType) { - return super.getEffects(game, effectType); - } - @Override public ActivationStatus canActivate(UUID playerId, Game game) { Permanent sourcePermanent = game.getBattlefield().getPermanent(this.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/m/MesmericFiend.java b/Mage.Sets/src/mage/cards/m/MesmericFiend.java index ee8645aa7e..7363102903 100644 --- a/Mage.Sets/src/mage/cards/m/MesmericFiend.java +++ b/Mage.Sets/src/mage/cards/m/MesmericFiend.java @@ -1,4 +1,3 @@ - package mage.cards.m; import java.util.UUID; @@ -11,15 +10,14 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.common.FilterNonlandCard; -import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetOpponent; @@ -32,7 +30,7 @@ import mage.util.CardUtil; public final class MesmericFiend extends CardImpl { public MesmericFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.NIGHTMARE); this.subtype.add(SubType.HORROR); @@ -79,22 +77,23 @@ class MesmericFiendExileEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(source.getFirstTarget()); Permanent sourcePermanent = (Permanent) source.getSourceObject(game); - if (controller != null && opponent != null && sourcePermanent != null) { + if (controller != null + && opponent != null + && sourcePermanent != null) { opponent.revealCards(sourcePermanent.getName(), opponent.getHand(), game); - TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard("nonland card to exile")); if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { Card card = opponent.getHand().get(target.getFirstTarget(), game); if (card != null) { - controller.moveCardToExileWithInfo(card, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true); + UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + game.getState().setValue(source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter(), exileId); + controller.moveCardsToExile(card, source, game, true, exileId, sourcePermanent.getName()); } } - return true; } return false; } - } class MesmericFiendLeaveEffect extends OneShotEffect { @@ -117,11 +116,15 @@ class MesmericFiendLeaveEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; - ExileZone exZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); - if (exZone != null) { - return controller.moveCards(exZone, Zone.HAND, source, game); + if (controller != null + && sourceObject != null) { + int zoneChangeMinusOne = source.getSourceObjectZoneChangeCounter() - 1; + UUID exileId = (UUID) game.getState().getValue(source.getSourceId().toString() + zoneChangeMinusOne); + if (exileId != null) { + Cards cards = game.getExile().getExileZone(exileId); + if (!cards.isEmpty()) { + return controller.moveCards(cards, Zone.HAND, source, game); + } } } return false; diff --git a/Mage.Sets/src/mage/cards/m/MesmerizingBenthid.java b/Mage.Sets/src/mage/cards/m/MesmerizingBenthid.java new file mode 100644 index 0000000000..330da20490 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MesmerizingBenthid.java @@ -0,0 +1,56 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.permanent.token.MesmerizingBenthidToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MesmerizingBenthid extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(SubType.ILLUSION); + + public MesmerizingBenthid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + + this.subtype.add(SubType.OCTOPUS); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Mesmerizing Benthid enters the battlefield, create two 0/2 blue Illusion creature tokens with "Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step." + this.addAbility(new EntersBattlefieldTriggeredAbility( + new CreateTokenEffect(new MesmerizingBenthidToken(), 2) + )); + + // Mesmerizing Benthid has hexproof as long as you control an Illusion. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(HexproofAbility.getInstance()), + new PermanentsOnTheBattlefieldCondition(filter), + "{this} has hexproof as long as you control an Illusion." + ))); + } + + private MesmerizingBenthid(final MesmerizingBenthid card) { + super(card); + } + + @Override + public MesmerizingBenthid copy() { + return new MesmerizingBenthid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MetalspinnersPuzzleknot.java b/Mage.Sets/src/mage/cards/m/MetalspinnersPuzzleknot.java index 38acc7c2cc..377521781d 100644 --- a/Mage.Sets/src/mage/cards/m/MetalspinnersPuzzleknot.java +++ b/Mage.Sets/src/mage/cards/m/MetalspinnersPuzzleknot.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -15,22 +13,21 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author emerald000 */ public final class MetalspinnersPuzzleknot extends CardImpl { public MetalspinnersPuzzleknot(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // When Metalspinner's Puzzleknot enters the battlefield, you draw a card and you lose 1 life. - Effect drawEffect = new DrawCardSourceControllerEffect(1); - drawEffect.setText("you draw a card"); + Effect drawEffect = new DrawCardSourceControllerEffect(1, "you"); Ability ability = new EntersBattlefieldTriggeredAbility(drawEffect); Effect lifeEffect = new LoseLifeSourceControllerEffect(1); - lifeEffect.setText("and you lose 1 life"); - ability.addEffect(lifeEffect); + ability.addEffect(lifeEffect.concatBy("and")); this.addAbility(ability); // {2}{B}, Sacrifice Metalspinner's Puzzleknot: You draw a card and you lose 1 life. diff --git a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java index 07c2c8a20a..ee046ca105 100644 --- a/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java +++ b/Mage.Sets/src/mage/cards/m/MetamorphicAlteration.java @@ -1,6 +1,5 @@ package mage.cards.m; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; @@ -19,8 +18,9 @@ import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author noahg */ public final class MetamorphicAlteration extends CardImpl { @@ -56,7 +56,7 @@ public final class MetamorphicAlteration extends CardImpl { class ChooseACreature extends OneShotEffect { - public static String INFO_KEY = "CHOSEN_CREATURE"; + public static final String INFO_KEY = "CHOSEN_CREATURE"; public ChooseACreature() { super(Outcome.Copy); @@ -74,7 +74,8 @@ class ChooseACreature extends OneShotEffect { if (sourceObject == null) { sourceObject = game.getObject(source.getSourceId()); } - if (controller != null && sourceObject != null) { + if (controller != null + && sourceObject != null) { Target target = new TargetCreaturePermanent(); target.setNotTarget(true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { @@ -108,12 +109,13 @@ class MetamorphicAlterationEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - //TODO this is stupid and there's got to be a better way, but it works and people probably want to practice full M19 before Prerelease. Permanent enchantment = game.getPermanent(source.getSourceId()); Permanent copied = (Permanent) game.getState().getValue(source.getSourceId().toString() + ChooseACreature.INFO_KEY); - if (enchantment != null && copied != null) { + if (enchantment != null + && copied != null) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); - if (permanent != null && layer == Layer.CopyEffects_1) { + if (permanent != null + && layer == Layer.CopyEffects_1) { permanent.setName(copied.getName()); permanent.getManaCost().clear(); permanent.getManaCost().addAll(copied.getManaCost()); @@ -123,20 +125,20 @@ class MetamorphicAlterationEffect extends ContinuousEffectImpl { permanent.addSuperType(t); } permanent.getCardType().clear(); - for (CardType t : copied.getCardType()) { - permanent.addCardType(t); + for (CardType cardType : copied.getCardType()) { + permanent.addCardType(cardType); } - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); - for (SubType t : copied.getSubtype(game)) { - permanent.getSubtype(game).add(t); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); + for (SubType subType : copied.getSubtype(game)) { + permanent.getSubtype(game).add(subType); } permanent.getColor(game).setColor(copied.getColor(game)); permanent.removeAllAbilities(source.getSourceId(), game); for (Ability ability : copied.getAbilities()) { permanent.addAbility(ability, source.getSourceId(), game); } - permanent.getPower().setValue(copied.getPower().getValue()); - permanent.getToughness().setValue(copied.getToughness().getValue()); + permanent.getPower().setValue(copied.getPower().getBaseValue()); + permanent.getToughness().setValue(copied.getToughness().getBaseValue()); return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MetathranElite.java b/Mage.Sets/src/mage/cards/m/MetathranElite.java new file mode 100644 index 0000000000..cfeed06ccf --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MetathranElite.java @@ -0,0 +1,47 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.EnchantedSourceCondition; +import mage.abilities.decorator.ConditionalRestrictionEffect; +import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * + * @author jeffwadsworth + */ +public final class MetathranElite extends CardImpl { + + private static final String rule = "{this} is unblockable as long as it's enchanted."; + + public MetathranElite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{U}"); + + this.subtype.add(SubType.METATHRAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Metathran Elite is unblockable as long as it's enchanted. + ConditionalRestrictionEffect effect = new ConditionalRestrictionEffect( + new CantBeBlockedSourceEffect(), new EnchantedSourceCondition()); + effect.setText(rule); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + + } + + public MetathranElite(final MetathranElite card) { + super(card); + } + + @Override + public MetathranElite copy() { + return new MetathranElite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MeteorBlast.java b/Mage.Sets/src/mage/cards/m/MeteorBlast.java index fb57f84cce..c4d2ae4233 100644 --- a/Mage.Sets/src/mage/cards/m/MeteorBlast.java +++ b/Mage.Sets/src/mage/cards/m/MeteorBlast.java @@ -1,86 +1,49 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.Target; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MeteorBlast extends CardImpl { public MeteorBlast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}{R}{R}"); // Meteor Blast deals 4 damage to each of X target creatures and/or players. - this.getSpellAbility().addEffect(new MeteorBlastEffect()); + this.getSpellAbility().addEffect( + new DamageTargetEffect(4).setText("{this} deals 4 damage to each of X targets") + ); + this.getSpellAbility().setTargetAdjuster(MeteorBlastAdjuster.instance); } - public MeteorBlast(final MeteorBlast card) { + private MeteorBlast(final MeteorBlast card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - int xValue = ability.getManaCostsToPay().getX(); - if (xValue > 0) { - Target target = new TargetAnyTarget(xValue); - ability.addTarget(target); - } - } - @Override public MeteorBlast copy() { return new MeteorBlast(this); } } -class MeteorBlastEffect extends OneShotEffect { - - public MeteorBlastEffect() { - super(Outcome.Damage); - staticText = "{this} deals 4 damage to each of X target creatures and/or players"; - } - - public MeteorBlastEffect(final MeteorBlastEffect effect) { - super(effect); - } +enum MeteorBlastAdjuster implements TargetAdjuster { + instance; @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (!source.getTargets().isEmpty()) { - for (UUID targetId : this.getTargetPointer().getTargets(game, source)) { - Permanent creature = game.getPermanent(targetId); - if (creature != null) { - creature.damage(4, source.getSourceId(), game, false, true); - } else { - Player player = game.getPlayer(targetId); - if (player != null) { - player.damage(4, source.getSourceId(), game, false, true); - } - } - } - } - return true; + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + if (xValue > 0) { + ability.addTarget(new TargetAnyTarget(xValue)); } - return false; - } - - @Override - public MeteorBlastEffect copy() { - return new MeteorBlastEffect(this); } } diff --git a/Mage.Sets/src/mage/cards/m/MeteorShower.java b/Mage.Sets/src/mage/cards/m/MeteorShower.java index 9c8031c50d..2fa2390c04 100644 --- a/Mage.Sets/src/mage/cards/m/MeteorShower.java +++ b/Mage.Sets/src/mage/cards/m/MeteorShower.java @@ -21,7 +21,7 @@ public final class MeteorShower extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{R}"); // Meteor Shower deals X plus 1 damage divided as you choose among any number of target creatures and/or players. - DynamicValue xValue = new IntPlusDynamicValue(1, new ManacostVariableValue()); + DynamicValue xValue = new IntPlusDynamicValue(1, ManacostVariableValue.instance); this.getSpellAbility().addEffect(new DamageMultiEffect(xValue)); this.getSpellAbility().addTarget(new TargetAnyTargetAmount(xValue)); } diff --git a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java index 0b77db9540..5288f95128 100644 --- a/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java +++ b/Mage.Sets/src/mage/cards/m/MetzaliTowerOfTriumph.java @@ -90,7 +90,7 @@ class MetzaliTowerOfTriumphEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + Watcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher instanceof AttackedThisTurnWatcher) { Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); List available = new ArrayList<>(); diff --git a/Mage.Sets/src/mage/cards/m/MidnightCharm.java b/Mage.Sets/src/mage/cards/m/MidnightCharm.java index f704b0be08..cecfceb71f 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightCharm.java +++ b/Mage.Sets/src/mage/cards/m/MidnightCharm.java @@ -28,12 +28,12 @@ public final class MidnightCharm extends CardImpl { this.getSpellAbility().addEffect(new GainLifeEffect(1).setText("and you gain 1 life")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); Mode mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); mode = new Mode(); - mode.getEffects().add(new TapTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new TapTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MidnightEntourage.java b/Mage.Sets/src/mage/cards/m/MidnightEntourage.java index 9c0843b6d7..4fdd87ec21 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightEntourage.java +++ b/Mage.Sets/src/mage/cards/m/MidnightEntourage.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.DiesThisOrAnotherCreatureTriggeredAbility; @@ -17,8 +15,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author Styxo */ public final class MidnightEntourage extends CardImpl { @@ -42,10 +41,9 @@ public final class MidnightEntourage extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, true))); // Whenever Midnight Entourage or another Aetherborn you control dies, you draw a card and you lose 1 life. - Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new DrawCardSourceControllerEffect(1), false, filter); + Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new DrawCardSourceControllerEffect(1, "you"), false, filter); Effect effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability.addEffect(effect); + ability.addEffect(effect.concatBy("and")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MidnightGuard.java b/Mage.Sets/src/mage/cards/m/MidnightGuard.java index b0c76111bc..3019134b08 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightGuard.java +++ b/Mage.Sets/src/mage/cards/m/MidnightGuard.java @@ -21,7 +21,7 @@ public final class MidnightGuard extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MidnightGuard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MidnightReaper.java b/Mage.Sets/src/mage/cards/m/MidnightReaper.java index 5af4535203..cfe9c74eb9 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightReaper.java +++ b/Mage.Sets/src/mage/cards/m/MidnightReaper.java @@ -27,7 +27,7 @@ public final class MidnightReaper extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public MidnightReaper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MidnightRitual.java b/Mage.Sets/src/mage/cards/m/MidnightRitual.java index 23205ab254..08ccd0518a 100644 --- a/Mage.Sets/src/mage/cards/m/MidnightRitual.java +++ b/Mage.Sets/src/mage/cards/m/MidnightRitual.java @@ -1,9 +1,7 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,9 +15,11 @@ import mage.game.Game; import mage.game.permanent.token.ZombieToken; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Skyler Sell */ public final class MidnightRitual extends CardImpl { @@ -31,14 +31,7 @@ public final class MidnightRitual extends CardImpl { // For each creature card exiled this way, create a 2/2 black Zombie creature token. this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().addEffect(new MidnightRitualEffect()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); - } + this.getSpellAbility().setTargetAdjuster(MidnightRitualAdjuster.instance); } public MidnightRitual(final MidnightRitual card) { @@ -51,6 +44,16 @@ public final class MidnightRitual extends CardImpl { } } +enum MidnightRitualAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + } +} + class MidnightRitualEffect extends OneShotEffect { public MidnightRitualEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MightBeyondReason.java b/Mage.Sets/src/mage/cards/m/MightBeyondReason.java index a074981fd7..dc6a309053 100644 --- a/Mage.Sets/src/mage/cards/m/MightBeyondReason.java +++ b/Mage.Sets/src/mage/cards/m/MightBeyondReason.java @@ -1,10 +1,11 @@ - package mage.cards.m; import java.util.UUID; + import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -12,13 +13,12 @@ import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; /** - * * @author LevelX2 */ public final class MightBeyondReason extends CardImpl { public MightBeyondReason(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); // Put two +1/+1 counter on target creature. // Delirium — Put three +1/+1 counter on that creature instead if there are four or more card types among cards in your graveyard. @@ -27,9 +27,10 @@ public final class MightBeyondReason extends CardImpl { new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)), DeliriumCondition.instance, "Put two +1/+1 counter on target creature.
    " - + "Delirium — Put three +1/+1 counter on that creature instead if there are four or more card types among cards in your graveyard" + + "Delirium — Put three +1/+1 counter on that creature instead if there are four or more card types among cards in your graveyard" )); getSpellAbility().addTarget(new TargetCreaturePermanent()); + getSpellAbility().addHint(DeliriumHint.instance); } public MightBeyondReason(final MightBeyondReason card) { diff --git a/Mage.Sets/src/mage/cards/m/MightOfOldKrosa.java b/Mage.Sets/src/mage/cards/m/MightOfOldKrosa.java index fb603636a0..ac0fe3ed0f 100644 --- a/Mage.Sets/src/mage/cards/m/MightOfOldKrosa.java +++ b/Mage.Sets/src/mage/cards/m/MightOfOldKrosa.java @@ -3,7 +3,7 @@ package mage.cards.m; import java.util.UUID; import mage.abilities.condition.LockedInCondition; -import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.condition.common.AddendumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; @@ -25,7 +25,7 @@ public final class MightOfOldKrosa extends CardImpl { this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new BoostTargetEffect(4,4, Duration.EndOfTurn), new BoostTargetEffect(2, 2, Duration.EndOfTurn), - new LockedInCondition(MyMainPhaseCondition.instance), + new LockedInCondition(AddendumCondition.instance), "Target creature gets +2/+2 until end of turn. If you cast this spell during your main phase, that creature gets +4/+4 until end of turn instead")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/m/MightOfTheMasses.java b/Mage.Sets/src/mage/cards/m/MightOfTheMasses.java index cfce861ea9..4a2fb1a42f 100644 --- a/Mage.Sets/src/mage/cards/m/MightOfTheMasses.java +++ b/Mage.Sets/src/mage/cards/m/MightOfTheMasses.java @@ -1,27 +1,26 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class MightOfTheMasses extends CardImpl { public MightOfTheMasses(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); - - PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); + // Target creature gets +1/+1 until end of turn for each creature you control. + PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addEffect(new BoostTargetEffect(value, value, Duration.EndOfTurn, true)); } diff --git a/Mage.Sets/src/mage/cards/m/MightOfTheWild.java b/Mage.Sets/src/mage/cards/m/MightOfTheWild.java index c9ce6c95e5..c7d78e1397 100644 --- a/Mage.Sets/src/mage/cards/m/MightOfTheWild.java +++ b/Mage.Sets/src/mage/cards/m/MightOfTheWild.java @@ -42,13 +42,13 @@ public final class MightOfTheWild extends CardImpl { // Destroy target artifact or enchantment. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filterMode2)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filterMode2)); this.getSpellAbility().addMode(mode); // Creatures you control gain indestructible this turn. mode = new Mode(); - mode.getEffects().add(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"))); + mode.addEffect(new GainAbilityControlledEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"))); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/Mightstone.java b/Mage.Sets/src/mage/cards/m/Mightstone.java index f7922170fd..bb36bf9e8d 100644 --- a/Mage.Sets/src/mage/cards/m/Mightstone.java +++ b/Mage.Sets/src/mage/cards/m/Mightstone.java @@ -21,7 +21,7 @@ public final class Mightstone extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creatures"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Mightstone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MijaeDjinn.java b/Mage.Sets/src/mage/cards/m/MijaeDjinn.java index 7407d86d66..6ec0f9b8d1 100644 --- a/Mage.Sets/src/mage/cards/m/MijaeDjinn.java +++ b/Mage.Sets/src/mage/cards/m/MijaeDjinn.java @@ -57,7 +57,7 @@ class MijaeDjinnEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent creature = game.getPermanent(source.getSourceId()); if (controller != null && creature != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { return true; } else { creature.removeFromCombat(game); diff --git a/Mage.Sets/src/mage/cards/m/MikaeusTheLunarch.java b/Mage.Sets/src/mage/cards/m/MikaeusTheLunarch.java index 5e0a0a0497..7f72fa46f4 100644 --- a/Mage.Sets/src/mage/cards/m/MikaeusTheLunarch.java +++ b/Mage.Sets/src/mage/cards/m/MikaeusTheLunarch.java @@ -30,7 +30,7 @@ public final class MikaeusTheLunarch extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MikaeusTheLunarch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MilitantAngel.java b/Mage.Sets/src/mage/cards/m/MilitantAngel.java new file mode 100644 index 0000000000..c1ff666a0d --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MilitantAngel.java @@ -0,0 +1,49 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.AttackedThisTurnOpponentsCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.KnightToken; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class MilitantAngel extends CardImpl { + + public MilitantAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}"); + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // When Militant Angel enters the battlefield, create a number of 2/2 white Knight creature tokens with vigilance equal to the number of opponents you attacked this turn. + Effect effect = new CreateTokenEffect(new KnightToken(), AttackedThisTurnOpponentsCount.instance); + effect.setText("create a number of 2/2 white Knight creature tokens with vigilance equal to the number of opponents you attacked this turn"); + this.addAbility(new EntersBattlefieldTriggeredAbility(effect)); + } + + public MilitantAngel(final MilitantAngel card) { + super(card); + } + + @Override + public MilitantAngel copy() { + return new MilitantAngel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MilitiasPride.java b/Mage.Sets/src/mage/cards/m/MilitiasPride.java index 1f23407eb2..5d413d911c 100644 --- a/Mage.Sets/src/mage/cards/m/MilitiasPride.java +++ b/Mage.Sets/src/mage/cards/m/MilitiasPride.java @@ -63,8 +63,8 @@ class MilitiasPrideTriggerAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(Predicates.not(new TokenPredicate())); - Permanent permanent = (Permanent) game.getPermanent(event.getSourceId()); + filter.add(Predicates.not(TokenPredicate.instance)); + Permanent permanent = game.getPermanent(event.getSourceId()); return permanent != null && filter.match(permanent, sourceId, controllerId, game); } diff --git a/Mage.Sets/src/mage/cards/m/Mimeofacture.java b/Mage.Sets/src/mage/cards/m/Mimeofacture.java index 8f4237b38c..e83670c3a9 100644 --- a/Mage.Sets/src/mage/cards/m/Mimeofacture.java +++ b/Mage.Sets/src/mage/cards/m/Mimeofacture.java @@ -79,7 +79,7 @@ class MimeofactureEffect extends OneShotEffect { FilterCard filter = new FilterCard("card named " + permanent.getName()); filter.add(new NamePredicate(permanent.getName())); TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (controller.searchLibrary(target, game, opponent.getId())) { + if (controller.searchLibrary(target, source, game, opponent.getId())) { Card card = opponent.getLibrary().getCard(target.getFirstTarget(), game); controller.moveCards(card, Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/m/MindBomb.java b/Mage.Sets/src/mage/cards/m/MindBomb.java index 56a35ad408..26b0855283 100644 --- a/Mage.Sets/src/mage/cards/m/MindBomb.java +++ b/Mage.Sets/src/mage/cards/m/MindBomb.java @@ -1,17 +1,10 @@ package mage.cards.m; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.filter.FilterCard; @@ -20,8 +13,11 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetDiscard; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class MindBomb extends CardImpl { @@ -67,6 +63,7 @@ class MindBombEffect extends OneShotEffect { if (controller != null && sourceObject != null) { Map cardsToDiscard = new HashMap<>(); + // choose for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { @@ -77,6 +74,8 @@ class MindBombEffect extends OneShotEffect { cardsToDiscard.put(playerId, cards); } } + + // discard for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { @@ -91,31 +90,17 @@ class MindBombEffect extends OneShotEffect { } } } + + // damage for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { Cards cardsPlayer = cardsToDiscard.get(playerId); - if (cardsPlayer != null && !cardsPlayer.isEmpty()) { + if (cardsPlayer != null) { player.damage(3 - cardsPlayer.size(), source.getId(), game, false, true); } } } - // reveal the searched lands, put in hands, and shuffle -// for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { -// Player player = game.getPlayer(playerId); -// if (player != null) { -// Cards cardsPlayer = cardsToReveal.get(playerId); -// if (cardsPlayer != null) { -// for (UUID cardId : cardsPlayer) { -// Cards cards = new CardsImpl(game.getCard(cardId)); -// Card card = game.getCard(cardId); -// player.revealCards(sourceObject.getIdName() + " (" + player.getName() + ')', cards, game); -// player.moveCards(card, Zone.HAND, source, game); -// player.shuffleLibrary(source, game); -// } -// } -// } -// } return true; } return false; diff --git a/Mage.Sets/src/mage/cards/m/MindMaggots.java b/Mage.Sets/src/mage/cards/m/MindMaggots.java new file mode 100644 index 0000000000..a53f2ceb1e --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MindMaggots.java @@ -0,0 +1,88 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.Card; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.common.FilterCreatureCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class MindMaggots extends CardImpl { + + public MindMaggots(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // When Mind Maggots enters the battlefield, discard any number of creature cards. + // For each card discarded this way, put two +1/+1 counters on Mind Maggots. + this.addAbility(new EntersBattlefieldTriggeredAbility(new MindMaggotsEffect())); + + } + + public MindMaggots(final MindMaggots card) { + super(card); + } + + @Override + public MindMaggots copy() { + return new MindMaggots(this); + } +} + +class MindMaggotsEffect extends OneShotEffect { + + MindMaggotsEffect() { + super(Outcome.BoostCreature); + this.staticText = "discard any number of creature cards. For each card discarded this way, put two +1/+1 counters on {this}"; + } + + MindMaggotsEffect(final MindMaggotsEffect effect) { + super(effect); + } + + @Override + public MindMaggotsEffect copy() { + return new MindMaggotsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int numToDiscard = controller.getAmount(0, + controller.getHand().getCards(new FilterCreatureCard(), game).size(), + "Discard how many creature cards?", + game); + TargetCardInHand target = new TargetCardInHand(numToDiscard, new FilterCreatureCard()); + if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + for (UUID targetId : target.getTargets()) { + Card card = game.getCard(targetId); + if (card != null + && controller.discard(card, source, game)) { + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)).apply(game, source); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MindShatter.java b/Mage.Sets/src/mage/cards/m/MindShatter.java index 244b241f93..8e048a27ab 100644 --- a/Mage.Sets/src/mage/cards/m/MindShatter.java +++ b/Mage.Sets/src/mage/cards/m/MindShatter.java @@ -19,7 +19,7 @@ public final class MindShatter extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}{B}"); // Target player discards X cards at random. - this.getSpellAbility().addEffect(new DiscardTargetEffect(new ManacostVariableValue(), true)); + this.getSpellAbility().addEffect(new DiscardTargetEffect(ManacostVariableValue.instance, true)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/m/MindSpring.java b/Mage.Sets/src/mage/cards/m/MindSpring.java index f327dde9c9..58b5994632 100644 --- a/Mage.Sets/src/mage/cards/m/MindSpring.java +++ b/Mage.Sets/src/mage/cards/m/MindSpring.java @@ -18,7 +18,7 @@ public final class MindSpring extends CardImpl { public MindSpring(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}"); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.instance)); } public MindSpring(final MindSpring card) { diff --git a/Mage.Sets/src/mage/cards/m/MindTwist.java b/Mage.Sets/src/mage/cards/m/MindTwist.java index 1b1b377ffc..bddc25745a 100644 --- a/Mage.Sets/src/mage/cards/m/MindTwist.java +++ b/Mage.Sets/src/mage/cards/m/MindTwist.java @@ -20,7 +20,7 @@ public final class MindTwist extends CardImpl { // Target player discards X cards at random. - this.getSpellAbility().addEffect(new DiscardTargetEffect(new ManacostVariableValue(), true)); + this.getSpellAbility().addEffect(new DiscardTargetEffect(ManacostVariableValue.instance, true)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/m/MindWarp.java b/Mage.Sets/src/mage/cards/m/MindWarp.java index c82cf55fb6..3db8935245 100644 --- a/Mage.Sets/src/mage/cards/m/MindWarp.java +++ b/Mage.Sets/src/mage/cards/m/MindWarp.java @@ -28,7 +28,7 @@ public final class MindWarp extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{3}{B}"); // Look at target player's hand and choose X cards from it. That player discards those cards. - this.getSpellAbility().addEffect(new MindWarpEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new MindWarpEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/m/MindWhip.java b/Mage.Sets/src/mage/cards/m/MindWhip.java new file mode 100644 index 0000000000..499372e0b1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MindWhip.java @@ -0,0 +1,99 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class MindWhip extends CardImpl { + + public MindWhip(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of the upkeep of enchanted creature's controller, that player may pay {3}. If he or she doesn't, Mind Whip deals 2 damage to that player and you tap that creature. + Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new MindWhipEffect(), + new ManaCostsImpl("{3}"), + ""); + effect.setText("that player may pay {3}. If he or she doesn't, {this} deals 2 damage to that player and you tap that creature."); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + effect, + TargetController.CONTROLLER_ATTACHED_TO, false)); + + } + + private MindWhip(final MindWhip card) { + super(card); + } + + @Override + public MindWhip copy() { + return new MindWhip(this); + } +} + +class MindWhipEffect extends OneShotEffect { + + public MindWhipEffect() { + super(Outcome.Neutral); + staticText = ""; + } + + public MindWhipEffect(final MindWhipEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controllerOfEnchantedCreature = game.getPlayer(targetPointer.getFirst(game, source)); + Permanent mindWhip = game.getPermanent(source.getSourceId()); + if (controllerOfEnchantedCreature != null + && mindWhip != null) { + Permanent enchantedCreature = game.getPermanent(mindWhip.getAttachedTo()); + if (enchantedCreature != null) { + Effect effect = new DamageTargetEffect(2); + effect.setTargetPointer(new FixedTarget(controllerOfEnchantedCreature.getId())); + effect.apply(game, source); + enchantedCreature.tap(game); + return true; + } + } + return false; + } + + @Override + public MindWhipEffect copy() { + return new MindWhipEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/m/MindbreakTrap.java b/Mage.Sets/src/mage/cards/m/MindbreakTrap.java index 253fc6ef50..9fc7ea6c50 100644 --- a/Mage.Sets/src/mage/cards/m/MindbreakTrap.java +++ b/Mage.Sets/src/mage/cards/m/MindbreakTrap.java @@ -52,7 +52,7 @@ enum MindbreakTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(opponentId) > 2) { diff --git a/Mage.Sets/src/mage/cards/m/MindsAglow.java b/Mage.Sets/src/mage/cards/m/MindsAglow.java index 2e1bdf7cfe..700a7a4c32 100644 --- a/Mage.Sets/src/mage/cards/m/MindsAglow.java +++ b/Mage.Sets/src/mage/cards/m/MindsAglow.java @@ -100,7 +100,7 @@ class MindsAglowEffect extends OneShotEffect { payed = true; } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}."); return xValue; } } diff --git a/Mage.Sets/src/mage/cards/m/MindsDesire.java b/Mage.Sets/src/mage/cards/m/MindsDesire.java index 49f6b5ac8d..b270cd023c 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDesire.java +++ b/Mage.Sets/src/mage/cards/m/MindsDesire.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -19,8 +17,9 @@ import mage.players.Player; import mage.target.targetpointer.FixedTargets; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author emerald000 */ public final class MindsDesire extends CardImpl { @@ -68,11 +67,14 @@ class MindsDesireEffect extends OneShotEffect { controller.shuffleLibrary(source, game); Card card = controller.getLibrary().getFromTop(game); if (card != null) { - UUID exileId = UUID.randomUUID(); - controller.moveCardsToExile(card, source, game, true, exileId, CardUtil.createObjectRealtedWindowTitle(source, game, null)); - ContinuousEffect effect = new MindsDesireCastFromExileEffect(); - effect.setTargetPointer(new FixedTargets(game.getExile().getExileZone(exileId).getCards(game), game)); - game.addEffect(effect, source); + UUID exileId = CardUtil.getExileZoneId(controller.getId().toString() + "-" + game.getState().getTurnNum() + "-" + MindsDesire.class.toString(), game); + String exileName = "Mind's Desire free cast on " + game.getState().getTurnNum() + " turn for " + controller.getName(); + game.getExile().createZone(exileId, exileName).setCleanupOnEndTurn(true); + if (controller.moveCardsToExile(card, source, game, true, exileId, exileName)) { + ContinuousEffect effect = new MindsDesireCastFromExileEffect(); + effect.setTargetPointer(new FixedTargets(game.getExile().getExileZone(exileId).getCards(game), game)); + game.addEffect(effect, source); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MindsDilation.java b/Mage.Sets/src/mage/cards/m/MindsDilation.java index 941ef597ac..b3a7c6381f 100644 --- a/Mage.Sets/src/mage/cards/m/MindsDilation.java +++ b/Mage.Sets/src/mage/cards/m/MindsDilation.java @@ -65,7 +65,7 @@ class MindsDilationTriggeredAbility extends SpellCastOpponentTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(event.getPlayerId()); if (spells != null && spells.size() == 1) { diff --git a/Mage.Sets/src/mage/cards/m/MindstormCrown.java b/Mage.Sets/src/mage/cards/m/MindstormCrown.java index c186f02a15..61b16ec257 100644 --- a/Mage.Sets/src/mage/cards/m/MindstormCrown.java +++ b/Mage.Sets/src/mage/cards/m/MindstormCrown.java @@ -1,4 +1,3 @@ - package mage.cards.m; import java.util.UUID; @@ -44,7 +43,7 @@ class MindstormCrownEffect extends OneShotEffect { MindstormCrownEffect() { super(Outcome.Benefit); - this.staticText = ""; + this.staticText = "draw a card if you had no cards in hand at the beginning of this turn. If you had a card in hand, {this} deals 1 damage to you"; } MindstormCrownEffect(final MindstormCrownEffect effect) { @@ -58,17 +57,18 @@ class MindstormCrownEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (player == null) { + if (controller == null) { return false; } - MindstormCrownWatcher watcher = (MindstormCrownWatcher) game.getState().getWatchers().get(MindstormCrownWatcher.class.getSimpleName()); - if (watcher != null && watcher.getCardsInHandCount() == 0) { - player.drawCards(1, game); + MindstormCrownWatcher watcher = game.getState().getWatcher(MindstormCrownWatcher.class); + if (watcher != null + && watcher.getCardsInHandCount() == 0) { + controller.drawCards(1, game); } else { if (permanent != null) { - player.damage(2, permanent.getId(), game, false, true); + controller.damage(1, permanent.getId(), game, false, true); } } return true; @@ -80,7 +80,7 @@ class MindstormCrownWatcher extends Watcher { private int cardsInHandCount; public MindstormCrownWatcher() { - super(MindstormCrownWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MindstormCrownWatcher(final MindstormCrownWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/m/Mindswipe.java b/Mage.Sets/src/mage/cards/m/Mindswipe.java index fbfa217fd3..1650b14967 100644 --- a/Mage.Sets/src/mage/cards/m/Mindswipe.java +++ b/Mage.Sets/src/mage/cards/m/Mindswipe.java @@ -29,7 +29,7 @@ public final class Mindswipe extends CardImpl { // Counter target spell unless its controller pays {X}. Mindswipe deals X damage to that spell's controller. - Effect effect = new CounterUnlessPaysEffect(new ManacostVariableValue()); + Effect effect = new CounterUnlessPaysEffect(ManacostVariableValue.instance); effect.setText("Counter target spell unless its controller pays {X}."); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetSpell()); @@ -74,7 +74,7 @@ class MindswipeEffect extends OneShotEffect { Spell spell = (Spell) object; Player spellController = game.getPlayer(spell.getControllerId()); if (spellController != null) { - int damage = new ManacostVariableValue().calculate(game, source, this); + int damage = ManacostVariableValue.instance.calculate(game, source, this); spellController.damage(damage, source.getSourceId(), game, false, true); } return true; diff --git a/Mage.Sets/src/mage/cards/m/MindwrackDemon.java b/Mage.Sets/src/mage/cards/m/MindwrackDemon.java index 1bcd1ff238..1eb9c35992 100644 --- a/Mage.Sets/src/mage/cards/m/MindwrackDemon.java +++ b/Mage.Sets/src/mage/cards/m/MindwrackDemon.java @@ -1,7 +1,7 @@ - package mage.cards.m; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -11,6 +11,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; import mage.abilities.effects.common.PutTopCardOfLibraryIntoGraveControllerEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -20,13 +21,12 @@ import mage.constants.SubType; import mage.constants.TargetController; /** - * * @author fireshoes */ public final class MindwrackDemon extends CardImpl { public MindwrackDemon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.DEMON); this.power = new MageInt(4); this.toughness = new MageInt(5); @@ -45,6 +45,7 @@ public final class MindwrackDemon extends CardImpl { new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(4), TargetController.YOU, false), new InvertCondition(DeliriumCondition.instance), "Delirium — At the beginning of your upkeep, you lose 4 life unless there are four or more card types among cards in your graveyard."); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MineMineMine.java b/Mage.Sets/src/mage/cards/m/MineMineMine.java index b5c54f0dad..4d227ec47f 100644 --- a/Mage.Sets/src/mage/cards/m/MineMineMine.java +++ b/Mage.Sets/src/mage/cards/m/MineMineMine.java @@ -33,7 +33,7 @@ public final class MineMineMine extends CardImpl { public MineMineMine(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{G}{G}"); - // When Mine, Mine, Mine enters the battlefield, each player puts his or her library into his or her hand. + // When Mine, Mine, Mine enters the battlefield, each player puts their library into their hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new MineMineMineDrawEffect())); // Players have no maximum hand size and don't lose the game for drawing from an empty library. @@ -45,7 +45,7 @@ public final class MineMineMine extends CardImpl { // Each player can't cast more than one spell each turn. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantCastMoreThanOneSpellEffect(TargetController.ANY))); - // When Mine, Mine, Mine leaves the battlefield, each player shuffles his or her hand and graveyard into his or her library. + // When Mine, Mine, Mine leaves the battlefield, each player shuffles their hand and graveyard into their library. this.addAbility(new LeavesBattlefieldTriggeredAbility(new ShuffleHandGraveyardAllEffect(), false)); } diff --git a/Mage.Sets/src/mage/cards/m/MinionOfLeshrac.java b/Mage.Sets/src/mage/cards/m/MinionOfLeshrac.java index a8dabd9b20..154468baf3 100644 --- a/Mage.Sets/src/mage/cards/m/MinionOfLeshrac.java +++ b/Mage.Sets/src/mage/cards/m/MinionOfLeshrac.java @@ -92,7 +92,7 @@ class MinionLeshracEffect extends OneShotEffect { && minionLeshrac != null) { FilterControlledPermanent filterCreature = new FilterControlledPermanent(); filterCreature.add(new CardTypePredicate(CardType.CREATURE)); - filterCreature.add(new AnotherPredicate()); + filterCreature.add(AnotherPredicate.instance); TargetControlledPermanent target = new TargetControlledPermanent(filterCreature); SacrificeTargetCost cost = new SacrificeTargetCost(target); if (controller.chooseUse(Outcome.AIDontUseIt, "Do you wish to sacrifice another creature to prevent the 5 damage to you?", source, game) diff --git a/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java b/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java index 71c4df4713..bf506fabc6 100644 --- a/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java +++ b/Mage.Sets/src/mage/cards/m/MinionOfTheWastes.java @@ -1,11 +1,11 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; @@ -13,17 +13,15 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class MinionOfTheWastes extends CardImpl { @@ -39,12 +37,12 @@ public final class MinionOfTheWastes extends CardImpl { // As Minion of the Wastes enters the battlefield, pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards. this.addAbility(new AsEntersBattlefieldAbility(new MinionOfTheWastesEffect())); - + // Minion of the Wastes's power and toughness are each equal to the life paid as it entered the battlefield. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this}'s power and toughness are each equal to the life paid as it entered the battlefield"))); } - public MinionOfTheWastes(final MinionOfTheWastes card) { + private MinionOfTheWastes(final MinionOfTheWastes card) { super(card); } @@ -56,12 +54,12 @@ public final class MinionOfTheWastes extends CardImpl { class MinionOfTheWastesEffect extends OneShotEffect { - public MinionOfTheWastesEffect() { + MinionOfTheWastesEffect() { super(Outcome.LoseLife); staticText = "pay any amount of life"; } - public MinionOfTheWastesEffect(final MinionOfTheWastesEffect effect) { + private MinionOfTheWastesEffect(final MinionOfTheWastesEffect effect) { super(effect); } @@ -73,15 +71,22 @@ class MinionOfTheWastesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card sourceCard = game.getCard(source.getSourceId()); - int payAmount = controller.getAmount(0, controller.getLife(), "Pay any amount of life", game); - controller.loseLife(payAmount, game, false); - game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName()) - .append(" pays ").append(payAmount).append(" life").toString()); - game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source); - return true; + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (controller == null || permanent == null) { + return false; } - return false; + int payAmount = controller.getAmount(0, controller.getLife(), "Pay any amount of life", game); + Cost cost = new PayLifeCost(payAmount); + if (!cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + return false; + } + Card sourceCard = game.getCard(source.getSourceId()); + game.informPlayers((sourceCard != null ? sourceCard.getLogName() : "") + ": " + controller.getLogName() + + " pays " + payAmount + " life"); + game.addEffect(new SetPowerToughnessSourceEffect( + payAmount, payAmount, Duration.Custom, SubLayer.CharacteristicDefining_7a + ), source); + permanent.addInfo("life paid", CardUtil.addToolTipMarkTags("Life paid: " + payAmount), game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/m/MinionReflector.java b/Mage.Sets/src/mage/cards/m/MinionReflector.java index a422664308..31da2e2881 100644 --- a/Mage.Sets/src/mage/cards/m/MinionReflector.java +++ b/Mage.Sets/src/mage/cards/m/MinionReflector.java @@ -35,7 +35,7 @@ public final class MinionReflector extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public MinionReflector(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MinionsMurmurs.java b/Mage.Sets/src/mage/cards/m/MinionsMurmurs.java index f94253c5d9..94fb18394a 100644 --- a/Mage.Sets/src/mage/cards/m/MinionsMurmurs.java +++ b/Mage.Sets/src/mage/cards/m/MinionsMurmurs.java @@ -1,9 +1,8 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -12,8 +11,9 @@ import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author Derpthemeus */ public final class MinionsMurmurs extends CardImpl { @@ -23,6 +23,7 @@ public final class MinionsMurmurs extends CardImpl { // You draw X cards and you lose X life, where X is the number of creatures you control. this.getSpellAbility().addEffect(new MinionsMurmursEffect()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); } public MinionsMurmurs(final MinionsMurmurs card) { diff --git a/Mage.Sets/src/mage/cards/m/MinistrantOfObligation.java b/Mage.Sets/src/mage/cards/m/MinistrantOfObligation.java new file mode 100644 index 0000000000..48c3fda603 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MinistrantOfObligation.java @@ -0,0 +1,37 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +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 MinistrantOfObligation extends CardImpl { + + public MinistrantOfObligation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Afterlife 2 + this.addAbility(new AfterlifeAbility(2)); + } + + private MinistrantOfObligation(final MinistrantOfObligation card) { + super(card); + } + + @Override + public MinistrantOfObligation copy() { + return new MinistrantOfObligation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Mirari.java b/Mage.Sets/src/mage/cards/m/Mirari.java index 0c0b0fe580..da05fc00c0 100644 --- a/Mage.Sets/src/mage/cards/m/Mirari.java +++ b/Mage.Sets/src/mage/cards/m/Mirari.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.Effect; @@ -19,17 +17,17 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; -import mage.target.TargetSpell; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Mirari extends CardImpl { public Mirari(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); addSuperType(SuperType.LEGENDARY); // Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy. @@ -58,8 +56,9 @@ class MirariTriggeredAbility extends TriggeredAbilityImpl { } MirariTriggeredAbility() { - super(Zone.BATTLEFIELD, new DoIfCostPaid(new CopyTargetSpellEffect(true), new GenericManaCost(3)), false); - this.addTarget(new TargetSpell(filter)); + super(Zone.BATTLEFIELD, new DoIfCostPaid( + new CopyTargetSpellEffect(true), + new GenericManaCost(3)), false); } MirariTriggeredAbility(final MirariTriggeredAbility ability) { @@ -82,7 +81,11 @@ class MirariTriggeredAbility extends TriggeredAbilityImpl { Spell spell = game.getStack().getSpell(event.getTargetId()); if (isControlledInstantOrSorcery(spell)) { for (Effect effect : getEffects()) { - effect.setTargetPointer(new FixedTarget(spell.getId())); + if (effect instanceof DoIfCostPaid) { + for (Effect execEffect : ((DoIfCostPaid) effect).getExecutingEffects()) { + execEffect.setTargetPointer(new FixedTarget(spell.getId())); + } + } } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MirriWeatherlightDuelist.java b/Mage.Sets/src/mage/cards/m/MirriWeatherlightDuelist.java index 7f195643e6..07ccad7533 100644 --- a/Mage.Sets/src/mage/cards/m/MirriWeatherlightDuelist.java +++ b/Mage.Sets/src/mage/cards/m/MirriWeatherlightDuelist.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -14,20 +12,14 @@ import mage.abilities.effects.common.AddContinuousEffectToGame; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class MirriWeatherlightDuelist extends CardImpl { @@ -86,7 +78,10 @@ class MirriWeatherlightDuelistBlockRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } for (UUID creature : game.getCombat().getBlockers()) { if (game.getPlayer(game.getPermanent(creature).getOwnerId()).hasOpponent(attacker.getControllerId(), game)) { return false; diff --git a/Mage.Sets/src/mage/cards/m/MirrorEntity.java b/Mage.Sets/src/mage/cards/m/MirrorEntity.java index b5246cc7e3..9174db87c9 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorEntity.java +++ b/Mage.Sets/src/mage/cards/m/MirrorEntity.java @@ -40,7 +40,7 @@ public final class MirrorEntity extends CardImpl { // Changeling this.addAbility(ChangelingAbility.getInstance()); // {X}: Until end of turn, creatures you control have base power and toughness X/X and gain all creature types. - DynamicValue variableMana = new ManacostVariableValue(); + DynamicValue variableMana = ManacostVariableValue.instance; Effect effect = new SetPowerToughnessAllEffect(variableMana, variableMana, Duration.EndOfTurn, filter, true); effect.setText("Until end of turn, creatures you control have base power and toughness X/X"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new VariableManaCost()); diff --git a/Mage.Sets/src/mage/cards/m/MirrorMarch.java b/Mage.Sets/src/mage/cards/m/MirrorMarch.java new file mode 100644 index 0000000000..c68bf6b03a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MirrorMarch.java @@ -0,0 +1,95 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MirrorMarch extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("nontoken creature"); + + static { + filter.add(Predicates.not(TokenPredicate.instance)); + } + + public MirrorMarch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{5}{R}"); + + // Whenever a nontoken creature enters the battlefield under your control, flip a coin until you lose a flip. For each flip you won, create a token that's a copy of that creature. Those tokens gain haste. Exile them at the beginning of the next end step. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, new MirrorMarchEffect(), filter, false, SetTargetPointer.PERMANENT, + "Whenever a nontoken creature enters the battlefield under your control, " + + "flip a coin until you lose a flip. For each flip you won, " + + "create a token that's a copy of that creature. Those tokens gain haste. " + + "Exile them at the beginning of the next end step." + )); + } + + private MirrorMarch(final MirrorMarch card) { + super(card); + } + + @Override + public MirrorMarch copy() { + return new MirrorMarch(this); + } +} + +class MirrorMarchEffect extends OneShotEffect { + + MirrorMarchEffect() { + super(Outcome.Benefit); + } + + private MirrorMarchEffect(final MirrorMarchEffect effect) { + super(effect); + } + + @Override + public MirrorMarchEffect copy() { + return new MirrorMarchEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int counter = 0; + boolean wonFlip = false; + do { + wonFlip = player.flipCoin(source, game, true); + if (wonFlip) { + counter++; + } + } while (wonFlip); + if (counter > 0) { + CreateTokenCopyTargetEffect effect + = new CreateTokenCopyTargetEffect(player.getId(), null, true, counter); + effect.setUseLKI(true); + effect.setTargetPointer(targetPointer); + effect.apply(game, source); + effect.exileTokensCreatedAtNextEndStep(game, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java index 737385b8fe..f959f3abb8 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java +++ b/Mage.Sets/src/mage/cards/m/MirrorOfTheForebears.java @@ -1,35 +1,39 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffect; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; -import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; -import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.ChosenSubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import mage.target.targetpointer.FixedTarget; import mage.util.functions.EmptyApplyToPermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class MirrorOfTheForebears extends CardImpl { + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new ChosenSubtypePredicate()); + } + public MirrorOfTheForebears(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); @@ -37,14 +41,12 @@ public final class MirrorOfTheForebears extends CardImpl { this.addAbility(new AsEntersBattlefieldAbility(new ChooseCreatureTypeEffect(Outcome.Copy))); // 1: Until end of turn, Mirror of the Forebears becomes a copy of target creature you control of the chosen type, except it's an artifact in addition to its other types. - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(new ChosenSubtypePredicate()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MirrorOfTheForebearsCopyEffect(), new ManaCostsImpl("{1}")); + Ability ability = new SimpleActivatedAbility(new MirrorOfTheForebearsCopyEffect(), new GenericManaCost(1)); ability.addTarget(new TargetPermanent(filter)); this.addAbility(ability); } - public MirrorOfTheForebears(final MirrorOfTheForebears card) { + private MirrorOfTheForebears(final MirrorOfTheForebears card) { super(card); } @@ -56,12 +58,12 @@ public final class MirrorOfTheForebears extends CardImpl { class MirrorOfTheForebearsCopyEffect extends OneShotEffect { - public MirrorOfTheForebearsCopyEffect() { + MirrorOfTheForebearsCopyEffect() { super(Outcome.Copy); this.staticText = "until end of turn, {this} becomes a copy of target creature you control of the chosen type, except it's an artifact in addition to its other types"; } - public MirrorOfTheForebearsCopyEffect(final MirrorOfTheForebearsCopyEffect effect) { + private MirrorOfTheForebearsCopyEffect(final MirrorOfTheForebearsCopyEffect effect) { super(effect); } @@ -76,11 +78,7 @@ class MirrorOfTheForebearsCopyEffect extends OneShotEffect { Permanent copyFromPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (sourcePermanent != null && copyFromPermanent != null) { game.copyPermanent(Duration.EndOfTurn, copyFromPermanent, sourcePermanent.getId(), source, new EmptyApplyToPermanent()); - if (!copyFromPermanent.isArtifact()) { - ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT); - effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); - game.addEffect(effect, source); - } + game.addEffect(new AddCardTypeSourceEffect(Duration.EndOfTurn, CardType.ARTIFACT), source); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/m/MirrorStrike.java b/Mage.Sets/src/mage/cards/m/MirrorStrike.java index b76e9ff569..f6f38df431 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorStrike.java +++ b/Mage.Sets/src/mage/cards/m/MirrorStrike.java @@ -29,7 +29,7 @@ public final class MirrorStrike extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creature"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } public MirrorStrike(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MirrorUniverse.java b/Mage.Sets/src/mage/cards/m/MirrorUniverse.java index 9963565d80..c8028a1053 100644 --- a/Mage.Sets/src/mage/cards/m/MirrorUniverse.java +++ b/Mage.Sets/src/mage/cards/m/MirrorUniverse.java @@ -29,7 +29,7 @@ public final class MirrorUniverse extends CardImpl { Zone.BATTLEFIELD, new ExchangeLifeTargetEffect(), new TapSourceCost(), - new IsStepCondition(PhaseStep.UPKEEP, true), + new IsStepCondition(PhaseStep.UPKEEP), null); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetOpponent()); diff --git a/Mage.Sets/src/mage/cards/m/MirrorwoodTreefolk.java b/Mage.Sets/src/mage/cards/m/MirrorwoodTreefolk.java new file mode 100644 index 0000000000..c648d36d5a --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MirrorwoodTreefolk.java @@ -0,0 +1,95 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.RedirectionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.common.TargetAnyTarget; + +/** + * + * @author LevelX2 & L_J + */ +public final class MirrorwoodTreefolk extends CardImpl { + + public MirrorwoodTreefolk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + this.subtype.add(SubType.TREEFOLK); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {2}{R}{W}: The next time damage would be dealt to Mirrorwood Treefolk this turn, that damage is dealt to any target instead. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MirrorwoodTreefolkEffect(), new ManaCostsImpl("{2}{R}{W}")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + } + + public MirrorwoodTreefolk(final MirrorwoodTreefolk card) { + super(card); + } + + @Override + public MirrorwoodTreefolk copy() { + return new MirrorwoodTreefolk(this); + } +} + +class MirrorwoodTreefolkEffect extends RedirectionEffect { + + protected MageObjectReference redirectToObject; + + public MirrorwoodTreefolkEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, UsageType.ONE_USAGE_ABSOLUTE); + staticText = "The next time damage would be dealt to {this} this turn, that damage is dealt to any target instead"; + } + + public MirrorwoodTreefolkEffect(final MirrorwoodTreefolkEffect effect) { + super(effect); + this.redirectToObject = effect.redirectToObject; + } + + @Override + public MirrorwoodTreefolkEffect copy() { + return new MirrorwoodTreefolkEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + redirectToObject = new MageObjectReference(source.getTargets().get(0).getFirstTarget(), game); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getTargetId().equals(source.getSourceId())) { + if (redirectToObject.equals(new MageObjectReference(source.getTargets().get(0).getFirstTarget(), game))) { + redirectTarget = source.getTargets().get(0); + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/m/Mirrorworks.java b/Mage.Sets/src/mage/cards/m/Mirrorworks.java index 80d4781657..95b8e4cc1d 100644 --- a/Mage.Sets/src/mage/cards/m/Mirrorworks.java +++ b/Mage.Sets/src/mage/cards/m/Mirrorworks.java @@ -23,11 +23,11 @@ import mage.filter.predicate.permanent.TokenPredicate; */ public final class Mirrorworks extends CardImpl { - private final static FilterArtifactPermanent filter = new FilterArtifactPermanent("another nontoken artifact"); + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("another nontoken artifact"); static { - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public Mirrorworks(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/Mise.java b/Mage.Sets/src/mage/cards/m/Mise.java index 23cdc07e72..06074b560f 100644 --- a/Mage.Sets/src/mage/cards/m/Mise.java +++ b/Mage.Sets/src/mage/cards/m/Mise.java @@ -52,7 +52,7 @@ class MiseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - Object object = (String) game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); + Object object = game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY); if (player != null && object instanceof String) { Card card = player.getLibrary().getFromTop(game); String namedCard = (String) object; diff --git a/Mage.Sets/src/mage/cards/m/MiseryCharm.java b/Mage.Sets/src/mage/cards/m/MiseryCharm.java index e347ec9ab2..c0195ee953 100644 --- a/Mage.Sets/src/mage/cards/m/MiseryCharm.java +++ b/Mage.Sets/src/mage/cards/m/MiseryCharm.java @@ -39,13 +39,13 @@ public final class MiseryCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or return target Cleric card from your graveyard to your hand Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(filter2)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filter2)); this.getSpellAbility().addMode(mode); // or target player loses 2 life. mode = new Mode(); - mode.getEffects().add(new LoseLifeTargetEffect(2)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new LoseLifeTargetEffect(2)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/Misfortune.java b/Mage.Sets/src/mage/cards/m/Misfortune.java new file mode 100644 index 0000000000..c3e0b8ec8b --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Misfortune.java @@ -0,0 +1,88 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author jeffwadsworth + */ +public final class Misfortune extends CardImpl { + + public Misfortune(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{R}{G}"); + + // An opponent chooses one - You put a +1/+1 counter on each creature you control and gain 4 life; or you put a -1/-1 counter on each creature that player controls and Misfortune deals 4 damage to him or her. + this.getSpellAbility().addEffect(new MisfortuneEffect()); + this.getSpellAbility().addTarget(new TargetOpponent(true)); + } + + private Misfortune(final Misfortune card) { + super(card); + } + + @Override + public Misfortune copy() { + return new Misfortune(this); + } +} + +class MisfortuneEffect extends OneShotEffect { + + public MisfortuneEffect() { + super(Outcome.Neutral); + staticText = "An opponent chooses one - " + + "You put a +1/+1 counter on each creature you control and gain " + + "4 life; or you put a -1/-1 counter on each creature that player " + + "controls and Misfortune deals 4 damage to him or her"; + } + + public MisfortuneEffect(final MisfortuneEffect effect) { + super(effect); + } + + @Override + public MisfortuneEffect copy() { + return new MisfortuneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player chosenOpponent = game.getPlayer(targetPointer.getFirst(game, source)); + if (controller != null + && chosenOpponent != null) { + if (chosenOpponent.chooseUse(Outcome.Neutral, "If you choose Yes, the controller puts a +1/+1 counter" + + "on each creature they control and they gain 4 life. If no, the controller puts a -1/-1 counter" + + "on each creature you control and {this} deals 4 damage to you.", source, game)) { + Effect putP1P1CounterOnEachControlledCreature = new AddCountersAllEffect( + CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent()); + putP1P1CounterOnEachControlledCreature.apply(game, source); + controller.gainLife(4, game, source); + } else { + FilterCreaturePermanent filterOpponentCreatures = new FilterCreaturePermanent(); + filterOpponentCreatures.add(new ControllerIdPredicate(chosenOpponent.getId())); + Effect putM1M1CounterOnEachOpponentCreature = new AddCountersAllEffect( + CounterType.M1M1.createInstance(), filterOpponentCreatures); + putM1M1CounterOnEachOpponentCreature.apply(game, source); + chosenOpponent.damage(4, source.getSourceId(), game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java b/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java index a7e9e69d51..a801c5a83d 100644 --- a/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java +++ b/Mage.Sets/src/mage/cards/m/MishraArtificerProdigy.java @@ -135,7 +135,7 @@ class MishraArtificerProdigyEffect extends OneShotEffect { // Library if (card == null && controller.chooseUse(Outcome.Neutral, "Search your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/m/MishrasSelfReplicator.java b/Mage.Sets/src/mage/cards/m/MishrasSelfReplicator.java index 351049efa7..709731b01e 100644 --- a/Mage.Sets/src/mage/cards/m/MishrasSelfReplicator.java +++ b/Mage.Sets/src/mage/cards/m/MishrasSelfReplicator.java @@ -23,7 +23,7 @@ public final class MishrasSelfReplicator extends CardImpl { private static final FilterSpell filter = new FilterSpell("a historic spell"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public MishrasSelfReplicator(UUID ownerId, CardSetInfo setInfo) { @@ -37,7 +37,7 @@ public final class MishrasSelfReplicator extends CardImpl { this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid( new CreateTokenCopySourceEffect() .setText("create a token that's a copy of {this}. (Artifacts, legendaries, and Sagas are historic.)"), - new ManaCostsImpl("{1}")), filter, true)); + new ManaCostsImpl("{1}")), filter, false)); } diff --git a/Mage.Sets/src/mage/cards/m/MissDemeanor.java b/Mage.Sets/src/mage/cards/m/MissDemeanor.java new file mode 100644 index 0000000000..e262d64ff8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MissDemeanor.java @@ -0,0 +1,87 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author Ketsuban + */ +public final class MissDemeanor extends CardImpl { + + public MissDemeanor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.LADYOFPROPERETIQUETTE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // At the beginning of each other player's upkeep, you may compliment that player on their game play. If you don't, sacrifice Miss Demeanour. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new MissDemeanorEffect(), TargetController.NOT_YOU, false, true)); + } + + public MissDemeanor(final MissDemeanor card) { + super(card); + } + + @Override + public MissDemeanor copy() { + return new MissDemeanor(this); + } +} + +class MissDemeanorEffect extends OneShotEffect { + + public MissDemeanorEffect() { + super(Outcome.Sacrifice); + this.staticText = "you may compliment that player on their game play. If you don't, sacrifice {this}"; + } + + public MissDemeanorEffect(final MissDemeanorEffect effect) { + super(effect); + } + + @Override + public MissDemeanorEffect copy() { + return new MissDemeanorEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourceObject = (Permanent) source.getSourceObjectIfItStillExists(game); + String activePlayerName = game.getPlayer(game.getActivePlayerId()).getName(); + if (sourceObject != null) { + if (controller.chooseUse(outcome, "Compliment " + activePlayerName + " on their game play?", source, game)) { + // TODO(Ketsuban): this could probably stand to be randomly chosen from a pool of compliments + game.informPlayers(controller.getLogName() + ": That's a well-built deck and you pilot it well, " + activePlayerName + "."); + } else { + sourceObject.sacrifice(source.getSourceId(), game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/m/MissionBriefing.java b/Mage.Sets/src/mage/cards/m/MissionBriefing.java index ecd3f55643..29642c0d63 100644 --- a/Mage.Sets/src/mage/cards/m/MissionBriefing.java +++ b/Mage.Sets/src/mage/cards/m/MissionBriefing.java @@ -13,7 +13,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -48,14 +47,12 @@ public final class MissionBriefing extends CardImpl { class MissionBriefingEffect extends OneShotEffect { - public static final FilterCard filter = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); - public MissionBriefingEffect() { super(Outcome.Benefit); this.staticText = "Surveil 2, then choose an instant or sorcery card " + "in your graveyard. You may cast that card this turn. " + "If that card would be put into your graveyard this turn, " - + "exile it instead."; + + "exile it instead"; } public MissionBriefingEffect(final MissionBriefingEffect effect) { @@ -74,9 +71,10 @@ class MissionBriefingEffect extends OneShotEffect { return false; } player.surveil(2, source, game); - Target target = new TargetCardInYourGraveyard(filter); + Target target = new TargetCardInYourGraveyard( + new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard")); if (!player.choose(outcome, target, source.getSourceId(), game)) { - return false; + return true; } Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/m/Mistcaller.java b/Mage.Sets/src/mage/cards/m/Mistcaller.java index 88f7d3952e..e2bef655e5 100644 --- a/Mage.Sets/src/mage/cards/m/Mistcaller.java +++ b/Mage.Sets/src/mage/cards/m/Mistcaller.java @@ -1,6 +1,5 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -8,21 +7,18 @@ import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.TransformAbility; import mage.cards.Card; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; import mage.watchers.common.CreatureWasCastWatcher; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Mistcaller extends CardImpl { @@ -96,14 +92,14 @@ class ContainmentPriestReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD) { Card card = game.getCard(event.getTargetId()); - Object entersTransformed = game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + event.getTargetId()); - if (entersTransformed instanceof Boolean && (Boolean) entersTransformed && card.getSecondCardFace() != null) { - card = card.getSecondCardFace(); - } - if (card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly - CreatureWasCastWatcher watcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName()); - if (watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId())) { - return true; + if (card != null) { + Object entersTransformed = game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + event.getTargetId()); + if (entersTransformed instanceof Boolean && (Boolean) entersTransformed && card.getSecondCardFace() != null) { + card = card.getSecondCardFace(); + } + if (card != null && card.isCreature()) { // TODO: Bestow Card cast as Enchantment probably not handled correctly + CreatureWasCastWatcher watcher = game.getState().getWatcher(CreatureWasCastWatcher.class); + return watcher != null && !watcher.wasCreatureCastThisTurn(event.getTargetId()); } } } diff --git a/Mage.Sets/src/mage/cards/m/Mistfolk.java b/Mage.Sets/src/mage/cards/m/Mistfolk.java new file mode 100644 index 0000000000..497feb0ec5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Mistfolk.java @@ -0,0 +1,83 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterSpell; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; +import mage.target.Target; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Mistfolk extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("spell that this creature"); + + static { + filter.add(MistfolkPredicate.instance); + } + + public Mistfolk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {U}: Counter target spell that targets Mistfolk. + Ability ability = new SimpleActivatedAbility( + new CounterTargetEffect() + .setText("counter target spell that targets {this}"), + new ManaCostsImpl("{U}") + ); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); + } + + public Mistfolk(final Mistfolk card) { + super(card); + } + + @Override + public Mistfolk copy() { + return new Mistfolk(this); + } +} + +enum MistfolkPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent sourceObject = game.getPermanent(input.getSourceId()); + if (sourceObject == null || input.getObject() == null) { + return false; + } + for (SpellAbility spellAbility : input.getObject().getSpellAbilities()) { + for (Mode mode : spellAbility.getModes().values()) { + for (Target target : spellAbility.getTargets()) { + if (target.getTargets().contains(input.getSourceId())) { + return true; + } + } + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MistveilPlains.java b/Mage.Sets/src/mage/cards/m/MistveilPlains.java index f564de722b..35d71a4487 100644 --- a/Mage.Sets/src/mage/cards/m/MistveilPlains.java +++ b/Mage.Sets/src/mage/cards/m/MistveilPlains.java @@ -1,6 +1,6 @@ - package mage.cards.m; +import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -20,8 +20,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; -import java.util.UUID; - /** * @author LevelX2 */ @@ -86,8 +84,8 @@ class MistveilPlainsGraveyardToLibraryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getFirstTarget()); Player player = game.getPlayer(source.getControllerId()); - if (card == null || player == null || - game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { + if (card == null || player == null + || game.getState().getZone(card.getId()) != Zone.GRAVEYARD) { return false; } return player.putCardsOnBottomOfLibrary(card, game, source, false); diff --git a/Mage.Sets/src/mage/cards/m/MizziumSkin.java b/Mage.Sets/src/mage/cards/m/MizziumSkin.java index e4ea1a4c58..909ffd2919 100644 --- a/Mage.Sets/src/mage/cards/m/MizziumSkin.java +++ b/Mage.Sets/src/mage/cards/m/MizziumSkin.java @@ -14,6 +14,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCreaturePermanent; @@ -25,28 +26,24 @@ import mage.target.common.TargetCreaturePermanent; */ public final class MizziumSkin extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } public MizziumSkin(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); // Target creature you control gets +0/+1 and gains hexproof until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)); this.getSpellAbility().addEffect(new BoostTargetEffect(0,1, Duration.EndOfTurn)); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(HexproofAbility.getInstance(), Duration.EndOfTurn)); // Overload {1}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") - OverloadAbility ability = new OverloadAbility(this, new BoostAllEffect(0,1, Duration.EndOfTurn,filter,false), new ManaCostsImpl("{1}{U}")); - ability.addEffect(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, filter)); + OverloadAbility ability = new OverloadAbility(this, new BoostAllEffect(0,1, Duration.EndOfTurn,StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED,false), new ManaCostsImpl("{1}{U}")); + ability.addEffect(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)); this.addAbility(ability); } - public MizziumSkin(final MizziumSkin card) { + private MizziumSkin(final MizziumSkin card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/m/MizziumTank.java b/Mage.Sets/src/mage/cards/m/MizziumTank.java new file mode 100644 index 0000000000..5201a837df --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MizziumTank.java @@ -0,0 +1,55 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MizziumTank extends CardImpl { + + public MizziumTank(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{R}{R}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever you cast a noncreature spell, Mizzium Tank becomes an artifact creature and gets +1/+1 until end of turn. + Ability ability = new SpellCastControllerTriggeredAbility(new AddCardTypeSourceEffect( + Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE + ).setText("{this} becomes an artifact creature"), StaticFilters.FILTER_SPELL_NON_CREATURE, false); + ability.addEffect(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ).setText("and gets +1/+1 until end of turn")); + this.addAbility(ability); + + // Crew 1 + this.addAbility(new CrewAbility(1)); + } + + private MizziumTank(final MizziumTank card) { + super(card); + } + + @Override + public MizziumTank copy() { + return new MizziumTank(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MnemonicBetrayal.java b/Mage.Sets/src/mage/cards/m/MnemonicBetrayal.java index 019527dd74..757e38dd83 100644 --- a/Mage.Sets/src/mage/cards/m/MnemonicBetrayal.java +++ b/Mage.Sets/src/mage/cards/m/MnemonicBetrayal.java @@ -10,10 +10,11 @@ import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; - import java.util.HashMap; import java.util.Map; import java.util.UUID; +import mage.abilities.effects.AsThoughManaEffect; +import mage.players.ManaPoolItem; /** * @author TheElk801 @@ -68,18 +69,19 @@ class MnemonicBetrayalExileEffect extends OneShotEffect { return false; } Cards cards = new CardsImpl(); - Map cardMap = new HashMap(); - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if (player != null) { - cards.addAll(player.getGraveyard()); - } - } - for (Card card : cards.getCards(game)) { + Map cardMap = new HashMap<>(); + game.getOpponents(source.getControllerId()).stream().map((playerId) -> game.getPlayer(playerId)).filter((player) -> (player != null)).forEachOrdered((player) -> { + cards.addAll(player.getGraveyard()); + }); + cards.getCards(game).stream().map((card) -> { cardMap.put(card.getId(), card.getZoneChangeCounter(game)); + return card; + }).map((card) -> { game.addEffect(new MnemonicBetrayalCastFromExileEffect(card, game), source); + return card; + }).forEachOrdered((card) -> { game.addEffect(new MnemonicBetrayalAnyColorEffect(card, game), source); - } + }); controller.moveCardsToExile(cards.getCards(game), source, game, true, source.getSourceId(), source.getSourceObjectIfItStillExists(game).getName()); game.addDelayedTriggeredAbility(new MnemonicBetrayalDelayedTriggeredAbility(cards, cardMap), source); return true; @@ -125,7 +127,7 @@ class MnemonicBetrayalCastFromExileEffect extends AsThoughEffectImpl { } } -class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl { +class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl implements AsThoughManaEffect { private final Card card; private final int zoneCounter; @@ -154,20 +156,29 @@ class MnemonicBetrayalAnyColorEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (card.getZoneChangeCounter(game) != zoneCounter) { - this.discard(); - return false; + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards + if (objectId.equals(card.getId()) + && card.getZoneChangeCounter(game) <= zoneCounter + 1 + && affectedControllerId.equals(source.getControllerId())) { + return true; + } else { + if (objectId.equals(card.getId())) { + this.discard(); + } } - return objectId.equals(card.getId()) - && card.getZoneChangeCounter(game) == zoneCounter - && affectedControllerId.equals(source.getControllerId()); + return false; + } + + @Override + public ManaType getAsThoughManaType(ManaType manaType, ManaPoolItem mana, UUID affectedControllerId, Ability source, Game game) { + return mana.getFirstAvailable(); } } class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility { private final Cards cards; - private final Map cardMap = new HashMap(); + private final Map cardMap = new HashMap<>(); public MnemonicBetrayalDelayedTriggeredAbility(Cards cards, Map cardMap) { super(new MnemonicBetrayalReturnEffect(cards, cardMap)); @@ -214,7 +225,7 @@ class MnemonicBetrayalDelayedTriggeredAbility extends DelayedTriggeredAbility { class MnemonicBetrayalReturnEffect extends OneShotEffect { private final Cards cards; - private final Map cardMap = new HashMap(); + private final Map cardMap = new HashMap<>(); public MnemonicBetrayalReturnEffect(Cards cards, Map cardMap) { super(Outcome.Benefit); @@ -240,12 +251,10 @@ class MnemonicBetrayalReturnEffect extends OneShotEffect { return false; } Cards cardsToReturn = new CardsImpl(); - for (Card card : cards.getCards(game)) { - if (game.getState().getZone(card.getId()) == Zone.EXILED - && card.getZoneChangeCounter(game) == cardMap.getOrDefault(card.getId(), -5) + 1) { - cardsToReturn.add(card); - } - } + cards.getCards(game).stream().filter((card) -> (game.getState().getZone(card.getId()) == Zone.EXILED + && card.getZoneChangeCounter(game) == cardMap.getOrDefault(card.getId(), -5) + 1)).forEachOrdered((card) -> { + cardsToReturn.add(card); + }); return player.moveCards(cardsToReturn, Zone.GRAVEYARD, source, game); } } diff --git a/Mage.Sets/src/mage/cards/m/MnemonicNexus.java b/Mage.Sets/src/mage/cards/m/MnemonicNexus.java index f1464aade3..8acec9890e 100644 --- a/Mage.Sets/src/mage/cards/m/MnemonicNexus.java +++ b/Mage.Sets/src/mage/cards/m/MnemonicNexus.java @@ -50,6 +50,9 @@ class MnemonicNexusEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player sourcePlayer = game.getPlayer(source.getControllerId()); + if(sourcePlayer == null){ + return false; + } for (UUID playerId: game.getState().getPlayersInRange(sourcePlayer.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage.Sets/src/mage/cards/m/MobJustice.java b/Mage.Sets/src/mage/cards/m/MobJustice.java index 8bc8519c22..467506ca6f 100644 --- a/Mage.Sets/src/mage/cards/m/MobJustice.java +++ b/Mage.Sets/src/mage/cards/m/MobJustice.java @@ -1,18 +1,17 @@ - package mage.cards.m; -import java.util.UUID; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetPlayerOrPlaneswalker; +import java.util.UUID; + /** - * * @author LoneFox */ public final class MobJustice extends CardImpl { @@ -21,10 +20,11 @@ public final class MobJustice extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); // Mob Justice deals damage to target player equal to the number of creatures you control. - Effect effect = new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent())); + Effect effect = new DamageTargetEffect(CreaturesYouControlCount.instance); effect.setText("{this} deals damage to target player or planeswalker equal to the number of creatures you control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); } public MobJustice(final MobJustice card) { diff --git a/Mage.Sets/src/mage/cards/m/MobMentality.java b/Mage.Sets/src/mage/cards/m/MobMentality.java new file mode 100644 index 0000000000..e00596f1a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MobMentality.java @@ -0,0 +1,111 @@ +package mage.cards.m; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.AttackingCreatureCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MobMentality extends CardImpl { + + public MobMentality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has trample. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.AURA))); + + // Whenever all non-Wall creatures you control attack, enchanted creature gets +X/+0 until end of turn, where X is the number of attacking creatures. + this.addAbility(new MobMentalityTriggeredAbility()); + } + + public MobMentality(final MobMentality card) { + super(card); + } + + @Override + public MobMentality copy() { + return new MobMentality(this); + } +} + +class MobMentalityTriggeredAbility extends TriggeredAbilityImpl { + MobMentalityTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostTargetEffect(new AttackingCreatureCount(), new StaticValue(0), Duration.EndOfTurn, true)); + } + + private MobMentalityTriggeredAbility(final MobMentalityTriggeredAbility ability) { + super(ability); + } + + @Override + public MobMentalityTriggeredAbility copy() { + return new MobMentalityTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DECLARED_ATTACKERS; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (!game.getCombat().getAttackingPlayerId().equals(getControllerId())) { + return false; + } + Permanent aura = game.getPermanent(getSourceId()); + if (aura == null) { + return false; + } + Permanent creature = game.getPermanent(aura.getAttachedTo()); + if (creature == null) { + return false; + } + for (Effect effect : getEffects()) { + effect.setTargetPointer(new FixedTarget(creature, game)); + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(getControllerId())) { + if (permanent.isCreature() + && !permanent.hasSubtype(SubType.WALL, game) + && !permanent.isAttacking()) { + return false; + } + } + return true; + } + + @Override + public String getRule() { + return "Whenever all non-Wall creatures you control attack, " + + "enchanted creature gets +X/+0 until end of turn, " + + "where X is the number of attacking creatures."; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MobRule.java b/Mage.Sets/src/mage/cards/m/MobRule.java index 35e12d740f..65c2226393 100644 --- a/Mage.Sets/src/mage/cards/m/MobRule.java +++ b/Mage.Sets/src/mage/cards/m/MobRule.java @@ -34,7 +34,7 @@ public final class MobRule extends CardImpl { // Gain control of all creatures with power 3 or less until end of turn. Untap those creatures. They gain haste until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new MobRuleEffect(ComparisonType.FEWER_THAN, 4)); + mode.addEffect(new MobRuleEffect(ComparisonType.FEWER_THAN, 4)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MobileGarrison.java b/Mage.Sets/src/mage/cards/m/MobileGarrison.java index 35793906e4..3ebd7811e8 100644 --- a/Mage.Sets/src/mage/cards/m/MobileGarrison.java +++ b/Mage.Sets/src/mage/cards/m/MobileGarrison.java @@ -27,7 +27,7 @@ public final class MobileGarrison extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target artifact or creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE) diff --git a/Mage.Sets/src/mage/cards/m/MobilizedDistrict.java b/Mage.Sets/src/mage/cards/m/MobilizedDistrict.java new file mode 100644 index 0000000000..35a6304eed --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MobilizedDistrict.java @@ -0,0 +1,126 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.token.TokenImpl; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MobilizedDistrict extends CardImpl { + + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(); + + static { + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + static final DynamicValue cardsCount = new PermanentsOnBattlefieldCount(filter); + + public MobilizedDistrict(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {4}: Mobilized District becomes a 3/3 Citizen creature with vigilance until end of turn. It's still a land. This ability costs {1} less to activate for each legendary creature and planeswalker you control. + // TODO: Make ability properly copiable + Ability ability = new SimpleActivatedAbility(new BecomesCreatureSourceEffect( + new MobilizedDistrictToken(), "land", Duration.EndOfTurn + ).setText("{this} becomes a 3/3 Citizen creature with vigilance until end of turn. " + + "It's still a land. This ability costs {1} less to activate " + + "for each legendary creature and planeswalker you control." + ), new GenericManaCost(4)); + this.addAbility(ability); + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new MobilizedDistrictCostIncreasingEffect(ability.getOriginalId()) + ).addHint(new ValueHint("Legendary creatures and planeswalkers you control", cardsCount))); + } + + private MobilizedDistrict(final MobilizedDistrict card) { + super(card); + } + + @Override + public MobilizedDistrict copy() { + return new MobilizedDistrict(this); + } +} + +class MobilizedDistrictToken extends TokenImpl { + + MobilizedDistrictToken() { + super("", "3/3 Citizen creature with vigilance"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.CITIZEN); + power = new MageInt(3); + toughness = new MageInt(3); + addAbility(VigilanceAbility.getInstance()); + } + + private MobilizedDistrictToken(final MobilizedDistrictToken token) { + super(token); + } + + public MobilizedDistrictToken copy() { + return new MobilizedDistrictToken(this); + } +} + +class MobilizedDistrictCostIncreasingEffect extends CostModificationEffectImpl { + + private final UUID originalId; + + MobilizedDistrictCostIncreasingEffect(UUID originalId) { + super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.REDUCE_COST); + this.originalId = originalId; + } + + private MobilizedDistrictCostIncreasingEffect(final MobilizedDistrictCostIncreasingEffect effect) { + super(effect); + this.originalId = effect.originalId; + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int count = MobilizedDistrict.cardsCount.calculate(game, source, this); + CardUtil.reduceCost(abilityToModify, count); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify.getOriginalId().equals(originalId); + } + + @Override + public MobilizedDistrictCostIncreasingEffect copy() { + return new MobilizedDistrictCostIncreasingEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoggAssassin.java b/Mage.Sets/src/mage/cards/m/MoggAssassin.java index 1051e3a9fd..8f8f2a9352 100644 --- a/Mage.Sets/src/mage/cards/m/MoggAssassin.java +++ b/Mage.Sets/src/mage/cards/m/MoggAssassin.java @@ -2,7 +2,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -11,8 +10,8 @@ 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.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; @@ -20,59 +19,36 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author L_J */ public final class MoggAssassin extends CardImpl { - private final UUID originalId; - public MoggAssassin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.ASSASSIN); this.power = new MageInt(2); this.toughness = new MageInt(1); - - //TODO: Make ability properly copiable + // {T}: You choose target creature an opponent controls, and that opponent chooses target creature. Flip a coin. If you win the flip, destroy the creature you chose. If you lose the flip, destroy the creature your opponent chose. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new MoggAssassinEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new MoggAssassinEffect(), + new TapSourceCost() + ); ability.addTarget(new TargetOpponentsCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(MoggAssassinAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - UUID opponentId = null; - if (game.getOpponents(controller.getId()).size() > 1) { - Target target = ability.getTargets().get(0); - if (controller.chooseTarget(Outcome.DestroyPermanent, target, ability, game)) { - Permanent permanent = game.getPermanent(target.getFirstTarget()); - opponentId = permanent.getControllerId(); - } else { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } - } else { - opponentId = game.getOpponents(controller.getId()).iterator().next(); - } - - if (opponentId != null) { - ability.getTargets().get(1).setTargetController(opponentId); - } - } - } } public MoggAssassin(final MoggAssassin card) { super(card); - this.originalId = card.originalId; } @Override @@ -82,6 +58,34 @@ public final class MoggAssassin extends CardImpl { } +enum MoggAssassinAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller == null) { + return; + } + UUID opponentId = null; + if (game.getOpponents(controller.getId()).size() > 1) { + Target target = ability.getTargets().get(0); + if (controller.chooseTarget(Outcome.DestroyPermanent, target, ability, game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + opponentId = permanent.getControllerId(); + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + } else { + opponentId = game.getOpponents(controller.getId()).iterator().next(); + } + + if (opponentId != null) { + ability.getTargets().get(1).setTargetController(opponentId); + } + } +} + class MoggAssassinEffect extends OneShotEffect { public MoggAssassinEffect() { @@ -100,21 +104,21 @@ class MoggAssassinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent chosenPermanent = game.getPermanent(source.getTargets().get(0).getFirstTarget()); - Permanent opponentsPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (controller.flipCoin(game)) { - if (chosenPermanent != null) { - chosenPermanent.destroy(source.getSourceId(), game, false); - return true; - } - } else { - if (opponentsPermanent != null) { - opponentsPermanent.destroy(source.getSourceId(), game, false); - return true; - } + if (controller == null) { + return false; + } + Permanent chosenPermanent = game.getPermanent(source.getTargets().get(0).getFirstTarget()); + Permanent opponentsPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (controller.flipCoin(source, game, true)) { + if (chosenPermanent != null) { + chosenPermanent.destroy(source.getSourceId(), game, false); + return true; + } + } else { + if (opponentsPermanent != null) { + opponentsPermanent.destroy(source.getSourceId(), game, false); + return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/m/MoggBombers.java b/Mage.Sets/src/mage/cards/m/MoggBombers.java new file mode 100644 index 0000000000..b0635fc2eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MoggBombers.java @@ -0,0 +1,60 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class MoggBombers extends CardImpl { + + private static final String rule = "When another creature enters the battlefield, sacrifice {this} and it deals 3 damage to target player."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public MoggBombers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.GOBLIN); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // When another creature enters the battlefield, sacrifice Mogg Bombers and it deals 3 damage to target player. + Effect sacrificeMoggBombers = new SacrificeSourceEffect(); + Effect damageTargetPlayer = new DamageTargetEffect(3); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, + sacrificeMoggBombers, + filter, false, rule); + ability.addEffect(damageTargetPlayer); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + } + + public MoggBombers(final MoggBombers card) { + super(card); + } + + @Override + public MoggBombers copy() { + return new MoggBombers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MoggConscripts.java b/Mage.Sets/src/mage/cards/m/MoggConscripts.java index f70bacbbfd..4ee69cfe89 100644 --- a/Mage.Sets/src/mage/cards/m/MoggConscripts.java +++ b/Mage.Sets/src/mage/cards/m/MoggConscripts.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,21 +7,22 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.watchers.common.PlayerCastCreatureWatcher; +import java.util.UUID; + /** - * * @author fireshoes */ public final class MoggConscripts extends CardImpl { public MoggConscripts(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(2); @@ -60,17 +59,15 @@ class MoggConscriptsEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - PlayerCastCreatureWatcher watcher = (PlayerCastCreatureWatcher) game.getState().getWatchers().get(PlayerCastCreatureWatcher.class.getSimpleName()); - if (watcher != null && !watcher.playerDidCastCreatureThisTurn(source.getControllerId())) { - return true; - } + PlayerCastCreatureWatcher watcher = game.getState().getWatcher(PlayerCastCreatureWatcher.class); + return watcher != null && !watcher.playerDidCastCreatureThisTurn(source.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/m/MoggJailer.java b/Mage.Sets/src/mage/cards/m/MoggJailer.java index bce46bb14a..8b8eb90e0a 100644 --- a/Mage.Sets/src/mage/cards/m/MoggJailer.java +++ b/Mage.Sets/src/mage/cards/m/MoggJailer.java @@ -25,7 +25,7 @@ public final class MoggJailer extends CardImpl { static final private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature with power 2 or less"); static { - filter.add(Predicates.and(new PowerPredicate(ComparisonType.FEWER_THAN, 2), Predicates.not(new TappedPredicate()))); + filter.add(Predicates.and(new PowerPredicate(ComparisonType.FEWER_THAN, 2), Predicates.not(TappedPredicate.instance))); } public MoggJailer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MoggSquad.java b/Mage.Sets/src/mage/cards/m/MoggSquad.java index c7b2934783..d41435d187 100644 --- a/Mage.Sets/src/mage/cards/m/MoggSquad.java +++ b/Mage.Sets/src/mage/cards/m/MoggSquad.java @@ -27,7 +27,7 @@ public final class MoggSquad extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("each other creature on the battlefield"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MoggSquad(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MoggToady.java b/Mage.Sets/src/mage/cards/m/MoggToady.java index 3b4d527761..b005016d82 100644 --- a/Mage.Sets/src/mage/cards/m/MoggToady.java +++ b/Mage.Sets/src/mage/cards/m/MoggToady.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,29 +7,30 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author emerald000 & L_J */ public final class MoggToady extends CardImpl { public MoggToady(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(2); this.toughness = new MageInt(2); // Mogg Toady can't attack unless you control more creatures than defending player. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MoggToadyCantAttackEffect())); - + // Mogg Toady can't block unless you control more creatures than attacking player. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new MoggToadyCantBlockEffect())); } @@ -63,25 +62,26 @@ class MoggToadyCantAttackEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + UUID defendingPlayerId; Player defender = game.getPlayer(defenderId); if (defender == null) { Permanent permanent = game.getPermanent(defenderId); if (permanent != null) { defendingPlayerId = permanent.getControllerId(); - } - else { + } else { return false; } - } - else { + } else { defendingPlayerId = defenderId; } if (defendingPlayerId != null) { return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), defendingPlayerId, game); - } - else { + } else { return true; } } @@ -109,7 +109,10 @@ class MoggToadyCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } UUID attackingPlayerId = attacker.getControllerId(); if (attackingPlayerId != null) { return game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledCreaturePermanent(), attackingPlayerId, game); diff --git a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java index 8c666bcf21..eef7327fa9 100644 --- a/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java +++ b/Mage.Sets/src/mage/cards/m/MogisGodOfSlaughter.java @@ -118,10 +118,8 @@ class DoUnlessTargetPaysCost extends OneShotEffect { if (!staticText.isEmpty()) { return staticText; } - StringBuilder sb = new StringBuilder(executingEffect.getText(mode)); - sb.append("unless he or she"); - sb.append(getCostText()); - return sb.toString(); + return executingEffect.getText(mode) + "unless they" + + getCostText(); } private String getCostText() { diff --git a/Mage.Sets/src/mage/cards/m/MogissMarauder.java b/Mage.Sets/src/mage/cards/m/MogissMarauder.java index b5271f482d..d797c3fd00 100644 --- a/Mage.Sets/src/mage/cards/m/MogissMarauder.java +++ b/Mage.Sets/src/mage/cards/m/MogissMarauder.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -12,20 +11,22 @@ import mage.abilities.keyword.IntimidateAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.ColoredManaSymbol; import mage.constants.Duration; +import mage.constants.SubType; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class MogissMarauder extends CardImpl { public MogissMarauder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.BERSERKER); @@ -35,24 +36,13 @@ public final class MogissMarauder extends CardImpl { // When Mogis's Marauder enters the battlefield, up to X target creatures each gain intimidate and haste, where X is your devotion to black. Ability ability = new EntersBattlefieldTriggeredAbility( new GainAbilityTargetEffect(IntimidateAbility.getInstance(), Duration.EndOfTurn, - "up to X target creatures each gain intimidate"), false); + "up to X target creatures each gain intimidate"), false); ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn, "and haste until end of turn, where X is your devotion to black")); - ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(MogissMarauderAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - int numbTargets = new DevotionCount(ColoredManaSymbol.B).calculate(game, ability, null); - if (numbTargets > 0) { - ability.addTarget(new TargetCreaturePermanent(0,numbTargets)); - } - } - } - public MogissMarauder(final MogissMarauder card) { super(card); } @@ -62,3 +52,16 @@ public final class MogissMarauder extends CardImpl { return new MogissMarauder(this); } } + +enum MogissMarauderAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = new DevotionCount(ColoredManaSymbol.B).calculate(game, ability, null); + if (numbTargets > 0) { + ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/Molder.java b/Mage.Sets/src/mage/cards/m/Molder.java index 5501bbe933..cffc75b81a 100644 --- a/Mage.Sets/src/mage/cards/m/Molder.java +++ b/Mage.Sets/src/mage/cards/m/Molder.java @@ -1,9 +1,7 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.GainLifeEffect; @@ -11,13 +9,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; import mage.filter.common.FilterArtifactOrEnchantmentPermanent; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LoneFox */ public final class Molder extends CardImpl { @@ -26,20 +27,9 @@ public final class Molder extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}"); // Destroy target artifact or enchantment with converted mana cost X. It can't be regenerated. You gain X life. - this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - this.getSpellAbility().addTarget(new TargetPermanent(new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with converted mana cost X"))); - this.getSpellAbility().addEffect(new GainLifeEffect(new ManacostVariableValue())); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterArtifactOrEnchantmentPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetPermanent(filter)); - } + this.getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target artifact or enchantment with converted mana cost X.", true)); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance)); + this.getSpellAbility().setTargetAdjuster(MolderAdjuster.instance); } public Molder(final Molder card) { @@ -51,3 +41,16 @@ public final class Molder extends CardImpl { return new Molder(this); } } + +enum MolderAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterPermanent filter = new FilterArtifactOrEnchantmentPermanent("artifact or enchantment with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetPermanent(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MolderBeast.java b/Mage.Sets/src/mage/cards/m/MolderBeast.java index 1547e0e79c..b598f362f2 100644 --- a/Mage.Sets/src/mage/cards/m/MolderBeast.java +++ b/Mage.Sets/src/mage/cards/m/MolderBeast.java @@ -62,8 +62,7 @@ class MolderBeastTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - return zEvent.getFromZone() == Zone.BATTLEFIELD - && zEvent.getToZone() == Zone.GRAVEYARD + return zEvent.isDiesEvent() && zEvent.getTarget().isArtifact(); } diff --git a/Mage.Sets/src/mage/cards/m/MoldgrafScavenger.java b/Mage.Sets/src/mage/cards/m/MoldgrafScavenger.java index 5fdcecb14f..77b4378ae4 100644 --- a/Mage.Sets/src/mage/cards/m/MoldgrafScavenger.java +++ b/Mage.Sets/src/mage/cards/m/MoldgrafScavenger.java @@ -1,12 +1,13 @@ - package mage.cards.m; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,13 +16,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class MoldgrafScavenger extends CardImpl { public MoldgrafScavenger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.FUNGUS); this.power = new MageInt(0); this.toughness = new MageInt(4); @@ -30,7 +30,8 @@ public final class MoldgrafScavenger extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect( new BoostSourceEffect(3, 0, Duration.WhileOnBattlefield), DeliriumCondition.instance, - "Delirium — {this} gets +3/+0 as long as there are four or more card types among cards in your graveyard"))); + "Delirium — {this} gets +3/+0 as long as there are four or more card types among cards in your graveyard")) + .addHint(DeliriumHint.instance)); } public MoldgrafScavenger(final MoldgrafScavenger card) { diff --git a/Mage.Sets/src/mage/cards/m/MoltenBirth.java b/Mage.Sets/src/mage/cards/m/MoltenBirth.java index 66898ae84d..6fbee1801c 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenBirth.java +++ b/Mage.Sets/src/mage/cards/m/MoltenBirth.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -14,8 +12,9 @@ import mage.game.Game; import mage.game.permanent.token.MoltenBirthElementalToken; import mage.players.Player; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class MoltenBirth extends CardImpl { @@ -57,13 +56,15 @@ class MoltenBirthEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card molten = game.getCard(source.getSourceId()); if (controller != null) { MoltenBirthElementalToken token = new MoltenBirthElementalToken(); token.putOntoBattlefield(2, game, source.getSourceId(), source.getControllerId()); - if (controller.flipCoin(game)) { - molten.moveToZone(Zone.HAND, source.getSourceId(), game, true); - game.informPlayers(controller.getLogName() + " won the flip. " + molten.getLogName() + " is returned to " + controller.getLogName() + "'s hand."); + if (controller.flipCoin(source, game, true)) { + Card molten = game.getCard(source.getSourceId()); + if (molten != null) { + molten.moveToZone(Zone.HAND, source.getSourceId(), game, true); + game.informPlayers(controller.getLogName() + " won the flip. " + molten.getLogName() + " is returned to " + controller.getLogName() + "'s hand."); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/m/MoltenInfluence.java b/Mage.Sets/src/mage/cards/m/MoltenInfluence.java index d7188dba64..05acc1f376 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenInfluence.java +++ b/Mage.Sets/src/mage/cards/m/MoltenInfluence.java @@ -61,7 +61,7 @@ class MoltenInfluenceEffect extends OneShotEffect { if (spell != null) { Player player = game.getPlayer(spell.getControllerId()); String message = "Have Molten Influence do 4 damage to you?"; - if (player.chooseUse(Outcome.Damage, message, source, game)) { + if (player != null && player.chooseUse(Outcome.Damage, message, source, game)) { player.damage(4, source.getSourceId(), game, false, true); return true; } else { diff --git a/Mage.Sets/src/mage/cards/m/MoltenNursery.java b/Mage.Sets/src/mage/cards/m/MoltenNursery.java index dcc0dace26..e0280c34cd 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenNursery.java +++ b/Mage.Sets/src/mage/cards/m/MoltenNursery.java @@ -22,7 +22,7 @@ public final class MoltenNursery extends CardImpl { private static final FilterSpell filter = new FilterSpell("a colorless spell"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public MoltenNursery(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MoltenPrimordial.java b/Mage.Sets/src/mage/cards/m/MoltenPrimordial.java index 58eaca7830..c557bcccf9 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenPrimordial.java +++ b/Mage.Sets/src/mage/cards/m/MoltenPrimordial.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,9 +12,9 @@ import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -23,16 +22,18 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class MoltenPrimordial extends CardImpl { public MoltenPrimordial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(6); @@ -42,23 +43,9 @@ public final class MoltenPrimordial extends CardImpl { this.addAbility(HasteAbility.getInstance()); // When Molten Primordial enters the battlefield, for each opponent, take control of up to one target creature that player controls until end of turn. Untap those creatures. They have haste until end of turn. - this.addAbility(new EntersBattlefieldTriggeredAbility(new MoltenPrimordialEffect(),false)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for(UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()); - filter.add(new ControllerIdPredicate(opponentId)); - TargetCreaturePermanent target = new TargetCreaturePermanent(0,1, filter,false); - ability.addTarget(target); - } - } - } + Ability ability = new EntersBattlefieldTriggeredAbility(new MoltenPrimordialEffect(), false); + ability.setTargetAdjuster(MoltenPrimordialAdjuster.instance); + this.addAbility(ability); } public MoltenPrimordial(final MoltenPrimordial card) { @@ -71,6 +58,24 @@ public final class MoltenPrimordial extends CardImpl { } } +enum MoltenPrimordialAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponentId)); + TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); + ability.addTarget(target); + } + } + } +} + class MoltenPrimordialEffect extends OneShotEffect { public MoltenPrimordialEffect() { @@ -90,7 +95,7 @@ class MoltenPrimordialEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { boolean result = false; - for (Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetCreaturePermanent) { Permanent targetCreature = game.getPermanent(target.getFirstTarget()); if (targetCreature != null) { diff --git a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java index bd9f8b6e8d..b8b6f7f18c 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenPsyche.java +++ b/Mage.Sets/src/mage/cards/m/MoltenPsyche.java @@ -83,11 +83,11 @@ class MoltenPsycheEffect extends OneShotEffect { } } if (MetalcraftCondition.instance.apply(game, source)) { - MoltenPsycheWatcher watcher = (MoltenPsycheWatcher) game.getState().getWatchers().get(MoltenPsycheWatcher.class.getSimpleName()); + MoltenPsycheWatcher watcher = game.getState().getWatcher(MoltenPsycheWatcher.class); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { if (game.isOpponent(controller, playerId)) { Player player = game.getPlayer(playerId); - if (player != null) { + if (player != null && watcher != null) { player.damage(watcher.getDraws(playerId), source.getSourceId(), game, false, true); } } @@ -111,7 +111,7 @@ class MoltenPsycheWatcher extends Watcher { private final Map draws = new HashMap<>(); public MoltenPsycheWatcher() { - super(MoltenPsycheWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MoltenPsycheWatcher(final MoltenPsycheWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/m/MoltenSentry.java b/Mage.Sets/src/mage/cards/m/MoltenSentry.java index c4640f09dc..31ec8892fd 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenSentry.java +++ b/Mage.Sets/src/mage/cards/m/MoltenSentry.java @@ -25,7 +25,7 @@ import mage.players.Player; */ public final class MoltenSentry extends CardImpl { - private final static String rule = "As {this} enters the battlefield, flip a coin. If the coin comes up heads, {this} enters the battlefield as a " + private static final String rule = "As {this} enters the battlefield, flip a coin. If the coin comes up heads, {this} enters the battlefield as a " + "5/2 creature with haste. If it comes up tails, {this} enters the battlefield as a 2/5 creature with defender."; public MoltenSentry(UUID ownerId, CardSetInfo setInfo) { @@ -64,7 +64,7 @@ class MoltenSentryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, false)) { game.informPlayers("Heads: " + permanent.getLogName() + " enters the battlefield as a 5/2 creature with haste"); permanent.getPower().modifyBaseValue(5); permanent.getToughness().modifyBaseValue(2); diff --git a/Mage.Sets/src/mage/cards/m/MoltenSlagheap.java b/Mage.Sets/src/mage/cards/m/MoltenSlagheap.java index a6e3ef4dea..5d339c274a 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenSlagheap.java +++ b/Mage.Sets/src/mage/cards/m/MoltenSlagheap.java @@ -36,7 +36,7 @@ public final class MoltenSlagheap extends CardImpl { this.addAbility(ability); // {1}, Remove X storage counters from Molten Slagheap: Add X mana in any combination of {B} and/or {R}. ability = new SimpleManaAbility(Zone.BATTLEFIELD, - new AddManaInAnyCombinationEffect(new RemovedCountersForCostValue(), ColoredManaSymbol.B, ColoredManaSymbol.R), + new AddManaInAnyCombinationEffect(RemovedCountersForCostValue.instance, ColoredManaSymbol.B, ColoredManaSymbol.R), new GenericManaCost(1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/m/MoltenVortex.java b/Mage.Sets/src/mage/cards/m/MoltenVortex.java index e436857f45..19474d57f0 100644 --- a/Mage.Sets/src/mage/cards/m/MoltenVortex.java +++ b/Mage.Sets/src/mage/cards/m/MoltenVortex.java @@ -1,7 +1,6 @@ package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; @@ -10,23 +9,25 @@ import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; -import mage.filter.common.FilterLandCard; -import mage.target.common.TargetCardInHand; +import mage.filter.StaticFilters; import mage.target.common.TargetAnyTarget; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; /** - * * @author fireshoes */ public final class MoltenVortex extends CardImpl { public MoltenVortex(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R}"); // {R}, Discard a land card: Molten Vortex deals 2 damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), new DiscardTargetCost(new TargetCardInHand(new FilterLandCard()))); - ability.addCost(new ManaCostsImpl("{R}")); + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(2), new ManaCostsImpl("{R}") + ); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(StaticFilters.FILTER_CARD_LAND_A))); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MomentOfSilence.java b/Mage.Sets/src/mage/cards/m/MomentOfSilence.java index 50e275a7ed..6607ae3528 100644 --- a/Mage.Sets/src/mage/cards/m/MomentOfSilence.java +++ b/Mage.Sets/src/mage/cards/m/MomentOfSilence.java @@ -1,11 +1,11 @@ - package mage.cards.m; import java.util.UUID; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.target.TargetPlayer; /** @@ -13,19 +13,19 @@ import mage.target.TargetPlayer; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class MomentOfSilence extends CardImpl { - + public MomentOfSilence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Target player skips their next combat phase this turn. - this.getSpellAbility().addEffect(new SkipNextCombatEffect()); + this.getSpellAbility().addEffect(new SkipCombatStepEffect(Duration.EndOfTurn).setText("Target player skips their next combat this turn")); this.getSpellAbility().addTarget(new TargetPlayer()); } - + public MomentOfSilence(final MomentOfSilence card) { super(card); } - + @Override public MomentOfSilence copy() { return new MomentOfSilence(this); diff --git a/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java b/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java index 4d3f500902..e508cc19b7 100644 --- a/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java +++ b/Mage.Sets/src/mage/cards/m/MonkeyMonkeyMonkey.java @@ -80,8 +80,8 @@ class ChooseLetterEffect extends OneShotEffect { ChoiceImpl choice = new ChoiceImpl(true); choice.setMessage("Choose letter"); Set choices = new HashSet<>(); - for (Character letter = 'A'; letter <= 'Z'; letter++) { - choices.add(letter.toString()); + for (char letter = 'A'; letter <= 'Z'; letter++) { + choices.add(Character.toString(letter)); } choice.setChoices(choices); @@ -122,8 +122,8 @@ class MonkeyMonkeyMonkeyCount implements DynamicValue { if (permanent != null && game.getState().getValue(mageObject.getId() + "_letter") != null) { int letters = 0; for (Permanent p : game.getBattlefield().getActivePermanents(new FilterNonlandPermanent(), sourceAbility.getControllerId(), sourceAbility.getSourceId(), game)) { - Character initial = Character.toUpperCase(p.getName().charAt(0)); - if (initial.toString().equals(game.getState().getValue(mageObject.getId() + "_letter"))) { + char initial = Character.toUpperCase(p.getName().charAt(0)); + if (Character.toString(initial).equals(game.getState().getValue(mageObject.getId() + "_letter"))) { letters++; } } diff --git a/Mage.Sets/src/mage/cards/m/Monsoon.java b/Mage.Sets/src/mage/cards/m/Monsoon.java index 4b91ad79f8..24c52740c5 100644 --- a/Mage.Sets/src/mage/cards/m/Monsoon.java +++ b/Mage.Sets/src/mage/cards/m/Monsoon.java @@ -50,7 +50,7 @@ class MonsoonEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterPermanent(); static { filter.add(new SubtypePredicate(SubType.ISLAND)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MonsoonEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MonstrousHound.java b/Mage.Sets/src/mage/cards/m/MonstrousHound.java new file mode 100644 index 0000000000..cdebb8caa7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MonstrousHound.java @@ -0,0 +1,138 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.RestrictionEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author jeffwadsworth + */ +public final class MonstrousHound extends CardImpl { + + public MonstrousHound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HOUND); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Monstrous Hound can't attack unless you control more lands than defending player. + Effect effect = new CantAttackUnlessControllerControlsMoreLandsEffect(); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + effect.setText("{this} can't attack unless you control more lands than defending player"))); + + // Monstrous Hound can't block unless you control more lands than attacking player. + Effect effect2 = new CantBlockUnlessControllerControlsMoreLandsEffect(); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + effect2.setText("{this} can't block unless you control more lands than attacking player"))); + + } + + public MonstrousHound(final MonstrousHound card) { + super(card); + } + + @Override + public MonstrousHound copy() { + return new MonstrousHound(this); + } +} + +class CantAttackUnlessControllerControlsMoreLandsEffect extends RestrictionEffect { + + CantAttackUnlessControllerControlsMoreLandsEffect() { + super(Duration.WhileOnBattlefield); + } + + CantAttackUnlessControllerControlsMoreLandsEffect(final CantAttackUnlessControllerControlsMoreLandsEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } + + @Override + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + + UUID defendingPlayerId; + Player defender = game.getPlayer(defenderId); + if (defender == null) { + Permanent permanent = game.getPermanent(defenderId); + if (permanent != null) { + defendingPlayerId = permanent.getControllerId(); + } else { + return false; + } + } else { + defendingPlayerId = defenderId; + } + if (defendingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledLandPermanent(), + source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledLandPermanent(), + defendingPlayerId, game); + } else { + return true; + } + } + + @Override + public CantAttackUnlessControllerControlsMoreLandsEffect copy() { + return new CantAttackUnlessControllerControlsMoreLandsEffect(this); + } +} + +class CantBlockUnlessControllerControlsMoreLandsEffect extends RestrictionEffect { + + CantBlockUnlessControllerControlsMoreLandsEffect() { + super(Duration.WhileOnBattlefield); + } + + CantBlockUnlessControllerControlsMoreLandsEffect(final CantBlockUnlessControllerControlsMoreLandsEffect effect) { + super(effect); + } + + @Override + public CantBlockUnlessControllerControlsMoreLandsEffect copy() { + return new CantBlockUnlessControllerControlsMoreLandsEffect(this); + } + + @Override + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } + UUID attackingPlayerId = attacker.getControllerId(); + if (attackingPlayerId != null) { + return game.getBattlefield().countAll(new FilterControlledLandPermanent(), + source.getControllerId(), game) > game.getBattlefield().countAll(new FilterControlledLandPermanent(), + attackingPlayerId, game); + } + return true; + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MonstrousOnslaught.java b/Mage.Sets/src/mage/cards/m/MonstrousOnslaught.java index 77087fd624..28f7226af5 100644 --- a/Mage.Sets/src/mage/cards/m/MonstrousOnslaught.java +++ b/Mage.Sets/src/mage/cards/m/MonstrousOnslaught.java @@ -21,7 +21,7 @@ public final class MonstrousOnslaught extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); // Monstrous Onslaught deals X damage divided as you choose among any number of target creatures, where X is the greatest power among creatures you control as you cast Monstrous Onslaught. - DynamicValue xValue = new GreatestPowerAmongControlledCreaturesValue(); + DynamicValue xValue = GreatestPowerAmongControlledCreaturesValue.instance; Effect effect = new DamageMultiEffect(xValue); effect.setText("{this} deals X damage divided as you choose among any number of target creatures, where X is the greatest power among creatures you control as you cast {this}"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/m/MoonlightHunt.java b/Mage.Sets/src/mage/cards/m/MoonlightHunt.java index 1a4d3aa743..a5d51d980e 100644 --- a/Mage.Sets/src/mage/cards/m/MoonlightHunt.java +++ b/Mage.Sets/src/mage/cards/m/MoonlightHunt.java @@ -25,7 +25,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class MoonlightHunt extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); @@ -51,7 +51,7 @@ public final class MoonlightHunt extends CardImpl { class MoonlightHuntEffect extends OneShotEffect { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(Predicates.or(new SubtypePredicate(SubType.WOLF), new SubtypePredicate(SubType.WEREWOLF))); diff --git a/Mage.Sets/src/mage/cards/m/Moonmist.java b/Mage.Sets/src/mage/cards/m/Moonmist.java index 8b199cf09f..a90d6b45d6 100644 --- a/Mage.Sets/src/mage/cards/m/Moonmist.java +++ b/Mage.Sets/src/mage/cards/m/Moonmist.java @@ -71,7 +71,7 @@ class MoonmistEffect extends OneShotEffect { for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { if (permanent.isTransformable()) { permanent.transform(game); - game.informPlayers(new StringBuilder(permanent.getName()).append(" transforms into ").append(permanent.getSecondCardFace().getName()).toString()); + game.informPlayers(permanent.getName() + " transforms into " + permanent.getSecondCardFace().getName()); } } return true; diff --git a/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java b/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java index b0bf0de8ee..3c5936be5f 100644 --- a/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java +++ b/Mage.Sets/src/mage/cards/m/MoorlandDrifter.java @@ -1,12 +1,13 @@ - package mage.cards.m; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,20 +16,19 @@ import mage.constants.SubType; import mage.constants.Zone; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class MoorlandDrifter extends CardImpl { public MoorlandDrifter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(2); this.toughness = new MageInt(2); // Delirium — Moorland Drifter has flying as long as there are four or more card types among cards in your graveyard. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), DeliriumCondition.instance, "Delirium — Moorland Drifter has flying as long as there are four or more card types among cards in your graveyard."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FlyingAbility.getInstance()), DeliriumCondition.instance, "Delirium — Moorland Drifter has flying as long as there are four or more card types among cards in your graveyard."); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(DeliriumHint.instance)); } public MoorlandDrifter(final MoorlandDrifter card) { diff --git a/Mage.Sets/src/mage/cards/m/MorgueBurst.java b/Mage.Sets/src/mage/cards/m/MorgueBurst.java index cefb0142fa..6637ed626e 100644 --- a/Mage.Sets/src/mage/cards/m/MorgueBurst.java +++ b/Mage.Sets/src/mage/cards/m/MorgueBurst.java @@ -83,8 +83,6 @@ class MorgueBurstEffect extends OneShotEffect { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append("Return target creature card from your graveyard to your hand. Morgue Burst deals damage to any target equal to the power of the card returned this way"); - return sb.toString(); + return "Return target creature card from your graveyard to your hand. Morgue Burst deals damage to any target equal to the power of the card returned this way"; } } diff --git a/Mage.Sets/src/mage/cards/m/MoriokScavenger.java b/Mage.Sets/src/mage/cards/m/MoriokScavenger.java index efc4865b8c..a2ef0d4733 100644 --- a/Mage.Sets/src/mage/cards/m/MoriokScavenger.java +++ b/Mage.Sets/src/mage/cards/m/MoriokScavenger.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class MoriokScavenger extends CardImpl { - final static FilterCreatureCard filter = new FilterCreatureCard("artifact creature card from your graveyard"); + static final FilterCreatureCard filter = new FilterCreatureCard("artifact creature card from your graveyard"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/m/MorkrutNecropod.java b/Mage.Sets/src/mage/cards/m/MorkrutNecropod.java index 7bffaa9327..08a609f0ed 100644 --- a/Mage.Sets/src/mage/cards/m/MorkrutNecropod.java +++ b/Mage.Sets/src/mage/cards/m/MorkrutNecropod.java @@ -27,7 +27,7 @@ public final class MorkrutNecropod extends CardImpl { filter.add(Predicates.or( new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.LAND))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MorkrutNecropod(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MortalObstinacy.java b/Mage.Sets/src/mage/cards/m/MortalObstinacy.java index 04530a8a01..41f87f79e1 100644 --- a/Mage.Sets/src/mage/cards/m/MortalObstinacy.java +++ b/Mage.Sets/src/mage/cards/m/MortalObstinacy.java @@ -92,7 +92,7 @@ class MortalObstinacyAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever enchanted creature deals combat damage to a player, ").append(super.getRule()).toString(); + return "Whenever enchanted creature deals combat damage to a player, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/m/Mortuary.java b/Mage.Sets/src/mage/cards/m/Mortuary.java index f1aa17f080..22797d4d4f 100644 --- a/Mage.Sets/src/mage/cards/m/Mortuary.java +++ b/Mage.Sets/src/mage/cards/m/Mortuary.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.PutOnLibraryTargetEffect; @@ -10,8 +8,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author HCrescent */ public final class Mortuary extends CardImpl { @@ -19,9 +18,9 @@ public final class Mortuary extends CardImpl { public Mortuary(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); - - Ability ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(new PutOnLibraryTargetEffect(true, "put that card on top of your library."), false, StaticFilters.FILTER_PERMANENT_CREATURE, true, true); + // Whenever a creature is put into your graveyard from the battlefield, put that card on top of your library. + Ability ability = new PutIntoGraveFromBattlefieldAllTriggeredAbility(new PutOnLibraryTargetEffect(true, "put that card on top of your library."), false, StaticFilters.FILTER_PERMANENT_CREATURE, true, true); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java index 1790367c6a..2218db67e6 100644 --- a/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java +++ b/Mage.Sets/src/mage/cards/m/MossbridgeTroll.java @@ -36,7 +36,7 @@ public final class MossbridgeTroll extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MossbridgeTroll(UUID ownerId, CardSetInfo setInfo) { @@ -109,8 +109,8 @@ class MossbridgeTrollCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("any number of untapped creatures other than {this} with total power 10 or greater"); static { - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TappedPredicate.instance)); } public MossbridgeTrollCost() { @@ -133,7 +133,7 @@ class MossbridgeTrollCost extends CostImpl { } } } - game.informPlayers(new StringBuilder("Tap creatures with total power of ").append(sumPower).toString()); + game.informPlayers("Tap creatures with total power of " + sumPower); paid = sumPower >= 10; return paid; } diff --git a/Mage.Sets/src/mage/cards/m/MothdustChangeling.java b/Mage.Sets/src/mage/cards/m/MothdustChangeling.java index 9f645fe8eb..6f276339b1 100644 --- a/Mage.Sets/src/mage/cards/m/MothdustChangeling.java +++ b/Mage.Sets/src/mage/cards/m/MothdustChangeling.java @@ -27,7 +27,7 @@ public final class MothdustChangeling extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MothdustChangeling(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MountainStronghold.java b/Mage.Sets/src/mage/cards/m/MountainStronghold.java new file mode 100644 index 0000000000..64775cba11 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MountainStronghold.java @@ -0,0 +1,47 @@ + +package mage.cards.m; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class MountainStronghold extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Red legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.RED)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public MountainStronghold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Red legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public MountainStronghold(final MountainStronghold card) { + super(card); + } + + @Override + public MountainStronghold copy() { + return new MountainStronghold(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/Mournwillow.java b/Mage.Sets/src/mage/cards/m/Mournwillow.java index 5a1fe7ec50..f4c83d13ea 100644 --- a/Mage.Sets/src/mage/cards/m/Mournwillow.java +++ b/Mage.Sets/src/mage/cards/m/Mournwillow.java @@ -1,30 +1,30 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.RestrictionEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class Mournwillow extends CardImpl { public Mournwillow(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{G}"); this.subtype.add(SubType.PLANT); this.subtype.add(SubType.SKELETON); this.power = new MageInt(3); @@ -39,7 +39,8 @@ public final class Mournwillow extends CardImpl { new EntersBattlefieldTriggeredAbility(new MournwillowEffect(), false), DeliriumCondition.instance, "Delirium — When {this} enters the battlefield, if there are four or more card types among cards in your graveyard, " - + "creatures with power 2 or less can't block this turn."); + + "creatures with power 2 or less can't block this turn."); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } @@ -75,7 +76,7 @@ class MournwillowEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/m/MouthFeed.java b/Mage.Sets/src/mage/cards/m/MouthFeed.java index 17fabe507f..c154c52090 100644 --- a/Mage.Sets/src/mage/cards/m/MouthFeed.java +++ b/Mage.Sets/src/mage/cards/m/MouthFeed.java @@ -38,7 +38,7 @@ public final class MouthFeed extends SplitCard { // to // Feed // Draw a card for each creature you control with power 3 or greater - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); Effect draw = new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(filterCreaturesYouControlPower3orGreater)); getRightHalfCard().getSpellAbility().addEffect(draw); diff --git a/Mage.Sets/src/mage/cards/m/MowuLoyalCompanion.java b/Mage.Sets/src/mage/cards/m/MowuLoyalCompanion.java new file mode 100644 index 0000000000..6b3fdc2c7c --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/MowuLoyalCompanion.java @@ -0,0 +1,102 @@ +package mage.cards.m; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.keyword.TrampleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class MowuLoyalCompanion extends CardImpl { + + public MowuLoyalCompanion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HOUND); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // If one or more +1/+1 counters would be put on Mowu, Loyal Companion, that many plus one +1/+1 counters are put on it instead. + this.addAbility(new SimpleStaticAbility(new MowuLoyalCompanionEffect())); + } + + private MowuLoyalCompanion(final MowuLoyalCompanion card) { + super(card); + } + + @Override + public MowuLoyalCompanion copy() { + return new MowuLoyalCompanion(this); + } +} + +class MowuLoyalCompanionEffect extends ReplacementEffectImpl { + + MowuLoyalCompanionEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature, false); + staticText = "If one or more +1/+1 counters would be put on {this}, " + + "that many plus one +1/+1 counters are put on it instead"; + } + + private MowuLoyalCompanionEffect(final MowuLoyalCompanionEffect effect) { + super(effect); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int amount = event.getAmount(); + if (amount > 0) { + event.setAmount(amount + 1); + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ADD_COUNTERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getData().equals(CounterType.P1P1.getName())) { + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null && permanent.getId().equals(source.getSourceId()) + && permanent.isCreature()) { + return true; + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public MowuLoyalCompanionEffect copy() { + return new MowuLoyalCompanionEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MudbrawlerCohort.java b/Mage.Sets/src/mage/cards/m/MudbrawlerCohort.java index a8ff123ee6..1d0ddf8e5c 100644 --- a/Mage.Sets/src/mage/cards/m/MudbrawlerCohort.java +++ b/Mage.Sets/src/mage/cards/m/MudbrawlerCohort.java @@ -34,7 +34,7 @@ public final class MudbrawlerCohort extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.RED)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MudbrawlerCohort(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/Mudslide.java b/Mage.Sets/src/mage/cards/m/Mudslide.java index c63e74715d..84d3855ead 100644 --- a/Mage.Sets/src/mage/cards/m/Mudslide.java +++ b/Mage.Sets/src/mage/cards/m/Mudslide.java @@ -65,7 +65,7 @@ class MudslideEffect extends OneShotEffect { static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } MudslideEffect() { diff --git a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java index f80bf2ab4d..fc55065416 100644 --- a/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java +++ b/Mage.Sets/src/mage/cards/m/MuldrothaTheGravetide.java @@ -88,7 +88,7 @@ class MuldrothaTheGravetideCastFromGraveyardEffect extends AsThoughEffectImpl { && source.isControlledBy(game.getOwnerId(objectId)) // only from your graveyard && affectedControllerId.equals(game.getActivePlayerId()) // only during your turns (e.g. prevent flash creatures) && Zone.GRAVEYARD.equals(game.getState().getZone(objectId))) { - MuldrothaTheGravetideWatcher watcher = (MuldrothaTheGravetideWatcher) game.getState().getWatchers().get(MuldrothaTheGravetideWatcher.class.getSimpleName()); + MuldrothaTheGravetideWatcher watcher = game.getState().getWatcher(MuldrothaTheGravetideWatcher.class); MageObject mageObject = game.getObject(objectId); if (mageObject != null && watcher != null) { for (CardType cardType : mageObject.getCardType()) { @@ -112,7 +112,7 @@ class MuldrothaTheGravetideCastFromGraveyardEffect extends AsThoughEffectImpl { */ class MuldrothaTheGravetideWatcher extends Watcher { - final HashMap> sourcePlayedPermanentTypes = new HashMap<>(); // source that played permanent types from graveyard + private final HashMap> sourcePlayedPermanentTypes = new HashMap<>(); // source that played permanent types from graveyard // final HashMap> playerPlayedPermanentTypes = new HashMap<>(); // player that played permanent types from graveyard // 4/27/2018 If multiple effects allow you to play a card from your graveyard, such as those of Gisa and Geralf and Karador, // Ghost Chieftain, you must announce which permission you're using as you begin to play the card. @@ -121,7 +121,7 @@ class MuldrothaTheGravetideWatcher extends Watcher { private Zone fromZone; public MuldrothaTheGravetideWatcher() { - super(MuldrothaTheGravetideWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MuldrothaTheGravetideWatcher(final MuldrothaTheGravetideWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/m/MultaniMaroSorcerer.java b/Mage.Sets/src/mage/cards/m/MultaniMaroSorcerer.java index 63949d9ba9..d2e45d955e 100644 --- a/Mage.Sets/src/mage/cards/m/MultaniMaroSorcerer.java +++ b/Mage.Sets/src/mage/cards/m/MultaniMaroSorcerer.java @@ -33,7 +33,7 @@ public final class MultaniMaroSorcerer extends CardImpl { this.addAbility(ShroudAbility.getInstance()); // Multani, Maro-Sorcerer's power and toughness are each equal to the total number of cards in all players' hands. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInAllHandsCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CardsInAllHandsCount.instance, Duration.EndOfGame))); } public MultaniMaroSorcerer(final MultaniMaroSorcerer card) { diff --git a/Mage.Sets/src/mage/cards/m/MultanisDecree.java b/Mage.Sets/src/mage/cards/m/MultanisDecree.java index 637e51995f..1286263e5e 100644 --- a/Mage.Sets/src/mage/cards/m/MultanisDecree.java +++ b/Mage.Sets/src/mage/cards/m/MultanisDecree.java @@ -62,7 +62,7 @@ class MultanisDecreeDestroyEffect extends OneShotEffect { enchantmentsDestoyed++; } } - if(enchantmentsDestoyed > 0) { + if(enchantmentsDestoyed > 0 && controller != null) { controller.gainLife(enchantmentsDestoyed * 2, game, source); } return false; diff --git a/Mage.Sets/src/mage/cards/m/MultanisPresence.java b/Mage.Sets/src/mage/cards/m/MultanisPresence.java index 2ad766fea5..3000f24d96 100644 --- a/Mage.Sets/src/mage/cards/m/MultanisPresence.java +++ b/Mage.Sets/src/mage/cards/m/MultanisPresence.java @@ -1,10 +1,8 @@ package mage.cards.m; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; +import java.util.*; + import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.cards.CardImpl; @@ -62,8 +60,8 @@ class MultanisPresenceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - MultanisPresenceWatcher watcher = (MultanisPresenceWatcher) game.getState().getWatchers().get(MultanisPresenceWatcher.class.getSimpleName()); - return (watcher.getSpellsCastThisTurn(controllerId).contains(event.getTargetId())); + MultanisPresenceWatcher watcher = game.getState().getWatcher(MultanisPresenceWatcher.class); + return watcher != null && watcher.getSpellsCastThisTurn(controllerId).contains(event.getTargetId()); } @Override @@ -74,10 +72,10 @@ class MultanisPresenceTriggeredAbility extends TriggeredAbilityImpl { class MultanisPresenceWatcher extends Watcher { - private final HashMap> spellsCast = new HashMap<>(); + private final Map> spellsCast = new HashMap<>(); public MultanisPresenceWatcher() { - super(MultanisPresenceWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MultanisPresenceWatcher(final MultanisPresenceWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/m/MummyParamount.java b/Mage.Sets/src/mage/cards/m/MummyParamount.java index e48d48455c..4555272f37 100644 --- a/Mage.Sets/src/mage/cards/m/MummyParamount.java +++ b/Mage.Sets/src/mage/cards/m/MummyParamount.java @@ -23,7 +23,7 @@ public final class MummyParamount extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another Zombie"); static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MummyParamount(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MundasVanguard.java b/Mage.Sets/src/mage/cards/m/MundasVanguard.java index b2c05c34b7..52708a4928 100644 --- a/Mage.Sets/src/mage/cards/m/MundasVanguard.java +++ b/Mage.Sets/src/mage/cards/m/MundasVanguard.java @@ -32,7 +32,7 @@ public final class MundasVanguard extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public MundasVanguard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java index 169a2b55ee..b26b8ec57f 100644 --- a/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java +++ b/Mage.Sets/src/mage/cards/m/MurderousCompulsion.java @@ -18,10 +18,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class MurderousCompulsion extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public MurderousCompulsion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MurmuringMystic.java b/Mage.Sets/src/mage/cards/m/MurmuringMystic.java index e68836883f..68ef0c9f87 100644 --- a/Mage.Sets/src/mage/cards/m/MurmuringMystic.java +++ b/Mage.Sets/src/mage/cards/m/MurmuringMystic.java @@ -1,18 +1,18 @@ package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.permanent.token.BirdIllusionToken; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class MurmuringMystic extends CardImpl { @@ -28,7 +28,7 @@ public final class MurmuringMystic extends CardImpl { // Whenever you cast an instant or sorcery spell, create a 1/1 blue Bird Illusion creature token with flying. this.addAbility(new SpellCastControllerTriggeredAbility( new CreateTokenEffect(new BirdIllusionToken()), - StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false )); } diff --git a/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java b/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java index 8d829a6831..5018a530ce 100644 --- a/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java +++ b/Mage.Sets/src/mage/cards/m/MurmursFromBeyond.java @@ -64,8 +64,7 @@ class MurmursFromBeyondEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 3)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); if (!cards.isEmpty()) { controller.revealCards(staticText, cards, game); Card cardToGraveyard; diff --git a/Mage.Sets/src/mage/cards/m/Musician.java b/Mage.Sets/src/mage/cards/m/Musician.java new file mode 100644 index 0000000000..4b99c7b004 --- /dev/null +++ b/Mage.Sets/src/mage/cards/m/Musician.java @@ -0,0 +1,134 @@ +package mage.cards.m; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.constants.SubType; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.abilities.effects.common.DoUnlessControllerPaysEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class Musician extends CardImpl { + + public Musician(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Cumulative upkeep {1} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); + + // {tap}: Put a music counter on target creature. If it doesn't have "At the beginning of your upkeep, destroy this creature unless you pay {1} for each music counter on it," it gains that ability. + Effect effect = new DoUnlessControllerPaysEffect( + new DestroySourceEffect(), + new DynamicValueGenericManaCost( + new CountersSourceCount( + CounterType.MUSIC))); + effect.setText("destroy this creature unless you pay {1} for each music counter on it"); + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, + effect, + TargetController.YOU, + false, + false, + "At the beginning of your upkeep, "); + Effect effect2 = new AddCountersTargetEffect(CounterType.MUSIC.createInstance()); + effect2.setText("Put a music counter on target creature"); + Effect effect3 = new GainAbilityTargetEffect( + ability, + Duration.WhileOnBattlefield); + effect3.setText("If it doesn't have \"At the beginning of your upkeep, destroy this creature unless you pay {1} for each music counter on it,\" it gains that ability"); + Ability ability2 = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + effect2, + new TapSourceCost()); + ability2.addTarget(new TargetCreaturePermanent()); + ability2.addEffect(effect3); + this.addAbility(ability2); + + } + + private Musician(final Musician card) { + super(card); + } + + @Override + public Musician copy() { + return new Musician(this); + } +} + +class DynamicValueGenericManaCost extends CostImpl { + + DynamicValue amount; + + public DynamicValueGenericManaCost(DynamicValue amount) { + this.amount = amount; + setText(); + } + + public DynamicValueGenericManaCost(DynamicValueGenericManaCost cost) { + super(cost); + this.amount = cost.amount; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + return cost.canPay(ability, sourceId, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + if (controller != null) { + paid = cost.pay(ability, game, sourceId, controllerId, noMana); + } + return paid; + } + + @Override + public DynamicValueGenericManaCost copy() { + return new DynamicValueGenericManaCost(this); + } + + private void setText() { + text = ("{1} for each music counter on {this}"); + } +} diff --git a/Mage.Sets/src/mage/cards/m/MycosynthFiend.java b/Mage.Sets/src/mage/cards/m/MycosynthFiend.java index ddeaa5a478..99d1ecdfb5 100644 --- a/Mage.Sets/src/mage/cards/m/MycosynthFiend.java +++ b/Mage.Sets/src/mage/cards/m/MycosynthFiend.java @@ -27,7 +27,7 @@ public final class MycosynthFiend extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - DynamicValue value = new OpponentsPoisonCountersCount(); + DynamicValue value = OpponentsPoisonCountersCount.instance; this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(value, value, Duration.WhileOnBattlefield))); } diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfCleansingFire.java b/Mage.Sets/src/mage/cards/m/MyojinOfCleansingFire.java index 923b7ab694..6bad3165ae 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfCleansingFire.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfCleansingFire.java @@ -34,7 +34,7 @@ public final class MyojinOfCleansingFire extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public MyojinOfCleansingFire(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/m/MyojinOfNightsReach.java b/Mage.Sets/src/mage/cards/m/MyojinOfNightsReach.java index b5c642008d..9f6f424fd3 100644 --- a/Mage.Sets/src/mage/cards/m/MyojinOfNightsReach.java +++ b/Mage.Sets/src/mage/cards/m/MyojinOfNightsReach.java @@ -74,8 +74,10 @@ class MyojinOfNightsReachEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { Player opponent = game.getPlayer(opponentId); - for (Card c : opponent.getHand().getCards(game)) { - opponent.discard(c, source, game); + if(opponent != null) { + for (Card c : opponent.getHand().getCards(game)) { + opponent.discard(c, source, game); + } } } return true; diff --git a/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java b/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java index 8349c70f48..b43eed17cc 100644 --- a/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java +++ b/Mage.Sets/src/mage/cards/m/MyrBattlesphere.java @@ -105,7 +105,7 @@ class MyrBattlesphereEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Myr you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.MYR)); } @@ -125,7 +125,7 @@ class MyrBattlesphereEffect extends OneShotEffect { Permanent myr = game.getPermanentOrLKIBattlefield(source.getSourceId()); int tappedAmount = 0; TargetPermanent target = new TargetPermanent(0, 1, filter, true); - while (true && controller.canRespond()) { + while (controller.canRespond()) { target.clearChosen(); if (target.canChoose(source.getControllerId(), game)) { Map options = new HashMap<>(); @@ -145,7 +145,7 @@ class MyrBattlesphereEffect extends OneShotEffect { } } if (tappedAmount > 0) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" taps ").append(tappedAmount).append(" Myrs").toString()); + game.informPlayers(controller.getLogName() + " taps " + tappedAmount + " Myrs"); // boost effect game.addEffect(new BoostSourceEffect(tappedAmount, 0, Duration.EndOfTurn), source); // damage to defender diff --git a/Mage.Sets/src/mage/cards/m/MyrIncubator.java b/Mage.Sets/src/mage/cards/m/MyrIncubator.java index 916a4f0e9d..a8996c7b95 100644 --- a/Mage.Sets/src/mage/cards/m/MyrIncubator.java +++ b/Mage.Sets/src/mage/cards/m/MyrIncubator.java @@ -72,7 +72,7 @@ class MyrIncubatorEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null - && controller.searchLibrary(target, game)) { + && controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { tokensToCreate = target.getTargets().size(); controller.moveCards(new CardsImpl(target.getTargets()), Zone.EXILED, source, game); diff --git a/Mage.Sets/src/mage/cards/m/MyriadLandscape.java b/Mage.Sets/src/mage/cards/m/MyriadLandscape.java index 10de4a54c7..be5c3e2e26 100644 --- a/Mage.Sets/src/mage/cards/m/MyriadLandscape.java +++ b/Mage.Sets/src/mage/cards/m/MyriadLandscape.java @@ -1,7 +1,6 @@ - package mage.cards.m; -import java.util.ArrayList; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -17,24 +16,23 @@ import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.game.Game; -import mage.target.common.TargetCardInLibrary; -import mage.util.SubTypeList; - -import java.util.Iterator; -import java.util.List; -import java.util.UUID; -import mage.MageObject; -import mage.constants.SuperType; import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInLibrary; +import mage.util.SubTypeList; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; /** - * * @author LevelX2 */ public final class MyriadLandscape extends CardImpl { @@ -70,19 +68,19 @@ public final class MyriadLandscape extends CardImpl { class TargetCardInLibrarySharingLandType extends TargetCardInLibrary { - private static final FilterCard filter = new FilterCard("basic land card"); + private static final FilterCard filterBasicLandCard = new FilterCard("basic land card"); static { List> subTypePreds = new ArrayList<>(); - for (SubType landType : SubType.getLandTypes(false)) { + for (SubType landType : SubType.getLandTypes()) { subTypePreds.add(new SubtypePredicate(landType)); } - filter.add(Predicates.or(subTypePreds)); - filter.add(new SupertypePredicate(SuperType.BASIC)); + filterBasicLandCard.add(Predicates.or(subTypePreds)); + filterBasicLandCard.add(new SupertypePredicate(SuperType.BASIC)); } public TargetCardInLibrarySharingLandType(int minNumTargets, int maxNumTargets) { - super(minNumTargets, maxNumTargets, filter); + super(minNumTargets, maxNumTargets, filterBasicLandCard); } public TargetCardInLibrarySharingLandType(final TargetCardInLibrarySharingLandType target) { @@ -107,7 +105,7 @@ class TargetCardInLibrarySharingLandType extends TargetCardInLibrary { } Card card = game.getCard(id); if (card != null && !landTypes.isEmpty()) { - for (Iterator iterator = landTypes.iterator(); iterator.hasNext();) { + for (Iterator iterator = landTypes.iterator(); iterator.hasNext(); ) { SubType next = iterator.next(); if (card.hasSubtype(next, game)) { return true; diff --git a/Mage.Sets/src/mage/cards/m/MysticConfluence.java b/Mage.Sets/src/mage/cards/m/MysticConfluence.java index 0617f72617..71defae9ed 100644 --- a/Mage.Sets/src/mage/cards/m/MysticConfluence.java +++ b/Mage.Sets/src/mage/cards/m/MysticConfluence.java @@ -33,13 +33,13 @@ public final class MysticConfluence extends CardImpl { // Return target creature to its owner's hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Draw a card. mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(1)); + mode.addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/m/MythUnbound.java b/Mage.Sets/src/mage/cards/m/MythUnbound.java index 28924a6075..86e13abb32 100644 --- a/Mage.Sets/src/mage/cards/m/MythUnbound.java +++ b/Mage.Sets/src/mage/cards/m/MythUnbound.java @@ -32,7 +32,7 @@ public final class MythUnbound extends CardImpl { private static final FilterPermanent filter = new FilterPermanent(); static { - filter.add(new CommanderPredicate()); + filter.add(CommanderPredicate.instance); filter.add(new OwnerPredicate(TargetController.YOU)); } @@ -78,9 +78,9 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - Ability spellAbility = (SpellAbility) abilityToModify; + Ability spellAbility = abilityToModify; if (spellAbility != null) { - Integer amount = (Integer) game.getState().getValue(abilityToModify.getControllerId() + "_castCount"); + Integer amount = (Integer) game.getState().getValue(abilityToModify.getSourceId() + "_castCount"); if (amount != null && amount > 0) { CardUtil.reduceCost(spellAbility, amount); return true; @@ -99,7 +99,7 @@ class MythUnboundCostReductionEffect extends CostModificationEffectImpl { if (abilityToModify.isControlledBy(source.getControllerId())) { Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); if (spell != null) { - return player.getCommandersIds().contains(spell.getId()); + return player.getCommandersIds().contains(spell.getSourceId()); } } } diff --git a/Mage.Sets/src/mage/cards/n/N1Starfighter.java b/Mage.Sets/src/mage/cards/n/N1Starfighter.java index 85284b54fc..bd50c4d84f 100644 --- a/Mage.Sets/src/mage/cards/n/N1Starfighter.java +++ b/Mage.Sets/src/mage/cards/n/N1Starfighter.java @@ -28,7 +28,7 @@ public final class N1Starfighter extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public N1Starfighter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NacreTalisman.java b/Mage.Sets/src/mage/cards/n/NacreTalisman.java index e995f40a39..439180b1c7 100644 --- a/Mage.Sets/src/mage/cards/n/NacreTalisman.java +++ b/Mage.Sets/src/mage/cards/n/NacreTalisman.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class NacreTalisman extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a white spell"); + private static final FilterSpell filter = new FilterSpell("a white spell"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); diff --git a/Mage.Sets/src/mage/cards/n/NagaEternal.java b/Mage.Sets/src/mage/cards/n/NagaEternal.java new file mode 100644 index 0000000000..4652ca3e8f --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NagaEternal.java @@ -0,0 +1,33 @@ +package mage.cards.n; + +import mage.MageInt; +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 NagaEternal extends CardImpl { + + public NagaEternal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.NAGA); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + } + + private NagaEternal(final NagaEternal card) { + super(card); + } + + @Override + public NagaEternal copy() { + return new NagaEternal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java b/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java new file mode 100644 index 0000000000..0b044b2aea --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NahiriStormOfStone.java @@ -0,0 +1,109 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayVariableLoyaltyCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.cost.AbilitiesCostReductionControllerEffect; +import mage.abilities.keyword.EquipAbility; +import mage.abilities.keyword.FirstStrikeAbility; +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.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NahiriStormOfStone extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped creature"); + + static { + filter.add(TappedPredicate.instance); + } + + public NahiriStormOfStone(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R/W}{R/W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NAHIRI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(6)); + + // As long as it's your turn, creatures you control have first strike and equip abilities you activate cost {1} less to activate. + Ability ability = new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityControlledEffect( + FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE + ), MyTurnCondition.instance, "As long as it's your turn, " + + "creatures you control have first strike" + )); + ability.addEffect(new ConditionalContinuousEffect( + new AbilitiesCostReductionControllerEffect( + EquipAbility.class, "Equip" + ), MyTurnCondition.instance, "and equip abilities you activate cost {1} less to activate" + )); + this.addAbility(ability); + + // -X: Nahiri, Storm of Stone deals X damage to target tapped creature. + ability = new LoyaltyAbility(new DamageTargetEffect(NahiriStormOfStoneValue.instance)); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private NahiriStormOfStone(final NahiriStormOfStone card) { + super(card); + } + + @Override + public NahiriStormOfStone copy() { + return new NahiriStormOfStone(this); + } +} + +enum NahiriStormOfStoneValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + for (Cost cost : sourceAbility.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + return ((PayVariableLoyaltyCost) cost).getAmount(); + } + } + return 0; + } + + @Override + public DynamicValue copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java b/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java index c0dd70f67e..693c492a3c 100644 --- a/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java +++ b/Mage.Sets/src/mage/cards/n/NahiriTheHarbinger.java @@ -1,4 +1,3 @@ - package mage.cards.n; import java.util.UUID; @@ -49,13 +48,13 @@ public final class NahiriTheHarbinger extends CardImpl { static { filter.add(Predicates.or(new CardTypePredicate(CardType.ENCHANTMENT), (Predicates.and(new CardTypePredicate(CardType.ARTIFACT), - new TappedPredicate())), + TappedPredicate.instance)), (Predicates.and(new CardTypePredicate(CardType.CREATURE), - new TappedPredicate())))); + TappedPredicate.instance)))); } public NahiriTheHarbinger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.PLANESWALKER},"{2}{R}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{W}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.NAHIRI); @@ -111,19 +110,21 @@ class NahiriTheHarbingerEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); - controller.moveCards(card, Zone.BATTLEFIELD, source, game); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - effect.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); - game.addEffect(effect, source); - Effect effect2 = new ReturnToHandTargetEffect(); - effect2.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect2); - game.addDelayedTriggeredAbility(delayedAbility, source); + if (card != null) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); + game.addEffect(effect, source); + Effect effect2 = new ReturnToHandTargetEffect(); + effect2.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect2); + game.addDelayedTriggeredAbility(delayedAbility, source); + } } } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/n/NahirisStoneblades.java b/Mage.Sets/src/mage/cards/n/NahirisStoneblades.java new file mode 100644 index 0000000000..6bc34f7402 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NahirisStoneblades.java @@ -0,0 +1,35 @@ +package mage.cards.n; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 NahirisStoneblades extends CardImpl { + + public NahirisStoneblades(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Up to two target creatures each get +2/+0 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 0, Duration.EndOfTurn + ).setText("Up to two target creatures each get +2/+0 until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); + } + + private NahirisStoneblades(final NahirisStoneblades card) { + super(card); + } + + @Override + public NahirisStoneblades copy() { + return new NahirisStoneblades(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NahirisWrath.java b/Mage.Sets/src/mage/cards/n/NahirisWrath.java index e23c093552..3777758cfe 100644 --- a/Mage.Sets/src/mage/cards/n/NahirisWrath.java +++ b/Mage.Sets/src/mage/cards/n/NahirisWrath.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.VariableCost; @@ -19,38 +18,26 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class NahirisWrath extends CardImpl { public NahirisWrath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); // As an additional cost to cast Nahiri's Wrath, discard X cards. this.getSpellAbility().addCost(new NahirisWrathAdditionalCost()); // Nahiri's Wrath deals damage equal to the total converted mana cost of the discarded cards to each of up to X target creatures and/or planeswalkers. - Effect effect = new DamageTargetEffect(new DiscardCostCardConvertedMana()); + Effect effect = new DamageTargetEffect(DiscardCostCardConvertedMana.instance); effect.setText("{this} deals damage equal to the total converted mana cost of the discarded cards to each of up to X target creatures and/or planeswalkers"); this.getSpellAbility().addEffect(effect); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - ability.getTargets().clear(); - int numTargets = 0; - for (VariableCost cost : ability.getCosts().getVariableCosts()) { - if (cost instanceof NahirisWrathAdditionalCost) { - numTargets = ((NahirisWrathAdditionalCost) cost).getAmount(); - break; - } - } - if (numTargets > 0) { - ability.addTarget(new TargetCreatureOrPlaneswalker(0, numTargets, new FilterCreatureOrPlaneswalkerPermanent(), false)); - } + this.getSpellAbility().setTargetAdjuster(NahirisWrathAdjuster.instance); } public NahirisWrath(final NahirisWrath card) { @@ -63,6 +50,25 @@ public final class NahirisWrath extends CardImpl { } } +enum NahirisWrathAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numTargets = 0; + for (VariableCost cost : ability.getCosts().getVariableCosts()) { + if (cost instanceof NahirisWrathAdditionalCost) { + numTargets = cost.getAmount(); + break; + } + } + if (numTargets > 0) { + ability.addTarget(new TargetCreatureOrPlaneswalker(0, numTargets, new FilterCreatureOrPlaneswalkerPermanent(), false)); + } + } +} + class NahirisWrathAdditionalCost extends VariableCostImpl { NahirisWrathAdditionalCost() { diff --git a/Mage.Sets/src/mage/cards/n/NamelessRace.java b/Mage.Sets/src/mage/cards/n/NamelessRace.java index f435ddecb3..eca9d51b5a 100644 --- a/Mage.Sets/src/mage/cards/n/NamelessRace.java +++ b/Mage.Sets/src/mage/cards/n/NamelessRace.java @@ -1,12 +1,12 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.dynamicvalue.common.CardsInAllGraveyardsCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.OneShotEffect; @@ -16,12 +16,7 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; @@ -30,10 +25,13 @@ import mage.filter.predicate.other.OwnerPredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author L_J */ public final class NamelessRace extends CardImpl { @@ -48,12 +46,12 @@ public final class NamelessRace extends CardImpl { // As Nameless Race enters the battlefield, pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards. this.addAbility(new AsEntersBattlefieldAbility(new NamelessRaceEffect())); - + // Nameless Race's power and toughness are each equal to the life paid as it entered the battlefield. this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this}'s power and toughness are each equal to the life paid as it entered the battlefield"))); } - public NamelessRace(final NamelessRace card) { + private NamelessRace(final NamelessRace card) { super(card); } @@ -64,24 +62,28 @@ public final class NamelessRace extends CardImpl { } class NamelessRaceEffect extends OneShotEffect { - - private static final FilterPermanent filter = new FilterPermanent("white nontoken permanents your opponents control"); - private static final FilterCard filter2 = new FilterCard("white cards in their graveyards"); - + + private static final FilterPermanent filter + = new FilterPermanent("white nontoken permanents your opponents control"); + private static final FilterCard filter2 + = new FilterCard("white cards in their graveyards"); + static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(new ControllerPredicate(TargetController.OPPONENT)); filter2.add(new ColorPredicate(ObjectColor.WHITE)); filter2.add(new OwnerPredicate(TargetController.OPPONENT)); } - public NamelessRaceEffect() { + NamelessRaceEffect() { super(Outcome.LoseLife); - staticText = "pay any amount of life. The amount you pay can't be more than the total number of white nontoken permanents your opponents control plus the total number of white cards in their graveyards"; + staticText = "pay any amount of life. The amount you pay can't be more than " + + "the total number of white nontoken permanents your opponents control " + + "plus the total number of white cards in their graveyards"; } - public NamelessRaceEffect(final NamelessRaceEffect effect) { + private NamelessRaceEffect(final NamelessRaceEffect effect) { super(effect); } @@ -93,18 +95,25 @@ class NamelessRaceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card sourceCard = game.getCard(source.getSourceId()); - int permanentsInPlay = new PermanentsOnBattlefieldCount(filter).calculate(game, source, null); - int cardsInGraveyards = new CardsInAllGraveyardsCount(filter2).calculate(game, source, null); - int maxAmount = Math.min(permanentsInPlay + cardsInGraveyards, controller.getLife()); - int payAmount = controller.getAmount(0, maxAmount, "Pay up to " + maxAmount + " life", game); - controller.loseLife(payAmount, game, false); - game.informPlayers(new StringBuilder(sourceCard.getLogName()).append(": ").append(controller.getLogName()) - .append(" pays ").append(payAmount).append(" life").toString()); - game.addEffect(new SetPowerToughnessSourceEffect(payAmount, payAmount, Duration.Custom, SubLayer.SetPT_7b), source); - return true; + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (controller == null || permanent == null) { + return false; } - return false; + int permanentsInPlay = new PermanentsOnBattlefieldCount(filter).calculate(game, source, null); + int cardsInGraveyards = new CardsInAllGraveyardsCount(filter2).calculate(game, source, null); + int maxAmount = Math.min(permanentsInPlay + cardsInGraveyards, controller.getLife()); + int payAmount = controller.getAmount(0, maxAmount, "Pay up to " + maxAmount + " life", game); + Cost cost = new PayLifeCost(payAmount); + if (!cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + return false; + } + Card sourceCard = game.getCard(source.getSourceId()); + game.informPlayers((sourceCard != null ? sourceCard.getLogName() : "") + ": " + controller.getLogName() + + " pays " + payAmount + " life"); + game.addEffect(new SetPowerToughnessSourceEffect( + payAmount, payAmount, Duration.Custom, SubLayer.CharacteristicDefining_7a + ), source); + permanent.addInfo("life paid", CardUtil.addToolTipMarkTags("Life paid: " + payAmount), game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NantukoShaman.java b/Mage.Sets/src/mage/cards/n/NantukoShaman.java index b17eaccb4b..ad62796b09 100644 --- a/Mage.Sets/src/mage/cards/n/NantukoShaman.java +++ b/Mage.Sets/src/mage/cards/n/NantukoShaman.java @@ -26,7 +26,7 @@ public final class NantukoShaman extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent(); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public NantukoShaman(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java b/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java new file mode 100644 index 0000000000..9a6571e6ce --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NarsetParterOfVeils.java @@ -0,0 +1,94 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.watchers.common.CardsAmountDrawnThisTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NarsetParterOfVeils extends CardImpl { + + private static final FilterCard filter = new FilterCard("noncreature, nonland card"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + } + + public NarsetParterOfVeils(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NARSET); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Each opponent can't draw more than one card each turn. + this.addAbility(new SimpleStaticAbility(new NarsetParterOfVeilsEffect()), new CardsAmountDrawnThisTurnWatcher()); + + // -2: Look at the top four cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. + this.addAbility(new LoyaltyAbility(new LookLibraryAndPickControllerEffect( + new StaticValue(4), false, new StaticValue(1), filter, + Zone.LIBRARY, false, true, false, Zone.HAND, + true, false, false + ).setBackInRandomOrder(true).setText("Look at the top four cards of your library. " + + "You may reveal a noncreature, nonland card from among them and put it into your hand. " + + "Put the rest on the bottom of your library in a random order." + ), -2)); + } + + private NarsetParterOfVeils(final NarsetParterOfVeils card) { + super(card); + } + + @Override + public NarsetParterOfVeils copy() { + return new NarsetParterOfVeils(this); + } +} + +class NarsetParterOfVeilsEffect extends ContinuousRuleModifyingEffectImpl { + + NarsetParterOfVeilsEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment, false, false); + staticText = "Each opponent can't draw more than one card each turn"; + } + + private NarsetParterOfVeilsEffect(final NarsetParterOfVeilsEffect effect) { + super(effect); + } + + @Override + public NarsetParterOfVeilsEffect copy() { + return new NarsetParterOfVeilsEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + CardsAmountDrawnThisTurnWatcher watcher = game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); + Player controller = game.getPlayer(source.getControllerId()); + return watcher != null && controller != null && watcher.getAmountCardsDrawn(event.getPlayerId()) >= 1 + && game.isOpponent(controller, event.getPlayerId()); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NarsetsReversal.java b/Mage.Sets/src/mage/cards/n/NarsetsReversal.java new file mode 100644 index 0000000000..a676babeac --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NarsetsReversal.java @@ -0,0 +1,37 @@ +package mage.cards.n; + +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NarsetsReversal extends CardImpl { + + public NarsetsReversal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{U}"); + + // Copy target instant or sorcery spell, then return it to its owner's hand. You may choose new targets for the copy. + this.getSpellAbility().addEffect(new CopyTargetSpellEffect() + .setText("Copy target instant or sorcery spell,")); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect() + .setText("then return it to its owner's hand. You may choose new targets for the copy.")); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY)); + } + + private NarsetsReversal(final NarsetsReversal card) { + super(card); + } + + @Override + public NarsetsReversal copy() { + return new NarsetsReversal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NaturalBalance.java b/Mage.Sets/src/mage/cards/n/NaturalBalance.java index 37a8f22490..ca4658a053 100644 --- a/Mage.Sets/src/mage/cards/n/NaturalBalance.java +++ b/Mage.Sets/src/mage/cards/n/NaturalBalance.java @@ -92,7 +92,7 @@ public final class NaturalBalance extends CardImpl { if (landCount < 5 && player.chooseUse(outcome, "Search your library for up to " + amount + " basic land cards and put them onto the battlefield?", source, game)) { // Select lands and put them onto battlefield TargetCardInLibrary target = new TargetCardInLibrary(0, amount, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game); } toShuffle.add(player); diff --git a/Mage.Sets/src/mage/cards/n/NaturesChosen.java b/Mage.Sets/src/mage/cards/n/NaturesChosen.java index 9cb96ea8a3..6fb1055bef 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesChosen.java +++ b/Mage.Sets/src/mage/cards/n/NaturesChosen.java @@ -49,7 +49,7 @@ public final class NaturesChosen extends CardImpl { static { filterWhiteUntappedCreature.add(new ColorPredicate(ObjectColor.WHITE)); - filterWhiteUntappedCreature.add(Predicates.not(new TappedPredicate())); + filterWhiteUntappedCreature.add(Predicates.not(TappedPredicate.instance)); } public NaturesChosen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NaturesWay.java b/Mage.Sets/src/mage/cards/n/NaturesWay.java index 49d697e5f3..ce8752367c 100644 --- a/Mage.Sets/src/mage/cards/n/NaturesWay.java +++ b/Mage.Sets/src/mage/cards/n/NaturesWay.java @@ -23,7 +23,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class NaturesWay extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); diff --git a/Mage.Sets/src/mage/cards/n/NayaCharm.java b/Mage.Sets/src/mage/cards/n/NayaCharm.java index 520eb601da..9df44f48e8 100644 --- a/Mage.Sets/src/mage/cards/n/NayaCharm.java +++ b/Mage.Sets/src/mage/cards/n/NayaCharm.java @@ -28,13 +28,13 @@ public final class NayaCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or return target card from a graveyard to its owner's hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInGraveyard()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInGraveyard()); this.getSpellAbility().addMode(mode); // or tap all creatures target player controls. mode = new Mode(); - mode.getEffects().add(new TapAllTargetPlayerControlsEffect(FILTER_PERMANENT_CREATURES)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new TapAllTargetPlayerControlsEffect(FILTER_PERMANENT_CREATURES)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/n/NayaHushblade.java b/Mage.Sets/src/mage/cards/n/NayaHushblade.java index 45c7ecb36e..343d71f445 100644 --- a/Mage.Sets/src/mage/cards/n/NayaHushblade.java +++ b/Mage.Sets/src/mage/cards/n/NayaHushblade.java @@ -29,8 +29,8 @@ public final class NayaHushblade extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another multicolor permanent"); static { - filter.add(new MulticoloredPredicate()); - filter.add(new AnotherPredicate()); + filter.add(MulticoloredPredicate.instance); + filter.add(AnotherPredicate.instance); } public NayaHushblade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java b/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java index 2c3bf2f8f7..bd4511146b 100644 --- a/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java +++ b/Mage.Sets/src/mage/cards/n/NazahnReveredBladesmith.java @@ -26,11 +26,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import java.util.UUID; /** - * * @author spjspj */ public final class NazahnReveredBladesmith extends CardImpl { @@ -38,7 +38,7 @@ public final class NazahnReveredBladesmith extends CardImpl { private static final FilterControlledCreaturePermanent equippedFilter = new FilterControlledCreaturePermanent("equipped creature you control"); static { - equippedFilter.add(new EquippedPredicate()); + equippedFilter.add(EquippedPredicate.instance); equippedFilter.add(new ControllerPredicate(TargetController.YOU)); } @@ -65,25 +65,10 @@ public final class NazahnReveredBladesmith extends CardImpl { // Whenever an equipped creature you control attacks, you may tap target creature defending player controls. Ability ability = new AttacksCreatureYouControlTriggeredAbility(new NazahnTapEffect(), true, equippedFilter, true); ability.addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature defending player controls"))); + ability.setTargetAdjuster(NazahnReveredBladesmithAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof AttacksCreatureYouControlTriggeredAbility) { - FilterCreaturePermanent filterDefender = new FilterCreaturePermanent("creature defending player controls"); - for (Effect effect : ability.getEffects()) { - if (effect instanceof NazahnTapEffect) { - filterDefender.add(new ControllerIdPredicate(game.getCombat().getDefendingPlayerId(effect.getTargetPointer().getFirst(game, ability), game))); - break; - } - } - ability.getTargets().clear(); - TargetCreaturePermanent target = new TargetCreaturePermanent(filterDefender); - ability.addTarget(target); - } - } - public NazahnReveredBladesmith(final NazahnReveredBladesmith card) { super(card); } @@ -94,6 +79,24 @@ public final class NazahnReveredBladesmith extends CardImpl { } } +enum NazahnReveredBladesmithAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + FilterCreaturePermanent filterDefender = new FilterCreaturePermanent("creature defending player controls"); + for (Effect effect : ability.getEffects()) { + if (effect instanceof NazahnTapEffect) { + filterDefender.add(new ControllerIdPredicate(game.getCombat().getDefendingPlayerId(effect.getTargetPointer().getFirst(game, ability), game))); + break; + } + } + ability.getTargets().clear(); + TargetCreaturePermanent target = new TargetCreaturePermanent(filterDefender); + ability.addTarget(target); + } +} + class NazahnTapEffect extends TapTargetEffect { NazahnTapEffect() { diff --git a/Mage.Sets/src/mage/cards/n/NebulonBFrigate.java b/Mage.Sets/src/mage/cards/n/NebulonBFrigate.java index 2d318c7129..ba7c2cf73d 100644 --- a/Mage.Sets/src/mage/cards/n/NebulonBFrigate.java +++ b/Mage.Sets/src/mage/cards/n/NebulonBFrigate.java @@ -25,7 +25,7 @@ public final class NebulonBFrigate extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public NebulonBFrigate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/Necrologia.java b/Mage.Sets/src/mage/cards/n/Necrologia.java index 1d35c3beba..d1c3dc8a26 100644 --- a/Mage.Sets/src/mage/cards/n/Necrologia.java +++ b/Mage.Sets/src/mage/cards/n/Necrologia.java @@ -29,7 +29,7 @@ public final class Necrologia extends CardImpl { this.getSpellAbility().addCost(new PayVariableLifeCost(true)); // Draw X cards. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new GetXValue())); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(GetXValue.instance)); } public Necrologia(final Necrologia card) { diff --git a/Mage.Sets/src/mage/cards/n/NecromancersMagemark.java b/Mage.Sets/src/mage/cards/n/NecromancersMagemark.java index 168c633cb7..1be965cbc8 100644 --- a/Mage.Sets/src/mage/cards/n/NecromancersMagemark.java +++ b/Mage.Sets/src/mage/cards/n/NecromancersMagemark.java @@ -36,7 +36,7 @@ public final class NecromancersMagemark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control that are enchanted"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } @@ -111,7 +111,7 @@ class NecromancersMagemarkEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent != null && permanent.isControlledBy(source.getControllerId())) { for (UUID attachmentId : permanent.getAttachments()) { diff --git a/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java b/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java index 68d4e77f9b..640496dabc 100644 --- a/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java +++ b/Mage.Sets/src/mage/cards/n/NecromancersStockpile.java @@ -67,14 +67,16 @@ class NecromancersStockpileDiscardTargetCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { if (targets.choose(Outcome.Discard, controllerId, sourceId, game)) { Player player = game.getPlayer(controllerId); - for (UUID targetId : targets.get(0).getTargets()) { - Card card = player.getHand().get(targetId, game); - if (card == null) { - return false; - } - isZombieCard = card.hasSubtype(SubType.ZOMBIE, game); - paid |= player.discard(card, null, game); + if(player != null) { + for (UUID targetId : targets.get(0).getTargets()) { + Card card = player.getHand().get(targetId, game); + if (card == null) { + return false; + } + isZombieCard = card.hasSubtype(SubType.ZOMBIE, game); + paid |= player.discard(card, null, game); + } } } return paid; diff --git a/Mage.Sets/src/mage/cards/n/Necromancy.java b/Mage.Sets/src/mage/cards/n/Necromancy.java index fe12c03723..50d87e1e83 100644 --- a/Mage.Sets/src/mage/cards/n/Necromancy.java +++ b/Mage.Sets/src/mage/cards/n/Necromancy.java @@ -138,7 +138,7 @@ class NecromancyLeavesBattlefieldTriggeredEffect extends OneShotEffect { class NecromancyChangeAbilityEffect extends ContinuousEffectImpl implements SourceEffect { - private final static Ability newAbility = new EnchantAbility("creature put onto the battlefield with Necromancy"); + private static final Ability newAbility = new EnchantAbility("creature put onto the battlefield with Necromancy"); static { newAbility.setRuleAtTheTop(true); diff --git a/Mage.Sets/src/mage/cards/n/Necroplasm.java b/Mage.Sets/src/mage/cards/n/Necroplasm.java index 2c1b4a9443..9974d50299 100644 --- a/Mage.Sets/src/mage/cards/n/Necroplasm.java +++ b/Mage.Sets/src/mage/cards/n/Necroplasm.java @@ -81,7 +81,9 @@ class NecroplasmEffect extends OneShotEffect { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, numCounters)); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - permanent.destroy(source.getSourceId(), game, false); + if(permanent != null) { + permanent.destroy(source.getSourceId(), game, false); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/n/NecropolisFiend.java b/Mage.Sets/src/mage/cards/n/NecropolisFiend.java index a4219545b3..e1b5a829d9 100644 --- a/Mage.Sets/src/mage/cards/n/NecropolisFiend.java +++ b/Mage.Sets/src/mage/cards/n/NecropolisFiend.java @@ -1,11 +1,11 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.ExileFromGraveCost; import mage.abilities.costs.common.TapSourceCost; @@ -21,8 +21,8 @@ import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; @@ -30,15 +30,17 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class NecropolisFiend extends CardImpl { public NecropolisFiend(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{7}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{7}{B}{B}"); this.subtype.add(SubType.DEMON); this.power = new MageInt(4); @@ -46,54 +48,29 @@ public final class NecropolisFiend extends CardImpl { // Delve this.addAbility(new DelveAbility()); + // Flying this.addAbility(FlyingAbility.getInstance()); - //TODO: Make ability properly copiable + // {X}, {T}, Exile X cards from your graveyard: Target creature gets -X/-X until end of turn. - DynamicValue xValue = new SignInversionDynamicValue(new ManacostVariableValue()); - Effect effect = new BoostTargetEffect(xValue,xValue,Duration.EndOfTurn); + DynamicValue xValue = new SignInversionDynamicValue(ManacostVariableValue.instance); + Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn); effect.setText("Target creature gets -X/-X until end of turn"); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, effect, + new ManaCostsImpl("{X}") + ); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetCreaturePermanent()); - ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard(1,1,new FilterCard("cards from your graveyard")), "Exile X cards from your graveyard")); + ability.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard( + 1, 1, new FilterCard("cards from your graveyard") + ), "Exile X cards from your graveyard")); + ability.setTargetAdjuster(NecropolisFiendTargetAdjuster.instance); + ability.setCostAdjuster(NecropolisFiendCostAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustCosts(Ability ability, Game game) { - if (ability instanceof SimpleActivatedAbility) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - for (VariableCost variableCost: ability.getManaCostsToPay().getVariableCosts()) { - if (variableCost instanceof VariableManaCost) { - ((VariableManaCost)variableCost).setMaxX(controller.getGraveyard().size()); - } - } - } - } - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SimpleActivatedAbility) { - int xValue = ability.getManaCostsToPay().getX(); - for(Cost cost: ability.getCosts()) { - if (cost instanceof ExileFromGraveCost) { - ExileFromGraveCost exileCost = (ExileFromGraveCost) cost; - for(Target target: exileCost.getTargets()) { - if (target instanceof TargetCardInYourGraveyard) { - target.setMaxNumberOfTargets(xValue); - target.setMinNumberOfTargets(xValue); - } - } - - } - } - } - } - public NecropolisFiend(final NecropolisFiend card) { super(card); } @@ -103,3 +80,41 @@ public final class NecropolisFiend extends CardImpl { return new NecropolisFiend(this); } } + +enum NecropolisFiendCostAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller == null) { + return; + } + for (VariableCost variableCost : ability.getManaCostsToPay().getVariableCosts()) { + if (variableCost instanceof VariableManaCost) { + ((VariableManaCost) variableCost).setMaxX(controller.getGraveyard().size()); + } + } + } +} + +enum NecropolisFiendTargetAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + for (Cost cost : ability.getCosts()) { + if (!(cost instanceof ExileFromGraveCost)) { + continue; + } + ExileFromGraveCost exileCost = (ExileFromGraveCost) cost; + for (Target target : exileCost.getTargets()) { + if (target instanceof TargetCardInYourGraveyard) { + target.setMaxNumberOfTargets(xValue); + target.setMinNumberOfTargets(xValue); + } + } + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/Necroskitter.java b/Mage.Sets/src/mage/cards/n/Necroskitter.java index 1cd96428c0..7fcfaea1b9 100644 --- a/Mage.Sets/src/mage/cards/n/Necroskitter.java +++ b/Mage.Sets/src/mage/cards/n/Necroskitter.java @@ -74,7 +74,7 @@ class NecroskitterTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = zEvent.getTarget(); if (permanent != null && permanent.getCounters(game).containsKey(CounterType.M1M1) diff --git a/Mage.Sets/src/mage/cards/n/NecroticPlague.java b/Mage.Sets/src/mage/cards/n/NecroticPlague.java index 00d17e6213..5bc9c3137a 100644 --- a/Mage.Sets/src/mage/cards/n/NecroticPlague.java +++ b/Mage.Sets/src/mage/cards/n/NecroticPlague.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.DiesAttachedTriggeredAbility; @@ -15,35 +14,24 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerPredicate; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponentsCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public final class NecroticPlague extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); - - static { - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - } - public NecroticPlague(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); this.subtype.add(SubType.AURA); @@ -53,33 +41,18 @@ public final class NecroticPlague extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Enchanted creature has "At the beginning of your upkeep, sacrifice this creature." // When enchanted creature dies, its controller chooses target creature one of their opponents controls. Return Necrotic Plague from its owner's graveyard to the battlefield attached to that creature. - Ability gainedAbility = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect(), TargetController.YOU, false); - Effect effect = new GainAbilityAttachedEffect(gainedAbility, AttachmentType.AURA, Duration.WhileOnBattlefield); + ability = new BeginningOfUpkeepTriggeredAbility(new SacrificeSourceEffect(), TargetController.YOU, false); + Effect effect = new GainAbilityAttachedEffect(ability, AttachmentType.AURA, Duration.WhileOnBattlefield); effect.setText("Enchanted creature has \"At the beginning of your upkeep, sacrifice this creature.\""); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); - this.addAbility(new DiesAttachedTriggeredAbility(new NecroticPlagueEffect(), "enchanted creature", false)); - } + ability = new DiesAttachedTriggeredAbility(new NecroticPlagueEffect(), "enchanted creature", false); + ability.setTargetAdjuster(NecroticPlagueAdjuster.instance); + this.addAbility(ability); - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof DiesAttachedTriggeredAbility) { - Permanent attachedTo = null; - for (Effect effect : ability.getEffects()) { - attachedTo = (Permanent) effect.getValue("attachedTo"); - } - if (attachedTo != null) { - Player creatureController = game.getPlayer(attachedTo.getControllerId()); - if (creatureController != null) { - ability.setControllerId(creatureController.getId()); - ability.getTargets().clear(); - TargetPermanent target = new TargetPermanent(filter); - ability.getTargets().add(target); - } - } - } } public NecroticPlague(final NecroticPlague card) { @@ -93,11 +66,35 @@ public final class NecroticPlague extends CardImpl { } +enum NecroticPlagueAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Permanent attachedTo = null; + for (Effect effect : ability.getEffects()) { + attachedTo = (Permanent) effect.getValue("attachedTo"); + } + if (attachedTo == null) { + return; + } + Player creatureController = game.getPlayer(attachedTo.getControllerId()); + if (creatureController == null) { + return; + } + ability.setControllerId(creatureController.getId()); + ability.getTargets().clear(); + TargetPermanent target = new TargetOpponentsCreaturePermanent(); + ability.getTargets().add(target); + } +} + class NecroticPlagueEffect extends OneShotEffect { public NecroticPlagueEffect() { super(Outcome.PutCardInPlay); - staticText = "its controller chooses target creature one of their opponents controls. Return {this} from its owner's graveyard to the battlefield attached to that creature"; + staticText = "its controller chooses target creature one of their opponents controls. " + + "Return {this} from its owner's graveyard to the battlefield attached to that creature"; } public NecroticPlagueEffect(final NecroticPlagueEffect effect) { diff --git a/Mage.Sets/src/mage/cards/n/NeedleDrop.java b/Mage.Sets/src/mage/cards/n/NeedleDrop.java index 2b299e4f35..63a5b8535d 100644 --- a/Mage.Sets/src/mage/cards/n/NeedleDrop.java +++ b/Mage.Sets/src/mage/cards/n/NeedleDrop.java @@ -58,7 +58,7 @@ class DamagedThisTurnPredicate implements Predicate { @Override public boolean apply(MageItem input, Game game) { - DamageDoneWatcher watcher = (DamageDoneWatcher) game.getState().getWatchers().get(DamageDoneWatcher.class.getSimpleName()); + DamageDoneWatcher watcher = game.getState().getWatcher(DamageDoneWatcher.class); if (watcher != null) { if (input instanceof MageObject) { return watcher.isDamaged(input.getId(), ((MageObject) input).getZoneChangeCounter(game), game); diff --git a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java index bfa69afdc8..5a07ec5668 100644 --- a/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java +++ b/Mage.Sets/src/mage/cards/n/NeedlebiteTrap.java @@ -51,10 +51,10 @@ enum NeedlebiteTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getSimpleName()); + PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { - if (watcher.getLiveGained(opponentId) > 0) { + if (watcher.getLifeGained(opponentId) > 0) { return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java b/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java new file mode 100644 index 0000000000..bb93391c24 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NehebDreadhordeChampion.java @@ -0,0 +1,99 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NehebDreadhordeChampion extends CardImpl { + + public NehebDreadhordeChampion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.MINOTAUR); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Neheb, Dreadhorde Champion deals combat damage to a player or planeswalker, you may discard any number of cards. If you do, draw that many cards and add that much {R}. Until end of turn, you don't lose this mana as steps and phases end. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new NehebDreadhordeChampionEffect(), true).setOrPlaneswalker(true) + ); + } + + private NehebDreadhordeChampion(final NehebDreadhordeChampion card) { + super(card); + } + + @Override + public NehebDreadhordeChampion copy() { + return new NehebDreadhordeChampion(this); + } +} + +class NehebDreadhordeChampionEffect extends OneShotEffect { + + NehebDreadhordeChampionEffect() { + super(Outcome.Benefit); + staticText = "discard any number of cards. If you do, draw that many cards and add that much {R}. " + + "Until end of turn, you don't lose this mana as steps and phases end."; + } + + private NehebDreadhordeChampionEffect(final NehebDreadhordeChampionEffect effect) { + super(effect); + } + + @Override + public NehebDreadhordeChampionEffect copy() { + return new NehebDreadhordeChampionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + TargetCard target = new TargetCardInHand(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Cards cards = new CardsImpl(target.getTargets()); + int counter = 0; + Mana mana = new Mana(); + for (Card card : cards.getCards(game)) { + if (player.discard(card, source, game)) { + counter++; + mana.increaseRed(); + } + } + if (counter == 0) { + return true; + } + player.drawCards(counter, game); + player.getManaPool().addMana(mana, game, source, true); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NehebTheEternal.java b/Mage.Sets/src/mage/cards/n/NehebTheEternal.java index 58bd4f5e39..c56200a21f 100644 --- a/Mage.Sets/src/mage/cards/n/NehebTheEternal.java +++ b/Mage.Sets/src/mage/cards/n/NehebTheEternal.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; @@ -18,8 +16,9 @@ import mage.constants.TargetController; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author spjspj */ public final class NehebTheEternal extends CardImpl { @@ -74,7 +73,7 @@ class NehebTheEternalManaEffect extends ManaEffect { @Override public Mana produceMana(boolean netMana, Game game, Ability source) { - return Mana.RedMana(new OpponentsLostLifeCount().calculate(game, source, this)); + return Mana.RedMana(OpponentsLostLifeCount.instance.calculate(game, source, this)); } @Override diff --git a/Mage.Sets/src/mage/cards/n/NemesisOfMortals.java b/Mage.Sets/src/mage/cards/n/NemesisOfMortals.java index ef22b710b6..0cab56e3fe 100644 --- a/Mage.Sets/src/mage/cards/n/NemesisOfMortals.java +++ b/Mage.Sets/src/mage/cards/n/NemesisOfMortals.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -11,19 +10,16 @@ import mage.abilities.effects.common.cost.SourceCostReductionForEachCardInGravey import mage.abilities.keyword.MonstrosityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.CostModificationType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NemesisOfMortals extends CardImpl { @@ -41,6 +37,7 @@ public final class NemesisOfMortals extends CardImpl { this.addAbility(ability); // {7}{G}{G}: Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard. + // TODO: Make ability properly copiable ability = new MonstrosityAbility("{7}{G}{G}", 5); for (Effect effect : ability.getEffects()) { effect.setText("Monstrosity 5. This ability costs {1} less to activate for each creature card in your graveyard"); @@ -49,7 +46,7 @@ public final class NemesisOfMortals extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new NemesisOfMortalsCostReducingEffect(ability.getOriginalId()))); } - public NemesisOfMortals(final NemesisOfMortals card) { + private NemesisOfMortals(final NemesisOfMortals card) { super(card); } @@ -68,7 +65,7 @@ class NemesisOfMortalsCostReducingEffect extends CostModificationEffectImpl { this.originalId = originalId; } - NemesisOfMortalsCostReducingEffect(final NemesisOfMortalsCostReducingEffect effect) { + private NemesisOfMortalsCostReducingEffect(final NemesisOfMortalsCostReducingEffect effect) { super(effect); this.originalId = effect.originalId; } @@ -77,7 +74,7 @@ class NemesisOfMortalsCostReducingEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - CardUtil.reduceCost(abilityToModify, controller.getGraveyard().getCards(new FilterCreatureCard(), game).size()); + CardUtil.reduceCost(abilityToModify, controller.getGraveyard().count(StaticFilters.FILTER_CARD_CREATURE, game)); } return true; } diff --git a/Mage.Sets/src/mage/cards/n/NemesisTrap.java b/Mage.Sets/src/mage/cards/n/NemesisTrap.java index 003fa1cb47..3951249678 100644 --- a/Mage.Sets/src/mage/cards/n/NemesisTrap.java +++ b/Mage.Sets/src/mage/cards/n/NemesisTrap.java @@ -36,7 +36,7 @@ public final class NemesisTrap extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public NemesisTrap(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/Neoform.java b/Mage.Sets/src/mage/cards/n/Neoform.java new file mode 100644 index 0000000000..56cd8b5d21 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/Neoform.java @@ -0,0 +1,152 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Neoform extends CardImpl { + + public Neoform(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{U}"); + + // As an additional cost to cast this spell, sacrifice a creature. + this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent( + 1, 1, StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT, true + ))); + + // Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, + // put that card onto the battlefield with an additional +1/+1 counter on it, then shuffle your library. + this.getSpellAbility().addEffect(new NeoformEffect()); + } + + private Neoform(final Neoform card) { + super(card); + } + + @Override + public Neoform copy() { + return new Neoform(this); + } +} + +class NeoformEffect extends OneShotEffect { + + NeoformEffect() { + super(Outcome.Benefit); + staticText = "Search your library for a creature card with converted mana cost equal to " + + "1 plus the sacrificed creature's converted mana cost, " + + "put that card onto the battlefield with an additional +1/+1 counter on it, then shuffle your library."; + } + + private NeoformEffect(final NeoformEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sacrificedPermanent = null; + for (Cost cost : source.getCosts()) { + if (cost instanceof SacrificeTargetCost) { + SacrificeTargetCost sacrificeCost = (SacrificeTargetCost) cost; + if (!sacrificeCost.getPermanents().isEmpty()) { + sacrificedPermanent = sacrificeCost.getPermanents().get(0); + } + break; + } + } + Player controller = game.getPlayer(source.getControllerId()); + if (sacrificedPermanent == null || controller == null) { + return false; + } + int newConvertedCost = sacrificedPermanent.getConvertedManaCost() + 1; + FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, newConvertedCost)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + if (controller.searchLibrary(target, source, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + ContinuousEffectImpl effect = new NeoformReplacementEffect(); + effect.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(effect, source); + if (!controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + effect.discard(); + } + } + } + controller.shuffleLibrary(source, game); + return true; + } + + @Override + public NeoformEffect copy() { + return new NeoformEffect(this); + } +} + +class NeoformReplacementEffect extends ReplacementEffectImpl { + + NeoformReplacementEffect() { + super(Duration.EndOfStep, Outcome.BoostCreature); + } + + private NeoformReplacementEffect(NeoformReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(getTargetPointer().getFirst(game, source)); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + if (creature != null) { + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } + discard(); + return false; + } + + @Override + public NeoformReplacementEffect copy() { + return new NeoformReplacementEffect(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java b/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java index 5a69454d63..04135db5ba 100644 --- a/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java +++ b/Mage.Sets/src/mage/cards/n/NephaliaSmuggler.java @@ -25,7 +25,7 @@ public final class NephaliaSmuggler extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public NephaliaSmuggler(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NessianGameWarden.java b/Mage.Sets/src/mage/cards/n/NessianGameWarden.java index 1869cf5538..4a44a2b6b7 100644 --- a/Mage.Sets/src/mage/cards/n/NessianGameWarden.java +++ b/Mage.Sets/src/mage/cards/n/NessianGameWarden.java @@ -81,8 +81,8 @@ class NessianGameWardenEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); int count = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); + Cards cards = new CardsImpl(); cards.addAll(controller.getLibrary().getTopCards(game, count)); controller.lookAtCards(sourcePermanent.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java b/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java index 3cb5b250f2..1d5e7026cb 100644 --- a/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java +++ b/Mage.Sets/src/mage/cards/n/NessianWildsRavager.java @@ -25,7 +25,7 @@ public final class NessianWildsRavager extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public NessianWildsRavager(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NetherTraitor.java b/Mage.Sets/src/mage/cards/n/NetherTraitor.java index 269030fc48..34d6a5fea4 100644 --- a/Mage.Sets/src/mage/cards/n/NetherTraitor.java +++ b/Mage.Sets/src/mage/cards/n/NetherTraitor.java @@ -79,7 +79,7 @@ class NetherTraitorTriggeredAbility extends TriggeredAbilityImpl { return false; } } - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget() != null && zEvent.getTarget().isOwnedBy(this.getControllerId()) && zEvent.getTarget().isCreature()&& diff --git a/Mage.Sets/src/mage/cards/n/NettleDrone.java b/Mage.Sets/src/mage/cards/n/NettleDrone.java index da8ddeef7c..e565226ee2 100644 --- a/Mage.Sets/src/mage/cards/n/NettleDrone.java +++ b/Mage.Sets/src/mage/cards/n/NettleDrone.java @@ -27,7 +27,7 @@ public final class NettleDrone extends CardImpl { private static final FilterSpell filterSpell = new FilterSpell("a colorless spell"); static { - filterSpell.add(new ColorlessPredicate()); + filterSpell.add(ColorlessPredicate.instance); } public NettleDrone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NettlevineBlight.java b/Mage.Sets/src/mage/cards/n/NettlevineBlight.java index 5eb850e5b1..446ee50799 100644 --- a/Mage.Sets/src/mage/cards/n/NettlevineBlight.java +++ b/Mage.Sets/src/mage/cards/n/NettlevineBlight.java @@ -1,4 +1,3 @@ - package mage.cards.n; import java.util.UUID; @@ -107,7 +106,8 @@ class NettlevineBlightEffect extends OneShotEffect { if (chosenPermanent != null) { Card nettlevineBlightCard = game.getCard(source.getSourceId()); if (nettlevineBlightCard != null) { - nettlevineBlight.attachTo(chosenPermanent.getId(), game); + game.getState().setValue("attachTo:" + nettlevineBlight.getId(), chosenPermanent); + chosenPermanent.addAttachment(nettlevineBlight.getId(), game); return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NettlingImp.java b/Mage.Sets/src/mage/cards/n/NettlingImp.java index 54fb70dae4..c96717e753 100644 --- a/Mage.Sets/src/mage/cards/n/NettlingImp.java +++ b/Mage.Sets/src/mage/cards/n/NettlingImp.java @@ -33,7 +33,7 @@ import mage.watchers.common.AttackedThisTurnWatcher; */ public final class NettlingImp extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall"); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Wall"); static { filter.add(Predicates.not(new SubtypePredicate(SubType.WALL))); diff --git a/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java b/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java index 886d089c0b..f7a8b2c227 100644 --- a/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java +++ b/Mage.Sets/src/mage/cards/n/NeurokTransmuter.java @@ -31,7 +31,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class NeurokTransmuter extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/n/NeutralizingBlast.java b/Mage.Sets/src/mage/cards/n/NeutralizingBlast.java index 39a9864fc7..f4eeb34985 100644 --- a/Mage.Sets/src/mage/cards/n/NeutralizingBlast.java +++ b/Mage.Sets/src/mage/cards/n/NeutralizingBlast.java @@ -18,7 +18,7 @@ public final class NeutralizingBlast extends CardImpl { private static final FilterSpell filter = new FilterSpell("multicolored spell"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public NeutralizingBlast(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NeverReturn.java b/Mage.Sets/src/mage/cards/n/NeverReturn.java index 8318ab0b60..60500ee835 100644 --- a/Mage.Sets/src/mage/cards/n/NeverReturn.java +++ b/Mage.Sets/src/mage/cards/n/NeverReturn.java @@ -31,7 +31,7 @@ public final class NeverReturn extends SplitCard { // Return // Exile target card from a graveyard. Create a 2/2 black Zombie creature token. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new ExileTargetEffect()); getRightHalfCard().getSpellAbility().addTarget(new TargetCardInGraveyard()); getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken())); diff --git a/Mage.Sets/src/mage/cards/n/NeverendingTorment.java b/Mage.Sets/src/mage/cards/n/NeverendingTorment.java index 0f3d26ed80..7df007f4fc 100644 --- a/Mage.Sets/src/mage/cards/n/NeverendingTorment.java +++ b/Mage.Sets/src/mage/cards/n/NeverendingTorment.java @@ -65,7 +65,7 @@ class NeverendingTormentEffect extends OneShotEffect { if (targetPlayer != null && you != null) { TargetCardInLibrary target = new TargetCardInLibrary(you.getHand().size(), new FilterCard()); - you.searchLibrary(target, game, targetPlayer.getId()); + you.searchLibrary(target, source, game, targetPlayer.getId()); for (UUID cardId : target.getTargets()) { final Card targetCard = game.getCard(cardId); if (targetCard != null) { diff --git a/Mage.Sets/src/mage/cards/n/NewBlood.java b/Mage.Sets/src/mage/cards/n/NewBlood.java index b4b1ee8437..4361a19ef0 100644 --- a/Mage.Sets/src/mage/cards/n/NewBlood.java +++ b/Mage.Sets/src/mage/cards/n/NewBlood.java @@ -39,7 +39,7 @@ public final class NewBlood extends CardImpl { TextPartSubType textPartVampire = (TextPartSubType) addTextPart(new TextPartSubType(SubType.VAMPIRE)); FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped Vampire you control"); filter.add(new TextPartSubtypePredicate(textPartVampire)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); // As an additional cost to cast New Blood, tap an untapped Vampire you control. this.getSpellAbility().addCost(new TapTargetCost( new TargetControlledCreaturePermanent(1, 1, filter, true))); diff --git a/Mage.Sets/src/mage/cards/n/NewFrontiers.java b/Mage.Sets/src/mage/cards/n/NewFrontiers.java index 340bb18a7e..0e5357b3a7 100644 --- a/Mage.Sets/src/mage/cards/n/NewFrontiers.java +++ b/Mage.Sets/src/mage/cards/n/NewFrontiers.java @@ -64,7 +64,7 @@ class NewFrontiersEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null && player.chooseUse(outcome, "Search your library for up to " + amount + " basic lands?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(0, amount, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); player.shuffleLibrary(source, game); } diff --git a/Mage.Sets/src/mage/cards/n/NiambiFaithfulHealer.java b/Mage.Sets/src/mage/cards/n/NiambiFaithfulHealer.java index 07ef2682dc..eac1abe152 100644 --- a/Mage.Sets/src/mage/cards/n/NiambiFaithfulHealer.java +++ b/Mage.Sets/src/mage/cards/n/NiambiFaithfulHealer.java @@ -19,7 +19,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class NiambiFaithfulHealer extends CardImpl { - private final static FilterCard filter = new FilterCard("Teferi, Timebender"); + private static final FilterCard filter = new FilterCard("Teferi, Timebender"); static { filter.add(new NamePredicate("Teferi, Timebender")); diff --git a/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java b/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java index aafd4aeadf..a0d0d6b82d 100644 --- a/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java +++ b/Mage.Sets/src/mage/cards/n/NiblisOfFrost.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -19,8 +17,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class NiblisOfFrost extends CardImpl { @@ -31,7 +30,7 @@ public final class NiblisOfFrost extends CardImpl { } public NiblisOfFrost(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -43,7 +42,7 @@ public final class NiblisOfFrost extends CardImpl { this.addAbility(new ProwessAbility()); // Whenever you cast an instant or sorcery spell, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. - Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false); + Ability ability = new SpellCastControllerTriggeredAbility(new TapTargetEffect(), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); ability.addTarget(new TargetCreaturePermanent(filterCreature)); ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That creature")); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java b/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java new file mode 100644 index 0000000000..5c6e26462c --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NicolBolasDragonGod.java @@ -0,0 +1,215 @@ +package mage.cards.n; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.common.FilterPlaneswalkerPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetControlledPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; +import mage.MageObject; +import mage.cards.Card; + +/** + * @author TheElk801 + */ +public final class NicolBolasDragonGod extends CardImpl { + + public NicolBolasDragonGod(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{U}{B}{B}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.BOLAS); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Nicol Bolas, Dragon-God has all loyalty abilities of all other planeswalkers on the battlefield. + this.addAbility(new SimpleStaticAbility(new NicolBolasDragonGodGainAbilitiesEffect())); + + // +1: You draw a card. Each opponent exiles a card from their hand or a permanent they control. + this.addAbility(new LoyaltyAbility(new NicolBolasDragonGodPlusOneEffect(), 1)); + + // -3: Destroy target creature or planeswalker. + Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); + ability.addTarget(new TargetCreatureOrPlaneswalker()); + this.addAbility(ability); + + // -8: Each opponent who doesn't control a legendary creature or planeswalker loses the game. + this.addAbility(new LoyaltyAbility(new NicolBolasDragonGodMinus8Effect(), -8)); + } + + private NicolBolasDragonGod(final NicolBolasDragonGod card) { + super(card); + } + + @Override + public NicolBolasDragonGod copy() { + return new NicolBolasDragonGod(this); + } +} + +class NicolBolasDragonGodGainAbilitiesEffect extends ContinuousEffectImpl { + + private static final FilterPermanent filter = new FilterPlaneswalkerPermanent(); + + static { + filter.add(AnotherPredicate.instance); + } + + NicolBolasDragonGodGainAbilitiesEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "{this} has all loyalty abilities of all other planeswalkers on the battlefield."; + } + + private NicolBolasDragonGodGainAbilitiesEffect(final NicolBolasDragonGodGainAbilitiesEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent perm = game.getPermanent(source.getSourceId()); + if (perm == null) { + return true; + } + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents( + filter, source.getControllerId(), source.getSourceId(), game + )) { + for (Ability ability : permanent.getAbilities()) { + if (ability instanceof LoyaltyAbility) { + perm.addAbility(ability, source.getSourceId(), game); + } + } + } + return true; + } + + @Override + public NicolBolasDragonGodGainAbilitiesEffect copy() { + return new NicolBolasDragonGodGainAbilitiesEffect(this); + } +} + +class NicolBolasDragonGodPlusOneEffect extends OneShotEffect { + + NicolBolasDragonGodPlusOneEffect() { + super(Outcome.Benefit); + staticText = "You draw a card. Each opponent exiles a card from their " + + "hand or a permanent they control."; + } + + private NicolBolasDragonGodPlusOneEffect(final NicolBolasDragonGodPlusOneEffect effect) { + super(effect); + } + + @Override + public NicolBolasDragonGodPlusOneEffect copy() { + return new NicolBolasDragonGodPlusOneEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Boolean applied = false; + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(1, game); + Set cardsOnBattlefield = new LinkedHashSet<>(); + Set cards = new LinkedHashSet<>(); + for (UUID opponentId : game.getState().getPlayersInRange(player.getId(), game)) { + if (!player.hasOpponent(opponentId, game)) { + continue; + } + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { + continue; + } + if (opponent.getHand().isEmpty() + || !opponent.chooseUse(outcome, "Exile a card in your hand or a permanent you control?", + null, "Card in hand", "Permanent", source, game)) { + TargetPermanent target = new TargetControlledPermanent(); + target.setNotTarget(true); + target.setTargetController(opponentId); + if (opponent.choose(outcome, target, source.getSourceId(), game)) { + MageObject mageObject = game.getObject(target.getFirstTarget()); + if (mageObject != null + && mageObject instanceof Permanent) { + cardsOnBattlefield.add((Card) mageObject); + } + } + } else { + TargetCardInHand target = new TargetCardInHand(); + if (opponent.choose(outcome, opponent.getHand(), target, game) + && game.getCard(target.getFirstTarget()) != null) { + cards.add(game.getCard(target.getFirstTarget())); + } + } + } + cards.addAll(cardsOnBattlefield); + for (Card card : cards) { + if (card != null) { + Player owner = game.getPlayer(card.getOwnerId()); + if (owner != null + && owner.moveCards(card, Zone.EXILED, source, game)) { + applied = true; + } + } + } + return applied; + } +} + +class NicolBolasDragonGodMinus8Effect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent(); + + static { + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + NicolBolasDragonGodMinus8Effect() { + super(Outcome.Benefit); + staticText = "Each opponent who doesn't control a legendary creature or planeswalker loses the game."; + } + + private NicolBolasDragonGodMinus8Effect(final NicolBolasDragonGodMinus8Effect effect) { + super(effect); + } + + @Override + public NicolBolasDragonGodMinus8Effect copy() { + return new NicolBolasDragonGodMinus8Effect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (UUID opponentId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player opponent = game.getPlayer(opponentId); + if (opponent == null || !opponent.hasOpponent(source.getControllerId(), game)) { + continue; + } + if (game.getBattlefield().getAllActivePermanents(filter, opponentId, game).isEmpty()) { + opponent.lost(game); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java b/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java index af68ba9102..dd4859ee9a 100644 --- a/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java +++ b/Mage.Sets/src/mage/cards/n/NicolBolasGodPharaoh.java @@ -1,4 +1,3 @@ - package mage.cards.n; import java.util.HashMap; @@ -91,37 +90,33 @@ class NicolBolasGodPharaohPlusOneEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { + Boolean applied = false; // Store for each player the cards to exile, that's important because all exile shall happen at the same time Map cardsToExile = new HashMap<>(); // Each player chooses 2 cards to discard - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + int numberOfCardsToExile = Math.min(2, opponent.getHand().size()); + Target target = new TargetCardInHand(numberOfCardsToExile, new FilterCard()); + target.setRequired(true); + if (opponent.chooseTarget(Outcome.Exile, target, source, game)) { + Cards cards = new CardsImpl(target.getTargets()); + cardsToExile.put(opponentId, cards); + } } - - int numberOfCardsToExile = Math.min(2, player.getHand().size()); - Cards cards = new CardsImpl(); - - Target target = new TargetCardInHand(numberOfCardsToExile, new FilterCard()); - - player.chooseTarget(Outcome.Exile, target, source, game); - cards.addAll(target.getTargets()); - cardsToExile.put(playerId, cards); } - // Exile all choosen cards - for (UUID playerId : game.getOpponents(source.getControllerId())) { - Player player = game.getPlayer(playerId); - if (player == null) { - continue; + // Exile all chosen cards at the same time + Cards cardsOpponentsChoseToExile = new CardsImpl(); + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + cardsOpponentsChoseToExile.addAll(cardsToExile.get(opponentId)); + opponent.moveCards(cardsOpponentsChoseToExile, Zone.EXILED, source, game); + applied = true; } - Cards cardsPlayerChoseToExile = cardsToExile.get(playerId); - if (cardsPlayerChoseToExile == null) { - continue; - } - player.moveCards(cardsPlayerChoseToExile.getCards(game), Zone.EXILED, source, game); } - return true; + return applied; } } @@ -129,7 +124,9 @@ class NicolBolasGodPharaohPlusTwoEffect extends OneShotEffect { public NicolBolasGodPharaohPlusTwoEffect() { super(Outcome.Detriment); - this.staticText = "Target opponent exiles cards from the top of their library until he or she exiles a nonland card. Until end of turn, you may cast that card without paying its mana cost"; + this.staticText = "Target opponent exiles cards from the top of their " + + "library until he or she exiles a nonland card. Until end of turn, " + + "you may cast that card without paying its mana cost"; } public NicolBolasGodPharaohPlusTwoEffect(final NicolBolasGodPharaohPlusTwoEffect effect) { @@ -153,12 +150,14 @@ class NicolBolasGodPharaohPlusTwoEffect extends OneShotEffect { opponent.moveCards(card, Zone.EXILED, source, game); if (!card.isLand()) { ContinuousEffect effect = new NicolBolasGodPharaohFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId()))); + effect.setTargetPointer(new FixedTarget(card.getId(), + game.getState().getZoneChangeCounter(card.getId()))); game.addEffect(effect, source); break; } } - } while (library.hasCards() && card != null); + } while (library.hasCards() + && card != null); return true; } return false; @@ -188,13 +187,20 @@ class NicolBolasGodPharaohFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - if (sourceId != null && sourceId.equals(getTargetPointer().getFirst(game, source)) + if (sourceId != null + && sourceId.equals(getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId())) { Card card = game.getCard(sourceId); - if (card != null && game.getState().getZone(sourceId) == Zone.EXILED) { - Player player = game.getPlayer(affectedControllerId); - player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); - return true; + if (card != null + && game.getState().getZone(sourceId) == Zone.EXILED) { + Player controller = game.getPlayer(affectedControllerId); + if (controller != null) { + controller.setCastSourceIdWithAlternateMana( + sourceId, + null, + card.getSpellAbility().getCosts()); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/n/NightDealings.java b/Mage.Sets/src/mage/cards/n/NightDealings.java index 6032b45792..ae7c7011a2 100644 --- a/Mage.Sets/src/mage/cards/n/NightDealings.java +++ b/Mage.Sets/src/mage/cards/n/NightDealings.java @@ -155,14 +155,13 @@ public final class NightDealings extends CardImpl { filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); String name = "Reveal"; - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); Card sourceCard = game.getCard(source.getSourceId()); if (sourceCard != null) { name = sourceCard.getName(); diff --git a/Mage.Sets/src/mage/cards/n/Nightcreep.java b/Mage.Sets/src/mage/cards/n/Nightcreep.java index 13e51cd7b0..45cde1263c 100644 --- a/Mage.Sets/src/mage/cards/n/Nightcreep.java +++ b/Mage.Sets/src/mage/cards/n/Nightcreep.java @@ -59,11 +59,6 @@ class NightcreepLandEffect extends BecomesBasicLandTargetEffect { this.setTargetPointer(new FixedTargets(targets, game)); } - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - return super.apply(layer, sublayer, source, game); - } - @Override public NightcreepLandEffect copy() { return new NightcreepLandEffect(this); @@ -88,11 +83,6 @@ class NightcreepCreatureEffect extends BecomesColorTargetEffect { this.setTargetPointer(new FixedTargets(targets, game)); } - @Override - public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - return super.apply(layer, sublayer, source, game); - } - @Override public NightcreepCreatureEffect copy() { return new NightcreepCreatureEffect(this); diff --git a/Mage.Sets/src/mage/cards/n/NightmareIncursion.java b/Mage.Sets/src/mage/cards/n/NightmareIncursion.java index 078fd20904..f2af74211b 100644 --- a/Mage.Sets/src/mage/cards/n/NightmareIncursion.java +++ b/Mage.Sets/src/mage/cards/n/NightmareIncursion.java @@ -80,7 +80,7 @@ class NightmareIncursionEffect extends OneShotEffect { if (controller != null && targetPlayer != null) { int amount = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard()); - if (controller.searchLibrary(target, game, targetPlayer.getId())) { + if (controller.searchLibrary(target, source, game, targetPlayer.getId())) { List targetId = target.getTargets(); for (UUID targetCard : targetId) { Card card = targetPlayer.getLibrary().remove(targetCard, game); diff --git a/Mage.Sets/src/mage/cards/n/NightmarishEnd.java b/Mage.Sets/src/mage/cards/n/NightmarishEnd.java index ccf1c13d35..c597bc8f7a 100644 --- a/Mage.Sets/src/mage/cards/n/NightmarishEnd.java +++ b/Mage.Sets/src/mage/cards/n/NightmarishEnd.java @@ -24,7 +24,7 @@ public final class NightmarishEnd extends CardImpl { // Target creature gets -X/-X until end of turn, where X is the number of cards in your hand. - DynamicValue xValue = new SignInversionDynamicValue(new CardsInControllerHandCount()); + DynamicValue xValue = new SignInversionDynamicValue(CardsInControllerHandCount.instance); Effect effect = new BoostTargetEffect(xValue, xValue, Duration.EndOfTurn, true); effect.setText("Target creature gets -X/-X until end of turn, where X is the number of cards in your hand"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/n/Nightsnare.java b/Mage.Sets/src/mage/cards/n/Nightsnare.java index 7a4517db4a..c189b8eedc 100644 --- a/Mage.Sets/src/mage/cards/n/Nightsnare.java +++ b/Mage.Sets/src/mage/cards/n/Nightsnare.java @@ -1,14 +1,8 @@ - package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -18,14 +12,15 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Nightsnare extends CardImpl { public Nightsnare(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Target opponent reveals their hand. You may choose a nonland card from it. If you do, that player discards that card. If you don't, that player discards two cards. this.getSpellAbility().addTarget(new TargetOpponent()); @@ -57,11 +52,11 @@ class NightsnareDiscardEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); if (player != null && controller != null) { if (!player.getHand().isEmpty()) { Cards revealedCards = new CardsImpl(); revealedCards.addAll(player.getHand()); + Card sourceCard = game.getCard(source.getSourceId()); player.revealCards(sourceCard != null ? sourceCard.getIdName() : "Discard", revealedCards, game); // You may choose a nonland card from it. if (controller.chooseUse(outcome, "Choose a a card to discard? (Otherwise " + player.getLogName() + " has to discard 2 cards).", source, game)) { diff --git a/Mage.Sets/src/mage/cards/n/NikyaOfTheOldWays.java b/Mage.Sets/src/mage/cards/n/NikyaOfTheOldWays.java new file mode 100644 index 0000000000..cdb990392d --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NikyaOfTheOldWays.java @@ -0,0 +1,88 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.common.TapForManaAllTriggeredManaAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.mana.AddManaOfAnyTypeProducedEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledLandPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NikyaOfTheOldWays extends CardImpl { + + public NikyaOfTheOldWays(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.CENTAUR); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // You can't cast noncreature spells. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, new NikyaOfTheOldWaysCantCastEffect() + )); + + // Whenever you tap a land for mana, add one mana of any type that land produced. + AddManaOfAnyTypeProducedEffect effect = new AddManaOfAnyTypeProducedEffect(); + effect.setText("add one mana of any type that land produced"); + this.addAbility(new TapForManaAllTriggeredManaAbility( + effect, + new FilterControlledLandPermanent("you tap a land"), + SetTargetPointer.PERMANENT) + ); + } + + private NikyaOfTheOldWays(final NikyaOfTheOldWays card) { + super(card); + } + + @Override + public NikyaOfTheOldWays copy() { + return new NikyaOfTheOldWays(this); + } +} + +class NikyaOfTheOldWaysCantCastEffect extends ContinuousRuleModifyingEffectImpl { + + NikyaOfTheOldWaysCantCastEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "You can't cast noncreature spells"; + } + + private NikyaOfTheOldWaysCantCastEffect(final NikyaOfTheOldWaysCantCastEffect effect) { + super(effect); + } + + @Override + public NikyaOfTheOldWaysCantCastEffect copy() { + return new NikyaOfTheOldWaysCantCastEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getPlayerId().equals(source.getControllerId())) { + Card card = game.getCard(event.getSourceId()); + return card != null && !card.isCreature(); + } + return false; + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NimblePilferer.java b/Mage.Sets/src/mage/cards/n/NimblePilferer.java new file mode 100644 index 0000000000..bbd383b664 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NimblePilferer.java @@ -0,0 +1,36 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class NimblePilferer extends CardImpl { + + public NimblePilferer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + this.addAbility(FlashAbility.getInstance()); + } + + public NimblePilferer(final NimblePilferer card) { + super(card); + } + + @Override + public NimblePilferer copy() { + return new NimblePilferer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NinthBridgePatrol.java b/Mage.Sets/src/mage/cards/n/NinthBridgePatrol.java index ebbcfc3ca7..1ba7fd421b 100644 --- a/Mage.Sets/src/mage/cards/n/NinthBridgePatrol.java +++ b/Mage.Sets/src/mage/cards/n/NinthBridgePatrol.java @@ -26,7 +26,7 @@ public final class NinthBridgePatrol extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public NinthBridgePatrol(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java b/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java index 375be16f43..9403be8418 100644 --- a/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java +++ b/Mage.Sets/src/mage/cards/n/NissaNaturesArtisan.java @@ -84,8 +84,7 @@ class NissaNaturesArtisanEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 2)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 2)); if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); Set toBattlefield = new LinkedHashSet<>(); diff --git a/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java b/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java new file mode 100644 index 0000000000..4156d5ea05 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NissaWhoShakesTheWorld.java @@ -0,0 +1,149 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.mana.TriggeredManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledLandPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.command.emblems.NissaWhoShakesTheWorldEmblem; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.TokenImpl; +import mage.target.TargetPermanent; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NissaWhoShakesTheWorld extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledLandPermanent("noncreature land you control"); + private static final FilterCard filter2 = new FilterCard("Forest cards"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + filter2.add(new SubtypePredicate(SubType.FOREST)); + } + + public NissaWhoShakesTheWorld(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{G}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NISSA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Whenever you tap a Forest for mana, add an additional {G}. + this.addAbility(new NissaWhoShakesTheWorldTriggeredAbility()); + + // +1: Put three +1/+1 counters on up to one target noncreature land you control. Untap it. It becomes a 0/0 Elemental creature with vigilance and haste that's still a land. + Ability ability = new LoyaltyAbility(new AddCountersTargetEffect( + CounterType.P1P1.createInstance(3) + ), 1); + ability.addEffect(new UntapTargetEffect().setText("Untap it.")); + ability.addEffect(new BecomesCreatureTargetEffect( + new NissaWhoShakesTheWorldToken(), false, true, Duration.Custom + ).setText("It becomes a 0/0 Elemental creature with vigilance and haste that's still a land.")); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + this.addAbility(ability); + + // -8: You get an emblem with "Lands you control have indestructible." Search your library for any number of Forest cards, put them onto the battlefield tapped, then shuffle your library. + ability = new LoyaltyAbility(new GetEmblemEffect(new NissaWhoShakesTheWorldEmblem()), -8); + ability.addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary( + 0, Integer.MAX_VALUE, filter2 + ), true)); + this.addAbility(ability); + } + + private NissaWhoShakesTheWorld(final NissaWhoShakesTheWorld card) { + super(card); + } + + @Override + public NissaWhoShakesTheWorld copy() { + return new NissaWhoShakesTheWorld(this); + } +} + +class NissaWhoShakesTheWorldTriggeredAbility extends TriggeredManaAbility { + + private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("Forest"); + + static { + filter.add(new SubtypePredicate(SubType.FOREST)); + } + + NissaWhoShakesTheWorldTriggeredAbility() { + super(Zone.BATTLEFIELD, new BasicManaEffect(Mana.GreenMana(1)), false); + this.usesStack = false; + } + + private NissaWhoShakesTheWorldTriggeredAbility(final NissaWhoShakesTheWorldTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TAPPED_FOR_MANA; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent land = game.getPermanent(event.getTargetId()); + return land != null && filter.match(land, this.getSourceId(), this.getControllerId(), game); + } + + @Override + public NissaWhoShakesTheWorldTriggeredAbility copy() { + return new NissaWhoShakesTheWorldTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever you tap a Forest for mana, add an additional {G}."; + } +} + +class NissaWhoShakesTheWorldToken extends TokenImpl { + + NissaWhoShakesTheWorldToken() { + super("", "0/0 Elemental creature with vigilance and haste that's still a land."); + this.cardType.add(CardType.CREATURE); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + this.addAbility(HasteAbility.getInstance()); + this.addAbility(VigilanceAbility.getInstance()); + } + + private NissaWhoShakesTheWorldToken(final NissaWhoShakesTheWorldToken token) { + super(token); + } + + public NissaWhoShakesTheWorldToken copy() { + return new NissaWhoShakesTheWorldToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java b/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java index d4bb863132..ff0d0eecc9 100644 --- a/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java +++ b/Mage.Sets/src/mage/cards/n/NissaWorldwaker.java @@ -89,7 +89,7 @@ class NissaWorldwakerSearchEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); diff --git a/Mage.Sets/src/mage/cards/n/NissasChosen.java b/Mage.Sets/src/mage/cards/n/NissasChosen.java index 464d54f53e..d29dd45a7e 100644 --- a/Mage.Sets/src/mage/cards/n/NissasChosen.java +++ b/Mage.Sets/src/mage/cards/n/NissasChosen.java @@ -73,7 +73,7 @@ class NissasChosenEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (event.getTargetId().equals(source.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent)event; - if ( zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD ) { + if ( zEvent.isDiesEvent() ) { return true; } } diff --git a/Mage.Sets/src/mage/cards/n/NissasDefeat.java b/Mage.Sets/src/mage/cards/n/NissasDefeat.java index 09cbbdc2be..829cbcd1ed 100644 --- a/Mage.Sets/src/mage/cards/n/NissasDefeat.java +++ b/Mage.Sets/src/mage/cards/n/NissasDefeat.java @@ -26,7 +26,7 @@ import mage.target.TargetPermanent; */ public final class NissasDefeat extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("Forest, green enchantment, or green planeswalker"); + private static final FilterPermanent filter = new FilterPermanent("Forest, green enchantment, or green planeswalker"); static { filter.add(Predicates.or(new SubtypePredicate(SubType.FOREST), diff --git a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java index 030d75b2d9..a94f770385 100644 --- a/Mage.Sets/src/mage/cards/n/NissasEncouragement.java +++ b/Mage.Sets/src/mage/cards/n/NissasEncouragement.java @@ -77,7 +77,7 @@ class NissasEncouragementEffect extends OneShotEffect { } NissasEncouragementTarget target = new NissasEncouragementTarget(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { boolean searchGY = false; if (target.getTargets().size() < 3) { diff --git a/Mage.Sets/src/mage/cards/n/NissasJudgment.java b/Mage.Sets/src/mage/cards/n/NissasJudgment.java index 554ddd8068..cdb1103af4 100644 --- a/Mage.Sets/src/mage/cards/n/NissasJudgment.java +++ b/Mage.Sets/src/mage/cards/n/NissasJudgment.java @@ -27,7 +27,7 @@ import mage.target.targetpointer.SecondTargetPointer; */ public final class NissasJudgment extends CardImpl { - private final static FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creature an opponent controls"); static { FILTER.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -59,8 +59,8 @@ public final class NissasJudgment extends CardImpl { class NissasJudgmentEffect extends OneShotEffect { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); - private final static FilterCreaturePermanent filterWithCounter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filterWithCounter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/n/NissasPilgrimage.java b/Mage.Sets/src/mage/cards/n/NissasPilgrimage.java index af4dda2a14..14663db780 100644 --- a/Mage.Sets/src/mage/cards/n/NissasPilgrimage.java +++ b/Mage.Sets/src/mage/cards/n/NissasPilgrimage.java @@ -81,7 +81,7 @@ class NissasPilgrimageEffect extends OneShotEffect { number++; } TargetCardInLibrary target = new TargetCardInLibrary(0, number, filter); - controller.searchLibrary(target, game); + controller.searchLibrary(target, source, game); if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/n/NissasRevelation.java b/Mage.Sets/src/mage/cards/n/NissasRevelation.java index df4d2e4992..220dd0fe86 100644 --- a/Mage.Sets/src/mage/cards/n/NissasRevelation.java +++ b/Mage.Sets/src/mage/cards/n/NissasRevelation.java @@ -62,10 +62,10 @@ class NissasRevelationEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); if (card != null) { + Cards cards = new CardsImpl(); cards.add(card); controller.revealCards(sourceObject.getIdName(), cards, game); if (card.isCreature()) { diff --git a/Mage.Sets/src/mage/cards/n/NissasTriumph.java b/Mage.Sets/src/mage/cards/n/NissasTriumph.java new file mode 100644 index 0000000000..8d5a5ceb7f --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NissasTriumph.java @@ -0,0 +1,63 @@ +package mage.cards.n; + +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NissasTriumph extends CardImpl { + + private static final FilterCard filter = new FilterCard("basic Forest cards"); + private static final FilterPermanent filter2 = new FilterControlledPlaneswalkerPermanent(SubType.NISSA); + + static { + filter.add(new SupertypePredicate(SuperType.BASIC)); + filter.add(new SubtypePredicate(SubType.FOREST)); + } + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter2); + + public NissasTriumph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}"); + + // Search your land for up to two basic Forest cards. If you control a Nissa planeswalker, instead search your library for up to three land cards. reveal those cards, put them in your hand, then shuffle your library. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new SearchLibraryPutInHandEffect(new TargetCardInLibrary( + 0, 3, StaticFilters.FILTER_CARD_LAND + ), true, true), + new SearchLibraryPutInHandEffect(new TargetCardInLibrary( + 0, 2, filter + ), true, true), + new PermanentsOnTheBattlefieldCondition(filter2), + "Search your library for up to two basic Forest cards. If you control a Nissa planeswalker, " + + "instead search your library for up to three land cards. " + + "Reveal those cards, put them into your hand, then shuffle your library." + )); + } + + private NissasTriumph(final NissasTriumph card) { + super(card); + } + + @Override + public NissasTriumph copy() { + return new NissasTriumph(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NivMizzetReborn.java b/Mage.Sets/src/mage/cards/n/NivMizzetReborn.java new file mode 100644 index 0000000000..2e034d4878 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NivMizzetReborn.java @@ -0,0 +1,160 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NivMizzetReborn extends CardImpl { + + public NivMizzetReborn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}{B}{R}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DRAGON); + this.subtype.add(SubType.AVATAR); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Niv-Mizzet Reborn enters the battlefield, reveal the top ten cards of your library. For each color pair, choose a card that's exactly those colors from among them. Put the chosen cards into your hand and the rest on the bottom of your library in a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new NivMizzetRebornEffect())); + } + + private NivMizzetReborn(final NivMizzetReborn card) { + super(card); + } + + @Override + public NivMizzetReborn copy() { + return new NivMizzetReborn(this); + } +} + +class NivMizzetRebornEffect extends OneShotEffect { + + private static enum Guild { + G0("W", "U"), G1("W", "B"), G2("U", "B"), G3("U", "R"), G4("B", "R"), + G5("B", "G"), G6("R", "G"), G7("R", "W"), G8("G", "W"), G9("G", "U"); + + private static final Map nameMap = new HashMap(); + + static { + nameMap.put("W", "white"); + nameMap.put("U", "blue"); + nameMap.put("B", "black"); + nameMap.put("R", "red"); + nameMap.put("G", "green"); + } + + private final String color1; + private final String color2; + + private Guild(String color1, String color2) { + this.color1 = color1; + this.color2 = color2; + } + + private FilterCard makeFilter() { + FilterCard filter = new FilterCard(getDescription()); + filter.add(new ColorPredicate(new ObjectColor(color1))); + filter.add(new ColorPredicate(new ObjectColor(color2))); + for (char c : getOtherColors().toCharArray()) { + filter.add(Predicates.not(new ColorPredicate(new ObjectColor("" + c)))); + } + return filter; + } + + private TargetCard getTarget() { + return new TargetCardInLibrary(makeFilter()); + } + + private String getDescription() { + return "card that is exactly " + nameMap.get(color1) + " and " + nameMap.get(color2); + } + + private String getOtherColors() { + String colors = color1 + color2; + String otherColors = ""; + for (char c : "WUBRG".toCharArray()) { + if (color1.charAt(0) == c || color2.charAt(0) == c) { + continue; + } + otherColors += c; + } + return otherColors; + } + + private boolean isInCards(Cards cards, Game game) { + FilterCard filter = makeFilter(); + return cards.getCards(game).stream().anyMatch(card -> filter.match(card, game)); + } + } + + NivMizzetRebornEffect() { + super(Outcome.Benefit); + staticText = "reveal the top ten cards of your library. For each color pair, " + + "choose a card that's exactly those colors from among them. " + + "Put the chosen cards into your hand and the rest on the bottom of your library in a random order."; + } + + private NivMizzetRebornEffect(final NivMizzetRebornEffect effect) { + super(effect); + } + + @Override + public NivMizzetRebornEffect copy() { + return new NivMizzetRebornEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 10)); + Cards cards2 = new CardsImpl(); + if (cards.isEmpty()) { + return false; + } + player.revealCards(source, cards, game); + for (Guild guild : Guild.values()) { + if (!guild.isInCards(cards, game)) { + continue; + } + TargetCard target = guild.getTarget(); + if (player.choose(outcome, cards, target, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + cards2.add(card); + } + } + } + cards.removeAll(cards2); + player.putCardsOnBottomOfLibrary(cards, game, source, false); + player.moveCards(cards2, Zone.HAND, source, game); + return true; + } +} +// I think this is my favorite card I've ever implemented diff --git a/Mage.Sets/src/mage/cards/n/NoContest.java b/Mage.Sets/src/mage/cards/n/NoContest.java index 1298ece808..5a2f142127 100644 --- a/Mage.Sets/src/mage/cards/n/NoContest.java +++ b/Mage.Sets/src/mage/cards/n/NoContest.java @@ -1,8 +1,5 @@ - package mage.cards.n; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.common.FightTargetsEffect; import mage.cards.Card; @@ -19,6 +16,9 @@ import mage.game.stack.Spell; import mage.target.TargetPermanent; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.Set; +import java.util.UUID; + /** * @author Styxo */ @@ -56,8 +56,11 @@ class TargetCreatureWithLessPowerPermanent extends TargetPermanent { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - int maxPower = Integer.MIN_VALUE; // get the most poerful controlled creature that can be targeted + int maxPower = Integer.MIN_VALUE; // get the most powerful controlled creature that can be targeted Card sourceCard = game.getCard(sourceId); + if (sourceCard == null) { + return false; + } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURES, sourceControllerId, game)) { if (permanent.getPower().getValue() > maxPower && permanent.canBeTargetedBy(sourceCard, sourceControllerId, game)) { maxPower = permanent.getPower().getValue(); diff --git a/Mage.Sets/src/mage/cards/n/NoEscape.java b/Mage.Sets/src/mage/cards/n/NoEscape.java new file mode 100644 index 0000000000..c2a428a973 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NoEscape.java @@ -0,0 +1,49 @@ +package mage.cards.n; + +import mage.abilities.effects.common.CounterTargetWithReplacementEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class NoEscape extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("creature or planeswalker spell"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public NoEscape(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); + + // Counter target creature or planeswalker spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard. + this.getSpellAbility().addEffect(new CounterTargetWithReplacementEffect(Zone.EXILED)); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + + // Scry 1. + this.getSpellAbility().addEffect(new ScryEffect(1)); + } + + private NoEscape(final NoEscape card) { + super(card); + } + + @Override + public NoEscape copy() { + return new NoEscape(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NoRestForTheWicked.java b/Mage.Sets/src/mage/cards/n/NoRestForTheWicked.java index 063f4958cb..0b0ceb3c9b 100644 --- a/Mage.Sets/src/mage/cards/n/NoRestForTheWicked.java +++ b/Mage.Sets/src/mage/cards/n/NoRestForTheWicked.java @@ -58,11 +58,11 @@ class NoRestForTheWickedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - NoRestForTheWickedWatcher watcher = (NoRestForTheWickedWatcher) game.getState().getWatchers().get(NoRestForTheWickedWatcher.class.getSimpleName()); + NoRestForTheWickedWatcher watcher = game.getState().getWatcher(NoRestForTheWickedWatcher.class); Player controller = game.getPlayer(source.getControllerId()); if (watcher != null && controller != null) { Cards cardsToHand = new CardsImpl(); - for (UUID cardId : watcher.cards) { + for (UUID cardId : watcher.getCards()) { Card c = game.getCard(cardId); if (c != null) { if (game.getState().getZone(cardId) == Zone.GRAVEYARD @@ -87,10 +87,14 @@ class NoRestForTheWickedEffect extends OneShotEffect { class NoRestForTheWickedWatcher extends Watcher { - List cards; + public List getCards() { + return cards; + } + + private List cards; public NoRestForTheWickedWatcher() { - super(NoRestForTheWickedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.cards = new ArrayList<>(); } diff --git a/Mage.Sets/src/mage/cards/n/NobleBenefactor.java b/Mage.Sets/src/mage/cards/n/NobleBenefactor.java index 61b5936ff1..d223291a3c 100644 --- a/Mage.Sets/src/mage/cards/n/NobleBenefactor.java +++ b/Mage.Sets/src/mage/cards/n/NobleBenefactor.java @@ -71,7 +71,7 @@ class NobleBenefactorEffect extends OneShotEffect { if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(); if (player.chooseUse(Outcome.Benefit, "Search your library for a card to put into your hand?", source, game)) { - player.searchLibrary(target, game); + player.searchLibrary(target, source, game); for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/n/NobleStand.java b/Mage.Sets/src/mage/cards/n/NobleStand.java index ed5d96b202..5d490b1457 100644 --- a/Mage.Sets/src/mage/cards/n/NobleStand.java +++ b/Mage.Sets/src/mage/cards/n/NobleStand.java @@ -56,8 +56,8 @@ class NobleStandAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(Predicates.not(new TokenPredicate())); - Permanent permanent = (Permanent) game.getPermanent(event.getSourceId()); + filter.add(Predicates.not(TokenPredicate.instance)); + Permanent permanent = game.getPermanent(event.getSourceId()); return permanent != null && filter.match(permanent, sourceId, controllerId, game); } diff --git a/Mage.Sets/src/mage/cards/n/NogginWhack.java b/Mage.Sets/src/mage/cards/n/NogginWhack.java index 3d5311a951..5aa88225c4 100644 --- a/Mage.Sets/src/mage/cards/n/NogginWhack.java +++ b/Mage.Sets/src/mage/cards/n/NogginWhack.java @@ -96,7 +96,7 @@ class NogginWhackEffect extends OneShotEffect { if (!revealedCards.isEmpty()) { targetPlayer.revealCards("Noggin Whack", revealedCards, game); controller.chooseTarget(Outcome.Exile, revealedCards, targetInHand, source, game); - for (UUID cardId : (List) targetInHand.getTargets()) { + for (UUID cardId : targetInHand.getTargets()) { Card card = game.getCard(cardId); if (card != null) { controller.discard(card, source, game); diff --git a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java index c117f72761..c459491f62 100644 --- a/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java +++ b/Mage.Sets/src/mage/cards/n/NoggleHedgeMage.java @@ -27,8 +27,8 @@ import mage.target.common.TargetPlayerOrPlaneswalker; */ public final class NoggleHedgeMage extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent(); - private final static FilterLandPermanent filter2 = new FilterLandPermanent(); + private static final FilterLandPermanent filter = new FilterLandPermanent(); + private static final FilterLandPermanent filter2 = new FilterLandPermanent(); static { filter.add(new SubtypePredicate(SubType.ISLAND)); diff --git a/Mage.Sets/src/mage/cards/n/NostalgicDreams.java b/Mage.Sets/src/mage/cards/n/NostalgicDreams.java index b0de519a18..a9d8eec1ae 100644 --- a/Mage.Sets/src/mage/cards/n/NostalgicDreams.java +++ b/Mage.Sets/src/mage/cards/n/NostalgicDreams.java @@ -1,9 +1,7 @@ package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.costs.common.DiscardXTargetCost; import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.Effect; @@ -15,11 +13,12 @@ import mage.constants.CardType; import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.game.Game; -import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class NostalgicDreams extends CardImpl { @@ -33,27 +32,31 @@ public final class NostalgicDreams extends CardImpl { Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target cards from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(NostalgicDreamsAdjuster.instance); + // Exile Nostalgic Dreams. this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); - } public NostalgicDreams(final NostalgicDreams card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = new GetXValue().calculate(game, ability, null); - Target target = new TargetCardInYourGraveyard(xValue, StaticFilters.FILTER_CARD_FROM_YOUR_GRAVEYARD); - ability.addTarget(target); - } - - } - @Override public NostalgicDreams copy() { return new NostalgicDreams(this); } } + +enum NostalgicDreamsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard( + GetXValue.instance.calculate(game, ability, null), + StaticFilters.FILTER_CARD_FROM_YOUR_GRAVEYARD + )); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NosyGoblin.java b/Mage.Sets/src/mage/cards/n/NosyGoblin.java index d0bf2f67eb..369af08b43 100644 --- a/Mage.Sets/src/mage/cards/n/NosyGoblin.java +++ b/Mage.Sets/src/mage/cards/n/NosyGoblin.java @@ -26,7 +26,7 @@ public final class NosyGoblin extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public NosyGoblin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NotionThief.java b/Mage.Sets/src/mage/cards/n/NotionThief.java index 9ff6a3977a..75626aeb1a 100644 --- a/Mage.Sets/src/mage/cards/n/NotionThief.java +++ b/Mage.Sets/src/mage/cards/n/NotionThief.java @@ -90,7 +90,7 @@ class NotionThiefReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { if (game.isActivePlayer(event.getPlayerId()) && game.getStep().getType() == PhaseStep.DRAW) { - CardsDrawnDuringDrawStepWatcher watcher = (CardsDrawnDuringDrawStepWatcher) game.getState().getWatchers().get(CardsDrawnDuringDrawStepWatcher.class.getSimpleName()); + CardsDrawnDuringDrawStepWatcher watcher = game.getState().getWatcher(CardsDrawnDuringDrawStepWatcher.class); if (watcher != null && watcher.getAmountCardsDrawn(event.getPlayerId()) > 0) { return true; } diff --git a/Mage.Sets/src/mage/cards/n/NotoriousThrong.java b/Mage.Sets/src/mage/cards/n/NotoriousThrong.java index 8663f38d83..cb553b3b77 100644 --- a/Mage.Sets/src/mage/cards/n/NotoriousThrong.java +++ b/Mage.Sets/src/mage/cards/n/NotoriousThrong.java @@ -70,7 +70,7 @@ class NotoriousThrongEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = (AmountOfDamageAPlayerReceivedThisTurnWatcher) game.getState().getWatchers().get(AmountOfDamageAPlayerReceivedThisTurnWatcher.class.getSimpleName()); + AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class); if(controller != null && watcher != null) { int numTokens = 0; for(UUID opponentId: game.getOpponents(controller.getId())) { diff --git a/Mage.Sets/src/mage/cards/n/NourishingShoal.java b/Mage.Sets/src/mage/cards/n/NourishingShoal.java index f6459c1085..aa39d1d90f 100644 --- a/Mage.Sets/src/mage/cards/n/NourishingShoal.java +++ b/Mage.Sets/src/mage/cards/n/NourishingShoal.java @@ -36,7 +36,7 @@ public final class NourishingShoal extends CardImpl { this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); // You gain X life. - this.getSpellAbility().addEffect(new GainLifeEffect(new ExileFromHandCostCardConvertedMana())); + this.getSpellAbility().addEffect(new GainLifeEffect(ExileFromHandCostCardConvertedMana.instance)); } diff --git a/Mage.Sets/src/mage/cards/n/NovablastWurm.java b/Mage.Sets/src/mage/cards/n/NovablastWurm.java index b61d7f32c3..e8c8fc9e02 100644 --- a/Mage.Sets/src/mage/cards/n/NovablastWurm.java +++ b/Mage.Sets/src/mage/cards/n/NovablastWurm.java @@ -22,7 +22,7 @@ public final class NovablastWurm extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CardTypePredicate(CardType.CREATURE)); } diff --git a/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java b/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java index 9314df3c4a..c41310dc4d 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousGearhulk.java @@ -28,7 +28,7 @@ public final class NoxiousGearhulk extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public NoxiousGearhulk(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NoxiousGhoul.java b/Mage.Sets/src/mage/cards/n/NoxiousGhoul.java index 6f7d180757..a789298444 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousGhoul.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousGhoul.java @@ -1,7 +1,6 @@ package mage.cards.n; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.common.continuous.BoostAllEffect; @@ -10,42 +9,45 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; -import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardIdPredicate; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class NoxiousGhoul extends CardImpl { - final FilterPermanent filter = new FilterPermanent("Noxious Ghoul or another Zombie"); - final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("non-Zombie"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterPermanent(); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(Predicates.not(new SubtypePredicate(SubType.ZOMBIE))); + filter2.add(NoxiousGhoulPredicate.instance); + } public NoxiousGhoul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(3); this.toughness = new MageInt(3); - filter.add(Predicates.or( - new CardIdPredicate(this.getId()), - new SubtypePredicate(SubType.ZOMBIE))); - - filter2.add(new CardTypePredicate(CardType.CREATURE)); - filter2.add(Predicates.not( - new SubtypePredicate(SubType.ZOMBIE))); - - final String rule = "Whenever {this} or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn."; - // Whenever Noxious Ghoul or another Zombie enters the battlefield, all non-Zombie creatures get -1/-1 until end of turn. - this.addAbility(new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter2, false), filter, false, rule)); + this.addAbility(new EntersBattlefieldAllTriggeredAbility( + new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false), + filter2, "Whenever {this} or another Zombie enters the battlefield, " + + "all non-Zombie creatures get -1/-1 until end of turn." + )); } public NoxiousGhoul(final NoxiousGhoul card) { @@ -57,3 +59,13 @@ public final class NoxiousGhoul extends CardImpl { return new NoxiousGhoul(this); } } + +enum NoxiousGhoulPredicate implements ObjectSourcePlayerPredicate> { + instance; + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().hasSubtype(SubType.ZOMBIE, game) + || input.getObject().getId().equals(input.getSourceId()); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/n/NoxiousGroodion.java b/Mage.Sets/src/mage/cards/n/NoxiousGroodion.java new file mode 100644 index 0000000000..f9af47f5b8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NoxiousGroodion.java @@ -0,0 +1,36 @@ +package mage.cards.n; + +import mage.MageInt; +import mage.abilities.keyword.DeathtouchAbility; +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 NoxiousGroodion extends CardImpl { + + public NoxiousGroodion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + } + + private NoxiousGroodion(final NoxiousGroodion card) { + super(card); + } + + @Override + public NoxiousGroodion copy() { + return new NoxiousGroodion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/n/NoxiousRevival.java b/Mage.Sets/src/mage/cards/n/NoxiousRevival.java index 64d5e54525..5a8ee8c05e 100644 --- a/Mage.Sets/src/mage/cards/n/NoxiousRevival.java +++ b/Mage.Sets/src/mage/cards/n/NoxiousRevival.java @@ -2,27 +2,28 @@ package mage.cards.n; -import java.util.UUID; import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author Loki */ public final class NoxiousRevival extends CardImpl { - public NoxiousRevival (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G/P}"); + public NoxiousRevival(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G/P}"); + // Put target card from a graveyard on top of its owner’s library. this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); } - public NoxiousRevival (final NoxiousRevival card) { + public NoxiousRevival(final NoxiousRevival card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/n/NoxiousVapors.java b/Mage.Sets/src/mage/cards/n/NoxiousVapors.java new file mode 100644 index 0000000000..1e67b13521 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NoxiousVapors.java @@ -0,0 +1,109 @@ + +package mage.cards.n; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.common.FilterNonlandCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author L_J + */ +public final class NoxiousVapors extends CardImpl { + + public NoxiousVapors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{B}"); + + // Each player reveals their hand, chooses one card of each color from it, then discards all other nonland cards. + this.getSpellAbility().addEffect(new NoxiousVaporsEffect()); + + } + + public NoxiousVapors(final NoxiousVapors card) { + super(card); + } + + @Override + public NoxiousVapors copy() { + return new NoxiousVapors(this); + } +} + +class NoxiousVaporsEffect extends OneShotEffect { + + private static final FilterNonlandCard filter = new FilterNonlandCard(); + + public NoxiousVaporsEffect() { + super(Outcome.Benefit); + this.staticText = "Each player reveals their hand, chooses one card of each color from it, then discards all other nonland cards"; + } + + public NoxiousVaporsEffect(final NoxiousVaporsEffect effect) { + super(effect); + } + + @Override + public NoxiousVaporsEffect copy() { + return new NoxiousVaporsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.revealCards(player.getName() + "'s hand", player.getHand(), game); + } + } + + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + Set chosenCards = new HashSet<>(); + chooseCardForColor(ObjectColor.WHITE, chosenCards, player, game, source); + chooseCardForColor(ObjectColor.BLUE, chosenCards, player, game, source); + chooseCardForColor(ObjectColor.BLACK, chosenCards, player, game, source); + chooseCardForColor(ObjectColor.RED, chosenCards, player, game, source); + chooseCardForColor(ObjectColor.GREEN, chosenCards, player, game, source); + + Set cards = player.getHand().getCards(game); + for (Card card : cards) { + if (card != null && !chosenCards.contains(card) && filter.match(card, game)) { + player.discard(card, source, game); + } + } + } + } + return true; + } + return false; + } + + private void chooseCardForColor(ObjectColor color, Set chosenCards, Player player, Game game, Ability source) { + FilterCard filter = new FilterCard(); + filter.add(new ColorPredicate(color)); + TargetCardInHand target = new TargetCardInHand(filter); + if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + chosenCards.add(card); + } + } + } +} diff --git a/Mage.Sets/src/mage/cards/n/NullChamber.java b/Mage.Sets/src/mage/cards/n/NullChamber.java new file mode 100644 index 0000000000..c3562465a3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/n/NullChamber.java @@ -0,0 +1,163 @@ +package mage.cards.n; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetOpponent; +import mage.util.CardUtil; + +/** + * + * @author jeffwadsworth + */ +public final class NullChamber extends CardImpl { + + public NullChamber(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + this.addSuperType(SuperType.WORLD); + + // As Null Chamber enters the battlefield, you and an opponent each name a card other than a basic land card. + // The named cards can't be played. + this.addAbility(new AsEntersBattlefieldAbility(new NullChamberChooseEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NullChamberReplacementEffect())); + + } + + public NullChamber(final NullChamber card) { + super(card); + } + + @Override + public NullChamber copy() { + return new NullChamber(this); + } +} + +class NullChamberChooseEffect extends OneShotEffect { + + public static final String INFO_KEY_CONTROLLER = "CONTROLLER_NAMED_CARD"; + public static final String INFO_KEY_OPPONENT = "OPPONENT_NAMED_CARD"; + + public NullChamberChooseEffect() { + super(Outcome.AIDontUseIt); + staticText = "you and an opponent each name a card other than a basic land card"; + } + + public NullChamberChooseEffect(final NullChamberChooseEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + TargetOpponent chosenOpponent = new TargetOpponent(true); + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = game.getPermanentEntering(source.getSourceId()); + if (sourceObject == null) { + sourceObject = game.getObject(source.getSourceId()); + } + if (controller != null + && sourceObject != null + && controller.choose(Outcome.Neutral, chosenOpponent, source.getSourceId(), game)) { + Player opponent = game.getPlayer(chosenOpponent.getFirstTarget()); + Choice cardChoice = new ChoiceImpl(); + cardChoice.setChoices(CardRepository.instance.getNotBasicLandNames()); + cardChoice.setMessage("Choose a card name other than a basic land card name"); + cardChoice.clearChoice(); + if (controller.choose(Outcome.Detriment, cardChoice, game)) { + String cardName = cardChoice.getChoice(); + if (!game.isSimulation()) { + game.informPlayers(sourceObject.getLogName() + ", controller named card: [" + cardName + ']'); + } + game.getState().setValue(source.getSourceId().toString() + INFO_KEY_CONTROLLER, cardName); + if (sourceObject instanceof Permanent) { + ((Permanent) sourceObject).addInfo(INFO_KEY_CONTROLLER, CardUtil.addToolTipMarkTags("Named card (Controller): " + cardName), game); + } + } + cardChoice.clearChoice(); + if (opponent != null + && opponent.choose(Outcome.Detriment, cardChoice, game)) { + String cardName = cardChoice.getChoice(); + if (!game.isSimulation()) { + game.informPlayers(sourceObject.getLogName() + ",chosen opponent named card: [" + cardName + ']'); + } + game.getState().setValue(source.getSourceId().toString() + INFO_KEY_OPPONENT, cardName); + if (sourceObject instanceof Permanent) { + ((Permanent) sourceObject).addInfo(INFO_KEY_OPPONENT, CardUtil.addToolTipMarkTags("Named card (Opponent): " + cardName), game); + } + return true; + } + } + return false; + } + + @Override + public NullChamberChooseEffect copy() { + return new NullChamberChooseEffect(this); + } +} + +class NullChamberReplacementEffect extends ContinuousRuleModifyingEffectImpl { + + public NullChamberReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.AIDontUseIt); + staticText = "The named cards can't be played"; + } + + public NullChamberReplacementEffect(final NullChamberReplacementEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public NullChamberReplacementEffect copy() { + return new NullChamberReplacementEffect(this); + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can't cast a spell with that name (" + mageObject.getLogName() + " in play)."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject object = game.getObject(event.getSourceId()); + if (object != null) { + return object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_CONTROLLER)) + || object.getName().equals(game.getState().getValue(source.getSourceId().toString() + NullChamberChooseEffect.INFO_KEY_OPPONENT)); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/n/NullRod.java b/Mage.Sets/src/mage/cards/n/NullRod.java index bec7e30480..3d7e290512 100644 --- a/Mage.Sets/src/mage/cards/n/NullRod.java +++ b/Mage.Sets/src/mage/cards/n/NullRod.java @@ -1,7 +1,5 @@ - package mage.cards.n; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -13,14 +11,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class NullRod extends CardImpl { public NullRod(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Activated abilities of artifacts can't be activated. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NullRodCantActivateEffect())); @@ -53,7 +52,7 @@ class NullRodCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/n/NullmageShepherd.java b/Mage.Sets/src/mage/cards/n/NullmageShepherd.java index 0373a0c16e..38ed9f9b56 100644 --- a/Mage.Sets/src/mage/cards/n/NullmageShepherd.java +++ b/Mage.Sets/src/mage/cards/n/NullmageShepherd.java @@ -28,7 +28,7 @@ public final class NullmageShepherd extends CardImpl { private static final FilterControlledCreaturePermanent filterCost = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filterCost.add(Predicates.not(new TappedPredicate())); + filterCost.add(Predicates.not(TappedPredicate.instance)); } public NullmageShepherd(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java b/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java index 35cbeedc1d..54997e89b6 100644 --- a/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java +++ b/Mage.Sets/src/mage/cards/n/NullstoneGargoyle.java @@ -74,7 +74,7 @@ class NullstoneGargoyleTriggeredAbility extends TriggeredAbilityImpl { if (spell.isCreature()) { return false; } - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null && watcher.getNumberOfNonCreatureSpells() == 1) { for (Effect effect : getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); diff --git a/Mage.Sets/src/mage/cards/n/NutCollector.java b/Mage.Sets/src/mage/cards/n/NutCollector.java index fc95c90735..69a240a6cd 100644 --- a/Mage.Sets/src/mage/cards/n/NutCollector.java +++ b/Mage.Sets/src/mage/cards/n/NutCollector.java @@ -23,7 +23,7 @@ import mage.game.permanent.token.SquirrelToken; */ public final class NutCollector extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("squirrel"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("squirrel"); static { filter.add(new SubtypePredicate(SubType.SQUIRREL)); diff --git a/Mage.Sets/src/mage/cards/n/NuteGunray.java b/Mage.Sets/src/mage/cards/n/NuteGunray.java index aad1a83e17..bffe968bd2 100644 --- a/Mage.Sets/src/mage/cards/n/NuteGunray.java +++ b/Mage.Sets/src/mage/cards/n/NuteGunray.java @@ -34,7 +34,7 @@ public final class NuteGunray extends CardImpl { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("non-token artifact"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public NuteGunray(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/n/NyleasPresence.java b/Mage.Sets/src/mage/cards/n/NyleasPresence.java index ec6583e080..14cb39ed09 100644 --- a/Mage.Sets/src/mage/cards/n/NyleasPresence.java +++ b/Mage.Sets/src/mage/cards/n/NyleasPresence.java @@ -1,4 +1,3 @@ - package mage.cards.n; import mage.Mana; @@ -23,13 +22,12 @@ import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public final class NyleasPresence extends CardImpl { public NyleasPresence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); this.subtype.add(SubType.AURA); @@ -62,7 +60,7 @@ class NyleasPresenceLandTypeEffect extends ContinuousEffectImpl { public NyleasPresenceLandTypeEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); - landTypes.addAll(SubType.getBasicLands(false)); + landTypes.addAll(SubType.getBasicLands()); this.staticText = "Enchanted land is every basic land type in addition to its other types"; } @@ -90,11 +88,11 @@ class NyleasPresenceLandTypeEffect extends ContinuousEffectImpl { switch (layer) { case AbilityAddingRemovingEffects_6: Mana mana = new Mana(); - for (Ability ability : land.getAbilities()){ + for (Ability ability : land.getAbilities()) { if (ability instanceof BasicManaAbility) { - for (Mana netMana: ((BasicManaAbility)ability ).getNetMana(game)) { + for (Mana netMana : ((BasicManaAbility) ability).getNetMana(game)) { mana.add(netMana); - } + } } } if (mana.getGreen() == 0 && landTypes.contains(SubType.FOREST)) { diff --git a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java index b494987c9e..6333d5a3f3 100644 --- a/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java +++ b/Mage.Sets/src/mage/cards/o/OKagachiVengefulKami.java @@ -99,7 +99,7 @@ class OKagachiVengefulKamiTriggeredAbility extends TriggeredAbilityImpl { UUID you = this.getControllerId(); Permanent p = game.getPermanent(event.getSourceId()); if (damageEvent.isCombatDamage() && p != null && p.getId().equals(this.getSourceId())) { - PlayersAttackedLastTurnWatcher watcher = (PlayersAttackedLastTurnWatcher) game.getState().getWatchers().get(PlayersAttackedLastTurnWatcher.class.getSimpleName()); + PlayersAttackedLastTurnWatcher watcher = game.getState().getWatcher(PlayersAttackedLastTurnWatcher.class); if (watcher != null && watcher.attackedLastTurn(damagedPlayerId, you)) { FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent defending player controls"); filter.add(new ControllerIdPredicate(damagedPlayerId)); diff --git a/Mage.Sets/src/mage/cards/o/OakStreetInnkeeper.java b/Mage.Sets/src/mage/cards/o/OakStreetInnkeeper.java index bd5dbb0a8b..a25c0b1616 100644 --- a/Mage.Sets/src/mage/cards/o/OakStreetInnkeeper.java +++ b/Mage.Sets/src/mage/cards/o/OakStreetInnkeeper.java @@ -26,7 +26,7 @@ public final class OakStreetInnkeeper extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("tapped creatures you control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public OakStreetInnkeeper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OathOfChandra.java b/Mage.Sets/src/mage/cards/o/OathOfChandra.java index 4610ca8f5c..57f63826f9 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfChandra.java +++ b/Mage.Sets/src/mage/cards/o/OathOfChandra.java @@ -30,7 +30,7 @@ import mage.watchers.Watcher; */ public final class OathOfChandra extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -69,7 +69,7 @@ enum OathOfChandraCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - OathOfChandraWatcher watcher = (OathOfChandraWatcher) game.getState().getWatchers().get(OathOfChandraWatcher.class.getSimpleName()); + OathOfChandraWatcher watcher = game.getState().getWatcher(OathOfChandraWatcher.class); return watcher != null && watcher.enteredPlaneswalkerForPlayer(source.getControllerId()); } @@ -85,7 +85,7 @@ class OathOfChandraWatcher extends Watcher { private final Set players = new HashSet<>(); public OathOfChandraWatcher() { - super(OathOfChandraWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public OathOfChandraWatcher(final OathOfChandraWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/o/OathOfDruids.java b/Mage.Sets/src/mage/cards/o/OathOfDruids.java index c8bb0d56eb..652548ad6f 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfDruids.java +++ b/Mage.Sets/src/mage/cards/o/OathOfDruids.java @@ -1,15 +1,10 @@ package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TargetController; @@ -21,20 +16,15 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Plopman */ public final class OathOfDruids extends CardImpl { - private final UUID originalId; - private static final FilterPlayer filter = new FilterPlayer(); - - static { - filter.add(new OathOfDruidsPredicate()); - } - public OathOfDruids(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); @@ -42,27 +32,12 @@ public final class OathOfDruids extends CardImpl { // The first player may reveal cards from the top of their library until he or she reveals a creature card. // If he or she does, that player puts that card onto the battlefield and all other cards revealed this way into their graveyard. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfDruidsEffect(), TargetController.ANY, false); - ability.addTarget(new TargetPlayer(1, 1, false, filter)); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(OathOfDruidsAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, filter); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } - } - public OathOfDruids(final OathOfDruids card) { super(card); - this.originalId = card.originalId; } @Override @@ -71,6 +46,26 @@ public final class OathOfDruids extends CardImpl { } } +enum OathOfDruidsAdjuster implements TargetAdjuster { + instance; + private static final FilterPlayer filter = new FilterPlayer(); + + static { + filter.add(new OathOfDruidsPredicate()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + class OathOfDruidsPredicate implements ObjectSourcePlayerPredicate> { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); diff --git a/Mage.Sets/src/mage/cards/o/OathOfGhouls.java b/Mage.Sets/src/mage/cards/o/OathOfGhouls.java index 310ab0a52a..73b5eb4677 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfGhouls.java +++ b/Mage.Sets/src/mage/cards/o/OathOfGhouls.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -15,57 +14,36 @@ import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.FilterPlayer; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.TargetPlayer; import mage.target.common.TargetCardInGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class OathOfGhouls extends CardImpl { - private final UUID originalId; - private static final FilterPlayer filter = new FilterPlayer(); - - static { - filter.add(new OathOfGhoulsPredicate()); - } - public OathOfGhouls(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}"); // At the beginning of each player's upkeep, that player chooses target player whose graveyard has fewer creature cards in it than their graveyard does and is their opponent. The first player may return a creature card from their graveyard to their hand. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfGhoulsEffect(), TargetController.ANY, false); - ability.addTarget(new TargetPlayer(1, 1, false, filter)); + ability.setTargetAdjuster(OathOfGhoulsAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, filter); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public OathOfGhouls(final OathOfGhouls card) { super(card); - this.originalId = card.originalId; } @Override @@ -74,14 +52,28 @@ public final class OathOfGhouls extends CardImpl { } } -class OathOfGhoulsPredicate implements ObjectSourcePlayerPredicate> { - - private static final FilterCard filter = new FilterCard("creature cards"); +enum OathOfGhoulsAdjuster implements TargetAdjuster { + instance; + private static final FilterPlayer filter = new FilterPlayer(); static { - filter.add(new CardTypePredicate(CardType.CREATURE)); + filter.add(new OathOfGhoulsPredicate()); } + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + +class OathOfGhoulsPredicate implements ObjectSourcePlayerPredicate> { + @Override public boolean apply(ObjectSourcePlayer input, Game game) { Player targetPlayer = input.getObject(); @@ -91,8 +83,8 @@ class OathOfGhoulsPredicate implements ObjectSourcePlayerPredicate> { - private static final FilterLandPermanent FILTER = new FilterLandPermanent(); - @Override public boolean apply(ObjectSourcePlayer input, Game game) { Player targetPlayer = input.getObject(); @@ -119,8 +114,8 @@ class OathOfLiegesPredicate implements ObjectSourcePlayerPredicate countActivePlayer; } diff --git a/Mage.Sets/src/mage/cards/o/OathOfLiliana.java b/Mage.Sets/src/mage/cards/o/OathOfLiliana.java index 5e45a1e6be..d6e81fc775 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfLiliana.java +++ b/Mage.Sets/src/mage/cards/o/OathOfLiliana.java @@ -57,7 +57,7 @@ enum OathOfLilianaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - OathOfLilianaWatcher watcher = (OathOfLilianaWatcher) game.getState().getWatchers().get(OathOfLilianaWatcher.class.getSimpleName()); + OathOfLilianaWatcher watcher = game.getState().getWatcher(OathOfLilianaWatcher.class); return watcher != null && watcher.enteredPlaneswalkerForPlayer(source.getControllerId()); } @@ -73,7 +73,7 @@ class OathOfLilianaWatcher extends Watcher { private final Set players = new HashSet<>(); public OathOfLilianaWatcher() { - super(OathOfLilianaWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public OathOfLilianaWatcher(final OathOfLilianaWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/o/OathOfLimDul.java b/Mage.Sets/src/mage/cards/o/OathOfLimDul.java new file mode 100644 index 0000000000..f650fe4815 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OathOfLimDul.java @@ -0,0 +1,139 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInHand; +import mage.target.common.TargetControlledPermanent; + +/** + * + * @author jeffwadsworth + */ +public final class OathOfLimDul extends CardImpl { + + public OathOfLimDul(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}"); + + // Whenever you lose life, for each 1 life you lost, sacrifice a permanent other than Oath of Lim-Dul unless you discard a card. + this.addAbility(new OathOfLimDulTriggeredAbility()); + + // {B}{B}: Draw a card. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{B}{B}"))); + + } + + private OathOfLimDul(final OathOfLimDul card) { + super(card); + } + + @Override + public OathOfLimDul copy() { + return new OathOfLimDul(this); + } +} + +class OathOfLimDulTriggeredAbility extends TriggeredAbilityImpl { + + public OathOfLimDulTriggeredAbility() { + super(Zone.BATTLEFIELD, new OathOfLimDulEffect()); + } + + public OathOfLimDulTriggeredAbility(final OathOfLimDulTriggeredAbility ability) { + super(ability); + } + + @Override + public OathOfLimDulTriggeredAbility copy() { + return new OathOfLimDulTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.LOST_LIFE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getPlayerId().equals(controllerId)) { + game.getState().setValue(sourceId.toString() + "oathOfLimDul", event.getAmount()); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever you lose life, for each 1 life you lost, sacrifice a permanent other than {this} unless you discard a card."; + } +} + +class OathOfLimDulEffect extends OneShotEffect { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent("controlled permanent other than Oath of Lim-Dul"); + + static { + filter.add(AnotherPredicate.instance); + } + + public OathOfLimDulEffect() { + super(Outcome.Neutral); + } + + public OathOfLimDulEffect(final OathOfLimDulEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + int amount = (int) game.getState().getValue(source.getSourceId().toString() + "oathOfLimDul"); + if (amount > 0 + && controller != null) { + for (int i = 0; i < amount; i++) { + TargetControlledPermanent target = new TargetControlledPermanent(filter); + target.setNotTarget(true); + if (target.canChoose(controller.getId(), game) + && controller.choose(Outcome.Sacrifice, target, source.getSourceId(), game)) { + Cost cost = new DiscardTargetCost(new TargetCardInHand()); + if (cost.canPay(source, source.getSourceId(), controller.getId(), game) + && controller.chooseUse(Outcome.Benefit, + "Do you wish to discard a card rather than sacrifice the target permanent?", source, game)) { + cost.pay(source, game, source.getSourceId(), controller.getId(), true); + } else { + Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.sacrifice(source.getSourceId(), game); + } + } + } + } + return true; + } + return false; + } + + @Override + public OathOfLimDulEffect copy() { + return new OathOfLimDulEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/o/OathOfMages.java b/Mage.Sets/src/mage/cards/o/OathOfMages.java index 4f43c74665..9621fcb8a7 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfMages.java +++ b/Mage.Sets/src/mage/cards/o/OathOfMages.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -17,46 +16,26 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class OathOfMages extends CardImpl { - private final UUID originalId; - private static final FilterPlayer filter = new FilterPlayer(); - - static { - filter.add(new OathOfMagesPredicate()); - } - public OathOfMages(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // At the beginning of each player's upkeep, that player chooses target player who has more life than he or she does and is their opponent. The first player may have Oath of Mages deal 1 damage to the second player. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfMagesEffect(), TargetController.ANY, false); - ability.addTarget(new TargetPlayer(1, 1, false, filter)); + ability.setTargetAdjuster(OathOfMagesAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, filter); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public OathOfMages(final OathOfMages card) { super(card); - this.originalId = card.originalId; } @Override @@ -65,6 +44,26 @@ public final class OathOfMages extends CardImpl { } } +enum OathOfMagesAdjuster implements TargetAdjuster { + instance; + private static final FilterPlayer filter = new FilterPlayer(); + + static { + filter.add(new OathOfMagesPredicate()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + class OathOfMagesPredicate implements ObjectSourcePlayerPredicate> { @Override diff --git a/Mage.Sets/src/mage/cards/o/OathOfNissa.java b/Mage.Sets/src/mage/cards/o/OathOfNissa.java index 514e75cb56..6f3fd0a697 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfNissa.java +++ b/Mage.Sets/src/mage/cards/o/OathOfNissa.java @@ -48,7 +48,7 @@ public final class OathOfNissa extends CardImpl { class OathOfNissaEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("a creature, land, or planeswalker card"); + private static final FilterCard filter = new FilterCard("a creature, land, or planeswalker card"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), diff --git a/Mage.Sets/src/mage/cards/o/OathOfScholars.java b/Mage.Sets/src/mage/cards/o/OathOfScholars.java index 9a61ce6de8..75d206ce16 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfScholars.java +++ b/Mage.Sets/src/mage/cards/o/OathOfScholars.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -17,47 +16,26 @@ import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class OathOfScholars extends CardImpl { - private final UUID originalId; - private static final FilterPlayer filter = new FilterPlayer(); - - static { - filter.add(new OathOfScholarsPredicate()); - } - public OathOfScholars(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); // At the beginning of each player's upkeep, that player chooses target player who has more cards in hand than he or she does and is their opponent. The first player may discard their hand and draw three cards. Ability ability = new BeginningOfUpkeepTriggeredAbility(new OathOfScholarsEffect(), TargetController.ANY, false); - ability.addTarget(new TargetPlayer(1, 1, false, filter)); + ability.setTargetAdjuster(OathOfScholarsAdjuster.instance); this.addAbility(ability); - originalId = ability.getOriginalId(); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - TargetPlayer target = new TargetPlayer(1, 1, false, filter); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public OathOfScholars(final OathOfScholars card) { super(card); - this.originalId = card.originalId; } @Override @@ -66,6 +44,26 @@ public final class OathOfScholars extends CardImpl { } } +enum OathOfScholarsAdjuster implements TargetAdjuster { + instance; + private static final FilterPlayer filter = new FilterPlayer(); + + static { + filter.add(new OathOfScholarsPredicate()); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + TargetPlayer target = new TargetPlayer(1, 1, false, filter); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + class OathOfScholarsPredicate implements ObjectSourcePlayerPredicate> { @Override diff --git a/Mage.Sets/src/mage/cards/o/OathOfTeferi.java b/Mage.Sets/src/mage/cards/o/OathOfTeferi.java index 047d944768..b71265aaf5 100644 --- a/Mage.Sets/src/mage/cards/o/OathOfTeferi.java +++ b/Mage.Sets/src/mage/cards/o/OathOfTeferi.java @@ -33,10 +33,10 @@ import mage.target.targetpointer.FixedTarget; */ public final class OathOfTeferi extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("another target permanent you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target permanent you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public OathOfTeferi(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java b/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java index c73958f38d..d5718d8eab 100644 --- a/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java +++ b/Mage.Sets/src/mage/cards/o/OathkeeperTakenosDaisho.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; @@ -22,33 +20,38 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class OathkeeperTakenosDaisho extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("it's a Samurai card"); + static { filter.add(new SubtypePredicate(SubType.SAMURAI)); } public OathkeeperTakenosDaisho(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +3/+1. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3,1, Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(3, 1, Duration.WhileOnBattlefield))); + // Whenever equipped creature dies, return that card to the battlefield under your control if it's a Samurai card. this.addAbility(new ConditionalInterveningIfTriggeredAbility( - new DiesAttachedTriggeredAbility(new ReturnToBattlefieldUnderYourControlAttachedEffect(),"equipped creature", false), + new DiesAttachedTriggeredAbility(new ReturnToBattlefieldUnderYourControlAttachedEffect(), "equipped creature", false), new OathkeeperEquippedMatchesFilterCondition(filter), "")); + // When Oathkeeper, Takeno's Daisho is put into a graveyard from the battlefield, exile equipped creature. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new ExileEquippedEffect())); + // Equip {2} - this.addAbility(new EquipAbility( Outcome.BoostCreature, new ManaCostsImpl("{2}"))); + this.addAbility(new EquipAbility(Outcome.BoostCreature, new ManaCostsImpl("{2}"))); } public OathkeeperTakenosDaisho(final OathkeeperTakenosDaisho card) { @@ -114,14 +117,12 @@ class OathkeeperEquippedMatchesFilterCondition implements Condition { } } if (attachedTo == null) { - for (Effect effect :source.getEffects()) { + for (Effect effect : source.getEffects()) { attachedTo = (Permanent) effect.getValue("attachedTo"); } } if (attachedTo != null) { - if (filter.match(attachedTo, attachedTo.getId(),attachedTo.getControllerId(), game)) { - return true; - } + return filter.match(attachedTo, attachedTo.getId(), attachedTo.getControllerId(), game); } } diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java b/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java index 5bea48f7f8..3a1003695b 100644 --- a/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java +++ b/Mage.Sets/src/mage/cards/o/ObNixilisReignited.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.Effect; @@ -18,8 +16,9 @@ import mage.game.command.emblems.ObNixilisReignitedEmblem; import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ObNixilisReignited extends CardImpl { @@ -32,12 +31,10 @@ public final class ObNixilisReignited extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); // +1: You draw a card and you lose 1 life. - Effect effect = new DrawCardSourceControllerEffect(1); - effect.setText("You draw a card"); + Effect effect = new DrawCardSourceControllerEffect(1, "you"); LoyaltyAbility ability1 = new LoyaltyAbility(effect, 1); effect = new LoseLifeSourceControllerEffect(1); - effect.setText("and you lose 1 life"); - ability1.addEffect(effect); + ability1.addEffect(effect.concatBy("and")); this.addAbility(ability1); // -3: Destroy target creature. @@ -47,7 +44,6 @@ public final class ObNixilisReignited extends CardImpl { // -8: Target opponent gets an emblem with "Whenever a player draws a card, you lose 2 life." effect = new GetEmblemTargetPlayerEffect(new ObNixilisReignitedEmblem()); - effect.setText("Target opponent gets an emblem with \"Whenever a player draws a card, you lose 2 life.\""); LoyaltyAbility ability3 = new LoyaltyAbility(effect, -8); ability3.addTarget(new TargetOpponent()); this.addAbility(ability3); diff --git a/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java new file mode 100644 index 0000000000..43c3addb15 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObNixilisTheHateTwisted.java @@ -0,0 +1,85 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.DrawCardOpponentTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ObNixilisTheHateTwisted extends CardImpl { + + public ObNixilisTheHateTwisted(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.NIXILIS); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Whenever an opponent draws a card, Ob Nixilis, the Hate-Twisted deals 1 damage to that player. + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect( + 1, "that player" + ), false, true)); + + // -2: Destroy target creature. Its controller draws two cards. + Ability ability = new LoyaltyAbility(new ObNixilisTheHateTwistedEffect(), -2); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private ObNixilisTheHateTwisted(final ObNixilisTheHateTwisted card) { + super(card); + } + + @Override + public ObNixilisTheHateTwisted copy() { + return new ObNixilisTheHateTwisted(this); + } +} + +class ObNixilisTheHateTwistedEffect extends OneShotEffect { + + ObNixilisTheHateTwistedEffect() { + super(Outcome.Benefit); + staticText = "Destroy target creature. Its controller draws two cards"; + } + + private ObNixilisTheHateTwistedEffect(final ObNixilisTheHateTwistedEffect effect) { + super(effect); + } + + @Override + public ObNixilisTheHateTwistedEffect copy() { + return new ObNixilisTheHateTwistedEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.destroy(source.getSourceId(), game, false); + Player player = game.getPlayer(permanent.getControllerId()); + if (player == null) { + return false; + } + player.drawCards(2, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/o/ObNixilissCruelty.java b/Mage.Sets/src/mage/cards/o/ObNixilissCruelty.java new file mode 100644 index 0000000000..10f11b4b30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/ObNixilissCruelty.java @@ -0,0 +1,35 @@ +package mage.cards.o; + +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +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 ObNixilissCruelty extends CardImpl { + + public ObNixilissCruelty(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Target creature gets -5/-5 until end of turn. If that creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new BoostTargetEffect(-5, -5, Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private ObNixilissCruelty(final ObNixilissCruelty card) { + super(card); + } + + @Override + public ObNixilissCruelty copy() { + return new ObNixilissCruelty(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java b/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java index 6343c6ef0c..1eb686645d 100644 --- a/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java +++ b/Mage.Sets/src/mage/cards/o/ObiWanKenobi.java @@ -15,6 +15,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Duration; import mage.game.command.emblems.ObiWanKenobiEmblem; import mage.target.common.TargetCreaturePermanent; @@ -27,6 +28,7 @@ public final class ObiWanKenobi extends CardImpl { public ObiWanKenobi(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}{U}"); + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.OBI_WAN); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); diff --git a/Mage.Sets/src/mage/cards/o/OblivionRing.java b/Mage.Sets/src/mage/cards/o/OblivionRing.java index 8b5f337223..8c4700b069 100644 --- a/Mage.Sets/src/mage/cards/o/OblivionRing.java +++ b/Mage.Sets/src/mage/cards/o/OblivionRing.java @@ -27,7 +27,7 @@ public final class OblivionRing extends CardImpl { private static final FilterNonlandPermanent anotherNonlandPermanent = new FilterNonlandPermanent("another target nonland permanent"); static { - anotherNonlandPermanent.add(new AnotherPredicate()); + anotherNonlandPermanent.add(AnotherPredicate.instance); } public OblivionRing(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OblivionSower.java b/Mage.Sets/src/mage/cards/o/OblivionSower.java index 8742de4f54..f3c8a5272d 100644 --- a/Mage.Sets/src/mage/cards/o/OblivionSower.java +++ b/Mage.Sets/src/mage/cards/o/OblivionSower.java @@ -81,7 +81,7 @@ class OblivionSowerEffect extends OneShotEffect { if (controller != null && targetPlayer != null) { FilterLandCard filter = new FilterLandCard(); filter.add(new OwnerIdPredicate(targetPlayer.getId())); - filter.add(Predicates.not(new FaceDownPredicate())); + filter.add(Predicates.not(FaceDownPredicate.instance)); Cards exiledCards = new CardsImpl(); exiledCards.addAll(game.getExile().getAllCards(game)); Cards exiledLands = new CardsImpl(); diff --git a/Mage.Sets/src/mage/cards/o/OboroEnvoy.java b/Mage.Sets/src/mage/cards/o/OboroEnvoy.java index c4990fe881..fa6d5891b0 100644 --- a/Mage.Sets/src/mage/cards/o/OboroEnvoy.java +++ b/Mage.Sets/src/mage/cards/o/OboroEnvoy.java @@ -39,7 +39,7 @@ public final class OboroEnvoy extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // {2}, Return a land you control to its owner's hand: Target creature gets -X/-0 until end of turn, where X is the number of cards in your hand. - Effect effect = new BoostTargetEffect(new SignInversionDynamicValue(new CardsInControllerHandCount()), new StaticValue(-0), Duration.EndOfTurn, true); + Effect effect = new BoostTargetEffect(new SignInversionDynamicValue(CardsInControllerHandCount.instance), new StaticValue(-0), Duration.EndOfTurn, true); effect.setText("Target creature gets -X/-0 until end of turn, where X is the number of cards in your hand"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new GenericManaCost(2)); ability.addCost(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land")))); diff --git a/Mage.Sets/src/mage/cards/o/ObscuringAether.java b/Mage.Sets/src/mage/cards/o/ObscuringAether.java index 0f4aa3723c..1b4e559253 100644 --- a/Mage.Sets/src/mage/cards/o/ObscuringAether.java +++ b/Mage.Sets/src/mage/cards/o/ObscuringAether.java @@ -25,7 +25,7 @@ public final class ObscuringAether extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("Face-down creature spells"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public ObscuringAether(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java b/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java index 2edac2bd3e..d7ddf06f57 100644 --- a/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java +++ b/Mage.Sets/src/mage/cards/o/ObsessiveSkinner.java @@ -1,7 +1,7 @@ - package mage.cards.o; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -9,6 +9,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -18,13 +19,12 @@ import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; /** - * * @author fireshoes */ public final class ObsessiveSkinner extends CardImpl { public ObsessiveSkinner(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(1); @@ -43,6 +43,7 @@ public final class ObsessiveSkinner extends CardImpl { "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " + "put a +1/+1 counter on target creature."); ability.addTarget(new TargetCreaturePermanent()); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/Occupation.java b/Mage.Sets/src/mage/cards/o/Occupation.java index 52e7aeae9d..17434efa30 100644 --- a/Mage.Sets/src/mage/cards/o/Occupation.java +++ b/Mage.Sets/src/mage/cards/o/Occupation.java @@ -1,16 +1,12 @@ package mage.cards.o; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.RestrictionEffect; -import mage.abilities.effects.common.combat.CantAttackBlockTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -21,15 +17,16 @@ import mage.game.permanent.Permanent; import mage.game.turn.Step; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author NinthWorld */ public final class Occupation extends CardImpl { public Occupation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}{B}"); - + // Creatures your opponents control enter the battlefield tapped. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new OccupationTapEffect())); @@ -81,9 +78,7 @@ class OccupationTapEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (game.getOpponents(source.getControllerId()).contains(event.getPlayerId())) { Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - if (permanent != null && permanent.isCreature()) { - return true; - } + return permanent != null && permanent.isCreature(); } return false; } @@ -164,24 +159,21 @@ class OccupationRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (this.targetPointer.getTargets(game, source).contains(permanent.getId())) { - return true; - } + return this.targetPointer.getTargets(game, source).contains(permanent.getId()); + } + + @Override + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { - return false; - } - - @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/o/OddlyUneven.java b/Mage.Sets/src/mage/cards/o/OddlyUneven.java index 977754139e..49944a6422 100644 --- a/Mage.Sets/src/mage/cards/o/OddlyUneven.java +++ b/Mage.Sets/src/mage/cards/o/OddlyUneven.java @@ -28,7 +28,7 @@ public final class OddlyUneven extends CardImpl { this.getSpellAbility().addEffect(new OddOrEvenEffect(true)); // * Destroy each creature with an even number of words in its name. Mode mode = new Mode(); - mode.getEffects().add(new OddOrEvenEffect(false)); + mode.addEffect(new OddOrEvenEffect(false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/o/OddsEnds.java b/Mage.Sets/src/mage/cards/o/OddsEnds.java index e83b5f5258..efdd05d6e1 100644 --- a/Mage.Sets/src/mage/cards/o/OddsEnds.java +++ b/Mage.Sets/src/mage/cards/o/OddsEnds.java @@ -65,7 +65,7 @@ class OddsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, false)) { game.informPlayers("Odds: Spell countered"); return game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java b/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java index 70498e24c5..51541f2daa 100644 --- a/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java +++ b/Mage.Sets/src/mage/cards/o/OdricMasterTactician.java @@ -87,7 +87,7 @@ class OdricMasterTacticianTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean apply(Game game, Ability source) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); if (watcher != null) { watcher.increment(); return true; @@ -130,7 +130,10 @@ class OdricMasterTacticianChooseBlockersEffect extends ContinuousRuleModifyingEf @Override public boolean applies(GameEvent event, Ability source, Game game) { - ChooseBlockersRedundancyWatcher watcher = (ChooseBlockersRedundancyWatcher) game.getState().getWatchers().get(ChooseBlockersRedundancyWatcher.class.getSimpleName()); + ChooseBlockersRedundancyWatcher watcher = game.getState().getWatcher(ChooseBlockersRedundancyWatcher.class); + if(watcher == null){ + return false; + } watcher.decrement(); watcher.copyCount--; if (watcher.copyCountApply > 0) { diff --git a/Mage.Sets/src/mage/cards/o/Offalsnout.java b/Mage.Sets/src/mage/cards/o/Offalsnout.java index 042e3ec854..3bc244c8c9 100644 --- a/Mage.Sets/src/mage/cards/o/Offalsnout.java +++ b/Mage.Sets/src/mage/cards/o/Offalsnout.java @@ -1,10 +1,9 @@ package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.keyword.EvokeAbility; import mage.abilities.keyword.FlashAbility; @@ -15,14 +14,15 @@ import mage.constants.SubType; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Offalsnout extends CardImpl { public Offalsnout(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(2); @@ -31,7 +31,7 @@ public final class Offalsnout extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); // When Offalsnout leaves the battlefield, exile target card from a graveyard. - Ability ability = new EntersBattlefieldTriggeredAbility(new ExileTargetEffect(),false); + Ability ability = new LeavesBattlefieldTriggeredAbility(new ExileTargetEffect(), false); Target target = new TargetCardInGraveyard(); ability.addTarget(target); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/OgreBattledriver.java b/Mage.Sets/src/mage/cards/o/OgreBattledriver.java index 59f1085d22..accee71886 100644 --- a/Mage.Sets/src/mage/cards/o/OgreBattledriver.java +++ b/Mage.Sets/src/mage/cards/o/OgreBattledriver.java @@ -26,11 +26,11 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class OgreBattledriver extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Whenever another creature enters the battlefield under your control, that creature gets +2/+0 and gains haste until end of turn."; diff --git a/Mage.Sets/src/mage/cards/o/OgrePainbringer.java b/Mage.Sets/src/mage/cards/o/OgrePainbringer.java new file mode 100644 index 0000000000..6a51e5b650 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OgrePainbringer.java @@ -0,0 +1,38 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class OgrePainbringer extends CardImpl { + + public OgrePainbringer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + this.subtype.add(SubType.OGRE); + + this.power = new MageInt(7); + this.toughness = new MageInt(3); + + // When Ogre Painbringer enters the battlefield, it deals 3 damage to each player. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(3, TargetController.ANY, "it"))); + } + + public OgrePainbringer(final OgrePainbringer card) { + super(card); + } + + @Override + public OgrePainbringer copy() { + return new OgrePainbringer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OgreSlumlord.java b/Mage.Sets/src/mage/cards/o/OgreSlumlord.java index 475c981d67..9c63fbc483 100644 --- a/Mage.Sets/src/mage/cards/o/OgreSlumlord.java +++ b/Mage.Sets/src/mage/cards/o/OgreSlumlord.java @@ -31,8 +31,8 @@ public final class OgreSlumlord extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken creature"); private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("Rats you control"); static { - filter.add(Predicates.not(new TokenPredicate())); - filter.add(new AnotherPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); + filter.add(AnotherPredicate.instance); filter2.add(new SubtypePredicate(SubType.RAT)); } diff --git a/Mage.Sets/src/mage/cards/o/OjutaiExemplars.java b/Mage.Sets/src/mage/cards/o/OjutaiExemplars.java index 51c0839087..c4fd7a5059 100644 --- a/Mage.Sets/src/mage/cards/o/OjutaiExemplars.java +++ b/Mage.Sets/src/mage/cards/o/OjutaiExemplars.java @@ -54,15 +54,15 @@ public final class OjutaiExemplars extends CardImpl { Mode mode = new Mode(); Effect effect = new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn); effect.setText("{this} gains first strike"); - mode.getEffects().add(effect); + mode.addEffect(effect); Effect effect2 = new GainAbilitySourceEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn); effect2.setText("and lifelink until end of turn"); - mode.getEffects().add(effect2); + mode.addEffect(effect2); ability.addMode(mode); // or Exile Ojutai Exemplars, then return it to the battlefield tapped under its owner's control. mode = new Mode(); - mode.getEffects().add(new OjutaiExemplarsEffect()); + mode.addEffect(new OjutaiExemplarsEffect()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/OjutaisCommand.java b/Mage.Sets/src/mage/cards/o/OjutaisCommand.java index 1e4f6dcc47..38da309eb7 100644 --- a/Mage.Sets/src/mage/cards/o/OjutaisCommand.java +++ b/Mage.Sets/src/mage/cards/o/OjutaisCommand.java @@ -43,18 +43,18 @@ public final class OjutaisCommand extends CardImpl { // or You gain 4 life; Mode mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(4)); + mode.addEffect(new GainLifeEffect(4)); this.getSpellAbility().getModes().addMode(mode); // or Counter target creature spell; mode = new Mode(); - mode.getTargets().add(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE)); - mode.getEffects().add(new CounterTargetEffect()); + mode.addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE)); + mode.addEffect(new CounterTargetEffect()); this.getSpellAbility().getModes().addMode(mode); // or Draw a card mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(1)); + mode.addEffect(new DrawCardSourceControllerEffect(1)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/o/OkaunEyeOfChaos.java b/Mage.Sets/src/mage/cards/o/OkaunEyeOfChaos.java index f22d1ea5c5..884c23d125 100644 --- a/Mage.Sets/src/mage/cards/o/OkaunEyeOfChaos.java +++ b/Mage.Sets/src/mage/cards/o/OkaunEyeOfChaos.java @@ -1,7 +1,6 @@ package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfCombatTriggeredAbility; import mage.abilities.common.WinsCoinFlipTriggeredAbility; @@ -13,18 +12,18 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.keyword.PartnerWithAbility; 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.constants.TargetController; +import mage.constants.*; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class OkaunEyeOfChaos extends CardImpl { + private static final DynamicValue sourcePower = new SourcePermanentPowerCount(); + private static final DynamicValue sourceToughness = new SourcePermanentToughnessValue(); + public OkaunEyeOfChaos(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); @@ -41,8 +40,6 @@ public final class OkaunEyeOfChaos extends CardImpl { this.addAbility(new BeginningOfCombatTriggeredAbility(new FlipUntilLoseEffect(), TargetController.YOU, false)); // Whenever a player wins a coin flip, double Okaun's power and toughness until end of turn. - DynamicValue sourcePower = new SourcePermanentPowerCount(); - DynamicValue sourceToughness = new SourcePermanentToughnessValue(); this.addAbility(new WinsCoinFlipTriggeredAbility( new BoostSourceEffect( sourcePower, diff --git a/Mage.Sets/src/mage/cards/o/OketraTheTrue.java b/Mage.Sets/src/mage/cards/o/OketraTheTrue.java index 5938752fba..2d7a644c6e 100644 --- a/Mage.Sets/src/mage/cards/o/OketraTheTrue.java +++ b/Mage.Sets/src/mage/cards/o/OketraTheTrue.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,12 +11,7 @@ import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; @@ -26,8 +19,9 @@ import mage.game.permanent.Permanent; import mage.game.permanent.token.WarriorVigilantToken; import mage.players.Player; +import java.util.UUID; + /** - * * @author fireshoes */ public final class OketraTheTrue extends CardImpl { @@ -80,12 +74,12 @@ class OketraTheTrueRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/o/Okk.java b/Mage.Sets/src/mage/cards/o/Okk.java index 32194b9aac..022b0a59ea 100644 --- a/Mage.Sets/src/mage/cards/o/Okk.java +++ b/Mage.Sets/src/mage/cards/o/Okk.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,22 +7,23 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.filter.common.FilterBlockingCreature; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author icetc */ public final class Okk extends CardImpl { public Okk(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.GOBLIN); this.power = new MageInt(4); this.toughness = new MageInt(4); @@ -65,7 +64,7 @@ class OkkAttackEffect extends RestrictionEffect { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @@ -103,7 +102,7 @@ class OkkBlockEffect extends RestrictionEffect { } @Override - public boolean canBlockCheckAfter(Ability source, Game game) { + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/o/OldFogey.java b/Mage.Sets/src/mage/cards/o/OldFogey.java new file mode 100644 index 0000000000..dabcf1537f --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OldFogey.java @@ -0,0 +1,74 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.abilities.keyword.EchoAbility; +import mage.abilities.keyword.FadingAbility; +import mage.abilities.keyword.FlankingAbility; +import mage.abilities.keyword.LandwalkAbility; +import mage.abilities.keyword.PhasingAbility; +import mage.abilities.keyword.ProtectionAbility; +import mage.abilities.keyword.RampageAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class OldFogey extends CardImpl { + + private static final FilterCard filter = new FilterCard("Homarids"); + private static final FilterLandPermanent filter2 = new FilterLandPermanent("snow-covered plains"); + + static { + filter.add(new SubtypePredicate(SubType.HOMARID)); + filter2.add(new SupertypePredicate(SuperType.SNOW)); + filter2.add(new SubtypePredicate(SubType.PLAINS)); + } + + public OldFogey(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}{G}"); + this.subtype.add(SubType.DINOSAUR); + this.power = new MageInt(7); + this.toughness = new MageInt(7); + + // Phasing + this.addAbility(PhasingAbility.getInstance()); + // Cumulative upkeep {1} + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{1}"))); + // Echo {G}{G} + this.addAbility(new EchoAbility("{G}{G}")); + // Fading 3 + this.addAbility(new FadingAbility(3, this, true)); + // Bands with other Dinosaurs + this.addAbility(new BandsWithOtherAbility(SubType.DINOSAUR)); + // Protection from Homarids + this.addAbility(new ProtectionAbility(filter)); + // Snow-covered plainswalk + this.addAbility(new LandwalkAbility(filter2)); + // Flanking + this.addAbility(new FlankingAbility()); + // Rampage 2 + this.addAbility(new RampageAbility(2, true)); + } + + public OldFogey(final OldFogey card) { + super(card); + } + + @Override + public OldFogey copy() { + return new OldFogey(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OldGrowthDryads.java b/Mage.Sets/src/mage/cards/o/OldGrowthDryads.java index a6ebc1b4c3..409a599c1b 100644 --- a/Mage.Sets/src/mage/cards/o/OldGrowthDryads.java +++ b/Mage.Sets/src/mage/cards/o/OldGrowthDryads.java @@ -71,7 +71,7 @@ class OldGrowthDryadsEffect extends OneShotEffect { Player opponent = game.getPlayer(opponentId); if (opponent != null && opponent.chooseUse(Outcome.PutLandInPlay, "Search your library for a basic land card and put it onto the battlefield tapped?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); - if (opponent.searchLibrary(target, game)) { + if (opponent.searchLibrary(target, source, game)) { Card targetCard = opponent.getLibrary().getCard(target.getFirstTarget(), game); if (targetCard != null) { opponent.moveCards(targetCard, Zone.BATTLEFIELD, source, game, true, false, false, null); diff --git a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java index 6e5a6763ed..c221c91dc2 100644 --- a/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java +++ b/Mage.Sets/src/mage/cards/o/OliviaVoldaren.java @@ -36,7 +36,7 @@ public final class OliviaVoldaren extends CardImpl { private static final FilterCreaturePermanent vampireFilter = new FilterCreaturePermanent("Vampire"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); vampireFilter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java b/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java index a5e986680f..797552378e 100644 --- a/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java +++ b/Mage.Sets/src/mage/cards/o/OnceMoreWithFeeling.java @@ -28,7 +28,7 @@ public final class OnceMoreWithFeeling extends CardImpl { public OnceMoreWithFeeling(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W}{W}{W}{W}"); - // Exile all permanents and all cards from all graveyards. Each player shuffles his or her hand into his or her library, then draws seven cards. Each player's life total becomes 10. Exile Once More with Feeling. + // Exile all permanents and all cards from all graveyards. Each player shuffles their hand into their library, then draws seven cards. Each player's life total becomes 10. Exile Once More with Feeling. this.getSpellAbility().addEffect(new OnceMoreWithFeelingEffect()); Effect effect = new DrawCardAllEffect(7); effect.setText(", then draws seven cards"); diff --git a/Mage.Sets/src/mage/cards/o/OnduWarCleric.java b/Mage.Sets/src/mage/cards/o/OnduWarCleric.java index 4a70adcb89..8ca40e0e6c 100644 --- a/Mage.Sets/src/mage/cards/o/OnduWarCleric.java +++ b/Mage.Sets/src/mage/cards/o/OnduWarCleric.java @@ -30,7 +30,7 @@ public final class OnduWarCleric extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public OnduWarCleric(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OneDozenEyes.java b/Mage.Sets/src/mage/cards/o/OneDozenEyes.java index 42bb0c0f5f..a49609571e 100644 --- a/Mage.Sets/src/mage/cards/o/OneDozenEyes.java +++ b/Mage.Sets/src/mage/cards/o/OneDozenEyes.java @@ -27,7 +27,7 @@ public final class OneDozenEyes extends CardImpl { this.getSpellAbility().addEffect(new CreateTokenEffect(new OneDozenEyesBeastToken())); // or create five 1/1 green Insect creature tokens. Mode mode = new Mode(); - mode.getEffects().add(new CreateTokenEffect(new InsectToken(), 5)); + mode.addEffect(new CreateTokenEffect(new InsectToken(), 5)); this.getSpellAbility().addMode(mode); // Entwine {G}{G}{G} this.addAbility(new EntwineAbility("{G}{G}{G}")); diff --git a/Mage.Sets/src/mage/cards/o/OnwardVictory.java b/Mage.Sets/src/mage/cards/o/OnwardVictory.java index b70f7bd4ae..e5d5aa698d 100644 --- a/Mage.Sets/src/mage/cards/o/OnwardVictory.java +++ b/Mage.Sets/src/mage/cards/o/OnwardVictory.java @@ -25,12 +25,12 @@ public final class OnwardVictory extends SplitCard { // Onward // Target creature gets +X/+0 until end of turn where X is its power. getLeftHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); - getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true)); + getLeftHalfCard().getSpellAbility().addEffect(new BoostTargetEffect(TargetPermanentPowerCount.instance, new StaticValue(0), Duration.EndOfTurn, true)); // to // Victory // Target creature gains double strike until end of turn. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); Effect effect = new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn); getRightHalfCard().getSpellAbility().addEffect(effect); getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/o/OnyxTalisman.java b/Mage.Sets/src/mage/cards/o/OnyxTalisman.java index 47beb9b901..75d3edb13f 100644 --- a/Mage.Sets/src/mage/cards/o/OnyxTalisman.java +++ b/Mage.Sets/src/mage/cards/o/OnyxTalisman.java @@ -21,7 +21,7 @@ import mage.target.TargetPermanent; */ public final class OnyxTalisman extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a black spell"); + private static final FilterSpell filter = new FilterSpell("a black spell"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); diff --git a/Mage.Sets/src/mage/cards/o/OpalAcrolith.java b/Mage.Sets/src/mage/cards/o/OpalAcrolith.java new file mode 100644 index 0000000000..235bf3a362 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OpalAcrolith.java @@ -0,0 +1,77 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +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.continuous.BecomesCreatureSourceEffect; +import mage.abilities.effects.common.continuous.BecomesEnchantmentSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class OpalAcrolith extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("creature spell"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public OpalAcrolith(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // Whenever an opponent casts a creature spell, if Opal Acrolith is an enchantment, Opal Acrolith becomes a 2/4 Soldier creature. + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new OpalAcrolithToken(), "", Duration.WhileOnBattlefield, true, false), + filter, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever an opponent casts a creature spell, if Opal Acrolith is an enchantment, Opal Acrolith becomes a 2/4 Soldier creature.")); + + // {0}: Opal Acrolith becomes an enchantment. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesEnchantmentSourceEffect(), new ManaCostsImpl("{0}"))); + + } + + public OpalAcrolith(final OpalAcrolith card) { + super(card); + } + + @Override + public OpalAcrolith copy() { + return new OpalAcrolith(this); + } +} + +class OpalAcrolithToken extends TokenImpl { + + public OpalAcrolithToken() { + super("Soldier", "2/4 Soldier creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SOLDIER); + power = new MageInt(2); + toughness = new MageInt(4); + } + + public OpalAcrolithToken(final OpalAcrolithToken token) { + super(token); + } + + public OpalAcrolithToken copy() { + return new OpalAcrolithToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OpalAvenger.java b/Mage.Sets/src/mage/cards/o/OpalAvenger.java new file mode 100644 index 0000000000..425200a714 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OpalAvenger.java @@ -0,0 +1,126 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class OpalAvenger extends CardImpl { + + public OpalAvenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // When you have 10 or less life, if Opal Avenger is an enchantment, Opal Avenger becomes a 3/5 Soldier creature. + this.addAbility(new OpalAvengerStateTriggeredAbility()); + } + + public OpalAvenger(final OpalAvenger card) { + super(card); + } + + @Override + public OpalAvenger copy() { + return new OpalAvenger(this); + } +} + +class OpalAvengerStateTriggeredAbility extends StateTriggeredAbility { + + public OpalAvengerStateTriggeredAbility() { + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new OpalAvengerToken(), "", Duration.Custom, true, false)); + } + + public OpalAvengerStateTriggeredAbility(final OpalAvengerStateTriggeredAbility ability) { + super(ability); + } + + @Override + public OpalAvengerStateTriggeredAbility copy() { + return new OpalAvengerStateTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (game.getState().getPlayer(getControllerId()) != null) { + return game.getState().getPlayer(getControllerId()).getLife() <= 10; + } + return false; + } + + @Override + public boolean checkInterveningIfClause(Game game) { + if (getSourcePermanentIfItStillExists(game) != null) { + return getSourcePermanentIfItStillExists(game).isEnchantment(); + } + return false; + } + + @Override + public boolean canTrigger(Game game) { + //20100716 - 603.8 + Boolean triggered = (Boolean) game.getState().getValue(getSourceId().toString() + "triggered"); + if (triggered == null) { + triggered = Boolean.FALSE; + } + return !triggered; + } + + @Override + public void trigger(Game game, UUID controllerId) { + //20100716 - 603.8 + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE); + super.trigger(game, controllerId); + } + + @Override + public boolean resolve(Game game) { + //20100716 - 603.8 + boolean result = super.resolve(game); + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + return result; + } + + @Override + public void counter(Game game) { + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + } + + @Override + public String getRule() { + return "When you have 10 or less life, if {this} is an enchantment, " + super.getRule(); + } + +} + +class OpalAvengerToken extends TokenImpl { + + public OpalAvengerToken() { + super("Soldier", "3/5 Soldier creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SOLDIER); + power = new MageInt(3); + toughness = new MageInt(5); + } + + public OpalAvengerToken(final OpalAvengerToken token) { + super(token); + } + + @Override + public OpalAvengerToken copy() { + return new OpalAvengerToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java b/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java index 4a41c8e08d..4d57054223 100644 --- a/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java +++ b/Mage.Sets/src/mage/cards/o/OpalLakeGatekeepers.java @@ -1,13 +1,12 @@ - - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.hint.ConditionHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,8 +15,9 @@ import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ @@ -25,12 +25,15 @@ import mage.filter.predicate.mageobject.SubtypePredicate; public final class OpalLakeGatekeepers extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + static { filter.add(new SubtypePredicate(SubType.GATE)); } - public OpalLakeGatekeepers (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public OpalLakeGatekeepers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.VEDALKEN); this.subtype.add(SubType.SOLDIER); @@ -40,11 +43,12 @@ public final class OpalLakeGatekeepers extends CardImpl { // When Opal Lake Gatekeepers enters the battlefield, if you control two or more Gates, you may draw a card. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1)), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), - "When Opal Lake Gatekeepers enters the battlefield, if you control two or more Gates, you may draw a card.")); + gatesCondition, + "When Opal Lake Gatekeepers enters the battlefield, if you control two or more Gates, you may draw a card.") + .addHint(new ConditionHint(gatesCondition, "You control two or more Gates"))); } - public OpalLakeGatekeepers (final OpalLakeGatekeepers card) { + public OpalLakeGatekeepers(final OpalLakeGatekeepers card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/o/OpalPalace.java b/Mage.Sets/src/mage/cards/o/OpalPalace.java index 345496aa2d..e010390c4f 100644 --- a/Mage.Sets/src/mage/cards/o/OpalPalace.java +++ b/Mage.Sets/src/mage/cards/o/OpalPalace.java @@ -63,20 +63,24 @@ public final class OpalPalace extends CardImpl { class OpalPalaceWatcher extends Watcher { - public List commanderId = new ArrayList<>(); + private List commanderId = new ArrayList<>(); private final String originalId; public OpalPalaceWatcher(String originalId) { - super(OpalPalaceWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); this.originalId = originalId; } - public OpalPalaceWatcher(final OpalPalaceWatcher watcher) { + private OpalPalaceWatcher(final OpalPalaceWatcher watcher) { super(watcher); this.commanderId.addAll(watcher.commanderId); this.originalId = watcher.originalId; } + public boolean manaUsedToCastCommander(UUID id){ + return commanderId.contains(id); + } + @Override public OpalPalaceWatcher copy() { return new OpalPalaceWatcher(this); @@ -119,7 +123,7 @@ class OpalPalaceEntersBattlefieldEffect extends ReplacementEffectImpl { staticText = "If you spend this mana to cast your commander, it enters the battlefield with a number of +1/+1 counters on it equal to the number of times it's been cast from the command zone this game"; } - public OpalPalaceEntersBattlefieldEffect(OpalPalaceEntersBattlefieldEffect effect) { + private OpalPalaceEntersBattlefieldEffect(OpalPalaceEntersBattlefieldEffect effect) { super(effect); } @@ -130,9 +134,9 @@ class OpalPalaceEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - OpalPalaceWatcher watcher = (OpalPalaceWatcher) game.getState().getWatchers().get(OpalPalaceWatcher.class.getSimpleName(), source.getSourceId()); + OpalPalaceWatcher watcher = game.getState().getWatcher(OpalPalaceWatcher.class, source.getSourceId()); return watcher != null - && watcher.commanderId.contains(event.getTargetId()); + && watcher.manaUsedToCastCommander(event.getTargetId()); } @Override diff --git a/Mage.Sets/src/mage/cards/o/OpalTitan.java b/Mage.Sets/src/mage/cards/o/OpalTitan.java new file mode 100644 index 0000000000..d75f1cd1e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OpalTitan.java @@ -0,0 +1,145 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.MageObjectReference; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.SourceEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import static mage.constants.Layer.PTChangingEffects_7; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; + +/** + * + * @author jeffwadsworth + */ +public final class OpalTitan extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("creature spell"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public OpalTitan(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}{W}"); + + // When an opponent casts a creature spell, if Opal Titan is an enchantment, Opal Titan becomes a 4/4 Giant creature with protection from each of that spell's colors. + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new OpalTitanBecomesCreatureEffect(), + filter, false, SetTargetPointer.SPELL); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "When an opponent casts a creature spell, if Opal Titan is an enchantment, Opal Titan becomes a 4/4 Giant creature with protection from each of that spell's colors.")); + + } + + public OpalTitan(final OpalTitan card) { + super(card); + } + + @Override + public OpalTitan copy() { + return new OpalTitan(this); + } +} + +class OpalTitanBecomesCreatureEffect extends ContinuousEffectImpl implements SourceEffect { + + public OpalTitanBecomesCreatureEffect() { + super(Duration.WhileOnBattlefield, Outcome.BecomeCreature); + staticText = "{this} becomes a 4/4 Giant creature with protection from each of that spell's colors."; + this.addDependencyType(DependencyType.BecomeCreature); + } + + public OpalTitanBecomesCreatureEffect(final OpalTitanBecomesCreatureEffect effect) { + super(effect); + } + + @Override + public OpalTitanBecomesCreatureEffect copy() { + return new OpalTitanBecomesCreatureEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + Spell creatureSpellCast = game.getSpell(targetPointer.getFirst(game, source)); + if (creatureSpellCast != null + && creatureSpellCast.getColor(game).hasColor()) { + game.getState().setValue("opalTitanColor" + source.getSourceId(), creatureSpellCast.getColor(game)); + } + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = affectedObjectList.get(0).getPermanent(game); + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + permanent.getCardType().clear(); + permanent.addCardType(CardType.CREATURE); + permanent.getSubtype(game).add(SubType.GIANT); + } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + if (game.getState().getValue("opalTitanColor" + source.getSourceId()) != null) { + for (ObjectColor color : ((ObjectColor) game.getState().getValue("opalTitanColor" + source.getSourceId())).getColors()) { + if (!permanent.getAbilities().contains(ProtectionAbility.from(color))) { + permanent.addAbility(ProtectionAbility.from(color)); + } + } + } + } + break; + case PTChangingEffects_7: + if ((sublayer == SubLayer.CharacteristicDefining_7a) + || (sublayer == SubLayer.SetPT_7b)) { + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + } + break; + } + return true; + } + this.discard(); + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 + || layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; + } + +} diff --git a/Mage.Sets/src/mage/cards/o/Opalescence.java b/Mage.Sets/src/mage/cards/o/Opalescence.java index 8037d645d0..40319bcfcd 100644 --- a/Mage.Sets/src/mage/cards/o/Opalescence.java +++ b/Mage.Sets/src/mage/cards/o/Opalescence.java @@ -52,7 +52,7 @@ class OpalescenceEffect extends ContinuousEffectImpl { static { filter.add(Predicates.not(new SubtypePredicate(SubType.AURA))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); checkDependencyTypes = EnumSet.of(DependencyType.AuraAddingRemoving, DependencyType.EnchantmentAddingRemoving); } diff --git a/Mage.Sets/src/mage/cards/o/OpenIntoWonder.java b/Mage.Sets/src/mage/cards/o/OpenIntoWonder.java index 41ef18e9eb..e92b99a2b5 100644 --- a/Mage.Sets/src/mage/cards/o/OpenIntoWonder.java +++ b/Mage.Sets/src/mage/cards/o/OpenIntoWonder.java @@ -1,9 +1,7 @@ package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; @@ -13,12 +11,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class OpenIntoWonder extends CardImpl { @@ -30,28 +29,28 @@ public final class OpenIntoWonder extends CardImpl { Effect effect = new CantBeBlockedTargetEffect(Duration.EndOfTurn); effect.setText("X target creatures can't be blocked this turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false)); Ability abilityToGain = new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), false); this.getSpellAbility().addEffect(new GainAbilityTargetEffect(abilityToGain, Duration.EndOfTurn, "Until end of turn, those creatures gain \"Whenever this creature deals combat damage to a player, draw a card.\"")); + this.getSpellAbility().setTargetAdjuster(OpenIntoWonderAdjuster.instance); } public OpenIntoWonder(final OpenIntoWonder card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numberOfTargets = ability.getManaCostsToPay().getX(); - numberOfTargets = Math.min(game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, ability.getSourceId(), ability.getControllerId(), game), numberOfTargets); - ability.addTarget(new TargetCreaturePermanent(numberOfTargets)); - } - } - @Override public OpenIntoWonder copy() { return new OpenIntoWonder(this); } } + +enum OpenIntoWonderAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/o/OpenSeason.java b/Mage.Sets/src/mage/cards/o/OpenSeason.java index 74377fe722..e43e9d4ca5 100644 --- a/Mage.Sets/src/mage/cards/o/OpenSeason.java +++ b/Mage.Sets/src/mage/cards/o/OpenSeason.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -22,10 +20,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; -import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Styxo */ public final class OpenSeason extends CardImpl { @@ -37,7 +36,7 @@ public final class OpenSeason extends CardImpl { Effect effect = new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()); effect.setText("for each opponent, put a bounty counter on target creature that player controls"); Ability ability = new EntersBattlefieldTriggeredAbility(effect); - ability.addTarget(new TargetCreaturePermanent()); + ability.setTargetAdjuster(OpenSeasonAdjuster.instance); this.addAbility(ability); // Creatures your opponent control with bounty counters on them can't activate abilities @@ -48,19 +47,6 @@ public final class OpenSeason extends CardImpl { } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()))); - } - } - } - } - public OpenSeason(final OpenSeason card) { super(card); } @@ -71,6 +57,21 @@ public final class OpenSeason extends CardImpl { } } +enum OpenSeasonAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + ability.addTarget(new TargetPermanent(new FilterCreaturePermanent("creature from opponent " + opponent.getLogName()))); + } + } + } +} + class OpenSeasonRestrictionEffect extends RestrictionEffect { public OpenSeasonRestrictionEffect() { @@ -90,7 +91,7 @@ class OpenSeasonRestrictionEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/o/OpenTheArmory.java b/Mage.Sets/src/mage/cards/o/OpenTheArmory.java index d529110cf8..a0063c18b6 100644 --- a/Mage.Sets/src/mage/cards/o/OpenTheArmory.java +++ b/Mage.Sets/src/mage/cards/o/OpenTheArmory.java @@ -40,15 +40,15 @@ public final class OpenTheArmory extends CardImpl { class OpenTheArmoryTarget extends TargetCardInLibrary { - private static final FilterCard filter = new FilterCard("Aura or Equipment card"); + private static final FilterCard auraOrEquipmentTarget = new FilterCard("Aura or Equipment card"); static { - filter.add(Predicates.or( + auraOrEquipmentTarget.add(Predicates.or( new SubtypePredicate(SubType.EQUIPMENT), new SubtypePredicate(SubType.AURA))); } public OpenTheArmoryTarget() { - super(1, 1, filter.copy()); + super(1, 1, auraOrEquipmentTarget.copy()); } public OpenTheArmoryTarget(final OpenTheArmoryTarget target) { @@ -64,7 +64,7 @@ class OpenTheArmoryTarget extends TargetCardInLibrary { public boolean canTarget(UUID id, Cards cards, Game game) { Card card = cards.get(id, game); if (card != null) { - return filter.match(card, game); + return auraOrEquipmentTarget.match(card, game); } return false; } diff --git a/Mage.Sets/src/mage/cards/o/OpenTheGates.java b/Mage.Sets/src/mage/cards/o/OpenTheGates.java new file mode 100644 index 0000000000..673655a821 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OpenTheGates.java @@ -0,0 +1,49 @@ +package mage.cards.o; + +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.target.common.TargetCardInLibrary; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class OpenTheGates extends CardImpl { + + private static final FilterCard filter = new FilterCard("basic land card or a Gate card"); + + static { + filter.add(Predicates.or( + Predicates.and( + new SupertypePredicate(SuperType.BASIC), + new CardTypePredicate(CardType.LAND) + ), new SubtypePredicate(SubType.GATE) + )); + } + + public OpenTheGates(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); + + // Search your library for a basic land card or a Gate card, reveal it, put it into your hand, then shuffled your library. + this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true)); + } + + private OpenTheGates(final OpenTheGates card) { + super(card); + } + + @Override + public OpenTheGates copy() { + return new OpenTheGates(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OpenTheGraves.java b/Mage.Sets/src/mage/cards/o/OpenTheGraves.java index b76f2b1047..aeb45f4a0e 100644 --- a/Mage.Sets/src/mage/cards/o/OpenTheGraves.java +++ b/Mage.Sets/src/mage/cards/o/OpenTheGraves.java @@ -23,7 +23,7 @@ public final class OpenTheGraves extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public OpenTheGraves(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OpenTheVaults.java b/Mage.Sets/src/mage/cards/o/OpenTheVaults.java index b1dd78e5c4..be29721888 100644 --- a/Mage.Sets/src/mage/cards/o/OpenTheVaults.java +++ b/Mage.Sets/src/mage/cards/o/OpenTheVaults.java @@ -60,7 +60,8 @@ class OpenTheVaultsEffect extends OneShotEffect { if (controller != null) { LinkedHashSet cardsToReturn = new LinkedHashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Cards graveyard = game.getPlayer(playerId).getGraveyard(); + Player player = game.getPlayer(playerId); + Cards graveyard = player.getGraveyard(); for (UUID cardId : graveyard) { Card card = game.getCard(cardId); if (card != null diff --git a/Mage.Sets/src/mage/cards/o/Opposition.java b/Mage.Sets/src/mage/cards/o/Opposition.java index 9f140a7c0c..30112bc8ee 100644 --- a/Mage.Sets/src/mage/cards/o/Opposition.java +++ b/Mage.Sets/src/mage/cards/o/Opposition.java @@ -36,7 +36,7 @@ public final class Opposition extends CardImpl { private static final FilterControlledCreaturePermanent untappedcreatureyoucontrol = new FilterControlledCreaturePermanent("untapped creature you control"); static { - untappedcreatureyoucontrol.add(Predicates.not(new TappedPredicate())); + untappedcreatureyoucontrol.add(Predicates.not(TappedPredicate.instance)); } public Opposition(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OracleEnVec.java b/Mage.Sets/src/mage/cards/o/OracleEnVec.java index 118fd61524..4338c19a85 100644 --- a/Mage.Sets/src/mage/cards/o/OracleEnVec.java +++ b/Mage.Sets/src/mage/cards/o/OracleEnVec.java @@ -1,8 +1,5 @@ - package mage.cards.o; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -18,12 +15,7 @@ import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TurnPhase; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -35,8 +27,10 @@ import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.AttackedThisTurnWatcher; +import java.util.List; +import java.util.UUID; + /** - * * @author emerald000 */ public final class OracleEnVec extends CardImpl { @@ -122,7 +116,8 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return this.getTargetPointer().getFirst(game, source).equals(permanent.getId()); + return this.getTargetPointer().getFirst(game, source) != null + && this.getTargetPointer().getFirst(game, source).equals(permanent.getId()); } @Override @@ -137,7 +132,7 @@ class OracleEnVecMustAttackRequirementEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { - return startingTurn != game.getTurnNum() + return getStartingTurnNum() != game.getTurnNum() && (game.getPhase().getType() == TurnPhase.END && game.isActivePlayer(this.getTargetPointer().getFirst(game, source))); } @@ -165,17 +160,18 @@ class OracleEnVecCantAttackRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - return this.getTargetPointer().getFirst(game, source).equals(permanent.getId()); + return this.getTargetPointer().getFirst(game, source) != null + && this.getTargetPointer().getFirst(game, source).equals(permanent.getId()); } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean isInactive(Ability source, Game game) { - return startingTurn != game.getTurnNum() + return getStartingTurnNum() != game.getTurnNum() && (game.getPhase().getType() == TurnPhase.END && game.isActivePlayer(this.getTargetPointer().getFirst(game, source))); } @@ -243,7 +239,7 @@ class OracleEnVecDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null) { for (UUID targetId : chosenCreatures) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage.Sets/src/mage/cards/o/OracleOfNectars.java b/Mage.Sets/src/mage/cards/o/OracleOfNectars.java index 0c8bd66cd1..94f72f3ee7 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfNectars.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfNectars.java @@ -30,7 +30,7 @@ public final class OracleOfNectars extends CardImpl { this.toughness = new MageInt(2); // {X}, {tap}: You gain X life. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java b/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java index 2d698b0f09..ddddb16971 100644 --- a/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java +++ b/Mage.Sets/src/mage/cards/o/OratorOfOjutai.java @@ -95,7 +95,7 @@ class OratorOfOjutaiTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { //Intervening if must be checked Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(getSourceId()); - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); return event.getTargetId().equals(getSourceId()) && watcher != null && watcher.castWithConditionTrue(sourcePermanent.getSpellAbility().getId()); @@ -135,7 +135,7 @@ class OratorOfOjutaiEffect extends OneShotEffect { if (controller != null) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourcePermanent != null) { - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); if (watcher != null && watcher.castWithConditionTrue(sourcePermanent.getSpellAbility().getId())) { controller.drawCards(1, game); return true; diff --git a/Mage.Sets/src/mage/cards/o/OrazcaRelic.java b/Mage.Sets/src/mage/cards/o/OrazcaRelic.java index 51bc961bfc..0d80cf5df3 100644 --- a/Mage.Sets/src/mage/cards/o/OrazcaRelic.java +++ b/Mage.Sets/src/mage/cards/o/OrazcaRelic.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.costs.common.SacrificeSourceCost; @@ -9,6 +7,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.mana.ColorlessManaAbility; import mage.cards.CardImpl; @@ -16,8 +15,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class OrazcaRelic extends CardImpl { @@ -37,7 +37,8 @@ public final class OrazcaRelic extends CardImpl { new TapSourceCost(), CitysBlessingCondition.instance); ability.addCost(new SacrificeSourceCost()); - ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and draw a card")); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/o/OrcGeneral.java b/Mage.Sets/src/mage/cards/o/OrcGeneral.java index b2d290e3e5..792b222f8a 100644 --- a/Mage.Sets/src/mage/cards/o/OrcGeneral.java +++ b/Mage.Sets/src/mage/cards/o/OrcGeneral.java @@ -33,7 +33,7 @@ public final class OrcGeneral extends CardImpl { static { filterOrcOrGoblin.add(Predicates.or(new SubtypePredicate(SubType.ORC), new SubtypePredicate(SubType.GOBLIN))); - filterOrcOrGoblin.add(new AnotherPredicate()); + filterOrcOrGoblin.add(AnotherPredicate.instance); filterOrc.add(new SubtypePredicate(SubType.ORC)); } diff --git a/Mage.Sets/src/mage/cards/o/OrcSureshot.java b/Mage.Sets/src/mage/cards/o/OrcSureshot.java index 80c5d978b3..f499838e56 100644 --- a/Mage.Sets/src/mage/cards/o/OrcSureshot.java +++ b/Mage.Sets/src/mage/cards/o/OrcSureshot.java @@ -29,7 +29,7 @@ public final class OrcSureshot extends CardImpl { private static final FilterCreaturePermanent filterOpponentCreature = new FilterCreaturePermanent("creature an opponent controls"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filterOpponentCreature.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/o/OrchardSpirit.java b/Mage.Sets/src/mage/cards/o/OrchardSpirit.java index f6d5dec0ff..d022aacc94 100644 --- a/Mage.Sets/src/mage/cards/o/OrchardSpirit.java +++ b/Mage.Sets/src/mage/cards/o/OrchardSpirit.java @@ -22,7 +22,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class OrchardSpirit extends CardImpl { - private final static FilterCreaturePermanent notFlyingorReachCreatures = new FilterCreaturePermanent("except by creatures with flying or reach"); + private static final FilterCreaturePermanent notFlyingorReachCreatures = new FilterCreaturePermanent("except by creatures with flying or reach"); static { notFlyingorReachCreatures.add(Predicates.not( diff --git a/Mage.Sets/src/mage/cards/o/OrchardWarden.java b/Mage.Sets/src/mage/cards/o/OrchardWarden.java index da5336125e..cd77dd9b47 100644 --- a/Mage.Sets/src/mage/cards/o/OrchardWarden.java +++ b/Mage.Sets/src/mage/cards/o/OrchardWarden.java @@ -26,7 +26,7 @@ public final class OrchardWarden extends CardImpl { static { filter.add(new SubtypePredicate(SubType.TREEFOLK)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public OrchardWarden(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OrcishCaptain.java b/Mage.Sets/src/mage/cards/o/OrcishCaptain.java index 998fe8e7e8..adb3772355 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishCaptain.java +++ b/Mage.Sets/src/mage/cards/o/OrcishCaptain.java @@ -69,7 +69,7 @@ class OrcishCaptainEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.informPlayers("Orcish Captain: Won flip. Target Orc creature gets +2/+0 until end of turn."); game.addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn), source); return true; diff --git a/Mage.Sets/src/mage/cards/o/OrcishSquatters.java b/Mage.Sets/src/mage/cards/o/OrcishSquatters.java index 33489a79f7..fd20a8044b 100644 --- a/Mage.Sets/src/mage/cards/o/OrcishSquatters.java +++ b/Mage.Sets/src/mage/cards/o/OrcishSquatters.java @@ -27,7 +27,7 @@ public final class OrcishSquatters extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("land defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public OrcishSquatters(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java index eb366f17fe..9633f56bb8 100644 --- a/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java +++ b/Mage.Sets/src/mage/cards/o/OrderOfSuccession.java @@ -97,7 +97,7 @@ class OrderOfSuccessionEffect extends OneShotEffect { } // if player is in range he chooses a creature to control if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(new StringBuilder("creature controlled by ").append(nextPlayer.getLogName()).toString()); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by " + nextPlayer.getLogName()); filter.add(new ControllerIdPredicate(nextPlayer.getId())); Target target = new TargetCreaturePermanent(filter); target.setNotTarget(true); diff --git a/Mage.Sets/src/mage/cards/o/OreskosExplorer.java b/Mage.Sets/src/mage/cards/o/OreskosExplorer.java index ceda298514..8325374b9c 100644 --- a/Mage.Sets/src/mage/cards/o/OreskosExplorer.java +++ b/Mage.Sets/src/mage/cards/o/OreskosExplorer.java @@ -87,7 +87,7 @@ class OreskosExplorerEffect extends OneShotEffect { filterPlains.add(new ControllerPredicate(TargetController.YOU)); filterPlains.add(new SubtypePredicate(SubType.PLAINS)); TargetCardInLibrary target = new TargetCardInLibrary(0, landsToSearch, filterPlains); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Cards cards = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), cards, game); controller.moveCards(cards.getCards(game), Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/o/Orgg.java b/Mage.Sets/src/mage/cards/o/Orgg.java index 60d0bc29d0..2112818ed0 100644 --- a/Mage.Sets/src/mage/cards/o/Orgg.java +++ b/Mage.Sets/src/mage/cards/o/Orgg.java @@ -29,7 +29,7 @@ public final class Orgg extends CardImpl { static final private FilterCreaturePermanent filter2 = new FilterCreaturePermanent("creatures with power 3 or greater"); static { - filter.add(Predicates.and(new PowerPredicate(ComparisonType.MORE_THAN, 2), Predicates.not(new TappedPredicate()))); + filter.add(Predicates.and(new PowerPredicate(ComparisonType.MORE_THAN, 2), Predicates.not(TappedPredicate.instance))); filter2.add(new PowerPredicate(ComparisonType.MORE_THAN, 2)); } public Orgg(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OrimsCure.java b/Mage.Sets/src/mage/cards/o/OrimsCure.java index d80a0cbe50..d7b5614896 100644 --- a/Mage.Sets/src/mage/cards/o/OrimsCure.java +++ b/Mage.Sets/src/mage/cards/o/OrimsCure.java @@ -31,7 +31,7 @@ public final class OrimsCure extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PLAINS)); - filterCreature.add(Predicates.not(new TappedPredicate())); + filterCreature.add(Predicates.not(TappedPredicate.instance)); } public OrimsCure(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OrimsPrayer.java b/Mage.Sets/src/mage/cards/o/OrimsPrayer.java index 290da1d657..b171246ae4 100644 --- a/Mage.Sets/src/mage/cards/o/OrimsPrayer.java +++ b/Mage.Sets/src/mage/cards/o/OrimsPrayer.java @@ -1,4 +1,3 @@ - package mage.cards.o; import java.util.UUID; @@ -58,7 +57,8 @@ class OrimsPrayerTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return game.getCombat().getDefenders().contains(getControllerId()); + return game.getCombat().getDefenders().contains(getControllerId()) + && game.getCombat().getAttackers().size() > 0; } @Override diff --git a/Mage.Sets/src/mage/cards/o/OrimsThunder.java b/Mage.Sets/src/mage/cards/o/OrimsThunder.java index ca705f089d..b1f8a47c07 100644 --- a/Mage.Sets/src/mage/cards/o/OrimsThunder.java +++ b/Mage.Sets/src/mage/cards/o/OrimsThunder.java @@ -3,7 +3,6 @@ package mage.cards.o; import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; @@ -18,17 +17,17 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class OrimsThunder extends CardImpl { public OrimsThunder(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); // Kicker {R} this.addAbility(new KickerAbility("{R}")); @@ -39,16 +38,9 @@ public final class OrimsThunder extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new OrimsThunderEffect2(), KickedCondition.instance, - "If Orim's Thunder was kicked, it deals damage equal to that permanent's converted mana cost to target creature")); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetCreaturePermanent()); - } - } + "If Orim's Thunder was kicked, it deals damage equal to that permanent's converted mana cost to target creature") + ); + this.getSpellAbility().setTargetAdjuster(OrimsThunderAdjuster.instance); } public OrimsThunder(final OrimsThunder card) { @@ -61,6 +53,18 @@ public final class OrimsThunder extends CardImpl { } } +enum OrimsThunderAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetCreaturePermanent()); + } + } + +} + class OrimsThunderEffect2 extends OneShotEffect { OrimsThunderEffect2() { diff --git a/Mage.Sets/src/mage/cards/o/OrzhovCharm.java b/Mage.Sets/src/mage/cards/o/OrzhovCharm.java index bf6486b1cb..ef49630a60 100644 --- a/Mage.Sets/src/mage/cards/o/OrzhovCharm.java +++ b/Mage.Sets/src/mage/cards/o/OrzhovCharm.java @@ -45,14 +45,14 @@ public final class OrzhovCharm extends CardImpl { // or destroy target creature and you lose life equal to its toughness; Mode mode = new Mode(); - mode.getEffects().add(new OrzhovCharmDestroyAndLoseLifeEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new OrzhovCharmDestroyAndLoseLifeEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or return target creature card with converted mana cost 1 or less from your graveyard to the battlefield. Mode mode2 = new Mode(); - mode2.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); - mode2.getTargets().add(new TargetCardInYourGraveyard(filter)); + mode2.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + mode2.addTarget(new TargetCardInYourGraveyard(filter)); this.getSpellAbility().addMode(mode2); diff --git a/Mage.Sets/src/mage/cards/o/OrzhovEnforcer.java b/Mage.Sets/src/mage/cards/o/OrzhovEnforcer.java new file mode 100644 index 0000000000..e944b3e15f --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrzhovEnforcer.java @@ -0,0 +1,41 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +import mage.abilities.keyword.DeathtouchAbility; +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 OrzhovEnforcer extends CardImpl { + + public OrzhovEnforcer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + private OrzhovEnforcer(final OrzhovEnforcer card) { + super(card); + } + + @Override + public OrzhovEnforcer copy() { + return new OrzhovEnforcer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrzhovLocket.java b/Mage.Sets/src/mage/cards/o/OrzhovLocket.java new file mode 100644 index 0000000000..a660da2dd0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrzhovLocket.java @@ -0,0 +1,46 @@ +package mage.cards.o; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class OrzhovLocket extends CardImpl { + + public OrzhovLocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add {W} or {B}. + this.addAbility(new WhiteManaAbility()); + this.addAbility(new BlackManaAbility()); + + // {W/B}{W/B}{W/B}{W/B}, {T}, Sacrifice Orzhov Locket: Draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{W/B}{W/B}{W/B}{W/B}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public OrzhovLocket(final OrzhovLocket card) { + super(card); + } + + @Override + public OrzhovLocket copy() { + return new OrzhovLocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java b/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java index 02e084e063..34017c4171 100644 --- a/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java +++ b/Mage.Sets/src/mage/cards/o/OrzhovPontiff.java @@ -41,7 +41,7 @@ public final class OrzhovPontiff extends CardImpl { // When Orzhov Pontiff enters the battlefield or the creature it haunts dies, choose one - Creatures you control get +1/+1 until end of turn; or creatures you don't control get -1/-1 until end of turn. Ability ability = new HauntAbility(this, new BoostAllEffect(1,1, Duration.EndOfTurn, filterControlled, false)); Mode mode = new Mode(); - mode.getEffects().add(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filterNotControlled, false)); + mode.addEffect(new BoostAllEffect(-1,-1, Duration.EndOfTurn, filterNotControlled, false)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/o/OrzhovRacketeers.java b/Mage.Sets/src/mage/cards/o/OrzhovRacketeers.java new file mode 100644 index 0000000000..5c96b03a86 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/OrzhovRacketeers.java @@ -0,0 +1,45 @@ +package mage.cards.o; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.AfterlifeAbility; +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 OrzhovRacketeers extends CardImpl { + + public OrzhovRacketeers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever Orzhov Racketeers deals combat damage to a player, that player discards a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DiscardTargetEffect(1), false, true + )); + + // Afterlife 2 + this.addAbility(new AfterlifeAbility(2)); + + } + + private OrzhovRacketeers(final OrzhovRacketeers card) { + super(card); + } + + @Override + public OrzhovRacketeers copy() { + return new OrzhovRacketeers(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/OtherworldAtlas.java b/Mage.Sets/src/mage/cards/o/OtherworldAtlas.java index 3f49b89fe5..660200e588 100644 --- a/Mage.Sets/src/mage/cards/o/OtherworldAtlas.java +++ b/Mage.Sets/src/mage/cards/o/OtherworldAtlas.java @@ -62,7 +62,7 @@ class OtherworldAtlasDrawEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player sourcePlayer = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { + if (permanent != null && sourcePlayer != null) { int amount = permanent.getCounters(game).getCount(CounterType.CHARGE); if (amount > 0) { for (UUID playerId : game.getState().getPlayersInRange(sourcePlayer.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/o/OtherworldlyOutburst.java b/Mage.Sets/src/mage/cards/o/OtherworldlyOutburst.java index 846dac4694..526cd50866 100644 --- a/Mage.Sets/src/mage/cards/o/OtherworldlyOutburst.java +++ b/Mage.Sets/src/mage/cards/o/OtherworldlyOutburst.java @@ -91,7 +91,7 @@ class OtherworldlyOutburstDelayedTriggeredAbility extends DelayedTriggeredAbilit public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(target)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/o/OupheVandals.java b/Mage.Sets/src/mage/cards/o/OupheVandals.java index d484706759..2c89a1075f 100644 --- a/Mage.Sets/src/mage/cards/o/OupheVandals.java +++ b/Mage.Sets/src/mage/cards/o/OupheVandals.java @@ -32,7 +32,7 @@ import mage.target.common.TargetActivatedOrTriggeredAbility; */ public final class OupheVandals extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("ability from an artifact source"); + private static final FilterStackObject filter = new FilterStackObject("ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); diff --git a/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java b/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java index 98ea2f4b72..438ca1a729 100644 --- a/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java +++ b/Mage.Sets/src/mage/cards/o/OuterRimSlaver.java @@ -1,4 +1,3 @@ - package mage.cards.o; import java.util.UUID; @@ -30,12 +29,13 @@ public final class OuterRimSlaver extends CardImpl { this.toughness = new MageInt(3); // When Outer Rim Slaver enters the battlefield, you may put a bounty counter on target creature. If you do, another target creature fights that creature - Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()), true); - ability.addEffect(new FightTargetsEffect("another target creature fights that creature")); - TargetCreaturePermanent target = new TargetCreaturePermanent(); + Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.BOUNTY.createInstance()) + .setText("you may put a bounty counter on target creature"), true); + ability.addEffect(new FightTargetsEffect("If you do, another target creature fights that creature")); + TargetCreaturePermanent target = new TargetCreaturePermanent(new FilterCreaturePermanent("creature to put a bounty counter on it")); target.setTargetTag(1); ability.addTarget(target); - FilterCreaturePermanent filter = new FilterCreaturePermanent(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature to fight that creature that gets the bounty counter"); filter.add(new AnotherTargetPredicate(2)); TargetCreaturePermanent target2 = new TargetCreaturePermanent(filter); target2.setTargetTag(2); diff --git a/Mage.Sets/src/mage/cards/o/Outmaneuver.java b/Mage.Sets/src/mage/cards/o/Outmaneuver.java new file mode 100644 index 0000000000..7e005e5bb7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/o/Outmaneuver.java @@ -0,0 +1,96 @@ +package mage.cards.o; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AsThoughEffectType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class Outmaneuver extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(BlockedPredicate.instance); + } + + public Outmaneuver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); + + // X target blocked creatures assign their combat damage this turn as though they weren't blocked. + this.getSpellAbility().addEffect(new OutmaneuverEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + + } + + public Outmaneuver(final Outmaneuver card) { + super(card); + } + + @Override + public Outmaneuver copy() { + return new Outmaneuver(this); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability instanceof SpellAbility) { + ability.getTargets().clear(); + int numberOfTargets = ability.getManaCostsToPay().getX(); + numberOfTargets = Math.min(game.getBattlefield().getAllActivePermanents(filter, + ability.getControllerId(), game).size(), numberOfTargets); + ability.addTarget(new TargetCreaturePermanent(numberOfTargets, + numberOfTargets, filter, false)); + } + } +} + +class OutmaneuverEffect extends AsThoughEffectImpl { + + public OutmaneuverEffect() { + super(AsThoughEffectType.DAMAGE_NOT_BLOCKED, Duration.EndOfTurn, Outcome.Damage); + this.staticText = "X target blocked creatures assign their combat damage this turn as though they weren't blocked."; + } + + public OutmaneuverEffect(OutmaneuverEffect effect) { + super(effect); + } + + @Override + public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { + Permanent blockedCreature = game.getPermanent(sourceId); + if (blockedCreature != null) { + Player controller = game.getPlayer(blockedCreature.getControllerId()); + if (controller != null) { + return controller.chooseUse(Outcome.Damage, "Do you wish to assign combat damage for " + + blockedCreature.getLogName() + " as though it weren't blocked?", source, game); + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public OutmaneuverEffect copy() { + return new OutmaneuverEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/o/Outnumber.java b/Mage.Sets/src/mage/cards/o/Outnumber.java index 0fe1e20ed0..dd6d2d3d42 100644 --- a/Mage.Sets/src/mage/cards/o/Outnumber.java +++ b/Mage.Sets/src/mage/cards/o/Outnumber.java @@ -1,30 +1,31 @@ - package mage.cards.o; -import java.util.UUID; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Outnumber extends CardImpl { public Outnumber(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Outnumber deals damage to target creature equal to the number of creatures you control. Effect effect = new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("the number of creatures you control"))); effect.setText("{this} deals damage to target creature equal to the number of creatures you control"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(CreaturesYouControlHint.instance); } diff --git a/Mage.Sets/src/mage/cards/o/OutpostSiege.java b/Mage.Sets/src/mage/cards/o/OutpostSiege.java index 2fabfdbc09..4062fa1c78 100644 --- a/Mage.Sets/src/mage/cards/o/OutpostSiege.java +++ b/Mage.Sets/src/mage/cards/o/OutpostSiege.java @@ -35,8 +35,8 @@ import mage.target.targetpointer.FixedTarget; */ public final class OutpostSiege extends CardImpl { - private final static String ruleTrigger1 = "&bull Khans — At the beginning of your upkeep, exile the top card of your library. Until end of turn, you may play that card."; - private final static String ruleTrigger2 = "&bull Dragons — Whenever a creature you control leaves the battlefield, {this} deals 1 damage to any target."; + private static final String ruleTrigger1 = "&bull Khans — At the beginning of your upkeep, exile the top card of your library. Until end of turn, you may play that card."; + private static final String ruleTrigger2 = "&bull Dragons — Whenever a creature you control leaves the battlefield, {this} deals 1 damage to any target."; public OutpostSiege(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}"); diff --git a/Mage.Sets/src/mage/cards/o/Outwit.java b/Mage.Sets/src/mage/cards/o/Outwit.java index 8ab33f01c9..5eeafbf255 100644 --- a/Mage.Sets/src/mage/cards/o/Outwit.java +++ b/Mage.Sets/src/mage/cards/o/Outwit.java @@ -101,7 +101,7 @@ public final class Outwit extends CardImpl { public boolean canChoose(UUID sourceControllerId, Game game) { int count = 0; for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && filter.match((Spell) stackObject, game)) { + if (stackObject instanceof Spell && filter.match(stackObject, game)) { if (targetsPlayer(stackObject.getId(), game)) { count++; if (count >= this.minNumberOfTargets) { @@ -117,7 +117,7 @@ public final class Outwit extends CardImpl { public Set possibleTargets(UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); for (StackObject stackObject : game.getStack()) { - if (stackObject instanceof Spell && filter.match((Spell) stackObject, game)) { + if (stackObject instanceof Spell && filter.match(stackObject, game)) { if (targetsPlayer(stackObject.getId(), game)) { possibleTargets.add(stackObject.getId()); } diff --git a/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java b/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java index c2b78462c6..6484e92303 100644 --- a/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java +++ b/Mage.Sets/src/mage/cards/o/OverbeingOfMyth.java @@ -33,7 +33,7 @@ public final class OverbeingOfMyth extends CardImpl { this.toughness = new MageInt(0); // Overbeing of Myth's power and toughness are each equal to the number of cards in your hand. - DynamicValue number = new CardsInControllerHandCount(); + DynamicValue number = CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(number, Duration.EndOfGame))); // At the beginning of your draw step, draw an additional card. diff --git a/Mage.Sets/src/mage/cards/o/Overburden.java b/Mage.Sets/src/mage/cards/o/Overburden.java index c41fad613f..fb145c2331 100644 --- a/Mage.Sets/src/mage/cards/o/Overburden.java +++ b/Mage.Sets/src/mage/cards/o/Overburden.java @@ -25,7 +25,7 @@ public final class Overburden extends CardImpl { private static final FilterControlledLandPermanent RETURN_FILTER = new FilterControlledLandPermanent("a land"); static { - ENTERS_BATTLEFIELD_FILTER.add(Predicates.not(new TokenPredicate())); + ENTERS_BATTLEFIELD_FILTER.add(Predicates.not(TokenPredicate.instance)); } public Overburden(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/Overmaster.java b/Mage.Sets/src/mage/cards/o/Overmaster.java index b5c7fdb07b..1f91bc9841 100644 --- a/Mage.Sets/src/mage/cards/o/Overmaster.java +++ b/Mage.Sets/src/mage/cards/o/Overmaster.java @@ -67,7 +67,7 @@ class OvermasterEffect extends ContinuousRuleModifyingEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - OvermasterWatcher watcher = (OvermasterWatcher) game.getState().getWatchers().get(OvermasterWatcher.class.getSimpleName(), source.getControllerId()); + OvermasterWatcher watcher = game.getState().getWatcher(OvermasterWatcher.class, source.getControllerId()); if (watcher != null) { watcher.setReady(); } @@ -95,7 +95,7 @@ class OvermasterEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Spell spell = game.getStack().getSpell(event.getTargetId()); - OvermasterWatcher watcher = (OvermasterWatcher) game.getState().getWatchers().get(OvermasterWatcher.class.getSimpleName(), source.getControllerId()); + OvermasterWatcher watcher = game.getState().getWatcher(OvermasterWatcher.class, source.getControllerId()); return spell != null && watcher != null && watcher.isUncounterable(spell.getId()); } } @@ -106,7 +106,7 @@ class OvermasterWatcher extends Watcher { protected UUID uncounterableSpell; OvermasterWatcher() { - super(OvermasterWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } OvermasterWatcher(final OvermasterWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/o/Overrule.java b/Mage.Sets/src/mage/cards/o/Overrule.java index 19b922b846..5f92d8fd35 100644 --- a/Mage.Sets/src/mage/cards/o/Overrule.java +++ b/Mage.Sets/src/mage/cards/o/Overrule.java @@ -20,11 +20,11 @@ public final class Overrule extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}{U}"); // Counter target spell unless its controller pays {X}. - this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetSpell()); // You gain X life. - this.getSpellAbility().addEffect(new GainLifeEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance)); } public Overrule(final Overrule card) { diff --git a/Mage.Sets/src/mage/cards/o/OverseerOfTheDamned.java b/Mage.Sets/src/mage/cards/o/OverseerOfTheDamned.java index 9877dac2df..a828ea6ca8 100644 --- a/Mage.Sets/src/mage/cards/o/OverseerOfTheDamned.java +++ b/Mage.Sets/src/mage/cards/o/OverseerOfTheDamned.java @@ -33,7 +33,7 @@ public final class OverseerOfTheDamned extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public OverseerOfTheDamned(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/o/OverwhelmingInstinct.java b/Mage.Sets/src/mage/cards/o/OverwhelmingInstinct.java index cf96fd4301..183e2b38fd 100644 --- a/Mage.Sets/src/mage/cards/o/OverwhelmingInstinct.java +++ b/Mage.Sets/src/mage/cards/o/OverwhelmingInstinct.java @@ -63,6 +63,6 @@ class OverwhelmingInstinctTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever you attack with three or more creatures, ").append(super.getRule()).toString(); + return "Whenever you attack with three or more creatures, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/o/OviyaPashiriSageLifecrafter.java b/Mage.Sets/src/mage/cards/o/OviyaPashiriSageLifecrafter.java index 323c43f20a..a0714ac140 100644 --- a/Mage.Sets/src/mage/cards/o/OviyaPashiriSageLifecrafter.java +++ b/Mage.Sets/src/mage/cards/o/OviyaPashiriSageLifecrafter.java @@ -1,7 +1,5 @@ - package mage.cards.o; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -9,21 +7,19 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; 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.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.token.OviyaPashiriSageLifecrafterToken; import mage.game.permanent.token.ServoToken; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class OviyaPashiriSageLifecrafter extends CardImpl { @@ -43,6 +39,7 @@ public final class OviyaPashiriSageLifecrafter extends CardImpl { // {4}{G}, {T}: Create an X/X colorless Construct artifact creature token, where X is the number of creatures you control. ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new OviyaPashiriSageLifecrafterEffect(), new ManaCostsImpl("{4}{G}")); ability.addCost(new TapSourceCost()); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PainKami.java b/Mage.Sets/src/mage/cards/p/PainKami.java index f682910a9b..68c11d1153 100644 --- a/Mage.Sets/src/mage/cards/p/PainKami.java +++ b/Mage.Sets/src/mage/cards/p/PainKami.java @@ -28,7 +28,7 @@ public final class PainKami extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}{R}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}{R}")); ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PainSeer.java b/Mage.Sets/src/mage/cards/p/PainSeer.java index a8871cb6a1..f14b4a5bc8 100644 --- a/Mage.Sets/src/mage/cards/p/PainSeer.java +++ b/Mage.Sets/src/mage/cards/p/PainSeer.java @@ -1,31 +1,27 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.InspiredAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; -import mage.constants.SubType; 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 LevelX2 */ public final class PainSeer extends CardImpl { public PainSeer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -71,14 +67,14 @@ class PainSeerEffect extends OneShotEffect { if (player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Pain Seer", cards, game); - if (card != null && - card.moveToZone(Zone.HAND, source.getSourceId(), game, false)) { - player.loseLife(card.getConvertedManaCost(), game, false); - return true; + if (card != null) { + Cards cards = new CardsImpl(card); + player.revealCards("Pain Seer", cards, game); + if(player.moveCards(card, Zone.HAND, source, game)) { + player.loseLife(card.getConvertedManaCost(), game, false); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/p/Painbringer.java b/Mage.Sets/src/mage/cards/p/Painbringer.java index 02af94d9bc..bc415a2ba1 100644 --- a/Mage.Sets/src/mage/cards/p/Painbringer.java +++ b/Mage.Sets/src/mage/cards/p/Painbringer.java @@ -35,7 +35,7 @@ public final class Painbringer extends CardImpl { this.toughness = new MageInt(1); // {tap}, Exile any number of cards from your graveyard: Target creature gets -X/-X until end of turn, where X is the number of cards exiled this way. - DynamicValue X = new SignInversionDynamicValue(new GetXValue()); + DynamicValue X = new SignInversionDynamicValue(GetXValue.instance); Effect effect = new BoostTargetEffect(X, X, Duration.EndOfTurn); effect.setText("Target creature gets -X/-X until end of turn, where X is the number of cards exiled this way"); Ability ability = new SimpleActivatedAbility(effect, new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/p/PalaceJailer.java b/Mage.Sets/src/mage/cards/p/PalaceJailer.java index d2d832438a..4ecbe07413 100644 --- a/Mage.Sets/src/mage/cards/p/PalaceJailer.java +++ b/Mage.Sets/src/mage/cards/p/PalaceJailer.java @@ -35,7 +35,7 @@ import mage.util.CardUtil; */ public final class PalaceJailer extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/p/PalaceSiege.java b/Mage.Sets/src/mage/cards/p/PalaceSiege.java index 97624a9c48..e73cefcb5e 100644 --- a/Mage.Sets/src/mage/cards/p/PalaceSiege.java +++ b/Mage.Sets/src/mage/cards/p/PalaceSiege.java @@ -26,8 +26,8 @@ import java.util.UUID; */ public final class PalaceSiege extends CardImpl { - private final static String ruleTrigger1 = "&bull Khans — At the beginning of your upkeep, return target creature card from your graveyard to your hand."; - private final static String ruleTrigger2 = "&bull Dragons — At the beginning of your upkeep, each opponent loses 2 life and you gain 2 life."; + private static final String ruleTrigger1 = "&bull Khans — At the beginning of your upkeep, return target creature card from your graveyard to your hand."; + private static final String ruleTrigger2 = "&bull Dragons — At the beginning of your upkeep, each opponent loses 2 life and you gain 2 life."; public PalaceSiege(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}{B}"); diff --git a/Mage.Sets/src/mage/cards/p/Paleoloth.java b/Mage.Sets/src/mage/cards/p/Paleoloth.java index 2a702d824e..a7650a5bbe 100644 --- a/Mage.Sets/src/mage/cards/p/Paleoloth.java +++ b/Mage.Sets/src/mage/cards/p/Paleoloth.java @@ -28,7 +28,7 @@ public final class Paleoloth extends CardImpl { static { filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 4)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Whenever another creature with power 5 or greater enters the battlefield under your control, you may return target creature card from your graveyard to your hand."; diff --git a/Mage.Sets/src/mage/cards/p/PalisadeGiant.java b/Mage.Sets/src/mage/cards/p/PalisadeGiant.java index 10a8ffde34..0ceed13bfb 100644 --- a/Mage.Sets/src/mage/cards/p/PalisadeGiant.java +++ b/Mage.Sets/src/mage/cards/p/PalisadeGiant.java @@ -1,23 +1,20 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** * @author LevelX2 @@ -43,7 +40,7 @@ import mage.players.Player; public final class PalisadeGiant extends CardImpl { public PalisadeGiant(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{W}{W}"); this.subtype.add(SubType.GIANT); this.subtype.add(SubType.SOLDIER); @@ -51,7 +48,7 @@ public final class PalisadeGiant extends CardImpl { this.toughness = new MageInt(7); // All damage that would be dealt to you or another permanent you control is dealt to Palisade Giant instead. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PalisadeGiantReplacementEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PalisadeGiantReplacementEffect())); } public PalisadeGiant(final PalisadeGiant card) { @@ -77,7 +74,7 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch(event.getType()) { + switch (event.getType()) { case DAMAGE_CREATURE: case DAMAGE_PLAYER: case DAMAGE_PLANESWALKER: @@ -89,17 +86,15 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER && event.getPlayerId().equals(source.getControllerId())) - { - return true; + if (event.getType() == GameEvent.EventType.DAMAGE_PLAYER && event.getPlayerId().equals(source.getControllerId())) { + return true; } - if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE || event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER) - { + if (event.getType() == GameEvent.EventType.DAMAGE_CREATURE || event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER) { Permanent targetPermanent = game.getPermanent(event.getTargetId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (targetPermanent != null && + if (targetPermanent != null && targetPermanent.isControlledBy(source.getControllerId()) && - !targetPermanent.getName().equals(sourcePermanent.getName())) { // no redirection from or to other Palisade Giants + !CardUtil.haveSameNames(targetPermanent, sourcePermanent)) { // no redirection from or to other Palisade Giants return true; } } @@ -108,7 +103,7 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - DamageEvent damageEvent = (DamageEvent)event; + DamageEvent damageEvent = (DamageEvent) event; Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (sourcePermanent != null) { // get name of old target @@ -118,13 +113,11 @@ class PalisadeGiantReplacementEffect extends ReplacementEffectImpl { message.append(damageEvent.getAmount()).append(" damage redirected from "); if (targetPermanent != null) { message.append(targetPermanent.getName()); - } - else { + } else { Player targetPlayer = game.getPlayer(event.getTargetId()); if (targetPlayer != null) { message.append(targetPlayer.getLogName()); - } - else { + } else { message.append("unknown"); } diff --git a/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java b/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java index 0ce811c3ee..f65845133d 100644 --- a/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java +++ b/Mage.Sets/src/mage/cards/p/PalladiaMorsTheRuiner.java @@ -78,7 +78,7 @@ enum PalladiaMorsTheRuinerCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - PalladiaMorsTheRuinerWatcher watcher = (PalladiaMorsTheRuinerWatcher) game.getState().getWatchers().get(PalladiaMorsTheRuinerWatcher.class.getSimpleName()); + PalladiaMorsTheRuinerWatcher watcher = game.getState().getWatcher(PalladiaMorsTheRuinerWatcher.class); return permanent != null && !watcher.getDamagers().contains(new MageObjectReference(permanent, game)); } @@ -91,10 +91,10 @@ enum PalladiaMorsTheRuinerCondition implements Condition { class PalladiaMorsTheRuinerWatcher extends Watcher { - private final Set damagers = new HashSet(); + private final Set damagers = new HashSet<>(); public PalladiaMorsTheRuinerWatcher() { - super(PalladiaMorsTheRuinerWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PalladiaMorsTheRuinerWatcher(final PalladiaMorsTheRuinerWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/p/Pallimud.java b/Mage.Sets/src/mage/cards/p/Pallimud.java index 780b62129b..92603a715f 100644 --- a/Mage.Sets/src/mage/cards/p/Pallimud.java +++ b/Mage.Sets/src/mage/cards/p/Pallimud.java @@ -61,7 +61,7 @@ class AnathemancerCount implements DynamicValue { Player chosenPlayer = game.getPlayer(playerId); if (chosenPlayer != null) { FilterLandPermanent filter = new FilterLandPermanent("tapped lands the chosen player controls"); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerIdPredicate(playerId)); return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); } diff --git a/Mage.Sets/src/mage/cards/p/Panacea.java b/Mage.Sets/src/mage/cards/p/Panacea.java index 70de0178e6..099c2d61c0 100644 --- a/Mage.Sets/src/mage/cards/p/Panacea.java +++ b/Mage.Sets/src/mage/cards/p/Panacea.java @@ -25,7 +25,7 @@ public final class Panacea extends CardImpl { // {X}{X}, {tap}: Prevent the next X damage that would be dealt to any target this turn. Ability ability = new SimpleActivatedAbility( - new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, new ManacostVariableValue()), + new PreventDamageToTargetEffect(Duration.EndOfTurn, false, true, ManacostVariableValue.instance), new ManaCostsImpl("{X}{X}") ); ability.addCost(new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/p/Pandemonium.java b/Mage.Sets/src/mage/cards/p/Pandemonium.java index 82d3bfefe3..581cb03e13 100644 --- a/Mage.Sets/src/mage/cards/p/Pandemonium.java +++ b/Mage.Sets/src/mage/cards/p/Pandemonium.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -16,39 +15,31 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class Pandemonium extends CardImpl { - private final UUID originalId; - public Pandemonium(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); // Whenever a creature enters the battlefield, that creature's controller may have it deal damage equal to its power to any target of their choice. - Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new PandemoniumEffect(), StaticFilters.FILTER_PERMANENT_CREATURE, false, SetTargetPointer.PERMANENT, ""); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, new PandemoniumEffect(), + StaticFilters.FILTER_PERMANENT_CREATURE, + false, SetTargetPointer.PERMANENT, "" + ); ability.addTarget(new TargetAnyTarget()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(PandemoniumAdjuster.instance); this.addAbility(ability); } public Pandemonium(final Pandemonium card) { super(card); - this.originalId = card.originalId; - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - UUID creatureId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); - Permanent creature = game.getPermanent(creatureId); - if (creature != null) { - ability.getTargets().get(0).setTargetController(creature.getControllerId()); - } - } } @Override @@ -57,6 +48,19 @@ public final class Pandemonium extends CardImpl { } } +enum PandemoniumAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + UUID creatureId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + Permanent creature = game.getPermanent(creatureId); + if (creature != null) { + ability.getTargets().get(0).setTargetController(creature.getControllerId()); + } + } +} + class PandemoniumEffect extends OneShotEffect { public PandemoniumEffect() { diff --git a/Mage.Sets/src/mage/cards/p/PanicSpellbomb.java b/Mage.Sets/src/mage/cards/p/PanicSpellbomb.java index 1b44b323f9..f6fbf675d4 100644 --- a/Mage.Sets/src/mage/cards/p/PanicSpellbomb.java +++ b/Mage.Sets/src/mage/cards/p/PanicSpellbomb.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -18,14 +16,15 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author North */ public final class PanicSpellbomb extends CardImpl { public PanicSpellbomb(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // Tap, Sacrifice Panic Spellbomb: Target creature can't block this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CantBlockTargetEffect(Duration.EndOfTurn), new TapSourceCost()); @@ -34,7 +33,7 @@ public final class PanicSpellbomb extends CardImpl { this.addAbility(ability); // When Panic Spellbomb is put into a graveyard from the battlefield, you may pay Red. If you do, draw a card. - this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{R}")), false)); + this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{R}")), false, false)); } public PanicSpellbomb(final PanicSpellbomb card) { diff --git a/Mage.Sets/src/mage/cards/p/ParadigmShift.java b/Mage.Sets/src/mage/cards/p/ParadigmShift.java index 7b60dfaa49..5ae7c00fb7 100644 --- a/Mage.Sets/src/mage/cards/p/ParadigmShift.java +++ b/Mage.Sets/src/mage/cards/p/ParadigmShift.java @@ -55,8 +55,7 @@ class ExileLibraryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { int count = controller.getLibrary().size(); - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, count)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, count)); controller.moveCards(cards, Zone.EXILED, source, game); for (Card card: controller.getGraveyard().getCards(game)) { diff --git a/Mage.Sets/src/mage/cards/p/ParadiseDruid.java b/Mage.Sets/src/mage/cards/p/ParadiseDruid.java new file mode 100644 index 0000000000..38b296e04d --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParadiseDruid.java @@ -0,0 +1,53 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.abilities.mana.AnyColorManaAbility; +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 ParadiseDruid extends CardImpl { + + public ParadiseDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Paradise Druid has hexproof as long as it's untapped. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + HexproofAbility.getInstance(), + Duration.WhileOnBattlefield + ), new InvertCondition(SourceTappedCondition.instance), + "{this} has hexproof as long as it's untapped" + ))); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private ParadiseDruid(final ParadiseDruid card) { + super(card); + } + + @Override + public ParadiseDruid copy() { + return new ParadiseDruid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ParadoxHaze.java b/Mage.Sets/src/mage/cards/p/ParadoxHaze.java index eb98a98e32..6262d3d258 100644 --- a/Mage.Sets/src/mage/cards/p/ParadoxHaze.java +++ b/Mage.Sets/src/mage/cards/p/ParadoxHaze.java @@ -80,7 +80,7 @@ class ParadoxHazeTriggeredAbility extends TriggeredAbilityImpl { if (permanent != null) { Player player = game.getPlayer(permanent.getAttachedTo()); if (player != null && game.isActivePlayer(player.getId())) { - FirstTimeStepWatcher watcher = (FirstTimeStepWatcher) game.getState().getWatchers().get(EventType.UPKEEP_STEP_POST.toString() + FirstTimeStepWatcher.class.getSimpleName()); + FirstTimeStepWatcher watcher = game.getState().getWatcher(FirstTimeStepWatcher.class, EventType.UPKEEP_STEP_POST.toString()); if (watcher != null && !watcher.conditionMet()) { this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId())); return true; diff --git a/Mage.Sets/src/mage/cards/p/ParadoxicalOutcome.java b/Mage.Sets/src/mage/cards/p/ParadoxicalOutcome.java index 189ad55868..5580ac75a1 100644 --- a/Mage.Sets/src/mage/cards/p/ParadoxicalOutcome.java +++ b/Mage.Sets/src/mage/cards/p/ParadoxicalOutcome.java @@ -30,11 +30,11 @@ import mage.util.CardUtil; */ public final class ParadoxicalOutcome extends CardImpl { - private static FilterControlledPermanent filter = new FilterControlledPermanent(new StringBuilder("any number of of target nonland, nontoken permanents you control").toString()); + private static FilterControlledPermanent filter = new FilterControlledPermanent("any number of target nonland, nontoken permanents you control"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public ParadoxicalOutcome(UUID ownerId, CardSetInfo setInfo) { @@ -107,7 +107,7 @@ class ParadoxicalOutcomeNumber implements DynamicValue { } } int number = 0; - Integer sweepNumber = (Integer) game.getState().getValue(new StringBuilder("ParadoxicalOutcomeEffect").append(source.getSourceId()).append(zoneChangeCounter).toString()); + Integer sweepNumber = (Integer) game.getState().getValue("ParadoxicalOutcomeEffect" + source.getSourceId() + zoneChangeCounter); if (sweepNumber != null) { number = sweepNumber; } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java b/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java index 572ffc20ec..c470aa6dae 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfEternalWilds.java @@ -39,7 +39,7 @@ public final class ParagonOfEternalWilds extends CardImpl { filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); filterGreen.add(new ControllerPredicate(TargetController.YOU)); filterGreen2.add(new ColorPredicate(ObjectColor.GREEN)); - filterGreen2.add(new AnotherPredicate()); + filterGreen2.add(AnotherPredicate.instance); } public ParagonOfEternalWilds(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java b/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java index c1fb7a9296..d88970bc0b 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfFierceDefiance.java @@ -35,7 +35,7 @@ public final class ParagonOfFierceDefiance extends CardImpl { static { filterCreatures.add(new ColorPredicate(ObjectColor.RED)); - filterCreature.add(new AnotherPredicate()); + filterCreature.add(AnotherPredicate.instance); filterCreature.add(new ColorPredicate(ObjectColor.RED)); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java b/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java index 17c8b02393..c25d4921de 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfGatheringMists.java @@ -39,7 +39,7 @@ public final class ParagonOfGatheringMists extends CardImpl { filterBlue.add(new ColorPredicate(ObjectColor.BLUE)); filterBlue.add(new ControllerPredicate(TargetController.YOU)); filterBlue2.add(new ColorPredicate(ObjectColor.BLUE)); - filterBlue2.add(new AnotherPredicate()); + filterBlue2.add(AnotherPredicate.instance); } public ParagonOfGatheringMists(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java b/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java index 7ae03275b0..a186d548cb 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfNewDawns.java @@ -37,7 +37,7 @@ public final class ParagonOfNewDawns extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.WHITE)); filter.add(new ControllerPredicate(TargetController.YOU)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); filter2.add(new ColorPredicate(ObjectColor.WHITE)); filter2.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java b/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java index d8a8909993..a23b31ee28 100644 --- a/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java +++ b/Mage.Sets/src/mage/cards/p/ParagonOfOpenGraves.java @@ -35,7 +35,7 @@ public final class ParagonOfOpenGraves extends CardImpl { static { filterCreatures.add(new ColorPredicate(ObjectColor.BLACK)); - filterCreature.add(new AnotherPredicate()); + filterCreature.add(AnotherPredicate.instance); filterCreature.add(new ColorPredicate(ObjectColor.BLACK)); } diff --git a/Mage.Sets/src/mage/cards/p/ParallelEvolution.java b/Mage.Sets/src/mage/cards/p/ParallelEvolution.java index 9fbccfd975..84af3037c4 100644 --- a/Mage.Sets/src/mage/cards/p/ParallelEvolution.java +++ b/Mage.Sets/src/mage/cards/p/ParallelEvolution.java @@ -51,7 +51,7 @@ class ParallelEvolutionEffect extends OneShotEffect { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public ParallelEvolutionEffect() { diff --git a/Mage.Sets/src/mage/cards/p/ParallelThoughts.java b/Mage.Sets/src/mage/cards/p/ParallelThoughts.java index 16858edec0..16306d9f34 100644 --- a/Mage.Sets/src/mage/cards/p/ParallelThoughts.java +++ b/Mage.Sets/src/mage/cards/p/ParallelThoughts.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.Arrays; @@ -78,7 +77,7 @@ class ParallelThoughtsSearchEffect extends OneShotEffect { if (controller != null && permanent != null) { TargetCardInLibrary target = new TargetCardInLibrary(7, new FilterCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { for (UUID targetId : target.getTargets()) { Card card = controller.getLibrary().getCard(targetId, game); if (card != null) { @@ -86,7 +85,7 @@ class ParallelThoughtsSearchEffect extends OneShotEffect { } } // shuffle that exiled pile - + UUID[] shuffled = cardsInExilePile.toArray(new UUID[0]); for (int n = shuffled.length - 1; n > 0; n--) { int r = RandomUtil.nextInt(n + 1); @@ -96,16 +95,15 @@ class ParallelThoughtsSearchEffect extends OneShotEffect { } cardsInExilePile.clear(); cardsInExilePile.addAll(Arrays.asList(shuffled)); - + // move to exile zone and turn face down - + String exileName = permanent.getIdName() + " (" + game.getState().getZoneChangeCounter(source.getSourceId()) + ")"; for (Card card : cardsInExilePile.getCards(game)) { - controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), permanent.getLogName()); + controller.moveCardsToExile(card, source, game, false, CardUtil.getCardExileZoneId(game, source), exileName); card.setFaceDown(true, game); } - + // shuffle controller library - controller.shuffleLibrary(source, game); } return true; @@ -118,7 +116,7 @@ class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl { ParallelThoughtsReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.DrawCard); - staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with Parallel Thoughts into your hand"; + staticText = "If you would draw a card, you may instead put the top card of the pile you exiled with {this} into your hand"; } ParallelThoughtsReplacementEffect(final ParallelThoughtsReplacementEffect effect) { @@ -135,12 +133,15 @@ class ParallelThoughtsReplacementEffect extends ReplacementEffectImpl { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && !game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).isEmpty()) { - Card card = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).iterator().next(); - if (card != null) { - controller.moveCards(card, Zone.HAND, source, game); + if (controller.chooseUse(outcome, "Draw a card from the pile you exiled instead drawing from your library?", source, game)) { + Card card = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)).getCards(game).iterator().next(); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + return true; } } - return true; + return false; } @Override diff --git a/Mage.Sets/src/mage/cards/p/ParanoidParishBlade.java b/Mage.Sets/src/mage/cards/p/ParanoidParishBlade.java index 6b549cd5c3..642055e2e5 100644 --- a/Mage.Sets/src/mage/cards/p/ParanoidParishBlade.java +++ b/Mage.Sets/src/mage/cards/p/ParanoidParishBlade.java @@ -1,7 +1,7 @@ - package mage.cards.p; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,26 +19,26 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class ParanoidParishBlade extends CardImpl { public ParanoidParishBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(3); this.toughness = new MageInt(2); // Delirium — Paranoid Parish-Blade gets +1/+0 and has first strike as long as there are four or more card types among cards in your graveyard. - ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), + ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new BoostSourceEffect(1, 0, Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} gets +1/+0 "); effect.setText("Delirium — {this} gets +1/+0"); Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); - effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield), + effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(FirstStrikeAbility.getInstance(), Duration.WhileOnBattlefield), DeliriumCondition.instance, "and has first strike as long as there are four or more card types among cards in your graveyard."); ability.addEffect(effect); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Parch.java b/Mage.Sets/src/mage/cards/p/Parch.java index 7019802d23..bed5546837 100644 --- a/Mage.Sets/src/mage/cards/p/Parch.java +++ b/Mage.Sets/src/mage/cards/p/Parch.java @@ -33,8 +33,8 @@ public final class Parch extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(2)); this.getSpellAbility().addTarget(new TargetAnyTarget()); Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(4)); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DamageTargetEffect(4)); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PardicDragon.java b/Mage.Sets/src/mage/cards/p/PardicDragon.java index 992255a6fa..ee175f1e66 100644 --- a/Mage.Sets/src/mage/cards/p/PardicDragon.java +++ b/Mage.Sets/src/mage/cards/p/PardicDragon.java @@ -82,7 +82,7 @@ class PardicDragonEffect extends OneShotEffect { Player opponent = game.getPlayer(getTargetPointer().getFirst(game, source)); Card sourceCard = game.getCard(source.getSourceId()); if (opponent != null && sourceCard != null) { - if (opponent.chooseUse(outcome, new StringBuilder("Put a time counter on ").append(sourceCard.getName()).append('?').toString(), source, game)) { + if (opponent.chooseUse(outcome, "Put a time counter on " + sourceCard.getName() + '?', source, game)) { sourceCard.addCounters(CounterType.TIME.createInstance(), source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/p/ParhelionII.java b/Mage.Sets/src/mage/cards/p/ParhelionII.java new file mode 100644 index 0000000000..4ccd337e3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ParhelionII.java @@ -0,0 +1,60 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.AngelVigilanceToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ParhelionII extends CardImpl { + + public ParhelionII(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever Parhelion II attacks, create two 4/4 white Angel creature tokens with flying and vigilance that are attacking. + this.addAbility(new AttacksTriggeredAbility(new CreateTokenEffect( + new AngelVigilanceToken(), 2, + false, true + ), false)); + + // Crew 4 + this.addAbility(new CrewAbility(4)); + + } + + private ParhelionII(final ParhelionII card) { + super(card); + } + + @Override + public ParhelionII copy() { + return new ParhelionII(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/Paroxysm.java b/Mage.Sets/src/mage/cards/p/Paroxysm.java new file mode 100644 index 0000000000..cd9a98a532 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Paroxysm.java @@ -0,0 +1,110 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class Paroxysm extends CardImpl { + + public Paroxysm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of the upkeep of enchanted creature's controller, that player reveals the top card of their library. + // If that card is a land card, destroy that creature. Otherwise, it gets +3/+3 until end of turn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, + new ParoxysmEffect(), + TargetController.CONTROLLER_ATTACHED_TO, + false, false, "At the beginning of the upkeep of enchanted creature's controller, ")); + } + + public Paroxysm(final Paroxysm card) { + super(card); + } + + @Override + public Paroxysm copy() { + return new Paroxysm(this); + } +} + +class ParoxysmEffect extends OneShotEffect { + + ParoxysmEffect() { + super(Outcome.BoostCreature); + this.staticText = "that player reveals the top card of their library. \n" + + "If that card is a land card, destroy that creature. \n" + + "Otherwise, it gets +3/+3 until end of turn."; + } + + ParoxysmEffect(final ParoxysmEffect effect) { + super(effect); + } + + @Override + public ParoxysmEffect copy() { + return new ParoxysmEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent aura = game.getPermanent(source.getSourceId()); + if (aura != null) { + Permanent creatureAttachedTo = game.getPermanent(aura.getAttachedTo()); + if (creatureAttachedTo != null) { + Player controllerOfCreature = game.getPlayer(creatureAttachedTo.getControllerId()); + if (controllerOfCreature != null) { + Card revealCardFromTop = controllerOfCreature.getLibrary().getFromTop(game); + if (revealCardFromTop != null) { + Cards cards = new CardsImpl(revealCardFromTop); + controllerOfCreature.revealCards(source, cards, game); + if (revealCardFromTop.isLand()) { + creatureAttachedTo.destroy(source.getSourceId(), game, false); + } else { + ContinuousEffect effect = new BoostTargetEffect(3, 3, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creatureAttachedTo.getId())); + game.addEffect(effect, source); + } + return true; + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PartWater.java b/Mage.Sets/src/mage/cards/p/PartWater.java index 0e7c6c11b1..47afdfb31e 100644 --- a/Mage.Sets/src/mage/cards/p/PartWater.java +++ b/Mage.Sets/src/mage/cards/p/PartWater.java @@ -1,9 +1,7 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.IslandwalkAbility; @@ -11,34 +9,26 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class PartWater extends CardImpl { public PartWater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{X}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{U}"); // X target creatures gain islandwalk until end of turn. Effect effect = new GainAbilityTargetEffect(new IslandwalkAbility(false), Duration.EndOfTurn); effect.setText("X target creatures gain islandwalk until end of turn"); this.getSpellAbility().getEffects().add(effect); - this.getSpellAbility().getTargets().add(new TargetCreaturePermanent(1,1)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures gain islandwalk until end of turn"); - ability.getTargets().add(new TargetCreaturePermanent(0, xValue, filter, false)); - } + this.getSpellAbility().getTargets().add(new TargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(PartWaterAdjuster.instance); } public PartWater(final PartWater card) { @@ -50,3 +40,13 @@ public final class PartWater extends CardImpl { return new PartWater(this); } } + +enum PartWaterAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.getTargets().add(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PastInFlames.java b/Mage.Sets/src/mage/cards/p/PastInFlames.java index 77ac3bb1d2..627aa8791b 100644 --- a/Mage.Sets/src/mage/cards/p/PastInFlames.java +++ b/Mage.Sets/src/mage/cards/p/PastInFlames.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; @@ -10,23 +8,19 @@ import mage.abilities.keyword.FlashbackAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.TimingRule; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class PastInFlames extends CardImpl { public PastInFlames(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); // Each instant and sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. @@ -72,7 +66,7 @@ class PastInFlamesEffect extends ContinuousEffectImpl { player.getGraveyard().stream().map((cardId) -> game.getCard(cardId)).filter((card) -> (card.isInstant() || card.isSorcery())).forEachOrdered((card) -> { affectedObjectList.add(new MageObjectReference(card, game)); }); - } + } } } @@ -82,17 +76,18 @@ class PastInFlamesEffect extends ContinuousEffectImpl { if (player != null) { player.getGraveyard().stream().filter((cardId) -> (affectedObjectList.contains(new MageObjectReference(cardId, game)))).forEachOrdered((cardId) -> { Card card = game.getCard(cardId); - FlashbackAbility ability = null; - if (card.isInstant()) { - ability = new FlashbackAbility(card.getManaCost(), TimingRule.INSTANT); - } - else if (card.isSorcery()) { - ability = new FlashbackAbility(card.getManaCost(), TimingRule.SORCERY); - } - if (ability != null) { - ability.setSourceId(cardId); - ability.setControllerId(card.getOwnerId()); - game.getState().addOtherAbility(card, ability); + if (card != null) { + FlashbackAbility ability = null; + if (card.isInstant()) { + ability = new FlashbackAbility(card.getManaCost(), TimingRule.INSTANT); + } else if (card.isSorcery()) { + ability = new FlashbackAbility(card.getManaCost(), TimingRule.SORCERY); + } + if (ability != null) { + ability.setSourceId(cardId); + ability.setControllerId(card.getOwnerId()); + game.getState().addOtherAbility(card, ability); + } } }); return true; diff --git a/Mage.Sets/src/mage/cards/p/PathOfMettle.java b/Mage.Sets/src/mage/cards/p/PathOfMettle.java index e2a2759b77..1e016aed39 100644 --- a/Mage.Sets/src/mage/cards/p/PathOfMettle.java +++ b/Mage.Sets/src/mage/cards/p/PathOfMettle.java @@ -28,7 +28,7 @@ import mage.game.events.GameEvent; */ public final class PathOfMettle extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that doesn't have first strike, double strike, vigilance, or haste"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that doesn't have first strike, double strike, vigilance, or haste"); static { filter.add(Predicates.not(Predicates.or( @@ -67,7 +67,7 @@ public final class PathOfMettle extends CardImpl { class PathOfMettleTriggeredAbility extends TriggeredAbilityImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that doesn't have first strike, double strike, vigilance, or haste"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that doesn't have first strike, double strike, vigilance, or haste"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/p/PathToExile.java b/Mage.Sets/src/mage/cards/p/PathToExile.java index 591ac25107..d4cb6a64ac 100644 --- a/Mage.Sets/src/mage/cards/p/PathToExile.java +++ b/Mage.Sets/src/mage/cards/p/PathToExile.java @@ -69,7 +69,7 @@ class PathToExileEffect extends OneShotEffect { controller.moveCardToExileWithInfo(permanent, null, "", source.getSourceId(), game, Zone.BATTLEFIELD, true); if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for a basic land card?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { player.moveCards(card, Zone.BATTLEFIELD, source, game, true, false, false, null); diff --git a/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java b/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java index 24eae2bf48..bf61c7675f 100644 --- a/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java +++ b/Mage.Sets/src/mage/cards/p/PatriarchsBidding.java @@ -62,7 +62,7 @@ class PatriarchsBiddingEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null) { + if (controller != null && sourceObject != null) { Set chosenTypes = new HashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); diff --git a/Mage.Sets/src/mage/cards/p/PatriciansScorn.java b/Mage.Sets/src/mage/cards/p/PatriciansScorn.java index 0aed2b41de..c9f0ed7d5f 100644 --- a/Mage.Sets/src/mage/cards/p/PatriciansScorn.java +++ b/Mage.Sets/src/mage/cards/p/PatriciansScorn.java @@ -52,7 +52,7 @@ class CastWhiteSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PatriciansScornWatcher watcher = (PatriciansScornWatcher) game.getState().getWatchers().get(PatriciansScornWatcher.class.getSimpleName(), source.getSourceId()); + PatriciansScornWatcher watcher = game.getState().getWatcher(PatriciansScornWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.conditionMet(); } @@ -73,7 +73,7 @@ class PatriciansScornWatcher extends Watcher { } public PatriciansScornWatcher() { - super(PatriciansScornWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } public PatriciansScornWatcher(final PatriciansScornWatcher watcher) { @@ -98,8 +98,4 @@ class PatriciansScornWatcher extends Watcher { } } - @Override - public void reset() { - super.reset(); - } } diff --git a/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java b/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java index 41a704dd0d..2e21f6d8c8 100644 --- a/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java +++ b/Mage.Sets/src/mage/cards/p/PatronOfTheVein.java @@ -144,6 +144,9 @@ class PatronOfTheVeinExileCreatureEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if(controller == null){ + return false; + } MageObject sourceObject = source.getSourceObject(game); Card card = game.getCard(this.getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/p/PatronWizard.java b/Mage.Sets/src/mage/cards/p/PatronWizard.java index 04b436b596..2e447eb094 100644 --- a/Mage.Sets/src/mage/cards/p/PatronWizard.java +++ b/Mage.Sets/src/mage/cards/p/PatronWizard.java @@ -30,7 +30,7 @@ public final class PatronWizard extends CardImpl { static { filter.add(new SubtypePredicate(SubType.WIZARD)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public PatronWizard(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java b/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java index a9cc52feb6..8184f1d060 100644 --- a/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java +++ b/Mage.Sets/src/mage/cards/p/PatternOfRebirth.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.DiesAttachedTriggeredAbility; import mage.abilities.effects.Effect; @@ -11,22 +9,23 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.SetTargetPointer; +import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PatternOfRebirth extends CardImpl { public PatternOfRebirth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -37,7 +36,7 @@ public final class PatternOfRebirth extends CardImpl { this.addAbility(ability); // When enchanted creature dies, that creature's controller may search their library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles their library. - Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, true, Outcome.PutCreatureInPlay); + Effect effect = new SearchLibraryPutInPlayTargetPlayerEffect(new TargetCardInLibrary(new FilterCreatureCard()), false, false, Outcome.PutCreatureInPlay); effect.setText("that creature's controller may search their library for a creature card and put that card onto the battlefield. If that player does, he or she shuffles their library"); this.addAbility(new DiesAttachedTriggeredAbility(effect, "enchanted creature", true, true, SetTargetPointer.ATTACHED_TO_CONTROLLER)); diff --git a/Mage.Sets/src/mage/cards/p/PaupersCage.java b/Mage.Sets/src/mage/cards/p/PaupersCage.java index 961a57eecb..fcfad9135d 100644 --- a/Mage.Sets/src/mage/cards/p/PaupersCage.java +++ b/Mage.Sets/src/mage/cards/p/PaupersCage.java @@ -26,8 +26,9 @@ public final class PaupersCage extends CardImpl { // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, Paupers' Cage deals 2 damage to him or her. TriggeredAbility ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(2), TargetController.OPPONENT, false, true); - CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 2 damage to him or her.")); + CardsInHandCondition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 3, null, TargetController.ACTIVE); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, + "At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, {this} deals 2 damage to him or her.")); } public PaupersCage(final PaupersCage card) { diff --git a/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java b/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java index 7c10dd1271..d9aa4601a3 100644 --- a/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java +++ b/Mage.Sets/src/mage/cards/p/PawnOfUlamog.java @@ -73,7 +73,7 @@ class PawnOfUlamogTriggeredAbility extends TriggeredAbilityImpl { if (card instanceof Permanent && !(card instanceof PermanentToken)) { Permanent permanent = (Permanent) card; ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD + if (zEvent.isDiesEvent() && permanent.isControlledBy(this.controllerId) && (targetId.equals(this.getSourceId()) || (permanent.isCreature() diff --git a/Mage.Sets/src/mage/cards/p/PeaceTalks.java b/Mage.Sets/src/mage/cards/p/PeaceTalks.java new file mode 100644 index 0000000000..4201fc1d83 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PeaceTalks.java @@ -0,0 +1,158 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +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.events.GameEvent; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author jeffwadsworth + */ +public final class PeaceTalks extends CardImpl { + + public PeaceTalks(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}"); + + // This turn and next turn, creatures can't attack, + // and players and permanents can't be the targets + // of spells or activated abilities. + this.getSpellAbility().addEffect(new PeaceTalksEffect()); + + } + + private PeaceTalks(final PeaceTalks card) { + super(card); + } + + @Override + public PeaceTalks copy() { + return new PeaceTalks(this); + } +} + +class PeaceTalksEffect extends OneShotEffect { + + public PeaceTalksEffect() { + super(Outcome.Neutral); + this.staticText = "This turn and next turn, creatures can't attack," + + "and players and permanents can't be the targets of spells " + + "or activated abilities"; + } + + public PeaceTalksEffect(final PeaceTalksEffect effect) { + super(effect); + } + + @Override + public PeaceTalksEffect copy() { + return new PeaceTalksEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + RestrictionEffect effect = new PeaceTalksCantAttackEffect(); + game.addEffect(effect, source); + ContinuousRuleModifyingEffect effect2 = new PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities(); + game.addEffect(effect2, source); + return true; + } +} + +class PeaceTalksCantAttackEffect extends RestrictionEffect { + + public PeaceTalksCantAttackEffect() { + super(Duration.Custom); + staticText = "Creatures can't attack this turn and next turn"; + } + + public PeaceTalksCantAttackEffect(final PeaceTalksCantAttackEffect effect) { + super(effect); + } + + @Override + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.isCreature(); + } + + @Override + public boolean canAttack(Game game, boolean canUseChooseDialogs) { + return false; + } + + @Override + public PeaceTalksCantAttackEffect copy() { + return new PeaceTalksCantAttackEffect(this); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (getStartingTurnNum() + 2 <= game.getTurnNum()) { + this.discard(); + return true; + } + return false; + } +} + +class PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities extends ContinuousRuleModifyingEffectImpl { + + public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities() { + super(Duration.Custom, Outcome.Neutral); + staticText = "players and permanents can't be the targets of spells or activated abilities"; + } + + public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities(final PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL + || event.getType() == GameEvent.EventType.ACTIVATE_ABILITY; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + for (UUID playerId : game.getPlayer(source.getControllerId()).getInRange()) { + if (event.getTargetId().equals(playerId)) { + return false; + } + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) { + if (event.getTargetId().equals(permanent.getId())) { + return false; + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities copy() { + return new PeaceTalksPlayersAndPermanentsCantBeTargetsOfSpellsOrActivatedAbilities(this); + } + + @Override + public boolean isInactive(Ability source, Game game) { + if (getStartingTurnNum() + 2 <= game.getTurnNum()) { + this.discard(); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/Peacekeeper.java b/Mage.Sets/src/mage/cards/p/Peacekeeper.java index 0ff2065d52..79d13a4b32 100644 --- a/Mage.Sets/src/mage/cards/p/Peacekeeper.java +++ b/Mage.Sets/src/mage/cards/p/Peacekeeper.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -11,22 +9,19 @@ import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Peacekeeper extends CardImpl { public Peacekeeper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.power = new MageInt(1); @@ -66,7 +61,7 @@ class PeacekeeperCantAttackEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java b/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java index 7ce316dfdd..6792fca6da 100644 --- a/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java +++ b/Mage.Sets/src/mage/cards/p/PeacewalkerColossus.java @@ -29,7 +29,7 @@ public final class PeacewalkerColossus extends CardImpl { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("another target vehicle"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.VEHICLE)); } diff --git a/Mage.Sets/src/mage/cards/p/PeemaAetherSeer.java b/Mage.Sets/src/mage/cards/p/PeemaAetherSeer.java index 4d87ffe984..84b1f2598e 100644 --- a/Mage.Sets/src/mage/cards/p/PeemaAetherSeer.java +++ b/Mage.Sets/src/mage/cards/p/PeemaAetherSeer.java @@ -34,7 +34,7 @@ public final class PeemaAetherSeer extends CardImpl { this.toughness = new MageInt(2); // When Peema Aether-Seer enters the battlefield, you get an amount of {E} equal to the greatest power among creatures you control. - Effect effect = new GetEnergyCountersControllerEffect(new GreatestPowerAmongControlledCreaturesValue()); + Effect effect = new GetEnergyCountersControllerEffect(GreatestPowerAmongControlledCreaturesValue.instance); effect.setText("you get an amount of {E} equal to the greatest power among creatures you control"); this.addAbility(new EntersBattlefieldTriggeredAbility(effect)); diff --git a/Mage.Sets/src/mage/cards/p/PegasusCourser.java b/Mage.Sets/src/mage/cards/p/PegasusCourser.java index 0388865a9c..6dbfdc659f 100644 --- a/Mage.Sets/src/mage/cards/p/PegasusCourser.java +++ b/Mage.Sets/src/mage/cards/p/PegasusCourser.java @@ -25,7 +25,7 @@ public final class PegasusCourser extends CardImpl { static final FilterAttackingCreature filter = new FilterAttackingCreature("another target attacking creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public PegasusCourser(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PemminsAura.java b/Mage.Sets/src/mage/cards/p/PemminsAura.java index 89139bc99d..4cd260a1ac 100644 --- a/Mage.Sets/src/mage/cards/p/PemminsAura.java +++ b/Mage.Sets/src/mage/cards/p/PemminsAura.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -17,20 +16,16 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.Choice; import mage.choices.ChoiceImpl; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class PemminsAura extends CardImpl { @@ -94,21 +89,28 @@ class PemminsAuraBoostEnchantedEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent enchantment = game.getPermanent(source.getSourceId()); - Permanent creature = game.getPermanent(enchantment.getAttachedTo()); - if (controller != null && creature != null) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Select how to boost"); - choice.getChoices().add(CHOICE_1); - choice.getChoices().add(CHOICE_2); - if (controller.choose(outcome, choice, game)) { - if (choice.getChoice().equals(CHOICE_1)) { - game.addEffect(new BoostEnchantedEffect(+1, -1, Duration.EndOfTurn), source); - } else { - game.addEffect(new BoostEnchantedEffect(-1, +1, Duration.EndOfTurn), source); - } - return true; - } + if (controller == null || enchantment == null) { + return false; } + + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature == null) { + return false; + } + + Choice choice = new ChoiceImpl(true); + choice.setMessage("Select how to boost"); + choice.getChoices().add(CHOICE_1); + choice.getChoices().add(CHOICE_2); + if (controller.choose(outcome, choice, game)) { + if (choice.getChoice().equals(CHOICE_1)) { + game.addEffect(new BoostEnchantedEffect(+1, -1, Duration.EndOfTurn), source); + } else { + game.addEffect(new BoostEnchantedEffect(-1, +1, Duration.EndOfTurn), source); + } + return true; + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/p/PennonBlade.java b/Mage.Sets/src/mage/cards/p/PennonBlade.java index d4ba43508b..7dc4018141 100644 --- a/Mage.Sets/src/mage/cards/p/PennonBlade.java +++ b/Mage.Sets/src/mage/cards/p/PennonBlade.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; @@ -10,23 +8,27 @@ import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author North */ public final class PennonBlade extends CardImpl { public PennonBlade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); this.subtype.add(SubType.EQUIPMENT); - PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()); + // Equipped creature gets +1/+1 for each creature you control. + PermanentsOnBattlefieldCount value = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(value, value))); + + // Equip {4} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(4))); } diff --git a/Mage.Sets/src/mage/cards/p/PeopleOfTheWoods.java b/Mage.Sets/src/mage/cards/p/PeopleOfTheWoods.java index 326d9fde0c..3987f7b24e 100644 --- a/Mage.Sets/src/mage/cards/p/PeopleOfTheWoods.java +++ b/Mage.Sets/src/mage/cards/p/PeopleOfTheWoods.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public final class PeopleOfTheWoods extends CardImpl { - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); diff --git a/Mage.Sets/src/mage/cards/p/Peregrination.java b/Mage.Sets/src/mage/cards/p/Peregrination.java index 5f4bce46bf..53d6f14045 100644 --- a/Mage.Sets/src/mage/cards/p/Peregrination.java +++ b/Mage.Sets/src/mage/cards/p/Peregrination.java @@ -71,7 +71,7 @@ class PeregrinationEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/p/PermafrostTrap.java b/Mage.Sets/src/mage/cards/p/PermafrostTrap.java index 0d6462c7fd..f336a14f5e 100644 --- a/Mage.Sets/src/mage/cards/p/PermafrostTrap.java +++ b/Mage.Sets/src/mage/cards/p/PermafrostTrap.java @@ -54,7 +54,7 @@ enum PermafrostTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List permanents = watcher.getThisTurnEnteringPermanents(opponentId); diff --git a/Mage.Sets/src/mage/cards/p/PermeatingMass.java b/Mage.Sets/src/mage/cards/p/PermeatingMass.java index 58a7466de3..286739e23c 100644 --- a/Mage.Sets/src/mage/cards/p/PermeatingMass.java +++ b/Mage.Sets/src/mage/cards/p/PermeatingMass.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -9,9 +8,9 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.functions.EmptyApplyToPermanent; @@ -23,7 +22,7 @@ import mage.util.functions.EmptyApplyToPermanent; public final class PermeatingMass extends CardImpl { public PermeatingMass(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(3); @@ -62,7 +61,7 @@ class PermeatingMassEffect extends OneShotEffect { public boolean apply(Game game, Ability ability) { Permanent copyTo = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, ability)); if (copyTo != null) { - Permanent copyFrom = (Permanent) ability.getSourceObject(game); + Permanent copyFrom = ability.getSourcePermanentOrLKI(game); if (copyFrom != null) { game.copyPermanent(Duration.Custom, copyFrom, copyTo.getId(), ability, new EmptyApplyToPermanent()); } diff --git a/Mage.Sets/src/mage/cards/p/PersistentPetitioners.java b/Mage.Sets/src/mage/cards/p/PersistentPetitioners.java new file mode 100644 index 0000000000..d3548d6bee --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PersistentPetitioners.java @@ -0,0 +1,75 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.TargetPlayer; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PersistentPetitioners extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("untapped Advisors you control"); + + static { + filter.add(Predicates.not(TappedPredicate.instance)); + filter.add(new SubtypePredicate(SubType.ADVISOR)); + } + + public PersistentPetitioners(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // {1}, {T}: Target player puts the top card of their library into their graveyard. + Ability ability = new SimpleActivatedAbility( + new PutLibraryIntoGraveTargetEffect(1), new GenericManaCost(1) + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // Tap four untapped Advisors you control: Target player puts the top twelve cards of their library into their graveyard. + ability = new SimpleActivatedAbility( + new PutLibraryIntoGraveTargetEffect(12), + new TapTargetCost(new TargetControlledPermanent( + 4, 4, filter, true + )) + ); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + + // A deck can have any number of cards named Persistent Petitioners. + this.getSpellAbility().addEffect(new InfoEffect("A deck can have any number of cards named Persistent Petitioners.")); + } + + private PersistentPetitioners(final PersistentPetitioners card) { + super(card); + } + + @Override + public PersistentPetitioners copy() { + return new PersistentPetitioners(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PersonalEnergyShield.java b/Mage.Sets/src/mage/cards/p/PersonalEnergyShield.java index 9fe269d416..dc6e98fe6a 100644 --- a/Mage.Sets/src/mage/cards/p/PersonalEnergyShield.java +++ b/Mage.Sets/src/mage/cards/p/PersonalEnergyShield.java @@ -22,7 +22,7 @@ import mage.target.TargetSpell; */ public final class PersonalEnergyShield extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets you or a permanent you control"); + private static final FilterSpell filter = new FilterSpell("spell that targets you or a permanent you control"); static { filter.add(new PersonalEnergyFieldPredicate()); diff --git a/Mage.Sets/src/mage/cards/p/PestilentSpirit.java b/Mage.Sets/src/mage/cards/p/PestilentSpirit.java new file mode 100644 index 0000000000..56f1611be3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PestilentSpirit.java @@ -0,0 +1,63 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.GainAbilitySpellsEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterObject; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PestilentSpirit extends CardImpl { + + private static final FilterObject filter = new FilterObject("instant and sorcery spells you control"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.INSTANT), + new CardTypePredicate(CardType.SORCERY) + )); + } + + public PestilentSpirit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Menace + this.addAbility(new MenaceAbility()); + + // Deathtouch + this.addAbility(DeathtouchAbility.getInstance()); + + // Instant and sorcery spells you control have deathtouch. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilitySpellsEffect( + DeathtouchAbility.getInstance(), filter + ).setText("Instant and sorcery spells you control have deathtouch") + )); + } + + private PestilentSpirit(final PestilentSpirit card) { + super(card); + } + + @Override + public PestilentSpirit copy() { + return new PestilentSpirit(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java index 85812a645e..167b6d2ba1 100644 --- a/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java +++ b/Mage.Sets/src/mage/cards/p/PetalmaneBaku.java @@ -37,7 +37,7 @@ public final class PetalmaneBaku extends CardImpl { // {1}, Remove X ki counters from Petalmane Baku: Add X mana of any one color. Ability ability = new DynamicManaAbility( new Mana(0, 0, 0, 0, 0, 0, 1, 0), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new ManaCostsImpl<>("{1}"), "Add X mana of any one color", true, new CountersSourceCount(CounterType.KI)); diff --git a/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java b/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java index 26b90f09b9..e331b79599 100644 --- a/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java +++ b/Mage.Sets/src/mage/cards/p/PetalsOfInsight.java @@ -61,8 +61,7 @@ class PetalsOfInsightEffect extends OneShotEffect { if (controller == null || sourceObject == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 3)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); controller.lookAtCards(sourceObject.getIdName(), cards, game); if (controller.chooseUse(outcome, "Put the cards on the bottom of your library in any order?", source, game)) { diff --git a/Mage.Sets/src/mage/cards/p/PetraSphinx.java b/Mage.Sets/src/mage/cards/p/PetraSphinx.java index cb6197c333..253d4e77f0 100644 --- a/Mage.Sets/src/mage/cards/p/PetraSphinx.java +++ b/Mage.Sets/src/mage/cards/p/PetraSphinx.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -20,8 +18,9 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com & L_J */ public final class PetraSphinx extends CardImpl { @@ -79,7 +78,7 @@ class PetraSphinxEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(source, cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.moveCards(cards, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/p/PetrifiedWoodKin.java b/Mage.Sets/src/mage/cards/p/PetrifiedWoodKin.java index cd47ad163c..5ebe0cbb21 100644 --- a/Mage.Sets/src/mage/cards/p/PetrifiedWoodKin.java +++ b/Mage.Sets/src/mage/cards/p/PetrifiedWoodKin.java @@ -2,6 +2,7 @@ package mage.cards.p; import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; @@ -82,16 +83,16 @@ class PetrifiedWoodKinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - DamageDoneWatcher watcher = (DamageDoneWatcher) game.getState().getWatchers().get(DamageDoneWatcher.class.getSimpleName()); + DamageDoneWatcher watcher = game.getState().getWatcher(DamageDoneWatcher.class); Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (player == null || watcher == null || permanent == null) { return false; } - ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event + List appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event int amount = 0; for (UUID opponentId : game.getOpponents(player.getId())) { MageObjectReference mor = new MageObjectReference(opponentId, game); - amount += watcher.damagedObjects.getOrDefault(mor, 0); + amount += watcher.getDamagedObjects().getOrDefault(mor, 0); } permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game, appliedEffects); return true; diff --git a/Mage.Sets/src/mage/cards/p/Phantasmagorian.java b/Mage.Sets/src/mage/cards/p/Phantasmagorian.java index 60557d6b6d..cbb8fcb36e 100644 --- a/Mage.Sets/src/mage/cards/p/Phantasmagorian.java +++ b/Mage.Sets/src/mage/cards/p/Phantasmagorian.java @@ -75,7 +75,8 @@ class CounterSourceEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); cost.clearPaid(); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) + if (player != null + && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(outcome, "Discard three cards to counter " + sourceObject.getIdName() + '?', source, game)) { if (cost.pay(source, game, source.getSourceId(), playerId, false, null)) { game.informPlayers(player.getLogName() + " discards 3 cards to counter " + sourceObject.getIdName() + '.'); diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalImage.java b/Mage.Sets/src/mage/cards/p/PhantasmalImage.java index 003ff68f88..9c0b2db68f 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalImage.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalImage.java @@ -21,14 +21,13 @@ import mage.util.functions.ApplyToPermanent; import java.util.UUID; /** - * * @author North */ public final class PhantasmalImage extends CardImpl { private static final String effectText = "a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it has \"When this creature becomes the target of a spell or ability, sacrifice it.\""; - ApplyToPermanent phantasmalImageApplier = new ApplyToPermanent() { + private static final ApplyToPermanent phantasmalImageApplier = new ApplyToPermanent() { @Override public boolean apply(Game game, Permanent permanent, Ability source, UUID copyToObjectId) { if (!permanent.hasSubtype(SubType.ILLUSION, game)) { diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalMount.java b/Mage.Sets/src/mage/cards/p/PhantasmalMount.java new file mode 100644 index 0000000000..549941c397 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhantasmalMount.java @@ -0,0 +1,156 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.ToughnessPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class PhantasmalMount extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("with toughness 2 or less"); + + static { + filter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3)); + } + + public PhantasmalMount(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.subtype.add(SubType.HORSE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {tap}: Target creature you control with toughness 2 or less gets +1/+1 and gains flying until end of turn. When Phantasmal Mount leaves the battlefield this turn, sacrifice that creature. When the creature leaves the battlefield this turn, sacrifice Phantasmal Mount. + Ability activatedAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PhantasmalMountEffect(), new TapSourceCost()); + activatedAbility.addTarget(new TargetControlledCreaturePermanent(filter)); + this.addAbility(activatedAbility); + + } + + private PhantasmalMount(final PhantasmalMount card) { + super(card); + } + + @Override + public PhantasmalMount copy() { + return new PhantasmalMount(this); + } +} + +class PhantasmalMountEffect extends OneShotEffect { + + PhantasmalMountEffect() { + super(Outcome.Neutral); + staticText = "Target creature you control with toughness 2 or less gets +1/+1 " + + "and gains flying until end of turn. When {this} leaves the battlefield this turn, " + + "sacrifice that creature. When the creature leaves the battlefield this turn, sacrifice {this}"; + } + + PhantasmalMountEffect(PhantasmalMountEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent targetCreature = game.getPermanent(source.getFirstTarget()); + if (targetCreature != null) { + ContinuousEffect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(source.getFirstTarget())); + game.addEffect(effect, source); + Effect sacrificeCreatureEffect = new SacrificeTargetEffect(); + Effect sacrificePhantasmalMountEffect = new SacrificeTargetEffect(); + ContinuousEffect gainAbility = new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn); + gainAbility.setTargetPointer(new FixedTarget(source.getFirstTarget())); + game.addEffect(gainAbility, source); + sacrificeCreatureEffect.setTargetPointer(new FixedTarget(source.getFirstTarget())); + sacrificePhantasmalMountEffect.setTargetPointer(new FixedTarget(source.getSourceId())); + DelayedTriggeredAbility dTA = new PhantasmalMountDelayedTriggeredAbility( + sacrificeCreatureEffect, + source.getSourceId()); + DelayedTriggeredAbility dTA2 = new PhantasmalMountDelayedTriggeredAbility( + sacrificePhantasmalMountEffect, + source.getFirstTarget()); + game.addDelayedTriggeredAbility(dTA, source); + game.addDelayedTriggeredAbility(dTA2, source); + return true; + } + return false; + } + + @Override + public PhantasmalMountEffect copy() { + return new PhantasmalMountEffect(this); + } +} + +class PhantasmalMountDelayedTriggeredAbility extends DelayedTriggeredAbility { + + UUID creatureId; + + PhantasmalMountDelayedTriggeredAbility(Effect effect, UUID creatureId) { + super(effect, Duration.EndOfTurn, true); + this.creatureId = creatureId; + } + + PhantasmalMountDelayedTriggeredAbility(PhantasmalMountDelayedTriggeredAbility ability) { + super(ability); + this.creatureId = ability.creatureId; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.ZONE_CHANGE + && event.getTargetId().equals(creatureId)) { + return true; + } + return false; + } + + @Override + public PhantasmalMountDelayedTriggeredAbility copy() { + return new PhantasmalMountDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "this left the battlefield"; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java b/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java new file mode 100644 index 0000000000..fb57f5e4ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhantasmalSphere.java @@ -0,0 +1,121 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.LeavesBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenTargetEffect; +import mage.abilities.effects.common.SacrificeSourceUnlessPaysEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.token.TokenImpl; +import mage.players.Player; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class PhantasmalSphere extends CardImpl { + + public PhantasmalSphere(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your upkeep, put a +1/+1 counter on Phantasmal Sphere, then sacrifice Phantasmal Sphere unless you pay {1} for each +1/+1 counter on it. + Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), TargetController.YOU, false); + Effect effect = new SacrificeSourceUnlessPaysEffect(new CountersSourceCount(CounterType.P1P1)); + effect.setText("then sacrifice {this} unless you pay {1} for each +1/+1 counter on it."); + ability.addEffect(effect); + this.addAbility(ability); + + // When Phantasmal Sphere leaves the battlefield, target opponent puts an X/X blue Orb creature token with flying onto the battlefield, where X is the number of +1/+1 counters on Phantasmal Sphere. + Ability ability2 = new LeavesBattlefieldTriggeredAbility(new PhantasmalSphereEffect(), false); + ability2.addTarget(new TargetOpponent()); + this.addAbility(ability2); + + } + + private PhantasmalSphere(final PhantasmalSphere card) { + super(card); + } + + @Override + public PhantasmalSphere copy() { + return new PhantasmalSphere(this); + } +} + +class PhantasmalSphereEffect extends OneShotEffect { + + public PhantasmalSphereEffect() { + super(Outcome.PutCreatureInPlay); + this.staticText = "target opponent puts an X/X blue Orb creature token " + + "with flying onto the battlefield, where X is the number " + + "of +1/+1 counters on {this}"; + } + + public PhantasmalSphereEffect(final PhantasmalSphereEffect effect) { + super(effect); + } + + @Override + public PhantasmalSphereEffect copy() { + return new PhantasmalSphereEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetOpponent = game.getPlayer(source.getFirstTarget()); + if (controller != null + && targetOpponent != null) { + Effect effect = new CreateTokenTargetEffect(new PhantasmalSphereToken( + new CountersSourceCount(CounterType.P1P1).calculate( + game, source, null))); + effect.setTargetPointer(new FixedTarget(targetOpponent.getId())); + effect.apply(game, source); + } + return false; + } +} + +class PhantasmalSphereToken extends TokenImpl { + + public PhantasmalSphereToken(int xValue) { + super("Orb", "X/X blue Orb creature token with flying"); + cardType.add(CardType.CREATURE); + color.setBlue(true); + subtype.add(SubType.ORB); + power = new MageInt(xValue); + toughness = new MageInt(xValue); + addAbility(FlyingAbility.getInstance()); + } + + public PhantasmalSphereToken(final PhantasmalSphereToken token) { + super(token); + } + + public PhantasmalSphereToken copy() { + return new PhantasmalSphereToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java b/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java index f5bb97875c..cb425f1d88 100644 --- a/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java +++ b/Mage.Sets/src/mage/cards/p/PhantasmalTerrain.java @@ -125,7 +125,8 @@ class PhantasmalTerrainContinuousEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/p/PhantomGeneral.java b/Mage.Sets/src/mage/cards/p/PhantomGeneral.java index a5e802e5d4..4f2ac31139 100644 --- a/Mage.Sets/src/mage/cards/p/PhantomGeneral.java +++ b/Mage.Sets/src/mage/cards/p/PhantomGeneral.java @@ -24,7 +24,7 @@ public final class PhantomGeneral extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens you control"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java b/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java index 9b044c1a68..6201578c0f 100644 --- a/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java +++ b/Mage.Sets/src/mage/cards/p/PhosphorescentFeast.java @@ -67,10 +67,11 @@ class PhosphorescentFeastEffect extends OneShotEffect { if (player == null) { return false; } - Cards cards = new CardsImpl(); if (player.getHand().count(new FilterCard(), game) > 0) { TargetCardInHand target = new TargetCardInHand(0, Integer.MAX_VALUE, new FilterCard()); if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + + Cards cards = new CardsImpl(); for (UUID uuid : target.getTargets()) { cards.add(player.getHand().get(uuid, game)); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java index 49daddf761..41900f0ee1 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianDreadnought.java @@ -56,7 +56,7 @@ class PhyrexianDreadnoughtSacrificeCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("any number of creatures with total power 12 or greater"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public PhyrexianDreadnoughtSacrificeCost() { @@ -79,7 +79,7 @@ class PhyrexianDreadnoughtSacrificeCost extends CostImpl { } } } - game.informPlayers(new StringBuilder("Sacrificed creatures with total power of ").append(sumPower).toString()); + game.informPlayers("Sacrificed creatures with total power of " + sumPower); paid = sumPower >= 12; return paid; } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java b/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java index 0904b81ba8..0b035db1bd 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianIngester.java @@ -36,7 +36,7 @@ public final class PhyrexianIngester extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public PhyrexianIngester(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianPortal.java b/Mage.Sets/src/mage/cards/p/PhyrexianPortal.java new file mode 100644 index 0000000000..b0cccd8a0a --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PhyrexianPortal.java @@ -0,0 +1,115 @@ + +package mage.cards.p; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetOpponent; + +/** + * + * @author L_J + */ +public final class PhyrexianPortal extends CardImpl { + + public PhyrexianPortal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); + + // {3}: If your library has ten or more cards in it, target opponent looks at the top ten cards of your library and separates them into two face-down piles. Exile one of those piles. Search the other pile for a card, put it into your hand, then shuffle the rest of that pile into your library. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PhyrexianPortalEffect(), new ManaCostsImpl("{3}")); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public PhyrexianPortal(final PhyrexianPortal card) { + super(card); + } + + @Override + public PhyrexianPortal copy() { + return new PhyrexianPortal(this); + } +} + +class PhyrexianPortalEffect extends OneShotEffect { + + public PhyrexianPortalEffect() { + super(Outcome.Benefit); + this.staticText = "If your library has ten or more cards in it, target opponent looks at the top ten cards of your library and separates them into two face-down piles. Exile one of those piles. Search the other pile for a card, put it into your hand, then shuffle the rest of that pile into your library"; + } + + public PhyrexianPortalEffect(final PhyrexianPortalEffect effect) { + super(effect); + } + + @Override + public PhyrexianPortalEffect copy() { + return new PhyrexianPortalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller != null && opponent != null) { + if (controller.getLibrary().size() >= 10) { + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 10)); + + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); + List pile1 = new ArrayList<>(); + if (opponent.choose(Outcome.Neutral, cards, target, game)) { + List targets = target.getTargets(); + for (UUID targetId : targets) { + Card card = cards.get(targetId, game); + if (card != null) { + pile1.add(card); + cards.remove(card); + } + } + } + List pile2 = new ArrayList<>(); + pile2.addAll(cards.getCards(game)); + + game.informPlayers(opponent.getLogName() + " separated the top 10 cards of " + controller.getLogName() + "'s library into two face-down piles (" + + pile1.size() + " cards and " + pile2.size() + " cards)"); + // it's not viable to turn cards face down here for choosePile (since they're still library cards), this is a workaround + boolean choice = controller.chooseUse(outcome, "Choose pile to search for a card (the other will be exiled):", + source.getSourceObject(game).getLogName(), "Pile 1 (" + pile1.size() + " cards)", "Pile 2 (" + pile2.size() + " cards)", source, game); + + game.informPlayers(controller.getLogName() + " chooses to search the " + (choice ? "first" : "second") + " pile"); + Cards pileToExile = new CardsImpl(); + pileToExile.addAll(choice ? pile2 : pile1); + controller.moveCardsToExile(pileToExile.getCards(game), source, game, true, null, ""); + Cards chosenPile = new CardsImpl(); + chosenPile.addAll(choice ? pile1 : pile2); + + TargetCard target2 = new TargetCard(Zone.HAND, new FilterCard("card to put into your hand")); + if (controller.choose(outcome, chosenPile, target2, game)) { + Card card = chosenPile.get(target2.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.HAND, source, game); + } + } + controller.shuffleLibrary(source, game); + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java index eb4d598ecf..e6a289cbe1 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianProcessor.java @@ -1,42 +1,46 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.Zone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.game.permanent.token.MinionToken; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author FenrisulfrX */ public final class PhyrexianProcessor extends CardImpl { public PhyrexianProcessor(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // As {this} enters the battlefield, pay any amount of life. - this.addAbility(new EntersBattlefieldTriggeredAbility(new PhyrexianProcessorEffect())); + this.addAbility(new AsEntersBattlefieldAbility(new PhyrexianProcessorPayLifeEffect())); + // {4}, {tap}: Create an X/X black Minion creature token, where X is the life paid as {this} entered the battlefield. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PhyrexianProcessorCreateTokenEffect(), new ManaCostsImpl("{4}")); + Ability ability = new SimpleActivatedAbility( + new PhyrexianProcessorCreateTokenEffect(), new GenericManaCost(4) + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } - public PhyrexianProcessor(final PhyrexianProcessor card) { + private PhyrexianProcessor(final PhyrexianProcessor card) { super(card); } @@ -46,50 +50,56 @@ public final class PhyrexianProcessor extends CardImpl { } } -class PhyrexianProcessorEffect extends OneShotEffect { +class PhyrexianProcessorPayLifeEffect extends OneShotEffect { - public PhyrexianProcessorEffect() { + PhyrexianProcessorPayLifeEffect() { super(Outcome.LoseLife); - staticText = "Pay any amount of life."; + staticText = "pay any amount of life."; } - public PhyrexianProcessorEffect(final PhyrexianProcessorEffect effect) { + private PhyrexianProcessorPayLifeEffect(final PhyrexianProcessorPayLifeEffect effect) { super(effect); } @Override - public PhyrexianProcessorEffect copy() { - return new PhyrexianProcessorEffect(this); + public PhyrexianProcessorPayLifeEffect copy() { + return new PhyrexianProcessorPayLifeEffect(this); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if(controller != null) { - Card sourceCard = game.getCard(source.getSourceId()); - int payAmount = controller.getAmount(0, controller.getLife(), staticText, game); - controller.loseLife(payAmount, game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(controller.getLogName()) - .append(" pays ").append(payAmount).append(" life.").toString()); - String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game); - game.getState().setValue(key, payAmount); - return true; + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if (controller == null || permanent == null) { + return false; } - return false; + int payAmount = controller.getAmount(0, controller.getLife(), "Pay any amount of life", game); + Cost cost = new PayLifeCost(payAmount); + if (!cost.pay(source, game, source.getSourceId(), source.getControllerId(), true)) { + return false; + } + Card sourceCard = game.getCard(source.getSourceId()); + game.informPlayers((sourceCard != null ? sourceCard.getName() : "") + ": " + controller.getLogName() + + " pays " + payAmount + " life."); + String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game); + game.getState().setValue(key, payAmount); + permanent.addInfo("life paid", CardUtil.addToolTipMarkTags("Life paid: " + payAmount), game); + return true; } } class PhyrexianProcessorCreateTokenEffect extends OneShotEffect { - - public PhyrexianProcessorCreateTokenEffect() { + + PhyrexianProcessorCreateTokenEffect() { super(Outcome.PutCreatureInPlay); - staticText = "Create an X/X black Minion creature token"; + staticText = "Create an X/X black Minion creature token, " + + "where X is the life paid as {this} entered the battlefield."; } - public PhyrexianProcessorCreateTokenEffect(PhyrexianProcessorCreateTokenEffect ability) { + private PhyrexianProcessorCreateTokenEffect(PhyrexianProcessorCreateTokenEffect ability) { super(ability); } - + @Override public PhyrexianProcessorCreateTokenEffect copy() { return new PhyrexianProcessorCreateTokenEffect(this); @@ -97,9 +107,9 @@ class PhyrexianProcessorCreateTokenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game); + String key = CardUtil.getCardZoneString("lifePaid", source.getSourceId(), game, true); Object object = game.getState().getValue(key); - if(object instanceof Integer) { + if (object instanceof Integer) { int lifePaid = (int) object; MinionToken token = new MinionToken(); token.getPower().modifyBaseValue(lifePaid); diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianPurge.java b/Mage.Sets/src/mage/cards/p/PhyrexianPurge.java index f6860e52d4..526c986b5b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianPurge.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianPurge.java @@ -1,9 +1,8 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.effects.common.DestroyMultiTargetEffect; import mage.abilities.effects.common.InfoEffect; @@ -13,9 +12,11 @@ import mage.constants.CardType; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author escplan9 - Derek Monturo */ public final class PhyrexianPurge extends CardImpl { @@ -28,24 +29,8 @@ public final class PhyrexianPurge extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); this.getSpellAbility().addEffect(new DestroyMultiTargetEffect()); this.getSpellAbility().addEffect(new InfoEffect("

    {this} costs 3 life more to cast for each target")); - } - - @Override - public void adjustCosts(Ability ability, Game game) { - int numTargets = ability.getTargets().get(0).getTargets().size(); - if (numTargets > 0) { - ability.getCosts().add(new PayLifeCost(numTargets * 3)); - } - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - Player you = game.getPlayer(ownerId); - int maxTargets = you.getLife() / 3; - ability.addTarget(new TargetCreaturePermanent(0, maxTargets)); - } + this.getSpellAbility().setTargetAdjuster(PhyrexianPurgeTargetAdjuster.instance); + this.getSpellAbility().setCostAdjuster(PhyrexianPurgeCostAdjuster.instance); } public PhyrexianPurge(final PhyrexianPurge card) { @@ -57,3 +42,27 @@ public final class PhyrexianPurge extends CardImpl { return new PhyrexianPurge(this); } } + +enum PhyrexianPurgeCostAdjuster implements CostAdjuster { + instance; + + @Override + public void adjustCosts(Ability ability, Game game) { + int numTargets = ability.getTargets().get(0).getTargets().size(); + if (numTargets > 0) { + ability.getCosts().add(new PayLifeCost(numTargets * 3)); + } + } +} + +enum PhyrexianPurgeTargetAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + Player you = game.getPlayer(ability.getControllerId()); + int maxTargets = you.getLife() / 3; + ability.addTarget(new TargetCreaturePermanent(0, maxTargets)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianRager.java b/Mage.Sets/src/mage/cards/p/PhyrexianRager.java index 62f62d7d51..98e5594f5b 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianRager.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianRager.java @@ -1,8 +1,5 @@ - - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,24 +10,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author Loki */ public final class PhyrexianRager extends CardImpl { - public PhyrexianRager (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + public PhyrexianRager(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); this.toughness = new MageInt(2); - Ability ability = new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false); - ability.addEffect(new LoseLifeSourceControllerEffect(1)); + Ability ability = new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); this.addAbility(ability); } - public PhyrexianRager (final PhyrexianRager card) { + public PhyrexianRager(final PhyrexianRager card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java index 4f2f1f4e2d..3dd4288d02 100644 --- a/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java +++ b/Mage.Sets/src/mage/cards/p/PhyrexianSwarmlord.java @@ -30,7 +30,7 @@ public final class PhyrexianSwarmlord extends CardImpl { this.addAbility(InfectAbility.getInstance()); this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", - new CreateTokenEffect(new InsectInfectToken(), new OpponentsPoisonCountersCount()))); + new CreateTokenEffect(new InsectInfectToken(), OpponentsPoisonCountersCount.instance))); } public PhyrexianSwarmlord(final PhyrexianSwarmlord card) { diff --git a/Mage.Sets/src/mage/cards/p/PiannaNomadCaptain.java b/Mage.Sets/src/mage/cards/p/PiannaNomadCaptain.java index 15e7870f00..72a9ca81f1 100644 --- a/Mage.Sets/src/mage/cards/p/PiannaNomadCaptain.java +++ b/Mage.Sets/src/mage/cards/p/PiannaNomadCaptain.java @@ -23,7 +23,7 @@ public final class PiannaNomadCaptain extends CardImpl { static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creatures"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public PiannaNomadCaptain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PiasRevolution.java b/Mage.Sets/src/mage/cards/p/PiasRevolution.java index bba23c5fc6..8580678631 100644 --- a/Mage.Sets/src/mage/cards/p/PiasRevolution.java +++ b/Mage.Sets/src/mage/cards/p/PiasRevolution.java @@ -93,7 +93,7 @@ class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { private static final FilterArtifactPermanent filter = new FilterArtifactPermanent(); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(new OwnerPredicate(TargetController.YOU)); } @@ -118,7 +118,7 @@ class PiasRevolutionTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && filter.match(permanent, sourceId, controllerId, game)) { for (Effect effect : this.getEffects()) { diff --git a/Mage.Sets/src/mage/cards/p/PickTheBrain.java b/Mage.Sets/src/mage/cards/p/PickTheBrain.java index 461cbb5277..4edb943d41 100644 --- a/Mage.Sets/src/mage/cards/p/PickTheBrain.java +++ b/Mage.Sets/src/mage/cards/p/PickTheBrain.java @@ -1,11 +1,12 @@ - package mage.cards.p; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.effects.common.search.SearchTargetGraveyardHandLibraryForCardNameAndExileEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,7 +20,6 @@ import mage.target.TargetCard; import mage.target.common.TargetOpponent; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class PickTheBrain extends CardImpl { @@ -31,6 +31,7 @@ public final class PickTheBrain extends CardImpl { // Delirium — If there are four or more card types among cards in your graveyard, search that player's graveyard, hand, and library for any number of cards with the same name as the exiled card, exile those cards, then that player shuffles their library. this.getSpellAbility().addEffect(new PickTheBrainEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); + this.getSpellAbility().addHint(DeliriumHint.instance); } public PickTheBrain(final PickTheBrain card) { diff --git a/Mage.Sets/src/mage/cards/p/PietyCharm.java b/Mage.Sets/src/mage/cards/p/PietyCharm.java index d76b2c9a82..157fcab437 100644 --- a/Mage.Sets/src/mage/cards/p/PietyCharm.java +++ b/Mage.Sets/src/mage/cards/p/PietyCharm.java @@ -43,12 +43,12 @@ public final class PietyCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or target Soldier creature gets +2/+2 until end of turn Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent(filter2)); + mode.addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent(filter2)); this.getSpellAbility().addMode(mode); // or creatures you control gain vigilance until end of turn. mode = new Mode(); - mode.getEffects().add(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"))); + mode.addEffect(new GainAbilityAllEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn, new FilterControlledCreaturePermanent("creatures you control"))); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java b/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java index 80b830551c..f238821e39 100644 --- a/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java +++ b/Mage.Sets/src/mage/cards/p/PillarOfOrigins.java @@ -97,7 +97,7 @@ class PillarOfOriginsManaCondition extends CreatureCastManaCondition { if (super.apply(game, source)) { // check: ... of the chosen type MageObject object = game.getObject(source.getSourceId()); - if (creatureType != null && object.hasSubtype(creatureType, game)) { + if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/p/PiousEvangel.java b/Mage.Sets/src/mage/cards/p/PiousEvangel.java index 3cf2046a8a..917a03a500 100644 --- a/Mage.Sets/src/mage/cards/p/PiousEvangel.java +++ b/Mage.Sets/src/mage/cards/p/PiousEvangel.java @@ -33,7 +33,7 @@ public final class PiousEvangel extends CardImpl { private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("another permanent"); static { - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public PiousEvangel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PiracyCharm.java b/Mage.Sets/src/mage/cards/p/PiracyCharm.java index 2b612fd12d..c654fc0bfc 100644 --- a/Mage.Sets/src/mage/cards/p/PiracyCharm.java +++ b/Mage.Sets/src/mage/cards/p/PiracyCharm.java @@ -29,13 +29,13 @@ public final class PiracyCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature gets +2/-1 until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(2, -1, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target player discards a card. mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(1)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new DiscardTargetEffect(1)); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PirsWhim.java b/Mage.Sets/src/mage/cards/p/PirsWhim.java index 09ea5499bb..b8da3732c6 100644 --- a/Mage.Sets/src/mage/cards/p/PirsWhim.java +++ b/Mage.Sets/src/mage/cards/p/PirsWhim.java @@ -64,13 +64,13 @@ class PirsWhimEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); ChooseFriendsAndFoes choice = new ChooseFriendsAndFoes(); - if (!choice.chooseFriendOrFoe(controller, source, game)) { + if (controller != null && !choice.chooseFriendOrFoe(controller, source, game)) { return false; } for (Player player : choice.getFriends()) { if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, StaticFilters.FILTER_CARD_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, true, null); player.shuffleLibrary(source, game); } diff --git a/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java b/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java index e362ad9416..e17e51ab88 100644 --- a/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java +++ b/Mage.Sets/src/mage/cards/p/PistonFistCyclops.java @@ -64,8 +64,8 @@ enum PistonFistCyclopsCondition implements Condition { @Override public boolean apply(Game game, Ability source) { SpellsCastWatcher watcher - = (SpellsCastWatcher) game.getState().getWatchers().get( - SpellsCastWatcher.class.getSimpleName() + = game.getState().getWatcher( + SpellsCastWatcher.class ); if (watcher == null) { return false; diff --git a/Mage.Sets/src/mage/cards/p/PithingNeedle.java b/Mage.Sets/src/mage/cards/p/PithingNeedle.java index 402cfba00d..d8049e8ab0 100644 --- a/Mage.Sets/src/mage/cards/p/PithingNeedle.java +++ b/Mage.Sets/src/mage/cards/p/PithingNeedle.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.Optional; @@ -9,6 +8,7 @@ import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ChooseACardNameEffect; +import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -71,9 +71,10 @@ class PithingNeedleEffect extends ContinuousRuleModifyingEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { MageObject object = game.getObject(event.getSourceId()); Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); - if (ability.isPresent() && object != null) { + if (ability.isPresent() + && object != null) { if (game.getState().getPlayersInRange(source.getControllerId(), game).contains(event.getPlayerId()) // controller in range - && ability.get().getAbilityType() != AbilityType.MANA + && !(ability.get() instanceof ActivatedManaAbilityImpl) // not an activated mana ability && object.getName().equals(game.getState().getValue(source.getSourceId().toString() + ChooseACardNameEffect.INFO_KEY))) { return true; } diff --git a/Mage.Sets/src/mage/cards/p/PitilessPlunderer.java b/Mage.Sets/src/mage/cards/p/PitilessPlunderer.java index fa3228ce6a..38d5ac492a 100644 --- a/Mage.Sets/src/mage/cards/p/PitilessPlunderer.java +++ b/Mage.Sets/src/mage/cards/p/PitilessPlunderer.java @@ -21,10 +21,10 @@ import mage.game.permanent.token.TreasureToken; */ public final class PitilessPlunderer extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/p/PitilessPontiff.java b/Mage.Sets/src/mage/cards/p/PitilessPontiff.java new file mode 100644 index 0000000000..4b342f2c18 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PitilessPontiff.java @@ -0,0 +1,55 @@ +package mage.cards.p; + +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.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PitilessPontiff extends CardImpl { + + public PitilessPontiff(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}, Sacrifice another creature: Pitiless Pontiff gains deathtouch and indestructible until end of turn. + Ability ability = new SimpleActivatedAbility(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ).setText("{this} gains deathtouch"), new GenericManaCost(1)); + ability.addEffect(new GainAbilitySourceEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("and indestructible until end of turn")); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + ))); + this.addAbility(ability); + } + + private PitilessPontiff(final PitilessPontiff card) { + super(card); + } + + @Override + public PitilessPontiff copy() { + return new PitilessPontiff(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlagueBelcher.java b/Mage.Sets/src/mage/cards/p/PlagueBelcher.java index e042dcf7eb..65ef7f718d 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueBelcher.java +++ b/Mage.Sets/src/mage/cards/p/PlagueBelcher.java @@ -32,7 +32,7 @@ public final class PlagueBelcher extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public PlagueBelcher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PlagueOfVermin.java b/Mage.Sets/src/mage/cards/p/PlagueOfVermin.java index f9c188f401..0a5dd16f1e 100644 --- a/Mage.Sets/src/mage/cards/p/PlagueOfVermin.java +++ b/Mage.Sets/src/mage/cards/p/PlagueOfVermin.java @@ -1,9 +1,5 @@ - package mage.cards.p; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -16,14 +12,17 @@ import mage.game.permanent.token.RatToken; import mage.players.Player; import mage.players.PlayerList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class PlagueOfVermin extends CardImpl { public PlagueOfVermin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{6}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{B}"); // Starting with you, each player may pay any amount of life. Repeat this process until no one pays life. Each player creates a 1/1 black Rat creature token for each 1 life he or she paid this way. @@ -60,7 +59,6 @@ class PlagueOfVerminEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); Map payLife = new HashMap<>(); int currentLifePaid; int totalPaidLife; @@ -90,15 +88,16 @@ class PlagueOfVerminEffect extends OneShotEffect { payLife.put(currentPlayer.getId(), currentLifePaid + totalPaidLife); } } - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(currentPlayer.getLogName()).append(" pays ").append(payLife.get(currentPlayer.getId())).append(" life").toString()); + Card sourceCard = game.getCard(source.getSourceId()); + game.informPlayers((sourceCard != null ? sourceCard.getName() : "") + ": " + currentPlayer.getLogName() + " pays " + payLife.get(currentPlayer.getId()) + " life"); firstInactivePlayer = null; } } - + // get next player playerList.getNext(); currentPlayer = game.getPlayer(playerList.get()); - + // if all player since this player didn't put permanent in play finish the process if (currentPlayer.getId().equals(firstInactivePlayer)) { break; diff --git a/Mage.Sets/src/mage/cards/p/PlagueWight.java b/Mage.Sets/src/mage/cards/p/PlagueWight.java new file mode 100644 index 0000000000..433b85b01d --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlagueWight.java @@ -0,0 +1,75 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BecomesBlockedTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PlagueWight extends CardImpl { + + public PlagueWight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Whenever Plague Wight becomes blocked, each creature blocking it gets -1/-1 until end of turn. + this.addAbility(new BecomesBlockedTriggeredAbility(new PlagueWightEffect(), false)); + } + + private PlagueWight(final PlagueWight card) { + super(card); + } + + @Override + public PlagueWight copy() { + return new PlagueWight(this); + } +} + +class PlagueWightEffect extends OneShotEffect { + + PlagueWightEffect() { + super(Outcome.Benefit); + staticText = "each creature blocking it gets -1/-1 until end of turn."; + } + + private PlagueWightEffect(final PlagueWightEffect effect) { + super(effect); + } + + @Override + public PlagueWightEffect copy() { + return new PlagueWightEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new BlockingAttackerIdPredicate(source.getSourceId())); + game.addEffect(new BoostAllEffect(-1, -1, Duration.EndOfTurn, filter, false), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java index 39eaf6eb38..19830b5503 100644 --- a/Mage.Sets/src/mage/cards/p/Plaguecrafter.java +++ b/Mage.Sets/src/mage/cards/p/Plaguecrafter.java @@ -1,8 +1,5 @@ package mage.cards.p; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -23,8 +20,11 @@ import mage.players.Player; import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author themogwi */ public final class Plaguecrafter extends CardImpl { @@ -43,7 +43,7 @@ public final class Plaguecrafter extends CardImpl { this.addAbility(new EntersBattlefieldTriggeredAbility(new PlaguecrafterEffect())); } - public Plaguecrafter(final Plaguecrafter card) { + private Plaguecrafter(final Plaguecrafter card) { super(card); } @@ -55,13 +55,13 @@ public final class Plaguecrafter extends CardImpl { class PlaguecrafterEffect extends OneShotEffect { - public PlaguecrafterEffect() { + PlaguecrafterEffect() { super(Outcome.Benefit); this.staticText = "each player sacrifices a creature or planeswalker. " + "Each player who can't discards a card."; } - public PlaguecrafterEffect(final PlaguecrafterEffect effect) { + private PlaguecrafterEffect(final PlaguecrafterEffect effect) { super(effect); } @@ -82,20 +82,22 @@ class PlaguecrafterEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null) { - FilterControlledPermanent filter = new FilterControlledPermanent(); - filter.add(Predicates.or( - new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.PLANESWALKER))); - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - if (target.canChoose(player.getId(), game)) { - while (!target.isChosen() && player.canRespond()) { - player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); - } - perms.addAll(target.getTargets()); - } else { - cantSac.add(playerId); + if (player == null) { + continue; + } + FilterControlledPermanent filter = new FilterControlledPermanent("creature or planeswalker"); + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + if (target.canChoose(player.getId(), game)) { + while (!target.isChosen() && player.canRespond()) { + player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); } + perms.addAll(target.getTargets()); + } else { + cantSac.add(playerId); } } diff --git a/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java b/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java index 8bbb6cb49e..2a5dabc403 100644 --- a/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java +++ b/Mage.Sets/src/mage/cards/p/PlaguemawBeast.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,11 +11,13 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + /** - * * @author Loki */ public final class PlaguemawBeast extends CardImpl { @@ -28,6 +28,8 @@ public final class PlaguemawBeast extends CardImpl { this.power = new MageInt(4); this.toughness = new MageInt(3); + + // {T}, Sacrifice a creature: Proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ProliferateEffect(), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PlanarChaos.java b/Mage.Sets/src/mage/cards/p/PlanarChaos.java index 4f4dc4c6a7..863a0d0d4a 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarChaos.java +++ b/Mage.Sets/src/mage/cards/p/PlanarChaos.java @@ -61,7 +61,7 @@ class PlanarChaosUpkeepEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { Permanent perm = game.getPermanent(source.getSourceId()); if (perm != null) { perm.sacrifice(source.getSourceId(), game); @@ -104,7 +104,7 @@ class PlanarChaosCastAllEffect extends OneShotEffect { if (sourceObject != null && spell != null) { Player caster = game.getPlayer(spell.getControllerId()); if (caster != null) { - if (!caster.flipCoin(game)) { + if (!caster.flipCoin(source, game, true)) { game.informPlayers(sourceObject.getLogName() + ": " + spell.getLogName() + " countered"); game.getStack().counter(getTargetPointer().getFirst(game, source), source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/cards/p/PlanarOutburst.java b/Mage.Sets/src/mage/cards/p/PlanarOutburst.java index fab9b40eb5..0d7bfc485a 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarOutburst.java +++ b/Mage.Sets/src/mage/cards/p/PlanarOutburst.java @@ -17,7 +17,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public final class PlanarOutburst extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("nonland creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonland creatures"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); diff --git a/Mage.Sets/src/mage/cards/p/PlanarOverlay.java b/Mage.Sets/src/mage/cards/p/PlanarOverlay.java index e86353fc92..d7d8681eec 100644 --- a/Mage.Sets/src/mage/cards/p/PlanarOverlay.java +++ b/Mage.Sets/src/mage/cards/p/PlanarOverlay.java @@ -1,4 +1,3 @@ - package mage.cards.p; import mage.abilities.Ability; @@ -20,7 +19,6 @@ import java.util.Set; import java.util.UUID; /** - * * @author Styxo */ public final class PlanarOverlay extends CardImpl { @@ -66,7 +64,7 @@ class PlanarOverlayEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - for (SubType landName : SubType.getBasicLands(false)) { + for (SubType landName : SubType.getBasicLands()) { FilterLandPermanent filter = new FilterLandPermanent(landName + " to return to hand"); filter.add(new SubtypePredicate(landName)); filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java b/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java index 875e2f697e..7ff16984da 100644 --- a/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java +++ b/Mage.Sets/src/mage/cards/p/PlaneswalkersMischief.java @@ -82,8 +82,7 @@ class PlaneswalkersMischiefEffect extends OneShotEffect { if (revealedCard == null) { return false; } - Cards cards = new CardsImpl(); - cards.add(revealedCard); + Cards cards = new CardsImpl(revealedCard); opponent.revealCards("Planeswalker's Mischief Reveal", cards, game); if (revealedCard.isInstant() || revealedCard.isSorcery()) { @@ -155,7 +154,7 @@ class PlaneswalkersMischiefCondition implements Condition { if (!game.getExile().getExileZone(exileId).contains(cardId)) { return false; } - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName(), source.getSourceId()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class, source.getSourceId()); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spells != null) { diff --git a/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java b/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java new file mode 100644 index 0000000000..bc78247019 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlanewideCelebration.java @@ -0,0 +1,56 @@ +package mage.cards.p; + +import mage.abilities.Mode; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.game.permanent.token.PlanewideCelebrationToken; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PlanewideCelebration extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard("permanent card from your graveyard"); + + public PlanewideCelebration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{G}{G}"); + + // Choose four. You may choose the same mode more than once. + this.getSpellAbility().getModes().setMinModes(4); + this.getSpellAbility().getModes().setMaxModes(4); + this.getSpellAbility().getModes().setEachModeMoreThanOnce(true); + + // • Create a 2/2 Citizen creature token that's all colors. + this.getSpellAbility().addEffect(new CreateTokenEffect(new PlanewideCelebrationToken())); + + // • Return target permanent card from your graveyard to your hand. + Mode mode = new Mode(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addMode(mode); + + // • Proliferate. + this.getSpellAbility().addMode(new Mode(new ProliferateEffect(false))); + + // • You gain 4 life. + this.getSpellAbility().addMode(new Mode(new GainLifeEffect(4))); + } + + private PlanewideCelebration(final PlanewideCelebration card) { + super(card); + } + + @Override + public PlanewideCelebration copy() { + return new PlanewideCelebration(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java new file mode 100644 index 0000000000..4a452918e6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PlazaOfHarmony.java @@ -0,0 +1,63 @@ +package mage.cards.p; + +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.mana.AnyColorLandsProduceManaAbility; +import mage.abilities.mana.ColorlessManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PlazaOfHarmony extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledPermanent(); + private static final FilterPermanent filter2 = new FilterPermanent(SubType.GATE, "Gate"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + private static final Condition condition + = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public PlazaOfHarmony(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // When Plaza of Harmony enters the battlefield, if you control two or more Gates, you gain 3 life. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new GainLifeEffect(3)), + condition, "When {this} enters the battlefield, " + + "if you control two or more Gates, you gain 3 life." + ).addHint(new ConditionHint(condition, "You control two or more Gates"))); + + // {T}: Add {C}. + this.addAbility(new ColorlessManaAbility()); + + // {T}: Add one mana of any type a Gate you control could produce. + this.addAbility(new AnyColorLandsProduceManaAbility(TargetController.YOU, false, filter2)); + } + + private PlazaOfHarmony(final PlazaOfHarmony card) { + super(card); + } + + @Override + public PlazaOfHarmony copy() { + return new PlazaOfHarmony(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PledgeOfUnity.java b/Mage.Sets/src/mage/cards/p/PledgeOfUnity.java new file mode 100644 index 0000000000..a183a351e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PledgeOfUnity.java @@ -0,0 +1,39 @@ +package mage.cards.p; + +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.counters.CounterType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PledgeOfUnity extends CardImpl { + + public PledgeOfUnity(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}{W}"); + + // Put a +1/+1 counter on each creature you control. You gain 1 life for each creature you control. + this.getSpellAbility().addEffect(new AddCountersAllEffect( + CounterType.P1P1.createInstance(), StaticFilters.FILTER_CONTROLLED_CREATURE + )); + this.getSpellAbility().addEffect(new GainLifeEffect( + new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE) + ).setText("You gain 1 life for each creature you control.")); + } + + private PledgeOfUnity(final PledgeOfUnity card) { + super(card); + } + + @Override + public PledgeOfUnity copy() { + return new PledgeOfUnity(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java b/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java index 51e4271bdd..869d5153fc 100644 --- a/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java +++ b/Mage.Sets/src/mage/cards/p/PlungeIntoDarkness.java @@ -41,7 +41,7 @@ public final class PlungeIntoDarkness extends CardImpl { this.getSpellAbility().addEffect(new PlungeIntoDarknessLifeEffect()); // or pay X life, then look at the top X cards of your library, put one of those cards into your hand, and exile the rest. Mode mode = new Mode(); - mode.getEffects().add(new PlungeIntoDarknessSearchEffect()); + mode.addEffect(new PlungeIntoDarknessSearchEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {B} diff --git a/Mage.Sets/src/mage/cards/p/PoeDameron.java b/Mage.Sets/src/mage/cards/p/PoeDameron.java index f0e7d9c6a8..a85a74dd10 100644 --- a/Mage.Sets/src/mage/cards/p/PoeDameron.java +++ b/Mage.Sets/src/mage/cards/p/PoeDameron.java @@ -25,7 +25,7 @@ public final class PoeDameron extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filterStarship.add(new ControllerPredicate(TargetController.YOU)); filterStarship.add(new SubtypePredicate(SubType.STARSHIP)); } diff --git a/Mage.Sets/src/mage/cards/p/PoisonbellyOgre.java b/Mage.Sets/src/mage/cards/p/PoisonbellyOgre.java index 866517b846..111a72772d 100644 --- a/Mage.Sets/src/mage/cards/p/PoisonbellyOgre.java +++ b/Mage.Sets/src/mage/cards/p/PoisonbellyOgre.java @@ -22,10 +22,10 @@ public final class PoisonbellyOgre extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } - private final static String RULE = "Whenever another creature enters the battlefield, its controller loses 1 life."; + private static final String RULE = "Whenever another creature enters the battlefield, its controller loses 1 life."; public PoisonbellyOgre(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); diff --git a/Mage.Sets/src/mage/cards/p/PollenRemedy.java b/Mage.Sets/src/mage/cards/p/PollenRemedy.java index 65d5256973..b13dadd098 100644 --- a/Mage.Sets/src/mage/cards/p/PollenRemedy.java +++ b/Mage.Sets/src/mage/cards/p/PollenRemedy.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -17,39 +16,30 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetAnyTargetAmount; +import mage.target.targetadjustment.TargetAdjuster; /** * * @author LoneFox - + * */ public final class PollenRemedy extends CardImpl { - private final UUID originalId; - public PollenRemedy(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); // Kicker-Sacrifice a land. this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(1, 1, new FilterControlledLandPermanent("a land"), true)))); // Prevent the next 3 damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose. If Pollen Remedy was kicked, prevent the next 6 damage this way instead. Effect effect = new ConditionalReplacementEffect(new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 6), - KickedCondition.instance, new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 3)); + KickedCondition.instance, new PreventDamageToTargetMultiAmountEffect(Duration.EndOfTurn, 3)); effect.setText("Prevent the next 3 damage that would be dealt this turn to any number of targets, divided as you choose. if this spell was kicked, prevent the next 6 damage this way instead."); this.getSpellAbility().addEffect(effect); - originalId = this.getSpellAbility().getOriginalId(); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if(ability.getOriginalId().equals(originalId)) { - ability.addTarget(new TargetAnyTargetAmount(KickedCondition.instance.apply(game, ability) ? 6 : 3)); - } + this.getSpellAbility().setTargetAdjuster(PollenRemedyAdjuster.instance); } public PollenRemedy(final PollenRemedy card) { super(card); - this.originalId = card.originalId; } @Override @@ -57,3 +47,12 @@ public final class PollenRemedy extends CardImpl { return new PollenRemedy(this); } } + +enum PollenRemedyAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.addTarget(new TargetAnyTargetAmount(KickedCondition.instance.apply(game, ability) ? 6 : 3)); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PollenbrightDruid.java b/Mage.Sets/src/mage/cards/p/PollenbrightDruid.java new file mode 100644 index 0000000000..cb51f26780 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PollenbrightDruid.java @@ -0,0 +1,51 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +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 PollenbrightDruid extends CardImpl { + + public PollenbrightDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Pollenbright Druid enters the battlefield, choose one — + // • Put a +1/+1 counter on target creature. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetCreaturePermanent()); + + // • Proliferate. (Choose any number of permanents and/or players, then give each another counter of each kind already there.) + ability.addMode(new Mode(new ProliferateEffect())); + this.addAbility(ability); + } + + private PollenbrightDruid(final PollenbrightDruid card) { + super(card); + } + + @Override + public PollenbrightDruid copy() { + return new PollenbrightDruid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PollutedBonds.java b/Mage.Sets/src/mage/cards/p/PollutedBonds.java index a6dc88dff1..1ceb68a6e1 100644 --- a/Mage.Sets/src/mage/cards/p/PollutedBonds.java +++ b/Mage.Sets/src/mage/cards/p/PollutedBonds.java @@ -33,12 +33,14 @@ public final class PollutedBonds extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{B}{B}"); // Whenever a land enters the battlefield under an opponent's control, that player loses 2 life and you gain 2 life. - Effect effect = new LoseLifeTargetEffect(2); - effect.setText("that player loses 2 life"); - Ability ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, effect, filter, false, SetTargetPointer.PLAYER, ""); - effect = new GainLifeEffect(2); - effect.setText("and you gain 2 life"); - ability.addEffect(effect); + Ability ability = new EntersBattlefieldAllTriggeredAbility( + Zone.BATTLEFIELD, + new LoseLifeTargetEffect(2), + filter, + false, + SetTargetPointer.PLAYER, + "Whenever a land enters the battlefield under an opponent's control, that player loses 2 life and you gain 2 life."); + ability.addEffect(new GainLifeEffect(2)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PolukranosWorldEater.java b/Mage.Sets/src/mage/cards/p/PolukranosWorldEater.java index 6f6b1ca6b6..0fa30f941f 100644 --- a/Mage.Sets/src/mage/cards/p/PolukranosWorldEater.java +++ b/Mage.Sets/src/mage/cards/p/PolukranosWorldEater.java @@ -1,9 +1,6 @@ package mage.cards.p; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BecomesMonstrousSourceTriggeredAbility; @@ -12,47 +9,44 @@ import mage.abilities.keyword.MonstrosityAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetCreaturePermanentAmount; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * * The value of X in Polukranos's last ability is equal to the value chosen - * for X when its activated ability was activated. - * + * for X when its activated ability was activated. + *

    * * The number of targets chosen for the triggered ability must be at least one - * (if X wasn't 0) and at most X. You choose the division of damage as you put - * the ability on the stack, not as it resolves. Each target must be assigned - * at least 1 damage. In multiplayer games, you may choose creatures controlled - * by different opponents. - * + * (if X wasn't 0) and at most X. You choose the division of damage as you put + * the ability on the stack, not as it resolves. Each target must be assigned + * at least 1 damage. In multiplayer games, you may choose creatures controlled + * by different opponents. + *

    * * If some, but not all, of the ability's targets become illegal, you can't change - * the division of damage. Damage that would've been dealt to illegal targets - * simply isn't dealt. - * + * the division of damage. Damage that would've been dealt to illegal targets + * simply isn't dealt. + *

    * * As Polukranos's triggered ability resolves, Polukranos deals damage first, then - * the target creatures do. Although no creature will die until after the ability - * finishes resolving, the order could matter if Polukranos has wither or infect. + * the target creatures do. Although no creature will die until after the ability + * finishes resolving, the order could matter if Polukranos has wither or infect. * * @author LevelX2 */ public final class PolukranosWorldEater extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); - static { - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - } - public PolukranosWorldEater(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HYDRA); @@ -61,20 +55,11 @@ public final class PolukranosWorldEater extends CardImpl { // {X}{X}{G}: Monstrosity X. this.addAbility(new MonstrosityAbility("{X}{X}{G}", Integer.MAX_VALUE)); + // When Polukranos, World Eater becomes monstrous, it deals X damage divided as you choose among any number of target creatures your opponents control. Each of those creatures deals damage equal to its power to Polukranos. Ability ability = new BecomesMonstrousSourceTriggeredAbility(new PolukranosWorldEaterEffect()); - ability.addTarget(new TargetCreaturePermanentAmount(1, filter)); + ability.setTargetAdjuster(PolukranosWorldEaterAdjuster.instance); this.addAbility(ability); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof BecomesMonstrousSourceTriggeredAbility) { - int xValue = ((BecomesMonstrousSourceTriggeredAbility) ability).getMonstrosityValue(); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanentAmount(xValue, filter)); - } } public PolukranosWorldEater(final PolukranosWorldEater card) { @@ -87,6 +72,17 @@ public final class PolukranosWorldEater extends CardImpl { } } +enum PolukranosWorldEaterAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ((BecomesMonstrousSourceTriggeredAbility) ability).getMonstrosityValue(); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanentAmount(xValue, StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE)); + } +} + class PolukranosWorldEaterEffect extends OneShotEffect { public PolukranosWorldEaterEffect() { @@ -108,7 +104,7 @@ class PolukranosWorldEaterEffect extends OneShotEffect { if (!source.getTargets().isEmpty()) { Target multiTarget = source.getTargets().get(0); Set permanents = new HashSet<>(); - for (UUID target: multiTarget.getTargets()) { + for (UUID target : multiTarget.getTargets()) { Permanent permanent = game.getPermanent(target); if (permanent != null) { permanents.add(permanent); @@ -118,7 +114,7 @@ class PolukranosWorldEaterEffect extends OneShotEffect { // Each of those creatures deals damage equal to its power to Polukranos Permanent sourceCreature = game.getPermanent(source.getSourceId()); if (sourceCreature != null) { - for (Permanent permanent :permanents) { + for (Permanent permanent : permanents) { sourceCreature.damage(permanent.getPower().getValue(), permanent.getId(), game, false, true); } } diff --git a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java index 78092c9673..fde45d3681 100644 --- a/Mage.Sets/src/mage/cards/p/PolymorphousRush.java +++ b/Mage.Sets/src/mage/cards/p/PolymorphousRush.java @@ -11,6 +11,7 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -26,11 +27,7 @@ import mage.util.functions.EmptyApplyToPermanent; */ public final class PolymorphousRush extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } public PolymorphousRush(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); @@ -39,7 +36,7 @@ public final class PolymorphousRush extends CardImpl { this.addAbility(new StriveAbility("{1}{U}")); // Choose a creature on the battlefield. Any number of target creatures you control each become a copy of that creature until end of turn. - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, filter, false)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, false)); this.getSpellAbility().addEffect(new PolymorphousRushCopyEffect()); } diff --git a/Mage.Sets/src/mage/cards/p/PontiffOfBlight.java b/Mage.Sets/src/mage/cards/p/PontiffOfBlight.java index 19a3aa1248..d7f18675a4 100644 --- a/Mage.Sets/src/mage/cards/p/PontiffOfBlight.java +++ b/Mage.Sets/src/mage/cards/p/PontiffOfBlight.java @@ -28,7 +28,7 @@ public final class PontiffOfBlight extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Other creatures you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/p/PorphyryNodes.java b/Mage.Sets/src/mage/cards/p/PorphyryNodes.java index b8991680b0..c1321059a7 100644 --- a/Mage.Sets/src/mage/cards/p/PorphyryNodes.java +++ b/Mage.Sets/src/mage/cards/p/PorphyryNodes.java @@ -100,7 +100,7 @@ class PorphyryNodesEffect extends OneShotEffect { } } if (permanentToDestroy != null) { - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(" chosen creature: ").append(permanentToDestroy.getName()).toString()); + game.informPlayers(sourcePermanent.getName() + " chosen creature: " + permanentToDestroy.getName()); return permanentToDestroy.destroy(source.getSourceId(), game, true); } return true; @@ -132,7 +132,7 @@ class PorphyryNodesStateTriggeredAbility extends StateTriggeredAbility { @Override public String getRule() { - return new StringBuilder("When there are no creatures on the battlefield, ").append(super.getRule()).toString() ; + return "When there are no creatures on the battlefield, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/p/Portcullis.java b/Mage.Sets/src/mage/cards/p/Portcullis.java index c238942678..1cddb7e13e 100644 --- a/Mage.Sets/src/mage/cards/p/Portcullis.java +++ b/Mage.Sets/src/mage/cards/p/Portcullis.java @@ -2,24 +2,30 @@ package mage.cards.p; import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; import mage.abilities.TriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility; -import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.condition.Condition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.abilities.effects.common.ReturnToBattlefieldUnderOwnerControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SetTargetPointer; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.players.Player; +import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; /** @@ -28,20 +34,20 @@ import mage.util.CardUtil; */ public final class Portcullis extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature"); public Portcullis(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature. - String rule = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature"; - TriggeredAbility ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new PortcullisExileEffect(), filter, false, SetTargetPointer.PERMANENT, rule); - MoreThanXCreaturesOnBFCondition condition = new MoreThanXCreaturesOnBFCondition(2); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, rule)); - // Return that card to the battlefield under its owner's control when Portcullis leaves the battlefield. - Ability ability2 = new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD), false); - this.addAbility(ability2); + String rule = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature."; + String rule2 = " Return that card to the battlefield under its owner's control when {this} leaves the battlefield."; + TriggeredAbility ability = new EntersBattlefieldAllTriggeredAbility(Zone.BATTLEFIELD, new PortcullisExileEffect(), + filter, false, SetTargetPointer.PERMANENT, rule); + MoreThanXCreaturesOnBFCondition condition = new MoreThanXCreaturesOnBFCondition(2); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, condition, rule + rule2)); + } public Portcullis(final Portcullis card) { @@ -74,8 +80,8 @@ class MoreThanXCreaturesOnBFCondition implements Condition { class PortcullisExileEffect extends OneShotEffect { public PortcullisExileEffect() { - super(Outcome.Neutral); - this.staticText = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature."; + super(Outcome.Exile); + this.staticText = "Whenever a creature enters the battlefield, if there are two or more other creatures on the battlefield, exile that creature"; } public PortcullisExileEffect(final PortcullisExileEffect effect) { @@ -89,20 +95,58 @@ class PortcullisExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); - - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - permanent = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); + Permanent creatureToExile = game.getPermanent(getTargetPointer().getFirst(game, source)); + Permanent portcullis = game.getPermanent(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); + if (portcullis != null + && creatureToExile != null + && controller != null) { + UUID exileZoneId = CardUtil.getExileZoneId(game, creatureToExile.getId(), creatureToExile.getZoneChangeCounter(game)); + controller.moveCardsToExile(creatureToExile, source, game, true, exileZoneId, portcullis.getName()); + FixedTarget fixedTarget = new FixedTarget(portcullis, game); + Effect returnEffect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); + returnEffect.setTargetPointer(new FixedTarget(creatureToExile.getId(), game.getState().getZoneChangeCounter(creatureToExile.getId()))); + DelayedTriggeredAbility delayedAbility = new PortcullisReturnToBattlefieldTriggeredAbility(fixedTarget, returnEffect); + game.addDelayedTriggeredAbility(delayedAbility, source); } - if (permanent != null && creature != null) { - Player controller = game.getPlayer(creature.getControllerId()); - Zone currentZone = game.getState().getZone(creature.getId()); - if (currentZone == Zone.BATTLEFIELD) { - controller.moveCardsToExile(creature, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); - return true; - } + return true; + } +} + +class PortcullisReturnToBattlefieldTriggeredAbility extends DelayedTriggeredAbility { + + protected FixedTarget fixedTarget; + + public PortcullisReturnToBattlefieldTriggeredAbility(FixedTarget fixedTarget, Effect effect) { + super(effect, Duration.OneUse); + this.fixedTarget = fixedTarget; + } + + public PortcullisReturnToBattlefieldTriggeredAbility(final PortcullisReturnToBattlefieldTriggeredAbility ability) { + super(ability); + this.fixedTarget = ability.fixedTarget; + } + + @Override + public PortcullisReturnToBattlefieldTriggeredAbility copy() { + return new PortcullisReturnToBattlefieldTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (((ZoneChangeEvent) event).getFromZone().match(Zone.BATTLEFIELD)) { + return (fixedTarget.getTarget().equals(event.getTargetId())); } return false; } + + @Override + public String getRule() { + return "Return this card to the battlefield under its owner's control when Portcullis leaves the battlefield."; + } } diff --git a/Mage.Sets/src/mage/cards/p/PossessedPortal.java b/Mage.Sets/src/mage/cards/p/PossessedPortal.java index e20da683ba..c970a34258 100644 --- a/Mage.Sets/src/mage/cards/p/PossessedPortal.java +++ b/Mage.Sets/src/mage/cards/p/PossessedPortal.java @@ -101,7 +101,7 @@ class PossessedPortalEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player = game.getPlayer(playerId); Cost discardCost = new DiscardCardCost(); - if (discardCost.canPay(source, source.getSourceId(), playerId, game) + if (player != null && discardCost.canPay(source, source.getSourceId(), playerId, game) && player.chooseUse(Outcome.Discard, "Discard a card? (Otherwise sacrifice a permanent)", source, game)) { discardCost.pay(source, game, source.getSourceId(), playerId, true, null); } diff --git a/Mage.Sets/src/mage/cards/p/PostmortemLunge.java b/Mage.Sets/src/mage/cards/p/PostmortemLunge.java index 65a32494f1..75f35c769a 100644 --- a/Mage.Sets/src/mage/cards/p/PostmortemLunge.java +++ b/Mage.Sets/src/mage/cards/p/PostmortemLunge.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.effects.ContinuousEffect; @@ -21,8 +19,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * @author North */ @@ -34,6 +35,7 @@ public final class PostmortemLunge extends CardImpl { // Return target creature card with converted mana cost X from your graveyard to the battlefield. It gains haste. Exile it at the beginning of the next end step. this.getSpellAbility().addEffect(new PostmortemLungeEffect()); this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().setTargetAdjuster(PostmortemLungeAdjuster.instance); } public PostmortemLunge(final PostmortemLunge card) { @@ -44,16 +46,18 @@ public final class PostmortemLunge extends CardImpl { public PostmortemLunge copy() { return new PostmortemLunge(this); } +} + +enum PostmortemLungeAdjuster implements TargetAdjuster { + instance; @Override public void adjustTargets(Ability ability, Game game) { - if (ability.getAbilityType() == AbilityType.SPELL) { // otherwise the target is also added to the delayed triggered ability - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - ability.getTargets().add(new TargetCardInYourGraveyard(filter)); - } + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().add(new TargetCardInYourGraveyard(filter)); } } @@ -76,13 +80,11 @@ class PostmortemLungeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getFirstTarget()); - if (card != null) { Player cardOwner = game.getPlayer(card.getOwnerId()); if (cardOwner == null) { return false; } - if (cardOwner.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { @@ -96,7 +98,6 @@ class PostmortemLungeEffect extends OneShotEffect { } return true; } - return false; } } diff --git a/Mage.Sets/src/mage/cards/p/PouncingLynx.java b/Mage.Sets/src/mage/cards/p/PouncingLynx.java new file mode 100644 index 0000000000..aa0e629f74 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PouncingLynx.java @@ -0,0 +1,50 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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 PouncingLynx extends CardImpl { + + public PouncingLynx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // As long as it's your turn, Pouncing Lynx has first strike. + this.addAbility(new SimpleStaticAbility( + new ConditionalContinuousEffect( + new GainAbilitySourceEffect( + FirstStrikeAbility.getInstance(), + Duration.WhileOnBattlefield + ), MyTurnCondition.instance, + "As long as it's your turn, " + + "{this} has first strike." + ) + )); + } + + private PouncingLynx(final PouncingLynx card) { + super(card); + } + + @Override + public PouncingLynx copy() { + return new PouncingLynx(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PowerConduit.java b/Mage.Sets/src/mage/cards/p/PowerConduit.java index 4fde62b1c8..bdf4af27b0 100644 --- a/Mage.Sets/src/mage/cards/p/PowerConduit.java +++ b/Mage.Sets/src/mage/cards/p/PowerConduit.java @@ -31,8 +31,8 @@ public final class PowerConduit extends CardImpl { ability.addCost(new RemoveCounterCost(new TargetControlledPermanent())); ability.addTarget(new TargetArtifactPermanent()); Mode mode = new Mode(); - mode.getEffects().add(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/PowerSink.java b/Mage.Sets/src/mage/cards/p/PowerSink.java index a8e51d8e47..e8e74662ef 100644 --- a/Mage.Sets/src/mage/cards/p/PowerSink.java +++ b/Mage.Sets/src/mage/cards/p/PowerSink.java @@ -74,14 +74,14 @@ class PowerSinkCounterUnlessPaysEffect extends OneShotEffect { String sb = String.valueOf("Pay " + cost.getText()) + Character.toString('?'); if (player.chooseUse(Outcome.Benefit, sb, source, game)) { if (cost.pay(source, game, source.getSourceId(), player.getId(), false)) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": additional cost was paid").toString()); + game.informPlayers(sourceObject.getName() + ": additional cost was paid"); return true; } } // Counter target spell unless its controller pays {X} if (game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": additional cost wasn't paid - countering ").append(spell.getName()).toString()); + game.informPlayers(sourceObject.getName() + ": additional cost wasn't paid - countering " + spell.getName()); } // that player taps all lands with mana abilities he or she controls... diff --git a/Mage.Sets/src/mage/cards/p/PowerSurge.java b/Mage.Sets/src/mage/cards/p/PowerSurge.java index 186e7039ba..dd2ee01afd 100644 --- a/Mage.Sets/src/mage/cards/p/PowerSurge.java +++ b/Mage.Sets/src/mage/cards/p/PowerSurge.java @@ -64,10 +64,12 @@ class PowerSurgeDamageEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); if (player != null) { - PowerSurgeWatcher watcher = (PowerSurgeWatcher) game.getState().getWatchers().get(PowerSurgeWatcher.class.getSimpleName()); - int damage = watcher.getUntappedLandCount(); - player.damage(damage, source.getSourceId(), game, false, true); - return true; + PowerSurgeWatcher watcher = game.getState().getWatcher(PowerSurgeWatcher.class); + if(watcher != null) { + int damage = watcher.getUntappedLandCount(); + player.damage(damage, source.getSourceId(), game, false, true); + return true; + } } return false; } @@ -83,13 +85,13 @@ class PowerSurgeWatcher extends Watcher { private static final FilterPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } private int untappedLandCount; public PowerSurgeWatcher() { - super(PowerSurgeWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PowerSurgeWatcher(final PowerSurgeWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/p/PowerTaint.java b/Mage.Sets/src/mage/cards/p/PowerTaint.java new file mode 100644 index 0000000000..c985eabd11 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PowerTaint.java @@ -0,0 +1,61 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetEnchantmentPermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessTargetPlayerOrTargetsControllerPaysEffect; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; + +/** + * + * @author jeffwadsworth + */ +public final class PowerTaint extends CardImpl { + + public PowerTaint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant enchantment + TargetPermanent auraTarget = new TargetEnchantmentPermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of the upkeep of enchanted enchantment's controller, that player loses 2 life unless he or she pays {2}. + Effect effect = new DoUnlessTargetPlayerOrTargetsControllerPaysEffect(new LoseLifeTargetEffect(2), + new ManaCostsImpl("{2}"), "that player loses 2 life unless he or she pays {2}"); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, effect, + TargetController.CONTROLLER_ATTACHED_TO, false, true, + "At the beginning of the upkeep of enchanted enchantment's controller, ")); + + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + + } + + public PowerTaint(final PowerTaint card) { + super(card); + } + + @Override + public PowerTaint copy() { + return new PowerTaint(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PraetorsGrasp.java b/Mage.Sets/src/mage/cards/p/PraetorsGrasp.java index 832e284f34..9f20c8703d 100644 --- a/Mage.Sets/src/mage/cards/p/PraetorsGrasp.java +++ b/Mage.Sets/src/mage/cards/p/PraetorsGrasp.java @@ -68,7 +68,7 @@ class PraetorsGraspEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && opponent != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (controller.searchLibrary(target, game, opponent.getId())) { + if (controller.searchLibrary(target, source, game, opponent.getId())) { UUID targetId = target.getFirstTarget(); Card card = opponent.getLibrary().getCard(targetId, game); UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); diff --git a/Mage.Sets/src/mage/cards/p/Preacher.java b/Mage.Sets/src/mage/cards/p/Preacher.java index 75f4f6df82..c492c3bae2 100644 --- a/Mage.Sets/src/mage/cards/p/Preacher.java +++ b/Mage.Sets/src/mage/cards/p/Preacher.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -25,6 +24,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetOpponentsChoicePermanent; +import mage.target.targetpointer.FixedTarget; /** * @@ -33,7 +33,7 @@ import mage.target.common.TargetOpponentsChoicePermanent; public final class Preacher extends CardImpl { public Preacher(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(1); @@ -45,7 +45,6 @@ public final class Preacher extends CardImpl { // {tap}: Gain control of target creature of an opponent's choice that he or she controls for as long as Preacher remains tapped. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreacherEffect(), new TapSourceCost()); ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, new FilterControlledCreaturePermanent(), false, true)); - this.addAbility(ability); } @@ -60,7 +59,6 @@ public final class Preacher extends CardImpl { } } - class PreacherEffect extends OneShotEffect { public PreacherEffect() { @@ -79,25 +77,22 @@ class PreacherEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - - - if (controller != null && sourcePermanent != null - && controller.getId().equals(sourcePermanent.getControllerId())) { - UUID target = source.getFirstTarget(); - if (target != null && game.getPermanent(target) != null) { - Permanent targetPermanent = game.getPermanent(target); - - SourceHasRemainedInSameZoneCondition condition = new SourceHasRemainedInSameZoneCondition(sourcePermanent.getId()); - SourceHasRemainedInSameZoneCondition conditionTarget = new SourceHasRemainedInSameZoneCondition(target); - + if (controller != null + && sourcePermanent != null) { + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (targetPermanent != null) { + SourceTappedCondition sourceTappedCondition = SourceTappedCondition.instance; + SourceHasRemainedInSameZoneCondition conditionSourceSameZone = new SourceHasRemainedInSameZoneCondition(sourcePermanent.getId()); + SourceHasRemainedInSameZoneCondition conditionTargetSameZone = new SourceHasRemainedInSameZoneCondition(targetPermanent.getId()); ConditionalContinuousEffect effect = new ConditionalContinuousEffect( new GainControlTargetEffect(Duration.Custom), - new CompoundCondition(SourceTappedCondition.instance, new CompoundCondition (condition, conditionTarget)), + new CompoundCondition(sourceTappedCondition, new CompoundCondition(conditionSourceSameZone, conditionTargetSameZone)), "Gain control of target creature of an opponent's choice that he or she controls for as long as {this} remains tapped"); + effect.setTargetPointer(new FixedTarget(targetPermanent.getId())); game.addEffect(effect, source); + return true; } } return false; diff --git a/Mage.Sets/src/mage/cards/p/Precognition.java b/Mage.Sets/src/mage/cards/p/Precognition.java index 2efda6c498..34a82e70a7 100644 --- a/Mage.Sets/src/mage/cards/p/Precognition.java +++ b/Mage.Sets/src/mage/cards/p/Precognition.java @@ -68,8 +68,7 @@ class PrecognitionEffect extends OneShotEffect { if (controller != null && player != null) { Card card = player.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("Precognition", cards, game); if (controller.chooseUse(outcome, "Do you wish to put card on the bottom of player's library?", source, game)) { controller.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.LIBRARY, false, false); diff --git a/Mage.Sets/src/mage/cards/p/PrecognitionField.java b/Mage.Sets/src/mage/cards/p/PrecognitionField.java index 46ab2eac8f..80a9b352d4 100644 --- a/Mage.Sets/src/mage/cards/p/PrecognitionField.java +++ b/Mage.Sets/src/mage/cards/p/PrecognitionField.java @@ -1,4 +1,3 @@ - package mage.cards.p; import mage.MageObject; @@ -7,8 +6,8 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -27,14 +26,13 @@ public final class PrecognitionField extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); // You may look at the top card of your library. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrecognitionFieldTopCardRevealedEffect())); + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); // You may cast the top card of your library if it's an instant or sorcery card. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PrecognitionFieldTopCardCastEffect())); + this.addAbility(new SimpleStaticAbility(new PrecognitionFieldTopCardCastEffect())); // {3}: Exile the top card of your library. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new PrecognitionFieldExileEffect(), new GenericManaCost(3))); + this.addAbility(new SimpleActivatedAbility(new PrecognitionFieldExileEffect(), new GenericManaCost(3))); } public PrecognitionField(final PrecognitionField card) { @@ -47,38 +45,6 @@ public final class PrecognitionField extends CardImpl { } } -class PrecognitionFieldTopCardRevealedEffect extends ContinuousEffectImpl { - - public PrecognitionFieldTopCardRevealedEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "You may look at the top card of your library any time."; - } - - public PrecognitionFieldTopCardRevealedEffect(final PrecognitionFieldTopCardRevealedEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card topCard = controller.getLibrary().getFromTop(game); - if (topCard != null) { - MageObject precognitionField = source.getSourceObject(game); - if (precognitionField != null) { - controller.lookAtCards("Top card of " + precognitionField.getIdName() + " controller's library", topCard, game); - } - } - } - return true; - } - - @Override - public PrecognitionFieldTopCardRevealedEffect copy() { - return new PrecognitionFieldTopCardRevealedEffect(this); - } -} - class PrecognitionFieldTopCardCastEffect extends AsThoughEffectImpl { public PrecognitionFieldTopCardCastEffect() { diff --git a/Mage.Sets/src/mage/cards/p/PrecognitivePerception.java b/Mage.Sets/src/mage/cards/p/PrecognitivePerception.java new file mode 100644 index 0000000000..32f2d03551 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrecognitivePerception.java @@ -0,0 +1,68 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrecognitivePerception extends CardImpl { + + public PrecognitivePerception(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{U}{U}"); + + // Draw three cards. + // Addendum — If you cast this spell during your main phase, instead scry 3, then draw three cards. + this.getSpellAbility().addEffect(new PrecognitivePerceptionEffect()); + } + + private PrecognitivePerception(final PrecognitivePerception card) { + super(card); + } + + @Override + public PrecognitivePerception copy() { + return new PrecognitivePerception(this); + } +} + +class PrecognitivePerceptionEffect extends OneShotEffect { + + PrecognitivePerceptionEffect() { + super(Outcome.Benefit); + staticText = "Draw three cards.
    Addendum — " + + "If you cast this spell during your main phase, " + + "instead scry 3, then draw three cards."; + } + + private PrecognitivePerceptionEffect(final PrecognitivePerceptionEffect effect) { + super(effect); + } + + @Override + public PrecognitivePerceptionEffect copy() { + return new PrecognitivePerceptionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + if (AddendumCondition.instance.apply(game, source)) { + controller.scry(3, source, game); + } + controller.drawCards(3, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PredatoryAdvantage.java b/Mage.Sets/src/mage/cards/p/PredatoryAdvantage.java index fe202bc1e0..8b7bba0c13 100644 --- a/Mage.Sets/src/mage/cards/p/PredatoryAdvantage.java +++ b/Mage.Sets/src/mage/cards/p/PredatoryAdvantage.java @@ -48,7 +48,7 @@ class DidNotCastCreatureCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent p = game.getPermanent(source.getSourceId()); if (p != null) { - Watcher watcher = game.getState().getWatchers().get(CastCreatureWatcher.class.getSimpleName(), source.getSourceId()); + Watcher watcher = game.getState().getWatcher(CastCreatureWatcher.class, source.getSourceId()); if (watcher != null && !watcher.conditionMet()) { return true; } @@ -58,15 +58,14 @@ class DidNotCastCreatureCondition implements Condition { @Override public String toString() { - StringBuilder sb = new StringBuilder("if that player didn't cast a creature spell this turn"); - return sb.toString(); + return "if that player didn't cast a creature spell this turn"; } } class CastCreatureWatcher extends Watcher { public CastCreatureWatcher() { - super(CastCreatureWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } public CastCreatureWatcher(final CastCreatureWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/p/PredatoryFocus.java b/Mage.Sets/src/mage/cards/p/PredatoryFocus.java index 807f524959..46311e34e0 100644 --- a/Mage.Sets/src/mage/cards/p/PredatoryFocus.java +++ b/Mage.Sets/src/mage/cards/p/PredatoryFocus.java @@ -1,12 +1,8 @@ package mage.cards.p; import java.util.UUID; - -import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.effects.AsThoughEffect; import mage.abilities.effects.AsThoughEffectImpl; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AsThoughEffectType; @@ -24,7 +20,6 @@ public final class PredatoryFocus extends CardImpl { public PredatoryFocus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); - // You may have creatures you control assign their combat damage this turn as though they weren't blocked. this.getSpellAbility().addEffect(new PredatoryFocusEffect()); @@ -58,10 +53,10 @@ class PredatoryFocusEffect extends AsThoughEffectImpl { super.init(source, game); Player controller = game.getPlayer(source.getControllerId()); String sourceName = source.getSourceObject(game).getLogName(); - choseUse = controller.chooseUse(Outcome.Damage, "Have creatures you control deal combat damage this turn" + - " as though they weren't blocked?", source, game); - game.informPlayers(choseUse ? controller.getName()+" chose to use "+sourceName+"'s effect" : - controller.getName()+" chose not to use "+sourceName+"'s effect."); + choseUse = controller.chooseUse(Outcome.Damage, "Have creatures you control deal combat damage this turn" + + " as though they weren't blocked?", source, game); + game.informPlayers(choseUse ? controller.getName() + " chose to use " + sourceName + "'s effect" + : controller.getName() + " chose not to use " + sourceName + "'s effect."); } @Override @@ -78,4 +73,4 @@ class PredatoryFocusEffect extends AsThoughEffectImpl { public PredatoryFocusEffect copy() { return new PredatoryFocusEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/p/Predict.java b/Mage.Sets/src/mage/cards/p/Predict.java index 193ae9b8c0..c2ae143a7a 100644 --- a/Mage.Sets/src/mage/cards/p/Predict.java +++ b/Mage.Sets/src/mage/cards/p/Predict.java @@ -1,6 +1,5 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; @@ -13,9 +12,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Quercitron */ public final class Predict extends CardImpl { @@ -66,7 +67,7 @@ class PredictEffect extends OneShotEffect { Card card = targetPlayer.getLibrary().getFromTop(game); if (card != null) { controller.moveCards(card, Zone.GRAVEYARD, source, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { amount = 2; } } diff --git a/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java b/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java index 552d957cb2..9207889fda 100644 --- a/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java +++ b/Mage.Sets/src/mage/cards/p/PreeminentCaptain.java @@ -71,7 +71,7 @@ class PreeminentCaptainEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); TargetCardInHand target = new TargetCardInHand(filter); - if (target.canChoose(controller.getId(), game) + if (controller != null && target.canChoose(controller.getId(), game) && target.choose(getOutcome(), controller.getId(), source.getSourceId(), game)) { if (!target.getTargets().isEmpty()) { UUID cardId = target.getFirstTarget(); diff --git a/Mage.Sets/src/mage/cards/p/PrematureBurial.java b/Mage.Sets/src/mage/cards/p/PrematureBurial.java index 9f35bb5888..a4542bed63 100644 --- a/Mage.Sets/src/mage/cards/p/PrematureBurial.java +++ b/Mage.Sets/src/mage/cards/p/PrematureBurial.java @@ -66,7 +66,7 @@ class ETBSinceYourLastTurnTarget extends TargetCreaturePermanent { @Override public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { System.out.println("canTarget called"); - ETBSinceYourLastTurnWatcher watcher = (ETBSinceYourLastTurnWatcher) game.getState().getWatchers().get(ETBSinceYourLastTurnWatcher.class.getSimpleName()); + ETBSinceYourLastTurnWatcher watcher = game.getState().getWatcher(ETBSinceYourLastTurnWatcher.class); if (watcher != null){ if (watcher.enteredSinceLastTurn(controllerId, new MageObjectReference(id, game))){ System.out.println(game.getPermanent(id).getIdName()+" entered since the last turn."); @@ -79,11 +79,13 @@ class ETBSinceYourLastTurnTarget extends TargetCreaturePermanent { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { MageObject targetSource = game.getObject(sourceId); - ETBSinceYourLastTurnWatcher watcher = (ETBSinceYourLastTurnWatcher) game.getState().getWatchers().get(ETBSinceYourLastTurnWatcher.class.getSimpleName()); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if(watcher.enteredSinceLastTurn(sourceControllerId, new MageObjectReference(permanent.getId(), game))) { - return true; + ETBSinceYourLastTurnWatcher watcher = game.getState().getWatcher(ETBSinceYourLastTurnWatcher.class); + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (watcher != null && watcher.enteredSinceLastTurn(sourceControllerId, new MageObjectReference(permanent.getId(), game))) { + return true; + } } } } @@ -101,7 +103,7 @@ class ETBSinceYourLastTurnWatcher extends Watcher { private final Map> playerToETBMap; public ETBSinceYourLastTurnWatcher() { - super(ETBSinceYourLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.playerToETBMap = new HashMap<>(); } diff --git a/Mage.Sets/src/mage/cards/p/PrepareFight.java b/Mage.Sets/src/mage/cards/p/PrepareFight.java index daa30221ac..366411f7ab 100644 --- a/Mage.Sets/src/mage/cards/p/PrepareFight.java +++ b/Mage.Sets/src/mage/cards/p/PrepareFight.java @@ -49,7 +49,7 @@ public final class PrepareFight extends SplitCard { // to // Fight // Target creature you control fights target creature you don't control. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new FightTargetsEffect()); getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); Target target = new TargetCreaturePermanent(filter); diff --git a/Mage.Sets/src/mage/cards/p/PrescientChimera.java b/Mage.Sets/src/mage/cards/p/PrescientChimera.java index 124a222a48..ad0c59673f 100644 --- a/Mage.Sets/src/mage/cards/p/PrescientChimera.java +++ b/Mage.Sets/src/mage/cards/p/PrescientChimera.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.keyword.ScryEffect; @@ -12,14 +10,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.filter.StaticFilters; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PrescientChimera extends CardImpl { public PrescientChimera(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.CHIMERA); this.power = new MageInt(3); @@ -28,7 +27,7 @@ public final class PrescientChimera extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever you cast an instant or sorcery spell, scry 1. - this.addAbility(new SpellCastControllerTriggeredAbility(new ScryEffect(1), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false)); + this.addAbility(new SpellCastControllerTriggeredAbility(new ScryEffect(1), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false)); } public PrescientChimera(final PrescientChimera card) { diff --git a/Mage.Sets/src/mage/cards/p/PresenceOfTheWise.java b/Mage.Sets/src/mage/cards/p/PresenceOfTheWise.java index 0129a82eb5..7c7037e939 100644 --- a/Mage.Sets/src/mage/cards/p/PresenceOfTheWise.java +++ b/Mage.Sets/src/mage/cards/p/PresenceOfTheWise.java @@ -20,7 +20,7 @@ public final class PresenceOfTheWise extends CardImpl { // You gain 2 life for each card in your hand. this.getSpellAbility().addEffect(new GainLifeEffect( - new MultipliedValue(new CardsInControllerHandCount(), 2),"You gain 2 life for each card in your hand")); + new MultipliedValue(CardsInControllerHandCount.instance, 2),"You gain 2 life for each card in your hand")); } public PresenceOfTheWise(final PresenceOfTheWise card) { diff --git a/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java b/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java new file mode 100644 index 0000000000..25b2ce6cc7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PriceOfBetrayal.java @@ -0,0 +1,132 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterOpponent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterPermanentOrPlayer; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetPermanentOrPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PriceOfBetrayal extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + private static final FilterPermanentOrPlayer filter2 = new FilterPermanentOrPlayer("artifact, creature, planeswalker, or opponent", filter, new FilterOpponent()); + + public PriceOfBetrayal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // Remove up to five counters from target artifact, creature, planeswalker, or opponent. + this.getSpellAbility().addEffect(new PriceOfBetrayalEffect()); + this.getSpellAbility().addTarget(new TargetPermanentOrPlayer(1, 1, filter2, false)); + } + + private PriceOfBetrayal(final PriceOfBetrayal card) { + super(card); + } + + @Override + public PriceOfBetrayal copy() { + return new PriceOfBetrayal(this); + } +} + +class PriceOfBetrayalEffect extends OneShotEffect { + + PriceOfBetrayalEffect() { + super(Outcome.Benefit); + staticText = "Remove up to five counters from target artifact, creature, planeswalker, or opponent."; + } + + private PriceOfBetrayalEffect(final PriceOfBetrayalEffect effect) { + super(effect); + } + + @Override + public PriceOfBetrayalEffect copy() { + return new PriceOfBetrayalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + int toRemove = 5; + int removed = 0; + String[] counterNames = permanent.getCounters(game).keySet().toArray(new String[0]); + for (String counterName : counterNames) { + if (controller.chooseUse(Outcome.Neutral, "Do you want to remove " + counterName + " counters?", source, game)) { + if (permanent.getCounters(game).get(counterName).getCount() == 1 || toRemove == 1) { + permanent.removeCounters(counterName, 1, game); + removed++; + } else { + int amount = controller.getAmount(1, Math.min(permanent.getCounters(game).get(counterName).getCount(), toRemove - removed), "How many?", game); + if (amount > 0) { + removed += amount; + permanent.removeCounters(counterName, amount, game); + } + } + } + if (removed >= toRemove) { + break; + } + } + game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source); + return true; + } + Player player = game.getPlayer(source.getFirstTarget()); + if (player != null) { + int toRemove = 5; + int removed = 0; + String[] counterNames = player.getCounters().keySet().toArray(new String[0]); + for (String counterName : counterNames) { + if (controller.chooseUse(Outcome.Neutral, "Do you want to remove " + counterName + " counters?", source, game)) { + if (player.getCounters().get(counterName).getCount() == 1 || toRemove == 1) { + player.removeCounters(counterName, 1, source, game); + removed++; + } else { + int amount = controller.getAmount(1, Math.min(player.getCounters().get(counterName).getCount(), toRemove - removed), "How many?", game); + if (amount > 0) { + removed += amount; + player.removeCounters(counterName, amount, source, game); + } + } + } + if (removed >= toRemove) { + break; + } + } + game.addEffect(new BoostSourceEffect(removed, 0, Duration.EndOfTurn), source); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PriceOfFame.java b/Mage.Sets/src/mage/cards/p/PriceOfFame.java index 79f7737b9e..0aefe57301 100644 --- a/Mage.Sets/src/mage/cards/p/PriceOfFame.java +++ b/Mage.Sets/src/mage/cards/p/PriceOfFame.java @@ -1,36 +1,44 @@ package mage.cards.p; -import java.util.Iterator; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; import mage.abilities.effects.keyword.SurveilEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SuperType; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.StackObject; -import mage.target.Target; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class PriceOfFame extends CardImpl { + private static final FilterPermanent filter + = new FilterCreaturePermanent("a legendary creature"); + + static { + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter); + public PriceOfFame(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{B}"); // This spell costs {2} less to cast if it targets a legendary creature. - this.addAbility(new SimpleStaticAbility(Zone.STACK, - new SpellCostReductionSourceEffect(2, PriceOfFameCondition.instance)) - .setRuleAtTheTop(true)); + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(2, condition) + ).setRuleAtTheTop(true)); // Destroy target creature. this.getSpellAbility().addEffect(new DestroyTargetEffect()); @@ -49,28 +57,3 @@ public final class PriceOfFame extends CardImpl { return new PriceOfFame(this); } } - -enum PriceOfFameCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); - if (sourceSpell != null) { - Iterator targets = sourceSpell.getStackAbility().getTargets().iterator(); - while (targets.hasNext()) { - Permanent permanent = game.getPermanentOrLKIBattlefield(targets.next().getFirstTarget()); - if (permanent != null && permanent.isCreature() && permanent.isLegendary()) { - return true; - } - } - } - return false; - } - - @Override - public String toString() { - return "it targets a legendary creature"; - } - -} diff --git a/Mage.Sets/src/mage/cards/p/PrideOfConquerors.java b/Mage.Sets/src/mage/cards/p/PrideOfConquerors.java index ae0e67a2e4..00b7eefb38 100644 --- a/Mage.Sets/src/mage/cards/p/PrideOfConquerors.java +++ b/Mage.Sets/src/mage/cards/p/PrideOfConquerors.java @@ -1,18 +1,18 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; import mage.abilities.effects.keyword.AscendEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class PrideOfConquerors extends CardImpl { @@ -27,6 +27,7 @@ public final class PrideOfConquerors extends CardImpl { this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new BoostControlledEffect(2, 2, Duration.EndOfTurn), new BoostControlledEffect(1, 1, Duration.EndOfTurn), CitysBlessingCondition.instance, "Creatures you control get +1/+1 until end of turn. If you have the city's blessing, those creatures get +2/+2 until end of turn instead")); + this.getSpellAbility().addHint(CitysBlessingHint.instance); } public PrideOfConquerors(final PrideOfConquerors card) { diff --git a/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java b/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java index ab9ce5f0c4..9ac6fc59b9 100644 --- a/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java +++ b/Mage.Sets/src/mage/cards/p/PrideOfTheClouds.java @@ -31,7 +31,7 @@ public final class PrideOfTheClouds extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature with flying on the battlefield"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new AbilityPredicate(FlyingAbility.class)); } diff --git a/Mage.Sets/src/mage/cards/p/PrideSovereign.java b/Mage.Sets/src/mage/cards/p/PrideSovereign.java index 42f476571a..929c2d2b73 100644 --- a/Mage.Sets/src/mage/cards/p/PrideSovereign.java +++ b/Mage.Sets/src/mage/cards/p/PrideSovereign.java @@ -38,7 +38,7 @@ public final class PrideSovereign extends CardImpl { // Pride Sovereign gets +1/+1 for each other Cat you control. FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.CAT, "other Cat you control"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); DynamicValue otherCats = new PermanentsOnBattlefieldCount(filter); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(otherCats, otherCats, Duration.WhileOnBattlefield))); // {W}, {t}, Exert Pride Sovereign: Create two 1/1 white Cat creature tokens with lifelink. diff --git a/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java b/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java new file mode 100644 index 0000000000..c24a3c6dde --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PriestOfForgottenGods.java @@ -0,0 +1,71 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.Mana; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.mana.BasicManaEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPlayer; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.LoseLifeTargetEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledPermanent; + +/** + * @author TheElk801 + */ +public final class PriestOfForgottenGods extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledCreaturePermanent("other creatures"); + + static { + filter.add(AnotherPredicate.instance); + } + + public PriestOfForgottenGods(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {T}, Sacrifice two other creatures: Any number of target players each lose 2 life and sacrifice a creature. You add {B}{B} and draw a card. + Ability ability = new SimpleActivatedAbility( + new LoseLifeTargetEffect(2) + .setText("Any number of target players each lose 2 life"), + new TapSourceCost() + ); + ability.addEffect( + new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "") + .setText("and sacrifice a creature") + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(2, 2, filter, true))); + ability.addEffect(new BasicManaEffect(Mana.BlackMana(2)).setText("You add {B}{B}")); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("and draw a card")); + ability.addTarget(new TargetPlayer(0, Integer.MAX_VALUE, false)); + this.addAbility(ability); + } + + private PriestOfForgottenGods(final PriestOfForgottenGods card) { + super(card); + } + + @Override + public PriestOfForgottenGods copy() { + return new PriestOfForgottenGods(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java b/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java index 17fc88ca5b..c13b1000e7 100644 --- a/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java +++ b/Mage.Sets/src/mage/cards/p/PriestOfTheWakeningSun.java @@ -100,8 +100,7 @@ class PriestOfTheWakeningSunEffect extends OneShotEffect { if (controller.chooseUse(outcome, "Reveal a Dinosaur card?", source, game)) { TargetCardInHand target = new TargetCardInHand(0, 1, filter); if (controller.chooseTarget(outcome, target, source, game) && !target.getTargets().isEmpty()) { - Cards cards = new CardsImpl(); - cards.addAll(target.getTargets()); + Cards cards = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), cards, game); controller.gainLife(2, game, source); return true; diff --git a/Mage.Sets/src/mage/cards/p/PrimalCommand.java b/Mage.Sets/src/mage/cards/p/PrimalCommand.java index 970dae2cdf..d20b5bf91c 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalCommand.java +++ b/Mage.Sets/src/mage/cards/p/PrimalCommand.java @@ -48,18 +48,18 @@ public final class PrimalCommand extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); // or put target noncreature permanent on top of its owner's library; Mode mode = new Mode(); - mode.getEffects().add(new PutOnLibraryTargetEffect(true)); + mode.addEffect(new PutOnLibraryTargetEffect(true)); Target target = new TargetPermanent(filterNonCreature); - mode.getTargets().add(target); + mode.addTarget(target); this.getSpellAbility().getModes().addMode(mode); // or target player shuffles their graveyard into their library; mode = new Mode(); - mode.getEffects().add(new PrimalCommandShuffleGraveyardEffect()); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new PrimalCommandShuffleGraveyardEffect()); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().getModes().addMode(mode); // or search your library for a creature card, reveal it, put it into your hand, then shuffle your library. mode = new Mode(); - mode.getEffects().add(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterCreatureCard()), true, true)); + mode.addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterCreatureCard()), true, true)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PrimalForcemage.java b/Mage.Sets/src/mage/cards/p/PrimalForcemage.java index 2a17cceae8..954fd329c8 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalForcemage.java +++ b/Mage.Sets/src/mage/cards/p/PrimalForcemage.java @@ -23,11 +23,11 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class PrimalForcemage extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Whenever another creature enters the battlefield under your control, that creature gets +3/+3 until end of turn."; diff --git a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java index 892fbbc636..4c9667d9e0 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalWellspring.java +++ b/Mage.Sets/src/mage/cards/p/PrimalWellspring.java @@ -50,7 +50,7 @@ public final class PrimalWellspring extends CardImpl { class PyrimalWellspringTriggeredAbility extends TriggeredAbilityImpl { - private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); String abilityOriginalId; diff --git a/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java b/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java index 3ea6fbad59..61901b4b91 100644 --- a/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java +++ b/Mage.Sets/src/mage/cards/p/PrimalWhisperer.java @@ -26,7 +26,7 @@ public final class PrimalWhisperer extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face-down creature"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public PrimalWhisperer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PrimeSpeakerVannifar.java b/Mage.Sets/src/mage/cards/p/PrimeSpeakerVannifar.java new file mode 100644 index 0000000000..e0c0313c7e --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrimeSpeakerVannifar.java @@ -0,0 +1,107 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 and Loki + */ +public final class PrimeSpeakerVannifar extends CardImpl { + + public PrimeSpeakerVannifar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.OOZE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // {T}, Sacrifice another creature: Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, new PrimeSpeakerVannifarEffect(), new TapSourceCost() + ); + ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent( + StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE + ))); + this.addAbility(ability); + } + + private PrimeSpeakerVannifar(final PrimeSpeakerVannifar card) { + super(card); + } + + @Override + public PrimeSpeakerVannifar copy() { + return new PrimeSpeakerVannifar(this); + } +} + +class PrimeSpeakerVannifarEffect extends OneShotEffect { + + PrimeSpeakerVannifarEffect() { + super(Outcome.Benefit); + staticText = "Search your library for a creature card with converted mana cost equal to 1 " + + "plus the sacrificed creature's converted mana cost, put that card " + + "onto the battlefield, then shuffle your library"; + } + + private PrimeSpeakerVannifarEffect(final PrimeSpeakerVannifarEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sacrificedPermanent = null; + for (Cost cost : source.getCosts()) { + if (cost instanceof SacrificeTargetCost) { + SacrificeTargetCost sacrificeCost = (SacrificeTargetCost) cost; + if (!sacrificeCost.getPermanents().isEmpty()) { + sacrificedPermanent = sacrificeCost.getPermanents().get(0); + } + break; + } + } + Player controller = game.getPlayer(source.getControllerId()); + if (sacrificedPermanent == null || controller == null) { + return false; + } + int newConvertedCost = sacrificedPermanent.getConvertedManaCost() + 1; + FilterCard filter = new FilterCard("creature card with converted mana cost " + newConvertedCost); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, newConvertedCost)); + filter.add(new CardTypePredicate(CardType.CREATURE)); + TargetCardInLibrary target = new TargetCardInLibrary(filter); + if (controller.searchLibrary(target, source, game)) { + Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } + controller.shuffleLibrary(source, game); + return true; + } + + @Override + public PrimeSpeakerVannifarEffect copy() { + return new PrimeSpeakerVannifarEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrimevalProtector.java b/Mage.Sets/src/mage/cards/p/PrimevalProtector.java index c68fabb66a..7a09b0723b 100644 --- a/Mage.Sets/src/mage/cards/p/PrimevalProtector.java +++ b/Mage.Sets/src/mage/cards/p/PrimevalProtector.java @@ -36,7 +36,7 @@ public final class PrimevalProtector extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public PrimevalProtector(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PrimordialMist.java b/Mage.Sets/src/mage/cards/p/PrimordialMist.java index 364db608db..891466a29b 100644 --- a/Mage.Sets/src/mage/cards/p/PrimordialMist.java +++ b/Mage.Sets/src/mage/cards/p/PrimordialMist.java @@ -35,7 +35,7 @@ public final class PrimordialMist extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("face down permanent"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public PrimordialMist(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PrincessLeia.java b/Mage.Sets/src/mage/cards/p/PrincessLeia.java index 3a47d9e3ea..9bcae9ff49 100644 --- a/Mage.Sets/src/mage/cards/p/PrincessLeia.java +++ b/Mage.Sets/src/mage/cards/p/PrincessLeia.java @@ -30,7 +30,7 @@ public final class PrincessLeia extends CardImpl { static { SubtypePredicate rebel = new SubtypePredicate(SubType.REBEL); - filter1.add(new AnotherPredicate()); + filter1.add(AnotherPredicate.instance); filter1.add(rebel); filter2.add(rebel); } diff --git a/Mage.Sets/src/mage/cards/p/PrismaticBoon.java b/Mage.Sets/src/mage/cards/p/PrismaticBoon.java new file mode 100644 index 0000000000..115a13cad3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrismaticBoon.java @@ -0,0 +1,75 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ProtectionAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.XTargetsAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrismaticBoon extends CardImpl { + + public PrismaticBoon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{U}"); + + // Choose a color. X target creatures gain protection from the chosen color until end of turn. + this.getSpellAbility().addEffect(new PrismaticBoonEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(XTargetsAdjuster.instance); + } + + private PrismaticBoon(final PrismaticBoon card) { + super(card); + } + + @Override + public PrismaticBoon copy() { + return new PrismaticBoon(this); + } +} + +class PrismaticBoonEffect extends OneShotEffect { + + PrismaticBoonEffect() { + super(Outcome.Benefit); + staticText = "Choose a color. X target creatures gain protection from the chosen color until end of turn."; + } + + private PrismaticBoonEffect(final PrismaticBoonEffect effect) { + super(effect); + } + + @Override + public PrismaticBoonEffect copy() { + return new PrismaticBoonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + ChoiceColor choice = new ChoiceColor(); + if (!player.choose(outcome, choice, game)) { + return false; + } + game.addEffect(new GainAbilityTargetEffect( + ProtectionAbility.from(choice.getColor()), Duration.EndOfTurn + ), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrismaticOmen.java b/Mage.Sets/src/mage/cards/p/PrismaticOmen.java index 88898aa75e..9403d698bd 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticOmen.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticOmen.java @@ -1,4 +1,3 @@ - package mage.cards.p; import mage.Mana; @@ -18,13 +17,12 @@ import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public final class PrismaticOmen extends CardImpl { public PrismaticOmen(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); // Lands you control are every basic land type in addition to their other types. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BecomesBasicLandTypeAllEffect("Swamp", "Mountain", "Forest", "Island", "Plains"))); @@ -46,7 +44,7 @@ class BecomesBasicLandTypeAllEffect extends ContinuousEffectImpl { public BecomesBasicLandTypeAllEffect(String... landNames) { super(Duration.WhileOnBattlefield, Outcome.Detriment); - landTypes.addAll(SubType.getBasicLands(false)); + landTypes.addAll(SubType.getBasicLands()); this.staticText = "Lands you control are every basic land type in addition to their other types"; } diff --git a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java index e5fb668061..06a50fb4d2 100644 --- a/Mage.Sets/src/mage/cards/p/PrismaticStrands.java +++ b/Mage.Sets/src/mage/cards/p/PrismaticStrands.java @@ -34,7 +34,7 @@ public final class PrismaticStrands extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ColorPredicate(ObjectColor.WHITE)); } diff --git a/Mage.Sets/src/mage/cards/p/Prismite.java b/Mage.Sets/src/mage/cards/p/Prismite.java new file mode 100644 index 0000000000..1f1794c28c --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Prismite.java @@ -0,0 +1,37 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.mana.AnyColorManaAbility; +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 Prismite extends CardImpl { + + public Prismite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}"); + + this.subtype.add(SubType.GOLEM); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {2}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility(new GenericManaCost(2))); + } + + private Prismite(final Prismite card) { + super(card); + } + + @Override + public Prismite copy() { + return new Prismite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrisonRealm.java b/Mage.Sets/src/mage/cards/p/PrisonRealm.java new file mode 100644 index 0000000000..e22f4296d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrisonRealm.java @@ -0,0 +1,55 @@ +package mage.cards.p; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.delayed.OnLeaveReturnExiledToBattlefieldAbility; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.ExileUntilSourceLeavesEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PrisonRealm extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker an opponent controls"); + + static { + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public PrisonRealm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); + + // When Prison Realm enters the battlefield, exile target creature or planeswalker an opponent controls until Prison Realm leaves the battlefield. + Ability ability = new EntersBattlefieldTriggeredAbility( + new ExileUntilSourceLeavesEffect(filter.getMessage()) + ); + ability.addTarget(new TargetPermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + this.addAbility(ability); + + // When Prison Realm enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + } + + private PrisonRealm(final PrisonRealm card) { + super(card); + } + + @Override + public PrisonRealm copy() { + return new PrisonRealm(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrivateResearch.java b/Mage.Sets/src/mage/cards/p/PrivateResearch.java new file mode 100644 index 0000000000..bef10ca1c2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PrivateResearch.java @@ -0,0 +1,60 @@ +package mage.cards.p; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; + +/** + * + * @author jeffwadsworth + */ +public final class PrivateResearch extends CardImpl { + + private static final String rule = "draw a card for each page counter on {this}."; + + public PrivateResearch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of your upkeep, you may put a page counter on Private Research. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.PAGE.createInstance(), true), TargetController.YOU, true)); + + // When enchanted creature dies, draw a card for each page counter on Private Research. + this.addAbility(new DiesAttachedTriggeredAbility(new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.PAGE)).setText(rule), "enchanted creature")); + + } + + public PrivateResearch(final PrivateResearch card) { + super(card); + } + + @Override + public PrivateResearch copy() { + return new PrivateResearch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PrivilegedPosition.java b/Mage.Sets/src/mage/cards/p/PrivilegedPosition.java index 98315cd3fc..9ef623711a 100644 --- a/Mage.Sets/src/mage/cards/p/PrivilegedPosition.java +++ b/Mage.Sets/src/mage/cards/p/PrivilegedPosition.java @@ -10,7 +10,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Zone; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; /** * @@ -23,7 +23,7 @@ public final class PrivilegedPosition extends CardImpl { // Other permanents you control have hexproof. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, new FilterPermanent(), true))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(HexproofAbility.getInstance(), Duration.WhileOnBattlefield, StaticFilters.FILTER_PERMANENTS, true))); } public PrivilegedPosition(final PrivilegedPosition card) { diff --git a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java index 77d939f26f..e8c4babc36 100644 --- a/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java +++ b/Mage.Sets/src/mage/cards/p/PrizedAmalgam.java @@ -89,7 +89,7 @@ class PrizedAmalgamTriggerdAbility extends EntersBattlefieldAllTriggeredAbility if (entersEvent.getFromZone() == Zone.GRAVEYARD) { result = true; } else if (entersEvent.getFromZone() == Zone.STACK && entersEvent.getTarget().isControlledBy(getControllerId())) { - CastFromGraveyardWatcher watcher = (CastFromGraveyardWatcher) game.getState().getWatchers().get(CastFromGraveyardWatcher.class.getSimpleName()); + CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); if (watcher != null) { int zcc = game.getState().getZoneChangeCounter(event.getSourceId()); result = watcher.spellWasCastFromGraveyard(event.getSourceId(), zcc - 1); diff --git a/Mage.Sets/src/mage/cards/p/Probe.java b/Mage.Sets/src/mage/cards/p/Probe.java index e8e4e7a689..6c98d48e93 100644 --- a/Mage.Sets/src/mage/cards/p/Probe.java +++ b/Mage.Sets/src/mage/cards/p/Probe.java @@ -1,9 +1,7 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect; @@ -14,9 +12,11 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.Game; import mage.target.TargetPlayer; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class Probe extends CardImpl { @@ -33,16 +33,7 @@ public final class Probe extends CardImpl { new DiscardTargetEffect(2), KickedCondition.instance, "

    if this spell was kicked, target player discards two cards")); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetPlayer()); - } - } + this.getSpellAbility().setTargetAdjuster(ProbeAdjuster.instance); } public Probe(final Probe card) { @@ -54,3 +45,15 @@ public final class Probe extends CardImpl { return new Probe(this); } } + +enum ProbeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetPlayer()); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java index 8a7f5767ed..9e9b5172f9 100644 --- a/Mage.Sets/src/mage/cards/p/ProfaneCommand.java +++ b/Mage.Sets/src/mage/cards/p/ProfaneCommand.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; @@ -26,6 +25,9 @@ import mage.game.Game; import mage.target.TargetPlayer; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** * @author LevelX2 @@ -36,7 +38,7 @@ public final class ProfaneCommand extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; // Choose two - this.getSpellAbility().getModes().setMinModes(2); this.getSpellAbility().getModes().setMaxModes(2); @@ -46,45 +48,26 @@ public final class ProfaneCommand extends CardImpl { // * Return target creature card with converted mana cost X or less from your graveyard to the battlefield. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard"))); + mode.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard"))); this.getSpellAbility().addMode(mode); // * Target creature gets -X/-X until end of turn. DynamicValue minusValue = new SignInversionDynamicValue(xValue); mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(minusValue, minusValue, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(minusValue, minusValue, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // * Up to X target creatures gain fear until end of turn. mode = new Mode(); Effect effect = new GainAbilityTargetEffect(FearAbility.getInstance(), Duration.EndOfTurn); effect.setText("Up to X target creatures gain fear until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(0, 1)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(0, 1)); this.getSpellAbility().addMode(mode); - } - @Override - public void adjustTargets(Ability ability, Game game) { - // adjust targets is called for every selected mode - Mode mode = ability.getModes().getMode(); - for (Effect effect : mode.getEffects()) { - if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) { - mode.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - mode.getTargets().add(new TargetCardInYourGraveyard(filter)); - } - if (effect instanceof GainAbilityTargetEffect) { - mode.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures gain fear until end of turn"); - mode.getTargets().add(new TargetCreaturePermanent(0, xValue, filter, false)); - } - } + this.getSpellAbility().setTargetAdjuster(ProfaneCommandAdjuster.instance); } public ProfaneCommand(final ProfaneCommand card) { @@ -96,3 +79,27 @@ public final class ProfaneCommand extends CardImpl { return new ProfaneCommand(this); } } + +enum ProfaneCommandAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + // adjust targets is called for every selected mode + Mode mode = ability.getModes().getMode(); + int xValue = ability.getManaCostsToPay().getX(); + for (Effect effect : mode.getEffects()) { + if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) { + mode.getTargets().clear(); + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + mode.addTarget(new TargetCardInYourGraveyard(filter)); + } + if (effect instanceof GainAbilityTargetEffect) { + mode.getTargets().clear(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures gain fear until end of turn"); + mode.addTarget(new TargetCreaturePermanent(0, xValue, filter, false)); + } + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java b/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java index 156ae583dc..2de51e27b9 100644 --- a/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java +++ b/Mage.Sets/src/mage/cards/p/ProgenitorMimic.java @@ -29,7 +29,7 @@ public final class ProgenitorMimic extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("no Token"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public ProgenitorMimic(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PromiseOfPower.java b/Mage.Sets/src/mage/cards/p/PromiseOfPower.java index 36a3fa8c29..44788d015e 100644 --- a/Mage.Sets/src/mage/cards/p/PromiseOfPower.java +++ b/Mage.Sets/src/mage/cards/p/PromiseOfPower.java @@ -41,7 +41,7 @@ public final class PromiseOfPower extends CardImpl { // - Create an X/X black Demon creature token with flying, where X is the number of cards in your hand. Mode mode = new Mode(); - mode.getEffects().add(new PromiseOfPowerEffect()); + mode.addEffect(new PromiseOfPowerEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {4} diff --git a/Mage.Sets/src/mage/cards/p/Prosperity.java b/Mage.Sets/src/mage/cards/p/Prosperity.java index edb928d7bc..17d84d0b32 100644 --- a/Mage.Sets/src/mage/cards/p/Prosperity.java +++ b/Mage.Sets/src/mage/cards/p/Prosperity.java @@ -19,7 +19,7 @@ public final class Prosperity extends CardImpl { // Each player draws X cards. - this.getSpellAbility().addEffect(new DrawCardAllEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardAllEffect(ManacostVariableValue.instance)); } public Prosperity(final Prosperity card) { diff --git a/Mage.Sets/src/mage/cards/p/ProsshSkyraiderOfKher.java b/Mage.Sets/src/mage/cards/p/ProsshSkyraiderOfKher.java index 3b3e48838b..bc9badb09f 100644 --- a/Mage.Sets/src/mage/cards/p/ProsshSkyraiderOfKher.java +++ b/Mage.Sets/src/mage/cards/p/ProsshSkyraiderOfKher.java @@ -38,7 +38,7 @@ public final class ProsshSkyraiderOfKher extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // When you cast Prossh, Skyraider of Kher, create X 0/1 red Kobold creature tokens named Kobolds of Kher Keep, where X is the amount of mana spent to cast Prossh. - this.addAbility(new CastSourceTriggeredAbility(new CreateTokenEffect(new ProsshKoboldToken(), new ManaSpentToCastCount()), false)); + this.addAbility(new CastSourceTriggeredAbility(new CreateTokenEffect(new ProsshKoboldToken(), ManaSpentToCastCount.instance), false)); // Sacrifice another creature: Prossh gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, true)))); diff --git a/Mage.Sets/src/mage/cards/p/ProteanHydra.java b/Mage.Sets/src/mage/cards/p/ProteanHydra.java index 571ba1c5c4..ca3820ba66 100644 --- a/Mage.Sets/src/mage/cards/p/ProteanHydra.java +++ b/Mage.Sets/src/mage/cards/p/ProteanHydra.java @@ -3,12 +3,11 @@ package mage.cards.p; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.PreventDamageAndRemoveCountersEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -16,13 +15,11 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Duration; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; /** * @@ -41,7 +38,7 @@ public final class ProteanHydra extends CardImpl { this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); // If damage would be dealt to Protean Hydra, prevent that damage and remove that many +1/+1 counters from it. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ProteanHydraEffect2())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect())); // Whenever a +1/+1 counter is removed from Protean Hydra, put two +1/+1 counters on it at the beginning of the next end step. this.addAbility(new ProteanHydraAbility()); @@ -57,50 +54,6 @@ public final class ProteanHydra extends CardImpl { return new ProteanHydra(this); } - static class ProteanHydraEffect2 extends PreventionEffectImpl { - - public ProteanHydraEffect2() { - super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); - staticText = "If damage would be dealt to {this}, prevent that damage and remove that many +1/+1 counters from it"; - } - - public ProteanHydraEffect2(final ProteanHydraEffect2 effect) { - super(effect); - } - - @Override - public ProteanHydraEffect2 copy() { - return new ProteanHydraEffect2(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public boolean replaceEvent(GameEvent event, Ability source, Game game) { - int damage = event.getAmount(); - preventDamageAction(event, source, game); - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); //MTG ruling Protean Hydra loses counters even if the damage isn't prevented - } - return false; - } - - @Override - public boolean applies(GameEvent event, Ability source, Game game) { - if (super.applies(event, source, game)) { - if (event.getTargetId().equals(source.getSourceId())) { - return true; - } - } - return false; - } - - } - class ProteanHydraAbility extends TriggeredAbilityImpl { public ProteanHydraAbility() { diff --git a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java index aae9d64c1b..ac4ddff684 100644 --- a/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java +++ b/Mage.Sets/src/mage/cards/p/ProtectiveSphere.java @@ -52,20 +52,20 @@ public final class ProtectiveSphere extends CardImpl { class ProtectiveSphereEffect extends PreventionEffectImpl { private final TargetSource target; - private Mana manaUsed; - private List colorsOfChosenSource = new ArrayList<>(); + private static Mana manaUsed; + private static List colorsOfChosenSource = new ArrayList<>(); public ProtectiveSphereEffect() { super(Duration.EndOfTurn, Integer.MAX_VALUE, false, false); - this.staticText = "Prevent all damage that would be dealt to you this turn by a source of your choice that shares a color with the mana spent on this activation cost."; + this.staticText = "Prevent all damage that would be dealt to you " + + "this turn by a source of your choice that shares a color " + + "with the mana spent on this activation cost."; this.target = new TargetSource(); } public ProtectiveSphereEffect(final ProtectiveSphereEffect effect) { super(effect); this.target = effect.target.copy(); - manaUsed = effect.manaUsed.copy(); - colorsOfChosenSource = effect.colorsOfChosenSource; } @Override @@ -81,8 +81,12 @@ class ProtectiveSphereEffect extends PreventionEffectImpl { Permanent protectiveSphere = game.getPermanent(source.getSourceId()); if (controller != null && protectiveSphere != null) { - game.getState().setValue("ProtectiveSphere" + source.getSourceId().toString(), source.getManaCostsToPay().getUsedManaToPay()); //store the mana used to pay - protectiveSphere.addInfo("MANA USED", CardUtil.addToolTipMarkTags("Last mana used for protective ability: " + source.getManaCostsToPay().getUsedManaToPay()), game); + game.getState().setValue("ProtectiveSphere" + + source.getSourceId().toString(), + source.getManaCostsToPay().getUsedManaToPay()); //store the mana used to pay + protectiveSphere.addInfo("MANA USED", + CardUtil.addToolTipMarkTags("Last mana used for protective ability: " + + source.getManaCostsToPay().getUsedManaToPay()), game); } this.target.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); super.init(source, game); diff --git a/Mage.Sets/src/mage/cards/p/ProwessOfTheFair.java b/Mage.Sets/src/mage/cards/p/ProwessOfTheFair.java index f642c2b466..990e3e7b7e 100644 --- a/Mage.Sets/src/mage/cards/p/ProwessOfTheFair.java +++ b/Mage.Sets/src/mage/cards/p/ProwessOfTheFair.java @@ -25,8 +25,8 @@ public final class ProwessOfTheFair extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ELF)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public ProwessOfTheFair(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/ProwlingCaracal.java b/Mage.Sets/src/mage/cards/p/ProwlingCaracal.java new file mode 100644 index 0000000000..06efcb4f4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/ProwlingCaracal.java @@ -0,0 +1,32 @@ +package mage.cards.p; + +import mage.MageInt; +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 ProwlingCaracal extends CardImpl { + + public ProwlingCaracal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.CAT); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + } + + private ProwlingCaracal(final ProwlingCaracal card) { + super(card); + } + + @Override + public ProwlingCaracal copy() { + return new ProwlingCaracal(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/ProwlingNightstalker.java b/Mage.Sets/src/mage/cards/p/ProwlingNightstalker.java index 19279f4048..59e6c5ccc4 100644 --- a/Mage.Sets/src/mage/cards/p/ProwlingNightstalker.java +++ b/Mage.Sets/src/mage/cards/p/ProwlingNightstalker.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class ProwlingNightstalker extends CardImpl { - private final static FilterCreaturePermanent notBlackCreatures = new FilterCreaturePermanent("except by black creatures"); + private static final FilterCreaturePermanent notBlackCreatures = new FilterCreaturePermanent("except by black creatures"); static { notBlackCreatures.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); diff --git a/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java b/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java index a6c373ffd1..e6eed74393 100644 --- a/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java +++ b/Mage.Sets/src/mage/cards/p/ProwlingPangolin.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -11,8 +10,8 @@ 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.SubType; import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; @@ -26,7 +25,7 @@ import mage.target.common.TargetControlledPermanent; public final class ProwlingPangolin extends CardImpl { public ProwlingPangolin(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.BEAST, SubType.PANGOLIN); this.power = new MageInt(6); this.toughness = new MageInt(5); diff --git a/Mage.Sets/src/mage/cards/p/PryingEyes.java b/Mage.Sets/src/mage/cards/p/PryingEyes.java new file mode 100644 index 0000000000..0718b39ff2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PryingEyes.java @@ -0,0 +1,33 @@ +package mage.cards.p; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class PryingEyes extends CardImpl { + + public PryingEyes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); + + + // Draw four cards, then discard two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(4)); + this.getSpellAbility().addEffect(new DiscardControllerEffect(2).concatBy(", then")); + } + + private PryingEyes(final PryingEyes card) { + super(card); + } + + @Override + public PryingEyes copy() { + return new PryingEyes(this); + } +} diff --git a/Mage.Sets/src/mage/cards/p/PsychicAllergy.java b/Mage.Sets/src/mage/cards/p/PsychicAllergy.java index c7c5c4cfeb..17af2bbb36 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicAllergy.java +++ b/Mage.Sets/src/mage/cards/p/PsychicAllergy.java @@ -84,7 +84,7 @@ class PsychicAllergyEffect extends OneShotEffect { if (player != null) { FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate((ObjectColor) game.getState().getValue(source.getSourceId() + "_color"))); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); int damage = game.getBattlefield().countAll(filter, player.getId(), game); player.damage(damage, source.getSourceId(), game, false, true); return true; diff --git a/Mage.Sets/src/mage/cards/p/PsychicBattle.java b/Mage.Sets/src/mage/cards/p/PsychicBattle.java index f4f3eb91b9..6c77281e1a 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicBattle.java +++ b/Mage.Sets/src/mage/cards/p/PsychicBattle.java @@ -31,7 +31,7 @@ public final class PsychicBattle extends CardImpl { public PsychicBattle(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}{U}"); - // Whenever a player chooses one or more targets, each player reveals the top card of his or her library. The player who reveals the card with the highest converted mana cost may change the target or targets. If two or more cards are tied for highest cost, the target or targets remain unchanged. Changing targets this way doesn't trigger abilities of permanents named Psychic Battle. + // Whenever a player chooses one or more targets, each player reveals the top card of their library. The player who reveals the card with the highest converted mana cost may change the target or targets. If two or more cards are tied for highest cost, the target or targets remain unchanged. Changing targets this way doesn't trigger abilities of permanents named Psychic Battle. this.addAbility(new PsychicBattleTriggeredAbility()); } diff --git a/Mage.Sets/src/mage/cards/p/PsychicDrain.java b/Mage.Sets/src/mage/cards/p/PsychicDrain.java index 6deb03654b..8008a2e7fb 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicDrain.java +++ b/Mage.Sets/src/mage/cards/p/PsychicDrain.java @@ -21,9 +21,9 @@ public final class PsychicDrain extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{B}"); // Target player puts the top X cards of their library into their graveyard and you gain X life. - this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); - Effect effect = new GainLifeEffect(new ManacostVariableValue()); + Effect effect = new GainLifeEffect(ManacostVariableValue.instance); effect.setText("and you gain X life"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java b/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java index 553b793657..9cc6cc4f33 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java +++ b/Mage.Sets/src/mage/cards/p/PsychicIntrusion.java @@ -1,4 +1,3 @@ - package mage.cards.p; import java.util.UUID; @@ -33,7 +32,7 @@ import mage.util.CardUtil; public final class PsychicIntrusion extends CardImpl { public PsychicIntrusion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}{B}"); // Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it. // You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color @@ -187,16 +186,15 @@ class PsychicIntrusionSpendAnyManaEffect extends AsThoughEffectImpl implements A @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - if (affectedControllerId.equals(source.getControllerId())) { // if the card moved from exile to spell the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else { if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted diff --git a/Mage.Sets/src/mage/cards/p/PsychicSurgery.java b/Mage.Sets/src/mage/cards/p/PsychicSurgery.java index a3c04aa326..1c21405e4e 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicSurgery.java +++ b/Mage.Sets/src/mage/cards/p/PsychicSurgery.java @@ -29,7 +29,7 @@ public final class PsychicSurgery extends CardImpl { public PsychicSurgery(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); - // Whenever an opponent shuffles his or her library, you may look at the top two cards of that library. + // Whenever an opponent shuffles their library, you may look at the top two cards of that library. // You may exile one of those cards. Then put the rest on top of that library in any order. this.addAbility(new PsychicSurgeryTriggeredAbility()); } @@ -114,7 +114,7 @@ class PsychicSurgeryEffect extends OneShotEffect { } } } - controller.putCardsOnBottomOfLibrary(cards, game, source, true); + controller.putCardsOnTopOfLibrary(cards, game, source, true); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/p/PsychicTheft.java b/Mage.Sets/src/mage/cards/p/PsychicTheft.java index b017003c21..1d2d948268 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicTheft.java +++ b/Mage.Sets/src/mage/cards/p/PsychicTheft.java @@ -162,7 +162,7 @@ class PsychicTheftCondition implements Condition { if (!game.getExile().getExileZone(exileId).contains(cardId)) { return false; } - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName(), source.getSourceId()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class, source.getSourceId()); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spells != null) { diff --git a/Mage.Sets/src/mage/cards/p/PsychicVortex.java b/Mage.Sets/src/mage/cards/p/PsychicVortex.java index 9cf553a4ed..31cd032e07 100644 --- a/Mage.Sets/src/mage/cards/p/PsychicVortex.java +++ b/Mage.Sets/src/mage/cards/p/PsychicVortex.java @@ -72,7 +72,7 @@ class PsychicVortexCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { Player controller = game.getPlayer(controllerId); - return controller.getLibrary().hasCards(); + return controller != null && controller.getLibrary().hasCards(); } @Override diff --git a/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java b/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java index 9df5371fa9..74128f25f3 100644 --- a/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java +++ b/Mage.Sets/src/mage/cards/p/PsychosisCrawler.java @@ -28,7 +28,7 @@ public final class PsychosisCrawler extends CardImpl { this.power = new MageInt(0); this.toughness = new MageInt(0); - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInControllerHandCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame))); this.addAbility(new DrawCardControllerTriggeredAbility(new LoseLifeOpponentsEffect(1), false)); } diff --git a/Mage.Sets/src/mage/cards/p/PsychoticFury.java b/Mage.Sets/src/mage/cards/p/PsychoticFury.java index 89a2e8bb19..c8ebd40196 100644 --- a/Mage.Sets/src/mage/cards/p/PsychoticFury.java +++ b/Mage.Sets/src/mage/cards/p/PsychoticFury.java @@ -22,7 +22,7 @@ public final class PsychoticFury extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("multicolored creature"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public PsychoticFury(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/Pteramander.java b/Mage.Sets/src/mage/cards/p/Pteramander.java new file mode 100644 index 0000000000..2172b5de82 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/Pteramander.java @@ -0,0 +1,94 @@ +package mage.cards.p; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.effects.keyword.AdaptEffect; +import mage.abilities.hint.ValueHint; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Pteramander extends CardImpl { + + static final DynamicValue cardsCount = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); + + public Pteramander(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.SALAMANDER); + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {7}{U}: Adapt 4. This ability costs {1} less to activate for each instant and sorcery card in your graveyard. + // TODO: Make ability properly copiable + Ability ability = new SimpleActivatedAbility(new AdaptEffect(4).setText("Adapt 4. This ability costs {1} less to activate for each instant and sorcery card in your graveyard."), new ManaCostsImpl("{7}{U}")); + this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new PteramanderCostIncreasingEffect(ability.getOriginalId())) + .addHint(new ValueHint("Instant and sorcery cards in your graveyard", cardsCount))); + } + + private Pteramander(final Pteramander card) { + super(card); + } + + @Override + public Pteramander copy() { + return new Pteramander(this); + } +} + +class PteramanderCostIncreasingEffect extends CostModificationEffectImpl { + + private final UUID originalId; + + PteramanderCostIncreasingEffect(UUID originalId) { + super(Duration.EndOfGame, Outcome.Benefit, CostModificationType.REDUCE_COST); + this.originalId = originalId; + } + + private PteramanderCostIncreasingEffect(final PteramanderCostIncreasingEffect effect) { + super(effect); + this.originalId = effect.originalId; + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int count = Pteramander.cardsCount.calculate(game, source, this); + CardUtil.reduceCost(abilityToModify, count); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify.getOriginalId().equals(originalId); + } + + @Override + public PteramanderCostIncreasingEffect copy() { + return new PteramanderCostIncreasingEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/p/PucasMischief.java b/Mage.Sets/src/mage/cards/p/PucasMischief.java index fb18899101..dcf0628b1b 100644 --- a/Mage.Sets/src/mage/cards/p/PucasMischief.java +++ b/Mage.Sets/src/mage/cards/p/PucasMischief.java @@ -64,18 +64,15 @@ class TargetControlledPermanentWithCMCGreaterOrLessThanOpponentPermanent extends super(target); } - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - return super.canTarget(controllerId, id, source, game); - } - @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } } } return possibleTargets; @@ -121,10 +118,12 @@ class PucasMischiefSecondTarget extends TargetPermanent { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if (firstTarget.getConvertedManaCost() >= permanent.getConvertedManaCost()) { - possibleTargets.add(permanent.getId()); + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (firstTarget.getConvertedManaCost() >= permanent.getConvertedManaCost()) { + possibleTargets.add(permanent.getId()); + } } } } diff --git a/Mage.Sets/src/mage/cards/p/PullFromEternity.java b/Mage.Sets/src/mage/cards/p/PullFromEternity.java index 46fe77e642..5a7aecf42d 100644 --- a/Mage.Sets/src/mage/cards/p/PullFromEternity.java +++ b/Mage.Sets/src/mage/cards/p/PullFromEternity.java @@ -26,7 +26,7 @@ public final class PullFromEternity extends CardImpl { private static final FilterCard filter = new FilterCard("face-up exiled card"); static { - filter.add(Predicates.not(new FaceDownPredicate())); + filter.add(Predicates.not(FaceDownPredicate.instance)); } public PullFromEternity(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PullFromTomorrow.java b/Mage.Sets/src/mage/cards/p/PullFromTomorrow.java index 2a2760fdeb..bc19074670 100644 --- a/Mage.Sets/src/mage/cards/p/PullFromTomorrow.java +++ b/Mage.Sets/src/mage/cards/p/PullFromTomorrow.java @@ -20,7 +20,7 @@ public final class PullFromTomorrow extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}{U}"); // Draw X cards, then discard a card. - getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new ManacostVariableValue())); + getSpellAbility().addEffect(new DrawCardSourceControllerEffect(ManacostVariableValue.instance)); Effect effect = new DiscardControllerEffect(1); effect.setText(", then discard a card"); getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/p/PulseOfLlanowar.java b/Mage.Sets/src/mage/cards/p/PulseOfLlanowar.java new file mode 100644 index 0000000000..e4ae658497 --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PulseOfLlanowar.java @@ -0,0 +1,98 @@ + +package mage.cards.p; + +import java.util.UUID; +import mage.MageObject; +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.mana.AddManaOfAnyColorEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SuperType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.events.ManaEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author L_J + */ +public final class PulseOfLlanowar extends CardImpl { + + public PulseOfLlanowar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PulseOfLlanowarReplacementEffect())); + } + + public PulseOfLlanowar(final PulseOfLlanowar card) { + super(card); + } + + @Override + public PulseOfLlanowar copy() { + return new PulseOfLlanowar(this); + } +} + +class PulseOfLlanowarReplacementEffect extends ReplacementEffectImpl { + + private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + static { + filter.add(new SupertypePredicate(SuperType.BASIC)); + } + + PulseOfLlanowarReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Neutral); + staticText = "If a basic land you control is tapped for mana, it produces mana of a color of your choice instead of any other type"; + } + + PulseOfLlanowarReplacementEffect(final PulseOfLlanowarReplacementEffect effect) { + super(effect); + } + + @Override + public PulseOfLlanowarReplacementEffect copy() { + return new PulseOfLlanowarReplacementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + ManaEvent manaEvent = (ManaEvent) event; + Mana mana = manaEvent.getMana(); + new AddManaOfAnyColorEffect(mana.count()).apply(game,source); + mana.setToMana(new Mana(0,0,0,0,0,0,0,0)); + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.TAPPED_FOR_MANA; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + MageObject mageObject = game.getObject(event.getSourceId()); + if (mageObject != null && mageObject.isLand()) { + Permanent land = game.getPermanent(event.getSourceId()); + return land != null && filter.match(land, game); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/p/PuppetMaster.java b/Mage.Sets/src/mage/cards/p/PuppetMaster.java new file mode 100644 index 0000000000..7b4a6f874b --- /dev/null +++ b/Mage.Sets/src/mage/cards/p/PuppetMaster.java @@ -0,0 +1,95 @@ + +package mage.cards.p; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.DiesAttachedTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class PuppetMaster extends CardImpl { + + public PuppetMaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}{U}{U}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // When enchanted creature dies, return that card to its owner's hand. If that card is returned to its owner’s hand this way, you may pay {U}{U}{U}. If you do, return Puppet Master to its owner’s hand. + this.addAbility(new DiesAttachedTriggeredAbility(new PuppetMasterEffect(), "enchanted creature")); + } + + public PuppetMaster(final PuppetMaster card) { + super(card); + } + + @Override + public PuppetMaster copy() { + return new PuppetMaster(this); + } +} + +class PuppetMasterEffect extends OneShotEffect { + + public PuppetMasterEffect() { + super(Outcome.ReturnToHand); + staticText = "return that card to its owner's hand. If that card is returned to its owner’s hand this way, you may pay {U}{U}{U}. If you do, return {this} to its owner’s hand"; + } + + public PuppetMasterEffect(final PuppetMasterEffect effect) { + super(effect); + } + + @Override + public PuppetMasterEffect copy() { + return new PuppetMasterEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Object object = getValue("attachedTo"); + if (object instanceof Permanent) { + Card card = game.getCard(((Permanent)object).getId()); + if (card != null) { + if (card.moveToZone(Zone.HAND, source.getSourceId(), game, false)) { + Cost cost = new ManaCostsImpl("{U}{U}{U}"); + Player controller = game.getPlayer(source.getControllerId()); + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && sourcePermanent != null) { + if (controller.chooseUse(Outcome.Neutral, "Pay " + cost.getText() + " to return " + sourcePermanent.getLogName() + " to its owner's hand?", source, game) + && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { + sourcePermanent.moveToZone(Zone.HAND, source.getSourceId(), game, false); + } + } + return true; + } + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/p/PuppeteerClique.java b/Mage.Sets/src/mage/cards/p/PuppeteerClique.java index 774fa5d6a5..6e874521b6 100644 --- a/Mage.Sets/src/mage/cards/p/PuppeteerClique.java +++ b/Mage.Sets/src/mage/cards/p/PuppeteerClique.java @@ -1,7 +1,6 @@ package mage.cards.p; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -17,12 +16,7 @@ import mage.abilities.keyword.PersistAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; @@ -31,15 +25,15 @@ import mage.target.Target; import mage.target.common.TargetCardInOpponentsGraveyard; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class PuppeteerClique extends CardImpl { public PuppeteerClique(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); this.subtype.add(SubType.FAERIE); this.subtype.add(SubType.WIZARD); @@ -59,7 +53,7 @@ public final class PuppeteerClique extends CardImpl { this.addAbility(new PersistAbility()); } - public PuppeteerClique(final PuppeteerClique card) { + private PuppeteerClique(final PuppeteerClique card) { super(card); } @@ -71,12 +65,12 @@ public final class PuppeteerClique extends CardImpl { class PuppeteerCliqueEffect extends OneShotEffect { - public PuppeteerCliqueEffect() { + PuppeteerCliqueEffect() { super(Outcome.PutCreatureInPlay); staticText = "put target creature card from an opponent's graveyard onto the battlefield under your control. It gains haste. At the beginning of your next end step, exile it"; } - public PuppeteerCliqueEffect(final PuppeteerCliqueEffect effect) { + private PuppeteerCliqueEffect(final PuppeteerCliqueEffect effect) { super(effect); } @@ -87,26 +81,25 @@ class PuppeteerCliqueEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - boolean result = false; Card card = game.getCard(getTargetPointer().getFirst(game, source)); - if (card != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); - hasteEffect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(hasteEffect, source); - ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); - exileEffect.setTargetPointer(new FixedTarget(permanent, game)); - DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); - game.addDelayedTriggeredAbility(delayedAbility, source); - result = true; - } - } - } + if (card == null) { + return false; } - return result; + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null || !controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return false; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent == null) { + return false; + } + ContinuousEffect hasteEffect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + hasteEffect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(hasteEffect, source); + ExileTargetEffect exileEffect = new ExileTargetEffect("exile " + permanent.getLogName()); + exileEffect.setTargetPointer(new FixedTarget(permanent, game)); + DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(exileEffect, TargetController.YOU); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; } } diff --git a/Mage.Sets/src/mage/cards/p/PuppetsVerdict.java b/Mage.Sets/src/mage/cards/p/PuppetsVerdict.java index ab3f3183fb..080d25a75c 100644 --- a/Mage.Sets/src/mage/cards/p/PuppetsVerdict.java +++ b/Mage.Sets/src/mage/cards/p/PuppetsVerdict.java @@ -54,7 +54,7 @@ class PuppetsVerdictEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { FilterCreaturePermanent filterPower2OrLess = new FilterCreaturePermanent("all creatures power 2 or less"); filterPower2OrLess.add(new PowerPredicate(ComparisonType.FEWER_THAN, 3)); diff --git a/Mage.Sets/src/mage/cards/p/PureSimple.java b/Mage.Sets/src/mage/cards/p/PureSimple.java index b73bf79b0c..e14378e1c5 100644 --- a/Mage.Sets/src/mage/cards/p/PureSimple.java +++ b/Mage.Sets/src/mage/cards/p/PureSimple.java @@ -27,7 +27,7 @@ public final class PureSimple extends SplitCard { static { filterDestroy.add(Predicates.or(new SubtypePredicate(SubType.AURA), new SubtypePredicate(SubType.EQUIPMENT))); - filterMulticolor.add(new MulticoloredPredicate()); + filterMulticolor.add(MulticoloredPredicate.instance); } public PureSimple(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PuresightMerrow.java b/Mage.Sets/src/mage/cards/p/PuresightMerrow.java index 6e9a4c7048..e8df9abeae 100644 --- a/Mage.Sets/src/mage/cards/p/PuresightMerrow.java +++ b/Mage.Sets/src/mage/cards/p/PuresightMerrow.java @@ -75,8 +75,7 @@ class PuresightMerrowEffect extends OneShotEffect { if (controller != null && sourceObject != null) { Card card = controller.getLibrary().getFromTop(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("Puresight Merrow", cards, game); if (controller.chooseUse(Outcome.Removal, "Do you wish to exile the card from the top of your library?", source, game)) { controller.moveCardToExileWithInfo(card, source.getSourceId(), sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); diff --git a/Mage.Sets/src/mage/cards/p/PurgingScythe.java b/Mage.Sets/src/mage/cards/p/PurgingScythe.java index 9ffa9791dd..17b15d25af 100644 --- a/Mage.Sets/src/mage/cards/p/PurgingScythe.java +++ b/Mage.Sets/src/mage/cards/p/PurgingScythe.java @@ -92,7 +92,7 @@ class PurgingScytheEffect extends OneShotEffect { } } if (permanentToDamage != null) { - game.informPlayers(new StringBuilder(sourcePermanent.getName()).append(" chosen creature: ").append(permanentToDamage.getName()).toString()); + game.informPlayers(sourcePermanent.getName() + " chosen creature: " + permanentToDamage.getName()); return permanentToDamage.damage(2, source.getSourceId(), game, false, true) > 0; } return true; diff --git a/Mage.Sets/src/mage/cards/p/PurphorosGodOfTheForge.java b/Mage.Sets/src/mage/cards/p/PurphorosGodOfTheForge.java index ad1bc787fa..31c7ecc867 100644 --- a/Mage.Sets/src/mage/cards/p/PurphorosGodOfTheForge.java +++ b/Mage.Sets/src/mage/cards/p/PurphorosGodOfTheForge.java @@ -27,7 +27,7 @@ public final class PurphorosGodOfTheForge extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public PurphorosGodOfTheForge(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/p/PutAway.java b/Mage.Sets/src/mage/cards/p/PutAway.java index b67ccad8ac..0f4c6da129 100644 --- a/Mage.Sets/src/mage/cards/p/PutAway.java +++ b/Mage.Sets/src/mage/cards/p/PutAway.java @@ -1,7 +1,5 @@ - package mage.cards.p; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -17,15 +15,15 @@ import mage.players.Player; import mage.target.TargetSpell; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth - * */ public final class PutAway extends CardImpl { public PutAway(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); // Counter target spell. You may shuffle up to one target card from your graveyard into your library. @@ -46,7 +44,7 @@ public final class PutAway extends CardImpl { } class PutAwayEffect extends OneShotEffect { - + boolean countered = false; public PutAwayEffect() { @@ -66,15 +64,14 @@ class PutAwayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(source.getFirstTarget()); - Card card = game.getCard(source.getTargets().get(1).getFirstTarget()); - Player you = game.getPlayer(source.getControllerId()); - if (spell != null - && game.getStack().counter(spell.getId(), source.getSourceId(), game)) { + if (spell != null && game.getStack().counter(spell.getId(), source.getSourceId(), game)) { countered = true; } - if (you != null) { - if (card != null - && you.chooseUse(Outcome.Benefit, "Do you wish to shuffle up to one target card from your graveyard into your library?", source, game) + + Card card = game.getCard(source.getTargets().get(1).getFirstTarget()); + Player you = game.getPlayer(source.getControllerId()); + if (you != null && card != null) { + if (you.chooseUse(Outcome.Benefit, "Do you wish to shuffle up to one target card from your graveyard into your library?", source, game) && game.getState().getZone(card.getId()).match(Zone.GRAVEYARD)) { card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); you.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/p/Putrefaction.java b/Mage.Sets/src/mage/cards/p/Putrefaction.java index 30bd43132e..216072a70c 100644 --- a/Mage.Sets/src/mage/cards/p/Putrefaction.java +++ b/Mage.Sets/src/mage/cards/p/Putrefaction.java @@ -41,13 +41,13 @@ public final class Putrefaction extends CardImpl { class PutrefactionTriggeredAbility extends SpellCastAllTriggeredAbility { - private static final FilterSpell filter = new FilterSpell("green or white spell"); + private static final FilterSpell filterGreenOrWhiteSpell = new FilterSpell("green or white spell"); static { - filter.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE))); + filterGreenOrWhiteSpell.add(Predicates.or(new ColorPredicate(ObjectColor.GREEN), new ColorPredicate(ObjectColor.WHITE))); } public PutrefactionTriggeredAbility() { - super(new DiscardTargetEffect(1), filter, false); + super(new DiscardTargetEffect(1), filterGreenOrWhiteSpell, false); } public PutrefactionTriggeredAbility(PutrefactionTriggeredAbility ability) { @@ -58,7 +58,7 @@ class PutrefactionTriggeredAbility extends SpellCastAllTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST) { Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null && filter.match(spell, getSourceId(), getControllerId(), game)) { + if (spell != null && filterGreenOrWhiteSpell.match(spell, getSourceId(), getControllerId(), game)) { this.getEffects().get(0).setTargetPointer(new FixedTarget(event.getPlayerId())); return true; } diff --git a/Mage.Sets/src/mage/cards/p/PutridWarrior.java b/Mage.Sets/src/mage/cards/p/PutridWarrior.java index a26efaf80f..a80e4163de 100644 --- a/Mage.Sets/src/mage/cards/p/PutridWarrior.java +++ b/Mage.Sets/src/mage/cards/p/PutridWarrior.java @@ -38,7 +38,7 @@ public final class PutridWarrior extends CardImpl { // Whenever Putrid Warrior deals damage, choose one - Each player loses 1 life; or each player gains 1 life. Ability ability = new PutridWarriorDealsDamageTriggeredAbility(new LoseLifeAllPlayersEffect(1)); Mode mode = new Mode(); - mode.getEffects().add(new PutridWarriorGainLifeEffect()); + mode.addEffect(new PutridWarriorGainLifeEffect()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/p/Pyramids.java b/Mage.Sets/src/mage/cards/p/Pyramids.java index 5d2b3d3ceb..4dafc88e56 100644 --- a/Mage.Sets/src/mage/cards/p/Pyramids.java +++ b/Mage.Sets/src/mage/cards/p/Pyramids.java @@ -45,8 +45,8 @@ public final class Pyramids extends CardImpl { Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}")); //or the next time target land would be destroyed this turn, remove all damage marked on it instead. Mode mode = new Mode(); //back in the day this was not technically "damage", hopefully this modern description will work nowadays - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn)); - mode.getTargets().add(new TargetLandPermanent()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn)); + mode.addTarget(new TargetLandPermanent()); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/Pyroblast.java b/Mage.Sets/src/mage/cards/p/Pyroblast.java index 3c61105ebd..e65d8908ae 100644 --- a/Mage.Sets/src/mage/cards/p/Pyroblast.java +++ b/Mage.Sets/src/mage/cards/p/Pyroblast.java @@ -28,8 +28,8 @@ public final class Pyroblast extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell()); Mode mode = new Mode(); - mode.getEffects().add(new PyroblastDestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent()); + mode.addEffect(new PyroblastDestroyTargetEffect()); + mode.addTarget(new TargetPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java index c4831f5dd2..2f6f176078 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancerAscension.java +++ b/Mage.Sets/src/mage/cards/p/PyromancerAscension.java @@ -1,8 +1,5 @@ - - package mage.cards.p; -import java.util.UUID; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CopyTargetSpellEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -17,19 +14,21 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author nantuko */ public final class PyromancerAscension extends CardImpl { public PyromancerAscension(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); // Whenever you cast an instant or sorcery spell that has the same name as a card in your graveyard, you may put a quest counter on Pyromancer Ascension. this.addAbility(new PyromancerAscensionQuestTriggeredAbility()); - + // Whenever you cast an instant or sorcery spell while Pyromancer Ascension has two or more quest counters on it, you may copy that spell. You may choose new targets for the copy. this.addAbility(new PyromancerAscensionCopyTriggeredAbility()); } @@ -75,21 +74,21 @@ class PyromancerAscensionQuestTriggeredAbility extends TriggeredAbilityImpl { for (UUID uuid : game.getPlayer(this.getControllerId()).getGraveyard()) { if (!uuid.equals(sourceCard.getId())) { Card card = game.getCard(uuid); - if (card != null && card.getName().equals(sourceCard.getName())) { + if (CardUtil.haveSameNames(card, sourceCard)) { return true; } } } - } + } } } return false; } private boolean isControlledInstantOrSorcery(Spell spell) { - return spell != null && - (spell.isControlledBy(this.getControllerId())) && - (spell.isInstant() || spell.isSorcery()); + return spell != null && + (spell.isControlledBy(this.getControllerId())) && + (spell.isInstant() || spell.isSorcery()); } @Override @@ -112,12 +111,12 @@ class PyromancerAscensionCopyTriggeredAbility extends TriggeredAbilityImpl { public PyromancerAscensionCopyTriggeredAbility copy() { return new PyromancerAscensionCopyTriggeredAbility(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 (event.getPlayerId().equals(this.getControllerId())) { @@ -134,9 +133,9 @@ class PyromancerAscensionCopyTriggeredAbility extends TriggeredAbilityImpl { } private boolean isControlledInstantOrSorcery(Spell spell) { - return spell != null && - (spell.isControlledBy(this.getControllerId())) && - (spell.isInstant() || spell.isSorcery()); + return spell != null && + (spell.isControlledBy(this.getControllerId())) && + (spell.isInstant() || spell.isSorcery()); } @Override diff --git a/Mage.Sets/src/mage/cards/p/PyromancersAssault.java b/Mage.Sets/src/mage/cards/p/PyromancersAssault.java index 8bc1f2d92f..f51ade6254 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersAssault.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersAssault.java @@ -63,7 +63,7 @@ class PyromancersAssaultTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { return true; } diff --git a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java index b26aed2ddd..f6f2ec08a5 100644 --- a/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java +++ b/Mage.Sets/src/mage/cards/p/PyromancersGoggles.java @@ -54,7 +54,7 @@ public final class PyromancersGoggles extends CardImpl { class PyromancersGogglesTriggeredAbility extends TriggeredAbilityImpl { - private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); static { filter.add(new ColorPredicate(ObjectColor.RED)); diff --git a/Mage.Sets/src/mage/cards/p/Pyromancy.java b/Mage.Sets/src/mage/cards/p/Pyromancy.java index b1d4d0a3cf..4cc770be5a 100644 --- a/Mage.Sets/src/mage/cards/p/Pyromancy.java +++ b/Mage.Sets/src/mage/cards/p/Pyromancy.java @@ -25,7 +25,7 @@ public final class Pyromancy extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{R}{R}"); // {3}, Discard a card at random: Pyromancy deals damage to any target equal to the converted mana cost of the discarded card. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new DiscardCostCardConvertedMana()), new ManaCostsImpl("{3}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(DiscardCostCardConvertedMana.instance), new ManaCostsImpl("{3}")); ability.addTarget(new TargetAnyTarget()); ability.addCost(new DiscardCardCost(true)); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java b/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java index 9c7e5e2455..cb8f478b37 100644 --- a/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java +++ b/Mage.Sets/src/mage/cards/p/PyxisOfPandemonium.java @@ -1,10 +1,8 @@ - package mage.cards.p; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -17,6 +15,7 @@ import mage.constants.Outcome; import mage.constants.Zone; import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; @@ -27,12 +26,19 @@ import mage.util.CardUtil; public final class PyxisOfPandemonium extends CardImpl { public PyxisOfPandemonium(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {T}: Each player exiles the top card of their library face down. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new PyxisOfPandemoniumExileEffect(), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new PyxisOfPandemoniumExileEffect(), + new TapSourceCost())); + // {7}, {T}, Sacrifice Pyxis of Pandemonium: Each player turns face up all cards he or she owns exiled with Pyxis of Pandemonium, then puts all permanent cards among them onto the battlefield. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PyxisOfPandemoniumPutOntoBattlefieldEffect(), new GenericManaCost(7)); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new PyxisOfPandemoniumPutOntoBattlefieldEffect(), + new GenericManaCost(7)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -68,10 +74,11 @@ class PyxisOfPandemoniumExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && controller != null) { + Permanent pyxis = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (pyxis != null + && controller != null) { Map exileIds; - String valueKey = CardUtil.getObjectZoneString("exileIds", sourceObject, game); + String valueKey = CardUtil.getObjectZoneString("exileIds", pyxis, game); Object object = game.getState().getValue(valueKey); if (object instanceof Map) { exileIds = (Map) object; @@ -79,20 +86,22 @@ class PyxisOfPandemoniumExileEffect extends OneShotEffect { exileIds = new HashMap<>(); game.getState().setValue(valueKey, exileIds); } - - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - + game.getState().getPlayersInRange(controller.getId(), game).forEach((playerId) -> { Player player = game.getPlayer(playerId); if (player != null) { if (player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - String exileKey = playerId.toString() + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()).toString(); + String exileKey = playerId.toString() + + CardUtil.getExileZoneId(game, + source.getSourceId(), + pyxis.getZoneChangeCounter(game)); UUID exileId = exileIds.computeIfAbsent(exileKey, k -> UUID.randomUUID()); - player.moveCardsToExile(card, source, game, false, exileId, sourceObject.getIdName() + " (" + player.getName() + ')'); + player.moveCardsToExile(card, source, game, false, + exileId, pyxis.getIdName() + " (" + player.getName() + ')'); card.setFaceDown(true, game); } } - } + }); return true; } return false; @@ -103,7 +112,8 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { public PyxisOfPandemoniumPutOntoBattlefieldEffect() { super(Outcome.PutCardInPlay); - this.staticText = "Each player turns face up all cards he or she owns exiled with {this}, then puts all permanent cards among them onto the battlefield"; + this.staticText = "Each player turns face up all cards he or she owns exiled with {this}, " + + "then puts all permanent cards among them onto the battlefield"; } public PyxisOfPandemoniumPutOntoBattlefieldEffect(final PyxisOfPandemoniumPutOntoBattlefieldEffect effect) { @@ -118,10 +128,11 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { + Permanent pyxis = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null + && pyxis != null) { Map exileIds; - String valueKey = CardUtil.getObjectZoneString("exileIds", sourceObject, game); + String valueKey = CardUtil.getObjectZoneString("exileIds", pyxis, game); Object object = game.getState().getValue(valueKey); if (object instanceof Map) { exileIds = (Map) object; @@ -129,24 +140,26 @@ class PyxisOfPandemoniumPutOntoBattlefieldEffect extends OneShotEffect { return true; } Cards cardsToBringIntoPlay = new CardsImpl(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + game.getState().getPlayersInRange(controller.getId(), game).forEach((playerId) -> { Player player = game.getPlayer(playerId); if (player != null) { - String exileKey = playerId.toString() + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()).toString(); + String exileKey = playerId.toString() + CardUtil.getExileZoneId(game, + source.getSourceId(), + pyxis.getZoneChangeCounter(game)); UUID exileId = exileIds.get(exileKey); if (exileId != null) { ExileZone exileZone = game.getState().getExile().getExileZone(exileId); if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { + exileZone.getCards(game).stream().map((card) -> { card.setFaceDown(false, game); - if (card.isPermanent()) { - cardsToBringIntoPlay.add(card); - } - } + return card; + }).filter((card) -> (card.isPermanent())).forEachOrdered((card) -> { + cardsToBringIntoPlay.add(card); + }); } } } - } + }); controller.moveCards(cardsToBringIntoPlay.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } diff --git a/Mage.Sets/src/mage/cards/q/QuagVampires.java b/Mage.Sets/src/mage/cards/q/QuagVampires.java index 4cd03cf178..ebea154499 100644 --- a/Mage.Sets/src/mage/cards/q/QuagVampires.java +++ b/Mage.Sets/src/mage/cards/q/QuagVampires.java @@ -36,7 +36,7 @@ public final class QuagVampires extends CardImpl { // Quag Vampires enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true), "with a +1/+1 counter on it for each time it was kicked")); } diff --git a/Mage.Sets/src/mage/cards/q/QuarantineField.java b/Mage.Sets/src/mage/cards/q/QuarantineField.java index ee87bc53b4..591e3c8d54 100644 --- a/Mage.Sets/src/mage/cards/q/QuarantineField.java +++ b/Mage.Sets/src/mage/cards/q/QuarantineField.java @@ -1,7 +1,6 @@ package mage.cards.q; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -21,10 +20,12 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class QuarantineField extends CardImpl { @@ -35,42 +36,43 @@ public final class QuarantineField extends CardImpl { // Quarantine Field enters the battlefield with X isolation counters on it. this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.ISOLATION.createInstance()))); - // When Quarantine Field enters the battlefield, for each isolation counter on it, exile up to one target nonland permanent an opponenet controls until Quarantine Field leaves the battlefield. + // When Quarantine Field enters the battlefield, for each isolation counter on it, exile up to one target nonland permanent an opponent controls until Quarantine Field leaves the battlefield. Ability ability = new EntersBattlefieldTriggeredAbility(new QuarantineFieldEffect(), false); ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility())); + ability.setTargetAdjuster(QuarantineFieldAdjuster.instance); this.addAbility(ability); - } public QuarantineField(final QuarantineField card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - Permanent sourceObject = game.getPermanent(ability.getSourceId()); - if (sourceObject != null) { - int isolationCounters = sourceObject.getCounters(game).getCount(CounterType.ISOLATION); - FilterNonlandPermanent filter = new FilterNonlandPermanent("up to " + isolationCounters + " nonland permanents controlled by any opponents"); - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - ability.addTarget(new TargetPermanent(0, isolationCounters, filter, false)); - } - - } - } - @Override public QuarantineField copy() { return new QuarantineField(this); } } +enum QuarantineFieldAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Permanent sourceObject = game.getPermanent(ability.getSourceId()); + if (sourceObject != null) { + int isolationCounters = sourceObject.getCounters(game).getCount(CounterType.ISOLATION); + FilterNonlandPermanent filter = new FilterNonlandPermanent("up to " + isolationCounters + " nonland permanents controlled by an opponent"); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + ability.addTarget(new TargetPermanent(0, isolationCounters, filter, false)); + } + } +} + class QuarantineFieldEffect extends OneShotEffect { public QuarantineFieldEffect() { super(Outcome.Exile); - this.staticText = "for each isolation counter on it, exile up to one target nonland permanent an opponenet controls until {this} leaves the battlefield"; + this.staticText = "for each isolation counter on it, exile up to one target nonland permanent an opponent controls until {this} leaves the battlefield"; } public QuarantineFieldEffect(final QuarantineFieldEffect effect) { diff --git a/Mage.Sets/src/mage/cards/q/Quench.java b/Mage.Sets/src/mage/cards/q/Quench.java new file mode 100644 index 0000000000..e1ca7a659f --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/Quench.java @@ -0,0 +1,33 @@ +package mage.cards.q; + +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Quench extends CardImpl { + + public Quench(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Counter target spell unless its controller pays {2}. + this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private Quench(final Quench card) { + super(card); + } + + @Override + public Quench copy() { + return new Quench(this); + } +} diff --git a/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java b/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java index ac0e51c6aa..984098d5fe 100644 --- a/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java +++ b/Mage.Sets/src/mage/cards/q/QuestForTheHolyRelic.java @@ -80,7 +80,7 @@ class QuestForTheHolyRelicEffect extends OneShotEffect { FilterCard filter = new FilterCard("Equipment"); filter.add(new SubtypePredicate(SubType.EQUIPMENT)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { Permanent equipment = game.getPermanent(card.getId()); diff --git a/Mage.Sets/src/mage/cards/q/Quicken.java b/Mage.Sets/src/mage/cards/q/Quicken.java index e34973989e..3ccc2a178b 100644 --- a/Mage.Sets/src/mage/cards/q/Quicken.java +++ b/Mage.Sets/src/mage/cards/q/Quicken.java @@ -64,7 +64,7 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { - quickenWatcher = (QuickenWatcher) game.getState().getWatchers().get(QuickenWatcher.class.getSimpleName()); + quickenWatcher = game.getState().getWatcher(QuickenWatcher.class); Card card = game.getCard(source.getSourceId()); if (quickenWatcher != null && card != null) { zoneChangeCounter = card.getZoneChangeCounter(game); @@ -97,13 +97,13 @@ class QuickenAsThoughEffect extends AsThoughEffectImpl { class QuickenWatcher extends Watcher { - public List activeQuickenSpells = new ArrayList<>(); + private List activeQuickenSpells = new ArrayList<>(); public QuickenWatcher() { - super(QuickenWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public QuickenWatcher(final QuickenWatcher watcher) { + private QuickenWatcher(final QuickenWatcher watcher) { super(watcher); } diff --git a/Mage.Sets/src/mage/cards/q/Quickling.java b/Mage.Sets/src/mage/cards/q/Quickling.java index abc6ffa7e7..4f409074ec 100644 --- a/Mage.Sets/src/mage/cards/q/Quickling.java +++ b/Mage.Sets/src/mage/cards/q/Quickling.java @@ -60,7 +60,7 @@ class QuicklingEffect extends OneShotEffect { private static final String effectText = "sacrifice it unless you return another creature you control to its owner's hand"; static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } QuicklingEffect() { diff --git a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java index 418f839664..5782524f16 100644 --- a/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java +++ b/Mage.Sets/src/mage/cards/q/QuicksilverFountain.java @@ -1,6 +1,6 @@ - package mage.cards.q; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -12,19 +12,24 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BecomesBasicLandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; import mage.counters.CounterType; import mage.filter.common.FilterLandPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.targetpointer.FixedTarget; - -import java.util.UUID; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; +import mage.target.targetpointer.FixedTarget; /** * @@ -32,42 +37,22 @@ import mage.target.common.TargetLandPermanent; */ public final class QuicksilverFountain extends CardImpl { - public final UUID originalId; - public QuicksilverFountain(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // At the beginning of each player's upkeep, that player puts a flood counter on target non-Island land he or she controls of their choice. That land is an Island for as long as it has a flood counter on it. Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new QuicksilverFountainEffect(), TargetController.ANY, false, true); ability.addTarget(new TargetLandPermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(QuicksilverFountainAdjuster.instance); this.addAbility(ability); // At the beginning of each end step, if all lands on the battlefield are Islands, remove all flood counters from them. Condition condition = new AllLandsAreSubtypeCondition(SubType.ISLAND); this.addAbility(new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new QuicksilverFountainEffect2(), TargetController.ANY, condition, false)); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Player activePlayer = game.getPlayer(game.getActivePlayerId()); - if (activePlayer != null) { - ability.getTargets().clear(); - FilterLandPermanent filter = new FilterLandPermanent(); - filter.add(Predicates.not(new SubtypePredicate(SubType.ISLAND))); - filter.add(new ControllerPredicate(TargetController.ACTIVE)); - TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, false); - target.setTargetController(activePlayer.getId()); - ability.getTargets().add(target); - } - } } public QuicksilverFountain(final QuicksilverFountain card) { super(card); - this.originalId = card.originalId; } @Override @@ -76,11 +61,29 @@ public final class QuicksilverFountain extends CardImpl { } } +enum QuicksilverFountainAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if (activePlayer != null) { + ability.getTargets().clear(); + FilterLandPermanent filter = new FilterLandPermanent(); + filter.add(Predicates.not(new SubtypePredicate(SubType.ISLAND))); + filter.add(new ControllerPredicate(TargetController.ACTIVE)); + TargetLandPermanent target = new TargetLandPermanent(1, 1, filter, false); + target.setTargetController(activePlayer.getId()); + ability.getTargets().add(target); + } + } +} + class QuicksilverFountainEffect extends OneShotEffect { public QuicksilverFountainEffect() { super(Outcome.Neutral); - staticText = "that player puts a flood counter on target non-Island land he or she controls of their choice. That land is an Island for as long as it has a flood counter on it"; + staticText = "that player puts a flood counter on target non-Island land they control of their choice. That land is an Island for as long as it has a flood counter on it"; } public QuicksilverFountainEffect(final QuicksilverFountainEffect effect) { diff --git a/Mage.Sets/src/mage/cards/q/QuietDisrepair.java b/Mage.Sets/src/mage/cards/q/QuietDisrepair.java index 2906000b21..f1837b8367 100644 --- a/Mage.Sets/src/mage/cards/q/QuietDisrepair.java +++ b/Mage.Sets/src/mage/cards/q/QuietDisrepair.java @@ -40,7 +40,7 @@ public final class QuietDisrepair extends CardImpl { // At the beginning of your upkeep, choose one - Destroy enchanted permanent; or you gain 2 life. ability = new BeginningOfUpkeepTriggeredAbility(new DestroyAttachedToEffect("enchanted permanent"), TargetController.YOU, false); Mode mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(2)); + mode.addEffect(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/q/QuietSpeculation.java b/Mage.Sets/src/mage/cards/q/QuietSpeculation.java index d189e274aa..9fafe47689 100644 --- a/Mage.Sets/src/mage/cards/q/QuietSpeculation.java +++ b/Mage.Sets/src/mage/cards/q/QuietSpeculation.java @@ -73,7 +73,7 @@ class SearchLibraryPutInGraveEffect extends SearchEffect { if (controller == null) { return false; } - if (targetPlayerID != null && controller.searchLibrary(target, game, targetPlayerID)) { + if (targetPlayerID != null && controller.searchLibrary(target, source, game, targetPlayerID)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(target.getTargets()); controller.revealCards("Quiet Speculation", cards, game); diff --git a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java index e98d72f803..5aa3ab8099 100644 --- a/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java +++ b/Mage.Sets/src/mage/cards/q/QuillmaneBaku.java @@ -1,4 +1,3 @@ - package mage.cards.q; import java.util.UUID; @@ -27,16 +26,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @author LevelX2 */ public final class QuillmaneBaku extends CardImpl { - private final UUID originalId; - public QuillmaneBaku(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(3); @@ -45,70 +43,70 @@ public final class QuillmaneBaku extends CardImpl { // Whenever you cast a Spirit or Arcane spell, you may put a ki counter on Skullmane Baku. this.addAbility(new SpellCastControllerTriggeredAbility(new AddCountersSourceEffect(CounterType.KI.createInstance()), StaticFilters.SPIRIT_OR_ARCANE_CARD, true)); - //TODO: Make ability properly copiable // {1}, Tap, Remove X ki counters from Quillmane Baku: Return target creature with converted mana cost X or less to its owner's hand. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new QuillmaneBakuReturnEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.KI.createInstance(1))); ability.addTarget(new TargetCreaturePermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(QuillmaneBakuAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - int maxConvManaCost = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof RemoveVariableCountersSourceCost) { - maxConvManaCost = ((RemoveVariableCountersSourceCost) cost).getAmount(); - } - } - ability.getTargets().clear(); - FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less"); - newFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxConvManaCost + 1)); - TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter); - ability.getTargets().add(target); - } - } - public QuillmaneBaku(final QuillmaneBaku card) { super(card); - this.originalId = card.originalId; } @Override public QuillmaneBaku copy() { return new QuillmaneBaku(this); } +} - static class QuillmaneBakuReturnEffect extends OneShotEffect { +enum QuillmaneBakuAdjuster implements TargetAdjuster { + instance; - public QuillmaneBakuReturnEffect() { - super(Outcome.ReturnToHand); - this.staticText = "Return target creature with converted mana cost X or less to its owner's hand"; - } - - public QuillmaneBakuReturnEffect(final QuillmaneBakuReturnEffect effect) { - super(effect); - } - - @Override - public QuillmaneBakuReturnEffect copy() { - return new QuillmaneBakuReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; + @Override + public void adjustTargets(Ability ability, Game game) { + int maxConvManaCost = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof RemoveVariableCountersSourceCost) { + maxConvManaCost = ((RemoveVariableCountersSourceCost) cost).getAmount(); } - Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (permanent != null) { - controller.moveCards(permanent, Zone.HAND, source, game); - } - return true; } + ability.getTargets().clear(); + FilterCreaturePermanent newFilter = new FilterCreaturePermanent("creature with converted mana cost " + maxConvManaCost + " or less"); + newFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxConvManaCost + 1)); + TargetCreaturePermanent target = new TargetCreaturePermanent(newFilter); + ability.getTargets().add(target); + } +} + +class QuillmaneBakuReturnEffect extends OneShotEffect { + + public QuillmaneBakuReturnEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return target creature with converted mana cost X or less to its owner's hand"; + } + + public QuillmaneBakuReturnEffect(final QuillmaneBakuReturnEffect effect) { + super(effect); + } + + @Override + public QuillmaneBakuReturnEffect copy() { + return new QuillmaneBakuReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent != null) { + controller.moveCards(permanent, Zone.HAND, source, game); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/q/Quillspike.java b/Mage.Sets/src/mage/cards/q/Quillspike.java index 4840111233..7b781ca8ac 100644 --- a/Mage.Sets/src/mage/cards/q/Quillspike.java +++ b/Mage.Sets/src/mage/cards/q/Quillspike.java @@ -15,6 +15,7 @@ import mage.constants.SubType; import mage.constants.Duration; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.target.TargetPermanent; @@ -34,13 +35,13 @@ public final class Quillspike extends CardImpl { // {BG}, Remove a -1/-1 counter from a creature you control: Quillspike gets +3/+3 until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(3, 3, Duration.EndOfTurn), new ManaCostsImpl("{B/G}")); - TargetPermanent target = new TargetPermanent(1, 1, new FilterControlledCreaturePermanent("creature you control"), true); + TargetPermanent target = new TargetPermanent(1, 1, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED, true); ability.addCost(new RemoveCounterCost(target, CounterType.M1M1)); this.addAbility(ability); } - public Quillspike(final Quillspike card) { + private Quillspike(final Quillspike card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/q/QuirionDruid.java b/Mage.Sets/src/mage/cards/q/QuirionDruid.java new file mode 100644 index 0000000000..f96dcb089b --- /dev/null +++ b/Mage.Sets/src/mage/cards/q/QuirionDruid.java @@ -0,0 +1,71 @@ +package mage.cards.q; + +import mage.MageInt; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BecomesCreatureTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.permanent.token.TokenImpl; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * + * @author jmharmon + */ + +public final class QuirionDruid extends CardImpl { + + public QuirionDruid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.DRUID); + + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {G}, {T}: Target land becomes a 2/2 green creature that’s still a land. (This effect lasts indefinitely.) + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BecomesCreatureTargetEffect(new QuirionDruidToken(), false, true, Duration.Custom), new ManaCostsImpl("{G}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetLandPermanent()); + this.addAbility(ability); + } + + public QuirionDruid(final QuirionDruid card) { + super(card); + } + + @Override + public QuirionDruid copy() { + return new QuirionDruid(this); + } +} + +class QuirionDruidToken extends TokenImpl { + + public QuirionDruidToken() { + super("", "2/2 green creature"); + this.color.addColor(ObjectColor.GREEN); + this.cardType.add(CardType.CREATURE); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + public QuirionDruidToken(final QuirionDruidToken token) { + super(token); + } + + public QuirionDruidToken copy() { + return new QuirionDruidToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RadiantArchangel.java b/Mage.Sets/src/mage/cards/r/RadiantArchangel.java index e75d2d19a8..263c3f9779 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantArchangel.java +++ b/Mage.Sets/src/mage/cards/r/RadiantArchangel.java @@ -29,7 +29,7 @@ public final class RadiantArchangel extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature with flying on the battlefield"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new AbilityPredicate(FlyingAbility.class)); } diff --git a/Mage.Sets/src/mage/cards/r/RadiantDestiny.java b/Mage.Sets/src/mage/cards/r/RadiantDestiny.java index f008dc39c4..b0b9bee031 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantDestiny.java +++ b/Mage.Sets/src/mage/cards/r/RadiantDestiny.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,26 +9,25 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.continuous.BoostAllOfChosenSubtypeEffect; import mage.abilities.effects.common.continuous.GainAbilityAllOfChosenSubtypeEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES_CONTROLLED; + /** - * * @author LevelX2 */ public final class RadiantDestiny extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); static { filter.add(new ControllerPredicate(TargetController.YOU)); @@ -52,6 +49,7 @@ public final class RadiantDestiny extends CardImpl { CitysBlessingCondition.instance, "As long as you have the city's blessing, they also have vigilance."); ability.addEffect(effect); + ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RadiantPurge.java b/Mage.Sets/src/mage/cards/r/RadiantPurge.java index 538c50c9ec..f4a393fd22 100644 --- a/Mage.Sets/src/mage/cards/r/RadiantPurge.java +++ b/Mage.Sets/src/mage/cards/r/RadiantPurge.java @@ -21,8 +21,8 @@ public final class RadiantPurge extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("multicolored creature or multicolored enchantment"); static { filter.add(Predicates.or( - Predicates.and(new CardTypePredicate(CardType.CREATURE), new MulticoloredPredicate()), - Predicates.and(new CardTypePredicate(CardType.ENCHANTMENT), new MulticoloredPredicate()))); + Predicates.and(new CardTypePredicate(CardType.CREATURE), MulticoloredPredicate.instance), + Predicates.and(new CardTypePredicate(CardType.ENCHANTMENT), MulticoloredPredicate.instance))); } public RadiantPurge(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RaffCapashenShipsMage.java b/Mage.Sets/src/mage/cards/r/RaffCapashenShipsMage.java index 599a30b642..1a399e4d41 100644 --- a/Mage.Sets/src/mage/cards/r/RaffCapashenShipsMage.java +++ b/Mage.Sets/src/mage/cards/r/RaffCapashenShipsMage.java @@ -26,7 +26,7 @@ public final class RaffCapashenShipsMage extends CardImpl { private static final FilterCard filter = new FilterCard("historic spells"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public RaffCapashenShipsMage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RafterDemon.java b/Mage.Sets/src/mage/cards/r/RafterDemon.java new file mode 100644 index 0000000000..10e7f1afef --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RafterDemon.java @@ -0,0 +1,53 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.SpectacleCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.discard.DiscardEachPlayerEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RafterDemon extends CardImpl { + + public RafterDemon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{R}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // Spectacle {3}{B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{3}{B}{R}"))); + + // When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DiscardEachPlayerEffect( + new StaticValue(1), false, TargetController.OPPONENT + )), SpectacleCondition.instance, + "When {this} enters the battlefield, " + + "if its spectacle cost was paid, " + + "each opponent discards a card." + )); + } + + public RafterDemon(final RafterDemon card) { + super(card); + } + + @Override + public RafterDemon copy() { + return new RafterDemon(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RageForger.java b/Mage.Sets/src/mage/cards/r/RageForger.java index b840f2e7fe..fb10108d1d 100644 --- a/Mage.Sets/src/mage/cards/r/RageForger.java +++ b/Mage.Sets/src/mage/cards/r/RageForger.java @@ -38,7 +38,7 @@ public final class RageForger extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SHAMAN)); filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filterAttack.add(new CounterPredicate(CounterType.P1P1)); } diff --git a/Mage.Sets/src/mage/cards/r/Ragefire.java b/Mage.Sets/src/mage/cards/r/Ragefire.java new file mode 100644 index 0000000000..4dbe92e704 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Ragefire.java @@ -0,0 +1,32 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Ragefire extends CardImpl { + + public Ragefire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}"); + + // Ragefire deals 3 damage to target creature. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Ragefire(final Ragefire card) { + super(card); + } + + @Override + public Ragefire copy() { + return new Ragefire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RagingKronch.java b/Mage.Sets/src/mage/cards/r/RagingKronch.java new file mode 100644 index 0000000000..6073012f68 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RagingKronch.java @@ -0,0 +1,36 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.keyword.CantAttackAloneAbility; +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 RagingKronch extends CardImpl { + + public RagingKronch(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Raging Kronch can't attack alone. + this.addAbility(new CantAttackAloneAbility()); + } + + private RagingKronch(final RagingKronch card) { + super(card); + } + + @Override + public RagingKronch copy() { + return new RagingKronch(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RagingSwordtooth.java b/Mage.Sets/src/mage/cards/r/RagingSwordtooth.java index 4b5253d56a..1363ae5ba0 100644 --- a/Mage.Sets/src/mage/cards/r/RagingSwordtooth.java +++ b/Mage.Sets/src/mage/cards/r/RagingSwordtooth.java @@ -19,10 +19,10 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class RagingSwordtooth extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RagingSwordtooth(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RagsRiches.java b/Mage.Sets/src/mage/cards/r/RagsRiches.java index 29033770e5..d8004b70a7 100644 --- a/Mage.Sets/src/mage/cards/r/RagsRiches.java +++ b/Mage.Sets/src/mage/cards/r/RagsRiches.java @@ -32,7 +32,7 @@ public final class RagsRiches extends SplitCard { // to // Riches // Each opponent chooses a creature he or she controls. You gain control of each of those creatures. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new RichesEffect()); } diff --git a/Mage.Sets/src/mage/cards/r/RaidingParty.java b/Mage.Sets/src/mage/cards/r/RaidingParty.java index 4ea934955a..9449c53670 100644 --- a/Mage.Sets/src/mage/cards/r/RaidingParty.java +++ b/Mage.Sets/src/mage/cards/r/RaidingParty.java @@ -73,7 +73,7 @@ class RaidingPartyEffect extends OneShotEffect { private static final FilterPermanent filter2 = new FilterPermanent("Plains"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ColorPredicate(ObjectColor.WHITE)); filter2.add(new SubtypePredicate(SubType.PLAINS)); } diff --git a/Mage.Sets/src/mage/cards/r/RainOfRust.java b/Mage.Sets/src/mage/cards/r/RainOfRust.java index f89ae7d9fb..641ff24a4f 100644 --- a/Mage.Sets/src/mage/cards/r/RainOfRust.java +++ b/Mage.Sets/src/mage/cards/r/RainOfRust.java @@ -26,8 +26,8 @@ public final class RainOfRust extends CardImpl { this.getSpellAbility().addTarget(new TargetArtifactPermanent()); //or destroy target land. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetLandPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetLandPermanent()); this.getSpellAbility().getModes().addMode(mode); // Entwine {3}{R} this.addAbility(new EntwineAbility("{3}{R}")); diff --git a/Mage.Sets/src/mage/cards/r/RainOfThorns.java b/Mage.Sets/src/mage/cards/r/RainOfThorns.java index c7553429fa..45c6aacf32 100644 --- a/Mage.Sets/src/mage/cards/r/RainOfThorns.java +++ b/Mage.Sets/src/mage/cards/r/RainOfThorns.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -11,31 +9,31 @@ import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetEnchantmentPermanent; import mage.target.common.TargetLandPermanent; -/** - * - * @author noxx +import java.util.UUID; +/** + * @author noxx */ public final class RainOfThorns extends CardImpl { public RainOfThorns(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); // Choose one or more - Destroy target artifact; destroy target enchantment; and/or destroy target land. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); this.getSpellAbility().getModes().setMaxModes(1); this.getSpellAbility().getModes().setMaxModes(3); Mode mode1 = new Mode(); - mode1.getEffects().add(new DestroyTargetEffect()); - mode1.getTargets().add(new TargetEnchantmentPermanent()); + mode1.addEffect(new DestroyTargetEffect()); + mode1.addTarget(new TargetEnchantmentPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); Mode mode2 = new Mode(); - mode2.getEffects().add(new DestroyTargetEffect()); - mode2.getTargets().add(new TargetLandPermanent()); + mode2.addEffect(new DestroyTargetEffect()); + mode2.addTarget(new TargetLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/r/RakdosAugermage.java b/Mage.Sets/src/mage/cards/r/RakdosAugermage.java index 422d4c3291..3fa747f9f5 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosAugermage.java +++ b/Mage.Sets/src/mage/cards/r/RakdosAugermage.java @@ -5,8 +5,6 @@ import mage.abilities.Ability; import mage.abilities.common.ActivateAsSorceryActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.RevealHandSourceControllerEffect; -import mage.abilities.effects.common.RevealHandTargetEffect; import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.*; @@ -23,14 +21,13 @@ import mage.target.common.TargetOpponent; import java.util.UUID; /** - * * @author noahg */ public final class RakdosAugermage extends CardImpl { public RakdosAugermage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{R}"); - + this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); this.power = new MageInt(3); @@ -71,16 +68,16 @@ class RakdosAugermageEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); if (player != null && controller != null) { Cards revealedCards = new CardsImpl(); revealedCards.addAll(controller.getHand()); - player.revealCards((sourceCard != null ? sourceCard.getIdName() + " (" + sourceCard.getZoneChangeCounter(game) + ") (" : "Discard (")+controller.getName()+")", revealedCards, game); + Card sourceCard = game.getCard(source.getSourceId()); + player.revealCards((sourceCard != null ? sourceCard.getIdName() + " (" + sourceCard.getZoneChangeCounter(game) + ") (" : "Discard (") + controller.getName() + ")", revealedCards, game); TargetCard target = new TargetCard(Zone.HAND, new FilterCard()); if (player.choose(Outcome.Benefit, revealedCards, target, game)) { Card card = revealedCards.get(target.getFirstTarget(), game); if (card != null) { - return player.discard(card, source, game); + return player.discard(card, source, game); } } } diff --git a/Mage.Sets/src/mage/cards/r/RakdosCharm.java b/Mage.Sets/src/mage/cards/r/RakdosCharm.java index 1b5cfc0191..ee46d6514b 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosCharm.java +++ b/Mage.Sets/src/mage/cards/r/RakdosCharm.java @@ -34,13 +34,13 @@ public final class RakdosCharm extends CardImpl { // or destroy target artifact; Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); // or each creature deals 1 damage to its controller. mode = new Mode(); - mode.getEffects().add(new RakdosCharmDamageEffect()); + mode.addEffect(new RakdosCharmDamageEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java new file mode 100644 index 0000000000..95b66c9ad0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosFirewheeler.java @@ -0,0 +1,49 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class RakdosFirewheeler extends CardImpl { + + public RakdosFirewheeler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{B}{R}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // When Rakdos Firewheeler enters the battlefield, it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker. + Effect effect = new DamageTargetEffect(2); + effect.setText("it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker"); + Ability ability = new EntersBattlefieldTriggeredAbility(effect, false); + ability.addTarget(new TargetOpponent()); + ability.addTarget(new TargetCreatureOrPlaneswalker(0, 1, new FilterCreatureOrPlaneswalkerPermanent(), false)); + this.addAbility(ability); + } + + public RakdosFirewheeler(final RakdosFirewheeler card) { + super(card); + } + + @Override + public RakdosFirewheeler copy() { + return new RakdosFirewheeler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdosLocket.java b/Mage.Sets/src/mage/cards/r/RakdosLocket.java new file mode 100644 index 0000000000..1af6807bde --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosLocket.java @@ -0,0 +1,46 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class RakdosLocket extends CardImpl { + + public RakdosLocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add {B} or {R}. + this.addAbility(new BlackManaAbility()); + this.addAbility(new RedManaAbility()); + + // {B/R}{B/R}{B/R}{B/R}, {T}, Sacrifice Rakdos Locket: Draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{B/R}{B/R}{B/R}{B/R}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public RakdosLocket(final RakdosLocket card) { + super(card); + } + + @Override + public RakdosLocket copy() { + return new RakdosLocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdosLordOfRiots.java b/Mage.Sets/src/mage/cards/r/RakdosLordOfRiots.java index 31d5b44e3d..37f5452921 100644 --- a/Mage.Sets/src/mage/cards/r/RakdosLordOfRiots.java +++ b/Mage.Sets/src/mage/cards/r/RakdosLordOfRiots.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -20,8 +18,9 @@ import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RakdosLordOfRiots extends CardImpl { @@ -84,9 +83,7 @@ class RakdosLordOfRiotsCantCastEffect extends ContinuousRuleModifyingEffectImpl @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getSourceId().equals(source.getSourceId())) { - if (new OpponentsLostLifeCount().calculate(game, source, this) == 0) { - return true; - } + return OpponentsLostLifeCount.instance.calculate(game, source, this) == 0; } return false; } @@ -105,10 +102,9 @@ class RakdosLordOfRiotsCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - Ability spellAbility = (SpellAbility) abilityToModify; + Ability spellAbility = abilityToModify; if (spellAbility != null) { - OpponentsLostLifeCount dynamicValue = new OpponentsLostLifeCount(); - int amount = dynamicValue.calculate(game, source, this); + int amount = OpponentsLostLifeCount.instance.calculate(game, source, this); if (amount > 0) { CardUtil.reduceCost(spellAbility, amount); return true; diff --git a/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java b/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java new file mode 100644 index 0000000000..301aed4e1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosRoustabout.java @@ -0,0 +1,79 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RakdosRoustabout extends CardImpl { + + public RakdosRoustabout(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Whenever Rakdos Roustabout becomes blocked, it deals 1 damage to the player or planeswalker its attacking. + this.addAbility(new RakdosRoustaboutAbility()); + } + + private RakdosRoustabout(final RakdosRoustabout card) { + super(card); + } + + @Override + public RakdosRoustabout copy() { + return new RakdosRoustabout(this); + } +} + +class RakdosRoustaboutAbility extends TriggeredAbilityImpl { + + RakdosRoustaboutAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(1)); + } + + private RakdosRoustaboutAbility(final RakdosRoustaboutAbility ability) { + super(ability); + } + + @Override + public RakdosRoustaboutAbility copy() { + return new RakdosRoustaboutAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CREATURE_BLOCKED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (sourceId.equals(event.getTargetId())) { + this.getEffects().get(0).setTargetPointer( + new FixedTarget(game.getCombat().getDefenderId(event.getTargetId()), game) + ); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} becomes blocked, it deals 1 damage to the player or planeswalker it’s attacking"; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdosTheShowstopper.java b/Mage.Sets/src/mage/cards/r/RakdosTheShowstopper.java new file mode 100644 index 0000000000..be9118e141 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosTheShowstopper.java @@ -0,0 +1,89 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RakdosTheShowstopper extends CardImpl { + + public RakdosTheShowstopper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.DEMON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Rakdos, the Showstopper enters the battlefield, flip a coin for each creature that isn't a Demon, Devil, or Imp. Destroy each creature whose coin comes up tails. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RakdosTheShowstopperEffect(), false)); + } + + private RakdosTheShowstopper(final RakdosTheShowstopper card) { + super(card); + } + + @Override + public RakdosTheShowstopper copy() { + return new RakdosTheShowstopper(this); + } +} + +class RakdosTheShowstopperEffect extends OneShotEffect { + + RakdosTheShowstopperEffect() { + super(Outcome.Benefit); + staticText = "flip a coin for each creature that isn't a Demon, Devil, or Imp." + + " Destroy each creature whose coin comes up tails."; + } + + private RakdosTheShowstopperEffect(final RakdosTheShowstopperEffect effect) { + super(effect); + } + + @Override + public RakdosTheShowstopperEffect copy() { + return new RakdosTheShowstopperEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (permanent != null + && permanent.isCreature() + && !permanent.hasSubtype(SubType.DEMON, game) + && !permanent.hasSubtype(SubType.DEVIL, game) + && !permanent.hasSubtype(SubType.IMP, game) + && !player.flipCoin(source, game, false)) { + permanent.destroy(source.getSourceId(), game, false); + } + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RakdosTrumpeter.java b/Mage.Sets/src/mage/cards/r/RakdosTrumpeter.java new file mode 100644 index 0000000000..a72d29d325 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RakdosTrumpeter.java @@ -0,0 +1,46 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.MenaceAbility; +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 RakdosTrumpeter extends CardImpl { + + public RakdosTrumpeter(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Menace + this.addAbility(new MenaceAbility()); + + // {3}{R}: Rakdos Trumpeter gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl("{3}{R}") + )); + } + + private RakdosTrumpeter(final RakdosTrumpeter card) { + super(card); + } + + @Override + public RakdosTrumpeter copy() { + return new RakdosTrumpeter(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RakdossReturn.java b/Mage.Sets/src/mage/cards/r/RakdossReturn.java index 5d9276caf3..a24d77837e 100644 --- a/Mage.Sets/src/mage/cards/r/RakdossReturn.java +++ b/Mage.Sets/src/mage/cards/r/RakdossReturn.java @@ -28,7 +28,7 @@ public final class RakdossReturn extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{R}"); // Rakdos's Return deals X damage to target opponent or planeswalker. That player or that planeswalker’s controller discards X cards. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addEffect(new RakdossReturnEffect()); this.getSpellAbility().addTarget(new TargetOpponentOrPlaneswalker()); } @@ -65,7 +65,7 @@ class RakdossReturnEffect extends OneShotEffect { if (player == null) { return false; } - Effect effect = new DiscardTargetEffect(new ManacostVariableValue()); + Effect effect = new DiscardTargetEffect(ManacostVariableValue.instance); effect.setTargetPointer(new FixedTarget(player.getId(), game)); return effect.apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/r/RakkaMar.java b/Mage.Sets/src/mage/cards/r/RakkaMar.java index 4e6f41225a..30db7aafab 100644 --- a/Mage.Sets/src/mage/cards/r/RakkaMar.java +++ b/Mage.Sets/src/mage/cards/r/RakkaMar.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -17,14 +16,13 @@ import mage.constants.SuperType; import mage.constants.Zone; import mage.game.permanent.token.RakkaMarElementalToken; +import java.util.UUID; + /** - * * @author Loki */ public final class RakkaMar extends CardImpl { - private RakkaMarElementalToken token = new RakkaMarElementalToken(); - public RakkaMar(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); addSuperType(SuperType.LEGENDARY); @@ -34,7 +32,12 @@ public final class RakkaMar extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(2); this.addAbility(HasteAbility.getInstance()); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CreateTokenEffect(token), new ManaCostsImpl("{R}")); + + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new CreateTokenEffect(new RakkaMarElementalToken()), + new ManaCostsImpl("{R}") + ); ability.addCost(new TapSourceCost()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RakshasaVizier.java b/Mage.Sets/src/mage/cards/r/RakshasaVizier.java index 955fc76258..d3722f81a0 100644 --- a/Mage.Sets/src/mage/cards/r/RakshasaVizier.java +++ b/Mage.Sets/src/mage/cards/r/RakshasaVizier.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.counter.AddCountersSourceEffect; @@ -14,29 +13,28 @@ import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; +import mage.game.events.ZoneChangeGroupEvent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class RakshasaVizier extends CardImpl { public RakshasaVizier(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{G}{U}"); + this.subtype.add(SubType.CAT); this.subtype.add(SubType.DEMON); - - this.power = new MageInt(4); this.toughness = new MageInt(4); // Whenever one or more cards are put into exile from your graveyard, put that many +1/+1 counters on Rakshasa Vizier. - // TODO: Handle effects that move more than one card with one trigger (e.g. if opponent want to counter a trigger, he has now to counter multiple instead of one). this.addAbility(new RakshasaVizierTriggeredAbility()); } - public RakshasaVizier(final RakshasaVizier card) { + private RakshasaVizier(final RakshasaVizier card) { super(card); } @@ -48,29 +46,38 @@ public final class RakshasaVizier extends CardImpl { class RakshasaVizierTriggeredAbility extends TriggeredAbilityImpl { - public RakshasaVizierTriggeredAbility() { + RakshasaVizierTriggeredAbility() { super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false); } - public RakshasaVizierTriggeredAbility(final RakshasaVizierTriggeredAbility ability) { + private RakshasaVizierTriggeredAbility(final RakshasaVizierTriggeredAbility ability) { super(ability); } @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; + return event.getType() == GameEvent.EventType.ZONE_CHANGE_GROUP; } @Override public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.GRAVEYARD - && zEvent.getToZone() == Zone.EXILED) { - Card card = game.getCard(event.getTargetId()); - if (card != null && card.isOwnedBy(getControllerId())) { - return true; + ZoneChangeGroupEvent zEvent = (ZoneChangeGroupEvent) event; + if (zEvent != null + && Zone.GRAVEYARD == zEvent.getFromZone() + && Zone.EXILED == zEvent.getToZone() + && zEvent.getCards() != null) { + int cardCount = 0; + for (Card card : zEvent.getCards()) { + if (card != null && card.isOwnedBy(getControllerId())) { + cardCount++; + } } - + if (cardCount == 0) { + return false; + } + this.getEffects().clear(); + this.getEffects().add(new AddCountersSourceEffect(CounterType.P1P1.createInstance(cardCount))); + return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/r/RalStormConduit.java b/Mage.Sets/src/mage/cards/r/RalStormConduit.java new file mode 100644 index 0000000000..ca9a9e2911 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RalStormConduit.java @@ -0,0 +1,138 @@ +package mage.cards.r; + +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyTargetSpellEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +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.TargetOpponentOrPlaneswalker; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RalStormConduit extends CardImpl { + + public RalStormConduit(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{U}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.RAL); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Whenever you cast or copy an instant or sorcery spell, Ral, Storm Conduit deals 1 damage to target opponent or planeswalker. + this.addAbility(new RalStormConduitTriggeredAbility()); + + // +2: Scry 1. + this.addAbility(new LoyaltyAbility(new ScryEffect(1), 2)); + + // -2: When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy. + this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect( + new RalStormConduitDelayedTriggeredAbility() + ).setText("When you cast your next instant or sorcery spell this turn, " + + "copy that spell. You may choose new targets for the copy" + ), -2)); + } + + private RalStormConduit(final RalStormConduit card) { + super(card); + } + + @Override + public RalStormConduit copy() { + return new RalStormConduit(this); + } +} + +class RalStormConduitTriggeredAbility extends TriggeredAbilityImpl { + + RalStormConduitTriggeredAbility() { + super(Zone.BATTLEFIELD, new DamageTargetEffect(1), false); + this.addTarget(new TargetOpponentOrPlaneswalker()); + } + + private RalStormConduitTriggeredAbility(final RalStormConduitTriggeredAbility effect) { + super(effect); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + switch (event.getType()) { + case COPIED_STACKOBJECT: + case SPELL_CAST: + return true; + default: + return false; + } + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Spell spell = game.getSpell(event.getTargetId()); + return spell != null && spell.isControlledBy(getControllerId()) && spell.isInstantOrSorcery(); + } + + @Override + public RalStormConduitTriggeredAbility copy() { + return new RalStormConduitTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever you cast or copy an instant or sorcery spell, " + + "{this} deals 1 damage to target opponent or planeswalker."; + } +} + +class RalStormConduitDelayedTriggeredAbility extends DelayedTriggeredAbility { + + RalStormConduitDelayedTriggeredAbility() { + super(new CopyTargetSpellEffect(true), Duration.EndOfTurn); + } + + private RalStormConduitDelayedTriggeredAbility(final RalStormConduitDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public RalStormConduitDelayedTriggeredAbility copy() { + return new RalStormConduitDelayedTriggeredAbility(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 (event.getPlayerId().equals(this.getControllerId())) { + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell != null && (spell.isInstant() || spell.isSorcery())) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When you cast your next instant or sorcery spell this turn, " + + "copy that spell. You may choose new targets for the copy."; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RalZarek.java b/Mage.Sets/src/mage/cards/r/RalZarek.java index 2dfe8cf9b6..23073717b2 100644 --- a/Mage.Sets/src/mage/cards/r/RalZarek.java +++ b/Mage.Sets/src/mage/cards/r/RalZarek.java @@ -99,7 +99,7 @@ class RalZarekExtraTurnsEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { for (int i = 0; i < 5; i++) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, false)) { game.getState().getTurnMods().add(new TurnMod(source.getControllerId(), false)); } } diff --git a/Mage.Sets/src/mage/cards/r/RallyOfWings.java b/Mage.Sets/src/mage/cards/r/RallyOfWings.java new file mode 100644 index 0000000000..f63a6ca6b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RallyOfWings.java @@ -0,0 +1,47 @@ +package mage.cards.r; + +import mage.abilities.effects.common.UntapAllControllerEffect; +import mage.abilities.effects.common.continuous.BoostAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RallyOfWings extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("Creatures you control with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public RallyOfWings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Untap all creatures you control. Creatures you control with flying get +2/+2 until end of turn. + this.getSpellAbility().addEffect(new UntapAllControllerEffect(StaticFilters.FILTER_PERMANENT_CREATURES)); + this.getSpellAbility().addEffect(new BoostAllEffect(2, 2, Duration.EndOfTurn, filter, false)); + } + + private RallyOfWings(final RallyOfWings card) { + super(card); + } + + @Override + public RallyOfWings copy() { + return new RallyOfWings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RallyToBattle.java b/Mage.Sets/src/mage/cards/r/RallyToBattle.java new file mode 100644 index 0000000000..6fce2ef673 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RallyToBattle.java @@ -0,0 +1,39 @@ +package mage.cards.r; + +import mage.abilities.effects.common.UntapAllControllerEffect; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RallyToBattle extends CardImpl { + + public RallyToBattle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); + + + // Creatures you control get +1/+3 until end of turn. Untap them. + this.getSpellAbility().addEffect( + new BoostControlledEffect(1, 3, Duration.EndOfTurn) + ); + this.getSpellAbility().addEffect(new UntapAllControllerEffect( + StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("Untap them")); + } + + private RallyToBattle(final RallyToBattle card) { + super(card); + } + + @Override + public RallyToBattle copy() { + return new RallyToBattle(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RalsDispersal.java b/Mage.Sets/src/mage/cards/r/RalsDispersal.java index 4747d592aa..224d594843 100644 --- a/Mage.Sets/src/mage/cards/r/RalsDispersal.java +++ b/Mage.Sets/src/mage/cards/r/RalsDispersal.java @@ -16,7 +16,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class RalsDispersal extends CardImpl { - private final static FilterCard filter = new FilterCard("Ral, Caller of Storms"); + private static final FilterCard filter = new FilterCard("Ral, Caller of Storms"); static { filter.add(new NamePredicate("Ral, Caller of Storms")); diff --git a/Mage.Sets/src/mage/cards/r/RalsOutburst.java b/Mage.Sets/src/mage/cards/r/RalsOutburst.java new file mode 100644 index 0000000000..40944d7951 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RalsOutburst.java @@ -0,0 +1,40 @@ +package mage.cards.r; + +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RalsOutburst extends CardImpl { + + public RalsOutburst(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{R}"); + + // Ral's Outburst deals 3 damage to any target. Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(2), false, new StaticValue(1), + StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false + )); + } + + private RalsOutburst(final RalsOutburst card) { + super(card); + } + + @Override + public RalsOutburst copy() { + return new RalsOutburst(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RalsStaticaster.java b/Mage.Sets/src/mage/cards/r/RalsStaticaster.java index d5b83f2540..87de152208 100644 --- a/Mage.Sets/src/mage/cards/r/RalsStaticaster.java +++ b/Mage.Sets/src/mage/cards/r/RalsStaticaster.java @@ -48,7 +48,7 @@ public final class RalsStaticaster extends CardImpl { // Whenever Ral's Staticaster attacks, if you control a Ral planeswalker, Ral's Staticaster gets +1/+0 for each card in your hand until end of turn. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new AttacksTriggeredAbility(new BoostSourceEffect( - new CardsInControllerHandCount(), new StaticValue(0), + CardsInControllerHandCount.instance, new StaticValue(0), Duration.EndOfTurn, true), false), new PermanentsOnTheBattlefieldCondition(filter), "Whenever {this} attacks, if you control a Ral planeswalker, " diff --git a/Mage.Sets/src/mage/cards/r/RamosianRally.java b/Mage.Sets/src/mage/cards/r/RamosianRally.java index ccd2a9213d..6f9b2d78da 100644 --- a/Mage.Sets/src/mage/cards/r/RamosianRally.java +++ b/Mage.Sets/src/mage/cards/r/RamosianRally.java @@ -29,7 +29,7 @@ public final class RamosianRally extends CardImpl { static { plainsFilter.add(new SubtypePredicate(SubType.PLAINS)); - creatureFilter.add(Predicates.not(new TappedPredicate())); + creatureFilter.add(Predicates.not(TappedPredicate.instance)); } public RamosianRally(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java b/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java new file mode 100644 index 0000000000..0d1c4fa05e --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampageOfTheClans.java @@ -0,0 +1,77 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.CentaurToken; +import mage.game.permanent.token.Token; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RampageOfTheClans extends CardImpl { + + public RampageOfTheClans(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}"); + + // Destroy all artifacts and enchantments. For each permanent destroyed this way, its controller creates a 3/3 green Centaur creature token. + this.getSpellAbility().addEffect(new RampageOfTheClansEffect()); + } + + private RampageOfTheClans(final RampageOfTheClans card) { + super(card); + } + + @Override + public RampageOfTheClans copy() { + return new RampageOfTheClans(this); + } +} + +class RampageOfTheClansEffect extends OneShotEffect { + + RampageOfTheClansEffect() { + super(Outcome.Benefit); + staticText = "Destroy all artifacts and enchantments. " + + "For each permanent destroyed this way, " + + "its controller creates a 3/3 green Centaur creature token."; + } + + private RampageOfTheClansEffect(final RampageOfTheClansEffect effect) { + super(effect); + } + + @Override + public RampageOfTheClansEffect copy() { + return new RampageOfTheClansEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Map playersWithPermanents = new HashMap<>(); + for (Permanent p : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT, + source.getControllerId(), source.getSourceId(), game + )) { + UUID controllerId = p.getControllerId(); + if (p.destroy(source.getSourceId(), game, false)) { + playersWithPermanents.put(controllerId, playersWithPermanents.getOrDefault(controllerId, 0) + 1); + } + } + Token token = new CentaurToken(); + for (Map.Entry amountDestroyedByPlayer : playersWithPermanents.entrySet()) { + token.putOntoBattlefield(amountDestroyedByPlayer.getValue(), game, source.getSourceId(), amountDestroyedByPlayer.getKey()); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java index f0403fa010..939e7eea41 100644 --- a/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java +++ b/Mage.Sets/src/mage/cards/r/RampagingFerocidon.java @@ -34,7 +34,7 @@ public final class RampagingFerocidon extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RampagingFerocidon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RampagingRendhorn.java b/Mage.Sets/src/mage/cards/r/RampagingRendhorn.java new file mode 100644 index 0000000000..eac81672fd --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RampagingRendhorn.java @@ -0,0 +1,36 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.keyword.RiotAbility; +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 RampagingRendhorn extends CardImpl { + + public RampagingRendhorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Riot + this.addAbility(new RiotAbility()); + } + + private RampagingRendhorn(final RampagingRendhorn card) { + super(card); + } + + @Override + public RampagingRendhorn copy() { + return new RampagingRendhorn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/Ramroller.java b/Mage.Sets/src/mage/cards/r/Ramroller.java index f2574f0484..297bd6a615 100644 --- a/Mage.Sets/src/mage/cards/r/Ramroller.java +++ b/Mage.Sets/src/mage/cards/r/Ramroller.java @@ -27,7 +27,7 @@ public final class Ramroller extends CardImpl { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Ramroller(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RamsesOverdark.java b/Mage.Sets/src/mage/cards/r/RamsesOverdark.java index 2ed9c824f4..43475b29cb 100644 --- a/Mage.Sets/src/mage/cards/r/RamsesOverdark.java +++ b/Mage.Sets/src/mage/cards/r/RamsesOverdark.java @@ -26,7 +26,7 @@ public final class RamsesOverdark extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("enchanted creature"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); } public RamsesOverdark(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RamunapHydra.java b/Mage.Sets/src/mage/cards/r/RamunapHydra.java index 7e74d67d64..38a86af768 100644 --- a/Mage.Sets/src/mage/cards/r/RamunapHydra.java +++ b/Mage.Sets/src/mage/cards/r/RamunapHydra.java @@ -68,7 +68,7 @@ public final class RamunapHydra extends CardImpl { class RamunapHydraBoostEffect extends WhileConditionContinuousEffect { - private final static FilterCard filter = new FilterCard("a Desert"); + private static final FilterCard filter = new FilterCard("a Desert"); static { filter.add(new SubtypePredicate(SubType.DESERT)); diff --git a/Mage.Sets/src/mage/cards/r/Ransack.java b/Mage.Sets/src/mage/cards/r/Ransack.java new file mode 100644 index 0000000000..4fe3889c39 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Ransack.java @@ -0,0 +1,87 @@ +package mage.cards.r; + +import static java.lang.Integer.min; +import java.util.Set; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPlayer; + +/** + * + * @author jeffwadsworth + */ +public final class Ransack extends CardImpl { + + public Ransack(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); + + // Look at the top five cards of target player's library. + //Put any number of them on the bottom of that library in any order + //and the rest on top of the library in any order. + this.getSpellAbility().addEffect(new RansackEffect()); + this.getSpellAbility().addTarget(new TargetPlayer()); + + } + + public Ransack(final Ransack card) { + super(card); + } + + @Override + public Ransack copy() { + return new Ransack(this); + } +} + +class RansackEffect extends OneShotEffect { + + public RansackEffect() { + super(Outcome.Detriment); + this.staticText = "Look at the top five cards of target player's library. " + + "Put any number of them on the bottom of that library in any order " + + "and the rest on top of the library in any order"; + } + + public RansackEffect(final RansackEffect effect) { + super(effect); + } + + @Override + public RansackEffect copy() { + return new RansackEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + FilterCard filter = new FilterCard("cards to put on the bottom of your library"); + if (player != null) { + int number = min(player.getLibrary().size(), 5); + Set cards = player.getLibrary().getTopCards(game, number); + Cards cardsRemaining = new CardsImpl(); + cardsRemaining.addAll(cards); + TargetCard target = new TargetCard(0, number, Zone.LIBRARY, filter); + if (player.choose(Outcome.DrawCard, cardsRemaining, target, game)) { + Cards pickedCards = new CardsImpl(target.getTargets()); + cardsRemaining.removeAll(pickedCards); + player.putCardsOnBottomOfLibrary(pickedCards, game, source, true); + player.putCardsOnTopOfLibrary(cardsRemaining, game, source, true); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RapidFire.java b/Mage.Sets/src/mage/cards/r/RapidFire.java new file mode 100644 index 0000000000..a57b9181ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RapidFire.java @@ -0,0 +1,82 @@ + +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; +import mage.abilities.condition.common.BeforeBlockersAreDeclaredCondition; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.RampageAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author L_J + */ +public final class RapidFire extends CardImpl { + + public RapidFire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{W}"); + + // Cast this spell only before blockers are declared. + this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(null, null, BeforeBlockersAreDeclaredCondition.instance, "Cast this spell only before blockers are declared")); + + // Target creature gains first strike until end of turn. If it doesn’t have rampage, that creature gains rampage 2 until end of turn. + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new RapidFireEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + + } + + public RapidFire(final RapidFire card) { + super(card); + } + + @Override + public RapidFire copy() { + return new RapidFire(this); + } + +} + +class RapidFireEffect extends OneShotEffect { + + public RapidFireEffect() { + super(Outcome.AddAbility); + this.staticText = "If it doesn’t have rampage, that creature gains rampage 2 until end of turn"; + } + + public RapidFireEffect(final RapidFireEffect effect) { + super(effect); + } + + @Override + public RapidFireEffect copy() { + return new RapidFireEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (controller != null && permanent != null) { + if (!permanent.getAbilities().containsClass(RampageAbility.class)) { + ContinuousEffect effect = new GainAbilityTargetEffect(new RampageAbility(2), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RapidHybridization.java b/Mage.Sets/src/mage/cards/r/RapidHybridization.java index c86b017c12..5c157eeb92 100644 --- a/Mage.Sets/src/mage/cards/r/RapidHybridization.java +++ b/Mage.Sets/src/mage/cards/r/RapidHybridization.java @@ -11,7 +11,7 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.RapidHybridizationToken; +import mage.game.permanent.token.FrogLizardToken; import mage.target.common.TargetCreaturePermanent; /** @@ -59,7 +59,7 @@ class RapidHybridizationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); if (permanent != null) { - RapidHybridizationToken token = new RapidHybridizationToken(); + FrogLizardToken token = new FrogLizardToken(); token.putOntoBattlefield(1, game, source.getSourceId(), permanent.getControllerId()); } return true; diff --git a/Mage.Sets/src/mage/cards/r/RashidaScalebane.java b/Mage.Sets/src/mage/cards/r/RashidaScalebane.java index 8e2de6b48a..af3c5daf3d 100644 --- a/Mage.Sets/src/mage/cards/r/RashidaScalebane.java +++ b/Mage.Sets/src/mage/cards/r/RashidaScalebane.java @@ -32,7 +32,7 @@ public final class RashidaScalebane extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking or blocking Dragon"); static { - filter.add(Predicates.or(new AttackingPredicate(), new BlockingPredicate())); + filter.add(Predicates.or(AttackingPredicate.instance, BlockingPredicate.instance)); filter.add(new SubtypePredicate(SubType.DRAGON)); } @@ -46,7 +46,7 @@ public final class RashidaScalebane extends CardImpl { // {tap}: Destroy target attacking or blocking Dragon. It can't be regenerated. You gain life equal to its power. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DestroyTargetEffect(true), new TapSourceCost()); - Effect effect = new GainLifeEffect(new TargetPermanentPowerCount()); + Effect effect = new GainLifeEffect(TargetPermanentPowerCount.instance); effect.setText("You gain life equal to its power"); ability.addEffect(effect); ability.addTarget(new TargetCreaturePermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java index d55cf3b457..6a09ed4940 100644 --- a/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java +++ b/Mage.Sets/src/mage/cards/r/RashmiEternitiesCrafter.java @@ -70,7 +70,7 @@ class RashmiEternitiesCrafterTriggeredAbility extends SpellCastControllerTrigger @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(event.getPlayerId()); if (spells != null && spells.size() == 1) { diff --git a/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java b/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java index 36a1b7cc43..73f4feebf4 100644 --- a/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java +++ b/Mage.Sets/src/mage/cards/r/RasputinDreamweaver.java @@ -80,7 +80,7 @@ enum RasputinDreamweaverStartedUntappedCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - RasputinDreamweaverStartedUntappedWatcher watcher = (RasputinDreamweaverStartedUntappedWatcher) game.getState().getWatchers().get(RasputinDreamweaverStartedUntappedWatcher.class.getSimpleName()); + RasputinDreamweaverStartedUntappedWatcher watcher = game.getState().getWatcher(RasputinDreamweaverStartedUntappedWatcher.class); if (watcher != null) { return watcher.startedUntapped(source.getSourceId()); } @@ -98,13 +98,13 @@ class RasputinDreamweaverStartedUntappedWatcher extends Watcher { private static final FilterPermanent filter = new FilterPermanent("Untapped permanents"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } private final Set startedUntapped = new HashSet<>(0); RasputinDreamweaverStartedUntappedWatcher() { - super(RasputinDreamweaverStartedUntappedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } RasputinDreamweaverStartedUntappedWatcher(final RasputinDreamweaverStartedUntappedWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/r/RatColony.java b/Mage.Sets/src/mage/cards/r/RatColony.java index fefee4c814..86b6a1d5c2 100644 --- a/Mage.Sets/src/mage/cards/r/RatColony.java +++ b/Mage.Sets/src/mage/cards/r/RatColony.java @@ -28,7 +28,7 @@ public final class RatColony extends CardImpl { static { filter.add(new SubtypePredicate(SubType.RAT)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RatColony(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RathiAssassin.java b/Mage.Sets/src/mage/cards/r/RathiAssassin.java index cb3f077059..07655c7778 100644 --- a/Mage.Sets/src/mage/cards/r/RathiAssassin.java +++ b/Mage.Sets/src/mage/cards/r/RathiAssassin.java @@ -39,7 +39,7 @@ public final class RathiAssassin extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MERCENARY)); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); - destroyFilter.add(new TappedPredicate()); + destroyFilter.add(TappedPredicate.instance); destroyFilter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); } diff --git a/Mage.Sets/src/mage/cards/r/RatsFeast.java b/Mage.Sets/src/mage/cards/r/RatsFeast.java new file mode 100644 index 0000000000..395650b520 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RatsFeast.java @@ -0,0 +1,49 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.target.common.TargetCardInASingleGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RatsFeast extends CardImpl { + + public RatsFeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}"); + + // Exile X target cards from a single graveyard. + this.getSpellAbility().addEffect(new ExileTargetEffect( + "Exile X target cards from a single graveyard.", true + )); + this.getSpellAbility().setTargetAdjuster(RatsFeastAdjuster.instance); + } + + private RatsFeast(final RatsFeast card) { + super(card); + } + + @Override + public RatsFeast copy() { + return new RatsFeast(this); + } +} + +enum RatsFeastAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInASingleGraveyard(xValue, xValue, StaticFilters.FILTER_CARD)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RavagerWurm.java b/Mage.Sets/src/mage/cards/r/RavagerWurm.java new file mode 100644 index 0000000000..f8af6558fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RavagerWurm.java @@ -0,0 +1,92 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.FightTargetSourceEffect; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AbilityType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RavagerWurm extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature you don't control"); + private static final FilterPermanent filter2 + = new FilterPermanent("land with an activated ability that isn't a mana ability"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + filter2.add(RavagerWurmPredicate.instance); + } + + public RavagerWurm(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{G}{G}"); + + this.subtype.add(SubType.WURM); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Riot + this.addAbility(new RiotAbility()); + + // When Ravager Wurm enters the battlefield, choose up to one — + // • Ravager Wurm fights target creature you don't control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new FightTargetSourceEffect().setText("{this} fights target creature you don't control"), false + ); + ability.addTarget(new TargetPermanent(filter)); + ability.getModes().setMinModes(0); + ability.getModes().setMaxModes(1); + + // • Destroy target land with an activated ability that isn't a mana ability. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter2)); + ability.addMode(mode); + this.addAbility(ability); + } + + private RavagerWurm(final RavagerWurm card) { + super(card); + } + + @Override + public RavagerWurm copy() { + return new RavagerWurm(this); + } +} + +enum RavagerWurmPredicate implements Predicate { + instance; + + @Override + public boolean apply(Permanent input, Game game) { + if (input == null || !input.isLand()) { + return false; + } + for (Ability ability : input.getAbilities()) { + if (ability.getAbilityType() == AbilityType.ACTIVATED) { + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RavagingBlaze.java b/Mage.Sets/src/mage/cards/r/RavagingBlaze.java index 6a85da0180..4b8f4e7f45 100644 --- a/Mage.Sets/src/mage/cards/r/RavagingBlaze.java +++ b/Mage.Sets/src/mage/cards/r/RavagingBlaze.java @@ -22,10 +22,10 @@ public final class RavagingBlaze extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{R}{R}"); // Ravaging Blaze deals X damage to target creature. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller. - this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetControllerEffect(new ManacostVariableValue()), + this.getSpellAbility().addEffect(new ConditionalOneShotEffect(new DamageTargetControllerEffect(ManacostVariableValue.instance), SpellMasteryCondition.instance, "
    Spell mastery — If there are two or more instant and/or sorcery cards in your graveyard, Ravaging Blaze also deals X damage to that creature's controller.")); } diff --git a/Mage.Sets/src/mage/cards/r/RavenousTrap.java b/Mage.Sets/src/mage/cards/r/RavenousTrap.java index c1f31a0fda..6ae2a950f7 100644 --- a/Mage.Sets/src/mage/cards/r/RavenousTrap.java +++ b/Mage.Sets/src/mage/cards/r/RavenousTrap.java @@ -50,7 +50,7 @@ enum RavenousTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { if (watcher.getAmountCardsPutToGraveyard(opponentId) > 2) { diff --git a/Mage.Sets/src/mage/cards/r/RavnicaAtWar.java b/Mage.Sets/src/mage/cards/r/RavnicaAtWar.java new file mode 100644 index 0000000000..4fde6d2102 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RavnicaAtWar.java @@ -0,0 +1,38 @@ +package mage.cards.r; + +import mage.abilities.effects.common.ExileAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.MulticoloredPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RavnicaAtWar extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("multicolored permanents"); + + static { + filter.add(MulticoloredPredicate.instance); + } + + public RavnicaAtWar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}"); + + // Exile all multicolored permanents. + this.getSpellAbility().addEffect(new ExileAllEffect(filter)); + } + + private RavnicaAtWar(final RavnicaAtWar card) { + super(card); + } + + @Override + public RavnicaAtWar copy() { + return new RavnicaAtWar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RaziasPurification.java b/Mage.Sets/src/mage/cards/r/RaziasPurification.java index 56ba6553e5..dc9c802b80 100644 --- a/Mage.Sets/src/mage/cards/r/RaziasPurification.java +++ b/Mage.Sets/src/mage/cards/r/RaziasPurification.java @@ -61,7 +61,7 @@ class RaziasPurificationEffect extends OneShotEffect { Target target1 = new TargetControlledPermanent(1, 1, new FilterControlledPermanent(), true); - if (target1.canChoose(player.getId(), game)) { + if (player != null && target1.canChoose(player.getId(), game)) { int chosenPermanents = 0; while (player.canRespond() && !target1.isChosen() && target1.canChoose(player.getId(), game) && chosenPermanents < 3) { player.chooseTarget(Outcome.Benefit, target1, source, game); diff --git a/Mage.Sets/src/mage/cards/r/RazorPendulum.java b/Mage.Sets/src/mage/cards/r/RazorPendulum.java new file mode 100644 index 0000000000..0c5d1f7151 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RazorPendulum.java @@ -0,0 +1,82 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RazorPendulum extends CardImpl { + + public RazorPendulum(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); + + + // At the beginning of each player’s end step, if that player has 5 or less life, Razor Pendulum deals 2 damage to that player. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfEndStepTriggeredAbility( + new RazorPendulumEffect(), TargetController.ANY, false + ), RazorPendulumCondition.instance, "At the beginning of each player's end step, " + + "if that player has 5 or less life, {this} deals 2 damage to that player." + )); + } + + private RazorPendulum(final RazorPendulum card) { + super(card); + } + + @Override + public RazorPendulum copy() { + return new RazorPendulum(this); + } +} + +class RazorPendulumEffect extends OneShotEffect { + + RazorPendulumEffect() { + super(Outcome.Benefit); + } + + private RazorPendulumEffect(final RazorPendulumEffect effect) { + super(effect); + } + + @Override + public RazorPendulumEffect copy() { + return new RazorPendulumEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + return false; + } + return player.damage(2, source.getSourceId(), game) > 0; + } +} + +enum RazorPendulumCondition implements Condition { + instance; + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + return false; + } + return player.getLife() < 6; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java b/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java index d4384fe277..e1bc066563 100644 --- a/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java +++ b/Mage.Sets/src/mage/cards/r/RazorfinAbolisher.java @@ -27,7 +27,7 @@ public final class RazorfinAbolisher extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with a counter on it"); static { - filter.add(new CounterAnyPredicate()); + filter.add(CounterAnyPredicate.instance); } public RazorfinAbolisher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/ReachOfShadows.java b/Mage.Sets/src/mage/cards/r/ReachOfShadows.java index 60c5d7b24a..0f697be957 100644 --- a/Mage.Sets/src/mage/cards/r/ReachOfShadows.java +++ b/Mage.Sets/src/mage/cards/r/ReachOfShadows.java @@ -20,7 +20,7 @@ public final class ReachOfShadows extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that's one or more colors"); static { - filter.add(Predicates.not(new ColorlessPredicate())); + filter.add(Predicates.not(ColorlessPredicate.instance)); } public ReachOfShadows(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RealitySpasm.java b/Mage.Sets/src/mage/cards/r/RealitySpasm.java index 43dc46c176..3d016b3fd9 100644 --- a/Mage.Sets/src/mage/cards/r/RealitySpasm.java +++ b/Mage.Sets/src/mage/cards/r/RealitySpasm.java @@ -28,7 +28,7 @@ public final class RealitySpasm extends CardImpl { // Choose one - Tap X target permanents; or untap X target permanents. this.getSpellAbility().addEffect(new RealitySpasmTapEffect()); Mode mode = new Mode(); - mode.getEffects().add(new RealitySpasmUntapEffect()); + mode.addEffect(new RealitySpasmUntapEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RealmSeekers.java b/Mage.Sets/src/mage/cards/r/RealmSeekers.java index 283fff9287..5ac43f2142 100644 --- a/Mage.Sets/src/mage/cards/r/RealmSeekers.java +++ b/Mage.Sets/src/mage/cards/r/RealmSeekers.java @@ -37,7 +37,7 @@ public final class RealmSeekers extends CardImpl { this.addAbility(new EntersBattlefieldAbility( new AddCountersSourceEffect( CounterType.P1P1.createInstance(), - new CardsInAllHandsCount(), + CardsInAllHandsCount.instance, false), "with X +1/+1 counters on it, where X is the total number of cards in all players' hands")); diff --git a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java index 0e7f04e6e3..399fb4494f 100644 --- a/Mage.Sets/src/mage/cards/r/RealmsUncharted.java +++ b/Mage.Sets/src/mage/cards/r/RealmsUncharted.java @@ -71,7 +71,7 @@ class RealmsUnchartedEffect extends OneShotEffect { } RealmsUnchartedTarget target = new RealmsUnchartedTarget(); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/r/Reanimate.java b/Mage.Sets/src/mage/cards/r/Reanimate.java index 3a70eaa36e..d91e2ad3e4 100644 --- a/Mage.Sets/src/mage/cards/r/Reanimate.java +++ b/Mage.Sets/src/mage/cards/r/Reanimate.java @@ -25,7 +25,7 @@ public final class Reanimate extends CardImpl { // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterCreatureCard("creature card from a graveyard"))); getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - Effect effect = new LoseLifeSourceControllerEffect(new TargetConvertedManaCost()); + Effect effect = new LoseLifeSourceControllerEffect(TargetConvertedManaCost.instance); effect.setText("You lose life equal to its converted mana cost"); getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/r/Reap.java b/Mage.Sets/src/mage/cards/r/Reap.java index 36d4d1baf6..f3db1b97ec 100644 --- a/Mage.Sets/src/mage/cards/r/Reap.java +++ b/Mage.Sets/src/mage/cards/r/Reap.java @@ -1,63 +1,40 @@ package mage.cards.r; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; -import mage.game.Game; import mage.filter.FilterCard; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetOpponent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author L_J */ public final class Reap extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("black permanents"); - - static { - filter.add(new ColorPredicate(ObjectColor.BLACK)); - } public Reap(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect().setText("Return up to X target cards from your graveyard to your hand, where X is the number of black permanents target opponent controls as you cast Reap.")); this.getSpellAbility().addTarget(new TargetOpponent()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 0, new FilterCard("cards from your graveyard"))); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 0)); + this.getSpellAbility().setTargetAdjuster(ReapAdjuster.instance); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null) { - ability.getTargets().clear(); - UUID opponentId = null; - Target target = new TargetOpponent(); - if (controller.chooseTarget(Outcome.ReturnToHand, target, ability, game)) { - opponentId = target.getFirstTarget(); - } - int numbTargets = game.getBattlefield().getAllActivePermanents(filter, opponentId, game).size(); - ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, new FilterCard("card" + (numbTargets == 1 ? "" : "s") + " from your graveyard"))); - } - } - } - - public Reap(final Reap card) { super(card); } @@ -67,3 +44,27 @@ public final class Reap extends CardImpl { return new Reap(this); } } + +enum ReapAdjuster implements TargetAdjuster { + instance; + private static final FilterPermanent filter = new FilterPermanent("black permanents"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller != null) { + ability.getTargets().clear(); + UUID opponentId = null; + Target target = new TargetOpponent(); + if (controller.chooseTarget(Outcome.ReturnToHand, target, ability, game)) { + opponentId = target.getFirstTarget(); + } + int numbTargets = game.getBattlefield().getAllActivePermanents(filter, opponentId, game).size(); + ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, new FilterCard("card" + (numbTargets == 1 ? "" : "s") + " from your graveyard"))); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/ReapAndSow.java b/Mage.Sets/src/mage/cards/r/ReapAndSow.java index e510ca8165..5f60426003 100644 --- a/Mage.Sets/src/mage/cards/r/ReapAndSow.java +++ b/Mage.Sets/src/mage/cards/r/ReapAndSow.java @@ -31,7 +31,7 @@ public final class ReapAndSow extends CardImpl { this.getSpellAbility().addTarget(new TargetLandPermanent()); //or search your library for a land card, put that card onto the battlefield, then shuffle your library. Mode mode = new Mode(); - mode.getEffects().add(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterLandCard()))); + mode.addEffect(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterLandCard()))); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{G} diff --git a/Mage.Sets/src/mage/cards/r/ReapIntellect.java b/Mage.Sets/src/mage/cards/r/ReapIntellect.java index 53fb7286a7..50e28670a3 100644 --- a/Mage.Sets/src/mage/cards/r/ReapIntellect.java +++ b/Mage.Sets/src/mage/cards/r/ReapIntellect.java @@ -128,7 +128,7 @@ class ReapIntellectEffect extends OneShotEffect { // search cards in Library TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); - controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); + controller.searchLibrary(targetCardsLibrary, source, game, targetPlayer.getId()); for (UUID cardId : targetCardsLibrary.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java b/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java index c9a9bf3f10..519ff15bcc 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java +++ b/Mage.Sets/src/mage/cards/r/ReaperFromTheAbyss.java @@ -81,8 +81,8 @@ class ReaperFromTheAbyssAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - Watcher watcher = game.getState().getWatchers().get(MorbidWatcher.class.getSimpleName()); - return watcher.conditionMet(); + Watcher watcher = game.getState().getWatcher(MorbidWatcher.class); + return watcher != null && watcher.conditionMet(); } @Override diff --git a/Mage.Sets/src/mage/cards/r/ReaperKing.java b/Mage.Sets/src/mage/cards/r/ReaperKing.java index ee8a6ef8b8..e3d65bef51 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperKing.java +++ b/Mage.Sets/src/mage/cards/r/ReaperKing.java @@ -27,7 +27,7 @@ public final class ReaperKing extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SCARECROW)); - filterTrigger.add(new AnotherPredicate()); + filterTrigger.add(AnotherPredicate.instance); filterTrigger.add(new SubtypePredicate(SubType.SCARECROW)); } diff --git a/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java b/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java index 9815106ec7..3f1cc81b4e 100644 --- a/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java +++ b/Mage.Sets/src/mage/cards/r/ReaperOfFlightMoonsilver.java @@ -1,12 +1,13 @@ - package mage.cards.r; import java.util.UUID; + import mage.MageInt; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,11 +15,12 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; + import static mage.filter.StaticFilters.FILTER_CONTROLLED_CREATURE_SHORT_TEXT; + import mage.target.common.TargetControlledCreaturePermanent; /** - * * @author fireshoes */ public final class ReaperOfFlightMoonsilver extends CardImpl { @@ -39,7 +41,8 @@ public final class ReaperOfFlightMoonsilver extends CardImpl { new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)), DeliriumCondition.instance, "Delirium — Sacrifice another creature: Reaper of Flight Moonsilver gets +2/+1 until end of turn. " - + "Activate this ability only if there are four or more card types among cards in your graveyard")); + + "Activate this ability only if there are four or more card types among cards in your graveyard") + .addHint(DeliriumHint.instance)); } public ReaperOfFlightMoonsilver(final ReaperOfFlightMoonsilver card) { diff --git a/Mage.Sets/src/mage/cards/r/ReasonBelieve.java b/Mage.Sets/src/mage/cards/r/ReasonBelieve.java index 0758c54389..a0d04ccc9e 100644 --- a/Mage.Sets/src/mage/cards/r/ReasonBelieve.java +++ b/Mage.Sets/src/mage/cards/r/ReasonBelieve.java @@ -32,7 +32,7 @@ public final class ReasonBelieve extends SplitCard { // Believe // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Look at the top card of your library. You may put it onto the battlefield if it's a creature card. If you don't, put it into your hand. getRightHalfCard().getSpellAbility().addEffect(new BelieveEffect()); diff --git a/Mage.Sets/src/mage/cards/r/ReaverDrone.java b/Mage.Sets/src/mage/cards/r/ReaverDrone.java index 0a37353854..441d903aff 100644 --- a/Mage.Sets/src/mage/cards/r/ReaverDrone.java +++ b/Mage.Sets/src/mage/cards/r/ReaverDrone.java @@ -28,8 +28,8 @@ public final class ReaverDrone extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public ReaverDrone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RebelInformer.java b/Mage.Sets/src/mage/cards/r/RebelInformer.java index d5328fc4a3..1bfcbcae63 100644 --- a/Mage.Sets/src/mage/cards/r/RebelInformer.java +++ b/Mage.Sets/src/mage/cards/r/RebelInformer.java @@ -36,7 +36,7 @@ public final class RebelInformer extends CardImpl { static { filterWhite.add(new ColorPredicate(ObjectColor.WHITE)); - filterRebel.add(Predicates.not(new TokenPredicate())); + filterRebel.add(Predicates.not(TokenPredicate.instance)); filterRebel.add(new SubtypePredicate(SubType.REBEL)); } diff --git a/Mage.Sets/src/mage/cards/r/RebornHope.java b/Mage.Sets/src/mage/cards/r/RebornHope.java index 0006834a88..47f878e885 100644 --- a/Mage.Sets/src/mage/cards/r/RebornHope.java +++ b/Mage.Sets/src/mage/cards/r/RebornHope.java @@ -19,7 +19,7 @@ public final class RebornHope extends CardImpl { private static final FilterCard filter = new FilterCard("multicolored card from your graveyard"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public RebornHope(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/Rebound.java b/Mage.Sets/src/mage/cards/r/Rebound.java new file mode 100644 index 0000000000..5afdee305d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Rebound.java @@ -0,0 +1,77 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterSpell; +import mage.filter.predicate.other.TargetsOnlyOnePlayerPredicate; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.TargetSpell; + +/** + * + * @author jeffwadsworth + */ +public final class Rebound extends CardImpl { + + public Rebound(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Change the target of target spell that targets only a player. The new target must be a player. + this.getSpellAbility().addEffect(new ReboundEffect()); + FilterSpell filter = new FilterSpell("spell that targets only a player"); + filter.add(new TargetsOnlyOnePlayerPredicate()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + + } + + public Rebound(final Rebound card) { + super(card); + } + + @Override + public Rebound copy() { + return new Rebound(this); + } +} + +class ReboundEffect extends OneShotEffect { + + public ReboundEffect() { + super(Outcome.Neutral); + this.staticText = "Change the target of target spell that targets only a player. The new target must be a player"; + } + + public ReboundEffect(final ReboundEffect effect) { + super(effect); + } + + @Override + public ReboundEffect copy() { + return new ReboundEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Spell spell = game.getStack().getSpell(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (spell != null + && controller != null) { + spell.getSpellAbility().getTargets().clear(); + TargetPlayer targetPlayer = new TargetPlayer(); + if (controller.choose(Outcome.Neutral, targetPlayer, source.getSourceId(), game)) { + spell.getSpellAbility().addTarget(targetPlayer); + game.informPlayers("The target of the spell was changed to " + targetPlayer.getTargetedName(game)); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RebuffTheWicked.java b/Mage.Sets/src/mage/cards/r/RebuffTheWicked.java index d5ecd01df4..e60d29822b 100644 --- a/Mage.Sets/src/mage/cards/r/RebuffTheWicked.java +++ b/Mage.Sets/src/mage/cards/r/RebuffTheWicked.java @@ -17,7 +17,7 @@ import mage.target.TargetSpell; */ public final class RebuffTheWicked extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + private static final FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); static { filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); diff --git a/Mage.Sets/src/mage/cards/r/Reciprocate.java b/Mage.Sets/src/mage/cards/r/Reciprocate.java index 1a4073f1c5..4b20b3759c 100644 --- a/Mage.Sets/src/mage/cards/r/Reciprocate.java +++ b/Mage.Sets/src/mage/cards/r/Reciprocate.java @@ -53,7 +53,7 @@ class ReciprocateTarget extends TargetPermanent { @Override public boolean canTarget(UUID id, Ability source, Game game) { - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), source.getControllerId()); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, source.getControllerId()); if (watcher != null && watcher.hasSourceDoneDamage(id, game)) { return super.canTarget(id, source, game); } @@ -64,7 +64,7 @@ class ReciprocateTarget extends TargetPermanent { public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set availablePossibleTargets = super.possibleTargets(sourceId, sourceControllerId, game); Set possibleTargets = new HashSet<>(); - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), sourceControllerId); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); for (UUID targetId : availablePossibleTargets) { Permanent permanent = game.getPermanent(targetId); if (permanent != null && watcher != null && watcher.hasSourceDoneDamage(targetId, game)) { @@ -82,13 +82,15 @@ class ReciprocateTarget extends TargetPermanent { } int count = 0; MageObject targetSource = game.getObject(sourceId); - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), sourceControllerId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game) - && watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) { - count++; - if (count >= remainingTargets) { - return true; + if(targetSource != null) { + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, sourceControllerId); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game) + && watcher != null && watcher.hasSourceDoneDamage(permanent.getId(), game)) { + count++; + if (count >= remainingTargets) { + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java b/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java index 0e83f3b7fc..c35a712869 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java +++ b/Mage.Sets/src/mage/cards/r/RecklessBushwhacker.java @@ -24,10 +24,10 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class RecklessBushwhacker extends CardImpl { - private final static FilterControlledCreaturePermanent FILTER = new FilterControlledCreaturePermanent("other creatures you control"); + private static final FilterControlledCreaturePermanent FILTER = new FilterControlledCreaturePermanent("other creatures you control"); static { - FILTER.add(new AnotherPredicate()); + FILTER.add(AnotherPredicate.instance); } public RecklessBushwhacker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RecklessCohort.java b/Mage.Sets/src/mage/cards/r/RecklessCohort.java index ec4d153313..a4f00f9e92 100644 --- a/Mage.Sets/src/mage/cards/r/RecklessCohort.java +++ b/Mage.Sets/src/mage/cards/r/RecklessCohort.java @@ -21,10 +21,10 @@ import mage.filter.predicate.permanent.AnotherPredicate; */ public final class RecklessCohort extends CardImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Ally"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Ally"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ALLY)); } diff --git a/Mage.Sets/src/mage/cards/r/ReclusiveWight.java b/Mage.Sets/src/mage/cards/r/ReclusiveWight.java index 01995437b1..936f3a340a 100644 --- a/Mage.Sets/src/mage/cards/r/ReclusiveWight.java +++ b/Mage.Sets/src/mage/cards/r/ReclusiveWight.java @@ -27,7 +27,7 @@ public final class ReclusiveWight extends CardImpl { static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ReclusiveWight(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/Reconnaissance.java b/Mage.Sets/src/mage/cards/r/Reconnaissance.java index fbd93e6ceb..84fe89dcc4 100644 --- a/Mage.Sets/src/mage/cards/r/Reconnaissance.java +++ b/Mage.Sets/src/mage/cards/r/Reconnaissance.java @@ -27,7 +27,7 @@ public final class Reconnaissance extends CardImpl { private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature controlled by you"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Reconnaissance(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RecumbentBliss.java b/Mage.Sets/src/mage/cards/r/RecumbentBliss.java index 1310902878..a914564eac 100644 --- a/Mage.Sets/src/mage/cards/r/RecumbentBliss.java +++ b/Mage.Sets/src/mage/cards/r/RecumbentBliss.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -17,14 +15,15 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class RecumbentBliss extends CardImpl { public RecumbentBliss(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{W}"); this.subtype.add(SubType.AURA); TargetPermanent auraTarget = new TargetCreaturePermanent(); @@ -59,19 +58,16 @@ class RecumbentBlissEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getAttachments().contains((source.getSourceId()))) { - return true; - } + return permanent.getAttachments().contains((source.getSourceId())); + } + + @Override + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { - return false; - } - - @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/Recuperate.java b/Mage.Sets/src/mage/cards/r/Recuperate.java index eac1cf5e39..2188c648df 100644 --- a/Mage.Sets/src/mage/cards/r/Recuperate.java +++ b/Mage.Sets/src/mage/cards/r/Recuperate.java @@ -25,8 +25,8 @@ public final class Recuperate extends CardImpl { this.getSpellAbility().addEffect(new GainLifeEffect(6)); // or prevent the next 6 damage that would be dealt to target creature this turn. Mode mode = new Mode(); - mode.getEffects().add(new PreventDamageToTargetEffect(Duration.EndOfTurn, 6)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new PreventDamageToTargetEffect(Duration.EndOfTurn, 6)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RedElementalBlast.java b/Mage.Sets/src/mage/cards/r/RedElementalBlast.java index cb0e684dac..aa86c01144 100644 --- a/Mage.Sets/src/mage/cards/r/RedElementalBlast.java +++ b/Mage.Sets/src/mage/cards/r/RedElementalBlast.java @@ -37,8 +37,8 @@ public final class RedElementalBlast extends CardImpl { this.getSpellAbility().addTarget(new TargetSpell(filterSpell)); Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filterPermanent)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filterPermanent)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RedManaBattery.java b/Mage.Sets/src/mage/cards/r/RedManaBattery.java index 461a4664e3..1281c0d257 100644 --- a/Mage.Sets/src/mage/cards/r/RedManaBattery.java +++ b/Mage.Sets/src/mage/cards/r/RedManaBattery.java @@ -36,7 +36,7 @@ public final class RedManaBattery extends CardImpl { // {tap}, Remove any number of charge counters from Red Mana Battery: Add {R}, then add an additional {R} for each charge counter removed this way. ability = new DynamicManaAbility( Mana.RedMana(1), - new IntPlusDynamicValue(1, new RemovedCountersForCostValue()), + new IntPlusDynamicValue(1, RemovedCountersForCostValue.instance), new TapSourceCost(), "Add {R}, then add {R} for each charge counter removed this way", true, new CountersSourceCount(CounterType.CHARGE)); diff --git a/Mage.Sets/src/mage/cards/r/RedSunsZenith.java b/Mage.Sets/src/mage/cards/r/RedSunsZenith.java index a95deffc58..9d39917e0c 100644 --- a/Mage.Sets/src/mage/cards/r/RedSunsZenith.java +++ b/Mage.Sets/src/mage/cards/r/RedSunsZenith.java @@ -26,7 +26,7 @@ public final class RedSunsZenith extends CardImpl { // If a creature dealt damage this way would die this turn, exile it instead. // Shuffle Red Sun's Zenith into its owner's library. this.getSpellAbility().addTarget(new TargetAnyTarget()); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addEffect(new DealtDamageToCreatureBySourceDies(this, Duration.EndOfTurn)); this.getSpellAbility().addEffect(ShuffleSpellEffect.getInstance()); this.getSpellAbility().addWatcher(new DamagedByWatcher()); diff --git a/Mage.Sets/src/mage/cards/r/ReduceRubble.java b/Mage.Sets/src/mage/cards/r/ReduceRubble.java index 792cfdb894..7c3cb39665 100644 --- a/Mage.Sets/src/mage/cards/r/ReduceRubble.java +++ b/Mage.Sets/src/mage/cards/r/ReduceRubble.java @@ -32,7 +32,7 @@ public final class ReduceRubble extends SplitCard { // Rubble // Up to three target lands don't untap during their controller's next untap step. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); Effect effect = new DontUntapInControllersNextUntapStepTargetEffect(); effect.setText("Up to three target lands don't untap during their controller's next untap step"); getRightHalfCard().getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/r/ReflectorMage.java b/Mage.Sets/src/mage/cards/r/ReflectorMage.java index a2514e833e..51ebede343 100644 --- a/Mage.Sets/src/mage/cards/r/ReflectorMage.java +++ b/Mage.Sets/src/mage/cards/r/ReflectorMage.java @@ -1,8 +1,5 @@ - package mage.cards.r; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,12 +8,7 @@ import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; @@ -25,14 +17,17 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.Objects; +import java.util.UUID; /** - * * @author LevelX2 */ public final class ReflectorMage extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -84,7 +79,7 @@ class ReflectorMageEffect extends OneShotEffect { Permanent targetCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); if (targetCreature != null) { controller.moveCards(targetCreature, Zone.HAND, source, game); - if (!targetCreature.getName().isEmpty()) { // if the creature had no name, no restrict effect will be created + if (!CardUtil.haveEmptyName(targetCreature)) { // if the creature had no name, no restrict effect will be created game.addEffect(new ExclusionRitualReplacementEffect(targetCreature.getName(), targetCreature.getOwnerId()), source); } } @@ -125,7 +120,7 @@ class ExclusionRitualReplacementEffect extends ContinuousRuleModifyingEffectImpl if (spell != null && spell.isFaceDown(game)) { return false; // Face Down cast spell (Morph creature) has no name } - return card.getName().equals(creatureName) && Objects.equals(ownerId, card.getOwnerId()); + return CardUtil.haveSameNames(card.getName(), creatureName) && Objects.equals(ownerId, card.getOwnerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/r/RefractionTrap.java b/Mage.Sets/src/mage/cards/r/RefractionTrap.java index 84d3bc3672..bea2ff1c96 100644 --- a/Mage.Sets/src/mage/cards/r/RefractionTrap.java +++ b/Mage.Sets/src/mage/cards/r/RefractionTrap.java @@ -59,7 +59,7 @@ enum RefractionTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List spells = watcher.getSpellsCastThisTurn(opponentId); diff --git a/Mage.Sets/src/mage/cards/r/RefuseCooperate.java b/Mage.Sets/src/mage/cards/r/RefuseCooperate.java index 2ee051d963..431cf7745c 100644 --- a/Mage.Sets/src/mage/cards/r/RefuseCooperate.java +++ b/Mage.Sets/src/mage/cards/r/RefuseCooperate.java @@ -34,7 +34,7 @@ public final class RefuseCooperate extends SplitCard { // Cooperate // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Copy target instant or sorcery spell. You may choose new targets for the copy. getRightHalfCard().getSpellAbility().addEffect(new CopyTargetSpellEffect()); getRightHalfCard().getSpellAbility().addTarget(new TargetSpell(new FilterInstantOrSorcerySpell())); diff --git a/Mage.Sets/src/mage/cards/r/RegalBehemoth.java b/Mage.Sets/src/mage/cards/r/RegalBehemoth.java index 07e8352ad1..fdf945fef1 100644 --- a/Mage.Sets/src/mage/cards/r/RegalBehemoth.java +++ b/Mage.Sets/src/mage/cards/r/RegalBehemoth.java @@ -80,9 +80,12 @@ class RegalBehemothTriggeredManaAbility extends TriggeredManaAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (isControlledBy(game.getMonarchId())) { + if (game.getMonarchId() != null + && isControlledBy(game.getMonarchId())) { Permanent permanent = game.getPermanentOrLKIBattlefield(event.getSourceId()); - if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + if (permanent != null + && getControllerId() != null + && filter.match(permanent, getSourceId(), getControllerId(), game)) { ManaEvent mEvent = (ManaEvent) event; for (Effect effect : getEffects()) { effect.setValue("mana", mEvent.getMana()); diff --git a/Mage.Sets/src/mage/cards/r/Regenesis.java b/Mage.Sets/src/mage/cards/r/Regenesis.java new file mode 100644 index 0000000000..9743d9c073 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Regenesis.java @@ -0,0 +1,36 @@ +package mage.cards.r; + +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterCard; +import mage.filter.common.FilterPermanentCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Regenesis extends CardImpl { + + private static final FilterCard filter = new FilterPermanentCard("permanent cards from your graveyard"); + + public Regenesis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{3}{G}{G}"); + + // Return up to two target permanent cards from your graveyard to your hand. + this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, 2, filter)); + } + + private Regenesis(final Regenesis card) { + super(card); + } + + @Override + public Regenesis copy() { + return new Regenesis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java b/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java index 12dd708519..4ed6423651 100644 --- a/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java +++ b/Mage.Sets/src/mage/cards/r/RegnaTheRedeemer.java @@ -75,12 +75,12 @@ class RegnaTheRedeemerCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int gainedLife = 0; - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getSimpleName()); + PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); if (watcher != null) { for (UUID playerId : game.getPlayerList()) { Player player = game.getPlayer(playerId); - if (!player.hasOpponent(source.getControllerId(), game)) { - gainedLife = watcher.getLiveGained(playerId); + if (player != null && !player.hasOpponent(source.getControllerId(), game)) { + gainedLife = watcher.getLifeGained(playerId); if (gainedLife > 0) { break; } diff --git a/Mage.Sets/src/mage/cards/r/RegnasSanction.java b/Mage.Sets/src/mage/cards/r/RegnasSanction.java index fef3d117ba..4ad60fb379 100644 --- a/Mage.Sets/src/mage/cards/r/RegnasSanction.java +++ b/Mage.Sets/src/mage/cards/r/RegnasSanction.java @@ -1,7 +1,7 @@ - package mage.cards.r; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.TapAllEffect; @@ -22,7 +22,6 @@ import mage.players.Player; import mage.target.TargetPermanent; /** - * * @author TheElk801 */ public final class RegnasSanction extends CardImpl { @@ -48,7 +47,9 @@ class RegnasSanctionEffect extends OneShotEffect { RegnasSanctionEffect() { super(Outcome.Benefit); - this.staticText = "For each player, choose friend or foe. Each friend puts a +1/+1 counter on each creature they control. Each foe chooses one untapped creature they control, then taps the rest"; + this.staticText = "For each player, choose friend or foe. " + + "Each friend puts a +1/+1 counter on each creature they control. " + + "Each foe chooses one untapped creature they control, then taps the rest"; } RegnasSanctionEffect(final RegnasSanctionEffect effect) { @@ -64,13 +65,16 @@ class RegnasSanctionEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); ChooseFriendsAndFoes choice = new ChooseFriendsAndFoes(); + if (controller == null) { + return false; + } if (!choice.chooseFriendOrFoe(controller, source, game)) { return false; } FilterCreaturePermanent filterToTap = new FilterCreaturePermanent(); for (Player player : choice.getFoes()) { FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creature you control"); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new ControllerIdPredicate(player.getId())); TargetPermanent target = new TargetPermanent(1, 1, filter, true); if (player.choose(Outcome.Benefit, target, source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/cards/r/ReignOfChaos.java b/Mage.Sets/src/mage/cards/r/ReignOfChaos.java index 6c1eaef884..0688a7bd83 100644 --- a/Mage.Sets/src/mage/cards/r/ReignOfChaos.java +++ b/Mage.Sets/src/mage/cards/r/ReignOfChaos.java @@ -41,9 +41,9 @@ public final class ReignOfChaos extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); this.getSpellAbility().addTarget(new TargetPermanent(filter2)); Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect(false, true)); - mode.getTargets().add(new TargetPermanent(filter3)); - mode.getTargets().add(new TargetPermanent(filter4)); + mode.addEffect(new DestroyTargetEffect(false, true)); + mode.addTarget(new TargetPermanent(filter3)); + mode.addTarget(new TargetPermanent(filter4)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/Reincarnation.java b/Mage.Sets/src/mage/cards/r/Reincarnation.java index ecd453ac2b..470183dfa4 100644 --- a/Mage.Sets/src/mage/cards/r/Reincarnation.java +++ b/Mage.Sets/src/mage/cards/r/Reincarnation.java @@ -95,7 +95,7 @@ class ReincarnationDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(target)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } @@ -143,6 +143,7 @@ class ReincarnationDelayedEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard("a creature card from " + player.getName() + "'s graveyard"); filter.add(new OwnerIdPredicate(player.getId())); Target targetCreature = new TargetCardInGraveyard(filter); + targetCreature.setNotTarget(true); if (targetCreature.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseTarget(outcome, targetCreature, source, game)) { Card card = game.getCard(targetCreature.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java b/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java index d0bc76ed94..eee1db1427 100644 --- a/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java +++ b/Mage.Sets/src/mage/cards/r/ReleaseTheGremlins.java @@ -1,9 +1,7 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; @@ -13,9 +11,11 @@ import mage.constants.CardType; import mage.game.Game; import mage.game.permanent.token.GremlinToken; import mage.target.common.TargetArtifactPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Styxo */ public final class ReleaseTheGremlins extends CardImpl { @@ -28,17 +28,9 @@ public final class ReleaseTheGremlins extends CardImpl { this.getSpellAbility().addTarget(new TargetArtifactPermanent()); // Create X 2/2 red Gremlin creature tokens. - this.getSpellAbility().addEffect(new CreateTokenEffect(new GremlinToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new GremlinToken(), ManacostVariableValue.instance)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetArtifactPermanent(xValue, xValue)); - } + this.getSpellAbility().setTargetAdjuster(ReleaseTheGremlinsAdjuster.instance); } public ReleaseTheGremlins(final ReleaseTheGremlins card) { @@ -50,3 +42,13 @@ public final class ReleaseTheGremlins extends CardImpl { return new ReleaseTheGremlins(this); } } + +enum ReleaseTheGremlinsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetArtifactPermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RelentlessAdvance.java b/Mage.Sets/src/mage/cards/r/RelentlessAdvance.java new file mode 100644 index 0000000000..69a14bb7d1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RelentlessAdvance.java @@ -0,0 +1,30 @@ +package mage.cards.r; + +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RelentlessAdvance extends CardImpl { + + public RelentlessAdvance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); + + // Amass 3. (Put three +1/+1 counters on an Army you control. If you don't control one, create a 0/0 black Zombie Army creature token first. + this.getSpellAbility().addEffect(new AmassEffect(3)); + } + + private RelentlessAdvance(final RelentlessAdvance card) { + super(card); + } + + @Override + public RelentlessAdvance copy() { + return new RelentlessAdvance(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RelentlessRats.java b/Mage.Sets/src/mage/cards/r/RelentlessRats.java index 8042cfcee1..02cb98cdd4 100644 --- a/Mage.Sets/src/mage/cards/r/RelentlessRats.java +++ b/Mage.Sets/src/mage/cards/r/RelentlessRats.java @@ -71,7 +71,7 @@ public final class RelentlessRats extends CardImpl { public boolean apply(Game game, Ability source) { int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; if (count > 0) { - Permanent target = (Permanent) game.getPermanent(source.getSourceId()); + Permanent target = game.getPermanent(source.getSourceId()); if (target != null) { target.addPower(count); target.addToughness(count); diff --git a/Mage.Sets/src/mage/cards/r/RelicBind.java b/Mage.Sets/src/mage/cards/r/RelicBind.java index 3068f732e7..546f42f721 100644 --- a/Mage.Sets/src/mage/cards/r/RelicBind.java +++ b/Mage.Sets/src/mage/cards/r/RelicBind.java @@ -50,8 +50,8 @@ public final class RelicBind extends CardImpl { ability2.addTarget(new TargetPlayerOrPlaneswalker()); // — Target player gains 1 life. Mode mode = new Mode(); - mode.getEffects().add(new GainLifeTargetEffect(1)); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new GainLifeTargetEffect(1)); + mode.addTarget(new TargetPlayer()); ability2.addMode(mode); this.addAbility(ability2); diff --git a/Mage.Sets/src/mage/cards/r/RelicRunner.java b/Mage.Sets/src/mage/cards/r/RelicRunner.java index 23e3aee8ec..034c428df0 100644 --- a/Mage.Sets/src/mage/cards/r/RelicRunner.java +++ b/Mage.Sets/src/mage/cards/r/RelicRunner.java @@ -58,7 +58,7 @@ class CastHistoricSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spells != null) { diff --git a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java index 3a4c87cf21..1233a0bb6a 100644 --- a/Mage.Sets/src/mage/cards/r/RememberTheFallen.java +++ b/Mage.Sets/src/mage/cards/r/RememberTheFallen.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -11,8 +9,9 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterArtifactCard; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class RememberTheFallen extends CardImpl { @@ -28,12 +27,12 @@ public final class RememberTheFallen extends CardImpl { // • Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); // • Return target artifact card from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(filterArtifact)); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filterArtifact).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/Remembrance.java b/Mage.Sets/src/mage/cards/r/Remembrance.java index 237553bc60..2a559585c8 100644 --- a/Mage.Sets/src/mage/cards/r/Remembrance.java +++ b/Mage.Sets/src/mage/cards/r/Remembrance.java @@ -1,33 +1,27 @@ package mage.cards.r; -import java.util.UUID; -import mage.MageObject; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.TargetController; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.NamePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; -import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Remembrance extends CardImpl { @@ -39,7 +33,7 @@ public final class Remembrance extends CardImpl { this.addAbility(new RemembranceTriggeredAbility()); } - public Remembrance(final Remembrance card) { + private Remembrance(final Remembrance card) { super(card); } @@ -51,19 +45,17 @@ public final class Remembrance extends CardImpl { class RemembranceTriggeredAbility extends TriggeredAbilityImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature you control"); + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } - public RemembranceTriggeredAbility() { - super(Zone.BATTLEFIELD, new RemembranceEffect()); - this.optional = true; + RemembranceTriggeredAbility() { + super(Zone.BATTLEFIELD, null, true); } - public RemembranceTriggeredAbility(final RemembranceTriggeredAbility ability) { + private RemembranceTriggeredAbility(final RemembranceTriggeredAbility ability) { super(ability); } @@ -79,53 +71,26 @@ class RemembranceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - MageObject mageObject = game.getObject(sourceId); - if (permanent != null - && filter.match(permanent, game)) { - game.getState().setValue(mageObject + "nameOfPermanent", permanent.getName()); - return true; - } + if (!((ZoneChangeEvent) event).isDiesEvent()) { + return false; + } + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (permanent != null && filter.match(permanent, game)) { + FilterCard filterCard = new FilterCard("card named " + permanent.getName()); + filterCard.add(new NamePredicate(permanent.getName())); + this.getEffects().clear(); + this.addEffect(new SearchLibraryPutInHandEffect( + new TargetCardInLibrary(filterCard), true, true + )); + return true; } return false; } @Override public String getRule() { - return "Whenever a nontoken creature you control dies, you may search your library for a card with the same name as that creature, reveal it, and put it into your hand. If you do, shuffle your library."; - } -} - -class RemembranceEffect extends OneShotEffect { - - private String cardName; - - RemembranceEffect() { - super(Outcome.Benefit); - } - - RemembranceEffect(final RemembranceEffect effect) { - super(effect); - } - - @Override - public RemembranceEffect copy() { - return new RemembranceEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject mageObject = game.getObject(source.getSourceId()); - cardName = (String) game.getState().getValue(mageObject + "nameOfPermanent"); - if (controller != null - && cardName != null) { - FilterCard filterCard = new FilterCard("card named " + cardName); - filterCard.add(new NamePredicate(cardName)); - return new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filterCard), true, true).apply(game, source); - } - return false; + return "Whenever a nontoken creature you control dies, " + + "you may search your library for a card with the same name as that creature, " + + "reveal it, and put it into your hand. If you do, shuffle your library."; } } diff --git a/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java b/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java index 3bfd103007..56387c6295 100644 --- a/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java +++ b/Mage.Sets/src/mage/cards/r/RemorselessPunishment.java @@ -43,7 +43,7 @@ public final class RemorselessPunishment extends CardImpl { class RemorselessPunishmentEffect extends OneShotEffect { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("creature or planeswalker"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("creature or planeswalker"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.CREATURE), new CardTypePredicate(CardType.PLANESWALKER))); diff --git a/Mage.Sets/src/mage/cards/r/RenderSilent.java b/Mage.Sets/src/mage/cards/r/RenderSilent.java index b7cdf3c89d..41c441d74b 100644 --- a/Mage.Sets/src/mage/cards/r/RenderSilent.java +++ b/Mage.Sets/src/mage/cards/r/RenderSilent.java @@ -30,7 +30,7 @@ public final class RenderSilent extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("multicolored permanent"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public RenderSilent(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RenegadeKrasis.java b/Mage.Sets/src/mage/cards/r/RenegadeKrasis.java index 95a9aceeef..e692bdb62c 100644 --- a/Mage.Sets/src/mage/cards/r/RenegadeKrasis.java +++ b/Mage.Sets/src/mage/cards/r/RenegadeKrasis.java @@ -52,7 +52,7 @@ class RenegadeKrasisTriggeredAbility extends TriggeredAbilityImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new CounterPredicate(CounterType.P1P1)); } diff --git a/Mage.Sets/src/mage/cards/r/RenounceTheGuilds.java b/Mage.Sets/src/mage/cards/r/RenounceTheGuilds.java index e19fdae0ad..3bd1e884dc 100644 --- a/Mage.Sets/src/mage/cards/r/RenounceTheGuilds.java +++ b/Mage.Sets/src/mage/cards/r/RenounceTheGuilds.java @@ -20,7 +20,7 @@ public final class RenounceTheGuilds extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("multicolored permanent"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public RenounceTheGuilds(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java b/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java index ed31ed8cc0..083aeb0eb1 100644 --- a/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java +++ b/Mage.Sets/src/mage/cards/r/RenownedWeaponsmith.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.ConditionalMana; import mage.MageInt; import mage.MageObject; @@ -14,14 +12,10 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.ConditionalColorlessManaAbility; import mage.abilities.mana.builder.ConditionalManaBuilder; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; @@ -30,14 +24,15 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class RenownedWeaponsmith extends CardImpl { public RenownedWeaponsmith(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ARTIFICER); this.power = new MageInt(1); @@ -118,13 +113,16 @@ class RenownedWeaponsmithEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (sourceObject != null && controller != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { - Card card = game.getCard(target.getFirstTarget()); Cards revealed = new CardsImpl(); - revealed.add(card); - controller.revealCards(sourceObject.getIdName(), revealed, game); - controller.moveCards(revealed, Zone.HAND, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card != null) { + revealed.add(card); + controller.revealCards(sourceObject.getIdName(), revealed, game); + controller.moveCards(revealed, Zone.HAND, source, game); + } + } } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/r/Repeal.java b/Mage.Sets/src/mage/cards/r/Repeal.java index 9738ab88b2..34851fedca 100644 --- a/Mage.Sets/src/mage/cards/r/Repeal.java +++ b/Mage.Sets/src/mage/cards/r/Repeal.java @@ -1,9 +1,7 @@ - package mage.cards.r; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; @@ -15,6 +13,7 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.TargetPermanent; import mage.target.common.TargetNonlandPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -23,29 +22,17 @@ import mage.target.common.TargetNonlandPermanent; public final class Repeal extends CardImpl { public Repeal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); // Return target nonland permanent with converted mana cost X to its owner's hand. this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(new FilterNonlandPermanent("nonland permanent with converted mana cost X"))); - + this.getSpellAbility().setTargetAdjuster(RepealAdjuster.instance); // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1)); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterNonlandPermanent filter = new FilterNonlandPermanent(new StringBuilder("nonland permanent with converted mana cost ").append(xValue).toString()); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - ability.addTarget(new TargetNonlandPermanent(filter)); - } - } - public Repeal(final Repeal card) { super(card); } @@ -55,3 +42,16 @@ public final class Repeal extends CardImpl { return new Repeal(this); } } + +enum RepealAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterNonlandPermanent filter = new FilterNonlandPermanent("nonland permanent with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetNonlandPermanent(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RepudiateReplicate.java b/Mage.Sets/src/mage/cards/r/RepudiateReplicate.java new file mode 100644 index 0000000000..b8257fe633 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RepudiateReplicate.java @@ -0,0 +1,41 @@ +package mage.cards.r; + +import mage.abilities.effects.common.CounterTargetEffect; +import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.target.common.TargetActivatedOrTriggeredAbility; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RepudiateReplicate extends SplitCard { + + public RepudiateReplicate(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{G/U}{G/U}", "{1}{G}{U}", SpellAbilityType.SPLIT); + + // Repudiate + // Counter target activated ability or triggered ability. + this.getLeftHalfCard().getSpellAbility().addEffect(new CounterTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetActivatedOrTriggeredAbility()); + + // Replicate + // Create a token that’s a copy of target creature you control. + this.getRightHalfCard().getSpellAbility().addEffect(new CreateTokenCopyTargetEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private RepudiateReplicate(final RepudiateReplicate card) { + super(card); + } + + @Override + public RepudiateReplicate copy() { + return new RepudiateReplicate(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RequiemAngel.java b/Mage.Sets/src/mage/cards/r/RequiemAngel.java index 7e7efb10e2..178164eab7 100644 --- a/Mage.Sets/src/mage/cards/r/RequiemAngel.java +++ b/Mage.Sets/src/mage/cards/r/RequiemAngel.java @@ -27,7 +27,7 @@ public final class RequiemAngel extends CardImpl { static { filter.add(Predicates.not(new SubtypePredicate(SubType.SPIRIT))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/r/RescueFromTheUnderworld.java b/Mage.Sets/src/mage/cards/r/RescueFromTheUnderworld.java index 4c975ab58c..1a8f126c8d 100644 --- a/Mage.Sets/src/mage/cards/r/RescueFromTheUnderworld.java +++ b/Mage.Sets/src/mage/cards/r/RescueFromTheUnderworld.java @@ -122,7 +122,7 @@ class RescueFromTheUnderworldCreateDelayedTriggeredAbilityEffect extends OneShot @Override public boolean apply(Game game, Ability source) { - DelayedTriggeredAbility delayedAbility = (DelayedTriggeredAbility) ability.copy(); + DelayedTriggeredAbility delayedAbility = ability.copy(); delayedAbility.getTargets().addAll(source.getTargets()); for (Effect effect : delayedAbility.getEffects()) { effect.getTargetPointer().init(game, source); diff --git a/Mage.Sets/src/mage/cards/r/RescuerSphinx.java b/Mage.Sets/src/mage/cards/r/RescuerSphinx.java new file mode 100644 index 0000000000..6987050ccd --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RescuerSphinx.java @@ -0,0 +1,100 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.effects.OneShotEffect; +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.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RescuerSphinx extends CardImpl { + + public RescuerSphinx(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // As Rescuer Sphinx enters the battlefield, you may return a nonland permanent you control to its owner's hand. If you do, Rescuer Sphinx enters the battlefield with a +1/+1 counter on it. + this.addAbility(new AsEntersBattlefieldAbility(new RescuerSphinxEffect())); + } + + private RescuerSphinx(final RescuerSphinx card) { + super(card); + } + + @Override + public RescuerSphinx copy() { + return new RescuerSphinx(this); + } +} + +class RescuerSphinxEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledPermanent("nonland permanent you control"); + + static { + filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); + } + + RescuerSphinxEffect() { + super(Outcome.Benefit); + staticText = "you may return a nonland permanent you control to its owner's hand. " + + "If you do, {this} enters the battlefield with a +1/+1 counter on it."; + } + + private RescuerSphinxEffect(final RescuerSphinxEffect effect) { + super(effect); + } + + @Override + public RescuerSphinxEffect copy() { + return new RescuerSphinxEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (!player.chooseUse(outcome, "Return a nonland permanent you control to your hand?", source, game)) { + return false; + } + Target target = new TargetPermanent(0, 1, filter, true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null || !player.moveCards(permanent, Zone.HAND, source, game)) { + return false; + } + return new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java b/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java new file mode 100644 index 0000000000..80f127f700 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ResoluteWatchdog.java @@ -0,0 +1,55 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.IndestructibleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ResoluteWatchdog extends CardImpl { + + public ResoluteWatchdog(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.HOUND); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {1}, Sacrifice Resolute Watchdog: Target creature you control gains indestructible until end of turn. + Ability ability = new SimpleActivatedAbility( + new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), + Duration.EndOfTurn + ), new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private ResoluteWatchdog(final ResoluteWatchdog card) { + super(card); + } + + @Override + public ResoluteWatchdog copy() { + return new ResoluteWatchdog(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java b/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java index eb2ca73672..5bdb527c89 100644 --- a/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java +++ b/Mage.Sets/src/mage/cards/r/ResplendentGriffin.java @@ -1,12 +1,11 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -15,8 +14,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.counters.CounterType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ResplendentGriffin extends CardImpl { @@ -37,7 +37,8 @@ public final class ResplendentGriffin extends CardImpl { // Whenever Resplendent Griffin attacks, if you have the city's blessing, put a +1/+1 counter on it. this.addAbility(new ConditionalInterveningIfTriggeredAbility(new AttacksTriggeredAbility( new AddCountersSourceEffect(CounterType.P1P1.createInstance()), false), CitysBlessingCondition.instance, - "Whenever {this} attacks, if you have the city's blessing, put a +1/+1 counter on it.")); + "Whenever {this} attacks, if you have the city's blessing, put a +1/+1 counter on it.") + .addHint(CitysBlessingHint.instance)); } public ResplendentGriffin(final ResplendentGriffin card) { diff --git a/Mage.Sets/src/mage/cards/r/RestlessDreams.java b/Mage.Sets/src/mage/cards/r/RestlessDreams.java index 9bc906e22a..a2b83827f3 100644 --- a/Mage.Sets/src/mage/cards/r/RestlessDreams.java +++ b/Mage.Sets/src/mage/cards/r/RestlessDreams.java @@ -1,23 +1,23 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.DiscardXTargetCost; -import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; import mage.filter.StaticFilters; import mage.game.Game; -import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; +import mage.abilities.costs.Cost; +import mage.filter.common.FilterCreatureCard; +import mage.target.Target; /** - * * @author fireshoes */ public final class RestlessDreams extends CardImpl { @@ -26,26 +26,40 @@ public final class RestlessDreams extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // As an additional cost to cast Restless Dreams, discard X cards. - this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); + this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); // Return X target creature cards from your graveyard to your hand. Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target creature cards from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(RestlessDreamsAdjuster.instance); + } public RestlessDreams(final RestlessDreams card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - int xValue = new GetXValue().calculate(game, ability, null); - Target target = new TargetCardInYourGraveyard(xValue, StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); - ability.addTarget(target); - } - @Override public RestlessDreams copy() { return new RestlessDreams(this); } } + +enum RestlessDreamsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof DiscardXTargetCost) { + xValue = ((DiscardXTargetCost) cost).getAmount(); + } + } + Target target = new TargetCardInYourGraveyard(xValue, + new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? + " creature cards" : "creature card").append(" from your graveyard").toString())); + ability.addTarget(target); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RestoreThePeace.java b/Mage.Sets/src/mage/cards/r/RestoreThePeace.java index 48d3e16fb2..ff0bd8cc49 100644 --- a/Mage.Sets/src/mage/cards/r/RestoreThePeace.java +++ b/Mage.Sets/src/mage/cards/r/RestoreThePeace.java @@ -56,7 +56,7 @@ class RestoreThePeaceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SourceDidDamageWatcher watcher = (SourceDidDamageWatcher) game.getState().getWatchers().get(SourceDidDamageWatcher.class.getSimpleName()); + SourceDidDamageWatcher watcher = game.getState().getWatcher(SourceDidDamageWatcher.class); if (watcher != null) { for (UUID permId : watcher.damageSources) { Permanent perm = game.getPermanent(permId); diff --git a/Mage.Sets/src/mage/cards/r/RetracedImage.java b/Mage.Sets/src/mage/cards/r/RetracedImage.java new file mode 100644 index 0000000000..050e0a7138 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RetracedImage.java @@ -0,0 +1,81 @@ +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCardInHand; + +/** + * + * @author jeffwadsworth + */ +public final class RetracedImage extends CardImpl { + + public RetracedImage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); + + // Reveal a card in your hand, then put that card onto the battlefield if it has the same name as a permanent. + this.getSpellAbility().addEffect(new RetracedImageEffect()); + + } + + private RetracedImage(final RetracedImage card) { + super(card); + } + + @Override + public RetracedImage copy() { + return new RetracedImage(this); + } +} + +class RetracedImageEffect extends OneShotEffect { + + public RetracedImageEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Reveal a card in your hand, then put that card onto the battlefield if it has the same name as a permanent"; + } + + public RetracedImageEffect(final RetracedImageEffect effect) { + super(effect); + } + + @Override + public RetracedImageEffect copy() { + return new RetracedImageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + TargetCardInHand target = new TargetCardInHand(); + if (target.canChoose(controller.getId(), game) + && controller.choose(outcome, target, source.getSourceId(), game)) { + Card chosenCard = game.getCard(target.getFirstTarget()); + if (chosenCard != null) { + Cards cards = new CardsImpl(); + cards.add(chosenCard); + controller.revealCards(source, cards, game); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents()) { + if (permanent.getName().equals(chosenCard.getName())) { + return controller.moveCards(chosenCard, Zone.BATTLEFIELD, source, game); + } + } + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java b/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java index 71c9b5267f..a8768402b7 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToCoralhelm.java @@ -24,7 +24,7 @@ public final class RetreatToCoralhelm extends CardImpl { LandfallAbility ability = new LandfallAbility(new MayTapOrUntapTargetEffect(), false); ability.addTarget(new TargetCreaturePermanent()); Mode mode = new Mode(); - mode.getEffects().add(new ScryEffect(1)); + mode.addEffect(new ScryEffect(1)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java b/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java index bdcd451314..b628cbfbc0 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToEmeria.java @@ -24,7 +24,7 @@ public final class RetreatToEmeria extends CardImpl { // Landfall — Whenever a land enters the battlefield under you control, choose one - Create a 1/1 white Kor Ally creature token; or Creatures you control get +1/+1 until end of turn. LandfallAbility ability = new LandfallAbility(new CreateTokenEffect(new KorAllyToken()), false); Mode mode = new Mode(); - mode.getEffects().add(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); + mode.addEffect(new BoostControlledEffect(1, 1, Duration.EndOfTurn)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToHagra.java b/Mage.Sets/src/mage/cards/r/RetreatToHagra.java index 056271f18e..1b6856cecb 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToHagra.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToHagra.java @@ -32,10 +32,10 @@ public final class RetreatToHagra extends CardImpl { // or Each opponent loses 1 life and you gain 1 life. Mode mode = new Mode(); - mode.getEffects().add(new LoseLifeOpponentsEffect(1)); + mode.addEffect(new LoseLifeOpponentsEffect(1)); Effect effect = new GainLifeEffect(1); effect.setText("and you gain 1 life"); - mode.getEffects().add(effect); + mode.addEffect(effect); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java b/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java index 6255692937..32f48be82f 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToKazandu.java @@ -25,7 +25,7 @@ public final class RetreatToKazandu extends CardImpl { LandfallAbility ability = new LandfallAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()), false); ability.addTarget(new TargetCreaturePermanent()); Mode mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(2)); + mode.addEffect(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/RetreatToValakut.java b/Mage.Sets/src/mage/cards/r/RetreatToValakut.java index 21ca19630a..e1a5c5c82b 100644 --- a/Mage.Sets/src/mage/cards/r/RetreatToValakut.java +++ b/Mage.Sets/src/mage/cards/r/RetreatToValakut.java @@ -27,8 +27,8 @@ public final class RetreatToValakut extends CardImpl { // or Target creature can't block this turn. Mode mode = new Mode(); - mode.getEffects().add(new CantBlockTargetEffect(Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new CantBlockTargetEffect(Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/r/Retribution.java b/Mage.Sets/src/mage/cards/r/Retribution.java index 2c0a7214ad..274f71fd50 100644 --- a/Mage.Sets/src/mage/cards/r/Retribution.java +++ b/Mage.Sets/src/mage/cards/r/Retribution.java @@ -68,7 +68,7 @@ class RetributionEffect extends OneShotEffect { Permanent creature = game.getPermanent(targetId); if (creature != null) { Player controllerOfCreature = game.getPlayer(creature.getControllerId()); - if ((count == 0 + if ((count == 0 && controllerOfCreature != null && controllerOfCreature.chooseUse(Outcome.Sacrifice, "Sacrifice " + creature.getLogName() + '?', source, game)) || (count == 1 && !sacrificeDone)) { diff --git a/Mage.Sets/src/mage/cards/r/RetributionOfTheAncients.java b/Mage.Sets/src/mage/cards/r/RetributionOfTheAncients.java index ce921ada40..42aab39e6f 100644 --- a/Mage.Sets/src/mage/cards/r/RetributionOfTheAncients.java +++ b/Mage.Sets/src/mage/cards/r/RetributionOfTheAncients.java @@ -36,7 +36,7 @@ public final class RetributionOfTheAncients extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); - DynamicValue xValue = new SignInversionDynamicValue(new GetXValue()); + DynamicValue xValue = new SignInversionDynamicValue(GetXValue.instance); // {B}, Remove X +1/+1 counters from among creatures you control: Target creature gets -X/-X until end of turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostTargetEffect(xValue,xValue,Duration.EndOfTurn, true), new ManaCostsImpl("{B}")); ability.addCost(new RemoveVariableCountersTargetCost(filter, CounterType.P1P1, "X", 0)); diff --git a/Mage.Sets/src/mage/cards/r/ReturnToDust.java b/Mage.Sets/src/mage/cards/r/ReturnToDust.java index c57d35ac04..2e25ab591f 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnToDust.java +++ b/Mage.Sets/src/mage/cards/r/ReturnToDust.java @@ -2,52 +2,87 @@ package mage.cards.r; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; -import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author emerald000 */ public final class ReturnToDust extends CardImpl { public ReturnToDust(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{W}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{W}"); // Exile target artifact or enchantment. If you cast this spell during your main phase, you may exile up to one other target artifact or enchantment. - Effect effect = new ExileTargetEffect(); - effect.setText("Exile target artifact or enchantment. If you cast this spell during your main phase, you may exile up to one other target artifact or enchantment"); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new ReturnToDustEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(1, 2, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT, false)); } public ReturnToDust(final ReturnToDust card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - if (game.isActivePlayer(ability.getControllerId()) && game.isMainPhase()) { - ability.addTarget(new TargetPermanent(1, 2, StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT, false)); - } - else { - ability.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); - } - } - } - @Override public ReturnToDust copy() { return new ReturnToDust(this); } } + +class ReturnToDustEffect extends OneShotEffect { + + ReturnToDustEffect() { + super(Outcome.DestroyPermanent); + staticText = "Exile target artifact or enchantment. If you cast this spell during your main phase, you may exile up to one other target artifact or enchantment"; + } + + private ReturnToDustEffect(final ReturnToDustEffect effect) { + super(effect); + } + + @Override + public Effect copy() { + return new ReturnToDustEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int targetsCleared = 0; + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + Permanent permanent = game.getPermanent(targetId); + if (permanent == null) { + continue; + } + if (targetsCleared == 0) { + player.moveCards(permanent, Zone.EXILED, source, game); + targetsCleared++; + } else if (targetsCleared == 1) { + if (game.isActivePlayer(source.getControllerId()) && game.isMainPhase() + && player.chooseUse(outcome, "Exile another permanent?", source, game)) { + player.moveCards(permanent, Zone.EXILED, source, game); + targetsCleared++; + } else { + break; + } + } else { + break; + } + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/ReturnToNature.java b/Mage.Sets/src/mage/cards/r/ReturnToNature.java new file mode 100644 index 0000000000..05f8100159 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/ReturnToNature.java @@ -0,0 +1,47 @@ +package mage.cards.r; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetArtifactPermanent; +import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetEnchantmentPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ReturnToNature extends CardImpl { + + public ReturnToNature(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Choose one — + // • Destroy target artifact. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + + // • Destroy target enchantment. + Mode mode = new Mode(new DestroyTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); + this.getSpellAbility().addMode(mode); + + // • Exile target card from a graveyard. + mode = new Mode(new ExileTargetEffect()); + mode.addTarget(new TargetCardInGraveyard()); + this.getSpellAbility().addMode(mode); + } + + private ReturnToNature(final ReturnToNature card) { + super(card); + } + + @Override + public ReturnToNature copy() { + return new ReturnToNature(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReturnToTheRanks.java b/Mage.Sets/src/mage/cards/r/ReturnToTheRanks.java index c0b4ec5645..326369bf41 100644 --- a/Mage.Sets/src/mage/cards/r/ReturnToTheRanks.java +++ b/Mage.Sets/src/mage/cards/r/ReturnToTheRanks.java @@ -1,7 +1,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; @@ -14,41 +13,26 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ReturnToTheRanks extends CardImpl { - private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 2 or less from your graveyard"); - - static { - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 3)); - } - public ReturnToTheRanks(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{W}{W}"); // Convoke this.addAbility(new ConvokeAbility()); + // Return X target creature cards with converted mana cost 2 or less from your graveyard to the battlefield. Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); effect.setText("Return X target creature cards with converted mana cost 2 or less from your graveyard to the battlefield"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0,Integer.MAX_VALUE, filter)); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - for (Effect effect : ability.getEffects()) { - if (effect instanceof ReturnFromGraveyardToBattlefieldTargetEffect) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(xValue,xValue, filter)); - } - } + this.getSpellAbility().setTargetAdjuster(ReturnToTheRanksAdjuster.instance); } public ReturnToTheRanks(final ReturnToTheRanks card) { @@ -60,3 +44,19 @@ public final class ReturnToTheRanks extends CardImpl { return new ReturnToTheRanks(this); } } + +enum ReturnToTheRanksAdjuster implements TargetAdjuster { + instance; + private static final FilterCreatureCard filter = new FilterCreatureCard("creature cards with converted mana cost 2 or less from your graveyard"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 3)); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(xValue, xValue, filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RevealingWind.java b/Mage.Sets/src/mage/cards/r/RevealingWind.java index a097878a84..c977cd9ddd 100644 --- a/Mage.Sets/src/mage/cards/r/RevealingWind.java +++ b/Mage.Sets/src/mage/cards/r/RevealingWind.java @@ -51,7 +51,7 @@ class RevealingWindEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterAttackingOrBlockingCreature("face-down creature that's attacking or blocking"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public RevealingWindEffect() { @@ -82,8 +82,7 @@ class RevealingWindEffect extends OneShotEffect { if (controller.chooseTarget(outcome, target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards(sourceObject.getName(), cards, game); game.informPlayers(controller.getLogName() + " look at a face-down attacking creature"); } diff --git a/Mage.Sets/src/mage/cards/r/RevelOfTheFallenGod.java b/Mage.Sets/src/mage/cards/r/RevelOfTheFallenGod.java index d5bf111ff4..615c684023 100644 --- a/Mage.Sets/src/mage/cards/r/RevelOfTheFallenGod.java +++ b/Mage.Sets/src/mage/cards/r/RevelOfTheFallenGod.java @@ -1,15 +1,15 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.game.permanent.token.RevelOfTheFallenGodSatyrToken; +import mage.game.permanent.token.XenagosSatyrToken; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class RevelOfTheFallenGod extends CardImpl { @@ -18,7 +18,7 @@ public final class RevelOfTheFallenGod extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}{R}{G}{G}"); // Create four 2/2 red and green Satyr creature tokens with haste. - this.getSpellAbility().addEffect(new CreateTokenEffect(new RevelOfTheFallenGodSatyrToken(), 4)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new XenagosSatyrToken(), 4)); } diff --git a/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java b/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java index 50b1fd07e8..e770b5d439 100644 --- a/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java +++ b/Mage.Sets/src/mage/cards/r/RevenantPatriarch.java @@ -1,4 +1,3 @@ - package mage.cards.r; import java.util.UUID; @@ -8,12 +7,13 @@ import mage.abilities.common.CantBlockAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.ManaWasSpentCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.ColoredManaSymbol; +import mage.constants.Duration; import mage.target.TargetPlayer; import mage.watchers.common.ManaSpentToCastWatcher; @@ -22,26 +22,26 @@ import mage.watchers.common.ManaSpentToCastWatcher; * @author ilcartographer */ public final class RevenantPatriarch extends CardImpl { - + public RevenantPatriarch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(4); this.toughness = new MageInt(3); // When Revenant Patriarch enters the battlefield, if {W} was spent to cast it, target player skips their next combat phase. - TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SkipNextCombatEffect(), false); + TriggeredAbility ability = new EntersBattlefieldTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("target player skips their next combat phase."), false); ability.addTarget(new TargetPlayer()); this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new ManaWasSpentCondition(ColoredManaSymbol.W), "if {W} was spent to cast it, target player skips their next combat phase."), new ManaSpentToCastWatcher()); // Revenant Patriarch can't block. this.addAbility(new CantBlockAbility()); } - + public RevenantPatriarch(final RevenantPatriarch card) { super(card); } - + @Override public RevenantPatriarch copy() { return new RevenantPatriarch(this); diff --git a/Mage.Sets/src/mage/cards/r/Revenge.java b/Mage.Sets/src/mage/cards/r/RevengeStarWars.java similarity index 87% rename from Mage.Sets/src/mage/cards/r/Revenge.java rename to Mage.Sets/src/mage/cards/r/RevengeStarWars.java index 2674b8c0fd..02c4466c76 100644 --- a/Mage.Sets/src/mage/cards/r/Revenge.java +++ b/Mage.Sets/src/mage/cards/r/RevengeStarWars.java @@ -25,9 +25,9 @@ import mage.watchers.common.PlayerLostLifeWatcher; * * @author Styxo */ -public final class Revenge extends CardImpl { +public final class RevengeStarWars extends CardImpl { - public Revenge(UUID ownerId, CardSetInfo setInfo) { + public RevengeStarWars(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Target creature you control gets +4/+0 until end of turn before it fights if you lost life this turn. @@ -45,13 +45,13 @@ public final class Revenge extends CardImpl { } - public Revenge(final Revenge card) { + public RevengeStarWars(final RevengeStarWars card) { super(card); } @Override - public Revenge copy() { - return new Revenge(this); + public RevengeStarWars copy() { + return new RevengeStarWars(this); } } @@ -62,10 +62,10 @@ enum LostLifeCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); UUID player = source.getControllerId(); if (watcher != null && player != null) { - return watcher.getLiveLost(player) > 0; + return watcher.getLifeLost(player) > 0; } return false; } diff --git a/Mage.Sets/src/mage/cards/r/Reverberation.java b/Mage.Sets/src/mage/cards/r/Reverberation.java new file mode 100644 index 0000000000..0a0768ae70 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/Reverberation.java @@ -0,0 +1,105 @@ + +package mage.cards.r; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterSpell; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.DamageEvent; +import mage.game.events.GameEvent; +import mage.game.stack.Spell; +import mage.players.Player; +import mage.target.TargetSpell; + +/** + * + * @author L_J + */ +public final class Reverberation extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("sorcery spell"); + + static { + filter.add(new CardTypePredicate(CardType.SORCERY)); + } + + public Reverberation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}{U}"); + + // All damage that would be dealt this turn by target sorcery spell is dealt to that spell’s controller instead. + this.getSpellAbility().addEffect(new ReverberationEffect()); + this.getSpellAbility().addTarget(new TargetSpell(filter)); + } + + public Reverberation(final Reverberation card) { + super(card); + } + + @Override + public Reverberation copy() { + return new Reverberation(this); + } +} + +class ReverberationEffect extends ReplacementEffectImpl { + + public ReverberationEffect() { + super(Duration.EndOfTurn, Outcome.RedirectDamage); + staticText = "All damage that would be dealt this turn by target sorcery spell is dealt to that spell’s controller instead"; + } + + public ReverberationEffect(final ReverberationEffect effect) { + super(effect); + } + + @Override + public ReverberationEffect copy() { + return new ReverberationEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CREATURE || + event.getType() == GameEvent.EventType.DAMAGE_PLANESWALKER || + event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + DamageEvent damageEvent = (DamageEvent) event; + if (controller != null) { + Spell targetSpell = game.getStack().getSpell(source.getFirstTarget()); + if (targetSpell != null) { + Player targetsController = game.getPlayer(targetSpell.getControllerId()); + if (targetsController != null) { + targetsController.damage(damageEvent.getAmount(), damageEvent.getSourceId(), game, damageEvent.isCombatDamage(), damageEvent.isPreventable(), damageEvent.getAppliedEffects()); + return true; + } + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + DamageEvent damageEvent = (DamageEvent) event; + Spell targetSpell = game.getStack().getSpell(source.getFirstTarget()); + if (targetSpell != null) { + return damageEvent.getAmount() > 0; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java index d68cf09648..80f2f9310c 100644 --- a/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java +++ b/Mage.Sets/src/mage/cards/r/ReversalOfFortune.java @@ -74,7 +74,7 @@ class ReversalOfFortuneEffect extends OneShotEffect { TargetCard target = new TargetCard(1, Zone.HAND, new FilterInstantOrSorceryCard()); target.setRequired(false); if (controller.choose(outcome, revealedCards, target, game)) { - Card card = revealedCards.get((UUID) target.getFirstTarget(), game); + Card card = revealedCards.get(target.getFirstTarget(), game); //If you do, you may cast the copy without paying its mana cost if (card != null) { Card copiedCard = game.copyCard(card, source, source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/r/ReversePolarity.java b/Mage.Sets/src/mage/cards/r/ReversePolarity.java index ca3a31fcb0..360daa6ed2 100644 --- a/Mage.Sets/src/mage/cards/r/ReversePolarity.java +++ b/Mage.Sets/src/mage/cards/r/ReversePolarity.java @@ -46,7 +46,7 @@ class ReversePolarityAmount implements DynamicValue { @Override public int calculate(Game game, Ability source, Effect effect) { - ReversePolarityWatcher watcher = (ReversePolarityWatcher) game.getState().getWatchers().get(ReversePolarityWatcher.class.getSimpleName()); + ReversePolarityWatcher watcher = game.getState().getWatcher(ReversePolarityWatcher.class); if(watcher != null) { return watcher.getArtifactDamageReceivedThisTurn(source.getControllerId()) * 2; } @@ -69,7 +69,7 @@ class ReversePolarityWatcher extends Watcher { private final Map artifactDamageReceivedThisTurn = new HashMap<>(); public ReversePolarityWatcher() { - super(ReversePolarityWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ReversePolarityWatcher(final ReversePolarityWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/r/ReverseTheSands.java b/Mage.Sets/src/mage/cards/r/ReverseTheSands.java index e32829e104..1744c1194d 100644 --- a/Mage.Sets/src/mage/cards/r/ReverseTheSands.java +++ b/Mage.Sets/src/mage/cards/r/ReverseTheSands.java @@ -63,7 +63,7 @@ class ReverseTheSandsEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); if (player != null) { - choices.add(new StringBuilder(Integer.toString(player.getLife())).append(" life of ").append(player.getLogName()).toString()); + choices.add(Integer.toString(player.getLife()) + " life of " + player.getLogName()); } } lifeChoice.setChoices(choices); diff --git a/Mage.Sets/src/mage/cards/r/RevivalRevenge.java b/Mage.Sets/src/mage/cards/r/RevivalRevenge.java new file mode 100644 index 0000000000..61846ac538 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RevivalRevenge.java @@ -0,0 +1,86 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Outcome; +import mage.constants.SpellAbilityType; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RevivalRevenge extends SplitCard { + + private static final FilterCard filter + = new FilterCreatureCard("creature card with converted mana cost 3 or less from your graveyard"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public RevivalRevenge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{W/B}{W/B}", "{4}{W}{B}", SpellAbilityType.SPLIT); + + // Revival + // Return target creature card with converted mana cost 3 or less from your graveyard to the battlefield. + this.getLeftHalfCard().getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetCardInYourGraveyard(filter)); + + // Revenge + // Double your life total. Target opponent loses half their life, rounded up. + this.getRightHalfCard().getSpellAbility().addEffect(new RevivalRevengeEffect()); + this.getRightHalfCard().getSpellAbility().addTarget(new TargetOpponent()); + } + + private RevivalRevenge(final RevivalRevenge card) { + super(card); + } + + @Override + public RevivalRevenge copy() { + return new RevivalRevenge(this); + } +} + +class RevivalRevengeEffect extends OneShotEffect { + + RevivalRevengeEffect() { + super(Outcome.Benefit); + staticText = "Double your life total. Target opponent loses half their life, rounded up."; + } + + private RevivalRevengeEffect(final RevivalRevengeEffect effect) { + super(effect); + } + + @Override + public RevivalRevengeEffect copy() { + return new RevivalRevengeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player player = game.getPlayer(source.getFirstTarget()); + if (controller == null || player == null) { + return false; + } + controller.gainLife(controller.getLife(), game, source); + int life = player.getLife(); + player.loseLife(Math.floorDiv(life, 2) + (life % 2), game, false); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RevivingMelody.java b/Mage.Sets/src/mage/cards/r/RevivingMelody.java index 8ee252ba8c..b9e3573fa3 100644 --- a/Mage.Sets/src/mage/cards/r/RevivingMelody.java +++ b/Mage.Sets/src/mage/cards/r/RevivingMelody.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; @@ -12,8 +10,9 @@ import mage.filter.StaticFilters; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RevivingMelody extends CardImpl { @@ -33,11 +32,11 @@ public final class RevivingMelody extends CardImpl { //Return target creature card from your graveyard to your hand; this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return to hand")); // and/or return target enchantment card from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(filterCard)); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(filterCard).withChooseHint("return to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RevivingVapors.java b/Mage.Sets/src/mage/cards/r/RevivingVapors.java index e64c2fef63..0c90f22883 100644 --- a/Mage.Sets/src/mage/cards/r/RevivingVapors.java +++ b/Mage.Sets/src/mage/cards/r/RevivingVapors.java @@ -60,8 +60,7 @@ class RevivingVaporsEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 3)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); if (!cards.isEmpty()) { controller.revealCards(sourceObject.getName(), cards, game); Card card = null; diff --git a/Mage.Sets/src/mage/cards/r/RewardsOfDiversity.java b/Mage.Sets/src/mage/cards/r/RewardsOfDiversity.java index 76fe7e8c9d..dd1270a20c 100644 --- a/Mage.Sets/src/mage/cards/r/RewardsOfDiversity.java +++ b/Mage.Sets/src/mage/cards/r/RewardsOfDiversity.java @@ -22,7 +22,7 @@ public final class RewardsOfDiversity extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public RewardsOfDiversity(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java index 7428ba1dce..08b6c51ffc 100644 --- a/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java +++ b/Mage.Sets/src/mage/cards/r/RhonasTheIndomitable.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -26,6 +24,8 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** * @author fireshoes */ @@ -34,7 +34,7 @@ public final class RhonasTheIndomitable extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RhonasTheIndomitable(UUID ownerId, CardSetInfo setInfo) { @@ -92,12 +92,12 @@ class RhonasTheIndomitableRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @@ -105,7 +105,7 @@ class RhonasTheIndomitableRestrictionEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); if (permanent.getId().equals(source.getSourceId())) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { diff --git a/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java b/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java index 1a46092cb3..800680e4ef 100644 --- a/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java +++ b/Mage.Sets/src/mage/cards/r/RhysTheRedeemed.java @@ -69,7 +69,7 @@ class RhysTheRedeemedEffect extends OneShotEffect { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public RhysTheRedeemedEffect() { diff --git a/Mage.Sets/src/mage/cards/r/RhythmOfTheWild.java b/Mage.Sets/src/mage/cards/r/RhythmOfTheWild.java new file mode 100644 index 0000000000..85519b4e26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RhythmOfTheWild.java @@ -0,0 +1,128 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.CantBeCounteredControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.FilterSpell; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureSpell; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.TokenPredicate; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.PermanentToken; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RhythmOfTheWild extends CardImpl { + + private static final FilterSpell filter + = new FilterCreatureSpell("Creature spells you control"); + private static final FilterPermanent filter2 + = new FilterControlledCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + filter2.add(Predicates.not(TokenPredicate.instance)); + } + + public RhythmOfTheWild(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}{G}"); + + // Creature spells you control can't be countered. + this.addAbility(new SimpleStaticAbility(new CantBeCounteredControlledEffect( + filter, null, Duration.WhileOnBattlefield + ))); + + // Nontoken creatures you control have riot. + Ability ability = new SimpleStaticAbility(new RhythmOfTheWildEffect()); + ability.addEffect(new GainAbilityControlledEffect( + new RiotAbility(), Duration.WhileOnBattlefield, filter2 + ).setText("")); + this.addAbility(ability); + } + + private RhythmOfTheWild(final RhythmOfTheWild card) { + super(card); + } + + @Override + public RhythmOfTheWild copy() { + return new RhythmOfTheWild(this); + } +} + +class RhythmOfTheWildEffect extends ReplacementEffectImpl { + + RhythmOfTheWildEffect() { + super(Duration.WhileOnBattlefield, Outcome.BoostCreature); + staticText = "Nontoken creatures you control have riot. " + + "(They enter the battlefield with your choice of a +1/+1 counter or haste.)"; + } + + private RhythmOfTheWildEffect(RhythmOfTheWildEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + return creature != null + && creature.isControlledBy(source.getControllerId()) + && creature.isCreature() + && !(creature instanceof PermanentToken); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + Player player = game.getPlayer(source.getControllerId()); + if (creature == null || player == null) { + return false; + } + if (player.chooseUse( + outcome, "Have " + creature.getLogName() + " enter the battlefield with a +1/+1 counter on it or with haste?", + null, "+1/+1 counter", "Haste", source, game + )) { + game.informPlayers(player.getLogName() + " choose to put a +1/+1 counter on " + creature.getName()); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } else { + ContinuousEffect effect = new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.Custom); + effect.setTargetPointer(new FixedTarget(creature.getId(), creature.getZoneChangeCounter(game) + 1)); + game.addEffect(effect, source); + } + return false; + } + + @Override + public RhythmOfTheWildEffect copy() { + return new RhythmOfTheWildEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RhythmicWaterVortex.java b/Mage.Sets/src/mage/cards/r/RhythmicWaterVortex.java index 01f4b225ac..412162b3f4 100644 --- a/Mage.Sets/src/mage/cards/r/RhythmicWaterVortex.java +++ b/Mage.Sets/src/mage/cards/r/RhythmicWaterVortex.java @@ -16,7 +16,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class RhythmicWaterVortex extends CardImpl { - private final static FilterCard filter = new FilterCard("Mu Yanling"); + private static final FilterCard filter = new FilterCard("Mu Yanling"); static { filter.add(new NamePredicate("Mu Yanling")); diff --git a/Mage.Sets/src/mage/cards/r/RicochetTrap.java b/Mage.Sets/src/mage/cards/r/RicochetTrap.java index 414dafbf65..5f3f059feb 100644 --- a/Mage.Sets/src/mage/cards/r/RicochetTrap.java +++ b/Mage.Sets/src/mage/cards/r/RicochetTrap.java @@ -61,7 +61,7 @@ enum RicochetTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List spells = watcher.getSpellsCastThisTurn(opponentId); diff --git a/Mage.Sets/src/mage/cards/r/RideDown.java b/Mage.Sets/src/mage/cards/r/RideDown.java index ad68abe732..65e87b36d8 100644 --- a/Mage.Sets/src/mage/cards/r/RideDown.java +++ b/Mage.Sets/src/mage/cards/r/RideDown.java @@ -30,7 +30,7 @@ public final class RideDown extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creature"); static { - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } public RideDown(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RidgescaleTusker.java b/Mage.Sets/src/mage/cards/r/RidgescaleTusker.java index aad9662f1d..47deb75e59 100644 --- a/Mage.Sets/src/mage/cards/r/RidgescaleTusker.java +++ b/Mage.Sets/src/mage/cards/r/RidgescaleTusker.java @@ -22,7 +22,7 @@ public final class RidgescaleTusker extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RidgescaleTusker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/Riftsweeper.java b/Mage.Sets/src/mage/cards/r/Riftsweeper.java index bdbba5d46f..8fc19bea15 100644 --- a/Mage.Sets/src/mage/cards/r/Riftsweeper.java +++ b/Mage.Sets/src/mage/cards/r/Riftsweeper.java @@ -27,7 +27,7 @@ public final class Riftsweeper extends CardImpl { private static final FilterCard filter = new FilterCard("face-up exiled card"); static { - filter.add(Predicates.not(new FaceDownPredicate())); + filter.add(Predicates.not(FaceDownPredicate.instance)); } public Riftsweeper(UUID ownerId, CardSetInfo setInfo) { @@ -79,7 +79,7 @@ class RiftsweeperEffect extends OneShotEffect { // move to exile card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); game.getPlayer(card.getOwnerId()).shuffleLibrary(source, game); - game.informPlayers(new StringBuilder("Riftsweeper: Choosen card was ").append(card.getName()).toString()); + game.informPlayers("Riftsweeper: Choosen card was " + card.getName()); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/r/RighteousAuthority.java b/Mage.Sets/src/mage/cards/r/RighteousAuthority.java index 8e066aae9a..399c1a17cf 100644 --- a/Mage.Sets/src/mage/cards/r/RighteousAuthority.java +++ b/Mage.Sets/src/mage/cards/r/RighteousAuthority.java @@ -2,7 +2,6 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfDrawTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -21,18 +20,18 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RighteousAuthority extends CardImpl { - public RighteousAuthority (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{U}"); + public RighteousAuthority(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{U}"); this.subtype.add(SubType.AURA); - // Enchant creature TargetPermanent auraTarget = new TargetCreaturePermanent(); this.getSpellAbility().addTarget(auraTarget); @@ -48,7 +47,7 @@ public final class RighteousAuthority extends CardImpl { this.addAbility(new BeginningOfDrawTriggeredAbility(new DrawCardTargetEffect(1), TargetController.CONTROLLER_ATTACHED_TO, false)); } - public RighteousAuthority (final RighteousAuthority card) { + public RighteousAuthority(final RighteousAuthority card) { super(card); } @@ -79,7 +78,7 @@ class CardsInEnchantedControllerHandCount implements DynamicValue { @Override public DynamicValue copy() { - return new mage.abilities.dynamicvalue.common.CardsInControllerHandCount(); + return new CardsInEnchantedControllerHandCount(); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RighteousConfluence.java b/Mage.Sets/src/mage/cards/r/RighteousConfluence.java index 3d37750f4f..3f43115e4a 100644 --- a/Mage.Sets/src/mage/cards/r/RighteousConfluence.java +++ b/Mage.Sets/src/mage/cards/r/RighteousConfluence.java @@ -31,13 +31,13 @@ public final class RighteousConfluence extends CardImpl { // - Exile target enchantment; Mode mode = new Mode(); - mode.getEffects().add(new ExileTargetEffect()); - mode.getTargets().add(new TargetEnchantmentPermanent()); + mode.addEffect(new ExileTargetEffect()); + mode.addTarget(new TargetEnchantmentPermanent()); this.getSpellAbility().getModes().addMode(mode); // You gain 5 life; mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(5)); + mode.addEffect(new GainLifeEffect(5)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RighteousFury.java b/Mage.Sets/src/mage/cards/r/RighteousFury.java index c7cc019ffc..6aa334fe0e 100644 --- a/Mage.Sets/src/mage/cards/r/RighteousFury.java +++ b/Mage.Sets/src/mage/cards/r/RighteousFury.java @@ -60,7 +60,7 @@ class RighteousFuryEffect extends OneShotEffect { if (controller != null) { int destroyedCreature = 0; FilterCreaturePermanent filter = new FilterCreaturePermanent("all tapped creatures"); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); for(Permanent creature: game.getState().getBattlefield().getActivePermanents(filter, controller.getId(), game)) { if (creature.destroy(source.getSourceId(), game, false)) { destroyedCreature++; diff --git a/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java b/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java index ba5d5bab91..255c570ecf 100644 --- a/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java +++ b/Mage.Sets/src/mage/cards/r/RikuOfTwoReflections.java @@ -1,22 +1,16 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.common.CopyTargetSpellEffect; -import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.SetTargetPointer; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterSpell; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -24,8 +18,9 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; import mage.filter.predicate.permanent.TokenPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RikuOfTwoReflections extends CardImpl { @@ -37,8 +32,8 @@ public final class RikuOfTwoReflections extends CardImpl { filter.add(Predicates.or( new CardTypePredicate(CardType.INSTANT), new CardTypePredicate(CardType.SORCERY))); - filterPermanent.add(Predicates.not(new TokenPredicate())); - filterPermanent.add(new AnotherPredicate()); + filterPermanent.add(Predicates.not(TokenPredicate.instance)); + filterPermanent.add(AnotherPredicate.instance); } @@ -53,7 +48,6 @@ public final class RikuOfTwoReflections extends CardImpl { // Whenever you cast an instant or sorcery spell, you may pay {U}{R}. If you do, copy that spell. You may choose new targets for the copy. Effect effect = new CopyTargetSpellEffect(true); - effect.setText("copy that spell. You may choose new targets for the copy"); this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(effect, new ManaCostsImpl("{U}{R}")), filter, false, true)); // Whenever another nontoken creature enters the battlefield under your control, you may pay {G}{U}. If you do, create a token that's a copy of that creature. diff --git a/Mage.Sets/src/mage/cards/r/RimehornAurochs.java b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java index 1976045e92..b1488d7428 100644 --- a/Mage.Sets/src/mage/cards/r/RimehornAurochs.java +++ b/Mage.Sets/src/mage/cards/r/RimehornAurochs.java @@ -32,8 +32,8 @@ public final class RimehornAurochs extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.AUROCHS, "other attacking Aurochs"); static { - filter.add(new AttackingPredicate()); - filter.add(new AnotherPredicate()); + filter.add(AttackingPredicate.instance); + filter.add(AnotherPredicate.instance); } public RimehornAurochs(UUID ownerId, CardSetInfo setInfo) { @@ -87,9 +87,9 @@ class RimehornAurochsEffect extends RequirementEffect { Permanent blocker = game.getPermanent(source.getTargets().get(0).getFirstTarget()); if (blocker != null && blocker.canBlock(source.getTargets().get(1).getFirstTarget(), game)) { - Permanent attacker = (Permanent) game.getPermanent(source.getTargets().get(1).getFirstTarget()); + Permanent attacker = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (attacker != null) { - BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher blockedAttackerWatcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) { // has already blocked this turn, so no need to do again diff --git a/Mage.Sets/src/mage/cards/r/RingOfImmortals.java b/Mage.Sets/src/mage/cards/r/RingOfImmortals.java index 3d61da68c2..bca0f2387d 100644 --- a/Mage.Sets/src/mage/cards/r/RingOfImmortals.java +++ b/Mage.Sets/src/mage/cards/r/RingOfImmortals.java @@ -26,7 +26,7 @@ import mage.target.TargetSpell; */ public final class RingOfImmortals extends CardImpl { - private final static FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); + private static final FilterSpell filter = new FilterSpell("instant or Aura spell that targets a permanent you control"); static { filter.add(Predicates.or(new CardTypePredicate(CardType.INSTANT), new SubtypePredicate(SubType.AURA))); diff --git a/Mage.Sets/src/mage/cards/r/Ringskipper.java b/Mage.Sets/src/mage/cards/r/Ringskipper.java index 82e16e5b1f..fceb01e0ce 100644 --- a/Mage.Sets/src/mage/cards/r/Ringskipper.java +++ b/Mage.Sets/src/mage/cards/r/Ringskipper.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.effects.common.DoIfClashWonEffect; @@ -12,24 +10,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** - * * @author Styxo */ public final class Ringskipper extends CardImpl { public Ringskipper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.FAERIE); this.subtype.add(SubType.WIZARD); this.power = new MageInt(1); this.toughness = new MageInt(1); - //Flying + // Flying this.addAbility(FlyingAbility.getInstance()); - //When {this} is put into graveyard from play, clash with an opponent. If you win return {this} to its owner's hand + // When {this} is put into graveyard from play, clash with an opponent. If you win return {this} to its owner's hand this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DoIfClashWonEffect(new ReturnToHandSourceEffect()))); } diff --git a/Mage.Sets/src/mage/cards/r/RiptideChronologist.java b/Mage.Sets/src/mage/cards/r/RiptideChronologist.java index 71ee115eed..6149c2b7bd 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideChronologist.java +++ b/Mage.Sets/src/mage/cards/r/RiptideChronologist.java @@ -66,15 +66,17 @@ class RiptideChronologistEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (player != null && player.choose(outcome, typeChoice, game)) { - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); - filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { - creature.untap(game); + if (player != null && sourceObject != null) { + Choice typeChoice = new ChoiceCreatureType(sourceObject); + if (player.choose(outcome, typeChoice, game)) { + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); + filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { + creature.untap(game); + } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/r/RiptideLaboratory.java b/Mage.Sets/src/mage/cards/r/RiptideLaboratory.java index dc0eeae984..049835c8ed 100644 --- a/Mage.Sets/src/mage/cards/r/RiptideLaboratory.java +++ b/Mage.Sets/src/mage/cards/r/RiptideLaboratory.java @@ -23,7 +23,7 @@ import mage.target.common.TargetControlledPermanent; */ public final class RiptideLaboratory extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("Wizard you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("Wizard you control"); static { filter.add(new SubtypePredicate(SubType.WIZARD)); diff --git a/Mage.Sets/src/mage/cards/r/RiseFall.java b/Mage.Sets/src/mage/cards/r/RiseFall.java index d636a11e8e..b3042b9902 100644 --- a/Mage.Sets/src/mage/cards/r/RiseFall.java +++ b/Mage.Sets/src/mage/cards/r/RiseFall.java @@ -113,12 +113,11 @@ class FallEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(getTargetPointer().getFirst(game, source)); if (targetPlayer != null) { if (!targetPlayer.getHand().isEmpty()) { - Cards cards = new CardsImpl(); Card card = targetPlayer.getHand().getRandom(game); if (card == null) { return false; } - cards.add(card); + Cards cards = new CardsImpl(card); if (targetPlayer.getHand().size() > 1) { do { card = targetPlayer.getHand().getRandom(game); diff --git a/Mage.Sets/src/mage/cards/r/RiseFromTheTides.java b/Mage.Sets/src/mage/cards/r/RiseFromTheTides.java index cdd12e6bea..56e5849d63 100644 --- a/Mage.Sets/src/mage/cards/r/RiseFromTheTides.java +++ b/Mage.Sets/src/mage/cards/r/RiseFromTheTides.java @@ -1,27 +1,30 @@ - package mage.cards.r; -import java.util.UUID; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.ValueHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterInstantOrSorceryCard; +import mage.filter.StaticFilters; import mage.game.permanent.token.ZombieToken; +import java.util.UUID; + /** - * * @author fireshoes */ public final class RiseFromTheTides extends CardImpl { + private static final DynamicValue cardsCount = new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY); + public RiseFromTheTides(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{U}"); // Create a tapped 2/2 black Zombie creature token for each instant and sorcery card in your graveyard. - CardsInControllerGraveyardCount value = new CardsInControllerGraveyardCount(new FilterInstantOrSorceryCard()); - this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), value, true, false)); + this.getSpellAbility().addEffect(new CreateTokenEffect(new ZombieToken(), cardsCount, true, false)); + this.getSpellAbility().addHint(new ValueHint("Instant and sorcery card in your graveyard", cardsCount)); } public RiseFromTheTides(final RiseFromTheTides card) { diff --git a/Mage.Sets/src/mage/cards/r/RishadanPawnshop.java b/Mage.Sets/src/mage/cards/r/RishadanPawnshop.java index af39234664..a51c3ece19 100644 --- a/Mage.Sets/src/mage/cards/r/RishadanPawnshop.java +++ b/Mage.Sets/src/mage/cards/r/RishadanPawnshop.java @@ -32,7 +32,7 @@ public final class RishadanPawnshop extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("nontoken permanent you control"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java b/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java index 5b34fdd0d1..591437ed8f 100644 --- a/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java +++ b/Mage.Sets/src/mage/cards/r/RishkarPeemaRenegade.java @@ -31,7 +31,7 @@ public final class RishkarPeemaRenegade extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each creature you control with a counter on it"); static { - filter.add(new CounterAnyPredicate()); + filter.add(CounterAnyPredicate.instance); } public RishkarPeemaRenegade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java b/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java index 35ff9c2d52..4dd55e8cdc 100644 --- a/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java +++ b/Mage.Sets/src/mage/cards/r/RishkarsExpertise.java @@ -19,7 +19,7 @@ public final class RishkarsExpertise extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}{G}"); // Draw cards equal to the greatest power among creatures you control. - Effect effect = new DrawCardSourceControllerEffect(new GreatestPowerAmongControlledCreaturesValue()); + Effect effect = new DrawCardSourceControllerEffect(GreatestPowerAmongControlledCreaturesValue.instance); effect.setText("Draw cards equal to the greatest power among creatures you control"); this.getSpellAbility().addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/r/RisingPopulace.java b/Mage.Sets/src/mage/cards/r/RisingPopulace.java new file mode 100644 index 0000000000..dfb3a35d4d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RisingPopulace.java @@ -0,0 +1,54 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; +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.constants.TargetController; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RisingPopulace extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("another creature or planeswalker you control"); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public RisingPopulace(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever another creature or planeswalker you control dies, put a +1/+1 counter on Rising Populace. + this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, filter, false + )); + } + + private RisingPopulace(final RisingPopulace card) { + super(card); + } + + @Override + public RisingPopulace copy() { + return new RisingPopulace(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RiskyMove.java b/Mage.Sets/src/mage/cards/r/RiskyMove.java index 7b5c9c8cc6..b72f91ad8d 100644 --- a/Mage.Sets/src/mage/cards/r/RiskyMove.java +++ b/Mage.Sets/src/mage/cards/r/RiskyMove.java @@ -76,8 +76,8 @@ class RiskyMoveGetControlEffect extends OneShotEffect { // remove old control effects of the same player for (ContinuousEffect effect : game.getState().getContinuousEffects().getLayeredEffects(game)) { if (effect instanceof GainControlTargetEffect) { - UUID checkId = (UUID) ((GainControlTargetEffect) effect).getValue("RiskyMoveSourceId"); - UUID controllerId = (UUID) ((GainControlTargetEffect) effect).getValue("RiskyMoveControllerId"); + UUID checkId = (UUID) effect.getValue("RiskyMoveSourceId"); + UUID controllerId = (UUID) effect.getValue("RiskyMoveControllerId"); if (source.getSourceId().equals(checkId) && newController.getId().equals(controllerId)) { effect.discard(); } @@ -162,7 +162,7 @@ class RiskyMoveFlipCoinEffect extends OneShotEffect { } Permanent permanent = game.getPermanent(target1.getFirstTarget()); Player chosenOpponent = game.getPlayer(target2.getFirstTarget()); - if (!controller.flipCoin(game)) { + if (!controller.flipCoin(source, game, true)) { if (permanent != null && chosenOpponent != null) { ContinuousEffect effect = new RiskyMoveCreatureGainControlEffect(Duration.Custom, chosenOpponent.getId()); effect.setTargetPointer(new FixedTarget(permanent.getId())); diff --git a/Mage.Sets/src/mage/cards/r/RithTheAwakener.java b/Mage.Sets/src/mage/cards/r/RithTheAwakener.java index 3441c4f45c..39e300e367 100644 --- a/Mage.Sets/src/mage/cards/r/RithTheAwakener.java +++ b/Mage.Sets/src/mage/cards/r/RithTheAwakener.java @@ -78,7 +78,7 @@ class RithTheAwakenerEffect extends OneShotEffect { } ChoiceColor choice = new ChoiceColor(); if (controller.choose(outcome, choice, game)) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" chooses ").append(choice.getColor()).toString()); + game.informPlayers(controller.getLogName() + " chooses " + choice.getColor()); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate(choice.getColor())); int cardsWithColor = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); diff --git a/Mage.Sets/src/mage/cards/r/RithsCharm.java b/Mage.Sets/src/mage/cards/r/RithsCharm.java index 5fd83f5445..19ac8401d5 100644 --- a/Mage.Sets/src/mage/cards/r/RithsCharm.java +++ b/Mage.Sets/src/mage/cards/r/RithsCharm.java @@ -27,12 +27,12 @@ public final class RithsCharm extends CardImpl { // or create three 1/1 green Saproling creature tokens; Mode mode = new Mode(); - mode.getEffects().add(new CreateTokenEffect(new SaprolingToken(), 3)); + mode.addEffect(new CreateTokenEffect(new SaprolingToken(), 3)); this.getSpellAbility().addMode(mode); // or prevent all damage a source of your choice would deal this turn. mode = new Mode(); - mode.getEffects().add(new PreventDamageBySourceEffect()); + mode.addEffect(new PreventDamageBySourceEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RivalsDuel.java b/Mage.Sets/src/mage/cards/r/RivalsDuel.java index a342736f02..08d8be7d6e 100644 --- a/Mage.Sets/src/mage/cards/r/RivalsDuel.java +++ b/Mage.Sets/src/mage/cards/r/RivalsDuel.java @@ -1,4 +1,3 @@ - package mage.cards.r; import java.util.UUID; @@ -51,8 +50,16 @@ class RivalsDuelFightTargetsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent creature1 = game.getPermanent(source.getFirstTarget()); - Permanent creature2 = game.getPermanent(source.getTargets().get(0).getTargets().get(1)); + Permanent creature1 = null; + Permanent creature2 = null; + for (UUID targetId : getTargetPointer().getTargets(game, source)) { + if (creature1 == null) { + creature1 = game.getPermanent(targetId); + } else { + creature2 = game.getPermanent(targetId); + } + } + // 20110930 - 701.10 if (creature1 != null && creature2 != null) { diff --git a/Mage.Sets/src/mage/cards/r/RiverSerpent.java b/Mage.Sets/src/mage/cards/r/RiverSerpent.java index d6ad3f4476..c423639f41 100644 --- a/Mage.Sets/src/mage/cards/r/RiverSerpent.java +++ b/Mage.Sets/src/mage/cards/r/RiverSerpent.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -12,21 +10,22 @@ import mage.abilities.keyword.CyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author stravant */ public final class RiverSerpent extends CardImpl { public RiverSerpent(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); - + this.subtype.add(SubType.SERPENT); this.power = new MageInt(5); this.toughness = new MageInt(5); @@ -64,7 +63,7 @@ class RiverSerpentEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RiverSneak.java b/Mage.Sets/src/mage/cards/r/RiverSneak.java index ccb15f52ab..ce86dc98cf 100644 --- a/Mage.Sets/src/mage/cards/r/RiverSneak.java +++ b/Mage.Sets/src/mage/cards/r/RiverSneak.java @@ -27,7 +27,7 @@ public final class RiverSneak extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another Merfolk"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new SubtypePredicate(SubType.MERFOLK)); } diff --git a/Mage.Sets/src/mage/cards/r/RiversFavor.java b/Mage.Sets/src/mage/cards/r/RiversFavor.java new file mode 100644 index 0000000000..523500e1ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RiversFavor.java @@ -0,0 +1,47 @@ +package mage.cards.r; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class RiversFavor extends CardImpl { + + public RiversFavor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +1/+1. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEnchantedEffect(1, 1))); + } + + public RiversFavor(final RiversFavor card) { + super(card); + } + + @Override + public RiversFavor copy() { + return new RiversFavor(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java b/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java index 0f8e1c76a9..4f4dcf71c3 100644 --- a/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java +++ b/Mage.Sets/src/mage/cards/r/RixMaadiGuildmage.java @@ -72,9 +72,9 @@ class PlayerLostLifePredicate implements Predicate { @Override public boolean apply(Player input, Game game) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { - return (0 < watcher.getLiveLost(input.getId())); + return (0 < watcher.getLifeLost(input.getId())); } return false; } diff --git a/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java new file mode 100644 index 0000000000..82136a1ee7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RixMaadiReveler.java @@ -0,0 +1,83 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.SpectacleCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.SpectacleAbility; +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.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RixMaadiReveler extends CardImpl { + + public RixMaadiReveler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Spectacle {2}{B}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{2}{B}{R}"))); + + // When Rix Maadi Reveler enters the battlefield, discard a card, then draw a card. If Rix Maadi Reveler's spectacle cost was paid, instead discard your hand, then draw three cards. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RixMaadiRevelerEffect(), false)); + } + + public RixMaadiReveler(final RixMaadiReveler card) { + super(card); + } + + @Override + public RixMaadiReveler copy() { + return new RixMaadiReveler(this); + } +} + +class RixMaadiRevelerEffect extends OneShotEffect { + + RixMaadiRevelerEffect() { + super(Outcome.Benefit); + staticText = "discard a card, then draw a card. " + + "If {this}'s spectacle cost was paid, " + + "instead discard your hand, then draw three cards."; + } + + private RixMaadiRevelerEffect(final RixMaadiRevelerEffect effect) { + super(effect); + } + + @Override + public RixMaadiRevelerEffect copy() { + return new RixMaadiRevelerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (SpectacleCondition.instance.apply(game, source)) { + player.discard(player.getHand().size(), false, source, game); + player.drawCards(3, game); + } else { + player.discard(1, false, source, game); + player.drawCards(1, game); + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoaleskApexHybrid.java b/Mage.Sets/src/mage/cards/r/RoaleskApexHybrid.java new file mode 100644 index 0000000000..6c77689b4a --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoaleskApexHybrid.java @@ -0,0 +1,72 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoaleskApexHybrid extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public RoaleskApexHybrid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Roalesk, Apex Hybrid enters the battlefield, put two +1/+1 counters on another target creature you control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)) + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // When Roalsk dies, proliferate, then proliferate again. (Choose any number of permanents and/or players, then give each another counter of each kind already there. Then do it again.) + ability = new DiesTriggeredAbility(new ProliferateEffect(false)); + ability.addEffect(new ProliferateEffect(" again", true).concatBy(", then")); + this.addAbility(ability); + } + + private RoaleskApexHybrid(final RoaleskApexHybrid card) { + super(card); + } + + @Override + public RoaleskApexHybrid copy() { + return new RoaleskApexHybrid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RoarOfChallenge.java b/Mage.Sets/src/mage/cards/r/RoarOfChallenge.java index 9ba4eaa3d6..3c7461f8da 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfChallenge.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfChallenge.java @@ -1,12 +1,11 @@ - package mage.cards.r; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.combat.MustBeBlockedByAllTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.IndestructibleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,14 +13,15 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RoarOfChallenge extends CardImpl { public RoarOfChallenge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // All creatures able to block target creature this turn do so. @@ -32,6 +32,7 @@ public final class RoarOfChallenge extends CardImpl { new LockedInCondition(FerociousCondition.instance), "
    Ferocious — That creature gains indestructible until end of turn if you control a creature with power 4 or greater.")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addHint(FerociousHint.instance); } public RoarOfChallenge(final RoarOfChallenge card) { diff --git a/Mage.Sets/src/mage/cards/r/RoarOfJukai.java b/Mage.Sets/src/mage/cards/r/RoarOfJukai.java index 153308f339..0945b7fbdf 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfJukai.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfJukai.java @@ -59,7 +59,7 @@ class RoarOfJukaiEffect extends OneShotEffect { static { filter.add(new SubtypePredicate(SubType.FOREST)); - filterBlocked.add(new BlockedPredicate()); + filterBlocked.add(BlockedPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java b/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java index 02c81f0a7f..5fc4c8a788 100644 --- a/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java +++ b/Mage.Sets/src/mage/cards/r/RoarOfTheKha.java @@ -28,7 +28,7 @@ public final class RoarOfTheKha extends CardImpl { // or untap all creatures you control. Mode mode = new Mode(); - mode.getEffects().add(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), rule)); + mode.addEffect(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), rule)); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{W} diff --git a/Mage.Sets/src/mage/cards/r/RockSlide.java b/Mage.Sets/src/mage/cards/r/RockSlide.java index e1bb04fa43..fe4a7869d9 100644 --- a/Mage.Sets/src/mage/cards/r/RockSlide.java +++ b/Mage.Sets/src/mage/cards/r/RockSlide.java @@ -26,8 +26,8 @@ public final class RockSlide extends CardImpl { static { filter.add(Predicates.or( - new AttackingPredicate(), - new BlockingPredicate() + AttackingPredicate.instance, + BlockingPredicate.instance )); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } @@ -36,7 +36,7 @@ public final class RockSlide extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{R}"); // Rock Slide deals X damage divided as you choose among any number of target attacking or blocking creatures without flying. - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new DamageMultiEffect(xValue)); this.getSpellAbility().addTarget(new TargetCreaturePermanentAmount(xValue, filter)); } diff --git a/Mage.Sets/src/mage/cards/r/RocketLauncher.java b/Mage.Sets/src/mage/cards/r/RocketLauncher.java index 5fb0060a45..ed0fcbcc7b 100644 --- a/Mage.Sets/src/mage/cards/r/RocketLauncher.java +++ b/Mage.Sets/src/mage/cards/r/RocketLauncher.java @@ -52,18 +52,18 @@ public final class RocketLauncher extends CardImpl { class RocketLauncherWatcher extends Watcher { - boolean changedControllerOR1stTurn; - UUID cardId = null; + private boolean changedControllerOR1stTurn; + private UUID cardId = null; public RocketLauncherWatcher(UUID cardId) { - super(RocketLauncherWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.changedControllerOR1stTurn = true; this.cardId = cardId; } public RocketLauncherWatcher(final RocketLauncherWatcher watcher) { super(watcher); - this.changedControllerOR1stTurn = watcher.changedControllerOR1stTurn; + this.changedControllerOR1stTurn = watcher.isChangedControllerOR1stTurn(); this.cardId = watcher.cardId; } @@ -88,6 +88,10 @@ class RocketLauncherWatcher extends Watcher { super.reset(); changedControllerOR1stTurn = true; //when is this reset called? may cause problems if in mid-life } + + public boolean isChangedControllerOR1stTurn() { + return changedControllerOR1stTurn; + } } enum ControlledTurnCondition implements Condition { @@ -97,9 +101,9 @@ enum ControlledTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - RocketLauncherWatcher watcher = (RocketLauncherWatcher) game.getState().getWatchers().get(RocketLauncherWatcher.class.getSimpleName()); + RocketLauncherWatcher watcher = game.getState().getWatcher(RocketLauncherWatcher.class); - return !watcher.changedControllerOR1stTurn; + return watcher != null && !watcher.isChangedControllerOR1stTurn(); } @Override diff --git a/Mage.Sets/src/mage/cards/r/RodOfSpanking.java b/Mage.Sets/src/mage/cards/r/RodOfSpanking.java new file mode 100644 index 0000000000..34c2506033 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RodOfSpanking.java @@ -0,0 +1,80 @@ + +package mage.cards.r; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.UntapSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +/** + * + * @author North + */ +public final class RodOfSpanking extends CardImpl { + + public RodOfSpanking(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.ARTIFACT }, "{1}"); + + // 2, T: Rod of Spanking deals 1 damage to target player. Then untap Rod of + // Spanking unless that player says "Thank you, sir. May I have another?" + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RodOfSpankingEffect(), new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + public RodOfSpanking(final RodOfSpanking card) { + super(card); + } + + @Override + public RodOfSpanking copy() { + return new RodOfSpanking(this); + } +} + +class RodOfSpankingEffect extends OneShotEffect { + + public RodOfSpankingEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 1 damage to target player. Then untap {this} unless that player says \"Thank you, sir. May I have another?\""; + } + + public RodOfSpankingEffect(final RodOfSpankingEffect effect) { + super(effect); + } + + @Override + public RodOfSpankingEffect copy() { + return new RodOfSpankingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player target = game.getPlayer(source.getFirstTarget()); + new DamageTargetEffect(1).apply(game, source); + if (target != null) { + if (target.chooseUse(Outcome.Untap, "Say \"Thank you, sir. May I have another?\"", source, game)) { + game.informPlayers(target.getLogName() + ": Thank you, sir. May I have another?"); + } else { + new UntapSourceEffect().apply(game, source); + } + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java b/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java new file mode 100644 index 0000000000..029c8fff97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RogueSkycaptain.java @@ -0,0 +1,103 @@ +package mage.cards.r; + +import java.util.Set; +import java.util.UUID; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RemoveAllCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetOpponent; + +/** + * + * @author Ketsuban + */ +public class RogueSkycaptain extends CardImpl { + + public RogueSkycaptain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{2}{R}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.MERCENARY); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your upkeep, put a wage counter on Rogue Skycaptain. You + // may pay 2 for each wage counter on it. If you don't, remove all wage counters + // from Rogue Skycaptain and an opponent gains control of it. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RogueSkycaptainEffect(), TargetController.YOU, false)); + } + + @Override + public Card copy() { + return null; + } + +} + +class RogueSkycaptainEffect extends OneShotEffect { + + public RogueSkycaptainEffect() { + super(Outcome.GainControl); + staticText = "put a wage counter on {this}. You may pay {2} for each wage counter on it. If you don't, remove all wage counters from {this} and an opponent gains control of it"; + } + + public RogueSkycaptainEffect(final RogueSkycaptainEffect effect) { + super(effect); + } + + @Override + public Effect copy() { + return new RogueSkycaptainEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (controller != null && permanent != null) { + new AddCountersSourceEffect(CounterType.WAGE.createInstance(), true).apply(game, source); + Cost cost = new GenericManaCost(2 * permanent.getCounters(game).getCount(CounterType.WAGE)); + if (!cost.pay(source, game, controller.getId(), controller.getId(), false)) { + new RemoveAllCountersSourceEffect(CounterType.WAGE).apply(game, source); + Player opponent; + Set opponents = game.getOpponents(controller.getId()); + if (opponents.size() == 1) { + opponent = game.getPlayer(opponents.iterator().next()); + } else { + Target target = new TargetOpponent(true); + target.setNotTarget(true); + target.choose(Outcome.GainControl, source.getControllerId(), source.getSourceId(), game); + opponent = game.getPlayer(target.getFirstTarget()); + } + if (opponent != null) { + permanent.changeControllerId(opponent.getId(), game); + } + } + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RoilingWaters.java b/Mage.Sets/src/mage/cards/r/RoilingWaters.java index e0ba7dd30b..a6d1d69d83 100644 --- a/Mage.Sets/src/mage/cards/r/RoilingWaters.java +++ b/Mage.Sets/src/mage/cards/r/RoilingWaters.java @@ -21,7 +21,7 @@ import mage.target.targetpointer.SecondTargetPointer; */ public final class RoilingWaters extends CardImpl { - private final static FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creatures your opponents control"); + private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("creatures your opponents control"); static { FILTER.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java b/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java index b4af39f406..496d1bd6a7 100644 --- a/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java +++ b/Mage.Sets/src/mage/cards/r/RoilmagesTrick.java @@ -22,7 +22,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class RoilmagesTrick extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures your opponents control"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/r/RoleReversal.java b/Mage.Sets/src/mage/cards/r/RoleReversal.java new file mode 100644 index 0000000000..f568a24904 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RoleReversal.java @@ -0,0 +1,94 @@ +package mage.cards.r; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RoleReversal extends CardImpl { + + public RoleReversal(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{U}{R}"); + + // Exchange control of two target permanents that share a permanent type. + this.getSpellAbility().addEffect(new ExchangeControlTargetEffect( + Duration.EndOfGame, "Exchange control of two target permanents that share a permanent type." + )); + this.getSpellAbility().addTarget(new TargetPermanentsThatShareCardType()); + } + + private RoleReversal(final RoleReversal card) { + super(card); + } + + @Override + public RoleReversal copy() { + return new RoleReversal(this); + } +} + +class TargetPermanentsThatShareCardType extends TargetPermanent { + + TargetPermanentsThatShareCardType() { + super(2, 2, StaticFilters.FILTER_PERMANENT, false); + targetName = "permanents that share a permanent type"; + } + + private TargetPermanentsThatShareCardType(final TargetPermanentsThatShareCardType target) { + super(target); + } + + @Override + public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { + if (super.canTarget(controllerId, id, source, game)) { + if (!getTargets().isEmpty()) { + Permanent targetOne = game.getPermanent(getTargets().get(0)); + Permanent targetTwo = game.getPermanent(id); + if (targetOne == null || targetTwo == null) { + return false; + } + return targetOne.shareTypes(targetTwo); + } + return true; + } + return false; + } + + @Override + public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { + Set cardTypes = new HashSet<>(); + MageObject targetSource = game.getObject(sourceId); + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + for (CardType cardType : permanent.getCardType()) { + if (cardTypes.contains(cardType)) { + return true; + } + } + cardTypes.addAll(permanent.getCardType()); + } + } + } + return false; + } + + @Override + public TargetPermanentsThatShareCardType copy() { + return new TargetPermanentsThatShareCardType(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RollingEarthquake.java b/Mage.Sets/src/mage/cards/r/RollingEarthquake.java index 005778c3c5..5e201d5140 100644 --- a/Mage.Sets/src/mage/cards/r/RollingEarthquake.java +++ b/Mage.Sets/src/mage/cards/r/RollingEarthquake.java @@ -29,7 +29,7 @@ public final class RollingEarthquake extends CardImpl { // Rolling Earthquake deals X damage to each creature without horsemanship and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageEverythingEffect(ManacostVariableValue.instance, filter)); } public RollingEarthquake(final RollingEarthquake card) { diff --git a/Mage.Sets/src/mage/cards/r/RollingThunder.java b/Mage.Sets/src/mage/cards/r/RollingThunder.java index b4b7e696ff..696e3ed0f6 100644 --- a/Mage.Sets/src/mage/cards/r/RollingThunder.java +++ b/Mage.Sets/src/mage/cards/r/RollingThunder.java @@ -20,7 +20,7 @@ public final class RollingThunder extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}{R}"); // Rolling Thunder deals X damage divided as you choose among any number of target creatures and/or players. - DynamicValue xValue = new ManacostVariableValue(); + DynamicValue xValue = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new DamageMultiEffect(xValue)); this.getSpellAbility().addTarget(new TargetAnyTargetAmount(xValue)); } diff --git a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java index 99e6b0c3a6..22072f622d 100644 --- a/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java +++ b/Mage.Sets/src/mage/cards/r/RoonOfTheHiddenRealm.java @@ -38,7 +38,7 @@ public final class RoonOfTheHiddenRealm extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RoonOfTheHiddenRealm(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RootKinAlly.java b/Mage.Sets/src/mage/cards/r/RootKinAlly.java index 75a457b9e7..8c148e5d98 100644 --- a/Mage.Sets/src/mage/cards/r/RootKinAlly.java +++ b/Mage.Sets/src/mage/cards/r/RootKinAlly.java @@ -26,7 +26,7 @@ public final class RootKinAlly extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public RootKinAlly(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RootingKavu.java b/Mage.Sets/src/mage/cards/r/RootingKavu.java index b70328f358..7e0fc263db 100644 --- a/Mage.Sets/src/mage/cards/r/RootingKavu.java +++ b/Mage.Sets/src/mage/cards/r/RootingKavu.java @@ -65,8 +65,7 @@ class RootingKavuEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + Cards cards = new CardsImpl(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); controller.putCardsOnTopOfLibrary(cards, game, source, false); controller.shuffleLibrary(source, game); return true; diff --git a/Mage.Sets/src/mage/cards/r/RootsOfLife.java b/Mage.Sets/src/mage/cards/r/RootsOfLife.java index 419f1d6235..c3f2cba6d6 100644 --- a/Mage.Sets/src/mage/cards/r/RootsOfLife.java +++ b/Mage.Sets/src/mage/cards/r/RootsOfLife.java @@ -22,8 +22,8 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class RootsOfLife extends CardImpl { - private final static String ruleTrigger1 = "&bull Island — Whenever an Island an opponent controls becomes tapped, you gain 1 life"; - private final static String ruleTrigger2 = "&bull Swamp — Whenever a Swamp an opponent controls becomes tapped, you gain 1 life"; + private static final String ruleTrigger1 = "&bull Island — Whenever an Island an opponent controls becomes tapped, you gain 1 life"; + private static final String ruleTrigger2 = "&bull Swamp — Whenever a Swamp an opponent controls becomes tapped, you gain 1 life"; private static final FilterPermanent islandFilter = new FilterPermanent("an Island an opponent controls"); private static final FilterPermanent swampFilter = new FilterPermanent("a Swamp an opponent controls"); diff --git a/Mage.Sets/src/mage/cards/r/RootwaterThief.java b/Mage.Sets/src/mage/cards/r/RootwaterThief.java index 0da71f36ad..4b58f29638 100644 --- a/Mage.Sets/src/mage/cards/r/RootwaterThief.java +++ b/Mage.Sets/src/mage/cards/r/RootwaterThief.java @@ -76,7 +76,7 @@ class RootwaterThiefEffect extends OneShotEffect { if(controller.chooseUse(Outcome.Benefit, message, source, game) && cost.pay(source, game, source.getSourceId(), controller.getId(), false, null)) { TargetCardInLibrary target = new TargetCardInLibrary(); - if (controller.searchLibrary(target, game, damagedPlayer.getId())) { + if (controller.searchLibrary(target, source, game, damagedPlayer.getId())) { if (!target.getTargets().isEmpty()) { Card card = damagedPlayer.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/r/RotHulk.java b/Mage.Sets/src/mage/cards/r/RotHulk.java new file mode 100644 index 0000000000..81b82e5526 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RotHulk.java @@ -0,0 +1,72 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.OpponentsCount; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.keyword.MenaceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class RotHulk extends CardImpl { + + private static final FilterCard filterZombie = new FilterCard("Zombie cards from your graveyard"); + + static { + filterZombie.add(new SubtypePredicate(SubType.ZOMBIE)); + } + + private final UUID entersBattlefieldAbilityID; + + public RotHulk(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Menace + this.addAbility(new MenaceAbility(false)); + + // When Rot Hulk enters the battlefield, return up to X target Zombie cards from your graveyard to the battlefield, where X is the number of opponents you have. + Effect effect = new ReturnFromGraveyardToBattlefieldTargetEffect(); + effect.setText("return up to X target Zombie cards from your graveyard to the battlefield, where X is the number of opponents you have."); + Ability ability = new EntersBattlefieldTriggeredAbility(effect); + ability.addTarget(new TargetCardInYourGraveyard()); + entersBattlefieldAbilityID = ability.getOriginalId(); // adjust targets + this.addAbility(ability); + } + + @Override + public void adjustTargets(Ability ability, Game game) { + if (ability.getOriginalId().equals(entersBattlefieldAbilityID)) { + // up to X target Zombie cards from your graveyard + // X is the number of opponents you have. + ability.getTargets().clear(); + int numbTargets = OpponentsCount.instance.calculate(game, ability, null); + ability.addTarget(new TargetCardInYourGraveyard(0, numbTargets, filterZombie)); + } + } + + public RotHulk(final RotHulk card) { + super(card); + this.entersBattlefieldAbilityID = card.entersBattlefieldAbilityID; + } + + @Override + public RotHulk copy() { + return new RotHulk(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RotShambler.java b/Mage.Sets/src/mage/cards/r/RotShambler.java index b719faaf28..1230e092c3 100644 --- a/Mage.Sets/src/mage/cards/r/RotShambler.java +++ b/Mage.Sets/src/mage/cards/r/RotShambler.java @@ -21,10 +21,10 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class RotShambler extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/r/RowanKenrith.java b/Mage.Sets/src/mage/cards/r/RowanKenrith.java index a5ef32577d..422dc96d90 100644 --- a/Mage.Sets/src/mage/cards/r/RowanKenrith.java +++ b/Mage.Sets/src/mage/cards/r/RowanKenrith.java @@ -1,7 +1,5 @@ - package mage.cards.r; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; @@ -13,14 +11,9 @@ import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.GetEmblemTargetPlayerEffect; import mage.abilities.keyword.PartnerWithAbility; -import mage.constants.SubType; -import mage.constants.SuperType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TurnPhase; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.filter.predicate.permanent.TappedPredicate; @@ -29,8 +22,9 @@ import mage.game.command.emblems.RowanKenrithEmblem; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class RowanKenrith extends CardImpl { @@ -54,11 +48,6 @@ public final class RowanKenrith extends CardImpl { // -8: Target player gets an emblem with "Whenever you activate an ability that isn't a mana ability, copy it. You may choose new targets for the copy." Effect effect = new GetEmblemTargetPlayerEffect(new RowanKenrithEmblem()); - effect.setText( - "Target player gets an emblem with " - + "\"Whenever you activate an ability that isn't a mana ability, " - + "copy it. You may choose new targets for the copy.\"" - ); ability = new LoyaltyAbility(effect, -8); ability.addTarget(new TargetPlayer()); this.addAbility(ability); @@ -112,7 +101,7 @@ class RowanKenrithAttackEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { - return (startingTurn != game.getTurnNum() + return (getStartingTurnNum() != game.getTurnNum() && (game.getPhase().getType() == TurnPhase.END && game.isActivePlayer(source.getFirstTarget()))) || // 6/15/2010: If a creature controlled by the affected player can't attack Gideon Jura (because he's no longer on the battlefield, for example), that player may have it attack you, another one of your planeswalkers, or nothing at all. @@ -149,7 +138,7 @@ class RowanKenrithDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerIdPredicate(source.getFirstTarget())); return new DamageAllEffect(3, filter).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/r/RoyalAssassin.java b/Mage.Sets/src/mage/cards/r/RoyalAssassin.java index 402c7d8ad5..a73c8b82cd 100644 --- a/Mage.Sets/src/mage/cards/r/RoyalAssassin.java +++ b/Mage.Sets/src/mage/cards/r/RoyalAssassin.java @@ -26,7 +26,7 @@ public final class RoyalAssassin extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public RoyalAssassin(UUID ownerId, CardSetInfo setInfo){ diff --git a/Mage.Sets/src/mage/cards/r/RubbleReading.java b/Mage.Sets/src/mage/cards/r/RubbleReading.java new file mode 100644 index 0000000000..5146f93aad --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubbleReading.java @@ -0,0 +1,34 @@ +package mage.cards.r; + +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetLandPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RubbleReading extends CardImpl { + + public RubbleReading(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Destroy target land. Scry 2. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addEffect(new ScryEffect(2)); + this.getSpellAbility().addTarget(new TargetLandPermanent()); + } + + private RubbleReading(final RubbleReading card) { + super(card); + } + + @Override + public RubbleReading copy() { + return new RubbleReading(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RubbleSlinger.java b/Mage.Sets/src/mage/cards/r/RubbleSlinger.java new file mode 100644 index 0000000000..5fafc01ba6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubbleSlinger.java @@ -0,0 +1,37 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.keyword.ReachAbility; +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 RubbleSlinger extends CardImpl { + + public RubbleSlinger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R/G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + } + + private RubbleSlinger(final RubbleSlinger card) { + super(card); + } + + @Override + public RubbleSlinger copy() { + return new RubbleSlinger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltRecluse.java b/Mage.Sets/src/mage/cards/r/RubblebeltRecluse.java new file mode 100644 index 0000000000..432cfad5f3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubblebeltRecluse.java @@ -0,0 +1,37 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.AttacksEachCombatStaticAbility; +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 RubblebeltRecluse extends CardImpl { + + public RubblebeltRecluse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(6); + this.toughness = new MageInt(5); + + // Rubblebelt Recluse attacks each combat if able. + this.addAbility(new AttacksEachCombatStaticAbility()); + } + + private RubblebeltRecluse(final RubblebeltRecluse card) { + super(card); + } + + @Override + public RubblebeltRecluse copy() { + return new RubblebeltRecluse(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltRioters.java b/Mage.Sets/src/mage/cards/r/RubblebeltRioters.java new file mode 100644 index 0000000000..836019948d --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubblebeltRioters.java @@ -0,0 +1,48 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.dynamicvalue.common.GreatestPowerAmongControlledCreaturesValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.HasteAbility; +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 RubblebeltRioters extends CardImpl { + + public RubblebeltRioters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever Rubblebelt Rioters attacks, it gets +X/+0 until end of turn, where X is the greatest power among creatures you control. + this.addAbility(new AttacksTriggeredAbility(new BoostSourceEffect( + GreatestPowerAmongControlledCreaturesValue.instance, new StaticValue(0), + Duration.EndOfTurn, true + ), false)); + } + + private RubblebeltRioters(final RubblebeltRioters card) { + super(card); + } + + @Override + public RubblebeltRioters copy() { + return new RubblebeltRioters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RubblebeltRunner.java b/Mage.Sets/src/mage/cards/r/RubblebeltRunner.java new file mode 100644 index 0000000000..dacc541e57 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RubblebeltRunner.java @@ -0,0 +1,50 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.common.SimpleEvasionAbility; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RubblebeltRunner extends CardImpl { + + public static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature tokens"); + + static { + filter.add(TokenPredicate.instance); + } + + public RubblebeltRunner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); + + this.subtype.add(SubType.VIASHINO); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Rubblebelt Runner can't be blocked by creature tokens. + this.addAbility(new SimpleEvasionAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.WhileOnBattlefield) + )); + } + + private RubblebeltRunner(final RubblebeltRunner card) { + super(card); + } + + @Override + public RubblebeltRunner copy() { + return new RubblebeltRunner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/r/RudeAwakening.java b/Mage.Sets/src/mage/cards/r/RudeAwakening.java index 8a34ec94d1..9e16198f99 100644 --- a/Mage.Sets/src/mage/cards/r/RudeAwakening.java +++ b/Mage.Sets/src/mage/cards/r/RudeAwakening.java @@ -32,7 +32,7 @@ public final class RudeAwakening extends CardImpl { this.getSpellAbility().addEffect(new UntapAllLandsControllerEffect()); // or until end of turn, lands you control become 2/2 creatures that are still lands. Mode mode = new Mode(); - mode.getEffects().add(new BecomesCreatureAllEffect( + mode.addEffect(new BecomesCreatureAllEffect( new CreatureToken(2, 2), "lands", new FilterControlledLandPermanent("lands you control"), Duration.EndOfTurn, false)); this.getSpellAbility().getModes().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/r/RuinInTheirWake.java b/Mage.Sets/src/mage/cards/r/RuinInTheirWake.java index 0d574c796a..1d2d0530ba 100644 --- a/Mage.Sets/src/mage/cards/r/RuinInTheirWake.java +++ b/Mage.Sets/src/mage/cards/r/RuinInTheirWake.java @@ -45,7 +45,7 @@ public final class RuinInTheirWake extends CardImpl { class RuinInTheirWakeEffect extends OneShotEffect { - private final static FilterLandPermanent filterWastes = new FilterLandPermanent(); + private static final FilterLandPermanent filterWastes = new FilterLandPermanent(); static { filterWastes.add(new NamePredicate("Wastes")); @@ -71,7 +71,7 @@ class RuinInTheirWakeEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = game.getCard(target.getFirstTarget()); if (card != null) { Cards cardsToReveal = new CardsImpl(card); diff --git a/Mage.Sets/src/mage/cards/r/RuinationGuide.java b/Mage.Sets/src/mage/cards/r/RuinationGuide.java index b008a9d362..c552cb5bca 100644 --- a/Mage.Sets/src/mage/cards/r/RuinationGuide.java +++ b/Mage.Sets/src/mage/cards/r/RuinationGuide.java @@ -25,7 +25,7 @@ public final class RuinationGuide extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creatures"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public RuinationGuide(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java b/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java index f9754711db..47d2869fdc 100644 --- a/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java +++ b/Mage.Sets/src/mage/cards/r/RuinsOfOranRief.java @@ -24,10 +24,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class RuinsOfOranRief extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature that entered the battlefield this turn"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creature that entered the battlefield this turn"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); filter.add(new EnteredThisTurnPredicate()); } diff --git a/Mage.Sets/src/mage/cards/r/RumblingRuin.java b/Mage.Sets/src/mage/cards/r/RumblingRuin.java new file mode 100644 index 0000000000..f4a611f453 --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RumblingRuin.java @@ -0,0 +1,77 @@ +package mage.cards.r; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.combat.CantBlockAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class RumblingRuin extends CardImpl { + + public RumblingRuin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // When Rumbling Ruin enters the battlefield, count the number of +1/+1 counters on creatures you control. Creatures your opponents control with power less than or equal to that number can't block this turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new RumblingRuinEffect())); + } + + private RumblingRuin(final RumblingRuin card) { + super(card); + } + + @Override + public RumblingRuin copy() { + return new RumblingRuin(this); + } +} + +class RumblingRuinEffect extends OneShotEffect { + + RumblingRuinEffect() { + super(Outcome.Benefit); + staticText = "count the number of +1/+1 counters on creatures you control. " + + "Creatures your opponents control with power less than or equal to that number can't block this turn."; + } + + private RumblingRuinEffect(final RumblingRuinEffect effect) { + super(effect); + } + + @Override + public RumblingRuinEffect copy() { + return new RumblingRuinEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int counter = 1; + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { + if (permanent == null || !permanent.isCreature()) { + continue; + } + counter += permanent.getCounters(game).getCount(CounterType.P1P1); + } + FilterCreaturePermanent filter = new FilterOpponentsCreaturePermanent(); + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, counter)); + game.addEffect(new CantBlockAllEffect(filter, Duration.EndOfTurn), source); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RunechantersPike.java b/Mage.Sets/src/mage/cards/r/RunechantersPike.java index b01ba3853a..8c61e3ba2a 100644 --- a/Mage.Sets/src/mage/cards/r/RunechantersPike.java +++ b/Mage.Sets/src/mage/cards/r/RunechantersPike.java @@ -1,4 +1,3 @@ - package mage.cards.r; import java.util.UUID; @@ -35,15 +34,21 @@ public final class RunechantersPike extends CardImpl { } public RunechantersPike(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); this.subtype.add(SubType.EQUIPMENT); // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); // Equipped creature has first strike and gets +X/+0 where X is the number of instant and sorcery cards in your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(new RunechantersPikeValue(), new StaticValue(0)))); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT))); + Effect effect = new GainAbilityAttachedEffect(FirstStrikeAbility.getInstance(), AttachmentType.EQUIPMENT); + Effect effect2 = new BoostEquippedEffect(new RunechantersPikeValue(), new StaticValue(0)); + effect.setText("Equipped creature has first strike"); + effect2.setText(" and gets +X/+0 where X is the number of instant and sorcery cards in your graveyard."); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + ability.addEffect(effect2); + this.addAbility(ability); + } public RunechantersPike(final RunechantersPike card) { diff --git a/Mage.Sets/src/mage/cards/r/RuneflareTrap.java b/Mage.Sets/src/mage/cards/r/RuneflareTrap.java index c446765d2a..90900deb32 100644 --- a/Mage.Sets/src/mage/cards/r/RuneflareTrap.java +++ b/Mage.Sets/src/mage/cards/r/RuneflareTrap.java @@ -83,7 +83,7 @@ enum RuneflareTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { CardsAmountDrawnThisTurnWatcher watcher = - (CardsAmountDrawnThisTurnWatcher) game.getState().getWatchers().get(CardsAmountDrawnThisTurnWatcher.class.getSimpleName()); + game.getState().getWatcher(CardsAmountDrawnThisTurnWatcher.class); return watcher != null && watcher.opponentDrewXOrMoreCards(source.getControllerId(), 3, game); } diff --git a/Mage.Sets/src/mage/cards/r/Runesword.java b/Mage.Sets/src/mage/cards/r/Runesword.java index 0a79d2da0e..5692512b9e 100644 --- a/Mage.Sets/src/mage/cards/r/Runesword.java +++ b/Mage.Sets/src/mage/cards/r/Runesword.java @@ -136,7 +136,7 @@ class RuneswordCantBeRegeneratedEffect extends ContinuousRuleModifyingEffectImpl @Override public boolean applies(GameEvent event, Ability source, Game game) { if (targetCreatureId != null) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), targetCreatureId); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, targetCreatureId); if (watcher != null) { return watcher.wasDamaged(event.getTargetId(), game); } diff --git a/Mage.Sets/src/mage/cards/r/RuptureSpire.java b/Mage.Sets/src/mage/cards/r/RuptureSpire.java index 2793a533f8..08dda4903d 100644 --- a/Mage.Sets/src/mage/cards/r/RuptureSpire.java +++ b/Mage.Sets/src/mage/cards/r/RuptureSpire.java @@ -1,8 +1,5 @@ - - package mage.cards.r; -import java.util.UUID; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -12,21 +9,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author Loki, North */ public final class RuptureSpire extends CardImpl { - public RuptureSpire (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},null); + public RuptureSpire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, null); this.addAbility(new EntersBattlefieldTappedAbility()); - this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{1}")), false)); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new ManaCostsImpl("{1}")).setText("sacrifice it unless you pay {1}") + )); this.addAbility(new AnyColorManaAbility()); } - public RuptureSpire (final RuptureSpire card) { + public RuptureSpire(final RuptureSpire card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/r/RushOfBlood.java b/Mage.Sets/src/mage/cards/r/RushOfBlood.java index 3a1b06858c..09daee68f0 100644 --- a/Mage.Sets/src/mage/cards/r/RushOfBlood.java +++ b/Mage.Sets/src/mage/cards/r/RushOfBlood.java @@ -22,7 +22,7 @@ public final class RushOfBlood extends CardImpl { // Target creature gets +X/+0 until end of turn, where X is its power. - this.getSpellAbility().addEffect(new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect(TargetPermanentPowerCount.instance, new StaticValue(0), Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/r/RushingRiver.java b/Mage.Sets/src/mage/cards/r/RushingRiver.java index 3f0ac959ed..b521104216 100644 --- a/Mage.Sets/src/mage/cards/r/RushingRiver.java +++ b/Mage.Sets/src/mage/cards/r/RushingRiver.java @@ -1,9 +1,7 @@ package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.costs.common.SacrificeTargetCost; import mage.abilities.decorator.ConditionalOneShotEffect; @@ -17,23 +15,25 @@ import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetNonlandPermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.SecondTargetPointer; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class RushingRiver extends CardImpl { public RushingRiver(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Kicker-Sacrifice a land. this.addAbility(new KickerAbility(new SacrificeTargetCost(new TargetControlledPermanent(new FilterControlledLandPermanent("a land"))))); // Return target nonland permanent to its owner's hand. If Rushing River was kicked, return another target nonland permanent to its owner's hand. - this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); + this.getSpellAbility().addEffect(new ReturnToHandTargetEffect()); Effect effect = new ConditionalOneShotEffect( new ReturnToHandTargetEffect(), KickedCondition.instance, @@ -41,16 +41,7 @@ public final class RushingRiver extends CardImpl { effect.setTargetPointer(new SecondTargetPointer()); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetNonlandPermanent()); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility && KickedCondition.instance.apply(game, ability)) { - ability.getTargets().clear(); - ability.addTarget(new TargetNonlandPermanent(2)); - } - + this.getSpellAbility().setTargetAdjuster(RushingRiverAdjuster.instance); } public RushingRiver(final RushingRiver card) { @@ -62,3 +53,15 @@ public final class RushingRiver extends CardImpl { return new RushingRiver(this); } } + +enum RushingRiverAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + if (KickedCondition.instance.apply(game, ability)) { + ability.getTargets().clear(); + ability.addTarget(new TargetNonlandPermanent(2)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/r/RushwoodGrove.java b/Mage.Sets/src/mage/cards/r/RushwoodGrove.java index 670f8b8f6b..604f7383f5 100644 --- a/Mage.Sets/src/mage/cards/r/RushwoodGrove.java +++ b/Mage.Sets/src/mage/cards/r/RushwoodGrove.java @@ -34,7 +34,7 @@ public final class RushwoodGrove extends CardImpl { // {T}, Remove any number of storage counters from Rushwood Grove: Add {G} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.GreenMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {G} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/r/Rust.java b/Mage.Sets/src/mage/cards/r/Rust.java index 1e88687beb..9557ecb1ed 100644 --- a/Mage.Sets/src/mage/cards/r/Rust.java +++ b/Mage.Sets/src/mage/cards/r/Rust.java @@ -17,7 +17,7 @@ import mage.target.common.TargetActivatedAbility; */ public final class Rust extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); + private static final FilterStackObject filter = new FilterStackObject("activated ability from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); diff --git a/Mage.Sets/src/mage/cards/r/RustElemental.java b/Mage.Sets/src/mage/cards/r/RustElemental.java index a7ae9da7f5..d6893f8980 100644 --- a/Mage.Sets/src/mage/cards/r/RustElemental.java +++ b/Mage.Sets/src/mage/cards/r/RustElemental.java @@ -53,7 +53,7 @@ class RustElementalEffect extends OneShotEffect { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("artifact"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public RustElementalEffect() { diff --git a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java index 9c11f4f079..0a3524d179 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessInstincts.java @@ -30,8 +30,8 @@ public final class RuthlessInstincts extends CardImpl { private static final FilterCreaturePermanent filterAttacking = new FilterCreaturePermanent("attacking creature"); static { - filter.add(Predicates.not(new AttackingPredicate())); - filterAttacking.add(new AttackingPredicate()); + filter.add(Predicates.not(AttackingPredicate.instance)); + filterAttacking.add(AttackingPredicate.instance); } public RuthlessInstincts(UUID ownerId, CardSetInfo setInfo) { @@ -54,11 +54,11 @@ public final class RuthlessInstincts extends CardImpl { Mode mode = new Mode(); effect = new BoostTargetEffect(2,2,Duration.EndOfTurn); effect.setText("Target attacking creature gets +2/+2"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterAttacking)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterAttacking)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/r/RuthlessInvasion.java b/Mage.Sets/src/mage/cards/r/RuthlessInvasion.java index 1480bac6ab..a2cff24e7b 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessInvasion.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessInvasion.java @@ -1,8 +1,5 @@ - - package mage.cards.r; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; @@ -12,19 +9,20 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Loki */ public final class RuthlessInvasion extends CardImpl { - public RuthlessInvasion (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{R/P}"); + public RuthlessInvasion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R/P}"); this.getSpellAbility().addEffect(new RuthlessInvasionEffect()); } - public RuthlessInvasion (final RuthlessInvasion card) { + public RuthlessInvasion(final RuthlessInvasion card) { super(card); } @@ -47,10 +45,7 @@ class RuthlessInvasionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (!permanent.isArtifact()) { - return true; - } - return false; + return !permanent.isArtifact(); } @Override @@ -59,7 +54,7 @@ class RuthlessInvasionEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/r/RuthlessRipper.java b/Mage.Sets/src/mage/cards/r/RuthlessRipper.java index d58fb8cc92..936b2a7f52 100644 --- a/Mage.Sets/src/mage/cards/r/RuthlessRipper.java +++ b/Mage.Sets/src/mage/cards/r/RuthlessRipper.java @@ -26,7 +26,7 @@ import mage.target.common.TargetCardInHand; */ public final class RuthlessRipper extends CardImpl { - private final static FilterCard filter = new FilterCard("a black card in your hand"); + private static final FilterCard filter = new FilterCard("a black card in your hand"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); } diff --git a/Mage.Sets/src/mage/cards/s/SabaccGame.java b/Mage.Sets/src/mage/cards/s/SabaccGame.java index 3d42eaf52f..4cfd1b6b46 100644 --- a/Mage.Sets/src/mage/cards/s/SabaccGame.java +++ b/Mage.Sets/src/mage/cards/s/SabaccGame.java @@ -88,7 +88,7 @@ class SabaccGameEffect extends OneShotEffect { if (target.chooseTarget(outcome, opponent.getId(), source, game)) { chosenPermanent = game.getPermanent(target.getFirstTarget()); } - boolean flipWin = controller.flipCoin(game); + boolean flipWin = controller.flipCoin(source, game, true); if (flipWin) { ContinuousEffect effect = new GainControlTargetEffect(Duration.Custom, true, controller.getId()); effect.setTargetPointer(new FixedTarget(targetPermanent, game)); diff --git a/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java b/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java index e962f95c8b..715fe21771 100644 --- a/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java +++ b/Mage.Sets/src/mage/cards/s/SaddlebackLagac.java @@ -20,10 +20,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class SaddlebackLagac extends CardImpl { - private final static FilterCreaturePermanent FILTER = new FilterCreaturePermanent("target creatures"); + private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("target creatures"); static { - FILTER.add(new AnotherPredicate()); + FILTER.add(AnotherPredicate.instance); } public SaddlebackLagac(UUID ownerId, CardSetInfo setInfo) { @@ -39,7 +39,7 @@ public final class SaddlebackLagac extends CardImpl { } - public SaddlebackLagac(final SaddlebackLagac card) { + private SaddlebackLagac(final SaddlebackLagac card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SadisticSacrament.java b/Mage.Sets/src/mage/cards/s/SadisticSacrament.java index f1f7a64ede..2f1b08a70b 100644 --- a/Mage.Sets/src/mage/cards/s/SadisticSacrament.java +++ b/Mage.Sets/src/mage/cards/s/SadisticSacrament.java @@ -80,7 +80,7 @@ class SadisticSacramentEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && targetPlayer != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard("cards to exile")); - if (player.searchLibrary(target, game, targetPlayer.getId())) { + if (player.searchLibrary(target, source, game, targetPlayer.getId())) { List targets = target.getTargets(); for (UUID targetId : targets) { Card card = targetPlayer.getLibrary().remove(targetId, game); diff --git a/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java b/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java index dcecae03c6..159e756f99 100644 --- a/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java +++ b/Mage.Sets/src/mage/cards/s/SageOfAncientLore.java @@ -43,7 +43,7 @@ public final class SageOfAncientLore extends CardImpl { this.secondSideCardClazz = mage.cards.w.WerewolfOfAncientHunger.class; // Sage of Ancient Lore's power and toughness are each equal to the number of cards in your hand. - DynamicValue xValue = new CardsInControllerHandCount(); + DynamicValue xValue = CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.ALL, new ConditionalContinuousEffect(new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame), new TransformedCondition(true), "{this}'s power and toughness are each equal to the total number of cards in your hand"))); diff --git a/Mage.Sets/src/mage/cards/s/SageOfHours.java b/Mage.Sets/src/mage/cards/s/SageOfHours.java index e5a9fe5eac..ba80bfe427 100644 --- a/Mage.Sets/src/mage/cards/s/SageOfHours.java +++ b/Mage.Sets/src/mage/cards/s/SageOfHours.java @@ -127,11 +127,11 @@ class SageOfHoursEffect extends OneShotEffect { for (int i = 0; i < turns; i++) { game.getState().getTurnMods().add(new TurnMod(player.getId(), false)); } - game.informPlayers(new StringBuilder("Removed ").append(countersRemoved) - .append(" +1/+1 counters: ").append(player.getLogName()).append(" takes ") - .append(CardUtil.numberToText(turns, "an")) - .append(turns > 1 ? " extra turns ":" extra turn ") - .append("after this one").toString()); + game.informPlayers("Removed " + countersRemoved + + " +1/+1 counters: " + player.getLogName() + " takes " + + CardUtil.numberToText(turns, "an") + + (turns > 1 ? " extra turns " : " extra turn ") + + "after this one"); return true; } return false; diff --git a/Mage.Sets/src/mage/cards/s/SagesRowDenizen.java b/Mage.Sets/src/mage/cards/s/SagesRowDenizen.java index ca6f76b109..2d69340779 100644 --- a/Mage.Sets/src/mage/cards/s/SagesRowDenizen.java +++ b/Mage.Sets/src/mage/cards/s/SagesRowDenizen.java @@ -29,7 +29,7 @@ public final class SagesRowDenizen extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.BLUE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/s/SagesRowSavant.java b/Mage.Sets/src/mage/cards/s/SagesRowSavant.java new file mode 100644 index 0000000000..f459b8ccaf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SagesRowSavant.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +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 SagesRowSavant extends CardImpl { + + public SagesRowSavant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Sage's Row Savant enters the battlefield, scry 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(2))); + } + + private SagesRowSavant(final SagesRowSavant card) { + super(card); + } + + @Override + public SagesRowSavant copy() { + return new SagesRowSavant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SagittarsVolley.java b/Mage.Sets/src/mage/cards/s/SagittarsVolley.java new file mode 100644 index 0000000000..1a017f2a8c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SagittarsVolley.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterOpponentsCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SagittarsVolley extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with flying"); + private static final FilterPermanent filter2 + = new FilterOpponentsCreaturePermanent("creature with flying your opponents control"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + filter2.add(new AbilityPredicate(FlyingAbility.class)); + } + + public SagittarsVolley(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); + + // Destroy target creature with flying. Sagittars' Volley deals 1 damage to each creature with flying your opponents control. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + this.getSpellAbility().addEffect(new DamageAllEffect(1, filter2)); + } + + private SagittarsVolley(final SagittarsVolley card) { + super(card); + } + + @Override + public SagittarsVolley copy() { + return new SagittarsVolley(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java b/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java new file mode 100644 index 0000000000..bb20999d03 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaheeliSublimeArtificer.java @@ -0,0 +1,113 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.AddCardTypeTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledArtifactPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AnotherTargetPredicate; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ServoToken; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.functions.EmptyApplyToPermanent; + +/** + * @author TheElk801 + */ +public final class SaheeliSublimeArtificer extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledArtifactPermanent(); + private static final FilterPermanent filter2 + = new FilterControlledPermanent("artifact or creature you control"); + + static { + filter.add(new AnotherTargetPredicate(1)); + filter2.add(new AnotherTargetPredicate(2)); + filter2.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE) + )); + } + + public SaheeliSublimeArtificer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{U/R}{U/R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SAHEELI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Whenever you cast a noncreature spell, create a 1/1 colorless Servo artifact creature token. + this.addAbility(new SpellCastControllerTriggeredAbility( + new CreateTokenEffect(new ServoToken()), StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + + // -2: Target artifact you control becomes a copy of another target artifact or creature you control until end of turn, except it's an artifact in addition to its other types. + Ability ability = new LoyaltyAbility(new SaheeliSublimeArtificerEffect(), -2); + Target target = new TargetPermanent(filter); + target.setTargetTag(1); + ability.addTarget(target); + target = new TargetPermanent(filter2); + target.setTargetTag(2); + ability.addTarget(target); + this.addAbility(ability); + } + + private SaheeliSublimeArtificer(final SaheeliSublimeArtificer card) { + super(card); + } + + @Override + public SaheeliSublimeArtificer copy() { + return new SaheeliSublimeArtificer(this); + } +} + +class SaheeliSublimeArtificerEffect extends OneShotEffect { + + SaheeliSublimeArtificerEffect() { + super(Outcome.Benefit); + staticText = "Target artifact you control becomes a copy of another target artifact or creature you control" + + " until end of turn, except it's an artifact in addition to its other types."; + } + + private SaheeliSublimeArtificerEffect(final SaheeliSublimeArtificerEffect effect) { + super(effect); + } + + @Override + public SaheeliSublimeArtificerEffect copy() { + return new SaheeliSublimeArtificerEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent copyTo = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (copyTo != null) { + Permanent copyFrom = game.getPermanentOrLKIBattlefield(source.getTargets().get(1).getFirstTarget()); + if (copyFrom != null) { + game.copyPermanent(Duration.EndOfTurn, copyFrom, copyTo.getId(), source, new EmptyApplyToPermanent()); + ContinuousEffect effect = new AddCardTypeTargetEffect(Duration.EndOfTurn, CardType.ARTIFACT); + effect.setTargetPointer(new FixedTarget(copyTo, game)); + game.addEffect(effect, source); + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java index 4d577674f8..f3fd326e19 100644 --- a/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java +++ b/Mage.Sets/src/mage/cards/s/SaheeliTheGifted.java @@ -86,7 +86,7 @@ class SaheeliTheGiftedCostReductionEffect extends CostModificationEffectImpl { @Override public void init(Ability source, Game game) { super.init(source, game); - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { spellsCast = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()); } @@ -104,7 +104,7 @@ class SaheeliTheGiftedCostReductionEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { if (watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) > spellsCast) { discard(); // only one use diff --git a/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java b/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java index c51d0036b8..b318a6dd4c 100644 --- a/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java +++ b/Mage.Sets/src/mage/cards/s/SaheelisArtistry.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.CreateTokenCopyTargetEffect; import mage.cards.CardImpl; @@ -10,30 +8,31 @@ import mage.constants.CardType; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SaheelisArtistry extends CardImpl { public SaheelisArtistry(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{U}{U}"); // Choose one or both — this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); // • Create a token that's a copy of target artifact. - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); effect.setText("Create a token that's a copy of target artifact"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("create copy of that")); // • Create a token that's a copy of target creature, except that it's an artifact in addition to its other types. Mode mode1 = new Mode(); - mode1.getTargets().add(new TargetCreaturePermanent()); effect = new CreateTokenCopyTargetEffect(); effect.setBecomesArtifact(true); effect.setText("Create a token that's a copy of target creature, except that it's an artifact in addition to its other types"); - mode1.getEffects().add(effect); + mode1.addEffect(effect); + mode1.addTarget(new TargetCreaturePermanent().withChooseHint("create copy of that, artifact type")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/s/SaheelisSilverwing.java b/Mage.Sets/src/mage/cards/s/SaheelisSilverwing.java new file mode 100644 index 0000000000..57cd9700d7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaheelisSilverwing.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.LookLibraryTopCardTargetPlayerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaheelisSilverwing extends CardImpl { + + public SaheelisSilverwing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); + + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Saheeli's Silverwing enters the battlefield, look at the top card of target opponent's library. + Ability ability = new EntersBattlefieldTriggeredAbility( + new LookLibraryTopCardTargetPlayerEffect().setText("look at the top card of target opponent's library") + ); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private SaheelisSilverwing(final SaheelisSilverwing card) { + super(card); + } + + @Override + public SaheelisSilverwing copy() { + return new SaheelisSilverwing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaiTok.java b/Mage.Sets/src/mage/cards/s/SaiTok.java index 04d1f9daa4..2fea4bab8d 100644 --- a/Mage.Sets/src/mage/cards/s/SaiTok.java +++ b/Mage.Sets/src/mage/cards/s/SaiTok.java @@ -11,7 +11,6 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.target.TargetPermanent; -import mage.target.common.TargetCreatureOrPlaneswalker; /** * @@ -36,7 +35,7 @@ public final class SaiTok extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter)); } - public SaiTok(final SaiTok card) { + private SaiTok(final SaiTok card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/Sailmonger.java b/Mage.Sets/src/mage/cards/s/Sailmonger.java index 738b1ecf8a..ec6d781bac 100644 --- a/Mage.Sets/src/mage/cards/s/Sailmonger.java +++ b/Mage.Sets/src/mage/cards/s/Sailmonger.java @@ -3,7 +3,6 @@ package mage.cards.s; import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.InfoEffect; diff --git a/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java b/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java index 233d60d5f9..3329be2819 100644 --- a/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java +++ b/Mage.Sets/src/mage/cards/s/SaltRoadAmbushers.java @@ -51,7 +51,7 @@ class SaltRoadAmbushersTriggeredAbility extends TurnedFaceUpAllTriggeredAbility private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another permanent you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SaltRoadAmbushersTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/s/Saltblast.java b/Mage.Sets/src/mage/cards/s/Saltblast.java index 66945dea2f..a17a04cf6b 100644 --- a/Mage.Sets/src/mage/cards/s/Saltblast.java +++ b/Mage.Sets/src/mage/cards/s/Saltblast.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -12,18 +11,21 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorPredicate; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Saltblast extends CardImpl { - static final protected FilterPermanent filter = new FilterPermanent("nonwhite permanent"); + private static final FilterPermanent filter = new FilterPermanent("nonwhite permanent"); + static { filter.add(Predicates.not(new ColorPredicate(ObjectColor.WHITE))); } + public Saltblast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}"); // Destroy target nonwhite permanent. diff --git a/Mage.Sets/src/mage/cards/s/SaltcrustedSteppe.java b/Mage.Sets/src/mage/cards/s/SaltcrustedSteppe.java index 8bc8e64d08..9b20de817d 100644 --- a/Mage.Sets/src/mage/cards/s/SaltcrustedSteppe.java +++ b/Mage.Sets/src/mage/cards/s/SaltcrustedSteppe.java @@ -36,7 +36,7 @@ public final class SaltcrustedSteppe extends CardImpl { this.addAbility(ability); // {1}, Remove X storage counters from Saltcrusted Steppe: Add X mana in any combination of {G} and/or {W}. ability = new SimpleManaAbility(Zone.BATTLEFIELD, - new AddManaInAnyCombinationEffect(new RemovedCountersForCostValue(), ColoredManaSymbol.G, ColoredManaSymbol.W), + new AddManaInAnyCombinationEffect(RemovedCountersForCostValue.instance, ColoredManaSymbol.G, ColoredManaSymbol.W), new GenericManaCost(1)); ability.addCost(new RemoveVariableCountersSourceCost(CounterType.STORAGE.createInstance())); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/Saltskitter.java b/Mage.Sets/src/mage/cards/s/Saltskitter.java index 6c73c55ab0..e97c2651ae 100644 --- a/Mage.Sets/src/mage/cards/s/Saltskitter.java +++ b/Mage.Sets/src/mage/cards/s/Saltskitter.java @@ -22,7 +22,7 @@ public final class Saltskitter extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Saltskitter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SamiteBlessing.java b/Mage.Sets/src/mage/cards/s/SamiteBlessing.java new file mode 100644 index 0000000000..1168cf6606 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamiteBlessing.java @@ -0,0 +1,58 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.PreventNextDamageFromChosenSourceToTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; + +/** + * + * @author jeffwadsworth + */ +public final class SamiteBlessing extends CardImpl { + + private static final String rule = "Enchanted creature has \"{T}: The next time a source of your choice would deal damage to target creature this turn, prevent that damage.\""; + + public SamiteBlessing(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has "{tap}: The next time a source of your choice would deal damage to target creature this turn, prevent that damage." + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PreventNextDamageFromChosenSourceToTargetEffect(Duration.EndOfTurn), new TapSourceCost()); + ability2.addTarget(new TargetCreaturePermanent()); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(ability2, AttachmentType.AURA, Duration.WhileOnBattlefield, rule))); + + } + + public SamiteBlessing(final SamiteBlessing card) { + super(card); + } + + @Override + public SamiteBlessing copy() { + return new SamiteBlessing(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SamiteMinistration.java b/Mage.Sets/src/mage/cards/s/SamiteMinistration.java new file mode 100644 index 0000000000..3f2fbe5abd --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamiteMinistration.java @@ -0,0 +1,90 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.PreventionEffectData; +import mage.abilities.effects.PreventionEffectImpl; +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.events.GameEvent; +import mage.players.Player; +import mage.target.TargetSource; + +/** + * + * @author L_J + */ +public final class SamiteMinistration extends CardImpl { + + public SamiteMinistration(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Prevent all damage that would be dealt to you this turn by a source of your choice. Whenever damage from a black or red source is prevented this way this turn, you gain that much life. + this.getSpellAbility().addEffect(new SamiteMinistrationEffect()); + } + + public SamiteMinistration(final SamiteMinistration card) { + super(card); + } + + @Override + public SamiteMinistration copy() { + return new SamiteMinistration(this); + } + +} + +class SamiteMinistrationEffect extends PreventionEffectImpl { + + private final TargetSource targetSource; + + public SamiteMinistrationEffect() { + super(Duration.EndOfTurn, Integer.MAX_VALUE, false); + this.staticText = "Prevent all damage that would be dealt to you this turn by a source of your choice. Whenever damage from a black or red source is prevented this way this turn, you gain that much life"; + this.targetSource = new TargetSource(); + } + + public SamiteMinistrationEffect(final SamiteMinistrationEffect effect) { + super(effect); + this.targetSource = effect.targetSource.copy(); + } + + @Override + public SamiteMinistrationEffect copy() { + return new SamiteMinistrationEffect(this); + } + + @Override + public void init(Ability source, Game game) { + this.targetSource.choose(Outcome.PreventDamage, source.getControllerId(), source.getSourceId(), game); + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + PreventionEffectData preventionData = preventDamageAction(event, source, game); + MageObject sourceObject = game.getObject(event.getSourceId()); + if (sourceObject != null && (sourceObject.getColor(game).isBlack() || sourceObject.getColor(game).isRed())) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.gainLife(preventionData.getPreventedDamage(), game, source); + } + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getControllerId()) && event.getSourceId().equals(targetSource.getFirstTarget())) { + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java b/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java index 27de3fc8b6..06b0e68256 100644 --- a/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java +++ b/Mage.Sets/src/mage/cards/s/SamuraiOfThePaleCurtain.java @@ -1,8 +1,5 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,39 +7,37 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.keyword.BushidoAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; /** - * * @author LevelX */ public final class SamuraiOfThePaleCurtain extends CardImpl { - public SamuraiOfThePaleCurtain (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); + public SamuraiOfThePaleCurtain(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); this.subtype.add(SubType.FOX); this.subtype.add(SubType.SAMURAI); this.power = new MageInt(2); this.toughness = new MageInt(2); - + // Bushido 1 (When this blocks or becomes blocked, it gets +1/+1 until end of turn.) this.addAbility(new BushidoAbility(1)); + // If a permanent would be put into a graveyard, exile it instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SamuraiOfThePaleCurtainEffect())); - } - public SamuraiOfThePaleCurtain (final SamuraiOfThePaleCurtain card) { + public SamuraiOfThePaleCurtain(final SamuraiOfThePaleCurtain card) { super(card); } @@ -56,12 +51,12 @@ public final class SamuraiOfThePaleCurtain extends CardImpl { class SamuraiOfThePaleCurtainEffect extends ReplacementEffectImpl { - public SamuraiOfThePaleCurtainEffect() { + SamuraiOfThePaleCurtainEffect() { super(Duration.WhileOnBattlefield, Outcome.Exile); staticText = "If a permanent would be put into a graveyard, exile it instead"; } - public SamuraiOfThePaleCurtainEffect(final SamuraiOfThePaleCurtainEffect effect) { + private SamuraiOfThePaleCurtainEffect(final SamuraiOfThePaleCurtainEffect effect) { super(effect); } @@ -72,9 +67,12 @@ class SamuraiOfThePaleCurtainEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - Permanent permanent = ((ZoneChangeEvent)event).getTarget(); + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent != null) { - return permanent.moveToExile(null, "", source.getSourceId(), game); + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + return player.moveCards(permanent, Zone.EXILED, source, game); + } } return false; } @@ -83,10 +81,10 @@ class SamuraiOfThePaleCurtainEffect extends ReplacementEffectImpl { public boolean checksEventType(GameEvent event, Game game) { return event.getType() == EventType.ZONE_CHANGE; } - + @Override public boolean applies(GameEvent event, Ability source, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent)event; + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.getToZone() == Zone.GRAVEYARD; } diff --git a/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java b/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java new file mode 100644 index 0000000000..8468e13ebb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamutTyrantSmasher.java @@ -0,0 +1,60 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.HasteAbility; +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.filter.StaticFilters; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author TheElk801 + */ +public final class SamutTyrantSmasher extends CardImpl { + + public SamutTyrantSmasher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R/G}{R/G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SAMUT); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Creatures you control have haste. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + HasteAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURES + ))); + + // -1: Target creature gets +2/+1 and gains haste until end of turn. Scry 1. + Ability ability = new LoyaltyAbility(new BoostTargetEffect( + 2, 1, Duration.EndOfTurn + ).setText("target creature gets +2/+1"), -1); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + ability.addEffect(new ScryEffect(1)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + private SamutTyrantSmasher(final SamutTyrantSmasher card) { + super(card); + } + + @Override + public SamutTyrantSmasher copy() { + return new SamutTyrantSmasher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java b/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java index a5fb791345..d42b0d8874 100644 --- a/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java +++ b/Mage.Sets/src/mage/cards/s/SamutVoiceOfDissent.java @@ -36,8 +36,8 @@ public final class SamutVoiceOfDissent extends CardImpl { private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); - filter2.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); + filter2.add(AnotherPredicate.instance); } public SamutVoiceOfDissent(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SamutsSprint.java b/Mage.Sets/src/mage/cards/s/SamutsSprint.java new file mode 100644 index 0000000000..1d631dd602 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SamutsSprint.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +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; + +/** + * @author TheElk801 + */ +public final class SamutsSprint extends CardImpl { + + public SamutsSprint(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Target creature gets +2/+1 and gains haste until end of turn. Scry 1. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 1, Duration.EndOfTurn + ).setText("target creature gets +2/+1")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains haste until end of turn")); + this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SamutsSprint(final SamutsSprint card) { + super(card); + } + + @Override + public SamutsSprint copy() { + return new SamutsSprint(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctifierOfSouls.java b/Mage.Sets/src/mage/cards/s/SanctifierOfSouls.java index 996c9946c3..24b24ee056 100644 --- a/Mage.Sets/src/mage/cards/s/SanctifierOfSouls.java +++ b/Mage.Sets/src/mage/cards/s/SanctifierOfSouls.java @@ -31,7 +31,7 @@ public final class SanctifierOfSouls extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SanctifierOfSouls(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java b/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java index 46269e831e..0a8238c866 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfTheSun.java @@ -32,7 +32,7 @@ public final class SanctumOfTheSun extends CardImpl { new InfoEffect("(Transforms from Azor's Gateway.)")).setRuleAtTheTop(true)); // {T}: Add X mana of any one color, where X is your life total. - this.addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), new ControllerLifeCount(), new TapSourceCost(), + this.addAbility(new DynamicManaAbility(new Mana(0, 0, 0, 0, 0, 0, 1, 0), ControllerLifeCount.instance, new TapSourceCost(), "Add X mana of any one color, where X is is your life total", true)); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfUgin.java b/Mage.Sets/src/mage/cards/s/SanctumOfUgin.java index bc747932c7..68c6258fc6 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumOfUgin.java +++ b/Mage.Sets/src/mage/cards/s/SanctumOfUgin.java @@ -27,8 +27,8 @@ public final class SanctumOfUgin extends CardImpl { private static final FilterSpell filterSpells = new FilterSpell("colorless spell with converted mana cost 7 or greater"); static { - filter.add(new ColorlessPredicate()); - filterSpells.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); + filterSpells.add(ColorlessPredicate.instance); filterSpells.add(new ConvertedManaCostPredicate(ComparisonType.MORE_THAN, 6)); } diff --git a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java index 5fcd464ced..9cb660d8c8 100644 --- a/Mage.Sets/src/mage/cards/s/SanctumPrelate.java +++ b/Mage.Sets/src/mage/cards/s/SanctumPrelate.java @@ -2,6 +2,7 @@ package mage.cards.s; import java.util.UUID; + import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -19,13 +20,12 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * * @author maxlebedev */ public final class SanctumPrelate extends CardImpl { public SanctumPrelate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); this.power = new MageInt(2); @@ -62,15 +62,17 @@ class ChooseNumberEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int numberChoice = controller.announceXMana(0, Integer.MAX_VALUE, "Choose a number. Noncreature spells with the chosen converted mana cost can't be cast", game, source); + game.getState().setValue(source.getSourceId().toString(), numberChoice); - int numberChoice = controller.announceXMana(0, Integer.MAX_VALUE, "Choose a number. Noncreature spells with the chosen converted mana cost can't be cast", game, source); - game.getState().setValue(source.getSourceId().toString(), numberChoice); - - Permanent permanent = game.getPermanentEntering(source.getSourceId()); - permanent.addInfo("chosen players", "Chosen Number: "+ numberChoice +"", game); - - game.informPlayers(permanent.getLogName() + ", chosen number: "+numberChoice); + Permanent permanent = game.getPermanentEntering(source.getSourceId()); + if(permanent != null) { + permanent.addInfo("chosen players", "Chosen Number: " + numberChoice + "", game); + game.informPlayers(permanent.getLogName() + ", chosen number: " + numberChoice); + } + } return true; } @@ -87,6 +89,7 @@ class ChooseNumberEffect extends OneShotEffect { class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl { Integer choiceValue; + public SanctumPrelateReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); staticText = "Noncreature spells with the chosen converted mana cost can't be cast"; @@ -124,8 +127,8 @@ class SanctumPrelateReplacementEffect extends ContinuousRuleModifyingEffectImpl public boolean applies(GameEvent event, Ability source, Game game) { choiceValue = (Integer) game.getState().getValue(source.getSourceId().toString()); Spell spell = game.getStack().getSpell(event.getTargetId()); - - if (spell != null && !spell.isCreature()){ + + if (spell != null && !spell.isCreature()) { return spell.getConvertedManaCost() == choiceValue; } return false; diff --git a/Mage.Sets/src/mage/cards/s/SandSilos.java b/Mage.Sets/src/mage/cards/s/SandSilos.java index 360ca7ffc8..61b800e3bd 100644 --- a/Mage.Sets/src/mage/cards/s/SandSilos.java +++ b/Mage.Sets/src/mage/cards/s/SandSilos.java @@ -44,7 +44,7 @@ public final class SandSilos extends CardImpl { // {tap}, Remove any number of storage counters from Sand Silos: Add {U} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.BlueMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {U} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/s/SandsOfDelirium.java b/Mage.Sets/src/mage/cards/s/SandsOfDelirium.java index cbbb1c6011..f10c51c2bf 100644 --- a/Mage.Sets/src/mage/cards/s/SandsOfDelirium.java +++ b/Mage.Sets/src/mage/cards/s/SandsOfDelirium.java @@ -25,7 +25,7 @@ public final class SandsOfDelirium extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{3}"); // {X}, {tap}: Target player puts the top X cards of their library into their graveyard. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(new ManacostVariableValue()), new VariableManaCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect(ManacostVariableValue.instance), new VariableManaCost()); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/Sandsower.java b/Mage.Sets/src/mage/cards/s/Sandsower.java index d53256882e..0e295fac41 100644 --- a/Mage.Sets/src/mage/cards/s/Sandsower.java +++ b/Mage.Sets/src/mage/cards/s/Sandsower.java @@ -27,7 +27,7 @@ public final class Sandsower extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Sandsower(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java b/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java index eaba57ceae..fcc419c66a 100644 --- a/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java +++ b/Mage.Sets/src/mage/cards/s/SandsteppeOutcast.java @@ -34,7 +34,7 @@ public final class SandsteppeOutcast extends CardImpl { // * Create a 1/1 white Spirit creature token with flying. Mode mode = new Mode(); - mode.getEffects().add(new CreateTokenEffect(new SpiritWhiteToken("FRF"))); + mode.addEffect(new CreateTokenEffect(new SpiritWhiteToken("FRF"))); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SanguineGlorifier.java b/Mage.Sets/src/mage/cards/s/SanguineGlorifier.java index be19360531..df998da572 100644 --- a/Mage.Sets/src/mage/cards/s/SanguineGlorifier.java +++ b/Mage.Sets/src/mage/cards/s/SanguineGlorifier.java @@ -25,7 +25,7 @@ public final class SanguineGlorifier extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target Vampire you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/s/SanguineSacrament.java b/Mage.Sets/src/mage/cards/s/SanguineSacrament.java index f80c3580ca..bbccf8ba5c 100644 --- a/Mage.Sets/src/mage/cards/s/SanguineSacrament.java +++ b/Mage.Sets/src/mage/cards/s/SanguineSacrament.java @@ -1,9 +1,8 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.ReturnToLibrarySpellEffect; @@ -12,8 +11,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.Game; +import java.util.UUID; + /** - * * @author spjspj */ public final class SanguineSacrament extends CardImpl { @@ -22,11 +22,11 @@ public final class SanguineSacrament extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{W}{W}"); // You gain twice X life. Put Sanguine Sacrament on the bottom of its owner's library. - this.getSpellAbility().addEffect(new GainLifeEffect(new SanguineSacramentValue())); + this.getSpellAbility().addEffect(new GainLifeEffect(SanguineSacramentValue.instance)); this.getSpellAbility().addEffect(new ReturnToLibrarySpellEffect(false)); } - public SanguineSacrament(final SanguineSacrament card) { + private SanguineSacrament(final SanguineSacrament card) { super(card); } @@ -36,16 +36,22 @@ public final class SanguineSacrament extends CardImpl { } } -class SanguineSacramentValue extends ManacostVariableValue { +enum SanguineSacramentValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return super.calculate(game, sourceAbility, effect) * 2; + return sourceAbility.getManaCostsToPay().getX() * 2; } @Override public SanguineSacramentValue copy() { - return new SanguineSacramentValue(); + return instance; + } + + @Override + public String getMessage() { + return ""; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SaplingOfColfenor.java b/Mage.Sets/src/mage/cards/s/SaplingOfColfenor.java index 3297faa9a2..4bfeb3924c 100644 --- a/Mage.Sets/src/mage/cards/s/SaplingOfColfenor.java +++ b/Mage.Sets/src/mage/cards/s/SaplingOfColfenor.java @@ -74,12 +74,14 @@ class SaplingOfColfenorEffect extends OneShotEffect { if (controller != null && sourceObject != null) { if (controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(card); - controller.revealCards(sourceObject.getIdName(), cards, game); - if (card.isCreature()) { - controller.gainLife(card.getToughness().getValue(), game, source); - controller.loseLife(card.getPower().getValue(), game, false); - return controller.moveCards(cards.getCards(game), Zone.HAND, source, game); + if(card != null) { + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + if (card.isCreature()) { + controller.gainLife(card.getToughness().getValue(), game, source); + controller.loseLife(card.getPower().getValue(), game, false); + return controller.moveCards(cards.getCards(game), Zone.HAND, source, game); + } } } return true; diff --git a/Mage.Sets/src/mage/cards/s/SapphireCharm.java b/Mage.Sets/src/mage/cards/s/SapphireCharm.java index 102db8d613..ca483f086a 100644 --- a/Mage.Sets/src/mage/cards/s/SapphireCharm.java +++ b/Mage.Sets/src/mage/cards/s/SapphireCharm.java @@ -44,14 +44,14 @@ public final class SapphireCharm extends CardImpl { // or target creature gains flying until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or target creature an opponent controls phases out. mode = new Mode(); - mode.getEffects().add(new PhaseOutTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new PhaseOutTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SaprazzanCove.java b/Mage.Sets/src/mage/cards/s/SaprazzanCove.java index 9f1c510d2a..5806b041e1 100644 --- a/Mage.Sets/src/mage/cards/s/SaprazzanCove.java +++ b/Mage.Sets/src/mage/cards/s/SaprazzanCove.java @@ -34,7 +34,7 @@ public final class SaprazzanCove extends CardImpl { // {tap}, Remove any number of storage counters from Saprazzan Cove: Add {U} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.BlueMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {U} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/s/SaprolingSymbiosis.java b/Mage.Sets/src/mage/cards/s/SaprolingSymbiosis.java index 865ef2088c..f13de832cd 100644 --- a/Mage.Sets/src/mage/cards/s/SaprolingSymbiosis.java +++ b/Mage.Sets/src/mage/cards/s/SaprolingSymbiosis.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.PayMoreToCastAsThoughtItHadFlashAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -11,25 +9,27 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.permanent.token.SaprolingToken; +import java.util.UUID; + /** - * * @author LoneFox - * */ public final class SaprolingSymbiosis extends CardImpl { public SaprolingSymbiosis(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); - Effect effect = new CreateTokenEffect(new SaprolingToken(), new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent())); - // You may cast Saproling Symbiosis as though it had flash if you pay {2} more to cast it. + Effect effect = new CreateTokenEffect(new SaprolingToken(), new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE)); + + // You may cast Saproling Symbiosis as though it had flash if you pay {2} more to cast it. (You may cast it any time you could cast an instant.) Ability ability = new PayMoreToCastAsThoughtItHadFlashAbility(this, new ManaCostsImpl("{2}")); ability.addEffect(effect); ability.setRuleAtTheTop(true); this.addAbility(ability); + // Create a 1/1 green Saproling creature token for each creature you control. this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java b/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java index 921f4fd270..9fdeaddc8b 100644 --- a/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java +++ b/Mage.Sets/src/mage/cards/s/SarkhanTheMad.java @@ -119,10 +119,13 @@ class SarkhanTheMadSacEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getTargets().getFirstTarget()); if (permanent != null) { - Player player = game.getPlayer(permanent.getControllerId()); permanent.sacrifice(this.getId(), game); - Token dragonToken = new DragonToken2(); - dragonToken.putOntoBattlefield(1, game, this.getId(), player.getId()); + + Player player = game.getPlayer(permanent.getControllerId()); + if(player != null) { + Token dragonToken = new DragonToken2(); + dragonToken.putOntoBattlefield(1, game, this.getId(), player.getId()); + } } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java b/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java new file mode 100644 index 0000000000..aa6a06f345 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SarkhanTheMasterless.java @@ -0,0 +1,165 @@ +package mage.cards.s; + +import mage.MageObjectReference; +import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.AttacksAllTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.DragonToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SarkhanTheMasterless extends CardImpl { + + public SarkhanTheMasterless(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{R}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SARKHAN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Whenever a creature attacks you or a planeswalker you control, each Dragon you control deals 1 damage to that creature. + this.addAbility(new AttacksAllTriggeredAbility( + new SarkhanTheMasterlessDamageEffect(), + false, StaticFilters.FILTER_PERMANENT_A_CREATURE, + SetTargetPointer.PERMANENT, true + )); + + // +1: Until end of turn, each planeswalker you control becomes a 4/4 red Dragon creature and gains flying. + this.addAbility(new LoyaltyAbility(new SarkhanTheMasterlessBecomeDragonEffect(), 1)); + + // -3: Create a 4/4 red Dragon creature token with flying. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DragonToken()), -3)); + } + + private SarkhanTheMasterless(final SarkhanTheMasterless card) { + super(card); + } + + @Override + public SarkhanTheMasterless copy() { + return new SarkhanTheMasterless(this); + } +} + +class SarkhanTheMasterlessDamageEffect extends OneShotEffect { + + SarkhanTheMasterlessDamageEffect() { + super(Outcome.Benefit); + staticText = "each Dragon you control deals 1 damage to that creature."; + } + + private SarkhanTheMasterlessDamageEffect(final SarkhanTheMasterlessDamageEffect effect) { + super(effect); + } + + @Override + public SarkhanTheMasterlessDamageEffect copy() { + return new SarkhanTheMasterlessDamageEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(targetPointer.getFirst(game, source)); + if (creature == null) { + return false; + } + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { + if (permanent != null && permanent.hasSubtype(SubType.DRAGON, game)) { + creature.damage(1, permanent.getId(), game); + } + } + return true; + } +} + +class SarkhanTheMasterlessBecomeDragonEffect extends ContinuousEffectImpl { + + SarkhanTheMasterlessBecomeDragonEffect() { + super(Duration.EndOfTurn, Outcome.BecomeCreature); + staticText = "Until end of turn, each planeswalker you control becomes a 4/4 red Dragon creature and gains flying."; + } + + private SarkhanTheMasterlessBecomeDragonEffect(final SarkhanTheMasterlessBecomeDragonEffect effect) { + super(effect); + } + + @Override + public SarkhanTheMasterlessBecomeDragonEffect copy() { + return new SarkhanTheMasterlessBecomeDragonEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(source.getControllerId())) { + if (permanent != null && permanent.isPlaneswalker()) { + affectedObjectList.add(new MageObjectReference(permanent, game)); + } + } + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + boolean flag = false; + for (MageObjectReference mor : affectedObjectList) { + Permanent permanent = mor.getPermanent(game); + if (permanent == null) { + continue; + } + flag = true; + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + permanent.getCardType().clear(); + permanent.addCardType(CardType.CREATURE); + permanent.getSubtype(game).clear(); + permanent.getSubtype(game).add(SubType.DRAGON); + permanent.getSuperType().clear(); + } + break; + case ColorChangingEffects_5: + permanent.getColor(game).setColor(ObjectColor.RED); + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + permanent.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + } + break; + case PTChangingEffects_7: + if (sublayer == SubLayer.SetPT_7b) { + permanent.getPower().setValue(4); + permanent.getToughness().setValue(4); + } + } + } + return flag; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 + || layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.ColorChangingEffects_5 + || layer == Layer.TypeChangingEffects_4; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SarkhansCatharsis.java b/Mage.Sets/src/mage/cards/s/SarkhansCatharsis.java new file mode 100644 index 0000000000..85db301710 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SarkhansCatharsis.java @@ -0,0 +1,32 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetPlayerOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SarkhansCatharsis extends CardImpl { + + public SarkhansCatharsis(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); + + // Sarkhan's Catharsis deals 5 damage to target player or planeswalker. + this.getSpellAbility().addEffect(new DamageTargetEffect(5)); + this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); + } + + private SarkhansCatharsis(final SarkhansCatharsis card) { + super(card); + } + + @Override + public SarkhansCatharsis copy() { + return new SarkhansCatharsis(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaruliCaretaker.java b/Mage.Sets/src/mage/cards/s/SaruliCaretaker.java new file mode 100644 index 0000000000..41e1e31fdf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SaruliCaretaker.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.costs.common.TapTargetCost; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SaruliCaretaker extends CardImpl { + + private static final FilterControlledCreaturePermanent filter + = new FilterControlledCreaturePermanent("an untapped creature you control"); + + static { + filter.add(Predicates.not(TappedPredicate.instance)); + } + + public SaruliCaretaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); + + this.subtype.add(SubType.DRYAD); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {T}, Tap an untapped creature you control: Add one mana of any color. + Ability ability = new AnyColorManaAbility(); + ability.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private SaruliCaretaker(final SaruliCaretaker card) { + super(card); + } + + @Override + public SaruliCaretaker copy() { + return new SaruliCaretaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java b/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java index 0d7f4450b6..2105f70749 100644 --- a/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SaruliGatekeepers.java @@ -1,13 +1,12 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.hint.ConditionHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,8 +15,9 @@ import mage.constants.SubType; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.SubtypePredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ @@ -25,12 +25,15 @@ import mage.filter.predicate.mageobject.SubtypePredicate; public final class SaruliGatekeepers extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + static { filter.add(new SubtypePredicate(SubType.GATE)); } - public SaruliGatekeepers (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{G}"); + private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public SaruliGatekeepers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.WARRIOR); @@ -40,11 +43,12 @@ public final class SaruliGatekeepers extends CardImpl { // When Saruli Gatekeepers enters the battlefield, if you control two or more Gates, gain 7 life. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new GainLifeEffect(7)), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), - "When {this} enters the battlefield, if you control two or more Gates, gain 7 life.")); + gatesCondition, + "When {this} enters the battlefield, if you control two or more Gates, gain 7 life.") + .addHint(new ConditionHint(gatesCondition, "You control two or more Gates"))); } - public SaruliGatekeepers (final SaruliGatekeepers card) { + public SaruliGatekeepers(final SaruliGatekeepers card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java b/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java index fafe925705..19e16e50ca 100644 --- a/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java +++ b/Mage.Sets/src/mage/cards/s/SatyrFiredancer.java @@ -1,9 +1,6 @@ package mage.cards.s; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -13,8 +10,8 @@ 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.SubType; import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; @@ -25,16 +22,20 @@ import mage.game.permanent.Permanent; import mage.game.stack.StackObject; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SatyrFiredancer extends CardImpl { public SatyrFiredancer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT,CardType.CREATURE},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{R}"); this.subtype.add(SubType.SATYR); this.power = new MageInt(1); @@ -47,19 +48,7 @@ public final class SatyrFiredancer extends CardImpl { public SatyrFiredancer(final SatyrFiredancer card) { super(card); } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SatyrFiredancerTriggeredAbility) { - Player opponent = game.getPlayer(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); - if (opponent != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by " + opponent.getLogName()); - filter.add(new ControllerIdPredicate(opponent.getId())); - ability.getTargets().add(new TargetCreaturePermanent(filter)); - } - } - } - + @Override public SatyrFiredancer copy() { return new SatyrFiredancer(this); @@ -72,6 +61,7 @@ class SatyrFiredancerTriggeredAbility extends TriggeredAbilityImpl { public SatyrFiredancerTriggeredAbility() { super(Zone.BATTLEFIELD, new SatyrFiredancerDamageEffect(), false); + targetAdjuster = SatyrFiredancerAdjuster.instance; } public SatyrFiredancerTriggeredAbility(final SatyrFiredancerTriggeredAbility ability) { @@ -97,15 +87,15 @@ class SatyrFiredancerTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (isControlledBy(game.getControllerId(event.getSourceId()))) { MageObject damageSource = game.getObject(event.getSourceId()); - if (damageSource != null) { + if (damageSource != null) { if (game.getOpponents(getControllerId()).contains(event.getTargetId())) { MageObject object = game.getObject(event.getSourceId()); - if (object.isInstant() || object.isSorcery()) { + if (object != null && (object.isInstant() || object.isSorcery())) { if (!(damageSource instanceof StackObject) || !handledStackObjects.contains(damageSource.getId())) { if (damageSource instanceof StackObject) { handledStackObjects.add(damageSource.getId()); } - for (Effect effect: this.getEffects()) { + for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(event.getTargetId())); // used by adjust targets effect.setValue("damage", event.getAmount()); } @@ -120,7 +110,7 @@ class SatyrFiredancerTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever an instant or sorcery spell you control deals damage to an opponent, ").append(super.getRule()).toString(); + return "Whenever an instant or sorcery spell you control deals damage to an opponent, " + super.getRule(); } } @@ -147,10 +137,24 @@ class SatyrFiredancerDamageEffect extends OneShotEffect { if (targetCreature != null && controller != null) { int damage = (Integer) this.getValue("damage"); if (damage > 0) { - targetCreature.damage(damage, source.getSourceId(), game, false, true); + targetCreature.damage(damage, source.getSourceId(), game, false, true); } return true; } return false; } } + +enum SatyrFiredancerAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Player opponent = game.getPlayer(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); + if (opponent != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature controlled by " + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponent.getId())); + ability.getTargets().add(new TargetCreaturePermanent(filter)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java b/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java index a913ed326f..c08d606f57 100644 --- a/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java +++ b/Mage.Sets/src/mage/cards/s/SatyrWayfinder.java @@ -71,8 +71,7 @@ class SatyrWayfinderEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); boolean properCardFound = cards.count(filterPutInHand, source.getControllerId(), source.getSourceId(), game) > 0; if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/s/SauroformHybrid.java b/Mage.Sets/src/mage/cards/s/SauroformHybrid.java new file mode 100644 index 0000000000..a26c167f88 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SauroformHybrid.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.AdaptAbility; +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 SauroformHybrid extends CardImpl { + + public SauroformHybrid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.LIZARD); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {4}{G}{G}: Adapt 4. + this.addAbility(new AdaptAbility(4, "{4}{G}{G}")); + } + + private SauroformHybrid(final SauroformHybrid card) { + super(card); + } + + @Override + public SauroformHybrid copy() { + return new SauroformHybrid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SavageAlliance.java b/Mage.Sets/src/mage/cards/s/SavageAlliance.java index 0563c3cd9b..3566b20362 100644 --- a/Mage.Sets/src/mage/cards/s/SavageAlliance.java +++ b/Mage.Sets/src/mage/cards/s/SavageAlliance.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.mana.GenericManaCost; @@ -29,22 +26,24 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SavageAlliance extends CardImpl { - private static final FilterPlayer filterPlayer = new FilterPlayer("player whose creatures gain trample"); - private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature to deal 2 damage to"); - private static final FilterPlayer filterOpponent = new FilterPlayer("opponent whose creatures get dealt damage"); + private static final FilterPlayer filterPlayer = new FilterPlayer(); + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent(); + private static final FilterPlayer filterOpponent = new FilterPlayer(); static { filterOpponent.add(new PlayerPredicate(TargetController.OPPONENT)); } public SavageAlliance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); // Escalate {1} this.addAbility(new EscalateAbility(new GenericManaCost(1))); @@ -55,20 +54,20 @@ public final class SavageAlliance extends CardImpl { // Creatures target player controls gain trample until end of turn. this.getSpellAbility().addEffect(new SavageAllianceGainTrampleEffect()); - this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterPlayer)); + this.getSpellAbility().addTarget(new TargetPlayer(1, 1, false, filterPlayer).withChooseHint("whose creatures gain trample")); // Savage Alliance deals 2 damage to target creature.; Mode mode = new Mode(); Effect effect = new DamageTargetEffect(2); effect.setText("{this} deals 2 damage to target creature"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent(filterCreature)); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent(filterCreature).withChooseHint("deals 2 damage to")); this.getSpellAbility().addMode(mode); // Savage Alliance deals 1 damage to each creature target opponent controls. mode = new Mode(); - mode.getEffects().add(new SavageAllianceDamageEffect()); - mode.getTargets().add(new TargetPlayer(1, 1, false, filterOpponent)); + mode.addEffect(new SavageAllianceDamageEffect()); + mode.addTarget(new TargetPlayer(1, 1, false, filterOpponent).withChooseHint("whose creatures get dealt 1 damage")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SavageBeating.java b/Mage.Sets/src/mage/cards/s/SavageBeating.java index 2cf2654c6b..43b482a887 100644 --- a/Mage.Sets/src/mage/cards/s/SavageBeating.java +++ b/Mage.Sets/src/mage/cards/s/SavageBeating.java @@ -36,8 +36,8 @@ public final class SavageBeating extends CardImpl { // or untap all creatures you control and after this phase, there is an additional combat phase. Mode mode = new Mode(); - mode.getEffects().add(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control")); - mode.getEffects().add(new AdditionalCombatPhaseEffect("and after this phase, there is an additional combat phase")); + mode.addEffect(new UntapAllControllerEffect(new FilterControlledCreaturePermanent(), "untap all creatures you control")); + mode.addEffect(new AdditionalCombatPhaseEffect("and after this phase, there is an additional combat phase")); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{R} diff --git a/Mage.Sets/src/mage/cards/s/SavagePunch.java b/Mage.Sets/src/mage/cards/s/SavagePunch.java index a2132158fe..44ecf46579 100644 --- a/Mage.Sets/src/mage/cards/s/SavagePunch.java +++ b/Mage.Sets/src/mage/cards/s/SavagePunch.java @@ -1,13 +1,12 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -19,8 +18,9 @@ import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SavagePunch extends CardImpl { @@ -40,6 +40,7 @@ public final class SavagePunch extends CardImpl { new LockedInCondition(FerociousCondition.instance), "Ferocious — The creature you control gets +2/+2 until end of turn before it fights if you control a creature with power 4 or greater"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addHint(FerociousHint.instance); // Target creature you control fights target creature you don't control. effect = new FightTargetsEffect(); diff --git a/Mage.Sets/src/mage/cards/s/SavageSmash.java b/Mage.Sets/src/mage/cards/s/SavageSmash.java new file mode 100644 index 0000000000..feea5a1e64 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SavageSmash.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SavageSmash extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public SavageSmash(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{R}{G}"); + + // Target creature you control gets +2/+2 until end of turn. It fights target creature you don't control. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getSpellAbility().addEffect( + new FightTargetsEffect().setText("It fights target creature you don't control") + ); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + private SavageSmash(final SavageSmash card) { + super(card); + } + + @Override + public SavageSmash copy() { + return new SavageSmash(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SavageStomp.java b/Mage.Sets/src/mage/cards/s/SavageStomp.java index 8a08017619..0b03f1085e 100644 --- a/Mage.Sets/src/mage/cards/s/SavageStomp.java +++ b/Mage.Sets/src/mage/cards/s/SavageStomp.java @@ -1,11 +1,9 @@ package mage.cards.s; -import java.util.Iterator; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; import mage.abilities.effects.Effect; import mage.abilities.effects.common.FightTargetsEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; @@ -17,35 +15,39 @@ import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.game.stack.StackObject; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SavageStomp extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you don't control"); + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + private static final FilterPermanent filter2 + = new FilterControlledCreaturePermanent(SubType.DINOSAUR, "a Dinosaur you control"); static { filter.add(new ControllerPredicate(TargetController.NOT_YOU)); } + private static final Condition condition = new SourceTargetsPermanentCondition(filter2); + public SavageStomp(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Savage Stomp costs {2} less to cast if it targets a Dinosaur you control. - this.addAbility(new SimpleStaticAbility(Zone.STACK, - new SpellCostReductionSourceEffect(2, SavageStompCondition.instance)) - .setRuleAtTheTop(true)); + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(2, condition) + ).setRuleAtTheTop(true)); // Put a +1/+1 counter on target creature you control. Then that creature fights target creature you don't control. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); @@ -67,34 +69,3 @@ public final class SavageStomp extends CardImpl { return new SavageStomp(this); } } - -enum SavageStompCondition implements Condition { - instance; - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Dinosaur you control"); - - static { - filter.add(new SubtypePredicate(SubType.DINOSAUR)); - filter.add(new ControllerPredicate(TargetController.YOU)); - } - - @Override - public boolean apply(Game game, Ability source) { - StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); - if (sourceSpell != null) { - Iterator targets = sourceSpell.getStackAbility().getTargets().iterator(); - while (targets.hasNext()) { - Permanent permanent = game.getPermanentOrLKIBattlefield(targets.next().getFirstTarget()); - if (permanent != null && filter.match(permanent, game) && permanent.isControlledBy(source.getControllerId())) { - return true; - } - } - } - return false; - } - - @Override - public String toString() { - return "it targets a Dinosaur you control"; - } - -} diff --git a/Mage.Sets/src/mage/cards/s/SavageSummoning.java b/Mage.Sets/src/mage/cards/s/SavageSummoning.java index 2d19dea4fb..f20f939cf8 100644 --- a/Mage.Sets/src/mage/cards/s/SavageSummoning.java +++ b/Mage.Sets/src/mage/cards/s/SavageSummoning.java @@ -75,7 +75,7 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get(SavageSummoningWatcher.class.getSimpleName(), source.getControllerId()); + watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId()); Card card = game.getCard(source.getSourceId()); if (watcher != null && card != null) { watcher.setSavageSummoningSpellActive(card, game); @@ -100,7 +100,7 @@ class SavageSummoningAsThoughEffect extends AsThoughEffectImpl { MageObject mageObject = game.getBaseObject(objectId); if (mageObject instanceof Commander) { Commander commander = (Commander) mageObject; - if (commander.isCreature() && commander.getControllerId().equals(source.getControllerId())) { + if (commander.isCreature() && commander.isControlledBy(source.getControllerId())) { return true; } } else if (mageObject instanceof Card) { @@ -122,7 +122,7 @@ class SavageSummoningWatcher extends Watcher { private Map> cardsCastWithSavageSummoning = new LinkedHashMap<>(); public SavageSummoningWatcher() { - super(SavageSummoningWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } public SavageSummoningWatcher(final SavageSummoningWatcher watcher) { @@ -148,7 +148,7 @@ class SavageSummoningWatcher extends Watcher { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.isCreature()) { spellsCastWithSavageSummoning.put(spell.getId(), new HashSet<>(savageSummoningSpells)); - String cardKey = new StringBuilder(spell.getCard().getId().toString()).append('_').append(spell.getCard().getZoneChangeCounter(game)).toString(); + String cardKey = spell.getCard().getId().toString() + '_' + spell.getCard().getZoneChangeCounter(game); cardsCastWithSavageSummoning.put(cardKey, new HashSet<>(savageSummoningSpells)); savageSummoningSpells.clear(); } @@ -157,7 +157,7 @@ class SavageSummoningWatcher extends Watcher { } public void setSavageSummoningSpellActive(Card card, Game game) { - String cardKey = new StringBuilder(card.getId().toString()).append('_').append(card.getZoneChangeCounter(game)).toString(); + String cardKey = card.getId().toString() + '_' + card.getZoneChangeCounter(game); savageSummoningSpells.add(cardKey); } @@ -166,7 +166,7 @@ class SavageSummoningWatcher extends Watcher { } public boolean isSpellCastWithThisSavageSummoning(UUID spellId, UUID cardId, int zoneChangeCounter) { - String cardKey = new StringBuilder(cardId.toString()).append('_').append(zoneChangeCounter).toString(); + String cardKey = cardId.toString() + '_' + zoneChangeCounter; Set savageSpells = spellsCastWithSavageSummoning.get(spellId); return savageSpells != null && savageSpells.contains(cardKey); } @@ -207,7 +207,7 @@ class SavageSummoningCantCounterEffect extends ContinuousRuleModifyingEffectImpl @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get(SavageSummoningWatcher.class.getSimpleName(), source.getControllerId()); + watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId()); Card card = game.getCard(source.getSourceId()); if (watcher == null || card == null) { throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); @@ -265,7 +265,7 @@ class SavageSummoningEntersBattlefieldEffect extends ReplacementEffectImpl { @Override public void init(Ability source, Game game) { - watcher = (SavageSummoningWatcher) game.getState().getWatchers().get(SavageSummoningWatcher.class.getSimpleName(), source.getControllerId()); + watcher = game.getState().getWatcher(SavageSummoningWatcher.class, source.getControllerId()); Card card = game.getCard(source.getSourceId()); if (watcher == null || card == null) { throw new IllegalArgumentException("Consume Savage watcher or card could not be found"); diff --git a/Mage.Sets/src/mage/cards/s/SavageTwister.java b/Mage.Sets/src/mage/cards/s/SavageTwister.java index 26acebbd85..0b9090439b 100644 --- a/Mage.Sets/src/mage/cards/s/SavageTwister.java +++ b/Mage.Sets/src/mage/cards/s/SavageTwister.java @@ -20,7 +20,7 @@ public final class SavageTwister extends CardImpl { // Savage Twister deals X damage to each creature. - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, new FilterCreaturePermanent())); } public SavageTwister(final SavageTwister card) { diff --git a/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java b/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java index c7b0d4f9e3..efb5f5926d 100644 --- a/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java +++ b/Mage.Sets/src/mage/cards/s/ScaldingSalamander.java @@ -26,7 +26,7 @@ public final class ScaldingSalamander extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); } diff --git a/Mage.Sets/src/mage/cards/s/ScaleguardSentinels.java b/Mage.Sets/src/mage/cards/s/ScaleguardSentinels.java index ee693bf611..6f0341a4e0 100644 --- a/Mage.Sets/src/mage/cards/s/ScaleguardSentinels.java +++ b/Mage.Sets/src/mage/cards/s/ScaleguardSentinels.java @@ -83,7 +83,7 @@ enum ScaleguardSentinelsCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentEntering(source.getSourceId()); if (sourcePermanent != null) { - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); return (watcher != null && watcher.castWithConditionTrue(sourcePermanent.getSpellAbility().getId())); } return false; diff --git a/Mage.Sets/src/mage/cards/s/Scapeshift.java b/Mage.Sets/src/mage/cards/s/Scapeshift.java index 7cf2a9cee6..b4eb29e6ee 100644 --- a/Mage.Sets/src/mage/cards/s/Scapeshift.java +++ b/Mage.Sets/src/mage/cards/s/Scapeshift.java @@ -66,8 +66,8 @@ class ScapeshiftEffect extends OneShotEffect { int amount = 0; TargetControlledPermanent sacrificeLand = new TargetControlledPermanent(0, Integer.MAX_VALUE, new FilterControlledLandPermanent("lands you control"), true); if (controller.chooseTarget(Outcome.Sacrifice, sacrificeLand, source, game)) { - for (Object uuid : sacrificeLand.getTargets()) { - Permanent land = game.getPermanent((UUID) uuid); + for (UUID uuid : sacrificeLand.getTargets()) { + Permanent land = game.getPermanent(uuid); if (land != null) { land.sacrifice(source.getSourceId(), game); amount++; @@ -75,7 +75,7 @@ class ScapeshiftEffect extends OneShotEffect { } } TargetCardInLibrary target = new TargetCardInLibrary(amount, new FilterLandCard("lands")); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/s/ScarabOfTheUnseen.java b/Mage.Sets/src/mage/cards/s/ScarabOfTheUnseen.java new file mode 100644 index 0000000000..7215fdc44f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScarabOfTheUnseen.java @@ -0,0 +1,102 @@ + +package mage.cards.s; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.other.OwnerPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +/** + * + * @author L_J + */ +public final class ScarabOfTheUnseen extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent("permanent you own"); + static { + filter.add(new OwnerPredicate(TargetController.YOU)); + } + + public ScarabOfTheUnseen(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + + // {T}, Sacrifice Scarab of the Unseen: Return all Auras attached to target permanent you own to their owners’ hands. Draw a card at the beginning of the next turn’s upkeep. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScarabOfTheUnseenEffect(), new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + ability.addEffect(new CreateDelayedTriggeredAbilityEffect(new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); + this.addAbility(ability); + } + + public ScarabOfTheUnseen(final ScarabOfTheUnseen card) { + super(card); + } + + @Override + public ScarabOfTheUnseen copy() { + return new ScarabOfTheUnseen(this); + } +} + +class ScarabOfTheUnseenEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterPermanent(); + static { + filter.add(new SubtypePredicate(SubType.AURA)); + } + + public ScarabOfTheUnseenEffect() { + super(Outcome.ReturnToHand); + this.staticText = "Return all Auras attached to target permanent you own to their owners’ hands"; + } + + public ScarabOfTheUnseenEffect(final ScarabOfTheUnseenEffect effect) { + super(effect); + } + + @Override + public ScarabOfTheUnseenEffect copy() { + return new ScarabOfTheUnseenEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (controller != null && targetPermanent != null) { + if (!targetPermanent.getAttachments().isEmpty()) { + List attachments = new ArrayList<>(); + attachments.addAll(targetPermanent.getAttachments()); + for (UUID attachedId : attachments) { + Permanent attachedPerm = game.getPermanent(attachedId); + if (attachedPerm != null && filter.match(attachedPerm, game)) { + controller.moveCards(attachedPerm, Zone.HAND, source, game); + } + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScarredPuma.java b/Mage.Sets/src/mage/cards/s/ScarredPuma.java index 9408d0a8bf..d1f88ee6b1 100644 --- a/Mage.Sets/src/mage/cards/s/ScarredPuma.java +++ b/Mage.Sets/src/mage/cards/s/ScarredPuma.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -11,21 +8,23 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Objects; +import java.util.UUID; + /** - * * @author Derpthemeus */ public final class ScarredPuma extends CardImpl { public ScarredPuma(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); this.subtype.add(SubType.CAT); this.power = new MageInt(2); this.toughness = new MageInt(1); @@ -62,7 +61,7 @@ public final class ScarredPuma extends CardImpl { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/ScavengingGhoul.java b/Mage.Sets/src/mage/cards/s/ScavengingGhoul.java index 103d57b360..d71e11b07b 100644 --- a/Mage.Sets/src/mage/cards/s/ScavengingGhoul.java +++ b/Mage.Sets/src/mage/cards/s/ScavengingGhoul.java @@ -32,7 +32,7 @@ public final class ScavengingGhoul extends CardImpl { // At the beginning of each end step, put a corpse counter on Scavenging Ghoul for each creature that died this turn. this.addAbility(new BeginningOfEndStepTriggeredAbility(new AddCountersSourceEffect(CounterType.CORPSE.createInstance(), - new CreaturesDiedThisTurnCount(), true), TargetController.ANY, false), new CreaturesDiedWatcher()); + CreaturesDiedThisTurnCount.instance, true), TargetController.ANY, false), new CreaturesDiedWatcher()); // Remove a corpse counter from Scavenging Ghoul: Regenerate Scavenging Ghoul. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new RemoveCountersSourceCost(CounterType.CORPSE.createInstance()))); diff --git a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java index 5907583eff..8455a23f8b 100644 --- a/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java +++ b/Mage.Sets/src/mage/cards/s/ScepterOfEmpires.java @@ -5,7 +5,6 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,8 +24,7 @@ public final class ScepterOfEmpires extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // {tap}: Scepter of Empires deals 1 damage to target player. It deals 3 damage to that player instead if you control artifacts named Crown of Empires and Throne of Empires. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScepterOfEmpiresEffect(), new GenericManaCost(0)); - ability.addCost(new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScepterOfEmpiresEffect(), new TapSourceCost()); ability.addTarget(new TargetPlayerOrPlaneswalker()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/ScholarOfAthreos.java b/Mage.Sets/src/mage/cards/s/ScholarOfAthreos.java index cc9c89b986..aebf8005de 100644 --- a/Mage.Sets/src/mage/cards/s/ScholarOfAthreos.java +++ b/Mage.Sets/src/mage/cards/s/ScholarOfAthreos.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -10,10 +9,11 @@ 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.SubType; import mage.constants.Zone; import mage.game.Game; +import mage.players.Player; /** * @@ -22,7 +22,7 @@ import mage.game.Game; public final class ScholarOfAthreos extends CardImpl { public ScholarOfAthreos(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.CLERIC); @@ -33,7 +33,7 @@ public final class ScholarOfAthreos extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScholarOfAthreosEffect(), new ManaCostsImpl("{2}{B}"))); } - public ScholarOfAthreos(final ScholarOfAthreos card) { + private ScholarOfAthreos(final ScholarOfAthreos card) { super(card); } @@ -50,17 +50,20 @@ class ScholarOfAthreosEffect extends OneShotEffect { staticText = "Each opponent loses 1 life. You gain life equal to the life lost this way"; } - public ScholarOfAthreosEffect(final ScholarOfAthreosEffect effect) { + private ScholarOfAthreosEffect(final ScholarOfAthreosEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { - int damage = 0; - for (UUID opponentId: game.getOpponents(source.getControllerId())) { - damage += game.getPlayer(opponentId).damage(1, source.getSourceId(), game, false, true); + int lifeLost = 0; + for (UUID opponentId : game.getOpponents(source.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if(opponent != null) { + lifeLost += opponent.loseLife(1, game, false); + } } - game.getPlayer(source.getControllerId()).gainLife(damage, game, source); + game.getPlayer(source.getControllerId()).gainLife(lifeLost, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/ScionOfTheUrDragon.java b/Mage.Sets/src/mage/cards/s/ScionOfTheUrDragon.java index ea6a90a501..5fccd4eb92 100644 --- a/Mage.Sets/src/mage/cards/s/ScionOfTheUrDragon.java +++ b/Mage.Sets/src/mage/cards/s/ScionOfTheUrDragon.java @@ -79,7 +79,7 @@ class ScionOfTheUrDragonEffect extends SearchEffect { Player player = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); if (player != null && sourcePermanent != null) { - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ScorchedEarth.java b/Mage.Sets/src/mage/cards/s/ScorchedEarth.java index bc2c406e14..0c578f5129 100644 --- a/Mage.Sets/src/mage/cards/s/ScorchedEarth.java +++ b/Mage.Sets/src/mage/cards/s/ScorchedEarth.java @@ -1,36 +1,36 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.common.FilterLandCard; import mage.filter.common.FilterLandPermanent; import mage.game.Game; import mage.target.common.TargetCardInHand; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class ScorchedEarth extends CardImpl { public ScorchedEarth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{R}"); // As an additional cost to cast Scorched Earth, discard X land cards. - Ability ability = new SimpleStaticAbility(Zone.ALL, new ScorchedEarthRuleEffect()); + Ability ability = new SimpleStaticAbility(Zone.ALL, new InfoEffect("as an additional cost to cast this spell, discard X land cards")); ability.setRuleAtTheTop(true); this.addAbility(ability); @@ -39,53 +39,39 @@ public final class ScorchedEarth extends CardImpl { effect.setText("Destroy X target lands"); this.getSpellAbility().addTarget(new TargetLandPermanent()); this.getSpellAbility().addEffect(effect); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetLandPermanent(xValue, xValue, new FilterLandPermanent(), false)); - } + this.getSpellAbility().setTargetAdjuster(ScorchedEarthTargetAdjuster.instance); + this.getSpellAbility().setCostAdjuster(ScorchedEarthCostAdjuster.instance); } public ScorchedEarth(final ScorchedEarth card) { super(card); } - @Override - public void adjustCosts(Ability ability, Game game) { - int xValue = ability.getManaCostsToPay().getX(); - if (xValue > 0) { - ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, new FilterLandCard("land cards")))); - } - } - @Override public ScorchedEarth copy() { return new ScorchedEarth(this); } } -class ScorchedEarthRuleEffect extends OneShotEffect { - - public ScorchedEarthRuleEffect() { - super(Outcome.Benefit); - this.staticText = "as an additional cost to cast this spell, discard X land cards"; - } - - public ScorchedEarthRuleEffect(final ScorchedEarthRuleEffect effect) { - super(effect); - } +enum ScorchedEarthTargetAdjuster implements TargetAdjuster { + instance; @Override - public ScorchedEarthRuleEffect copy() { - return new ScorchedEarthRuleEffect(this); + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetLandPermanent(xValue, xValue, new FilterLandPermanent(), false)); } +} + +enum ScorchedEarthCostAdjuster implements CostAdjuster { + instance; @Override - public boolean apply(Game game, Ability source) { - return true; + public void adjustCosts(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + if (xValue > 0) { + ability.addCost(new DiscardTargetCost(new TargetCardInHand(xValue, xValue, new FilterLandCard("land cards")))); + } } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/ScorchedRuins.java b/Mage.Sets/src/mage/cards/s/ScorchedRuins.java index f211684d46..7aad42b439 100644 --- a/Mage.Sets/src/mage/cards/s/ScorchedRuins.java +++ b/Mage.Sets/src/mage/cards/s/ScorchedRuins.java @@ -29,7 +29,7 @@ public final class ScorchedRuins extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("two untapped lands"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ScorchedRuins(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/Scorchmark.java b/Mage.Sets/src/mage/cards/s/Scorchmark.java new file mode 100644 index 0000000000..7cb9756207 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Scorchmark.java @@ -0,0 +1,34 @@ +package mage.cards.s; + +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileTargetIfDiesEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Scorchmark extends CardImpl { + + public Scorchmark(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); + + // Scorchmark deals 2 damage to target creature. If that creature would die this turn, exile it instead. + this.getSpellAbility().addEffect(new DamageTargetEffect(2)); + this.getSpellAbility().addEffect(new ExileTargetIfDiesEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private Scorchmark(final Scorchmark card) { + super(card); + } + + @Override + public Scorchmark copy() { + return new Scorchmark(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ScoriaCat.java b/Mage.Sets/src/mage/cards/s/ScoriaCat.java index 26dc4a4b40..718623d998 100644 --- a/Mage.Sets/src/mage/cards/s/ScoriaCat.java +++ b/Mage.Sets/src/mage/cards/s/ScoriaCat.java @@ -27,7 +27,7 @@ public final class ScoriaCat extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ScoriaCat(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ScoriaWurm.java b/Mage.Sets/src/mage/cards/s/ScoriaWurm.java index 4c05f8d350..5f02aba6f9 100644 --- a/Mage.Sets/src/mage/cards/s/ScoriaWurm.java +++ b/Mage.Sets/src/mage/cards/s/ScoriaWurm.java @@ -60,7 +60,7 @@ class ScoriaWurmEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { return true; } else { new ReturnToHandSourceEffect().apply(game, source); diff --git a/Mage.Sets/src/mage/cards/s/ScourTheLaboratory.java b/Mage.Sets/src/mage/cards/s/ScourTheLaboratory.java index 184a09f0ae..4b52a814ce 100644 --- a/Mage.Sets/src/mage/cards/s/ScourTheLaboratory.java +++ b/Mage.Sets/src/mage/cards/s/ScourTheLaboratory.java @@ -1,12 +1,13 @@ - package mage.cards.s; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.AbilityWord; @@ -14,18 +15,18 @@ import mage.constants.CardType; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class ScourTheLaboratory extends CardImpl { public ScourTheLaboratory(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{U}{U}"); // Delirium — Scour the Laboratory costs {2} less to cast if there are four or more card types among cards in your graveyard. Ability ability = new SimpleStaticAbility(Zone.STACK, new SpellCostReductionSourceEffect(2, DeliriumCondition.instance)); ability.setRuleAtTheTop(true); ability.setAbilityWord(AbilityWord.DELIRIUM); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); // Draw three cards. diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfKherRidges.java b/Mage.Sets/src/mage/cards/s/ScourgeOfKherRidges.java index ec103fb903..56a7d280b3 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfKherRidges.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfKherRidges.java @@ -30,7 +30,7 @@ public final class ScourgeOfKherRidges extends CardImpl { static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); filter2.add(new AbilityPredicate(FlyingAbility.class)); - filter2.add(new AnotherPredicate()); + filter2.add(AnotherPredicate.instance); } public ScourgeOfKherRidges(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java b/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java index 2e3a2d0277..d762ba2de5 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeOfValkas.java @@ -31,7 +31,7 @@ import mage.target.common.TargetAnyTarget; */ public final class ScourgeOfValkas extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("{this} or another Dragon"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("{this} or another Dragon"); static { filter.add(new SubtypePredicate(SubType.DRAGON)); diff --git a/Mage.Sets/src/mage/cards/s/ScourgeWolf.java b/Mage.Sets/src/mage/cards/s/ScourgeWolf.java index bb9df75099..be99ccbd46 100644 --- a/Mage.Sets/src/mage/cards/s/ScourgeWolf.java +++ b/Mage.Sets/src/mage/cards/s/ScourgeWolf.java @@ -1,12 +1,13 @@ - package mage.cards.s; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; @@ -17,13 +18,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class ScourgeWolf extends CardImpl { public ScourgeWolf(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{R}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); this.subtype.add(SubType.WOLF); this.subtype.add(SubType.HORROR); this.power = new MageInt(2); @@ -35,7 +35,7 @@ public final class ScourgeWolf extends CardImpl { // Delirium — Scourge Wolf has double strike as long as there are four or more card types among cards in your graveyard. ConditionalContinuousEffect effect = new ConditionalContinuousEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield), DeliriumCondition.instance, "Delirium — {this} has double strike as long as there are four or more card types among cards in your graveyard."); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(DeliriumHint.instance)); } public ScourgeWolf(final ScourgeWolf card) { diff --git a/Mage.Sets/src/mage/cards/s/ScoutsWarning.java b/Mage.Sets/src/mage/cards/s/ScoutsWarning.java index 5ddb9e6c3a..0310f8d1f5 100644 --- a/Mage.Sets/src/mage/cards/s/ScoutsWarning.java +++ b/Mage.Sets/src/mage/cards/s/ScoutsWarning.java @@ -65,7 +65,7 @@ class ScoutsWarningAsThoughEffect extends AsThoughEffectImpl { @Override public void init(Ability source, Game game) { - watcher = (ScoutsWarningWatcher) game.getState().getWatchers().get(ScoutsWarningWatcher.class.getSimpleName(), source.getControllerId()); + watcher = game.getState().getWatcher(ScoutsWarningWatcher.class, source.getControllerId()); Card card = game.getCard(source.getSourceId()); if (watcher != null && card != null) { zoneChangeCounter = card.getZoneChangeCounter(game); @@ -98,10 +98,10 @@ class ScoutsWarningAsThoughEffect extends AsThoughEffectImpl { class ScoutsWarningWatcher extends Watcher { - public List activeScoutsWarningSpells = new ArrayList<>(); + private List activeScoutsWarningSpells = new ArrayList<>(); public ScoutsWarningWatcher() { - super(ScoutsWarningWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } public ScoutsWarningWatcher(final ScoutsWarningWatcher watcher) { @@ -116,29 +116,36 @@ class ScoutsWarningWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.SPELL_CAST) { - if (!activeScoutsWarningSpells.isEmpty() && event.getPlayerId().equals(getControllerId())) { + if (!getActiveScoutsWarningSpells().isEmpty() && event.getPlayerId().equals(getControllerId())) { Spell spell = game.getStack().getSpell(event.getTargetId()); if (spell != null && spell.isCreature()) { - activeScoutsWarningSpells.clear(); + getActiveScoutsWarningSpells().clear(); } } } } public void addScoutsWarningSpell(UUID sourceId, int zoneChangeCounter) { - String spellKey = new StringBuilder(sourceId.toString()).append('_').append(zoneChangeCounter).toString(); - activeScoutsWarningSpells.add(spellKey); + String spellKey = sourceId.toString() + '_' + zoneChangeCounter; + getActiveScoutsWarningSpells().add(spellKey); } public boolean isScoutsWarningSpellActive(UUID sourceId, int zoneChangeCounter) { - String spellKey = new StringBuilder(sourceId.toString()).append('_').append(zoneChangeCounter).toString(); - return activeScoutsWarningSpells.contains(spellKey); + String spellKey = sourceId.toString() + '_' + zoneChangeCounter; + return getActiveScoutsWarningSpells().contains(spellKey); } @Override public void reset() { super.reset(); - activeScoutsWarningSpells.clear(); + getActiveScoutsWarningSpells().clear(); } + public List getActiveScoutsWarningSpells() { + return activeScoutsWarningSpells; + } + + public void setActiveScoutsWarningSpells(List activeScoutsWarningSpells) { + this.activeScoutsWarningSpells = activeScoutsWarningSpells; + } } diff --git a/Mage.Sets/src/mage/cards/s/ScrabblingClaws.java b/Mage.Sets/src/mage/cards/s/ScrabblingClaws.java index b06aa9a731..357f45b6bb 100644 --- a/Mage.Sets/src/mage/cards/s/ScrabblingClaws.java +++ b/Mage.Sets/src/mage/cards/s/ScrabblingClaws.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -23,8 +22,9 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author fireshoes */ public final class ScrabblingClaws extends CardImpl { @@ -33,18 +33,27 @@ public final class ScrabblingClaws extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // {tap}: Target player exiles a card from their graveyard. - Ability firstAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScrabblingClawsEffect(), new TapSourceCost()); - firstAbility.addTarget(new TargetPlayer()); - this.addAbility(firstAbility); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ScrabblingClawsEffect(), new + TapSourceCost() + ); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + // {1}, Sacrifice Scrabbling Claws: Exile target card from a graveyard. Draw a card. - SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new SacrificeSourceCost()); - ability.addCost(new GenericManaCost(1)); + ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ExileTargetEffect(), + new GenericManaCost(1) + ); + ability.addCost(new SacrificeSourceCost()); ability.addTarget(new TargetCardInGraveyard()); ability.addEffect(new DrawCardSourceControllerEffect(1)); this.addAbility(ability); } - public ScrabblingClaws(final ScrabblingClaws card) { + private ScrabblingClaws(final ScrabblingClaws card) { super(card); } @@ -56,12 +65,12 @@ public final class ScrabblingClaws extends CardImpl { class ScrabblingClawsEffect extends OneShotEffect { - public ScrabblingClawsEffect() { + ScrabblingClawsEffect() { super(Outcome.Exile); this.staticText = "Target player exiles a card from their graveyard"; } - public ScrabblingClawsEffect(final ScrabblingClawsEffect effect) { + private ScrabblingClawsEffect(final ScrabblingClawsEffect effect) { super(effect); } @@ -73,18 +82,16 @@ class ScrabblingClawsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player targetPlayer = game.getPlayer(source.getFirstTarget()); - if (targetPlayer != null) { - FilterCard filter = new FilterCard("card from your graveyard"); - filter.add(new OwnerIdPredicate(targetPlayer.getId())); - TargetCardInGraveyard target = new TargetCardInGraveyard(filter); - if (targetPlayer.chooseTarget(Outcome.Exile, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null) { - targetPlayer.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.GRAVEYARD, true); - } - return true; - } + if (targetPlayer == null) { + return false; } - return false; + FilterCard filter = new FilterCard("card from your graveyard"); + filter.add(new OwnerIdPredicate(targetPlayer.getId())); + TargetCardInGraveyard target = new TargetCardInGraveyard(filter); + if (!targetPlayer.chooseTarget(Outcome.Exile, target, source, game)) { + return false; + } + Card card = game.getCard(target.getFirstTarget()); + return card != null && targetPlayer.moveCards(card, Zone.EXILED, source, game); } } diff --git a/Mage.Sets/src/mage/cards/s/Scrapheap.java b/Mage.Sets/src/mage/cards/s/Scrapheap.java index b57e7f95e6..78385f1a2f 100644 --- a/Mage.Sets/src/mage/cards/s/Scrapheap.java +++ b/Mage.Sets/src/mage/cards/s/Scrapheap.java @@ -62,7 +62,7 @@ class ScrapheapTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && permanent.isOwnedBy(this.getControllerId())) { if (StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT.match(permanent, sourceId, controllerId, game)) { diff --git a/Mage.Sets/src/mage/cards/s/ScreamingShield.java b/Mage.Sets/src/mage/cards/s/ScreamingShield.java new file mode 100644 index 0000000000..a31cb67e01 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScreamingShield.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.effects.common.continuous.BoostEquippedEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.keyword.EquipAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ScreamingShield extends CardImpl { + + public ScreamingShield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); + + this.subtype.add(SubType.EQUIPMENT); + + // Equipped creature gets +0/+3 and has "{2}, {T}: Target player puts the top three cards of their library into their graveyard." + Ability toAdd = new SimpleActivatedAbility( + new PutLibraryIntoGraveTargetEffect(3), new GenericManaCost(2) + ); + toAdd.addCost(new TapSourceCost()); + toAdd.addTarget(new TargetPlayer()); + Ability ability = new SimpleStaticAbility(new BoostEquippedEffect(0, 3)); + ability.addEffect(new GainAbilityAttachedEffect( + toAdd, AttachmentType.EQUIPMENT + ).setText("and has \"{2}, {T}: Target player puts the top three cards of their library into their graveyard.\"")); + this.addAbility(ability); + + // Equip {3} + this.addAbility(new EquipAbility(3)); + } + + private ScreamingShield(final ScreamingShield card) { + super(card); + } + + @Override + public ScreamingShield copy() { + return new ScreamingShield(this); + } +} +// AAAAAAAAAAAAAAAAAAAAAAHHHHHHHHHHHHHHHHHHHHH diff --git a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java index b356cdac11..da04611f60 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingSilcaw.java @@ -20,7 +20,7 @@ import mage.constants.SubType; */ public final class ScreechingSilcaw extends CardImpl { - private static final String text = "Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard."; + private static final String rule = "Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard."; public ScreechingSilcaw(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); @@ -34,7 +34,7 @@ public final class ScreechingSilcaw extends CardImpl { //"Metalcraft — Whenever Screeching Silcaw deals combat damage to a player, if you control three or more artifacts, that player puts the top four cards of their library into their graveyard. TriggeredAbility conditional = new ConditionalInterveningIfTriggeredAbility( new DealsCombatDamageToAPlayerTriggeredAbility(new PutLibraryIntoGraveTargetEffect(4), false, true), - MetalcraftCondition.instance, text); + MetalcraftCondition.instance, rule); this.addAbility(conditional); } diff --git a/Mage.Sets/src/mage/cards/s/ScreechingSliver.java b/Mage.Sets/src/mage/cards/s/ScreechingSliver.java index afff09d73a..908ef9eda5 100644 --- a/Mage.Sets/src/mage/cards/s/ScreechingSliver.java +++ b/Mage.Sets/src/mage/cards/s/ScreechingSliver.java @@ -23,7 +23,7 @@ import mage.target.TargetPlayer; */ public final class ScreechingSliver extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent(SubType.SLIVER, "All Slivers"); + private static final FilterPermanent allSliversFilter = new FilterPermanent(SubType.SLIVER, "All Slivers"); public ScreechingSliver(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); @@ -37,7 +37,7 @@ public final class ScreechingSliver extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAllEffect(ability, Duration.WhileOnBattlefield, - filter, "All Slivers have \"{T}: Target player puts the top card of their library into their graveyard.\""))); + allSliversFilter, "All Slivers have \"{T}: Target player puts the top card of their library into their graveyard.\""))); } public ScreechingSliver(final ScreechingSliver card) { diff --git a/Mage.Sets/src/mage/cards/s/ScribNibblers.java b/Mage.Sets/src/mage/cards/s/ScribNibblers.java index 93806d4abd..8b47ffbf42 100644 --- a/Mage.Sets/src/mage/cards/s/ScribNibblers.java +++ b/Mage.Sets/src/mage/cards/s/ScribNibblers.java @@ -75,7 +75,7 @@ class ScribNibblersEffect extends OneShotEffect { if (targetPlayer != null && targetPlayer.getLibrary().hasCards()) { Card card = targetPlayer.getLibrary().getFromTop(game); card.moveToExile(id, "Scrib Nibblers Exile", source.getSourceId(), game); - if (card.isLand()) { + if (card.isLand() && you != null) { you.gainLife(1, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java index 13c98760f3..c9421d3b05 100644 --- a/Mage.Sets/src/mage/cards/s/ScroungingBandar.java +++ b/Mage.Sets/src/mage/cards/s/ScroungingBandar.java @@ -32,7 +32,7 @@ public final class ScroungingBandar extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ScroungingBandar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ScryingGlass.java b/Mage.Sets/src/mage/cards/s/ScryingGlass.java new file mode 100644 index 0000000000..bb535f3a52 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ScryingGlass.java @@ -0,0 +1,87 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.ChoiceColor; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author jeffwadsworth + */ +public final class ScryingGlass extends CardImpl { + + public ScryingGlass(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // {3}, {tap}: Choose a number greater than 0 and a color. Target opponent reveals their hand. If that opponent reveals exactly the chosen number of cards of the chosen color, you draw a card. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ScryingGlassEffect(), new ManaCostsImpl("{3}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + + } + + public ScryingGlass(final ScryingGlass card) { + super(card); + } + + @Override + public ScryingGlass copy() { + return new ScryingGlass(this); + } +} + +class ScryingGlassEffect extends OneShotEffect { + + public ScryingGlassEffect() { + super(Outcome.Neutral); + staticText = "Choose a number greater than 0 and a color. Target opponent reveals their hand. If that opponent reveals exactly the chosen number of cards of the chosen color, you draw a card"; + } + + public ScryingGlassEffect(final ScryingGlassEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player targetOpponent = game.getPlayer(source.getFirstTarget()); + ChoiceColor color = new ChoiceColor(); + int amount = 0; + if (controller != null + && targetOpponent != null) { + amount = controller.getAmount(1, Integer.MAX_VALUE, "Choose a number", game); + controller.choose(Outcome.Discard, color, game); + FilterCard filter = new FilterCard(); + filter.add(new ColorPredicate(color.getColor())); + targetOpponent.revealCards(source, targetOpponent.getHand(), game); + if (targetOpponent.getHand().count(filter, game) == amount) { + game.informPlayers(controller.getName() + " has chosen the exact number and color of the revealed cards from " + targetOpponent.getName() + "'s hand. They draw a card."); + controller.drawCards(1, game); + return true; + } else { + game.informPlayers(controller.getName() + " has chosen incorrectly and will not draw a card."); + } + } + return false; + } + + @Override + public ScryingGlassEffect copy() { + return new ScryingGlassEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Scuttlegator.java b/Mage.Sets/src/mage/cards/s/Scuttlegator.java new file mode 100644 index 0000000000..9cde2f38b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Scuttlegator.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.decorator.ConditionalAsThoughEffect; +import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Scuttlegator extends CardImpl { + + public Scuttlegator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G/U}{G/U}"); + + this.subtype.add(SubType.CRAB); + this.subtype.add(SubType.TURTLE); + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {6}{G/U}{G/U}: Adapt 3. + this.addAbility(new AdaptAbility(3, "{6}{G/U}{G/U}")); + + // As long as Scuttlegator has a +1/+1 counter on it, it can attack as though it didn't have defender. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalAsThoughEffect( + new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), + new SourceHasCounterCondition(CounterType.P1P1) + ).setText("As long as {this} has a +1/+1 counter on it, " + + "it can attack as though it didn't have defender.") + )); + } + + private Scuttlegator(final Scuttlegator card) { + super(card); + } + + @Override + public Scuttlegator copy() { + return new Scuttlegator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeaTroll.java b/Mage.Sets/src/mage/cards/s/SeaTroll.java index 09a364ec86..2db49072d5 100644 --- a/Mage.Sets/src/mage/cards/s/SeaTroll.java +++ b/Mage.Sets/src/mage/cards/s/SeaTroll.java @@ -58,7 +58,7 @@ class SeaTrollWatcher extends Watcher { private final Set blockedOrBlockedByBlueThisTurnCreatures; public SeaTrollWatcher() { - super(SeaTrollWatcher.class.getSimpleName(), WatcherScope.GAME); + super( WatcherScope.GAME); blockedOrBlockedByBlueThisTurnCreatures = new HashSet<>(); } @@ -103,7 +103,7 @@ class SeaTrollCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourcePermanent != null){ - SeaTrollWatcher watcher = (SeaTrollWatcher) game.getState().getWatchers().get(SeaTrollWatcher.class.getSimpleName()); + SeaTrollWatcher watcher = game.getState().getWatcher(SeaTrollWatcher.class); if (watcher != null) { return watcher.blockedOrBlockedByBlueCreatureThisTurn(new MageObjectReference(sourcePermanent, game)); } diff --git a/Mage.Sets/src/mage/cards/s/SeafarersQuay.java b/Mage.Sets/src/mage/cards/s/SeafarersQuay.java new file mode 100644 index 0000000000..ce62ca0040 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeafarersQuay.java @@ -0,0 +1,47 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class SeafarersQuay extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Blue legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLUE)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public SeafarersQuay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Blue legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public SeafarersQuay(final SeafarersQuay card) { + super(card); + } + + @Override + public SeafarersQuay copy() { + return new SeafarersQuay(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SealAway.java b/Mage.Sets/src/mage/cards/s/SealAway.java index ebf5fdcdb8..9ad8ab7f25 100644 --- a/Mage.Sets/src/mage/cards/s/SealAway.java +++ b/Mage.Sets/src/mage/cards/s/SealAway.java @@ -24,11 +24,11 @@ import mage.target.TargetPermanent; */ public final class SealAway extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SealAway(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java b/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java new file mode 100644 index 0000000000..06e24dc5c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SearchForSurvivors.java @@ -0,0 +1,101 @@ +package mage.cards.s; + +import java.util.Arrays; +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.util.RandomUtil; + +/** + * + * @author jeffwadsworth + */ + +/* + The card is chosen at random, so the computer just picks a card at random from + the controller's graveyard. Devs, feel free to set up something else... + */ +public final class SearchForSurvivors extends CardImpl { + + public SearchForSurvivors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Reorder your graveyard at random. An opponent chooses a card at random in your graveyard. If it's a creature card, put it onto the battlefield. Otherwise, exile it. + this.getSpellAbility().addEffect(new SearchForSurvivorsEffect()); + + } + + public SearchForSurvivors(final SearchForSurvivors card) { + super(card); + } + + @Override + public SearchForSurvivors copy() { + return new SearchForSurvivors(this); + } +} + +class SearchForSurvivorsEffect extends OneShotEffect { + + public SearchForSurvivorsEffect() { + super(Outcome.PutCardInPlay); + this.staticText = "Reorder your graveyard at random. " + + "An opponent chooses a card at random in your graveyard. " + + "If it's a creature card, put it onto the battlefield. " + + "Otherwise, exile it"; + } + + public SearchForSurvivorsEffect(final SearchForSurvivorsEffect effect) { + super(effect); + } + + @Override + public SearchForSurvivorsEffect copy() { + return new SearchForSurvivorsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + game.informPlayers("The controller of Search for Survivors will have their graveyard randomized. " + + " A card will be chosen at random from the controller's graveyard. " + + " The result is essentially the same as the card rule"); + // randomly arrange the graveyard + UUID[] shuffled = controller.getGraveyard().toArray(new UUID[0]); + for (int n = shuffled.length - 1; n > 0; n--) { + int r = RandomUtil.nextInt(n + 1); + UUID temp = shuffled[r]; + shuffled[r] = shuffled[n]; + shuffled[n] = temp; + } + controller.getGraveyard().clear(); + controller.getGraveyard().addAll(Arrays.asList(shuffled)); + // end of randomize + Cards cards = new CardsImpl(controller.getGraveyard().getCards(game)); + if (!cards.isEmpty()) { + Card card = cards.getRandom(game); + cards.clear(); + cards.add(card); + controller.revealCards(source, cards, game); // reveal the card randomly chosen. + if (card.isCreature()) { + controller.moveCards(card, Zone.BATTLEFIELD, source, game); + } else { + controller.moveCards(card, Zone.EXILED, source, game); + } + } + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SearchTheCity.java b/Mage.Sets/src/mage/cards/s/SearchTheCity.java index e1b87380fb..57ad86e633 100644 --- a/Mage.Sets/src/mage/cards/s/SearchTheCity.java +++ b/Mage.Sets/src/mage/cards/s/SearchTheCity.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -22,9 +20,11 @@ import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.game.turn.TurnMod; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SearchTheCity extends CardImpl { @@ -157,7 +157,7 @@ class SearchTheCityExiledCardToHandEffect extends OneShotEffect { ExileZone searchTheCityExileZone = game.getExile().getExileZone(source.getSourceId()); if (cardName != null && searchTheCityExileZone != null) { for (Card card : searchTheCityExileZone.getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { if (card.moveToZone(Zone.HAND, source.getSourceId(), game, true)) { game.informPlayers("Search the City: put " + card.getName() + " into owner's hand"); } diff --git a/Mage.Sets/src/mage/cards/s/SearingBlaze.java b/Mage.Sets/src/mage/cards/s/SearingBlaze.java index cda4d3ce25..03c5e9287c 100644 --- a/Mage.Sets/src/mage/cards/s/SearingBlaze.java +++ b/Mage.Sets/src/mage/cards/s/SearingBlaze.java @@ -67,7 +67,7 @@ class SearingBlazeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - LandfallWatcher watcher = (LandfallWatcher) game.getState().getWatchers().get(LandfallWatcher.class.getSimpleName()); + LandfallWatcher watcher = game.getState().getWatcher(LandfallWatcher.class); Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); int damage = 1; if (watcher != null && watcher.landPlayed(source.getControllerId())) { diff --git a/Mage.Sets/src/mage/cards/s/SearingBlood.java b/Mage.Sets/src/mage/cards/s/SearingBlood.java index e6a483074f..2adff7cba2 100644 --- a/Mage.Sets/src/mage/cards/s/SearingBlood.java +++ b/Mage.Sets/src/mage/cards/s/SearingBlood.java @@ -93,7 +93,7 @@ class SearingBloodDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(target)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java b/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java index 35cc67e2c3..f50857d9f2 100644 --- a/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java +++ b/Mage.Sets/src/mage/cards/s/SeasonOfTheWitch.java @@ -87,13 +87,13 @@ class SeasonOfTheWitchEffect extends OneShotEffect { continue; } // Creatures that attacked are safe. - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { continue; } // Creatures that couldn't attack are safe. - CouldAttackThisTurnWatcher watcher2 = (CouldAttackThisTurnWatcher) game.getState().getWatchers().get(CouldAttackThisTurnWatcher.class.getSimpleName()); + CouldAttackThisTurnWatcher watcher2 = game.getState().getWatcher(CouldAttackThisTurnWatcher.class); if (watcher2 != null && !watcher2.getCouldAttackThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { continue; @@ -109,10 +109,10 @@ class SeasonOfTheWitchEffect extends OneShotEffect { class CouldAttackThisTurnWatcher extends Watcher { - public final Set couldAttackThisTurnCreatures = new HashSet<>(); + private final Set couldAttackThisTurnCreatures = new HashSet<>(); public CouldAttackThisTurnWatcher() { - super(CouldAttackThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CouldAttackThisTurnWatcher(final CouldAttackThisTurnWatcher watcher) { @@ -124,6 +124,9 @@ class CouldAttackThisTurnWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.DECLARE_ATTACKERS_STEP_PRE) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); + if(activePlayer == null){ + return; + } for (Permanent permanent : game.getBattlefield().getAllActivePermanents(activePlayer.getId())) { if (permanent.isCreature()) { for (UUID defender : game.getCombat().getDefenders()) { diff --git a/Mage.Sets/src/mage/cards/s/SecondGuess.java b/Mage.Sets/src/mage/cards/s/SecondGuess.java index 140e9f74a2..175535ad47 100644 --- a/Mage.Sets/src/mage/cards/s/SecondGuess.java +++ b/Mage.Sets/src/mage/cards/s/SecondGuess.java @@ -49,9 +49,9 @@ class SecondSpellPredicate implements Predicate { @Override public boolean apply(StackObject input, Game game) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); - if (watcher.getSpellOrder(new MageObjectReference(input.getId(), game), game) == 2) { + if (watcher != null && watcher.getSpellOrder(new MageObjectReference(input.getId(), game), game) == 2) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/SecondHarvest.java b/Mage.Sets/src/mage/cards/s/SecondHarvest.java index 747a0073d4..841cb58737 100644 --- a/Mage.Sets/src/mage/cards/s/SecondHarvest.java +++ b/Mage.Sets/src/mage/cards/s/SecondHarvest.java @@ -60,7 +60,7 @@ class SecondHarvestEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { FilterControlledPermanent filter = new FilterControlledPermanent("each token you control"); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game)) { if (permanent != null) { CreateTokenCopyTargetEffect effect = new CreateTokenCopyTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/s/SecondSight.java b/Mage.Sets/src/mage/cards/s/SecondSight.java index a25e08b223..b3daccbbbf 100644 --- a/Mage.Sets/src/mage/cards/s/SecondSight.java +++ b/Mage.Sets/src/mage/cards/s/SecondSight.java @@ -1,10 +1,8 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LookLibraryControllerEffect; import mage.abilities.keyword.EntwineAbility; @@ -18,8 +16,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SecondSight extends CardImpl { @@ -32,22 +31,17 @@ public final class SecondSight extends CardImpl { this.getSpellAbility().getModes().setMaxModes(1); //Look at the top five cards of target opponent's library, then put them back in any order; - Effect effect = new SecondSightEffect(); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect(new SecondSightEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); //or look at the top five cards of your library, then put them back in any order. - effect = new LookLibraryControllerEffect(5); - Mode mode = new Mode(); - mode.getEffects().add(effect); - this.getSpellAbility().getModes().addMode(mode); + this.getSpellAbility().getModes().addMode(new Mode(new LookLibraryControllerEffect(5))); // Entwine {U} this.addAbility(new EntwineAbility("{U}")); - } - public SecondSight(final SecondSight card) { + private SecondSight(final SecondSight card) { super(card); } @@ -59,12 +53,12 @@ public final class SecondSight extends CardImpl { class SecondSightEffect extends OneShotEffect { - public SecondSightEffect() { + SecondSightEffect() { super(Outcome.DrawCard); this.staticText = "look at the top five cards of target opponent's library, then put them back in any order"; } - public SecondSightEffect(final SecondSightEffect effect) { + private SecondSightEffect(final SecondSightEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/s/SecondSunrise.java b/Mage.Sets/src/mage/cards/s/SecondSunrise.java index c4eed33e12..80eab7a411 100644 --- a/Mage.Sets/src/mage/cards/s/SecondSunrise.java +++ b/Mage.Sets/src/mage/cards/s/SecondSunrise.java @@ -57,9 +57,9 @@ class SecondSunriseEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SecondSunriseWatcher watcher = (SecondSunriseWatcher) game.getState().getWatchers().get(SecondSunriseWatcher.class.getSimpleName()); + SecondSunriseWatcher watcher = game.getState().getWatcher(SecondSunriseWatcher.class); if (watcher != null) { - for (UUID id : watcher.cards) { + for (UUID id : watcher.getCards()) { Card c = game.getCard(id); if (c != null && game.getState().getZone(id) == Zone.GRAVEYARD) { if (c.isArtifact() || c.isCreature() || @@ -79,10 +79,10 @@ class SecondSunriseEffect extends OneShotEffect { } class SecondSunriseWatcher extends Watcher { - List cards = new ArrayList<>(); + private List cards = new ArrayList<>(); public SecondSunriseWatcher() { - super(SecondSunriseWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SecondSunriseWatcher(final SecondSunriseWatcher watcher) { @@ -107,4 +107,8 @@ class SecondSunriseWatcher extends Watcher { super.reset(); cards.clear(); } + + public List getCards(){ + return cards; + } } diff --git a/Mage.Sets/src/mage/cards/s/SecretPlans.java b/Mage.Sets/src/mage/cards/s/SecretPlans.java index 9809873940..b8ec3a1539 100644 --- a/Mage.Sets/src/mage/cards/s/SecretPlans.java +++ b/Mage.Sets/src/mage/cards/s/SecretPlans.java @@ -24,7 +24,7 @@ public final class SecretPlans extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Face-down creatures"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public SecretPlans(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SecretSalvage.java b/Mage.Sets/src/mage/cards/s/SecretSalvage.java index 04707c8c43..50495f98a5 100644 --- a/Mage.Sets/src/mage/cards/s/SecretSalvage.java +++ b/Mage.Sets/src/mage/cards/s/SecretSalvage.java @@ -76,7 +76,7 @@ class SecretSalvageEffect extends OneShotEffect { String nameToSearch = targetCard.isSplitCard() ? ((SplitCard) targetCard).getLeftHalfCard().getName() : targetCard.getName(); nameFilter.add(new NamePredicate(nameToSearch)); TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, nameFilter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java b/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java index 03e1500255..705800cd94 100644 --- a/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java +++ b/Mage.Sets/src/mage/cards/s/SecretsOfTheGoldenCity.java @@ -1,17 +1,17 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.keyword.AscendEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SecretsOfTheGoldenCity extends CardImpl { @@ -28,6 +28,7 @@ public final class SecretsOfTheGoldenCity extends CardImpl { new DrawCardSourceControllerEffect(2), CitysBlessingCondition.instance, "Draw two cards. If you have the city's blessing, draw three cards instead")); + this.getSpellAbility().addHint(CitysBlessingHint.instance); } public SecretsOfTheGoldenCity(final SecretsOfTheGoldenCity card) { diff --git a/Mage.Sets/src/mage/cards/s/SecureTheWastes.java b/Mage.Sets/src/mage/cards/s/SecureTheWastes.java index 8d8e83e675..2540f72bbe 100644 --- a/Mage.Sets/src/mage/cards/s/SecureTheWastes.java +++ b/Mage.Sets/src/mage/cards/s/SecureTheWastes.java @@ -19,7 +19,7 @@ public final class SecureTheWastes extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}"); // create X 1/1 white Warrior creature tokens. - this.getSpellAbility().addEffect(new CreateTokenEffect(new WarriorToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new WarriorToken(), ManacostVariableValue.instance)); } public SecureTheWastes(final SecureTheWastes card) { diff --git a/Mage.Sets/src/mage/cards/s/SeeBeyond.java b/Mage.Sets/src/mage/cards/s/SeeBeyond.java index 45be2d1d1d..74728b840c 100644 --- a/Mage.Sets/src/mage/cards/s/SeeBeyond.java +++ b/Mage.Sets/src/mage/cards/s/SeeBeyond.java @@ -52,17 +52,19 @@ class SeeBeyondEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - controller.drawCards(2, game); - if (!controller.getHand().isEmpty()) { - TargetCard target = new TargetCard(Zone.HAND, new FilterCard("card to shuffle into your library")); - controller.choose(Outcome.Detriment, controller.getHand(), target, game); - Card card = controller.getHand().get(target.getFirstTarget(), game); - if (card != null) { - controller.moveCards(card, Zone.LIBRARY, source, game); - controller.shuffleLibrary(source, game); - } - return true; + if(controller != null) { + controller.drawCards(2, game); + if (!controller.getHand().isEmpty()) { + TargetCard target = new TargetCard(Zone.HAND, new FilterCard("card to shuffle into your library")); + controller.choose(Outcome.Detriment, controller.getHand(), target, game); + Card card = controller.getHand().get(target.getFirstTarget(), game); + if (card != null) { + controller.moveCards(card, Zone.LIBRARY, source, game); + controller.shuffleLibrary(source, game); + } + return true; + } } return true; } diff --git a/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java b/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java index a56e262ad4..5b993df82d 100644 --- a/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java +++ b/Mage.Sets/src/mage/cards/s/SeeTheUnwritten.java @@ -1,12 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; @@ -19,8 +18,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SeeTheUnwritten extends CardImpl { @@ -35,7 +35,8 @@ public final class SeeTheUnwritten extends CardImpl { new SeeTheUnwrittenEffect(2), new InvertCondition(FerociousCondition.instance), "Reveal the top eight cards of your library. You may put a creature card from among them onto the battlefield. Put the rest into your graveyard." - + "
    Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one")); + + "
    Ferocious — If you control a creature with power 4 or greater, you may put two creature cards onto the battlefield instead of one")); + this.getSpellAbility().addHint(FerociousHint.instance); } public SeeTheUnwritten(final SeeTheUnwritten card) { diff --git a/Mage.Sets/src/mage/cards/s/SeedlingCharm.java b/Mage.Sets/src/mage/cards/s/SeedlingCharm.java index 7b1c9ab29c..0490c56ab5 100644 --- a/Mage.Sets/src/mage/cards/s/SeedlingCharm.java +++ b/Mage.Sets/src/mage/cards/s/SeedlingCharm.java @@ -44,13 +44,13 @@ public final class SeedlingCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetPermanent(filter1)); // or regenerate target green creature Mode mode = new Mode(); - mode.getEffects().add(new RegenerateTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter2)); + mode.addEffect(new RegenerateTargetEffect()); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().addMode(mode); // or target creature gains trample until end of turn. mode = new Mode(); - mode.getEffects().add(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SeedsOfInnocence.java b/Mage.Sets/src/mage/cards/s/SeedsOfInnocence.java index 4c704e23e4..d5eb50421e 100644 --- a/Mage.Sets/src/mage/cards/s/SeedsOfInnocence.java +++ b/Mage.Sets/src/mage/cards/s/SeedsOfInnocence.java @@ -61,7 +61,9 @@ class SeedsOfInnocenceEffect extends OneShotEffect { Player artifactController = game.getPlayer(artifact.getControllerId()); int cmc = artifact.getConvertedManaCost(); if (artifact.destroy(source.getSourceId(), game, true)) { - artifactController.gainLife(cmc, game, source); + if(artifactController != null) { + artifactController.gainLife(cmc, game, source); + } } } return true; diff --git a/Mage.Sets/src/mage/cards/s/Seedtime.java b/Mage.Sets/src/mage/cards/s/Seedtime.java index dd90232dcf..efa5e33ce8 100644 --- a/Mage.Sets/src/mage/cards/s/Seedtime.java +++ b/Mage.Sets/src/mage/cards/s/Seedtime.java @@ -22,8 +22,8 @@ import mage.watchers.common.SpellsCastWatcher; */ public final class Seedtime extends CardImpl { - private final static String rule = "Cast this spell only during your turn."; - private final static String rule2 = "Take an extra turn after this one if an opponent cast a blue spell this turn."; + private static final String rule = "Cast this spell only during your turn."; + private static final String rule2 = "Take an extra turn after this one if an opponent cast a blue spell this turn."; public Seedtime(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); @@ -53,7 +53,7 @@ enum OpponentCastBlueSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { if (opponentId != null) { diff --git a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java index 9e1b83cbdd..172b7a1c2b 100644 --- a/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java +++ b/Mage.Sets/src/mage/cards/s/SeekerOfInsight.java @@ -56,7 +56,7 @@ class CastNonCreatureSpellCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spellsCast = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spellsCast != null) { diff --git a/Mage.Sets/src/mage/cards/s/SekKuarDeathkeeper.java b/Mage.Sets/src/mage/cards/s/SekKuarDeathkeeper.java index a1668e7278..202bb00e80 100644 --- a/Mage.Sets/src/mage/cards/s/SekKuarDeathkeeper.java +++ b/Mage.Sets/src/mage/cards/s/SekKuarDeathkeeper.java @@ -28,8 +28,8 @@ public final class SekKuarDeathkeeper extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public SekKuarDeathkeeper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SelectForInspection.java b/Mage.Sets/src/mage/cards/s/SelectForInspection.java index b6dd0d2991..ebb2a82019 100644 --- a/Mage.Sets/src/mage/cards/s/SelectForInspection.java +++ b/Mage.Sets/src/mage/cards/s/SelectForInspection.java @@ -20,7 +20,7 @@ public final class SelectForInspection extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SelectForInspection(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SelectiveMemory.java b/Mage.Sets/src/mage/cards/s/SelectiveMemory.java index cd753fec8b..83966eb414 100644 --- a/Mage.Sets/src/mage/cards/s/SelectiveMemory.java +++ b/Mage.Sets/src/mage/cards/s/SelectiveMemory.java @@ -59,7 +59,7 @@ class SelectiveMemoryEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, Integer.MAX_VALUE, new FilterNonlandCard()); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { for (UUID targetId : target.getTargets()) { Card card = player.getLibrary().remove(targetId, game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java index 62c2d93864..9e983af1c3 100644 --- a/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java +++ b/Mage.Sets/src/mage/cards/s/SelesnyaCharm.java @@ -46,13 +46,13 @@ public final class SelesnyaCharm extends CardImpl { // or exile target creature with power 5 or greater; Mode mode = new Mode(); - mode.getEffects().add(new ExileTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new ExileTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); // or create a 2/2 white Knight creature token with vigilance. mode = new Mode(); - mode.getEffects().add(new CreateTokenEffect(new KnightToken())); + mode.addEffect(new CreateTokenEffect(new KnightToken())); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java b/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java index a2a95ba492..9b5a523281 100644 --- a/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java +++ b/Mage.Sets/src/mage/cards/s/SelesnyaEvangel.java @@ -29,7 +29,7 @@ public final class SelesnyaEvangel extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SelesnyaEvangel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java b/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java index 5cec078a86..bc52232f2c 100644 --- a/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java +++ b/Mage.Sets/src/mage/cards/s/SelkieHedgeMage.java @@ -32,7 +32,7 @@ public final class SelkieHedgeMage extends CardImpl { static { filter.add(new SubtypePredicate(SubType.FOREST)); filter2.add(new SubtypePredicate(SubType.ISLAND)); - filter3.add(new TappedPredicate()); + filter3.add(TappedPredicate.instance); } private static final String rule1 = "When {this} enters the battlefield, if you control two or more Forests, you may gain 3 life."; diff --git a/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java b/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java index 34e2daf97d..3516ba3642 100644 --- a/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/s/SelvalaHeartOfTheWilds.java @@ -35,7 +35,7 @@ public final class SelvalaHeartOfTheWilds extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Whenever another creature enters the battlefield, its controller may draw a card if its power is greater than each other creature's power."; @@ -54,7 +54,7 @@ public final class SelvalaHeartOfTheWilds extends CardImpl { // {G}, {T}: Add X mana in any combination of colors, where X is the greatest power among creatures you control. ManaEffect manaEffect = new AddManaInAnyCombinationEffect( - new GreatestPowerAmongControlledCreaturesValue(), rule2, + GreatestPowerAmongControlledCreaturesValue.instance, rule2, ColoredManaSymbol.B, ColoredManaSymbol.U, ColoredManaSymbol.R, ColoredManaSymbol.W, ColoredManaSymbol.G); Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, manaEffect, new ManaCostsImpl("{G}")); ability.addCost(new TapSourceCost()); @@ -133,31 +133,4 @@ class GreatestPowerPredicate implements Predicate { public String toString() { return "Greatest Power"; } -} - -class GreatestPowerYouControlValue implements DynamicValue { - - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - Player player = game.getPlayer(sourceAbility.getControllerId()); - int amount = 0; - if (player != null) { - for (Permanent permanent : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)) { - if (permanent.getPower().getValue() > amount) { - amount = permanent.getPower().getValue(); - } - } - } - return amount; - } - - @Override - public DynamicValue copy() { - return new GreatestPowerYouControlValue(); - } - - @Override - public String getMessage() { - return "Add X mana in any combination of colors, where X is the greatest power among creatures you control."; - } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SemblanceAnvil.java b/Mage.Sets/src/mage/cards/s/SemblanceAnvil.java index 34372611f2..dba8d34db8 100644 --- a/Mage.Sets/src/mage/cards/s/SemblanceAnvil.java +++ b/Mage.Sets/src/mage/cards/s/SemblanceAnvil.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -21,6 +18,9 @@ import mage.players.Player; import mage.target.TargetCard; import mage.util.CardUtil; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -62,7 +62,7 @@ class SemblanceAnvilEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (!player.getHand().isEmpty()) { + if (player != null && !player.getHand().isEmpty()) { TargetCard target = new TargetCard(Zone.HAND, filter); player.choose(Outcome.Benefit, player.getHand(), target, game); Card card = player.getHand().get(target.getFirstTarget(), game); @@ -113,11 +113,9 @@ class SemblanceAnvilCostReductionEffect extends CostModificationEffectImpl { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { List imprinted = permanent.getImprinted(); - if (!imprinted.isEmpty()) { + if (imprinted != null && !imprinted.isEmpty()) { Card imprintedCard = game.getCard(imprinted.get(0)); - if (imprintedCard != null && imprintedCard.shareTypes(sourceCard)) { - return true; - } + return imprintedCard != null && imprintedCard.shareTypes(sourceCard); } } } diff --git a/Mage.Sets/src/mage/cards/s/SenateCourier.java b/Mage.Sets/src/mage/cards/s/SenateCourier.java new file mode 100644 index 0000000000..b016c0c4bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SenateCourier.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +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 SenateCourier extends CardImpl { + + public SenateCourier(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}{W}: Senate Courier gains vigilance until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl("{1}{W}"))); + } + + private SenateCourier(final SenateCourier card) { + super(card); + } + + @Override + public SenateCourier copy() { + return new SenateCourier(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SenateGriffin.java b/Mage.Sets/src/mage/cards/s/SenateGriffin.java new file mode 100644 index 0000000000..d85c995f77 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SenateGriffin.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.FlyingAbility; +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 SenateGriffin extends CardImpl { + + public SenateGriffin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W/U}{W/U}"); + + this.subtype.add(SubType.GRIFFIN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Senate Griffin enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + } + + private SenateGriffin(final SenateGriffin card) { + super(card); + } + + @Override + public SenateGriffin copy() { + return new SenateGriffin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SenateGuildmage.java b/Mage.Sets/src/mage/cards/s/SenateGuildmage.java new file mode 100644 index 0000000000..d70f55d3dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SenateGuildmage.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawDiscardControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class SenateGuildmage extends CardImpl { + + public SenateGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{U}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {W}, {T}: You gain 2 life. + Ability ability1 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(2), new ManaCostsImpl<>("{W}")); + ability1.addCost(new TapSourceCost()); + this.addAbility(ability1); + + // {U}, {T}: Draw a card, then discard a card. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawDiscardControllerEffect(), new ManaCostsImpl("{U}")); + ability2.addCost(new TapSourceCost()); + this.addAbility(ability2); + } + + public SenateGuildmage(final SenateGuildmage card) { + super(card); + } + + @Override + public SenateGuildmage copy() { + return new SenateGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SengirAutocrat.java b/Mage.Sets/src/mage/cards/s/SengirAutocrat.java index ccfa468fd3..4355da9a6e 100644 --- a/Mage.Sets/src/mage/cards/s/SengirAutocrat.java +++ b/Mage.Sets/src/mage/cards/s/SengirAutocrat.java @@ -27,7 +27,7 @@ public final class SengirAutocrat extends CardImpl { static { filter.add(new SubtypePredicate(SubType.SERF)); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public SengirAutocrat(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SentinelOfTheEternalWatch.java b/Mage.Sets/src/mage/cards/s/SentinelOfTheEternalWatch.java index 04acffd490..e3f64e774f 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelOfTheEternalWatch.java +++ b/Mage.Sets/src/mage/cards/s/SentinelOfTheEternalWatch.java @@ -1,11 +1,9 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfCombatTriggeredAbility; -import mage.abilities.effects.Effect; import mage.abilities.effects.common.TapTargetEffect; import mage.abilities.keyword.VigilanceAbility; import mage.cards.CardImpl; @@ -14,24 +12,26 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerIdPredicate; -import mage.game.Game; -import mage.players.Player; -import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; -import mage.target.targetpointer.FirstTargetPointer; +import mage.filter.predicate.permanent.ControllerIsActivePlayerPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SentinelOfTheEternalWatch extends CardImpl { - private final UUID originalId; + private static final FilterPermanent filter = new FilterCreaturePermanent("creature controlled by the active player"); + + static { + filter.add(new ControllerIsActivePlayerPredicate()); + } public SentinelOfTheEternalWatch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); this.subtype.add(SubType.GIANT); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(4); @@ -39,38 +39,22 @@ public final class SentinelOfTheEternalWatch extends CardImpl { // Vigilance this.addAbility(VigilanceAbility.getInstance()); - // At the beginning of combat on each opponent's turn, tap target creature that player controls. - Ability ability = new BeginningOfCombatTriggeredAbility(Zone.BATTLEFIELD, new TapTargetEffect("target creature that player controls"), TargetController.OPPONENT, false, true); - originalId = ability.getOriginalId(); - this.addAbility(ability); + // At the beginning of combat on each opponent's turn, tap target creature that player controls. + Ability ability = new BeginningOfCombatTriggeredAbility( + Zone.BATTLEFIELD, new TapTargetEffect("target creature that player controls"), + TargetController.OPPONENT, false, false + ); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); } public SentinelOfTheEternalWatch(final SentinelOfTheEternalWatch card) { super(card); - this.originalId = card.originalId; } @Override public SentinelOfTheEternalWatch copy() { return new SentinelOfTheEternalWatch(this); } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - for (Effect effect : ability.getEffects()) { - UUID opponentId = effect.getTargetPointer().getFirst(game, ability); - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - effect.setTargetPointer(new FirstTargetPointer()); - FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature from the active opponent"); - filter.add(new ControllerIdPredicate(opponentId)); - Target target = new TargetCreaturePermanent(filter); - ability.addTarget(target); - } - } - } - } - -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java b/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java index 8d433e8853..97a6036248 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java +++ b/Mage.Sets/src/mage/cards/s/SentinelOfThePearlTrident.java @@ -30,10 +30,10 @@ import mage.target.targetpointer.FixedTarget; */ public final class SentinelOfThePearlTrident extends CardImpl { - private final static FilterControlledPermanent filter = new FilterControlledPermanent("historic permanent you control"); + private static final FilterControlledPermanent filter = new FilterControlledPermanent("historic permanent you control"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public SentinelOfThePearlTrident(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SentinelTower.java b/Mage.Sets/src/mage/cards/s/SentinelTower.java index 9988c741cc..7b0f0667b1 100644 --- a/Mage.Sets/src/mage/cards/s/SentinelTower.java +++ b/Mage.Sets/src/mage/cards/s/SentinelTower.java @@ -1,9 +1,5 @@ - package mage.cards.s; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.common.SpellCastAllTriggeredAbility; @@ -20,8 +16,11 @@ import mage.game.events.GameEvent; import mage.target.common.TargetAnyTarget; import mage.watchers.Watcher; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SentinelTower extends CardImpl { @@ -46,7 +45,7 @@ public final class SentinelTower extends CardImpl { class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { SentinelTowerTriggeredAbility() { - super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false); + super(new DamageTargetEffect(0), StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false); this.addTarget(new TargetAnyTarget()); } @@ -63,7 +62,7 @@ class SentinelTowerTriggeredAbility extends SpellCastAllTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (game.isActivePlayer(getControllerId()) && super.checkTrigger(event, game)) { - SentinelTowerWatcher watcher = (SentinelTowerWatcher) game.getState().getWatchers().get(SentinelTowerWatcher.class.getSimpleName()); + SentinelTowerWatcher watcher = game.getState().getWatcher(SentinelTowerWatcher.class); if (watcher == null) { return false; } @@ -102,7 +101,7 @@ class SentinelTowerWatcher extends Watcher { private final List spellsThisTurn; SentinelTowerWatcher() { - super(SentinelTowerWatcher.class.getSimpleName(), WatcherScope.GAME); + super( WatcherScope.GAME); this.spellsThisTurn = new ArrayList<>(); } diff --git a/Mage.Sets/src/mage/cards/s/SentinelsMark.java b/Mage.Sets/src/mage/cards/s/SentinelsMark.java new file mode 100644 index 0000000000..d22a0487ad --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SentinelsMark.java @@ -0,0 +1,67 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +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.FlashAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.VigilanceAbility; +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 SentinelsMark extends CardImpl { + + public SentinelsMark(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); + + 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)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets +1/+2 and has vigilance. + ability = new SimpleStaticAbility(new BoostEnchantedEffect(1, 2)); + ability.addEffect(new GainAbilityAttachedEffect( + VigilanceAbility.getInstance(), AttachmentType.AURA + ).setText("and has vigilance")); + this.addAbility(ability); + + // Addendum — When Sentinel's Mark enters the battlefield, if you cast it during your main phase, enchanted creature gains lifelink until end of turn. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new GainAbilityAttachedEffect( + LifelinkAbility.getInstance(), AttachmentType.AURA, Duration.EndOfTurn + )), AddendumCondition.instance, "
    Addendum — When {this} enters the battlefield, " + + "if you cast it during your main phase, enchanted creature gains lifelink until end of turn." + )); + } + + private SentinelsMark(final SentinelsMark card) { + super(card); + } + + @Override + public SentinelsMark copy() { + return new SentinelsMark(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java b/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java index b0073013b9..614a0252bc 100644 --- a/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java +++ b/Mage.Sets/src/mage/cards/s/SepulchralPrimordial.java @@ -1,9 +1,6 @@ package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -13,8 +10,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; @@ -23,9 +20,13 @@ import mage.game.Game; import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInOpponentsGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; /** - * * @author LevelX2 */ public final class SepulchralPrimordial extends CardImpl { @@ -37,28 +38,14 @@ public final class SepulchralPrimordial extends CardImpl { this.power = new MageInt(5); this.toughness = new MageInt(4); - //Vigilance + // Intimidate this.addAbility(IntimidateAbility.getInstance()); // When Sepulchral Primordial enters the battlefield, for each opponent, you may put up to one // target creature card from that player's graveyard onto the battlefield under your control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SepulchralPrimordialEffect(), false)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for (UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterCard filter = new FilterCreatureCard("creature card from " + opponent.getName() + "'s graveyard"); - filter.add(new OwnerIdPredicate(opponentId)); - TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(0, 1, filter); - ability.addTarget(target); - } - } - } + Ability ability = new EntersBattlefieldTriggeredAbility(new SepulchralPrimordialEffect(), false); + ability.setTargetAdjuster(SepulchralPrimordialAdjuster.instance); + this.addAbility(ability); } public SepulchralPrimordial(final SepulchralPrimordial card) { @@ -71,6 +58,24 @@ public final class SepulchralPrimordial extends CardImpl { } } +enum SepulchralPrimordialAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterCard filter = new FilterCreatureCard("creature card from " + opponent.getName() + "'s graveyard"); + filter.add(new OwnerIdPredicate(opponentId)); + TargetCardInOpponentsGraveyard target = new TargetCardInOpponentsGraveyard(0, 1, filter); + ability.addTarget(target); + } + } + } +} + class SepulchralPrimordialEffect extends OneShotEffect { public SepulchralPrimordialEffect() { diff --git a/Mage.Sets/src/mage/cards/s/Seraph.java b/Mage.Sets/src/mage/cards/s/Seraph.java new file mode 100644 index 0000000000..b656237d5d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Seraph.java @@ -0,0 +1,140 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.DealtDamageAndDiedTriggeredAbility; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.constants.SubType; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.players.Player; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author jeffwadsworth + */ +public final class Seraph extends CardImpl { + + public Seraph(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever a creature dealt damage by Seraph this turn dies, put that card onto the battlefield under your control at the beginning of the next end step. Sacrifice the creature when you lose control of Seraph. + Effect effect = new CreateDelayedTriggeredAbilityEffect( + new AtTheBeginOfNextEndStepDelayedTriggeredAbility( + new SeraphEffect())); + effect.setText("put that card onto the battlefield under your control at the beginning of the next end step. Sacrifice the creature when you lose control of {this}"); + this.addAbility(new DealtDamageAndDiedTriggeredAbility(effect)); + + } + + private Seraph(final Seraph card) { + super(card); + } + + @Override + public Seraph copy() { + return new Seraph(this); + } +} + +class SeraphEffect extends OneShotEffect { + + SeraphEffect() { + super(Outcome.Neutral); + staticText = "put that card onto the battlefield under your control. Sacrifice it when you lose control of {this}"; + } + + SeraphEffect(SeraphEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Card creatureCard = game.getCard(targetPointer.getFirst(game, source)); + if (controller != null + && creatureCard != null + && game.getState().getZone(creatureCard.getId()) == Zone.GRAVEYARD) { // must be still in the graveyard + controller.moveCards(creatureCard, Zone.BATTLEFIELD, source, game, false, false, false, null); + OneShotEffect effect = new SacrificeTargetEffect(); + effect.setText("Sacrifice this if Seraph leaves the battlefield or its current controller loses control of it."); + effect.setTargetPointer(new FixedTarget(creatureCard.getId())); + SeraphDelayedTriggeredAbility dTA = new SeraphDelayedTriggeredAbility(effect, source.getSourceId()); + game.addDelayedTriggeredAbility(dTA, source); + return true; + } + return false; + } + + @Override + public SeraphEffect copy() { + return new SeraphEffect(this); + } +} + +class SeraphDelayedTriggeredAbility extends DelayedTriggeredAbility { + + UUID seraph; + + SeraphDelayedTriggeredAbility(Effect effect, UUID seraph) { + super(effect, Duration.EndOfGame, true); + this.seraph = seraph; + } + + SeraphDelayedTriggeredAbility(SeraphDelayedTriggeredAbility ability) { + super(ability); + this.seraph = ability.seraph; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.LOST_CONTROL + || event.getType() == EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getType() == EventType.LOST_CONTROL + && event.getSourceId().equals(seraph)) { + return true; + } + if (event.getType() == EventType.ZONE_CHANGE + && event.getTargetId().equals(seraph)) { + return true; + } + return false; + } + + @Override + public SeraphDelayedTriggeredAbility copy() { + return new SeraphDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Control of Seraph was lost, sacrifice this."; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SeraphOfTheMasses.java b/Mage.Sets/src/mage/cards/s/SeraphOfTheMasses.java index ba526a9688..1aaa733038 100644 --- a/Mage.Sets/src/mage/cards/s/SeraphOfTheMasses.java +++ b/Mage.Sets/src/mage/cards/s/SeraphOfTheMasses.java @@ -1,31 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.ConvokeAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SeraphOfTheMasses extends CardImpl { - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); - public SeraphOfTheMasses(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{W}"); this.subtype.add(SubType.ANGEL); this.power = new MageInt(0); @@ -36,9 +33,8 @@ public final class SeraphOfTheMasses extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Seraph of the Masses's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.EndOfGame))); - - + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); } public SeraphOfTheMasses(final SeraphOfTheMasses card) { diff --git a/Mage.Sets/src/mage/cards/s/SeraphOfTheScales.java b/Mage.Sets/src/mage/cards/s/SeraphOfTheScales.java new file mode 100644 index 0000000000..d21c04c48f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SeraphOfTheScales.java @@ -0,0 +1,65 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.AfterlifeAbility; +import mage.abilities.keyword.DeathtouchAbility; +import mage.abilities.keyword.FlyingAbility; +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 mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SeraphOfTheScales extends CardImpl { + + public SeraphOfTheScales(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {W}: Seraph of the Scales gains vigilance until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect( + VigilanceAbility.getInstance(), + Duration.EndOfTurn + ), new ManaCostsImpl("{W}") + )); + + // {B}: Seraph of the Scales gains deathtouch until end of turn. + this.addAbility(new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), + Duration.EndOfTurn + ), new ManaCostsImpl("{B}") + )); + + // Afterlife 2 + this.addAbility(new AfterlifeAbility(2)); + } + + private SeraphOfTheScales(final SeraphOfTheScales card) { + super(card); + } + + @Override + public SeraphOfTheScales copy() { + return new SeraphOfTheScales(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java b/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java index b0ff816b46..2b1808a1f9 100644 --- a/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java +++ b/Mage.Sets/src/mage/cards/s/SerendibSorcerer.java @@ -26,7 +26,7 @@ public final class SerendibSorcerer extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than {this}"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SerendibSorcerer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SereneOffering.java b/Mage.Sets/src/mage/cards/s/SereneOffering.java index b8a0060a5a..09a48a3deb 100644 --- a/Mage.Sets/src/mage/cards/s/SereneOffering.java +++ b/Mage.Sets/src/mage/cards/s/SereneOffering.java @@ -22,7 +22,7 @@ public final class SereneOffering extends CardImpl { // Destroy target enchantment. You gain life equal to its converted mana cost. this.getSpellAbility().addEffect(new DestroyTargetEffect()); - Effect effect = new GainLifeEffect(new TargetConvertedManaCost()); + Effect effect = new GainLifeEffect(TargetConvertedManaCost.instance); effect.setText("You gain life equal to its converted mana cost"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetEnchantmentPermanent()); diff --git a/Mage.Sets/src/mage/cards/s/SereneRemembrance.java b/Mage.Sets/src/mage/cards/s/SereneRemembrance.java index 15c9014ab8..b805b2f3b5 100644 --- a/Mage.Sets/src/mage/cards/s/SereneRemembrance.java +++ b/Mage.Sets/src/mage/cards/s/SereneRemembrance.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; @@ -15,20 +13,21 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInASingleGraveyard; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SereneRemembrance extends CardImpl { - public SereneRemembrance (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); + public SereneRemembrance(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Shuffle Serene Remembrance and up to three target cards from a single graveyard into their owners' libraries. this.getSpellAbility().addEffect(new SereneRemembranceEffect()); - this.getSpellAbility().addTarget(new TargetCardInASingleGraveyard(0,3,new FilterCard("up to three target cards from a single graveyard"))); - + this.getSpellAbility().addTarget(new TargetCardInASingleGraveyard(0, 3, new FilterCard("up to three target cards from a single graveyard"))); + } public SereneRemembrance(final SereneRemembrance card) { @@ -36,30 +35,32 @@ public final class SereneRemembrance extends CardImpl { } @Override - public SereneRemembrance copy() { + public SereneRemembrance copy() { return new SereneRemembrance(this); } } class SereneRemembranceEffect extends OneShotEffect { - + public SereneRemembranceEffect() { super(Outcome.Benefit); this.staticText = "Shuffle Serene Remembrance and up to three target cards from a single graveyard into their owners' libraries"; } - + public SereneRemembranceEffect(final SereneRemembranceEffect effect) { super(effect); } - + @Override public SereneRemembranceEffect copy() { return new SereneRemembranceEffect(this); } - + @Override public boolean apply(Game game, Ability source) { boolean result = false; + + // 3 cards to graveyard Player graveyardPlayer = null; for (UUID cardInGraveyard : targetPointer.getTargets(game, source)) { Card card = game.getCard(cardInGraveyard); @@ -71,17 +72,22 @@ class SereneRemembranceEffect extends OneShotEffect { result |= card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); } } - } + } } + + // source card to graveyard Card card = game.getCard(source.getSourceId()); - result |= card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); - Player player = game.getPlayer(card.getOwnerId()); - if (player != null){ - player.shuffleLibrary(source, game); - } - if (graveyardPlayer != null && !graveyardPlayer.equals(player)) { - graveyardPlayer.shuffleLibrary(source, game); + if (card != null) { + result |= card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, false); + Player player = game.getPlayer(card.getOwnerId()); + if (player != null) { + player.shuffleLibrary(source, game); + } + if (graveyardPlayer != null && !graveyardPlayer.equals(player)) { + graveyardPlayer.shuffleLibrary(source, game); + } } + return result; } } diff --git a/Mage.Sets/src/mage/cards/s/SerraAvatar.java b/Mage.Sets/src/mage/cards/s/SerraAvatar.java index 49680a7cc6..9fb4458a34 100644 --- a/Mage.Sets/src/mage/cards/s/SerraAvatar.java +++ b/Mage.Sets/src/mage/cards/s/SerraAvatar.java @@ -29,7 +29,7 @@ public final class SerraAvatar extends CardImpl { this.toughness = new MageInt(0); // Serra Avatar's power and toughness are each equal to your life total. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new ControllerLifeCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(ControllerLifeCount.instance, Duration.EndOfGame))); // When Serra Avatar is put into a graveyard from anywhere, shuffle it into its owner's library. this.addAbility(new PutIntoGraveFromAnywhereSourceTriggeredAbility(new ShuffleIntoLibrarySourceEffect())); diff --git a/Mage.Sets/src/mage/cards/s/SerraInquisitors.java b/Mage.Sets/src/mage/cards/s/SerraInquisitors.java index dacf3b265c..afb0119766 100644 --- a/Mage.Sets/src/mage/cards/s/SerraInquisitors.java +++ b/Mage.Sets/src/mage/cards/s/SerraInquisitors.java @@ -20,7 +20,7 @@ import java.util.UUID; */ public final class SerraInquisitors extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("black creatures"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("black creatures"); static { filter.add(new ColorPredicate(ObjectColor.BLACK)); diff --git a/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java b/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java new file mode 100644 index 0000000000..1620e1cb57 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SerraTheBenevolent.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GetEmblemEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.command.emblems.SerraTheBenevolentEmblem; +import mage.game.permanent.token.AngelVigilanceToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SerraTheBenevolent extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("Creatures you control with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public SerraTheBenevolent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SERRA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // +2: Creatures you control with flying get +1/+1 until end of turn. + this.addAbility(new LoyaltyAbility(new BoostControlledEffect(1, 1, Duration.EndOfTurn, filter), 2)); + + // -3: Create a 4/4 white Angel creature token with flying and vigilance. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new AngelVigilanceToken()), -3)); + + // -6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead." + this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new SerraTheBenevolentEmblem()), -6)); + } + + private SerraTheBenevolent(final SerraTheBenevolent card) { + super(card); + } + + @Override + public SerraTheBenevolent copy() { + return new SerraTheBenevolent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerrasHymn.java b/Mage.Sets/src/mage/cards/s/SerrasHymn.java new file mode 100644 index 0000000000..5d7b9be30b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SerrasHymn.java @@ -0,0 +1,55 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.PreventDamageToTargetMultiAmountEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetAnyTargetAmount; + +/** + * + * @author jeffwadsworth + */ +public final class SerrasHymn extends CardImpl { + + private static final String rule = "Prevent the next X damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose, where X is the number of verse counters on {this}."; + + public SerrasHymn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // At the beginning of your upkeep, you may put a verse counter on Serra's Hymn. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, + new AddCountersSourceEffect(CounterType.VERSE.createInstance(), true), TargetController.YOU, true)); + + // Sacrifice Serra's Hymn: Prevent the next X damage that would be dealt this turn to any number of target creatures and/or players, divided as you choose, where X is the number of verse counters on Serra's Hymn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + new PreventDamageToTargetMultiAmountEffect( + Duration.EndOfTurn, + 1, false, true, // the integer 1 is ignored due to the dynamic number being set + new CountersSourceCount(CounterType.VERSE)).setText(rule), + new SacrificeSourceCost()); + ability.addTarget(new TargetAnyTargetAmount(new CountersSourceCount(CounterType.VERSE))); + this.addAbility(ability); + + } + + public SerrasHymn(final SerrasHymn card) { + super(card); + } + + @Override + public SerrasHymn copy() { + return new SerrasHymn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SerumPowder.java b/Mage.Sets/src/mage/cards/s/SerumPowder.java index 955f9a5bf6..b30d9caf37 100644 --- a/Mage.Sets/src/mage/cards/s/SerumPowder.java +++ b/Mage.Sets/src/mage/cards/s/SerumPowder.java @@ -65,10 +65,7 @@ class SerumPowderReplaceEffect extends ReplacementEffectImpl { } int cardsHand = controller.getHand().size(); if (cardsHand > 0){ - Cards cards = new CardsImpl(); - for (UUID cardId: controller.getHand()) { - cards.add(game.getCard(cardId)); - } + Cards cards = new CardsImpl(controller.getHand()); for (Card card: cards.getCards(game)) { card.moveToExile(null, null, source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/cards/s/SetessanTactics.java b/Mage.Sets/src/mage/cards/s/SetessanTactics.java index 20cbc8d6bb..51e2b69656 100644 --- a/Mage.Sets/src/mage/cards/s/SetessanTactics.java +++ b/Mage.Sets/src/mage/cards/s/SetessanTactics.java @@ -28,7 +28,7 @@ public final class SetessanTactics extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SetessanTactics(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java b/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java index 560c551805..41fc8d67f0 100644 --- a/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java +++ b/Mage.Sets/src/mage/cards/s/SetonKrosanProtector.java @@ -24,10 +24,10 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public final class SetonKrosanProtector extends CardImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Druid you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Druid you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.DRUID)); } diff --git a/Mage.Sets/src/mage/cards/s/SettleTheWreckage.java b/Mage.Sets/src/mage/cards/s/SettleTheWreckage.java index 4a2a86accd..8156a6bc70 100644 --- a/Mage.Sets/src/mage/cards/s/SettleTheWreckage.java +++ b/Mage.Sets/src/mage/cards/s/SettleTheWreckage.java @@ -80,7 +80,7 @@ class SettleTheWreckageEffect extends OneShotEffect { } controller.moveCards(toExile, Zone.EXILED, source, game); TargetCardInLibrary target = new TargetCardInLibrary(0, attackers, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.chooseUse(Outcome.Benefit, "Search for up to " + attackers + " basic land" + ((attackers == 1) ? "" : "s") + "?", source, game) && player.searchLibrary(target, game)) { + if (player.chooseUse(Outcome.Benefit, "Search for up to " + attackers + " basic land" + ((attackers == 1) ? "" : "s") + "?", source, game) && player.searchLibrary(target, source, game)) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); player.shuffleLibrary(source, game); } diff --git a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java index 3cbbee01a8..dfde359a4f 100644 --- a/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java +++ b/Mage.Sets/src/mage/cards/s/SeverTheBloodline.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; @@ -19,15 +17,17 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author North */ public final class SeverTheBloodline extends CardImpl { public SeverTheBloodline(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}"); // Exile target creature and all other creatures with the same name as that creature. @@ -69,7 +69,7 @@ class SeverTheBloodlineEffect extends OneShotEffect { Permanent targetPermanent = game.getPermanent(targetPointer.getFirst(game, source)); if (controller != null && targetPermanent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); diff --git a/Mage.Sets/src/mage/cards/s/SeveredStrands.java b/Mage.Sets/src/mage/cards/s/SeveredStrands.java index a0e7278361..523aedf125 100644 --- a/Mage.Sets/src/mage/cards/s/SeveredStrands.java +++ b/Mage.Sets/src/mage/cards/s/SeveredStrands.java @@ -26,7 +26,7 @@ public final class SeveredStrands extends CardImpl { // You gain life equal to the sacrificed creature's toughness. Destroy target creature an opponent controls. this.getSpellAbility().addEffect(new GainLifeEffect( - new SacrificeCostCreaturesToughness(), + SacrificeCostCreaturesToughness.instance, "You gain life equal to the " + "sacrificed creature's toughness." )); diff --git a/Mage.Sets/src/mage/cards/s/ShaakHerd.java b/Mage.Sets/src/mage/cards/s/ShaakHerd.java index f4405e9621..96f3933057 100644 --- a/Mage.Sets/src/mage/cards/s/ShaakHerd.java +++ b/Mage.Sets/src/mage/cards/s/ShaakHerd.java @@ -20,7 +20,7 @@ import mage.target.common.TargetCardInYourGraveyard; */ public final class ShaakHerd extends CardImpl { - private final static FilterCard filter = new FilterCard("another target creature card"); + private static final FilterCard filter = new FilterCard("another target creature card"); static { filter.add(new AnotherCardPredicate()); diff --git a/Mage.Sets/src/mage/cards/s/ShadesBreath.java b/Mage.Sets/src/mage/cards/s/ShadesBreath.java index 92ad48f6b6..f1f8aa659e 100644 --- a/Mage.Sets/src/mage/cards/s/ShadesBreath.java +++ b/Mage.Sets/src/mage/cards/s/ShadesBreath.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,20 +9,16 @@ import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.SubTypeList; +import java.util.List; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class ShadesBreath extends CardImpl { @@ -102,7 +95,7 @@ class ShadesBreathSetSubtypeEffect extends ContinuousEffectImpl { if (permanent != null) { SubTypeList subtype = permanent.getSubtype(game); if (subtype != null && (subtype.size() != 1 || !subtype.contains(SubType.SHADE))) { - subtype.removeAll(SubType.getCreatureTypes(false)); + subtype.clear(); subtype.add(SubType.SHADE); } } diff --git a/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java b/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java index 7efd4395a8..99013be6f0 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java +++ b/Mage.Sets/src/mage/cards/s/ShadowAlleyDenizen.java @@ -29,7 +29,7 @@ public final class ShadowAlleyDenizen extends CardImpl { static { filter.add(new ColorPredicate(ObjectColor.BLACK)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ShadowAlleyDenizen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShadowOfTheGrave.java b/Mage.Sets/src/mage/cards/s/ShadowOfTheGrave.java index c85fcab35d..68795142d2 100644 --- a/Mage.Sets/src/mage/cards/s/ShadowOfTheGrave.java +++ b/Mage.Sets/src/mage/cards/s/ShadowOfTheGrave.java @@ -58,7 +58,7 @@ class ShadowOfTheGraveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - CardsCycledOrDiscardedThisTurnWatcher watcher = (CardsCycledOrDiscardedThisTurnWatcher) game.getState().getWatchers().get(CardsCycledOrDiscardedThisTurnWatcher.class.getSimpleName()); + CardsCycledOrDiscardedThisTurnWatcher watcher = game.getState().getWatcher(CardsCycledOrDiscardedThisTurnWatcher.class); if (controller != null && watcher != null) { for (Card card : watcher.getCardsCycledOrDiscardedThisTurn(controller.getId()).getCards(game)) { diff --git a/Mage.Sets/src/mage/cards/s/Shadowfeed.java b/Mage.Sets/src/mage/cards/s/Shadowfeed.java index 8e615530b7..bd0c8400ff 100644 --- a/Mage.Sets/src/mage/cards/s/Shadowfeed.java +++ b/Mage.Sets/src/mage/cards/s/Shadowfeed.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; @@ -9,19 +8,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** - * * @author North */ public final class Shadowfeed extends CardImpl { public Shadowfeed(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}"); // Exile target card from a graveyard. this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetCardInGraveyard()); + // You gain 3 life. this.getSpellAbility().addEffect(new GainLifeEffect(3)); } diff --git a/Mage.Sets/src/mage/cards/s/ShalaiVoiceOfPlenty.java b/Mage.Sets/src/mage/cards/s/ShalaiVoiceOfPlenty.java index 502e9a53ff..621daf3a92 100644 --- a/Mage.Sets/src/mage/cards/s/ShalaiVoiceOfPlenty.java +++ b/Mage.Sets/src/mage/cards/s/ShalaiVoiceOfPlenty.java @@ -65,7 +65,7 @@ public final class ShalaiVoiceOfPlenty extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersAllEffect( CounterType.P1P1.createInstance(), - new FilterControlledCreaturePermanent("creature you control") + StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED ), new ManaCostsImpl("{4}{G}{G}") )); diff --git a/Mage.Sets/src/mage/cards/s/ShaleskinBruiser.java b/Mage.Sets/src/mage/cards/s/ShaleskinBruiser.java index 1b093b930c..c666d6d3bf 100644 --- a/Mage.Sets/src/mage/cards/s/ShaleskinBruiser.java +++ b/Mage.Sets/src/mage/cards/s/ShaleskinBruiser.java @@ -27,7 +27,7 @@ public final class ShaleskinBruiser extends CardImpl { static { filter.add(new SubtypePredicate(SubType.BEAST)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } diff --git a/Mage.Sets/src/mage/cards/s/ShamanicRevelation.java b/Mage.Sets/src/mage/cards/s/ShamanicRevelation.java index 2b3916e3f6..2acd43e060 100644 --- a/Mage.Sets/src/mage/cards/s/ShamanicRevelation.java +++ b/Mage.Sets/src/mage/cards/s/ShamanicRevelation.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.effects.Effect; @@ -11,11 +9,13 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.ComparisonType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShamanicRevelation extends CardImpl { @@ -27,17 +27,16 @@ public final class ShamanicRevelation extends CardImpl { } public ShamanicRevelation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}{G}"); // Draw a card for each creature you control. - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()))); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE))); // Ferocious — You gain 4 life for each creature you control with power 4 or greater. DynamicValue amount = new PermanentsOnBattlefieldCount(filter, 4); Effect effect = new GainLifeEffect(amount); effect.setText("
    Ferocious — You gain 4 life for each creature you control with power 4 or greater."); this.getSpellAbility().addEffect(effect); - } public ShamanicRevelation(final ShamanicRevelation card) { diff --git a/Mage.Sets/src/mage/cards/s/ShannaSisaysLegacy.java b/Mage.Sets/src/mage/cards/s/ShannaSisaysLegacy.java index 6041c37855..51cb113f7b 100644 --- a/Mage.Sets/src/mage/cards/s/ShannaSisaysLegacy.java +++ b/Mage.Sets/src/mage/cards/s/ShannaSisaysLegacy.java @@ -101,7 +101,7 @@ class ShannaSisaysLegacyEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Card targetCard = game.getCard(event.getTargetId()); - StackObject stackObject = (StackObject) game.getStack().getStackObject(event.getSourceId()); + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); if (targetCard != null && stackObject != null && targetCard.getId().equals(source.getSourceId())) { if (stackObject instanceof Ability) { if (!stackObject.isControlledBy(source.getControllerId())) { diff --git a/Mage.Sets/src/mage/cards/s/ShapeAnew.java b/Mage.Sets/src/mage/cards/s/ShapeAnew.java index 63a7595fad..feaef70514 100644 --- a/Mage.Sets/src/mage/cards/s/ShapeAnew.java +++ b/Mage.Sets/src/mage/cards/s/ShapeAnew.java @@ -74,7 +74,7 @@ public final class ShapeAnew extends CardImpl { if (artifactCard != null) { targetController.moveCards(artifactCard, Zone.BATTLEFIELD, source, game); } - // 1/1/2011: If the first card the player reveals is an artifact card, he or she will still have to shuffle his or her library even though no other cards were revealed this way. + // 1/1/2011: If the first card the player reveals is an artifact card, he or she will still have to shuffle their library even though no other cards were revealed this way. targetController.shuffleLibrary(source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java b/Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java index 3e33b199b6..1d2774317e 100644 --- a/Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java +++ b/Mage.Sets/src/mage/cards/s/ShapeOfTheWiitigo.java @@ -70,7 +70,7 @@ class AttachedAttackedOrBlockedSinceYourLastUpkeepCondition implements Condition @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getBattlefield().getPermanent(source.getSourceId()); - AttackedOrBlockedSinceYourLastUpkeepWatcher watcher = (AttackedOrBlockedSinceYourLastUpkeepWatcher) game.getState().getWatchers().get(AttackedOrBlockedSinceYourLastUpkeepWatcher.class.getSimpleName()); + AttackedOrBlockedSinceYourLastUpkeepWatcher watcher = game.getState().getWatcher(AttackedOrBlockedSinceYourLastUpkeepWatcher.class); if (permanent != null && permanent.getAttachedTo() != null && watcher != null) { Permanent attachedTo = game.getBattlefield().getPermanent(permanent.getAttachedTo()); if (attachedTo == null) { @@ -95,7 +95,7 @@ class AttackedOrBlockedSinceYourLastUpkeepWatcher extends Watcher{ private final Map> attackedOrBlockedCreatures = new HashMap<>(); public AttackedOrBlockedSinceYourLastUpkeepWatcher() { - super(AttackedOrBlockedSinceYourLastUpkeepWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AttackedOrBlockedSinceYourLastUpkeepWatcher(AttackedOrBlockedSinceYourLastUpkeepWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/ShaperApprentice.java b/Mage.Sets/src/mage/cards/s/ShaperApprentice.java index 32fa83dc11..69e437c926 100644 --- a/Mage.Sets/src/mage/cards/s/ShaperApprentice.java +++ b/Mage.Sets/src/mage/cards/s/ShaperApprentice.java @@ -28,7 +28,7 @@ public final class ShaperApprentice extends CardImpl { static { filter.add(new SubtypePredicate(SubType.MERFOLK)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ShaperApprentice(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShardConvergence.java b/Mage.Sets/src/mage/cards/s/ShardConvergence.java index 704e64c710..b0ed89c4df 100644 --- a/Mage.Sets/src/mage/cards/s/ShardConvergence.java +++ b/Mage.Sets/src/mage/cards/s/ShardConvergence.java @@ -77,7 +77,7 @@ class ShardConvergenceEffect extends OneShotEffect { FilterLandCard filter = new FilterLandCard(subtype); filter.add(new SubtypePredicate(SubType.byDescription(subtype))); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { Card card = player.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { card.moveToZone(Zone.HAND, source.getSourceId(), game, false); diff --git a/Mage.Sets/src/mage/cards/s/SharedAnimosity.java b/Mage.Sets/src/mage/cards/s/SharedAnimosity.java index a51cea36fb..5cc7288616 100644 --- a/Mage.Sets/src/mage/cards/s/SharedAnimosity.java +++ b/Mage.Sets/src/mage/cards/s/SharedAnimosity.java @@ -73,7 +73,7 @@ class SharedAnimosityEffect extends ContinuousEffectImpl { FilterCreaturePermanent filter = new FilterCreaturePermanent(); filter.add(Predicates.not(new PermanentIdPredicate(this.targetPointer.getFirst(game, source)))); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); boolean allCreatureTypes = false; if (permanent.isAllCreatureTypes()) { allCreatureTypes = true; @@ -98,7 +98,7 @@ class SharedAnimosityEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent target = (Permanent) game.getPermanent(this.targetPointer.getFirst(game, source)); + Permanent target = game.getPermanent(this.targetPointer.getFirst(game, source)); if (target != null) { target.addPower(power); return true; diff --git a/Mage.Sets/src/mage/cards/s/SharedDiscovery.java b/Mage.Sets/src/mage/cards/s/SharedDiscovery.java index ec2df78cad..5f79ba960e 100644 --- a/Mage.Sets/src/mage/cards/s/SharedDiscovery.java +++ b/Mage.Sets/src/mage/cards/s/SharedDiscovery.java @@ -21,7 +21,7 @@ public final class SharedDiscovery extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SharedDiscovery(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SharedFate.java b/Mage.Sets/src/mage/cards/s/SharedFate.java index 6f581fac8f..af6e235b33 100644 --- a/Mage.Sets/src/mage/cards/s/SharedFate.java +++ b/Mage.Sets/src/mage/cards/s/SharedFate.java @@ -133,7 +133,7 @@ class SharedFatePlayEffect extends AsThoughEffectImpl { if (exileId != null) { ExileZone exileZone = game.getExile().getExileZone(exileId); if (exileZone != null && exileZone.contains(objectId)) { - if (player.chooseUse(outcome, "Play " + game.getCard(objectId).getIdName() + '?', source, game)) { + if (player != null && player.chooseUse(outcome, "Play " + game.getCard(objectId).getIdName() + '?', source, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SharedTrauma.java b/Mage.Sets/src/mage/cards/s/SharedTrauma.java index b8b9eb8e53..b20a0a7bc1 100644 --- a/Mage.Sets/src/mage/cards/s/SharedTrauma.java +++ b/Mage.Sets/src/mage/cards/s/SharedTrauma.java @@ -99,7 +99,7 @@ class SharedTraumaEffect extends OneShotEffect { payed = true; } } - game.informPlayers(new StringBuilder(player.getLogName()).append(" pays {").append(xValue).append("}.").toString()); + game.informPlayers(player.getLogName() + " pays {" + xValue + "}."); return xValue; } } diff --git a/Mage.Sets/src/mage/cards/s/Sharktocrab.java b/Mage.Sets/src/mage/cards/s/Sharktocrab.java new file mode 100644 index 0000000000..64c91d73a1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Sharktocrab.java @@ -0,0 +1,49 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.OneOrMoreCountersAddedTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.AdaptAbility; +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 Sharktocrab extends CardImpl { + + public Sharktocrab(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + + this.subtype.add(SubType.FISH); + this.subtype.add(SubType.OCTOPUS); + this.subtype.add(SubType.CRAB); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // {2}{G}{U}: Adapt 1. + this.addAbility(new AdaptAbility(1, "{2}{G}{U}")); + + // Whenever one or more +1/+1 counter are put on Sharktocrab, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step. + Ability ability = new OneOrMoreCountersAddedTriggeredAbility(new TapTargetEffect()); + ability.addEffect(new DontUntapInControllersNextUntapStepTargetEffect("That creature")); + ability.addTarget(new TargetOpponentsCreaturePermanent()); + this.addAbility(ability); + } + + private Sharktocrab(final Sharktocrab card) { + super(card); + } + + @Override + public Sharktocrab copy() { + return new Sharktocrab(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShatteredCrypt.java b/Mage.Sets/src/mage/cards/s/ShatteredCrypt.java index a2c22cc7bf..7ce9d8e152 100644 --- a/Mage.Sets/src/mage/cards/s/ShatteredCrypt.java +++ b/Mage.Sets/src/mage/cards/s/ShatteredCrypt.java @@ -1,9 +1,7 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; @@ -15,9 +13,11 @@ import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.target.Target; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class ShatteredCrypt extends CardImpl { @@ -29,18 +29,8 @@ public final class ShatteredCrypt extends CardImpl { Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target creature cards from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(new ManacostVariableValue())); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(1, new FilterCreatureCard())); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard(new StringBuilder(xValue).append(xValue != 1 ? " creature cards" : "creature card").append(" from your graveyard").toString())); - ability.addTarget(target); - } + this.getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(ManacostVariableValue.instance)); + this.getSpellAbility().setTargetAdjuster(ShatteredCryptAdjuster.instance); } public ShatteredCrypt(final ShatteredCrypt card) { @@ -52,3 +42,15 @@ public final class ShatteredCrypt extends CardImpl { return new ShatteredCrypt(this); } } + +enum ShatteredCryptAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + Target target = new TargetCardInYourGraveyard(xValue, new FilterCreatureCard((xValue != 1 ? " creature cards" : "creature card") + " from your graveyard")); + ability.addTarget(target); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java b/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java index 73ea093e0d..2db55d0a3c 100644 --- a/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java +++ b/Mage.Sets/src/mage/cards/s/ShattergangBrothers.java @@ -75,7 +75,7 @@ class ShattergangBrothersEffect extends OneShotEffect { public ShattergangBrothersEffect(FilterControlledPermanent filter) { super(Outcome.Sacrifice); this.filter = filter; - this.staticText = new StringBuilder("Each other player sacrifices ").append(filter.getMessage()).toString(); + this.staticText = "Each other player sacrifices " + filter.getMessage(); } public ShattergangBrothersEffect(final ShattergangBrothersEffect effect) { diff --git a/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java b/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java index 7ed79f033b..1b4c1e9e29 100644 --- a/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java +++ b/Mage.Sets/src/mage/cards/s/ShaukuEndbringer.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -15,42 +13,36 @@ 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.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; -import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Saga */ -public final class ShaukuEndbringer extends CardImpl{ - - public ShaukuEndbringer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}{B}"); +public final class ShaukuEndbringer extends CardImpl { + + public ShaukuEndbringer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}{B}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.VAMPIRE); this.power = new MageInt(5); this.toughness = new MageInt(5); - + this.addAbility(FlyingAbility.getInstance()); - + // Shauku, Endbringer can't attack if there's another creature on the battlefield. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShaukuEndbringerEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShaukuEndbringerEffect())); // At the beginning of your upkeep, you lose 3 life. this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LoseLifeSourceControllerEffect(3), TargetController.YOU, false)); - + // {T}: Exile target creature and put a +1/+1 counter on Shauku. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), new TapSourceCost()); ability.addEffect(new AddCountersSourceEffect(CounterType.P1P1.createInstance())); @@ -68,13 +60,14 @@ public final class ShaukuEndbringer extends CardImpl{ } } - class ShaukuEndbringerEffect extends RestrictionEffect { - +class ShaukuEndbringerEffect extends RestrictionEffect { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } - + public ShaukuEndbringerEffect() { super(Duration.WhileOnBattlefield); staticText = "{this} can't attack if there's another creature on the battlefield."; @@ -90,13 +83,13 @@ public final class ShaukuEndbringer extends CardImpl{ } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean applies(Permanent permanent, Ability source, Game game) { - return permanent.getId().equals(source.getSourceId()) && + public boolean applies(Permanent permanent, Ability source, Game game) { + return permanent.getId().equals(source.getSourceId()) && game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) > 0; } } diff --git a/Mage.Sets/src/mage/cards/s/SheerDrop.java b/Mage.Sets/src/mage/cards/s/SheerDrop.java index b0b89c1a29..2e4abc4c43 100644 --- a/Mage.Sets/src/mage/cards/s/SheerDrop.java +++ b/Mage.Sets/src/mage/cards/s/SheerDrop.java @@ -17,10 +17,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class SheerDrop extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SheerDrop(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java b/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java new file mode 100644 index 0000000000..0d5f206ecf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShelkinBrownie.java @@ -0,0 +1,45 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class ShelkinBrownie extends CardImpl { + + public ShelkinBrownie(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + this.subtype.add(SubType.OUPHE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {T}: Target creature loses all "bands with other" abilities until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LoseAbilityTargetEffect(new BandsWithOtherAbility(), Duration.EndOfTurn), new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public ShelkinBrownie(final ShelkinBrownie card) { + super(card); + } + + @Override + public ShelkinBrownie copy() { + return new ShelkinBrownie(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java b/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java new file mode 100644 index 0000000000..7526f97c07 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShelteringPrayers.java @@ -0,0 +1,98 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.keyword.ShroudAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.AbilityAddingRemovingEffects_6; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class ShelteringPrayers extends CardImpl { + + public ShelteringPrayers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + // Basic lands each player controls have shroud as long as that player controls three or fewer lands. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShelteringPrayersEffect())); + + } + + public ShelteringPrayers(final ShelteringPrayers card) { + super(card); + } + + @Override + public ShelteringPrayers copy() { + return new ShelteringPrayers(this); + } +} + +class ShelteringPrayersEffect extends ContinuousEffectImpl { + + public ShelteringPrayersEffect() { + super(Duration.WhileOnBattlefield, Outcome.AddAbility); + staticText = "Basic lands each player controls have shroud as long as that player controls three or fewer lands."; + dependencyTypes.add(DependencyType.AddingAbility); + + } + + public ShelteringPrayersEffect(final ShelteringPrayersEffect effect) { + super(effect); + } + + @Override + public ShelteringPrayersEffect copy() { + return new ShelteringPrayersEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null + && game.getBattlefield().getAllActivePermanents(new FilterLandPermanent(), playerId, game).size() < 4) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(new FilterLandPermanent(), playerId, game)) { + if (land != null + && land.isBasic()) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + land.getAbilities().add(ShroudAbility.getInstance()); + } + break; + } + } + } + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return Layer.AbilityAddingRemovingEffects_6 == layer; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java b/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java index a56fda7596..7439718122 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java +++ b/Mage.Sets/src/mage/cards/s/ShieldOfTheAvatar.java @@ -1,39 +1,35 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.EquipAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ShieldOfTheAvatar extends CardImpl { public ShieldOfTheAvatar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add(SubType.EQUIPMENT); // If a source would deal damage to equipped creature, prevent X of that damage, where X is the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShieldOfTheAvatarPreventionEffect())); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ShieldOfTheAvatarPreventionEffect()) + .addHint(CreaturesYouControlHint.instance)); + // Equip {2} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(2))); } @@ -49,9 +45,7 @@ public final class ShieldOfTheAvatar extends CardImpl { } class ShieldOfTheAvatarPreventionEffect extends PreventionEffectImpl { - - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); - + ShieldOfTheAvatarPreventionEffect() { super(Duration.WhileOnBattlefield); this.staticText = "If a source would deal damage to equipped creature, prevent X of that damage, where X is the number of creatures you control."; @@ -76,19 +70,18 @@ class ShieldOfTheAvatarPreventionEffect extends PreventionEffectImpl { boolean result = false; Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { - int numberOfCreaturesControlled = new PermanentsOnBattlefieldCount(filter).calculate(game, source, this); + int numberOfCreaturesControlled = CreaturesYouControlCount.instance.calculate(game, source, this); int toPrevent = Math.min(numberOfCreaturesControlled, event.getAmount()); GameEvent preventEvent = new GameEvent(GameEvent.EventType.PREVENT_DAMAGE, equipment.getAttachedTo(), source.getSourceId(), source.getControllerId(), toPrevent, false); if (!game.replaceEvent(preventEvent)) { if (event.getAmount() >= toPrevent) { event.setAmount(event.getAmount() - toPrevent); - } - else { + } else { event.setAmount(0); result = true; } if (toPrevent > 0) { - game.informPlayers(new StringBuilder("Shield of the Avatar ").append("prevented ").append(toPrevent).append(" damage to ").append(game.getPermanent(equipment.getAttachedTo()).getName()).toString()); + game.informPlayers("Shield of the Avatar " + "prevented " + toPrevent + " damage to " + game.getPermanent(equipment.getAttachedTo()).getName()); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, equipment.getAttachedTo(), source.getSourceId(), source.getControllerId(), toPrevent)); } @@ -101,10 +94,8 @@ class ShieldOfTheAvatarPreventionEffect extends PreventionEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game)) { Permanent equipment = game.getPermanent(source.getSourceId()); - if (equipment != null && equipment.getAttachedTo() != null - && event.getTargetId().equals(equipment.getAttachedTo())) { - return true; - } + return equipment != null && equipment.getAttachedTo() != null + && event.getTargetId().equals(equipment.getAttachedTo()); } return false; } diff --git a/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java b/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java index b89b5bde7d..68d416731e 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java +++ b/Mage.Sets/src/mage/cards/s/ShieldhideDragon.java @@ -27,7 +27,7 @@ public final class ShieldhideDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other Dragon creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/s/ShieldmageElder.java b/Mage.Sets/src/mage/cards/s/ShieldmageElder.java index f31d93ea59..b79d1d0544 100644 --- a/Mage.Sets/src/mage/cards/s/ShieldmageElder.java +++ b/Mage.Sets/src/mage/cards/s/ShieldmageElder.java @@ -30,13 +30,13 @@ public final class ShieldmageElder extends CardImpl { private static final FilterControlledPermanent filter1 = new FilterControlledPermanent("untapped Clerics you control"); static { - filter1.add(Predicates.not(new TappedPredicate())); + filter1.add(Predicates.not(TappedPredicate.instance)); filter1.add(new SubtypePredicate(SubType.CLERIC)); } private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("untapped Wizards you control"); static { - filter2.add(Predicates.not(new TappedPredicate())); + filter2.add(Predicates.not(TappedPredicate.instance)); filter2.add(new SubtypePredicate(SubType.WIZARD)); } diff --git a/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java b/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java index af8b412ecf..5c502625ee 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java +++ b/Mage.Sets/src/mage/cards/s/ShiftingLoyalties.java @@ -1,9 +1,6 @@ package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.common.continuous.ExchangeControlTargetEffect; @@ -11,19 +8,22 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ShiftingLoyalties extends CardImpl { public ShiftingLoyalties(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{U}"); // Exchange control of two target permanents that share a card type. (Artifact, creature, enchantment, land, and planeswalker are card types.) this.getSpellAbility().addEffect(new ExchangeControlTargetEffect(Duration.EndOfGame, "Exchange control of two target permanents that share a card type. (Artifact, creature, enchantment, land, and planeswalker are card types.)")); @@ -31,7 +31,7 @@ public final class ShiftingLoyalties extends CardImpl { } - public ShiftingLoyalties(final ShiftingLoyalties card) { + private ShiftingLoyalties(final ShiftingLoyalties card) { super(card); } @@ -43,12 +43,12 @@ public final class ShiftingLoyalties extends CardImpl { class TargetPermanentsThatShareCardType extends TargetPermanent { - public TargetPermanentsThatShareCardType() { - super(2, 2, new FilterPermanent(), false); + TargetPermanentsThatShareCardType() { + super(2, 2, StaticFilters.FILTER_PERMANENT, false); targetName = "permanents that share a card type"; } - public TargetPermanentsThatShareCardType(final TargetPermanentsThatShareCardType target) { + private TargetPermanentsThatShareCardType(final TargetPermanentsThatShareCardType target) { super(target); } @@ -72,14 +72,16 @@ class TargetPermanentsThatShareCardType extends TargetPermanent { public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { Set cardTypes = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - for (CardType cardType :permanent.getCardType()) { - if (cardTypes.contains(cardType)) { - return true; + if (targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + for (CardType cardType : permanent.getCardType()) { + if (cardTypes.contains(cardType)) { + return true; + } } + cardTypes.addAll(permanent.getCardType()); } - cardTypes.addAll(permanent.getCardType()); } } return false; diff --git a/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java index 79ea220f12..c73a0b3f5b 100644 --- a/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java +++ b/Mage.Sets/src/mage/cards/s/ShiftyDoppelganger.java @@ -81,7 +81,7 @@ class ShiftyDoppelgangerExileEffect extends OneShotEffect { boolean putCreature = false; UUID creatureId = UUID.randomUUID(); Player player = game.getPlayer(source.getControllerId()); - if (player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) { + if (player != null && player.chooseUse(Outcome.PutCardInPlay, "Put " + filter.getMessage() + " from your hand onto the battlefield?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); if (player.choose(Outcome.PutCreatureInPlay, target, source.getSourceId(), game)) { Card card = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java index 34d307add1..5729db0fec 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java +++ b/Mage.Sets/src/mage/cards/s/ShimianNightStalker.java @@ -31,7 +31,7 @@ public final class ShimianNightStalker extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public ShimianNightStalker(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java index b10e036e41..a06d58fe98 100644 --- a/Mage.Sets/src/mage/cards/s/ShimianSpecter.java +++ b/Mage.Sets/src/mage/cards/s/ShimianSpecter.java @@ -125,7 +125,7 @@ class ShimianSpecterEffect extends OneShotEffect { // If the player has no nonland cards in their hand, you can still search that player's library and have him or her shuffle it. if (chosenCard != null || controller.chooseUse(outcome, "Search library anyway?", source, game)) { TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); - controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); + controller.searchLibrary(targetCardsLibrary, source, game, targetPlayer.getId()); for (UUID cardId : targetCardsLibrary.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java b/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java new file mode 100644 index 0000000000..46bfea6cf1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShimmerOfPossibility.java @@ -0,0 +1,36 @@ +package mage.cards.s; + +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ShimmerOfPossibility extends CardImpl { + + public ShimmerOfPossibility(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}"); + + // Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order. + this.getSpellAbility().addEffect(new LookLibraryAndPickControllerEffect( + new StaticValue(4), false, new StaticValue(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, + false, false, false, Zone.HAND, false, false, false + ).setBackInRandomOrder(true)); + } + + private ShimmerOfPossibility(final ShimmerOfPossibility card) { + super(card); + } + + @Override + public ShimmerOfPossibility copy() { + return new ShimmerOfPossibility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShiningShoal.java b/Mage.Sets/src/mage/cards/s/ShiningShoal.java index 5733872da8..f4d8b7a908 100644 --- a/Mage.Sets/src/mage/cards/s/ShiningShoal.java +++ b/Mage.Sets/src/mage/cards/s/ShiningShoal.java @@ -44,7 +44,7 @@ public final class ShiningShoal extends CardImpl { this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); // The next X damage that a source of your choice would deal to you and/or creatures you control this turn is dealt to any target instead. - this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect(Duration.EndOfTurn, new ExileFromHandCostCardConvertedMana())); + this.getSpellAbility().addEffect(new ShiningShoalRedirectDamageTargetEffect(Duration.EndOfTurn, ExileFromHandCostCardConvertedMana.instance)); this.getSpellAbility().addTarget(new TargetSource()); this.getSpellAbility().addTarget(new TargetAnyTarget()); } @@ -103,7 +103,7 @@ class ShiningShoalRedirectDamageTargetEffect extends RedirectDamageFromSourceToT return false; } // do the 2 objects match? - if (!sourceObject.getId().equals(chosenSourceObject.getId())) { + if (chosenSourceObject == null || !sourceObject.getId().equals(chosenSourceObject.getId())) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/ShipbreakerKraken.java b/Mage.Sets/src/mage/cards/s/ShipbreakerKraken.java index d43cfaed03..8fa2848498 100644 --- a/Mage.Sets/src/mage/cards/s/ShipbreakerKraken.java +++ b/Mage.Sets/src/mage/cards/s/ShipbreakerKraken.java @@ -121,7 +121,7 @@ class ShipbreakerKrakenReplacementEffect extends ContinuousRuleModifyingEffectIm class ShipbreakerKrakenWatcher extends Watcher { ShipbreakerKrakenWatcher () { - super("ControlLost", WatcherScope.CARD); + super(WatcherScope.CARD); } ShipbreakerKrakenWatcher(ShipbreakerKrakenWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java b/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java index a207a9a8b5..de016872ae 100644 --- a/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java +++ b/Mage.Sets/src/mage/cards/s/ShipwreckSinger.java @@ -33,7 +33,7 @@ public final class ShipwreckSinger extends CardImpl { private static final FilterCreaturePermanent filterAttacking = new FilterCreaturePermanent("Attacking creatures"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filterAttacking.add(new AttackingPredicate()); + filterAttacking.add(AttackingPredicate.instance); } public ShipwreckSinger(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java b/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java index 6e0d7d255f..5af0b2937e 100644 --- a/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java +++ b/Mage.Sets/src/mage/cards/s/ShireiShizosCaretaker.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -13,11 +11,7 @@ import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEf import mage.cards.Card; 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.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -25,8 +19,9 @@ import mage.game.events.ZoneChangeEvent; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class ShireiShizosCaretaker extends CardImpl { @@ -78,8 +73,8 @@ class ShireiShizosCaretakerTriggeredAbility extends TriggeredAbilityImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; Permanent LKIpermanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); Card card = game.getCard(zEvent.getTargetId()); - - if (card != null && LKIpermanent != null + if (card != null + && LKIpermanent != null && card.isOwnedBy(this.controllerId) && zEvent.getToZone() == Zone.GRAVEYARD && zEvent.getFromZone() == Zone.BATTLEFIELD diff --git a/Mage.Sets/src/mage/cards/s/ShivanSandMage.java b/Mage.Sets/src/mage/cards/s/ShivanSandMage.java index 23ab234be7..8b286bf275 100644 --- a/Mage.Sets/src/mage/cards/s/ShivanSandMage.java +++ b/Mage.Sets/src/mage/cards/s/ShivanSandMage.java @@ -40,8 +40,8 @@ public final class ShivanSandMage extends CardImpl { // Put two time counters on target permanent with a time counter on it or suspended card. Mode mode = new Mode(); - mode.getEffects().add(new ShivanSandMageEffect(true)); - mode.getTargets().add(new TargetPermanentOrSuspendedCard()); + mode.addEffect(new ShivanSandMageEffect(true)); + mode.addTarget(new TargetPermanentOrSuspendedCard()); ability.addMode(mode); ability.getModes().addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/ShorecomberCrab.java b/Mage.Sets/src/mage/cards/s/ShorecomberCrab.java new file mode 100644 index 0000000000..03dee68e49 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShorecomberCrab.java @@ -0,0 +1,32 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ShorecomberCrab extends CardImpl { + + public ShorecomberCrab(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + this.subtype.add(SubType.CRAB); + + this.power = new MageInt(0); + this.toughness = new MageInt(4); + } + + public ShorecomberCrab(final ShorecomberCrab card) { + super(card); + } + + @Override + public ShorecomberCrab copy() { + return new ShorecomberCrab(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShredsOfSanity.java b/Mage.Sets/src/mage/cards/s/ShredsOfSanity.java index 00536e942e..172af9fbd3 100644 --- a/Mage.Sets/src/mage/cards/s/ShredsOfSanity.java +++ b/Mage.Sets/src/mage/cards/s/ShredsOfSanity.java @@ -25,8 +25,8 @@ import mage.target.TargetCard; */ public final class ShredsOfSanity extends CardImpl { - private final static FilterCard filterInstant = new FilterCard("an instant card in your graveyard"); - private final static FilterCard filterSorcery = new FilterCard("a sorcery card in your graveyard"); + private static final FilterCard filterInstant = new FilterCard("an instant card in your graveyard"); + private static final FilterCard filterSorcery = new FilterCard("a sorcery card in your graveyard"); static { filterInstant.add(new CardTypePredicate(CardType.INSTANT)); diff --git a/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java b/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java index 4b944809d9..b4b36b3e2b 100644 --- a/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java +++ b/Mage.Sets/src/mage/cards/s/ShrewdHatchling.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -14,11 +12,7 @@ import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ColorPredicate; @@ -27,28 +21,28 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; -/** - * - * @author jeffwadsworth +import java.util.UUID; +/** + * @author jeffwadsworth */ public final class ShrewdHatchling extends CardImpl { - + private static final FilterSpell filter = new FilterSpell("blue spell"); private static final FilterSpell filter2 = new FilterSpell("red spell"); - + static { filter.add(new ControllerPredicate(TargetController.YOU)); filter.add(new ColorPredicate(ObjectColor.BLUE)); filter2.add(new ControllerPredicate(TargetController.YOU)); filter2.add(new ColorPredicate(ObjectColor.RED)); } - + private String rule = "Whenever you cast a blue spell, remove a -1/-1 counter from Shrewd Hatchling."; private String rule2 = "Whenever you cast a red spell, remove a -1/-1 counter from Shrewd Hatchling."; public ShrewdHatchling(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U/R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U/R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(6); @@ -56,18 +50,18 @@ public final class ShrewdHatchling extends CardImpl { // Shrewd Hatchling enters the battlefield with four -1/-1 counters on it. this.addAbility(new EntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.M1M1.createInstance(4)))); - + // {UR}: Target creature can't block Shrewd Hatchling this turn. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShrewdHatchlingEffect(), new ManaCostsImpl("{U/R}")); ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - + // Whenever you cast a blue spell, remove a -1/-1 counter from Shrewd Hatchling. this.addAbility(new SpellCastAllTriggeredAbility(new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filter, false, rule)); - + // Whenever you cast a red spell, remove a -1/-1 counter from Shrewd Hatchling. this.addAbility(new SpellCastAllTriggeredAbility(new RemoveCounterSourceEffect(CounterType.M1M1.createInstance()), filter2, false, rule2)); - + } public ShrewdHatchling(final ShrewdHatchling card) { @@ -93,18 +87,13 @@ class ShrewdHatchlingEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { UUID targetId = source.getFirstTarget(); - if (targetId != null && blocker.getId().equals(targetId)) - return false; - return true; + return targetId == null || !blocker.getId().equals(targetId); } @Override diff --git a/Mage.Sets/src/mage/cards/s/Shriekdiver.java b/Mage.Sets/src/mage/cards/s/Shriekdiver.java new file mode 100644 index 0000000000..0c975762c3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Shriekdiver.java @@ -0,0 +1,48 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HasteAbility; +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 Shriekdiver extends CardImpl { + + public Shriekdiver(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {1}: Shriekdiver gains haste until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ), new GenericManaCost(1))); + } + + private Shriekdiver(final Shriekdiver card) { + super(card); + } + + @Override + public Shriekdiver copy() { + return new Shriekdiver(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java b/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java index 58a756bbe8..50f0cb86e9 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java +++ b/Mage.Sets/src/mage/cards/s/ShriekingAffliction.java @@ -1,47 +1,40 @@ - - package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.condition.common.CardsInHandCondition; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.LoseLifeTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; +import mage.constants.ComparisonType; +import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.targetpointer.FixedTarget; + +import java.util.UUID; /** - * http://www.wizards.com/magic/magazine/article.aspx?x=mtg/faq/rtr - * Shrieking Affliction's ability will trigger only if an opponent begins his or - * her upkeep with one or fewer cards in hand. - * The ability will check the number of cards in that player's hand again when - * it tries to resolve. If that player has two or more cards in hand at that time, - * that player won't lose life. - * * @author LevelX2 */ public final class ShriekingAffliction extends CardImpl { - static final String rule = "At the beginning of the upkeep of enchanted creature's controller, that player loses 2 life"; - - public ShriekingAffliction (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); - + public ShriekingAffliction(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); // At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, he or she loses 3 life. - this.addAbility(new ShriekingAfflictionTriggeredAbility()); + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new LoseLifeTargetEffect(3), + TargetController.OPPONENT, false, true + ), + (Condition)new CardsInHandCondition(ComparisonType.FEWER_THAN, 2, null, TargetController.ACTIVE), + "At the beginning of each opponent’s upkeep, if that player has one or fewer cards in hand, they lose 3 life." + )); } - public ShriekingAffliction (final ShriekingAffliction card) { + private ShriekingAffliction(final ShriekingAffliction card) { super(card); } @@ -50,75 +43,3 @@ public final class ShriekingAffliction extends CardImpl { return new ShriekingAffliction(this); } } - -class ShriekingAfflictionTriggeredAbility extends TriggeredAbilityImpl { - - public ShriekingAfflictionTriggeredAbility() { - super(Zone.BATTLEFIELD, null); - } - - public ShriekingAfflictionTriggeredAbility(final ShriekingAfflictionTriggeredAbility ability) { - super(ability); - } - - @Override - public ShriekingAfflictionTriggeredAbility copy() { - return new ShriekingAfflictionTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.UPKEEP_STEP_PRE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - if (game.getOpponents(controllerId).contains(event.getPlayerId())) { - Player player = game.getPlayer(event.getPlayerId()); - if (player != null && player.getHand().size() < 2) { - this.getEffects().clear(); - ShriekingAfflictionTargetEffect effect = new ShriekingAfflictionTargetEffect(); - effect.setTargetPointer(new FixedTarget(player.getId())); - this.addEffect(effect); - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, he or she loses 3 life."; - } -} -class ShriekingAfflictionTargetEffect extends OneShotEffect { - - public ShriekingAfflictionTargetEffect() { - super(Outcome.Damage); - staticText = "he or she loses 3 life"; - } - - public ShriekingAfflictionTargetEffect(final ShriekingAfflictionTargetEffect effect) { - super(effect); - } - - @Override - public ShriekingAfflictionTargetEffect copy() { - return new ShriekingAfflictionTargetEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null && player.getHand().size() < 2) { - Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent != null) { - game.informPlayers(sourcePermanent.getName() + ": " + player.getLogName() + " loses 3 life"); - } - player.loseLife(3, game, false); - return true; - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/s/ShriekingMogg.java b/Mage.Sets/src/mage/cards/s/ShriekingMogg.java index 63260a809a..2df0930767 100644 --- a/Mage.Sets/src/mage/cards/s/ShriekingMogg.java +++ b/Mage.Sets/src/mage/cards/s/ShriekingMogg.java @@ -23,7 +23,7 @@ public final class ShriekingMogg extends CardImpl { static final FilterCreaturePermanent filter = new FilterCreaturePermanent("all other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ShriekingMogg(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShrineKeeper.java b/Mage.Sets/src/mage/cards/s/ShrineKeeper.java new file mode 100644 index 0000000000..67682826d7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/ShrineKeeper.java @@ -0,0 +1,32 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ShrineKeeper extends CardImpl { + + public ShrineKeeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + this.subtype.add(SubType.HUMAN, SubType.CLERIC); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + public ShrineKeeper(final ShrineKeeper card) { + super(card); + } + + @Override + public ShrineKeeper copy() { + return new ShrineKeeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/ShrineOfTheForsakenGods.java b/Mage.Sets/src/mage/cards/s/ShrineOfTheForsakenGods.java index 992ffd901c..0dac6ffc82 100644 --- a/Mage.Sets/src/mage/cards/s/ShrineOfTheForsakenGods.java +++ b/Mage.Sets/src/mage/cards/s/ShrineOfTheForsakenGods.java @@ -25,7 +25,7 @@ public final class ShrineOfTheForsakenGods extends CardImpl { private static final FilterSpell filter = new FilterSpell("colorless spells"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public ShrineOfTheForsakenGods(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/ShrivelingRot.java b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java index 57c8db9535..dfe775bf0e 100644 --- a/Mage.Sets/src/mage/cards/s/ShrivelingRot.java +++ b/Mage.Sets/src/mage/cards/s/ShrivelingRot.java @@ -37,7 +37,7 @@ public final class ShrivelingRot extends CardImpl { this.getSpellAbility().addEffect(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotDestroyTriggeredAbility())); // Until end of turn, whenever a creature dies, that creature's controller loses life equal to its toughness. Mode mode = new Mode(); - mode.getEffects().add(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotLoseLifeTriggeredAbility())); + mode.addEffect(new CreateDelayedTriggeredAbilityEffect(new ShrivelingRotLoseLifeTriggeredAbility())); this.getSpellAbility().getModes().addMode(mode); // Entwine {2}{B} @@ -111,7 +111,7 @@ class ShrivelingRotLoseLifeTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget().isCreature()) { Effect effect = this.getEffects().get(0); effect.setTargetPointer(new FixedTarget(event.getTargetId())); diff --git a/Mage.Sets/src/mage/cards/s/ShroudedLore.java b/Mage.Sets/src/mage/cards/s/ShroudedLore.java index 16abab99ed..b4042febd6 100644 --- a/Mage.Sets/src/mage/cards/s/ShroudedLore.java +++ b/Mage.Sets/src/mage/cards/s/ShroudedLore.java @@ -1,16 +1,10 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; @@ -23,14 +17,15 @@ import mage.players.Player; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LoneFox */ public final class ShroudedLore extends CardImpl { public ShroudedLore(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); // Target opponent chooses a card in your graveyard. You may pay {B}. If you do, repeat this process except that opponent can't choose a card already chosen for Shrouded Lore. Then put the last chosen card into your hand. this.getSpellAbility().addEffect(new ShroudedLoreEffect()); @@ -67,8 +62,7 @@ class ShroudedLoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(targetPointer.getFirst(game, source)); - if(you != null && opponent != null) - { + if (you != null && opponent != null) { FilterCard filter = new FilterCard(); filter.add(new OwnerIdPredicate(you.getId())); Cost cost = new ManaCostsImpl("{B}"); @@ -78,31 +72,31 @@ class ShroudedLoreEffect extends OneShotEffect { do { chosenCard = new TargetCardInGraveyard(filter); chosenCard.setNotTarget(true); - if(chosenCard.canChoose(opponent.getId(), game)) { + if (chosenCard.canChoose(opponent.getId(), game)) { opponent.chooseTarget(Outcome.ReturnToHand, chosenCard, source, game); card = game.getCard(chosenCard.getFirstTarget()); - filter.add(Predicates.not(new CardIdPredicate(card.getId()))); - game.informPlayers("Shrouded Lore: " + opponent.getLogName() + " has chosen " + card.getLogName()); - } - else { + if (card != null) { + filter.add(Predicates.not(new CardIdPredicate(card.getId()))); + game.informPlayers("Shrouded Lore: " + opponent.getLogName() + " has chosen " + card.getLogName()); + } + } else { done = true; } - if(!done) { - if(cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {B} to choose a different card ?", source, game)) { + if (!done) { + if (cost.canPay(source, source.getSourceId(), you.getId(), game) && you.chooseUse(Outcome.Benefit, "Pay {B} to choose a different card ?", source, game)) { cost.clearPaid(); - if(!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { + if (!cost.pay(source, game, source.getSourceId(), you.getId(), false, null)) { done = true; } - } - else { + } else { done = true; } } - } while(!done); + } while (!done); - if(card != null) { + if (card != null) { Cards cardsToHand = new CardsImpl(); cardsToHand.add(card); you.moveCards(cardsToHand, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SickeningDreams.java b/Mage.Sets/src/mage/cards/s/SickeningDreams.java index ba51c25580..3a74c9e7ee 100644 --- a/Mage.Sets/src/mage/cards/s/SickeningDreams.java +++ b/Mage.Sets/src/mage/cards/s/SickeningDreams.java @@ -30,7 +30,7 @@ public final class SickeningDreams extends CardImpl { this.getSpellAbility().addCost(new SickeningDreamsAdditionalCost()); // Sickening Dreams deals X damage to each creature and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new GetXValue(), new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new DamageEverythingEffect(GetXValue.instance, new FilterCreaturePermanent())); } public SickeningDreams(final SickeningDreams card) { diff --git a/Mage.Sets/src/mage/cards/s/SickeningShoal.java b/Mage.Sets/src/mage/cards/s/SickeningShoal.java index 32b4fb3587..5bec8f2fe7 100644 --- a/Mage.Sets/src/mage/cards/s/SickeningShoal.java +++ b/Mage.Sets/src/mage/cards/s/SickeningShoal.java @@ -40,7 +40,7 @@ public final class SickeningShoal extends CardImpl { this.addAbility(new AlternativeCostSourceAbility(new ExileFromHandCost(new TargetCardInHand(filter), true))); // Target creature gets -X/-X until end of turn. - DynamicValue x = new SignInversionDynamicValue(new ExileFromHandCostCardConvertedMana()); + DynamicValue x = new SignInversionDynamicValue(ExileFromHandCostCardConvertedMana.instance); this.getSpellAbility().addEffect(new BoostTargetEffect(x, x, Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SickleDancer.java b/Mage.Sets/src/mage/cards/s/SickleDancer.java index ec80b693b9..c5d70a1f74 100644 --- a/Mage.Sets/src/mage/cards/s/SickleDancer.java +++ b/Mage.Sets/src/mage/cards/s/SickleDancer.java @@ -24,7 +24,7 @@ public final class SickleDancer extends CardImpl { private static final FilterTeamPermanent filter = new FilterTeamPermanent(SubType.WARRIOR, "Warrior creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SickleDancer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SidarJabari.java b/Mage.Sets/src/mage/cards/s/SidarJabari.java index 75cd2d644d..73f1b6593e 100644 --- a/Mage.Sets/src/mage/cards/s/SidarJabari.java +++ b/Mage.Sets/src/mage/cards/s/SidarJabari.java @@ -24,7 +24,7 @@ public final class SidarJabari extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public SidarJabari(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java index 7e767a16c2..f3db71d472 100644 --- a/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java +++ b/Mage.Sets/src/mage/cards/s/SidarKondoOfJamuraa.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -13,19 +11,15 @@ import mage.abilities.keyword.PartnerAbility; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SidarKondoOfJamuraa extends CardImpl { @@ -92,9 +86,12 @@ class SidarKondoOfJamuraaCantBlockCreaturesSourceEffect extends RestrictionEffec } return game.getOpponents(source.getControllerId()).contains(permanent.getControllerId()); } - + @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage.Sets/src/mage/cards/s/SiftThroughSands.java b/Mage.Sets/src/mage/cards/s/SiftThroughSands.java index bb58142306..496d32332f 100644 --- a/Mage.Sets/src/mage/cards/s/SiftThroughSands.java +++ b/Mage.Sets/src/mage/cards/s/SiftThroughSands.java @@ -66,7 +66,7 @@ class SiftThroughSandsCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SiftThroughSandsWatcher watcher = (SiftThroughSandsWatcher) game.getState().getWatchers().get(SiftThroughSandsWatcher.class.getSimpleName(), source.getControllerId()); + SiftThroughSandsWatcher watcher = game.getState().getWatcher(SiftThroughSandsWatcher.class, source.getControllerId()); if (watcher != null) { return watcher.conditionMet(); } @@ -80,7 +80,7 @@ class SiftThroughSandsWatcher extends Watcher { boolean castReachThroughMists = false; public SiftThroughSandsWatcher() { - super(SiftThroughSandsWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } public SiftThroughSandsWatcher(final SiftThroughSandsWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/SifterOfSkulls.java b/Mage.Sets/src/mage/cards/s/SifterOfSkulls.java index fd5064b861..cf4e004867 100644 --- a/Mage.Sets/src/mage/cards/s/SifterOfSkulls.java +++ b/Mage.Sets/src/mage/cards/s/SifterOfSkulls.java @@ -28,8 +28,8 @@ public final class SifterOfSkulls extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public SifterOfSkulls(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SifterWurm.java b/Mage.Sets/src/mage/cards/s/SifterWurm.java index 27d1fe73d1..da4a909703 100644 --- a/Mage.Sets/src/mage/cards/s/SifterWurm.java +++ b/Mage.Sets/src/mage/cards/s/SifterWurm.java @@ -73,10 +73,10 @@ class SifterWurmEffect extends OneShotEffect { if (controller != null && sourceObject != null) { controller.scry(3, source, game); - Cards cards = new CardsImpl(); Card card = controller.getLibrary().getFromTop(game); if (card != null) { + Cards cards = new CardsImpl(); cards.add(card); controller.revealCards(sourceObject.getIdName(), cards, game); controller.gainLife(card.getConvertedManaCost(), game, source); diff --git a/Mage.Sets/src/mage/cards/s/SigardasAid.java b/Mage.Sets/src/mage/cards/s/SigardasAid.java index d2be5aacd4..8b7a18df42 100644 --- a/Mage.Sets/src/mage/cards/s/SigardasAid.java +++ b/Mage.Sets/src/mage/cards/s/SigardasAid.java @@ -25,7 +25,7 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public final class SigardasAid extends CardImpl { - private final static FilterArtifactPermanent filter = new FilterArtifactPermanent("an Equipment"); + private static final FilterArtifactPermanent filter = new FilterArtifactPermanent("an Equipment"); private static final FilterCard filterCard = new FilterCard("Aura and Equipment spells"); static { diff --git a/Mage.Sets/src/mage/cards/s/SigilCaptain.java b/Mage.Sets/src/mage/cards/s/SigilCaptain.java index e14f9428f6..0e5408a88a 100644 --- a/Mage.Sets/src/mage/cards/s/SigilCaptain.java +++ b/Mage.Sets/src/mage/cards/s/SigilCaptain.java @@ -87,8 +87,6 @@ class SigilCaptainTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - StringBuilder sb = new StringBuilder(); - sb.append("Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it"); - return sb.toString(); + return "Whenever a creature enters the battlefield under your control, if that creature is 1/1, put two +1/+1 counters on it"; } } diff --git a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java index 2a84a060c0..9e054e1d7f 100644 --- a/Mage.Sets/src/mage/cards/s/SigilOfSleep.java +++ b/Mage.Sets/src/mage/cards/s/SigilOfSleep.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -19,6 +18,7 @@ import mage.game.Game; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FirstTargetPointer; /** @@ -27,10 +27,8 @@ import mage.target.targetpointer.FirstTargetPointer; */ public final class SigilOfSleep extends CardImpl { - private final UUID originalId; - public SigilOfSleep(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -39,34 +37,17 @@ public final class SigilOfSleep extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Whenever enchanted creature deals damage to a player, return target creature that player controls to its owner's hand. Effect effect = new ReturnToHandTargetEffect(); effect.setText("return target creature that player controls to its owner's hand"); ability = new DealsDamageToAPlayerAttachedTriggeredAbility(effect, "enchanted", false, true, false); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(SigilOfSleepAdjuster.instance); this.addAbility(ability); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - UUID playerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); - if (playerId != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that player controls"); - filter.add(new ControllerIdPredicate(playerId)); - Target target = new TargetCreaturePermanent(filter); - ability.getTargets().clear(); - ability.addTarget(target); - ability.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); - } - - } } public SigilOfSleep(final SigilOfSleep card) { super(card); - this.originalId = card.originalId; } @Override @@ -74,3 +55,20 @@ public final class SigilOfSleep extends CardImpl { return new SigilOfSleep(this); } } + +enum SigilOfSleepAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + UUID playerId = ability.getEffects().get(0).getTargetPointer().getFirst(game, ability); + if (playerId != null) { + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that player controls"); + filter.add(new ControllerIdPredicate(playerId)); + Target target = new TargetCreaturePermanent(filter); + ability.getTargets().clear(); + ability.addTarget(target); + ability.getEffects().get(0).setTargetPointer(new FirstTargetPointer()); + } + } +} diff --git a/Mage.Sets/src/mage/cards/s/SigilTracer.java b/Mage.Sets/src/mage/cards/s/SigilTracer.java index bcce031f3b..d8658b60d9 100644 --- a/Mage.Sets/src/mage/cards/s/SigilTracer.java +++ b/Mage.Sets/src/mage/cards/s/SigilTracer.java @@ -29,7 +29,7 @@ public final class SigilTracer extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Wizards you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.WIZARD)); } diff --git a/Mage.Sets/src/mage/cards/s/SignalPest.java b/Mage.Sets/src/mage/cards/s/SignalPest.java index ea2b26fdec..dab7642273 100644 --- a/Mage.Sets/src/mage/cards/s/SignalPest.java +++ b/Mage.Sets/src/mage/cards/s/SignalPest.java @@ -23,7 +23,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class SignalPest extends CardImpl { - private final static FilterCreaturePermanent notFlyingorReachCreatures = new FilterCreaturePermanent("except by creatures with flying or reach"); + private static final FilterCreaturePermanent notFlyingorReachCreatures = new FilterCreaturePermanent("except by creatures with flying or reach"); static { notFlyingorReachCreatures.add(Predicates.not( diff --git a/Mage.Sets/src/mage/cards/s/SignalTheClans.java b/Mage.Sets/src/mage/cards/s/SignalTheClans.java index 4c46610557..44fc5b18e5 100644 --- a/Mage.Sets/src/mage/cards/s/SignalTheClans.java +++ b/Mage.Sets/src/mage/cards/s/SignalTheClans.java @@ -13,7 +13,6 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; -import java.util.List; import java.util.UUID; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -66,10 +65,10 @@ class SignalTheClansEffect extends SearchEffect { return false; } //Search your library for three creature cards - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); - for (UUID cardId: (List)target.getTargets()) { + for (UUID cardId: target.getTargets()) { Card card = player.getLibrary().remove(cardId, game); if (card != null){ cards.add(card); diff --git a/Mage.Sets/src/mage/cards/s/SilburlindSnapper.java b/Mage.Sets/src/mage/cards/s/SilburlindSnapper.java index bf16032e77..bc5057f4cd 100644 --- a/Mage.Sets/src/mage/cards/s/SilburlindSnapper.java +++ b/Mage.Sets/src/mage/cards/s/SilburlindSnapper.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,22 +7,24 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.stack.Spell; import mage.watchers.common.SpellsCastWatcher; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SilburlindSnapper extends CardImpl { public SilburlindSnapper(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.TURTLE); this.power = new MageInt(6); this.toughness = new MageInt(6); @@ -61,15 +60,14 @@ class SilburlindSnapperEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { - + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spellsCast = watcher.getSpellsCastThisTurn(source.getControllerId()); if (spellsCast != null) { diff --git a/Mage.Sets/src/mage/cards/s/SilentArbiter.java b/Mage.Sets/src/mage/cards/s/SilentArbiter.java index dfb2d7406f..c5f13bd46a 100644 --- a/Mage.Sets/src/mage/cards/s/SilentArbiter.java +++ b/Mage.Sets/src/mage/cards/s/SilentArbiter.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,27 +7,28 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author emerald000 */ public final class SilentArbiter extends CardImpl { public SilentArbiter(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(1); this.toughness = new MageInt(5); // No more than one creature can attack each combat. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SilentArbiterAttackRestrictionEffect())); - + // No more than one creature can block each combat. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SilentArbiterBlockRestrictionEffect())); } @@ -45,55 +44,55 @@ public final class SilentArbiter extends CardImpl { } class SilentArbiterAttackRestrictionEffect extends RestrictionEffect { - + SilentArbiterAttackRestrictionEffect() { super(Duration.WhileOnBattlefield); staticText = "No more than one creature can attack each combat"; } - + SilentArbiterAttackRestrictionEffect(final SilentArbiterAttackRestrictionEffect effect) { super(effect); } - + @Override public SilentArbiterAttackRestrictionEffect copy() { return new SilentArbiterAttackRestrictionEffect(this); } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { return true; } - + @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getAttackers().isEmpty(); } } class SilentArbiterBlockRestrictionEffect extends RestrictionEffect { - + SilentArbiterBlockRestrictionEffect() { super(Duration.WhileOnBattlefield); staticText = "No more than one creature can block each combat"; } - + SilentArbiterBlockRestrictionEffect(final SilentArbiterBlockRestrictionEffect effect) { super(effect); } - + @Override public SilentArbiterBlockRestrictionEffect copy() { return new SilentArbiterBlockRestrictionEffect(this); } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { return true; } - + @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getBlockers().isEmpty(); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SilentChantZubera.java b/Mage.Sets/src/mage/cards/s/SilentChantZubera.java index 8854eb990e..b2d0ec1e0b 100644 --- a/Mage.Sets/src/mage/cards/s/SilentChantZubera.java +++ b/Mage.Sets/src/mage/cards/s/SilentChantZubera.java @@ -48,8 +48,11 @@ class SilentChantZuberaDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - ZuberasDiedWatcher watcher = (ZuberasDiedWatcher) game.getState().getWatchers().get(ZuberasDiedWatcher.class.getSimpleName()); - return watcher.zuberasDiedThisTurn * 2; + ZuberasDiedWatcher watcher = game.getState().getWatcher(ZuberasDiedWatcher.class); + if(watcher != null) { + return watcher.getZuberasDiedThisTurn() * 2; + } + return 0; } @Override diff --git a/Mage.Sets/src/mage/cards/s/SilentSubmersible.java b/Mage.Sets/src/mage/cards/s/SilentSubmersible.java new file mode 100644 index 0000000000..5539dff893 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilentSubmersible.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.CrewAbility; +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 SilentSubmersible extends CardImpl { + + public SilentSubmersible(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{U}{U}"); + + this.subtype.add(SubType.VEHICLE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever Silent Submarine deals combat damage to a player or planeswalker, draw a card. + this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ).setOrPlaneswalker(true)); + + // Crew 2 + this.addAbility(new CrewAbility(2)); + } + + private SilentSubmersible(final SilentSubmersible card) { + super(card); + } + + @Override + public SilentSubmersible copy() { + return new SilentSubmersible(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilhanaLedgewalker.java b/Mage.Sets/src/mage/cards/s/SilhanaLedgewalker.java index 5e8bb86892..360c27082c 100644 --- a/Mage.Sets/src/mage/cards/s/SilhanaLedgewalker.java +++ b/Mage.Sets/src/mage/cards/s/SilhanaLedgewalker.java @@ -1,8 +1,5 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -12,20 +9,21 @@ import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SilhanaLedgewalker extends CardImpl { - public SilhanaLedgewalker (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + public SilhanaLedgewalker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.ROGUE); @@ -39,7 +37,7 @@ public final class SilhanaLedgewalker extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SilhanaLedgewalkerEffect())); } - public SilhanaLedgewalker (final SilhanaLedgewalker card) { + public SilhanaLedgewalker(final SilhanaLedgewalker card) { super(card); } @@ -63,18 +61,12 @@ class SilhanaLedgewalkerEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (source.getSourceId().equals(permanent.getId())) { - return true; - } - return false; + return source.getSourceId().equals(permanent.getId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (blocker.getAbilities().contains(FlyingAbility.getInstance())) { - return true; - } - return false; + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return blocker.getAbilities().contains(FlyingAbility.getInstance()); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java b/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java new file mode 100644 index 0000000000..38d0f6e90e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SilhanaWayfinder.java @@ -0,0 +1,60 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SilhanaWayfinder extends CardImpl { + + private static final FilterCard filter + = new FilterCard("a creature or land card"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND) + )); + } + + public SilhanaWayfinder(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // When Silhana Wayfinder enters the battlefield, look at the top four cards of your library. You may reveal a creature or land card from among them and put it on top of your library. Put the rest on the bottom of your library in a random order. + this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( + new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, + true, true, Zone.LIBRARY, false, true, false + ).setBackInRandomOrder(true).setText("look at the top four cards of your library. " + + "You may reveal a creature or land card from among them " + + "and put it on top of your library. Put the rest " + + "on the bottom of your library in a random order."), false + )); + } + + private SilhanaWayfinder(final SilhanaWayfinder card) { + super(card); + } + + @Override + public SilhanaWayfinder copy() { + return new SilhanaWayfinder(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SilklashSpider.java b/Mage.Sets/src/mage/cards/s/SilklashSpider.java index 0cd6ebd135..05b44bcf58 100644 --- a/Mage.Sets/src/mage/cards/s/SilklashSpider.java +++ b/Mage.Sets/src/mage/cards/s/SilklashSpider.java @@ -40,7 +40,7 @@ public final class SilklashSpider extends CardImpl { this.addAbility(ReachAbility.getInstance()); // {X}{G}{G}: Silklash Spider deals X damage to each creature with flying. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new DamageAllEffect(new ManacostVariableValue(), filter), + new DamageAllEffect(ManacostVariableValue.instance, filter), new ManaCostsImpl("{X}{G}{G}"))); } diff --git a/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java b/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java index 68482edc93..b4c37bd9bc 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarsCommand.java @@ -46,20 +46,20 @@ public final class SilumgarsCommand extends CardImpl { // or Return target permanent to its owner's hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetPermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetPermanent()); this.getSpellAbility().getModes().addMode(mode); // or Target creature gets -3/-3 until end of turn; mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-3, -3, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // or Destroy target planeswalker. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter2)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filter2)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SilumgarsScorn.java b/Mage.Sets/src/mage/cards/s/SilumgarsScorn.java index ed30b202d8..c275bbc3a6 100644 --- a/Mage.Sets/src/mage/cards/s/SilumgarsScorn.java +++ b/Mage.Sets/src/mage/cards/s/SilumgarsScorn.java @@ -93,7 +93,7 @@ class SilumgarsScornCounterEffect extends OneShotEffect { if (spell != null) { Player player = game.getPlayer(spell.getControllerId()); if (player != null) { - DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = (DragonOnTheBattlefieldWhileSpellWasCastWatcher) game.getState().getWatchers().get(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName()); + DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher = game.getState().getWatcher(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class); boolean condition = watcher != null && watcher.castWithConditionTrue(source.getId()); if (!condition) { for (Cost cost: source.getCosts()) { diff --git a/Mage.Sets/src/mage/cards/s/SimicAscendancy.java b/Mage.Sets/src/mage/cards/s/SimicAscendancy.java new file mode 100644 index 0000000000..6316d881f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SimicAscendancy.java @@ -0,0 +1,107 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.WinGameSourceControllerEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class SimicAscendancy extends CardImpl { + + public SimicAscendancy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{U}"); + + // {1}{G}{U}: Put a +1/+1 counter on target creature you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.P1P1.createInstance()), new ManaCostsImpl("{1}{G}{U}")); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + // Whenever one or more +1/+1 counters are put on a creature you control, put that many growth counters on Simic Ascendancy. + this.addAbility(new SimicAscendancyTriggeredAbility()); + + // At the beginning of your upkeep, if Simic Ascendancy has twenty or more growth counters on it, you win the game. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new WinGameSourceControllerEffect(), + TargetController.YOU, false + ), new SourceHasCounterCondition(CounterType.GROWTH, 20, Integer.MAX_VALUE), + "At the beginning of your upkeep, if {this} has twenty " + + "or more growth counters on it, you win the game" + )); + } + + private SimicAscendancy(final SimicAscendancy card) { + super(card); + } + + @Override + public SimicAscendancy copy() { + return new SimicAscendancy(this); + } +} + +class SimicAscendancyTriggeredAbility extends TriggeredAbilityImpl { + + SimicAscendancyTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.GROWTH.createInstance()), false); + } + + private SimicAscendancyTriggeredAbility(final SimicAscendancyTriggeredAbility ability) { + super(ability); + } + + @Override + public SimicAscendancyTriggeredAbility copy() { + return new SimicAscendancyTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COUNTERS_ADDED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getData().equals(CounterType.P1P1.getName()) && event.getAmount() > 0) { + Permanent permanent = game.getPermanentOrLKIBattlefield(event.getTargetId()); + if (permanent == null) { + permanent = game.getPermanentEntering(event.getTargetId()); + } + if (permanent != null + && !event.getTargetId().equals(this.getSourceId()) + && permanent.isCreature() + && permanent.isControlledBy(this.getControllerId())) { + this.getEffects().clear(); + this.addEffect(new AddCountersSourceEffect(CounterType.GROWTH.createInstance(event.getAmount()))); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever one or more +1/+1 counters are put on a creature you control, put that many growth counters on {this}."; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SimicCharm.java b/Mage.Sets/src/mage/cards/s/SimicCharm.java index 2248e97e21..9daae89120 100644 --- a/Mage.Sets/src/mage/cards/s/SimicCharm.java +++ b/Mage.Sets/src/mage/cards/s/SimicCharm.java @@ -28,12 +28,12 @@ public final class SimicCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); //permanents you control gain hexproof until end of turn Mode mode = new Mode(); - mode.getEffects().add(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, new FilterControlledPermanent())); + mode.addEffect(new GainAbilityAllEffect(HexproofAbility.getInstance(), Duration.EndOfTurn, new FilterControlledPermanent())); this.getSpellAbility().addMode(mode); //return target creature to its owner's hand. Mode mode2 = new Mode(); - mode2.getEffects().add(new ReturnToHandTargetEffect()); - mode2.getTargets().add(new TargetCreaturePermanent()); + mode2.addEffect(new ReturnToHandTargetEffect()); + mode2.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode2); } diff --git a/Mage.Sets/src/mage/cards/s/SimicLocket.java b/Mage.Sets/src/mage/cards/s/SimicLocket.java new file mode 100644 index 0000000000..f301f9cb59 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SimicLocket.java @@ -0,0 +1,47 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.BlackManaAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.GreenManaAbility; +import mage.abilities.mana.RedManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class SimicLocket extends CardImpl { + + public SimicLocket(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); + + // {T}: Add {G} or {U}. + this.addAbility(new GreenManaAbility()); + this.addAbility(new BlueManaAbility()); + + // {G/U}{G/U}{G/U}{G/U}, {T}, Sacrifice Simic Locket: Draw two cards. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(2), new ManaCostsImpl<>("{G/U}{G/U}{G/U}{G/U}")); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + public SimicLocket(final SimicLocket card) { + super(card); + } + + @Override + public SimicLocket copy() { + return new SimicLocket(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SimicManipulator.java b/Mage.Sets/src/mage/cards/s/SimicManipulator.java index 5e74a62d85..c639c7341a 100644 --- a/Mage.Sets/src/mage/cards/s/SimicManipulator.java +++ b/Mage.Sets/src/mage/cards/s/SimicManipulator.java @@ -6,7 +6,6 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.RemoveVariableCountersSourceCost; -import mage.abilities.costs.common.RemoveVariableCountersTargetCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.EvolveAbility; @@ -79,8 +78,8 @@ enum SimicManipulatorAdjuster implements TargetAdjuster { if (sourcePermanent != null) { int xValue = 0; for (Cost cost : ability.getCosts()) { - if (cost instanceof RemoveVariableCountersTargetCost) { - xValue = ((RemoveVariableCountersTargetCost) cost).getAmount(); + if (cost instanceof RemoveVariableCountersSourceCost) { + xValue = ((RemoveVariableCountersSourceCost) cost).getAmount(); break; } } diff --git a/Mage.Sets/src/mage/cards/s/Simulacrum.java b/Mage.Sets/src/mage/cards/s/Simulacrum.java index a810a5f4c9..f1afc1603d 100644 --- a/Mage.Sets/src/mage/cards/s/Simulacrum.java +++ b/Mage.Sets/src/mage/cards/s/Simulacrum.java @@ -47,7 +47,7 @@ class SimulacrumAmount implements DynamicValue { @Override public int calculate(Game game, Ability source, Effect effect) { - AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = (AmountOfDamageAPlayerReceivedThisTurnWatcher) game.getState().getWatchers().get(AmountOfDamageAPlayerReceivedThisTurnWatcher.class.getSimpleName()); + AmountOfDamageAPlayerReceivedThisTurnWatcher watcher = game.getState().getWatcher(AmountOfDamageAPlayerReceivedThisTurnWatcher.class); if(watcher != null) { return watcher.getAmountOfDamageReceivedThisTurn(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/s/SingleCombat.java b/Mage.Sets/src/mage/cards/s/SingleCombat.java new file mode 100644 index 0000000000..d4c235beb1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SingleCombat.java @@ -0,0 +1,128 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SingleCombat extends CardImpl { + + public SingleCombat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{W}{W}"); + + // Each player chooses a creature or planeswalker they control, then sacrifices the rest. Players can't cast creature or planeswalker spells until the end of your next turn. + this.getSpellAbility().addEffect(new SingleCombatEffect()); + this.getSpellAbility().addEffect(new SingleCombatRestrictionEffect()); + } + + private SingleCombat(final SingleCombat card) { + super(card); + } + + @Override + public SingleCombat copy() { + return new SingleCombat(this); + } +} + +class SingleCombatEffect extends OneShotEffect { + + private static final FilterPermanent filter + = new FilterControlledPermanent("creature or planeswalker you control (to keep)"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + SingleCombatEffect() { + super(Outcome.Benefit); + staticText = "Each player chooses a creature or planeswalker they control, then sacrifices the rest."; + } + + private SingleCombatEffect(final SingleCombatEffect effect) { + super(effect); + } + + @Override + public SingleCombatEffect copy() { + return new SingleCombatEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + FilterPermanent filterSac = new FilterCreatureOrPlaneswalkerPermanent(); + for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { + continue; + } + Target target = new TargetPermanent(filter); + target.setNotTarget(true); + if (player.choose(outcome, target, source.getSourceId(), game)) { + filterSac.add(Predicates.not(new PermanentIdPredicate(target.getFirstTarget()))); + } + } + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterSac, source.getControllerId(), game)) { + permanent.sacrifice(source.getSourceId(), game); + } + return true; + } +} + +class SingleCombatRestrictionEffect extends ContinuousRuleModifyingEffectImpl { + + SingleCombatRestrictionEffect() { + super(Duration.UntilEndOfYourNextTurn, Outcome.Neutral); + staticText = "Players can't cast creature or planeswalker spells until the end of your next turn."; + } + + private SingleCombatRestrictionEffect(final SingleCombatRestrictionEffect effect) { + super(effect); + } + + @Override + public SingleCombatRestrictionEffect copy() { + return new SingleCombatRestrictionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Card card = game.getCard(event.getSourceId()); + return card != null && (card.isCreature() || card.isPlaneswalker()); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SinsOfThePast.java b/Mage.Sets/src/mage/cards/s/SinsOfThePast.java index 013b5780d7..21aa8edb35 100644 --- a/Mage.Sets/src/mage/cards/s/SinsOfThePast.java +++ b/Mage.Sets/src/mage/cards/s/SinsOfThePast.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -11,32 +10,29 @@ import mage.abilities.effects.common.ExileSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AsThoughEffectType; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterInstantOrSorceryCard; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; import mage.players.Player; -import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author emerald000 */ public final class SinsOfThePast extends CardImpl { public SinsOfThePast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}"); // Until end of turn, you may cast target instant or sorcery card from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead. Exile Sins of the Past. this.getSpellAbility().addEffect(new SinsOfThePastEffect()); this.getSpellAbility().addEffect(new ExileSourceEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(new FilterInstantOrSorceryCard())); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterInstantOrSorceryCard())); } public SinsOfThePast(final SinsOfThePast card) { @@ -104,8 +100,10 @@ class SinsOfThePastCastFromGraveyardEffect extends AsThoughEffectImpl { public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { if (sourceId.equals(this.getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId())) { Player player = game.getPlayer(affectedControllerId); - player.setCastSourceIdWithAlternateMana(sourceId, null, null); - return true; + if(player != null) { + player.setCastSourceIdWithAlternateMana(sourceId, null, null); + return true; + } } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SirensCall.java b/Mage.Sets/src/mage/cards/s/SirensCall.java index 9512ea85e4..e37225124e 100644 --- a/Mage.Sets/src/mage/cards/s/SirensCall.java +++ b/Mage.Sets/src/mage/cards/s/SirensCall.java @@ -120,7 +120,7 @@ class SirensCallDestroyEffect extends OneShotEffect { continue; } // Creatures that attacked are safe. - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { continue; } diff --git a/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java b/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java index c32c0bcd37..ab178a600c 100644 --- a/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java +++ b/Mage.Sets/src/mage/cards/s/SistersOfStoneDeath.java @@ -1,8 +1,5 @@ - package mage.cards.s; -import java.util.LinkedList; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -14,11 +11,7 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreatureCard; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; @@ -30,8 +23,10 @@ import mage.players.Player; import mage.target.TargetCard; import mage.target.common.TargetCreaturePermanent; +import java.util.LinkedList; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SistersOfStoneDeath extends CardImpl { @@ -39,7 +34,7 @@ public final class SistersOfStoneDeath extends CardImpl { private UUID exileId = UUID.randomUUID(); public SistersOfStoneDeath(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}{G}{G}"); this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.GORGON); @@ -100,7 +95,9 @@ class SistersOfStoneDeathEffect extends OneShotEffect { LinkedList cards = new LinkedList<>(exile); for (UUID cardId : cards) { Card card = game.getCard(cardId); - cardsInExile.add(card); + if (card != null) { + cardsInExile.add(card); + } } if (controller.choose(Outcome.PutCreatureInPlay, cardsInExile, target, game)) { Card chosenCard = game.getCard(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SithLord.java b/Mage.Sets/src/mage/cards/s/SithLord.java index 0334ca86df..9b5b76c118 100644 --- a/Mage.Sets/src/mage/cards/s/SithLord.java +++ b/Mage.Sets/src/mage/cards/s/SithLord.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -11,14 +9,15 @@ import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Styxo */ public final class SithLord extends CardImpl { @@ -26,7 +25,7 @@ public final class SithLord extends CardImpl { private static final String rule = "with X +1/+1 counters on it, where X is the total life lost by your opponents this turn"; public SithLord(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SITH); this.power = new MageInt(2); @@ -62,7 +61,7 @@ public final class SithLord extends CardImpl { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { - int oll = new OpponentsLostLifeCount().calculate(game, source, this); + int oll = OpponentsLostLifeCount.instance.calculate(game, source, this); if (oll > 0) { permanent.addCounters(CounterType.P1P1.createInstance(oll), source, game); } @@ -76,5 +75,5 @@ public final class SithLord extends CardImpl { return new SithLordEffect(this); } } - + } diff --git a/Mage.Sets/src/mage/cards/s/SivvisValor.java b/Mage.Sets/src/mage/cards/s/SivvisValor.java index 631c739f70..307d3a3f45 100644 --- a/Mage.Sets/src/mage/cards/s/SivvisValor.java +++ b/Mage.Sets/src/mage/cards/s/SivvisValor.java @@ -38,7 +38,7 @@ public final class SivvisValor extends CardImpl { static { filter.add(new SubtypePredicate(SubType.PLAINS)); - filterCreature.add(Predicates.not(new TappedPredicate())); + filterCreature.add(Predicates.not(TappedPredicate.instance)); } public SivvisValor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java b/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java index 9f445da773..63368b9c1e 100644 --- a/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java +++ b/Mage.Sets/src/mage/cards/s/SkarrganFirebird.java @@ -61,8 +61,8 @@ class OpponentWasDealtDamageCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get(BloodthirstWatcher.class.getSimpleName(), source.getControllerId()); - return watcher.conditionMet(); + BloodthirstWatcher watcher = game.getState().getWatcher(BloodthirstWatcher.class, source.getControllerId()); + return watcher != null && watcher.conditionMet(); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java b/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java new file mode 100644 index 0000000000..91818d5cc2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkarrganHellkite.java @@ -0,0 +1,58 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.condition.common.SourceHasCounterCondition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.DamageMultiEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.RiotAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.target.common.TargetAnyTargetAmount; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkarrganHellkite extends CardImpl { + + public SkarrganHellkite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}"); + + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Riot + this.addAbility(new RiotAbility()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {3}{R}: Skarrgan Hellkite deals 2 damage divided as you choose among one or two targets. Activate this ability only if Skarrgan Hellkite has a +1/+1 counter on it. + Ability ability = new ConditionalActivatedAbility( + Zone.BATTLEFIELD, new DamageMultiEffect(2), + new ManaCostsImpl("{3}{R}"), new SourceHasCounterCondition(CounterType.P1P1), + "{3}{R}: {this} deals 2 damage divided as you choose among one or two targets. " + + "Activate this ability only if {this} has a +1/+1 counter on it." + ); + ability.addTarget(new TargetAnyTargetAmount(2)); + this.addAbility(ability); + } + + private SkarrganHellkite(final SkarrganHellkite card) { + super(card); + } + + @Override + public SkarrganHellkite copy() { + return new SkarrganHellkite(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkatewingSpy.java b/Mage.Sets/src/mage/cards/s/SkatewingSpy.java new file mode 100644 index 0000000000..5e54811771 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkatewingSpy.java @@ -0,0 +1,64 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.AdaptAbility; +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.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.CounterPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkatewingSpy extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + } + + public SkatewingSpy(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.VEDALKEN); + this.subtype.add(SubType.ROGUE); + this.subtype.add(SubType.MUTANT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {5}{U}: Adapt 2. + this.addAbility(new AdaptAbility(2, "{5}{U}")); + + // Each creature you control with a +1/+1 counter on it has flying. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAllEffect( + FlyingAbility.getInstance(), + Duration.WhileOnBattlefield, + filter, "Each creature you control " + + "with a +1/+1 counter on it has flying" + ) + )); + } + + private SkatewingSpy(final SkatewingSpy card) { + super(card); + } + + @Override + public SkatewingSpy copy() { + return new SkatewingSpy(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkeletalScrying.java b/Mage.Sets/src/mage/cards/s/SkeletalScrying.java index 712f565e93..558d631939 100644 --- a/Mage.Sets/src/mage/cards/s/SkeletalScrying.java +++ b/Mage.Sets/src/mage/cards/s/SkeletalScrying.java @@ -34,7 +34,7 @@ public final class SkeletalScrying extends CardImpl { ability.setRuleAtTheTop(true); this.addAbility(ability); // You draw X cards and you lose X life. - this.getSpellAbility().addEffect(new SkeletalScryingEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new SkeletalScryingEffect(ManacostVariableValue.instance)); } diff --git a/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java b/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java new file mode 100644 index 0000000000..c15d68bdd0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkeletonScavengers.java @@ -0,0 +1,129 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class SkeletonScavengers extends CardImpl { + + public SkeletonScavengers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.SKELETON); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Skeleton Scavengers enters the battlefield with a +1/+1 counter on it. + this.addAbility(new AsEntersBattlefieldAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()))); + + // Pay {1} for each +1/+1 counter on Skeleton Scavengers: Regenerate Skeleton Scavengers. When it regenerates this way, put a +1/+1 counter on it. + this.addAbility(new SimpleActivatedAbility(new SkeletonScavengersEffect(), new DynamicValueGenericManaCost(new CountersSourceCount(CounterType.P1P1)))); + + } + + public SkeletonScavengers(final SkeletonScavengers card) { + super(card); + } + + @Override + public SkeletonScavengers copy() { + return new SkeletonScavengers(this); + } +} + +class DynamicValueGenericManaCost extends CostImpl { + + DynamicValue amount; + + public DynamicValueGenericManaCost(DynamicValue amount) { + this.amount = amount; + setText(); + } + + public DynamicValueGenericManaCost(DynamicValueGenericManaCost cost) { + super(cost); + this.amount = cost.amount; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player controller = game.getPlayer(controllerId); + if (controller == null) { + return false; + } + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + return cost.canPay(ability, sourceId, controllerId, game); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + int convertedCost = amount.calculate(game, ability, null); + Cost cost = new GenericManaCost(convertedCost); + if (controller != null) { + paid = cost.pay(ability, game, sourceId, controllerId, noMana); + } + return paid; + } + + @Override + public DynamicValueGenericManaCost copy() { + return new DynamicValueGenericManaCost(this); + } + + private void setText() { + text = ("Pay {1} for each +1/+1 counter on {this}"); + } +} + +class SkeletonScavengersEffect extends OneShotEffect { + + SkeletonScavengersEffect() { + super(Outcome.Benefit); + this.staticText = "Regenerate {this}. When it regenerates this way, put a +1/+1 counter on it"; + } + + SkeletonScavengersEffect(final SkeletonScavengersEffect effect) { + super(effect); + } + + @Override + public SkeletonScavengersEffect copy() { + return new SkeletonScavengersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent skeletonScavengers = game.getPermanent(source.getSourceId()); + if (skeletonScavengers != null) { + if (new RegenerateSourceEffect().apply(game, source)) { + return new AddCountersSourceEffect(CounterType.P1P1.createInstance()).apply(game, source); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/Skeletonize.java b/Mage.Sets/src/mage/cards/s/Skeletonize.java index 7eba0bdead..d00c5ef374 100644 --- a/Mage.Sets/src/mage/cards/s/Skeletonize.java +++ b/Mage.Sets/src/mage/cards/s/Skeletonize.java @@ -95,7 +95,7 @@ class SkeletonizeDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zce = (ZoneChangeEvent) event; if (zce.isDiesEvent()) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), this.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, this.getSourceId()); if (watcher != null) { return watcher.wasDamaged(zce.getTarget(), game); } diff --git a/Mage.Sets/src/mage/cards/s/SkewerTheCritics.java b/Mage.Sets/src/mage/cards/s/SkewerTheCritics.java new file mode 100644 index 0000000000..808d6637fa --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkewerTheCritics.java @@ -0,0 +1,37 @@ +package mage.cards.s; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.keyword.SpectacleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkewerTheCritics extends CardImpl { + + public SkewerTheCritics(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}"); + + // Skewer the Critics deals 3 damage to any target. + this.getSpellAbility().addEffect(new DamageTargetEffect(3)); + this.getSpellAbility().addTarget(new TargetAnyTarget()); + + // Spectacle {R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{R}"))); + } + + private SkewerTheCritics(final SkewerTheCritics card) { + super(card); + } + + @Override + public SkewerTheCritics copy() { + return new SkewerTheCritics(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Skinshifter.java b/Mage.Sets/src/mage/cards/s/Skinshifter.java index b43463ee85..4765cc305e 100644 --- a/Mage.Sets/src/mage/cards/s/Skinshifter.java +++ b/Mage.Sets/src/mage/cards/s/Skinshifter.java @@ -38,11 +38,11 @@ public final class Skinshifter extends CardImpl { new ManaCostsImpl("{G}")); Mode mode = new Mode(); - mode.getEffects().add(new BecomesCreatureSourceEffect(new BirdToken(), "", Duration.EndOfTurn)); + mode.addEffect(new BecomesCreatureSourceEffect(new BirdToken(), "", Duration.EndOfTurn)); ability.addMode(mode); mode = new Mode(); - mode.getEffects().add(new BecomesCreatureSourceEffect(new PlantToken(), "", Duration.EndOfTurn)); + mode.addEffect(new BecomesCreatureSourceEffect(new PlantToken(), "", Duration.EndOfTurn)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java b/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java index f7f8cb1518..72d6ed3a65 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java +++ b/Mage.Sets/src/mage/cards/s/SkirkAlarmist.java @@ -35,7 +35,7 @@ public final class SkirkAlarmist extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face-down creature you control"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/s/SkirkFireMarshal.java b/Mage.Sets/src/mage/cards/s/SkirkFireMarshal.java index 0ad0bc887d..fe57a459ed 100644 --- a/Mage.Sets/src/mage/cards/s/SkirkFireMarshal.java +++ b/Mage.Sets/src/mage/cards/s/SkirkFireMarshal.java @@ -29,7 +29,7 @@ public final class SkirkFireMarshal extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Goblins you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.GOBLIN)); } diff --git a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java index 15b2be1caf..736b0a2bde 100644 --- a/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java +++ b/Mage.Sets/src/mage/cards/s/SkirsdagHighPriest.java @@ -30,7 +30,7 @@ public final class SkirsdagHighPriest extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SkirsdagHighPriest(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkitterEel.java b/Mage.Sets/src/mage/cards/s/SkitterEel.java new file mode 100644 index 0000000000..ffd78c8f39 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkitterEel.java @@ -0,0 +1,37 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.AdaptAbility; +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 SkitterEel extends CardImpl { + + public SkitterEel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.FISH); + this.subtype.add(SubType.CRAB); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // {2}{U}: Adapt 2. + this.addAbility(new AdaptAbility(2, "{2}{U}")); + } + + private SkitterEel(final SkitterEel card) { + super(card); + } + + @Override + public SkitterEel copy() { + return new SkitterEel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkitterOfLizards.java b/Mage.Sets/src/mage/cards/s/SkitterOfLizards.java index 95353e03aa..b4a9f5a524 100644 --- a/Mage.Sets/src/mage/cards/s/SkitterOfLizards.java +++ b/Mage.Sets/src/mage/cards/s/SkitterOfLizards.java @@ -35,7 +35,7 @@ public final class SkitterOfLizards extends CardImpl { // Skitter of Lizards enters the battlefield with a +1/+1 counter on it for each time it was kicked. this.addAbility(new EntersBattlefieldAbility( - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new MultikickerCount(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), MultikickerCount.instance, true), "with a +1/+1 counter on it for each time it was kicked")); } diff --git a/Mage.Sets/src/mage/cards/s/Skitterskin.java b/Mage.Sets/src/mage/cards/s/Skitterskin.java index a61b9b0d39..0ce710eb67 100644 --- a/Mage.Sets/src/mage/cards/s/Skitterskin.java +++ b/Mage.Sets/src/mage/cards/s/Skitterskin.java @@ -28,8 +28,8 @@ public final class Skitterskin extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("you control another colorless creature"); static { - filter.add(new AnotherPredicate()); - filter.add(new ColorlessPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(ColorlessPredicate.instance); } public Skitterskin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkittishValesk.java b/Mage.Sets/src/mage/cards/s/SkittishValesk.java index 8ba58f3f85..604f9a2e6d 100644 --- a/Mage.Sets/src/mage/cards/s/SkittishValesk.java +++ b/Mage.Sets/src/mage/cards/s/SkittishValesk.java @@ -63,7 +63,7 @@ class SkittishValeskEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (controller != null && permanent != null && !controller.flipCoin(game)) { + if (controller != null && permanent != null && !controller.flipCoin(source, game, true)) { return permanent.turnFaceDown(game, source.getControllerId()); } return false; diff --git a/Mage.Sets/src/mage/cards/s/SkullStorm.java b/Mage.Sets/src/mage/cards/s/SkullStorm.java index 164cf6e303..5f1d8d884f 100644 --- a/Mage.Sets/src/mage/cards/s/SkullStorm.java +++ b/Mage.Sets/src/mage/cards/s/SkullStorm.java @@ -65,13 +65,13 @@ class SkullStormEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { game.getOpponents(source.getControllerId()).forEach((playerId) -> { Player player = game.getPlayer(playerId); - if (!(player == null)) { + if (player != null) { FilterPermanent filter = new FilterCreaturePermanent(); filter.add(new ControllerIdPredicate(playerId)); if (game.getBattlefield().getActivePermanents( filter, source.getControllerId(), game ).isEmpty()) { - int lifeToLose = (int) Math.ceil(player.getLife() / 2); + int lifeToLose = (int) Math.ceil(player.getLife() / 2f); player.loseLife(lifeToLose, game, false); } else { Effect effect = new SacrificeEffect( diff --git a/Mage.Sets/src/mage/cards/s/SkullbriarTheWalkingGrave.java b/Mage.Sets/src/mage/cards/s/SkullbriarTheWalkingGrave.java index 7c21786363..d37ca591ec 100644 --- a/Mage.Sets/src/mage/cards/s/SkullbriarTheWalkingGrave.java +++ b/Mage.Sets/src/mage/cards/s/SkullbriarTheWalkingGrave.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.StaticAbility; @@ -22,15 +21,15 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import java.util.UUID; + /** - * * @author anonymous */ public final class SkullbriarTheWalkingGrave extends CardImpl { - private Counters counters; public SkullbriarTheWalkingGrave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.ELEMENTAL); @@ -46,7 +45,9 @@ public final class SkullbriarTheWalkingGrave extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.ALL, new SkullbriarEffect())); } - public SkullbriarTheWalkingGrave(SkullbriarTheWalkingGrave card) { super(card); } + public SkullbriarTheWalkingGrave(SkullbriarTheWalkingGrave card) { + super(card); + } @Override public SkullbriarTheWalkingGrave copy() { @@ -58,7 +59,7 @@ public final class SkullbriarTheWalkingGrave extends CardImpl { public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) { boolean skullBriarEffectApplied = false; if (event.getToZone() != Zone.HAND && event.getToZone() != Zone.LIBRARY) { - for (StaticAbility ability : getAbilities (game).getStaticAbilities(event.getFromZone())) { + for (StaticAbility ability : getAbilities(game).getStaticAbilities(event.getFromZone())) { for (Effect effect : ability.getEffects(game, EffectType.REPLACEMENT)) { if (effect instanceof SkullbriarEffect && event.getAppliedEffects().contains(effect.getId())) { skullBriarEffectApplied = true; @@ -84,7 +85,7 @@ public final class SkullbriarTheWalkingGrave extends CardImpl { copyTo = this.getCounters(game); } if (copyTo != null && copyFrom != null) { - for(Counter counter : copyFrom.values()) { + for (Counter counter : copyFrom.values()) { copyTo.addCounter(counter); } } diff --git a/Mage.Sets/src/mage/cards/s/Skullsnatcher.java b/Mage.Sets/src/mage/cards/s/Skullsnatcher.java index 4ff8480c45..484a2c9b31 100644 --- a/Mage.Sets/src/mage/cards/s/Skullsnatcher.java +++ b/Mage.Sets/src/mage/cards/s/Skullsnatcher.java @@ -32,7 +32,7 @@ public final class Skullsnatcher extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("unblocked attacker you control"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } public Skullsnatcher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkyHussar.java b/Mage.Sets/src/mage/cards/s/SkyHussar.java index 074294d305..eb73ff2f48 100644 --- a/Mage.Sets/src/mage/cards/s/SkyHussar.java +++ b/Mage.Sets/src/mage/cards/s/SkyHussar.java @@ -29,7 +29,7 @@ public final class SkyHussar extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped white and/or blue creatures you control"); static { filter.add(Predicates.or(new ColorPredicate(ObjectColor.WHITE), new ColorPredicate(ObjectColor.BLUE))); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SkyHussar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkyScourer.java b/Mage.Sets/src/mage/cards/s/SkyScourer.java index 0350d7c473..c5f8142e32 100644 --- a/Mage.Sets/src/mage/cards/s/SkyScourer.java +++ b/Mage.Sets/src/mage/cards/s/SkyScourer.java @@ -24,7 +24,7 @@ public final class SkyScourer extends CardImpl { private static final FilterSpell filterSpell = new FilterSpell("a colorless spell"); static { - filterSpell.add(new ColorlessPredicate()); + filterSpell.add(ColorlessPredicate.instance); } public SkyScourer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SkyTether.java b/Mage.Sets/src/mage/cards/s/SkyTether.java new file mode 100644 index 0000000000..d24831c318 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkyTether.java @@ -0,0 +1,54 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.common.continuous.LoseAbilityAttachedEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlyingAbility; +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 SkyTether extends CardImpl { + + public SkyTether(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{W}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has defender and loses flying. + ability = new SimpleStaticAbility(new GainAbilityAttachedEffect( + DefenderAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield + )); + ability.addEffect(new LoseAbilityAttachedEffect( + FlyingAbility.getInstance(), AttachmentType.AURA + ).concatBy("and")); + this.addAbility(ability); + } + + private SkyTether(final SkyTether card) { + super(card); + } + + @Override + public SkyTether copy() { + return new SkyTether(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkyTheaterStrix.java b/Mage.Sets/src/mage/cards/s/SkyTheaterStrix.java new file mode 100644 index 0000000000..518481cf59 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SkyTheaterStrix.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +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.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SkyTheaterStrix extends CardImpl { + + public SkyTheaterStrix(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast a noncreature spell, Sky Theater Strix gets +1/+0 until end of turn. + this.addAbility(new SpellCastControllerTriggeredAbility( + new BoostSourceEffect(1, 0, Duration.EndOfTurn), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + } + + private SkyTheaterStrix(final SkyTheaterStrix card) { + super(card); + } + + @Override + public SkyTheaterStrix copy() { + return new SkyTheaterStrix(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SkyblinderStaff.java b/Mage.Sets/src/mage/cards/s/SkyblinderStaff.java index 8e029f9592..b87bbcd6c5 100644 --- a/Mage.Sets/src/mage/cards/s/SkyblinderStaff.java +++ b/Mage.Sets/src/mage/cards/s/SkyblinderStaff.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -15,21 +13,22 @@ import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SkyblinderStaff extends CardImpl { public SkyblinderStaff(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); this.subtype.add(SubType.EQUIPMENT); // Equipped creature gets +1/+0 and can't be blocked by creatures with flying. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(1, 0)); ability.addEffect(new CantBeBlockedByCreaturesWithFlyingAttachedEffect()); this.addAbility(ability); - + // Equip {3} this.addAbility(new EquipAbility(Outcome.BoostCreature, new GenericManaCost(3))); @@ -63,7 +62,7 @@ class CantBeBlockedByCreaturesWithFlyingAttachedEffect extends RestrictionEffect } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !blocker.getAbilities().contains(FlyingAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/s/SkyclawThrash.java b/Mage.Sets/src/mage/cards/s/SkyclawThrash.java index 3e9bf12b52..b0a9e3f91b 100644 --- a/Mage.Sets/src/mage/cards/s/SkyclawThrash.java +++ b/Mage.Sets/src/mage/cards/s/SkyclawThrash.java @@ -70,7 +70,7 @@ class SkyclawThrashEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (controller.flipCoin(game) && sourcePermanent != null) { + if (controller.flipCoin(source, game, true) && sourcePermanent != null) { ContinuousEffect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); game.addEffect(effect, source); diff --git a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java index ab3981c926..899b0aa5aa 100644 --- a/Mage.Sets/src/mage/cards/s/SkyfireKirin.java +++ b/Mage.Sets/src/mage/cards/s/SkyfireKirin.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -22,6 +21,7 @@ import mage.game.stack.Spell; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTarget; /** @@ -29,8 +29,6 @@ import mage.target.targetpointer.FixedTarget; */ public final class SkyfireKirin extends CardImpl { - private final UUID originalId; - public SkyfireKirin(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); addSuperType(SuperType.LEGENDARY); @@ -43,30 +41,17 @@ public final class SkyfireKirin extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Whenever you cast a Spirit or Arcane spell, you may gain control of target creature with that spell's converted mana cost until end of turn. - Ability ability = new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new SkyfireKirinEffect(), StaticFilters.SPIRIT_OR_ARCANE_CARD, true, true); + Ability ability = new SpellCastControllerTriggeredAbility( + Zone.BATTLEFIELD, new SkyfireKirinEffect(), + StaticFilters.SPIRIT_OR_ARCANE_CARD, true, true + ); ability.addTarget(new TargetCreaturePermanent()); - originalId = ability.getOriginalId(); + ability.setTargetAdjuster(SkyfireKirinAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - Spell spell = game.getStack().getSpell(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); - if (spell != null) { - int cmc = spell.getConvertedManaCost(); - ability.getTargets().clear(); - FilterPermanent filter = new FilterCreaturePermanent(new StringBuilder("creature with converted mana costs of ").append(cmc).toString()); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); - Target target = new TargetPermanent(filter); - ability.addTarget(target); - } - } - } - public SkyfireKirin(final SkyfireKirin card) { super(card); - this.originalId = card.originalId; } @Override @@ -75,6 +60,22 @@ public final class SkyfireKirin extends CardImpl { } } +enum SkyfireKirinAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Spell spell = game.getStack().getSpell(ability.getEffects().get(0).getTargetPointer().getFirst(game, ability)); + if (spell != null) { + int cmc = spell.getConvertedManaCost(); + ability.getTargets().clear(); + FilterPermanent filter = new FilterCreaturePermanent("creature with converted mana cost " + cmc); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); + ability.addTarget(new TargetPermanent(filter)); + } + } +} + class SkyfireKirinEffect extends OneShotEffect { public SkyfireKirinEffect() { diff --git a/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java b/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java index 94095c759b..0293180fb4 100644 --- a/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java +++ b/Mage.Sets/src/mage/cards/s/SkymarcherAspirant.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +7,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -18,8 +17,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SkymarcherAspirant extends CardImpl { @@ -39,7 +39,7 @@ public final class SkymarcherAspirant extends CardImpl { ContinuousEffect boostSource = new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.WhileOnBattlefield); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, "{this} has flying as long as you have the city's blessing"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SkyriderPatrol.java b/Mage.Sets/src/mage/cards/s/SkyriderPatrol.java index 25fde9c0a6..c7119a8183 100644 --- a/Mage.Sets/src/mage/cards/s/SkyriderPatrol.java +++ b/Mage.Sets/src/mage/cards/s/SkyriderPatrol.java @@ -95,7 +95,7 @@ class SkyriderPatrolReflexiveTriggeredAbility extends DelayedTriggeredAbility { = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SkyriderPatrolReflexiveTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/s/Skyscribing.java b/Mage.Sets/src/mage/cards/s/Skyscribing.java index eba3cb37bf..cf37f0c5c6 100644 --- a/Mage.Sets/src/mage/cards/s/Skyscribing.java +++ b/Mage.Sets/src/mage/cards/s/Skyscribing.java @@ -20,7 +20,7 @@ public final class Skyscribing extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}"); // Each player draws X cards. - this.getSpellAbility().addEffect(new DrawCardAllEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardAllEffect(ManacostVariableValue.instance)); // Forecast - {2}{U}, Reveal Skyscribing from your hand: Each player draws a card. this.addAbility(new ForecastAbility(new DrawCardAllEffect(1), new ManaCostsImpl("{2}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/s/SkyshipWeatherlight.java b/Mage.Sets/src/mage/cards/s/SkyshipWeatherlight.java index e57d02047a..da4ce8dc16 100644 --- a/Mage.Sets/src/mage/cards/s/SkyshipWeatherlight.java +++ b/Mage.Sets/src/mage/cards/s/SkyshipWeatherlight.java @@ -91,7 +91,7 @@ class SkyshipWeatherlightEffect extends SearchEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (sourceObject != null && controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { UUID exileZone = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); if (!target.getTargets().isEmpty()) { for (UUID cardID : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/s/Slagstorm.java b/Mage.Sets/src/mage/cards/s/Slagstorm.java index 885a1075c2..88f321ef45 100644 --- a/Mage.Sets/src/mage/cards/s/Slagstorm.java +++ b/Mage.Sets/src/mage/cards/s/Slagstorm.java @@ -22,7 +22,7 @@ public final class Slagstorm extends CardImpl { this.getSpellAbility().addEffect(new DamageAllEffect(3, new FilterCreaturePermanent())); Mode mode = new Mode(); - mode.getEffects().add(new DamagePlayersEffect(3)); + mode.addEffect(new DamagePlayersEffect(3)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SlateOfAncestry.java b/Mage.Sets/src/mage/cards/s/SlateOfAncestry.java index 3df3402730..e90f23dfce 100644 --- a/Mage.Sets/src/mage/cards/s/SlateOfAncestry.java +++ b/Mage.Sets/src/mage/cards/s/SlateOfAncestry.java @@ -13,6 +13,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; /** @@ -26,7 +27,7 @@ public final class SlateOfAncestry extends CardImpl { // {4}, {tap}, Discard your hand: Draw a card for each creature you control. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creature you control"))), + new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)), new GenericManaCost(4)); ability.addCost(new TapSourceCost()); ability.addCost(new DiscardHandCost()); diff --git a/Mage.Sets/src/mage/cards/s/SlaughterTheStrong.java b/Mage.Sets/src/mage/cards/s/SlaughterTheStrong.java index eae88feb37..1765113460 100644 --- a/Mage.Sets/src/mage/cards/s/SlaughterTheStrong.java +++ b/Mage.Sets/src/mage/cards/s/SlaughterTheStrong.java @@ -1,9 +1,6 @@ package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; @@ -22,8 +19,11 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SlaughterTheStrong extends CardImpl { @@ -90,7 +90,19 @@ class SlaughterTheStrongEffect extends OneShotEffect { } else { currentFilter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 5 - powerSum)); } - Target target = new TargetPermanent(0, 1, currentFilter, true); + + // human can de-select targets, but AI must choose only one time + Target target; + if (player.isHuman()) { + target = new TargetPermanent(0, 1, currentFilter, true); + } else { + FilterControlledCreaturePermanent strictFilter = currentFilter.copy(); + selectedCreatures.stream().forEach(id -> { + strictFilter.add(Predicates.not(new PermanentIdPredicate(id))); + }); + target = new TargetPermanent(0, 1, strictFilter, true); + } + player.chooseTarget(Outcome.BoostCreature, target, source, game); if (target.getFirstTarget() != null) { if (selectedCreatures.contains(target.getFirstTarget())) { diff --git a/Mage.Sets/src/mage/cards/s/SlaveringNulls.java b/Mage.Sets/src/mage/cards/s/SlaveringNulls.java index c1a9958c7d..5cdd25f835 100644 --- a/Mage.Sets/src/mage/cards/s/SlaveringNulls.java +++ b/Mage.Sets/src/mage/cards/s/SlaveringNulls.java @@ -81,7 +81,7 @@ class SlaveringNullsTriggeredAbility extends TriggeredAbilityImpl { if (game.getBattlefield().countAll(filter, controllerId, game) > 0) { Permanent slaveringNulls = game.getPermanent(event.getSourceId()); Player player = game.getPlayer(event.getTargetId()); - if (slaveringNulls != null) { + if (slaveringNulls != null && player != null) { Effect effect = this.getEffects().get(0); effect.setTargetPointer(new FixedTarget(player.getId())); return true; diff --git a/Mage.Sets/src/mage/cards/s/Slimebind.java b/Mage.Sets/src/mage/cards/s/Slimebind.java new file mode 100644 index 0000000000..345de79d54 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Slimebind.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FlashAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Slimebind extends CardImpl { + + public Slimebind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + 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)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature gets -4/-0. + this.addAbility(new SimpleStaticAbility(new BoostEnchantedEffect(-4, 0))); + } + + private Slimebind(final Slimebind card) { + super(card); + } + + @Override + public Slimebind copy() { + return new Slimebind(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SlipperyScoundrel.java b/Mage.Sets/src/mage/cards/s/SlipperyScoundrel.java index 3476f5f56f..b7a860089c 100644 --- a/Mage.Sets/src/mage/cards/s/SlipperyScoundrel.java +++ b/Mage.Sets/src/mage/cards/s/SlipperyScoundrel.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -13,6 +11,7 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.combat.CantBeBlockedSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.HexproofAbility; import mage.cards.CardImpl; @@ -22,8 +21,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SlipperyScoundrel extends CardImpl { @@ -48,6 +48,7 @@ public final class SlipperyScoundrel extends CardImpl { Effect effect2 = new ConditionalRestrictionEffect(restrictionEffect, CitysBlessingCondition.instance) .setText("and can't be blocked"); ability.addEffect(effect2); + ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SliverLegion.java b/Mage.Sets/src/mage/cards/s/SliverLegion.java index 37aa4dc675..16e7d5dc51 100644 --- a/Mage.Sets/src/mage/cards/s/SliverLegion.java +++ b/Mage.Sets/src/mage/cards/s/SliverLegion.java @@ -24,7 +24,7 @@ public final class SliverLegion extends CardImpl { private static final FilterPermanent countfilter = new FilterPermanent(SubType.SLIVER, "other Sliver on the battlefield"); static { - countfilter.add(new AnotherPredicate()); + countfilter.add(AnotherPredicate.instance); } public SliverLegion(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SludgeStrider.java b/Mage.Sets/src/mage/cards/s/SludgeStrider.java index 219edc42f9..fb389b7393 100644 --- a/Mage.Sets/src/mage/cards/s/SludgeStrider.java +++ b/Mage.Sets/src/mage/cards/s/SludgeStrider.java @@ -61,7 +61,7 @@ class SludgeStriderTriggeredAbility extends TriggeredAbilityImpl { private static final FilterArtifactCard filter = new FilterArtifactCard("another artifact under your control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SludgeStriderTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/s/SlumberingDragon.java b/Mage.Sets/src/mage/cards/s/SlumberingDragon.java index 42375795b3..5133283bb2 100644 --- a/Mage.Sets/src/mage/cards/s/SlumberingDragon.java +++ b/Mage.Sets/src/mage/cards/s/SlumberingDragon.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksAllTriggeredAbility; @@ -11,18 +9,15 @@ 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.SubType; -import mage.constants.Duration; -import mage.constants.SetTargetPointer; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SlumberingDragon extends CardImpl { @@ -68,22 +63,19 @@ class SlumberingDragonEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (permanent.getCounters(game).getCount(CounterType.P1P1) >= 5) { - return false; - } - return true; + return permanent.getCounters(game).getCount(CounterType.P1P1) < 5; } // don't apply for all other creatures! return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java b/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java index 08ca61777e..5b04d9e138 100644 --- a/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java +++ b/Mage.Sets/src/mage/cards/s/SlyRequisitioner.java @@ -24,7 +24,7 @@ public final class SlyRequisitioner extends CardImpl { private static final FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("a nontoken artifact you control"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public SlyRequisitioner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java b/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java index e607e3faf6..dcf97b4eb7 100644 --- a/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SmeltWardGatekeepers.java @@ -1,16 +1,15 @@ - - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.hint.ConditionHint; import mage.abilities.keyword.HasteAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -22,8 +21,9 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ @@ -32,13 +32,16 @@ public final class SmeltWardGatekeepers extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); private static final FilterCreaturePermanent targetFilter = new FilterCreaturePermanent("creature an opponent controls"); + static { filter.add(new SubtypePredicate(SubType.GATE)); targetFilter.add(new ControllerPredicate(TargetController.OPPONENT)); } - public SmeltWardGatekeepers (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public SmeltWardGatekeepers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WARRIOR); @@ -48,16 +51,17 @@ public final class SmeltWardGatekeepers extends CardImpl { // When Smelt-Ward Gatekeepers enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn. Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new GainControlTargetEffect(Duration.EndOfTurn)), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), + gatesCondition, "When {this} enters the battlefield, if you control two or more Gates, gain control of target creature an opponent controls until end of turn. Untap that creature. That creature gains haste until end of turn."); ability.addEffect(new UntapTargetEffect()); ability.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.EndOfTurn)); Target target = new TargetCreaturePermanent(targetFilter); ability.addTarget(target); + ability.addHint(new ConditionHint(gatesCondition, "You control two or more Gates")); this.addAbility(ability); } - public SmeltWardGatekeepers (final SmeltWardGatekeepers card) { + public SmeltWardGatekeepers(final SmeltWardGatekeepers card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java b/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java new file mode 100644 index 0000000000..df72e415ed --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SmeltWardIgnus.java @@ -0,0 +1,63 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SmeltWardIgnus extends CardImpl { + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature with power 3 or less"); + + static { + filter.add(new PowerPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public SmeltWardIgnus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {2}{R}, Sacrifice Smelt-Ward Ignus: Gain control of target creature with power 3 or less until end of turn. Untap that creature. It gains haste until end of turn. Activate this ability only any time you could cast a sorcery. + Ability ability = new ActivateAsSorceryActivatedAbility( + Zone.BATTLEFIELD, + new GainControlTargetEffect( + Duration.EndOfTurn, true + ), new ManaCostsImpl("{2}{R}") + ); + ability.addEffect(new UntapTargetEffect().setText("Untap that creature")); + ability.addEffect(new GainAbilityTargetEffect( + HasteAbility.getInstance(), Duration.EndOfTurn + ).setText("It gains haste until end of turn")); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + private SmeltWardIgnus(final SmeltWardIgnus card) { + super(card); + } + + @Override + public SmeltWardIgnus copy() { + return new SmeltWardIgnus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Smite.java b/Mage.Sets/src/mage/cards/s/Smite.java index 67050e3b54..f6f46285dc 100644 --- a/Mage.Sets/src/mage/cards/s/Smite.java +++ b/Mage.Sets/src/mage/cards/s/Smite.java @@ -19,7 +19,7 @@ public final class Smite extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocked creature"); static { - filter.add(new BlockedPredicate()); + filter.add(BlockedPredicate.instance); } public Smite(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SmokeTeller.java b/Mage.Sets/src/mage/cards/s/SmokeTeller.java index 3254a12f88..3d3f74865f 100644 --- a/Mage.Sets/src/mage/cards/s/SmokeTeller.java +++ b/Mage.Sets/src/mage/cards/s/SmokeTeller.java @@ -32,7 +32,7 @@ public final class SmokeTeller extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public SmokeTeller(UUID ownerId, CardSetInfo setInfo) { @@ -86,8 +86,7 @@ class SmokeTellerLookFaceDownEffect extends OneShotEffect { if (faceDownCreature != null) { Permanent copyFaceDown = faceDownCreature.copy(); copyFaceDown.setFaceDown(false, game); - Cards cards = new CardsImpl(); - cards.add(copyFaceDown); + Cards cards = new CardsImpl(copyFaceDown); player.lookAtCards("face down card - " + mageObject.getName(), cards, game); } else { return false; diff --git a/Mage.Sets/src/mage/cards/s/SmotheringTithe.java b/Mage.Sets/src/mage/cards/s/SmotheringTithe.java new file mode 100644 index 0000000000..e5da099746 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SmotheringTithe.java @@ -0,0 +1,74 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DrawCardOpponentTriggeredAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +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.TreasureToken; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SmotheringTithe extends CardImpl { + + public SmotheringTithe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); + + // Whenever an opponent draws a card, that player may pay {2}. If the player doesn't, you create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color." + this.addAbility(new DrawCardOpponentTriggeredAbility( + new SmotheringTitheEffect(), false, true + )); + } + + private SmotheringTithe(final SmotheringTithe card) { + super(card); + } + + @Override + public SmotheringTithe copy() { + return new SmotheringTithe(this); + } +} + +class SmotheringTitheEffect extends OneShotEffect { + + SmotheringTitheEffect() { + super(Outcome.Benefit); + staticText = "that player may pay {2}. If the player doesn't, " + + "you create a colorless Treasure artifact token " + + "with \"{T}, Sacrifice this artifact: Add one mana of any color.\""; + } + + private SmotheringTitheEffect(final SmotheringTitheEffect effect) { + super(effect); + } + + @Override + public SmotheringTitheEffect copy() { + return new SmotheringTitheEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(targetPointer.getFirst(game, source)); + if (player == null) { + return false; + } + Cost cost = new GenericManaCost(2); + if (!player.chooseUse(Outcome.Detriment, "Pay {2} to prevent this effect?", source, game) + || !cost.pay(source, game, source.getSourceId(), player.getId(), false)) { + return new CreateTokenEffect(new TreasureToken()).apply(game, source); + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/Snag.java b/Mage.Sets/src/mage/cards/s/Snag.java index 877484cf1f..4c016086e6 100644 --- a/Mage.Sets/src/mage/cards/s/Snag.java +++ b/Mage.Sets/src/mage/cards/s/Snag.java @@ -29,7 +29,7 @@ public final class Snag extends CardImpl { static { filter.add(new SubtypePredicate(SubType.FOREST)); - filter2.add(Predicates.not(new BlockedPredicate())); + filter2.add(Predicates.not(BlockedPredicate.instance)); } public Snag(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SnakeBasket.java b/Mage.Sets/src/mage/cards/s/SnakeBasket.java index 66862965c2..6cc0acd59d 100644 --- a/Mage.Sets/src/mage/cards/s/SnakeBasket.java +++ b/Mage.Sets/src/mage/cards/s/SnakeBasket.java @@ -25,7 +25,7 @@ public final class SnakeBasket extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); // {X}, Sacrifice Snake Basket: create X 1/1 green Snake creature tokens. Activate this ability only any time you could cast a sorcery. - Effect effect = new CreateTokenEffect(new SnakeToken(), new ManacostVariableValue()); + Effect effect = new CreateTokenEffect(new SnakeToken(), ManacostVariableValue.instance); Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{X}")); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/s/SnakePit.java b/Mage.Sets/src/mage/cards/s/SnakePit.java index b2d173c76b..a7a108f024 100644 --- a/Mage.Sets/src/mage/cards/s/SnakePit.java +++ b/Mage.Sets/src/mage/cards/s/SnakePit.java @@ -19,7 +19,7 @@ import mage.game.permanent.token.SnakeToken; */ public final class SnakePit extends CardImpl { - private final static FilterSpell filter = new FilterSpell("a blue or black spell"); + private static final FilterSpell filter = new FilterSpell("a blue or black spell"); static { filter.add(Predicates.or(new ColorPredicate(ObjectColor.BLUE), new ColorPredicate(ObjectColor.BLACK))); diff --git a/Mage.Sets/src/mage/cards/s/Snarespinner.java b/Mage.Sets/src/mage/cards/s/Snarespinner.java new file mode 100644 index 0000000000..d738467dd8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Snarespinner.java @@ -0,0 +1,78 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class Snarespinner extends CardImpl { + + public Snarespinner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.SPIDER); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // Whenever Snarespinner blocks a creature with flying, Snarespinner gets +2/+0 until end of turn. + this.addAbility(new SnarespinnerTriggeredAbility()); + } + + private Snarespinner(final Snarespinner card) { + super(card); + } + + @Override + public Snarespinner copy() { + return new Snarespinner(this); + } +} + +class SnarespinnerTriggeredAbility extends TriggeredAbilityImpl { + + SnarespinnerTriggeredAbility() { + super(Zone.BATTLEFIELD, new BoostSourceEffect(2, 0, Duration.EndOfTurn), false); + } + + private SnarespinnerTriggeredAbility(final SnarespinnerTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.BLOCKER_DECLARED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getSourceId().equals(this.getSourceId()) + && game.getPermanent(event.getTargetId()).getAbilities().containsKey(FlyingAbility.getInstance().getId()); + } + + @Override + public String getRule() { + return "Whenever {this} blocks a creature with flying, {} gets +2/+0 until end of turn"; + } + + @Override + public SnarespinnerTriggeredAbility copy() { + return new SnarespinnerTriggeredAbility(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SnickeringSquirrel.java b/Mage.Sets/src/mage/cards/s/SnickeringSquirrel.java index 8f515860bc..bc72bae2dd 100644 --- a/Mage.Sets/src/mage/cards/s/SnickeringSquirrel.java +++ b/Mage.Sets/src/mage/cards/s/SnickeringSquirrel.java @@ -8,10 +8,7 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -26,8 +23,7 @@ public final class SnickeringSquirrel extends CardImpl { public SnickeringSquirrel(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); - this.subtype.add("Squirrel"); - this.subtype.add("Advisor"); + this.subtype.add(SubType.SQUIRREL, SubType.ADVISOR); this.power = new MageInt(1); this.toughness = new MageInt(1); diff --git a/Mage.Sets/src/mage/cards/s/SnowDevil.java b/Mage.Sets/src/mage/cards/s/SnowDevil.java new file mode 100644 index 0000000000..69ae57ac5b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SnowDevil.java @@ -0,0 +1,98 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.AttachmentType; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.game.combat.CombatGroup; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class SnowDevil extends CardImpl { + + public SnowDevil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Enchanted creature has flying. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityAttachedEffect(FlyingAbility.getInstance(), AttachmentType.AURA, Duration.WhileOnBattlefield))); + + // Enchanted creature has first strike as long as it's blocking and you control a snow land. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new ConditionalContinuousEffect( + new GainAbilityAttachedEffect( + FirstStrikeAbility.getInstance(), + AttachmentType.AURA, + Duration.WhileOnBattlefield), + SnowDevilCondition.instance, + "Enchanted creature has first strike as long as it's blocking and you control a snow land" + ))); + } + + private SnowDevil(final SnowDevil card) { + super(card); + } + + @Override + public SnowDevil copy() { + return new SnowDevil(this); + } +} + +enum SnowDevilCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + FilterLandPermanent filter = new FilterLandPermanent(); + filter.add(new SupertypePredicate(SuperType.SNOW)); + Permanent enchantment = game.getPermanent(source.getSourceId()); + if (enchantment != null) { + Player controller = game.getPlayer(enchantment.getControllerId()); + Permanent creature = game.getPermanent(enchantment.getAttachedTo()); + if (creature != null + && controller != null) { + CombatGroup combatGroup = game.getCombat().findGroupOfBlocker(creature.getId()); + if (combatGroup != null + && !game.getBattlefield().getAllActivePermanents(filter, controller.getId(), game).isEmpty()) { + return true; + } + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SnowFortress.java b/Mage.Sets/src/mage/cards/s/SnowFortress.java index 01ec8530ea..5d1b580f92 100644 --- a/Mage.Sets/src/mage/cards/s/SnowFortress.java +++ b/Mage.Sets/src/mage/cards/s/SnowFortress.java @@ -18,7 +18,7 @@ import mage.constants.Duration; import mage.constants.Zone; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/s/SnubhornSentry.java b/Mage.Sets/src/mage/cards/s/SnubhornSentry.java index c573af3009..07dbb91cd0 100644 --- a/Mage.Sets/src/mage/cards/s/SnubhornSentry.java +++ b/Mage.Sets/src/mage/cards/s/SnubhornSentry.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +7,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,8 +16,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SnubhornSentry extends CardImpl { @@ -37,7 +37,7 @@ public final class SnubhornSentry extends CardImpl { ContinuousEffect boostSource = new BoostSourceEffect(3, 0, Duration.WhileOnBattlefield); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, "{this} gets +3/+0 as long as you have the city's blessing"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SokenzanSpellblade.java b/Mage.Sets/src/mage/cards/s/SokenzanSpellblade.java index fda9d9d998..56e925fe0c 100644 --- a/Mage.Sets/src/mage/cards/s/SokenzanSpellblade.java +++ b/Mage.Sets/src/mage/cards/s/SokenzanSpellblade.java @@ -35,7 +35,7 @@ public final class SokenzanSpellblade extends CardImpl { // Bushido 1 this.addAbility(new BushidoAbility(1)); // {1}{R}: Sokenzan Spellblade gets +X/+0 until end of turn, where X is the number of cards in your hand. - Effect effect = new BoostSourceEffect(new CardsInControllerHandCount(), new StaticValue(0), Duration.EndOfTurn, true); + Effect effect = new BoostSourceEffect(CardsInControllerHandCount.instance, new StaticValue(0), Duration.EndOfTurn, true); effect.setText("{this} gets +X/+0 until end of turn, where X is the number of cards in your hand"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{1}{R}") diff --git a/Mage.Sets/src/mage/cards/s/SolarBlaze.java b/Mage.Sets/src/mage/cards/s/SolarBlaze.java new file mode 100644 index 0000000000..eeeca91888 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SolarBlaze.java @@ -0,0 +1,62 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SolarBlaze extends CardImpl { + + public SolarBlaze(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{R}{W}"); + + // Each creature deals damage to itself equal to its power. + this.getSpellAbility().addEffect(new SolarBlazeEffect()); + } + + private SolarBlaze(final SolarBlaze card) { + super(card); + } + + @Override + public SolarBlaze copy() { + return new SolarBlaze(this); + } +} + +class SolarBlazeEffect extends OneShotEffect { + + SolarBlazeEffect() { + super(Outcome.Benefit); + staticText = "Each creature deals damage to itself equal to its power."; + } + + private SolarBlazeEffect(final SolarBlazeEffect effect) { + super(effect); + } + + @Override + public SolarBlazeEffect copy() { + return new SolarBlazeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent permanent : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game) + ) { + permanent.damage(permanent.getPower().getValue(), permanent.getId(), game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SolarTide.java b/Mage.Sets/src/mage/cards/s/SolarTide.java index 221a496cbe..861aebdff7 100644 --- a/Mage.Sets/src/mage/cards/s/SolarTide.java +++ b/Mage.Sets/src/mage/cards/s/SolarTide.java @@ -37,7 +37,7 @@ public final class SolarTide extends CardImpl { // or destroy all creatures with power 3 or greater. Mode mode = new Mode(); - mode.getEffects().add(new DestroyAllEffect(filter2)); + mode.addEffect(new DestroyAllEffect(filter2)); this.getSpellAbility().getModes().addMode(mode); // Entwine-Sacrifice two lands. diff --git a/Mage.Sets/src/mage/cards/s/SoldeviExcavations.java b/Mage.Sets/src/mage/cards/s/SoldeviExcavations.java index 6ab8ca5938..21cb230813 100644 --- a/Mage.Sets/src/mage/cards/s/SoldeviExcavations.java +++ b/Mage.Sets/src/mage/cards/s/SoldeviExcavations.java @@ -33,7 +33,7 @@ public final class SoldeviExcavations extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ISLAND)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SoldeviExcavations(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SoldeviGolem.java b/Mage.Sets/src/mage/cards/s/SoldeviGolem.java index b4192c145a..b2c0364d08 100644 --- a/Mage.Sets/src/mage/cards/s/SoldeviGolem.java +++ b/Mage.Sets/src/mage/cards/s/SoldeviGolem.java @@ -30,7 +30,7 @@ public final class SoldeviGolem extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SoldeviGolem(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SoldeviSentry.java b/Mage.Sets/src/mage/cards/s/SoldeviSentry.java new file mode 100644 index 0000000000..14d2fdb476 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoldeviSentry.java @@ -0,0 +1,68 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.RegenerateSourceEffect; +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.TargetOpponent; + +/** + * + * @author Ketsuban + */ +public final class SoldeviSentry extends CardImpl { + + public SoldeviSentry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.ARTIFACT, CardType.CREATURE }, "{1}"); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // 1: Choose target opponent. Regenerate Soldevi Sentry. When it regenerates + // this way, that player may draw a card. + Ability ability = new SimpleActivatedAbility(new SoldeviSentryEffect(), new GenericManaCost(1)); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + public SoldeviSentry(final SoldeviSentry card) { + super(card); + } + + @Override + public SoldeviSentry copy() { + return new SoldeviSentry(this); + } +} + +class SoldeviSentryEffect extends RegenerateSourceEffect { + + @Override + public boolean apply(Game game, Ability source) { + //20110204 - 701.11 + Player opponent = game.getPlayer(source.getFirstTarget()); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null && permanent.regenerate(this.getId(), game)) { + if (opponent != null) { + if (opponent.chooseUse(Outcome.DrawCard, "Draw a card?", source, game)) { + opponent.drawCards(1, game); + } + } + this.used = true; + return true; + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SoldierOfThePantheon.java b/Mage.Sets/src/mage/cards/s/SoldierOfThePantheon.java index 90b2c056dc..be3cbe3147 100644 --- a/Mage.Sets/src/mage/cards/s/SoldierOfThePantheon.java +++ b/Mage.Sets/src/mage/cards/s/SoldierOfThePantheon.java @@ -24,7 +24,7 @@ public final class SoldierOfThePantheon extends CardImpl { private static final FilterObject filter = new FilterObject("multicolored"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public SoldierOfThePantheon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SoltariGuerrillas.java b/Mage.Sets/src/mage/cards/s/SoltariGuerrillas.java index 6d45a47b12..7d9fed18c7 100644 --- a/Mage.Sets/src/mage/cards/s/SoltariGuerrillas.java +++ b/Mage.Sets/src/mage/cards/s/SoltariGuerrillas.java @@ -2,6 +2,7 @@ package mage.cards.s; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -23,13 +24,12 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** - * * @author LevelX2 */ public final class SoltariGuerrillas extends CardImpl { public SoltariGuerrillas(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{R}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}"); this.subtype.add(SubType.SOLTARI); this.subtype.add(SubType.SOLDIER); this.power = new MageInt(3); @@ -67,14 +67,16 @@ class SoltariGuerrillasReplacementEffect extends PreventionEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; + return event.getType() == GameEvent.EventType.DAMAGE_PLAYER; } @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getSourceId().equals(source.getSourceId())) { Player controller = game.getPlayer(source.getControllerId()); - return controller.hasOpponent(event.getTargetId(), game); + if (controller != null) { + return controller.hasOpponent(event.getTargetId(), game); + } } return false; } diff --git a/Mage.Sets/src/mage/cards/s/SomberwaldAlpha.java b/Mage.Sets/src/mage/cards/s/SomberwaldAlpha.java index da9c48a8d0..00bc7f78f4 100644 --- a/Mage.Sets/src/mage/cards/s/SomberwaldAlpha.java +++ b/Mage.Sets/src/mage/cards/s/SomberwaldAlpha.java @@ -28,7 +28,7 @@ import mage.target.common.TargetControlledCreaturePermanent; */ public final class SomberwaldAlpha extends CardImpl { - final static private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); + static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/s/SongOfSerenity.java b/Mage.Sets/src/mage/cards/s/SongOfSerenity.java index 2d58303653..cc324767f9 100644 --- a/Mage.Sets/src/mage/cards/s/SongOfSerenity.java +++ b/Mage.Sets/src/mage/cards/s/SongOfSerenity.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -15,8 +13,9 @@ import mage.filter.predicate.permanent.EnchantedPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SongOfSerenity extends CardImpl { @@ -44,7 +43,7 @@ class SongOfSerenityRestrictionEffect extends RestrictionEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); } public SongOfSerenityRestrictionEffect() { @@ -62,12 +61,12 @@ class SongOfSerenityRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/Soothsaying.java b/Mage.Sets/src/mage/cards/s/Soothsaying.java index fe88a0035c..2f67392f25 100644 --- a/Mage.Sets/src/mage/cards/s/Soothsaying.java +++ b/Mage.Sets/src/mage/cards/s/Soothsaying.java @@ -27,7 +27,7 @@ public final class Soothsaying extends CardImpl { this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ShuffleLibrarySourceEffect(), new ManaCostsImpl<>("{3}{U}{U}"))); // {X}: Look at the top X cards of your library, then put them back in any order. - Effect effect = new LookLibraryControllerEffect(new ManacostVariableValue()); + Effect effect = new LookLibraryControllerEffect(ManacostVariableValue.instance); effect.setText("Look at the top X cards of your library, then put them back in any order"); this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl<>("X"))); } diff --git a/Mage.Sets/src/mage/cards/s/SophicCentaur.java b/Mage.Sets/src/mage/cards/s/SophicCentaur.java index d28ffa11af..76ed6c4d03 100644 --- a/Mage.Sets/src/mage/cards/s/SophicCentaur.java +++ b/Mage.Sets/src/mage/cards/s/SophicCentaur.java @@ -33,7 +33,7 @@ public final class SophicCentaur extends CardImpl { this.toughness = new MageInt(1); // {2}{G}{G}, {tap}, Discard a card: You gain 2 life for each card in your hand. - DynamicValue lifeToGainAmount = new MultipliedValue(new CardsInControllerHandCount(), 2); + DynamicValue lifeToGainAmount = new MultipliedValue(CardsInControllerHandCount.instance, 2); Effect effect = new GainLifeEffect(lifeToGainAmount); effect.setText("You gain 2 life for each card in your hand"); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{2}{G}{G}")); diff --git a/Mage.Sets/src/mage/cards/s/SoramaroFirstToDream.java b/Mage.Sets/src/mage/cards/s/SoramaroFirstToDream.java index d197ae5806..62a0867b8b 100644 --- a/Mage.Sets/src/mage/cards/s/SoramaroFirstToDream.java +++ b/Mage.Sets/src/mage/cards/s/SoramaroFirstToDream.java @@ -39,7 +39,7 @@ public final class SoramaroFirstToDream extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); // Soramaro, First to Dream's power and toughness are each equal to the number of cards in your hand. - DynamicValue xValue= new CardsInControllerHandCount(); + DynamicValue xValue= CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame))); // {4}, Return a land you control to its owner's hand: Draw a card. diff --git a/Mage.Sets/src/mage/cards/s/SorceressQueen.java b/Mage.Sets/src/mage/cards/s/SorceressQueen.java index f3b81ce449..e455408d29 100644 --- a/Mage.Sets/src/mage/cards/s/SorceressQueen.java +++ b/Mage.Sets/src/mage/cards/s/SorceressQueen.java @@ -26,7 +26,7 @@ public final class SorceressQueen extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than {this}"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SorceressQueen(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java b/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java index a4d363f8bf..639a1cb10c 100644 --- a/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java +++ b/Mage.Sets/src/mage/cards/s/SorinGrimNemesis.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; @@ -13,24 +12,17 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.cards.*; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.token.VampireKnightToken; import mage.players.Player; import mage.players.PlayerList; import mage.target.common.TargetCreatureOrPlaneswalker; +import java.util.UUID; + /** - * * @author fireshoes */ public final class SorinGrimNemesis extends CardImpl { @@ -90,90 +82,91 @@ class SorinGrimNemesisRevealEffect extends OneShotEffect { if (player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); - cards.add(card); - player.revealCards("Sorin, Grim Nemesis", cards, game); + if (card != null) { + Cards cards = new CardsImpl(); + cards.add(card); + player.revealCards("Sorin, Grim Nemesis", cards, game); - if (card != null - && card.moveToZone(Zone.HAND, source.getSourceId(), game, false)) { - for (UUID playerId : game.getOpponents(source.getControllerId())) { - if (card.getConvertedManaCost() > 0) { - Player opponent = game.getPlayer(playerId); - if (opponent != null) { - opponent.loseLife(card.getConvertedManaCost(), game, false); + if (card.moveToZone(Zone.HAND, source.getSourceId(), game, false)) { + for (UUID playerId : game.getOpponents(source.getControllerId())) { + if (card.getConvertedManaCost() > 0) { + Player opponent = game.getPlayer(playerId); + if (opponent != null) { + opponent.loseLife(card.getConvertedManaCost(), game, false); + } } } + return true; } - return true; } } return false; } } -class SorinXValue implements DynamicValue { + class SorinXValue implements DynamicValue { - private static final SorinXValue defaultValue = new SorinXValue(); + private static final SorinXValue defaultValue = new SorinXValue(); - @Override - public int calculate(Game game, Ability sourceAbility, Effect effect) { - for (Cost cost : sourceAbility.getCosts()) { - if (cost instanceof PayVariableLoyaltyCost) { - return ((PayVariableLoyaltyCost) cost).getAmount(); - } - } - return 0; - } - - @Override - public DynamicValue copy() { - return defaultValue; - } - - @Override - public String getMessage() { - return ""; - } - - @Override - public String toString() { - return "X"; - } - - public static SorinXValue getDefault() { - return defaultValue; - } -} - -class SorinTokenEffect extends OneShotEffect { - - SorinTokenEffect() { - super(Outcome.GainLife); - staticText = "Create a number of 1/1 black Vampire Knight creature tokens with lifelink equal to the highest life total among all players"; - } - - SorinTokenEffect(final SorinTokenEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - int maxLife = 0; - PlayerList playerList = game.getState().getPlayersInRange(source.getControllerId(), game); - for (UUID pid : playerList) { - Player p = game.getPlayer(pid); - if (p != null) { - if (maxLife < p.getLife()) { - maxLife = p.getLife(); + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + for (Cost cost : sourceAbility.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + return ((PayVariableLoyaltyCost) cost).getAmount(); } } + return 0; + } + + @Override + public DynamicValue copy() { + return defaultValue; + } + + @Override + public String getMessage() { + return ""; + } + + @Override + public String toString() { + return "X"; + } + + public static SorinXValue getDefault() { + return defaultValue; } - new CreateTokenEffect(new VampireKnightToken(), maxLife).apply(game, source); - return true; } - @Override - public SorinTokenEffect copy() { - return new SorinTokenEffect(this); + class SorinTokenEffect extends OneShotEffect { + + SorinTokenEffect() { + super(Outcome.GainLife); + staticText = "Create a number of 1/1 black Vampire Knight creature tokens with lifelink equal to the highest life total among all players"; + } + + SorinTokenEffect(final SorinTokenEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + int maxLife = 0; + PlayerList playerList = game.getState().getPlayersInRange(source.getControllerId(), game); + for (UUID pid : playerList) { + Player p = game.getPlayer(pid); + if (p != null) { + if (maxLife < p.getLife()) { + maxLife = p.getLife(); + } + } + } + new CreateTokenEffect(new VampireKnightToken(), maxLife).apply(game, source); + return true; + } + + @Override + public SorinTokenEffect copy() { + return new SorinTokenEffect(this); + } } -} diff --git a/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java b/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java new file mode 100644 index 0000000000..922afbf6eb --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SorinVengefulBloodlord.java @@ -0,0 +1,142 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayVariableLoyaltyCost; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.target.common.TargetPlayerOrPlaneswalker; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SorinVengefulBloodlord extends CardImpl { + + public SorinVengefulBloodlord(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SORIN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // As long as it's your turn, creatures and planeswalkers you control have lifelink. + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A + ), MyTurnCondition.instance, "As long as it's your turn, " + + "creatures and planeswalkers you control have lifelink." + ))); + + // +2: Sorin, Vengeful Bloodlord deals 1 damage to target player or planeswalker. + Ability ability = new LoyaltyAbility(new DamageTargetEffect(1), 2); + ability.addTarget(new TargetPlayerOrPlaneswalker()); + this.addAbility(ability); + + // -X: Return target creature card with converted mana cost X from your graveyard to the battlefield. That creature is a vampire in addition to its other types. + ability = new LoyaltyAbility(new ReturnFromGraveyardToBattlefieldTargetEffect().setText( + "Return target creature card with converted mana cost X from your graveyard to the battlefield." + )); + ability.addEffect(new SorinVengefulBloodlordEffect()); + ability.setTargetAdjuster(SorinVengefulBloodlordAdjuster.instance); + this.addAbility(ability); + } + + private SorinVengefulBloodlord(final SorinVengefulBloodlord card) { + super(card); + } + + @Override + public SorinVengefulBloodlord copy() { + return new SorinVengefulBloodlord(this); + } +} + +enum SorinVengefulBloodlordAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + xValue = ((PayVariableLoyaltyCost) cost).getAmount(); + } + } + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + } +} + +class SorinVengefulBloodlordEffect extends ContinuousEffectImpl { + SorinVengefulBloodlordEffect() { + super(Duration.Custom, Outcome.Neutral); + staticText = "That creature is a vampire in addition to its other types."; + } + + private SorinVengefulBloodlordEffect(final SorinVengefulBloodlordEffect effect) { + super(effect); + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4; + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent creature; + if (source.getTargets().getFirstTarget() == null) { + creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + } else { + creature = game.getPermanent(source.getTargets().getFirstTarget()); + if (creature == null) { + creature = game.getPermanentEntering(source.getTargets().getFirstTarget()); + } + } + if (creature != null) { + if (sublayer == SubLayer.NA) { + if (!creature.hasSubtype(SubType.VAMPIRE, game)) { + creature.getSubtype(game).add(SubType.VAMPIRE); + } + } + return true; + } else { + this.used = true; + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public SorinVengefulBloodlordEffect copy() { + return new SorinVengefulBloodlordEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SorrowsPath.java b/Mage.Sets/src/mage/cards/s/SorrowsPath.java index dc056479a8..ee972bc336 100644 --- a/Mage.Sets/src/mage/cards/s/SorrowsPath.java +++ b/Mage.Sets/src/mage/cards/s/SorrowsPath.java @@ -36,7 +36,7 @@ public final class SorrowsPath extends CardImpl { private static final FilterOpponentsCreaturePermanent filter = new FilterOpponentsCreaturePermanent("blocking creatures an opponent controls"); static { - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } public SorrowsPath(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SosukesSummons.java b/Mage.Sets/src/mage/cards/s/SosukesSummons.java index e5ea61eb3b..8e8de87915 100644 --- a/Mage.Sets/src/mage/cards/s/SosukesSummons.java +++ b/Mage.Sets/src/mage/cards/s/SosukesSummons.java @@ -1,8 +1,7 @@ package mage.cards.s; -import java.util.UUID; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ReturnSourceFromGraveyardToHandEffect; import mage.cards.CardImpl; @@ -16,30 +15,34 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.SnakeToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SosukesSummons extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken Snake"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a nontoken Snake"); static { - filter.add(new SubtypePredicate(SubType.SNAKE)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(new SubtypePredicate(SubType.SNAKE)); + filter.add(Predicates.not(TokenPredicate.instance)); } public SosukesSummons(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); // Create two 1/1 green Snake creature tokens. this.getSpellAbility().addEffect(new CreateTokenEffect(new SnakeToken(), 2)); // Whenever a nontoken Snake enters the battlefield under your control, you may return Sosuke's Summons from your graveyard to your hand. - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(Zone.GRAVEYARD, new ReturnSourceFromGraveyardToHandEffect(), filter, true, false)); - - + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.GRAVEYARD, + new ReturnSourceFromGraveyardToHandEffect(), + filter, + true) + ); } public SosukesSummons(final SosukesSummons card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulBurn.java b/Mage.Sets/src/mage/cards/s/SoulBurn.java index e759b2f18d..7ae356dc11 100644 --- a/Mage.Sets/src/mage/cards/s/SoulBurn.java +++ b/Mage.Sets/src/mage/cards/s/SoulBurn.java @@ -1,27 +1,32 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; import mage.filter.FilterMana; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** * @author Johnny E. Hastings */ public final class SoulBurn extends CardImpl { - static final FilterMana filterBlackOrRed = new FilterMana(); + private static final FilterMana filterBlackOrRed = new FilterMana(); static { filterBlackOrRed.setBlack(true); @@ -29,9 +34,13 @@ public final class SoulBurn extends CardImpl { } public SoulBurn(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{2}{B}"); // Spend only black or red mana on X. + this.addAbility(new SimpleStaticAbility( + Zone.ALL, new InfoEffect("Spend only black or red mana on X")).setRuleAtTheTop(true) + ); + // Soul Burn deals X damage to any target. You gain life equal to the damage dealt for each black mana spent on X; not more life than the player's life total before Soul Burn dealt damage, or the creature's toughness. this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(new SoulBurnEffect()); @@ -41,7 +50,7 @@ public final class SoulBurn extends CardImpl { } } - public SoulBurn(final SoulBurn card) { + private SoulBurn(final SoulBurn card) { super(card); } @@ -53,33 +62,35 @@ public final class SoulBurn extends CardImpl { class SoulBurnEffect extends OneShotEffect { - public SoulBurnEffect() { + SoulBurnEffect() { super(Outcome.Damage); - staticText = "{this} deals X damage to any target for each black or red mana spent on X. You gain life equal to the damage dealt for each black mana spent; not more life than the player's life total before Soul Burn dealt damage, or the creature's toughness."; + staticText = "{this} deals X damage to any target. You gain life equal to the damage dealt, " + + "but not more than the amount of {B} spent on X, the player’s life total before the damage was dealt, " + + "the planeswalker’s loyalty before the damage was dealt, or the creature’s toughness."; } - public SoulBurnEffect(final SoulBurnEffect effect) { + private SoulBurnEffect(final SoulBurnEffect effect) { super(effect); } /*** * @param game * @param source - * @return + * @return */ @Override public boolean apply(Game game, Ability source) { - + // Get the colors we care about. (This isn't racist, honestly.) int amountBlack = source.getManaCostsToPay().getPayment().getBlack(); int amountRed = source.getManaCostsToPay().getPayment().getRed(); - + // Get the colors we don't really care about. (See note above.) int amountWhite = source.getManaCostsToPay().getPayment().getWhite(); int amountGreen = source.getManaCostsToPay().getPayment().getGreen(); int amountBlue = source.getManaCostsToPay().getPayment().getBlue(); int amountColorless = source.getManaCostsToPay().getPayment().getColorless(); - + // Figure out what was spent on the spell in total, determine proper values for // black and red, minus initial casting cost. int totalColorlessForCastingCost = amountWhite + amountGreen + amountBlue + amountColorless; @@ -90,17 +101,17 @@ class SoulBurnEffect extends OneShotEffect { // The game should never let this happen, but I'll check anyway since I don't know // the guts of the game [yet]. amountOffsetByColorless = 2; - } + } } - + // Remove 1 black to account for casting cost. amountBlack--; - + // Determine if we need to offset the red or black values any further due to the // amount of non-red and non-black paid. if (amountOffsetByColorless < 2) { int amountToOffsetBy = 2 - amountOffsetByColorless; - + if (amountRed > 0) { if (amountRed >= amountToOffsetBy) { // Pay all additional unpaid casting cost with red. @@ -118,35 +129,36 @@ class SoulBurnEffect extends OneShotEffect { amountBlack = amountBlack - amountToOffsetBy; } } - + int totalXAmount = amountBlack + amountRed; - + int lifetogain = amountBlack; - if (totalXAmount > 0) { - Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null ) { - if (permanent.getToughness().getValue() < lifetogain) { - lifetogain = permanent.getToughness().getValue(); - } - permanent.damage(totalXAmount, source.getSourceId(), game, false, true); - } else { - Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (player != null) { - if (player.getLife() < lifetogain) { - lifetogain = player.getLife(); - } - player.damage(totalXAmount, source.getSourceId(), game, false, true); - } else { - return false; - } - } - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.gainLife(lifetogain, game, source); + if (totalXAmount == 0) { + return false; + } + Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + if (permanent.isCreature()) { + lifetogain = Math.min(permanent.getToughness().getValue(), lifetogain); + } else if (permanent.isPlaneswalker()) { + lifetogain = Math.min(permanent.getCounters(game).getCount(CounterType.LOYALTY), lifetogain); } else { return false; } + permanent.damage(totalXAmount, source.getSourceId(), game); + } else { + Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); + if (player == null) { + return false; + } + lifetogain = Math.min(player.getLife(), lifetogain); + player.damage(totalXAmount, source.getSourceId(), game); } + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + controller.gainLife(lifetogain, game, source); return true; } diff --git a/Mage.Sets/src/mage/cards/s/SoulDiviner.java b/Mage.Sets/src/mage/cards/s/SoulDiviner.java new file mode 100644 index 0000000000..0b02ccf33d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulDiviner.java @@ -0,0 +1,62 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.RemoveCounterCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SoulDiviner extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("an artifact, creature, land, or planeswalker you control"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public SoulDiviner(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {T}, Remove a counter from an artifact, creature, land, or planeswalker you control: Draw a card. + Ability ability = new SimpleActivatedAbility( + new DrawCardSourceControllerEffect(1), new TapSourceCost() + ); + ability.addCost(new RemoveCounterCost(new TargetPermanent(filter))); + this.addAbility(ability); + } + + private SoulDiviner(final SoulDiviner card) { + super(card); + } + + @Override + public SoulDiviner copy() { + return new SoulDiviner(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulManipulation.java b/Mage.Sets/src/mage/cards/s/SoulManipulation.java index c3e1201842..9341546527 100644 --- a/Mage.Sets/src/mage/cards/s/SoulManipulation.java +++ b/Mage.Sets/src/mage/cards/s/SoulManipulation.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; @@ -12,8 +10,9 @@ import mage.filter.StaticFilters; import mage.target.TargetSpell; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SoulManipulation extends CardImpl { @@ -27,12 +26,12 @@ public final class SoulManipulation extends CardImpl { // Counter target creature spell; this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE)); + this.getSpellAbility().addTarget(new TargetSpell(StaticFilters.FILTER_SPELL_CREATURE).withChooseHint("counter it")); // and/or return target creature card from your graveyard to your hand. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD).withChooseHint("return it to hand")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SoulOfTheHarvest.java b/Mage.Sets/src/mage/cards/s/SoulOfTheHarvest.java index 76a157f25d..da6115bfce 100644 --- a/Mage.Sets/src/mage/cards/s/SoulOfTheHarvest.java +++ b/Mage.Sets/src/mage/cards/s/SoulOfTheHarvest.java @@ -25,8 +25,8 @@ public final class SoulOfTheHarvest extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("another nontoken creature"); static { - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public SoulOfTheHarvest(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SoulReap.java b/Mage.Sets/src/mage/cards/s/SoulReap.java index bd70f570e8..d0b9a7d1df 100644 --- a/Mage.Sets/src/mage/cards/s/SoulReap.java +++ b/Mage.Sets/src/mage/cards/s/SoulReap.java @@ -65,7 +65,7 @@ class CastBlackSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SoulReapWatcher watcher = (SoulReapWatcher) game.getState().getWatchers().get(SoulReapWatcher.class.getSimpleName(), source.getControllerId()); + SoulReapWatcher watcher = game.getState().getWatcher(SoulReapWatcher.class, source.getControllerId()); if (watcher != null) { return watcher.conditionMet(); } @@ -84,7 +84,7 @@ class SoulReapWatcher extends Watcher { private UUID cardId; public SoulReapWatcher(UUID cardId) { - super(SoulReapWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); this.cardId = cardId; } diff --git a/Mage.Sets/src/mage/cards/s/SoulSculptor.java b/Mage.Sets/src/mage/cards/s/SoulSculptor.java new file mode 100644 index 0000000000..f82ccd16f1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulSculptor.java @@ -0,0 +1,149 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class SoulSculptor extends CardImpl { + + final String rule = "Target creature becomes an enchantment and loses all abilities until a player casts a creature spell."; + + public SoulSculptor(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // {1}{W}, {tap}: Target creature becomes an enchantment and loses all abilities until a player casts a creature spell. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new SoulSculptorEffect(), SoulSculptorCondition.instance, rule), new ManaCostsImpl("{1}{W}")); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + + } + + public SoulSculptor(final SoulSculptor card) { + super(card); + } + + @Override + public SoulSculptor copy() { + return new SoulSculptor(this); + } +} + +class SoulSculptorEffect extends ContinuousEffectImpl { + + public SoulSculptorEffect() { + super(Duration.Custom, Outcome.LoseAbility); + staticText = "target becomes an Enchantment and loses all abilites"; + dependencyTypes.add(DependencyType.EnchantmentAddingRemoving); + dependencyTypes.add(DependencyType.AddingAbility); + + } + + public SoulSculptorEffect(final SoulSculptorEffect effect) { + super(effect); + } + + @Override + public SoulSculptorEffect copy() { + return new SoulSculptorEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + Permanent targetPermanent = game.getPermanent(source.getFirstTarget()); + if (targetPermanent != null) { + affectedObjectList.add(new MageObjectReference(targetPermanent, game)); + } + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = affectedObjectList.get(0).getPermanent(game); + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + permanent.getCardType().clear(); + permanent.getSubtype(game).clear(); + if (!permanent.getCardType().contains(CardType.ENCHANTMENT)) { + permanent.getCardType().add(CardType.ENCHANTMENT); + } + } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + permanent.getAbilities().clear(); + } + break; + } + return true; + } + this.discard(); + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return Layer.TypeChangingEffects_4 == layer + || Layer.AbilityAddingRemovingEffects_6 == layer; + } + +} + +enum SoulSculptorCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (!game.getStack().isEmpty()) { + StackObject stackObject = game.getStack().getFirst(); + if (stackObject != null) { + return !stackObject.getCardType().contains(CardType.CREATURE); + } + } + return true; + } + + @Override + public String toString() { + return "creature spell cast"; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SoulSeizer.java b/Mage.Sets/src/mage/cards/s/SoulSeizer.java index f578200ea0..c525664df3 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSeizer.java +++ b/Mage.Sets/src/mage/cards/s/SoulSeizer.java @@ -115,7 +115,7 @@ class SoulSeizerEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null && permanent.isTransformable()) { if (permanent.transform(game)) { - game.informPlayers(new StringBuilder(permanent.getName()).append(" transforms into ").append(permanent.getSecondCardFace().getName()).toString()); + game.informPlayers(permanent.getName() + " transforms into " + permanent.getSecondCardFace().getName()); Permanent attachTo = game.getPermanent(targetPointer.getFirst(game, source)); if (attachTo != null) { return attachTo.addAttachment(source.getSourceId(), game); diff --git a/Mage.Sets/src/mage/cards/s/SoulSnare.java b/Mage.Sets/src/mage/cards/s/SoulSnare.java index 27b5e19b93..375944152d 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSnare.java +++ b/Mage.Sets/src/mage/cards/s/SoulSnare.java @@ -11,7 +11,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; /** diff --git a/Mage.Sets/src/mage/cards/s/SoulStrings.java b/Mage.Sets/src/mage/cards/s/SoulStrings.java new file mode 100644 index 0000000000..5ae9b10d29 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulStrings.java @@ -0,0 +1,39 @@ +package mage.cards.s; + +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DoUnlessAnyPlayerPaysEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.common.FilterCreatureCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.ManacostVariableValue; + +/** + * @author jmharmon + */ + +public final class SoulStrings extends CardImpl { + + public SoulStrings(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}"); + + // Return two target creature cards from your graveyard to your hand unless any player pays {X}. + Effect effect = new DoUnlessAnyPlayerPaysEffect( + new ReturnFromGraveyardToHandTargetEffect(), ManacostVariableValue.instance); + this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(2, new FilterCreatureCard("creature cards from your graveyard"))); + } + + public SoulStrings(final SoulStrings card) { + super(card); + } + + @Override + public SoulStrings copy() { + return new SoulStrings(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulSwallower.java b/Mage.Sets/src/mage/cards/s/SoulSwallower.java index db981fbebb..d6ea2417b5 100644 --- a/Mage.Sets/src/mage/cards/s/SoulSwallower.java +++ b/Mage.Sets/src/mage/cards/s/SoulSwallower.java @@ -1,12 +1,13 @@ - package mage.cards.s; import java.util.UUID; + import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,13 +18,12 @@ import mage.constants.Zone; import mage.counters.CounterType; /** - * * @author fireshoes */ public final class SoulSwallower extends CardImpl { public SoulSwallower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}"); this.subtype.add(SubType.WURM); this.power = new MageInt(3); this.toughness = new MageInt(3); @@ -36,7 +36,8 @@ public final class SoulSwallower extends CardImpl { new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(3)), TargetController.YOU, false), DeliriumCondition.instance, "Delirium — At the beginning of your upkeep, if there are four or more card types among cards in your graveyard, " - + "put three +1/+1 counters on Soul Swallower.")); + + "put three +1/+1 counters on Soul Swallower.") + .addHint(DeliriumHint.instance)); } public SoulSwallower(final SoulSwallower card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulWarden.java b/Mage.Sets/src/mage/cards/s/SoulWarden.java index 79c309845f..c95ae0e875 100644 --- a/Mage.Sets/src/mage/cards/s/SoulWarden.java +++ b/Mage.Sets/src/mage/cards/s/SoulWarden.java @@ -22,7 +22,7 @@ public final class SoulWarden extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SoulWarden(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SoulcatchersAerie.java b/Mage.Sets/src/mage/cards/s/SoulcatchersAerie.java index 6b82168d40..aec13a77cf 100644 --- a/Mage.Sets/src/mage/cards/s/SoulcatchersAerie.java +++ b/Mage.Sets/src/mage/cards/s/SoulcatchersAerie.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.common.PutIntoGraveFromBattlefieldAllTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.dynamicvalue.common.CountersSourceCount; @@ -18,8 +16,9 @@ import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; +import java.util.UUID; + /** - * * @author LoneFox */ public final class SoulcatchersAerie extends CardImpl { @@ -33,15 +32,16 @@ public final class SoulcatchersAerie extends CardImpl { } public SoulcatchersAerie(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // Whenever a Bird is put into your graveyard from the battlefield, put a feather counter on Soulcatchers' Aerie. this.addAbility(new PutIntoGraveFromBattlefieldAllTriggeredAbility(new AddCountersSourceEffect(CounterType.FEATHER.createInstance()), - false, filter, false, true)); + false, filter, false, true)); + // Bird creatures get +1/+1 for each feather counter on Soulcatchers' Aerie. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(new CountersSourceCount(CounterType.FEATHER), - new CountersSourceCount(CounterType.FEATHER), Duration.WhileOnBattlefield, filter2, false, - "Bird creatures get +1/+1 for each feather counter on {this}."))); + new CountersSourceCount(CounterType.FEATHER), Duration.WhileOnBattlefield, filter2, false, + "Bird creatures get +1/+1 for each feather counter on {this}."))); } public SoulcatchersAerie(final SoulcatchersAerie card) { diff --git a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java index abd70447d8..e567d41558 100644 --- a/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java +++ b/Mage.Sets/src/mage/cards/s/SoulfireGrandMaster.java @@ -1,14 +1,11 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.GainAbilitySpellsEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -16,13 +13,7 @@ import mage.abilities.keyword.LifelinkAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.FilterObject; import mage.filter.predicate.Predicates; @@ -30,13 +21,12 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; import mage.game.stack.Spell; -import mage.game.stack.StackObject; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SoulfireGrandMaster extends CardImpl { @@ -111,7 +101,7 @@ class SoulfireGrandMasterCastFromHandReplacementEffect extends ReplacementEffect @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { MageObject mageObject = game.getObject(spellId); - if (!(mageObject instanceof Spell) || ((Spell) mageObject).isCopiedSpell()) { + if (!(mageObject instanceof Spell) || mageObject.isCopy()) { return false; } else { Card sourceCard = game.getCard(spellId); diff --git a/Mage.Sets/src/mage/cards/s/Soulflayer.java b/Mage.Sets/src/mage/cards/s/Soulflayer.java index 62a492f357..2195981e79 100644 --- a/Mage.Sets/src/mage/cards/s/Soulflayer.java +++ b/Mage.Sets/src/mage/cards/s/Soulflayer.java @@ -1,44 +1,26 @@ - package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.continuous.SourceEffect; -import mage.abilities.keyword.DeathtouchAbility; -import mage.abilities.keyword.DelveAbility; -import mage.abilities.keyword.DoubleStrikeAbility; -import mage.abilities.keyword.FirstStrikeAbility; -import mage.abilities.keyword.FlyingAbility; -import mage.abilities.keyword.HasteAbility; -import mage.abilities.keyword.HexproofAbility; -import mage.abilities.keyword.IndestructibleAbility; -import mage.abilities.keyword.LifelinkAbility; -import mage.abilities.keyword.ReachAbility; -import mage.abilities.keyword.TrampleAbility; -import mage.abilities.keyword.VigilanceAbility; +import mage.abilities.keyword.*; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.CardUtil; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Soulflayer extends CardImpl { @@ -82,7 +64,9 @@ class SoulflayerEffect extends ContinuousEffectImpl implements SourceEffect { super(effect); if (effect.abilitiesToAdd != null) { this.abilitiesToAdd = new HashSet<>(); - this.abilitiesToAdd.addAll(effect.abilitiesToAdd); + for (Ability a : effect.abilitiesToAdd) { + this.abilitiesToAdd.add(a.copy()); + } } this.objectReference = effect.objectReference; } @@ -96,6 +80,7 @@ class SoulflayerEffect extends ContinuousEffectImpl implements SourceEffect { public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { + // one time abilities collect if (objectReference == null || !objectReference.refersTo(permanent, game)) { abilitiesToAdd = new HashSet<>(); this.objectReference = new MageObjectReference(permanent, game); @@ -144,6 +129,8 @@ class SoulflayerEffect extends ContinuousEffectImpl implements SourceEffect { } } } + + // all time abilities apply for (Ability ability : abilitiesToAdd) { permanent.addAbility(ability, source.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java new file mode 100644 index 0000000000..dba46f380c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SoulhunterRakshasa.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.CantBlockAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.target.common.TargetOpponentOrPlaneswalker; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class SoulhunterRakshasa extends CardImpl { + + public SoulhunterRakshasa(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}"); + this.subtype.add(SubType.CAT, SubType.DEMON); + + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Soulhunter Rakshasa can’t block. + this.addAbility(new CantBlockAbility()); + + // When Soulhunter Rakshasa enters the battlefield, it deals 5 damage to target opponent. + Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5, "it"), false); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + public SoulhunterRakshasa(final SoulhunterRakshasa card) { + super(card); + } + + @Override + public SoulhunterRakshasa copy() { + return new SoulhunterRakshasa(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulsAttendant.java b/Mage.Sets/src/mage/cards/s/SoulsAttendant.java index fc40b46303..fbdc7aeb6c 100644 --- a/Mage.Sets/src/mage/cards/s/SoulsAttendant.java +++ b/Mage.Sets/src/mage/cards/s/SoulsAttendant.java @@ -22,7 +22,7 @@ public final class SoulsAttendant extends CardImpl { private static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SoulsAttendant(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/Soulshriek.java b/Mage.Sets/src/mage/cards/s/Soulshriek.java new file mode 100644 index 0000000000..93dc244d8a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Soulshriek.java @@ -0,0 +1,83 @@ +package mage.cards.s; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.SacrificeTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.targetpointer.FixedTarget; + +/* + * + * @author Ketsuban + */ +public class Soulshriek extends CardImpl { + + protected static final FilterCard filterCard = new FilterCard("creature cards"); + + static { + filterCard.add(new CardTypePredicate(CardType.CREATURE)); + } + + public Soulshriek(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}"); + + // Target creature you control gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. Sacrifice that creature at the beginning of the next end step. + this.getSpellAbility().addEffect(new SoulshriekEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + @Override + public Card copy() { + return null; + } +} + +class SoulshriekEffect extends OneShotEffect { + + public SoulshriekEffect() { + super(Outcome.DestroyPermanent); + this.staticText = "Target creature you control gets +X/+0 until end of turn, where X is the number of creature cards in your graveyard. Sacrifice that creature at the beginning of the next end step"; + } + + public SoulshriekEffect(final SoulshriekEffect effect) { + super(effect); + } + + @Override + public SoulshriekEffect copy() { + return new SoulshriekEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent != null) { + ContinuousEffect boost = new BoostTargetEffect(new CardsInControllerGraveyardCount(Soulshriek.filterCard), new StaticValue(0), Duration.EndOfTurn); + boost.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(boost, source); + Effect sacrifice = new SacrificeTargetEffect("Sacrifice that creature at the beginning of the next end step", source.getControllerId()); + sacrifice.setTargetPointer(new FixedTarget(permanent, game)); + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(sacrifice), source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SoulsurgeElemental.java b/Mage.Sets/src/mage/cards/s/SoulsurgeElemental.java index 6265728549..30c73c3ec6 100644 --- a/Mage.Sets/src/mage/cards/s/SoulsurgeElemental.java +++ b/Mage.Sets/src/mage/cards/s/SoulsurgeElemental.java @@ -1,29 +1,28 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.SetPowerSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.FirstStrikeAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author Loki */ public final class SoulsurgeElemental extends CardImpl { public SoulsurgeElemental(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(0); @@ -33,8 +32,9 @@ public final class SoulsurgeElemental extends CardImpl { this.addAbility(FirstStrikeAbility.getInstance()); // Soulsurge Elemental's power is equal to the number of creatures you control. - Effect effect = new SetPowerSourceEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent("creatures you control")), Duration.EndOfGame); - this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); + Effect effect = new SetPowerSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame); + this.addAbility(new SimpleStaticAbility(Zone.ALL, effect) + .addHint(CreaturesYouControlHint.instance)); } public SoulsurgeElemental(final SoulsurgeElemental card) { diff --git a/Mage.Sets/src/mage/cards/s/SoultetherGolem.java b/Mage.Sets/src/mage/cards/s/SoultetherGolem.java index 7028c37c7f..3c449c8770 100644 --- a/Mage.Sets/src/mage/cards/s/SoultetherGolem.java +++ b/Mage.Sets/src/mage/cards/s/SoultetherGolem.java @@ -26,11 +26,11 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class SoultetherGolem extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SoultetherGolem(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java b/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java index bf9a5c6d90..14990a29f0 100644 --- a/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java +++ b/Mage.Sets/src/mage/cards/s/SovereignsOfLostAlara.java @@ -114,7 +114,7 @@ class SovereignsOfLostAlaraEffect extends OneShotEffect { if (controller.chooseUse(Outcome.Benefit, "Do you want to search your library?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(filter); target.setNotTarget(true); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (target.getFirstTarget() != null) { Card aura = game.getCard(target.getFirstTarget()); game.getState().setValue("attachTo:" + aura.getId(), attackingCreature); diff --git a/Mage.Sets/src/mage/cards/s/SparkDouble.java b/Mage.Sets/src/mage/cards/s/SparkDouble.java new file mode 100644 index 0000000000..b036665e2f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparkDouble.java @@ -0,0 +1,105 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CopyPermanentEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.util.functions.ApplyToPermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class SparkDouble extends CardImpl { + + private static FilterPermanent filter = new FilterControlledPermanent("a creature or planeswalker you control"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER))); + } + + public SparkDouble(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // You may have Spark Double enter the battlefield as a copy of a creature or planeswalker you control, + // except it enters with an additional +1/+1 counter on it if it’s a creature, + // it enters with an additional loyalty counter on it if it’s a planeswalker, and it isn’t legendary if that permanent is legendary. + Effect effect = new CopyPermanentEffect(filter, new SparkDoubleExceptEffectsApplyerToPermanent()); + effect.setText("as a copy of a creature or planeswalker you control, " + + "except it enters with an additional +1/+1 counter on it if it’s a creature, " + + "it enters with an additional loyalty counter on it if it’s a planeswalker, and it isn’t legendary if that permanent is legendary."); + EntersBattlefieldAbility ability = new EntersBattlefieldAbility(effect, true); + this.addAbility(ability); + } + + public SparkDouble(final SparkDouble card) { + super(card); + } + + @Override + public SparkDouble copy() { + return new SparkDouble(this); + } +} + +class SparkDoubleExceptEffectsApplyerToPermanent extends ApplyToPermanent { + + @Override + public boolean apply(Game game, Permanent copyFromBlueprint, Ability source, UUID copyToObjectId) { + return apply(game, (MageObject) copyFromBlueprint, source, copyToObjectId); + } + + @Override + public boolean apply(Game game, MageObject copyFromBlueprint, Ability source, UUID copyToObjectId) { + Permanent destCard = game.getPermanentEntering(copyToObjectId); + if (destCard == null) { + return false; + } + + // it isn’t legendary if that permanent is legendary + copyFromBlueprint.getSuperType().remove(SuperType.LEGENDARY); + + // TODO: Blood Moon problem, can't apply on type changing effects (same as TeferisTimeTwist) + // see https://magic.wizards.com/en/articles/archive/feature/war-spark-release-notes-2019-04-19 + // If the copied permanent is affected by a type-changing effect, Spark Double may enter the battlefield with + // different permanent types than the copied permanent currently has. Use the characteristics of Spark Double as + // it enters the battlefield, not of the copied permanent, to determine whether it enters with an additional + // counter on it. Notably, if Spark Double copies a Gideon planeswalker that's a creature because its loyalty + // ability caused it to become a planeswalker creature, Spark Double enters as a noncreature planeswalker and + // doesn't get a +1/+1 counter. On the other hand, if Spark Double copies Gideon Blackblade during your turn, + // Spark Double enters as a planeswalker creature and gets both kinds of counters. + + // enters with an additional +1/+1 counter on it if it’s a creature + if (copyFromBlueprint.isCreature()) { + destCard.addCounters(CounterType.P1P1.createInstance(), source, game); + } + + // enters with an additional loyalty counter on it if it’s a planeswalker + if (copyFromBlueprint.isPlaneswalker()) { + destCard.addCounters(CounterType.LOYALTY.createInstance(), source, game); + } + + return true; + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SparkHarvest.java b/Mage.Sets/src/mage/cards/s/SparkHarvest.java new file mode 100644 index 0000000000..39c55762c6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparkHarvest.java @@ -0,0 +1,42 @@ +package mage.cards.s; + +import mage.abilities.costs.OrCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreatureOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SparkHarvest extends CardImpl { + + public SparkHarvest(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}"); + + // As an additional cost to cast this spell, sacrifice a creature or pay {3}{B}. + this.getSpellAbility().addCost(new OrCost( + new SacrificeTargetCost(new TargetControlledCreaturePermanent()), + new ManaCostsImpl("{3}{B}"), "sacrifice a creature or pay {3}{B}" + )); + + // Destroy target creature or planeswalker. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker()); + } + + private SparkHarvest(final SparkHarvest card) { + super(card); + } + + @Override + public SparkHarvest copy() { + return new SparkHarvest(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SparkReaper.java b/Mage.Sets/src/mage/cards/s/SparkReaper.java new file mode 100644 index 0000000000..da57ae0a3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SparkReaper.java @@ -0,0 +1,58 @@ +package mage.cards.s; + +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.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SparkReaper extends CardImpl { + + private static final FilterControlledPermanent filter + = new FilterControlledPermanent("a creature or planeswalker"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + } + + public SparkReaper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {3}, Sacrifice a creature or planeswalker: You gain 1 life and draw a card. + Ability ability = new SimpleActivatedAbility(new GainLifeEffect(1), new GenericManaCost(3)); + ability.addEffect(new DrawCardSourceControllerEffect(1).concatBy("and")); + ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); + this.addAbility(ability); + } + + private SparkReaper(final SparkReaper card) { + super(card); + } + + @Override + public SparkReaper copy() { + return new SparkReaper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpawnOfMayhem.java b/Mage.Sets/src/mage/cards/s/SpawnOfMayhem.java new file mode 100644 index 0000000000..3e0215662e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpawnOfMayhem.java @@ -0,0 +1,94 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.SpectacleAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.counters.CounterType; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpawnOfMayhem extends CardImpl { + + public SpawnOfMayhem(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}{B}"); + + this.subtype.add(SubType.DEMON); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // Spectacle {1}{B}{B} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{1}{B}{B}"))); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // At the beginning of your upkeep, Spawn of Mayhem deals 1 damage to each player. Then if you have 10 or less life, put a +1/+1 counter on Spawn of Mayhem. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new DamagePlayersEffect(1, TargetController.ANY), + TargetController.YOU, false + ); + ability.addEffect(new SpawnOfMayhemEffect()); + this.addAbility(ability); + } + + private SpawnOfMayhem(final SpawnOfMayhem card) { + super(card); + } + + @Override + public SpawnOfMayhem copy() { + return new SpawnOfMayhem(this); + } +} + +class SpawnOfMayhemEffect extends OneShotEffect { + + SpawnOfMayhemEffect() { + super(Outcome.Benefit); + staticText = "Then if you have 10 or less life, put a +1/+1 counter on {this}."; + } + + private SpawnOfMayhemEffect(final SpawnOfMayhemEffect effect) { + super(effect); + } + + @Override + public SpawnOfMayhemEffect copy() { + return new SpawnOfMayhemEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (player.getLife() < 11) { + return new AddCountersSourceEffect( + CounterType.P1P1.createInstance() + ).apply(game, source); + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SpawnbinderMage.java b/Mage.Sets/src/mage/cards/s/SpawnbinderMage.java index a14197c7d7..1a163c26c7 100644 --- a/Mage.Sets/src/mage/cards/s/SpawnbinderMage.java +++ b/Mage.Sets/src/mage/cards/s/SpawnbinderMage.java @@ -31,7 +31,7 @@ public final class SpawnbinderMage extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SpawnbinderMage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/Spawnbroker.java b/Mage.Sets/src/mage/cards/s/Spawnbroker.java index 822f3cafbe..1d83a023cd 100644 --- a/Mage.Sets/src/mage/cards/s/Spawnbroker.java +++ b/Mage.Sets/src/mage/cards/s/Spawnbroker.java @@ -69,18 +69,15 @@ class TargetControlledCreatureWithPowerGreaterOrLessThanOpponentPermanent extend super(target); } - @Override - public boolean canTarget(UUID controllerId, UUID id, Ability source, Game game) { - return super.canTarget(controllerId, id, source, game); - } - @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - possibleTargets.add(permanent.getId()); + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + possibleTargets.add(permanent.getId()); + } } } return possibleTargets; @@ -126,10 +123,12 @@ class SpawnbrokerSecondTarget extends TargetPermanent { Set possibleTargets = new HashSet<>(); if (firstTarget != null) { MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if (firstTarget.getPower().getValue() >= permanent.getPower().getValue()) { - possibleTargets.add(permanent.getId()); + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (!targets.containsKey(permanent.getId()) && permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (firstTarget.getPower().getValue() >= permanent.getPower().getValue()) { + possibleTargets.add(permanent.getId()); + } } } } diff --git a/Mage.Sets/src/mage/cards/s/SpearSpewer.java b/Mage.Sets/src/mage/cards/s/SpearSpewer.java new file mode 100644 index 0000000000..2dbb8527dc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpearSpewer.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.keyword.DefenderAbility; +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 SpearSpewer extends CardImpl { + + public SpearSpewer(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(0); + this.toughness = new MageInt(2); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // {T}: Spear Spewer deals 1 damage to each player. + this.addAbility(new SimpleActivatedAbility(new DamagePlayersEffect(1), new TapSourceCost())); + } + + private SpearSpewer(final SpearSpewer card) { + super(card); + } + + @Override + public SpearSpewer copy() { + return new SpearSpewer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpectralBears.java b/Mage.Sets/src/mage/cards/s/SpectralBears.java index e4440f2419..20790a16bc 100644 --- a/Mage.Sets/src/mage/cards/s/SpectralBears.java +++ b/Mage.Sets/src/mage/cards/s/SpectralBears.java @@ -52,7 +52,7 @@ class SpectralBearsTriggeredAbility extends TriggeredAbilityImpl { static { filter.add(new ColorPredicate(ObjectColor.BLACK)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public SpectralBearsTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/s/SpellBlast.java b/Mage.Sets/src/mage/cards/s/SpellBlast.java index 36a131fdb2..85337f0ce5 100644 --- a/Mage.Sets/src/mage/cards/s/SpellBlast.java +++ b/Mage.Sets/src/mage/cards/s/SpellBlast.java @@ -1,9 +1,7 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.CounterTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -12,24 +10,22 @@ import mage.constants.ComparisonType; import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; -import mage.target.Target; import mage.target.TargetSpell; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SpellBlast extends CardImpl { - private static final FilterSpell filter = new FilterSpell("spell with converted mana cost X"); - public SpellBlast(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); // Counter target spell with converted mana cost X. - this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetSpell(filter)); + this.getSpellAbility().addEffect(new CounterTargetEffect().setText("counter target spell with converted mana cost X")); + this.getSpellAbility().setTargetAdjuster(SpellBlastAdjuster.instance); } public SpellBlast(final SpellBlast card) { @@ -40,17 +36,17 @@ public final class SpellBlast extends CardImpl { public SpellBlast copy() { return new SpellBlast(this); } +} + +enum SpellBlastAdjuster implements TargetAdjuster { + instance; @Override public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - FilterSpell newfilter = new FilterSpell(new StringBuilder("spell with converted mana cost ").append(xValue).toString()); - newfilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); - Target target = new TargetSpell(newfilter); - ability.addTarget(target); - } - + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + FilterSpell filter = new FilterSpell("spell with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetSpell(filter)); } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SpellBurst.java b/Mage.Sets/src/mage/cards/s/SpellBurst.java index 35d8c2a6cc..7c2cae1ae7 100644 --- a/Mage.Sets/src/mage/cards/s/SpellBurst.java +++ b/Mage.Sets/src/mage/cards/s/SpellBurst.java @@ -1,9 +1,7 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.keyword.BuybackAbility; import mage.cards.CardImpl; @@ -14,6 +12,9 @@ import mage.filter.FilterSpell; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.TargetSpell; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** * @author LevelX2 @@ -23,23 +24,12 @@ public final class SpellBurst extends CardImpl { public SpellBurst(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{U}"); - // Buyback {3} this.addAbility(new BuybackAbility("{3}")); // Counter target spell with converted mana cost X. - this.getSpellAbility().addEffect(new CounterTargetEffect()); - this.getSpellAbility().addTarget(new TargetSpell(new FilterSpell("spell with converted mana cost X"))); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - FilterSpell filter = new FilterSpell("spell with converted mana cost X"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, ability.getManaCostsToPay().getX())); - ability.addTarget(new TargetSpell(filter)); - } + this.getSpellAbility().addEffect(new CounterTargetEffect().setText("counter target spell with converted mana cost X")); + this.getSpellAbility().setTargetAdjuster(SpellBurstAdjuster.instance); } public SpellBurst(final SpellBurst card) { @@ -51,3 +41,16 @@ public final class SpellBurst extends CardImpl { return new SpellBurst(this); } } + +enum SpellBurstAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int xValue = ability.getManaCostsToPay().getX(); + ability.getTargets().clear(); + FilterSpell filter = new FilterSpell("spell with converted mana cost " + xValue); + filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, xValue)); + ability.addTarget(new TargetSpell(filter)); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpellContortion.java b/Mage.Sets/src/mage/cards/s/SpellContortion.java index 208f327bd2..fd89cb7298 100644 --- a/Mage.Sets/src/mage/cards/s/SpellContortion.java +++ b/Mage.Sets/src/mage/cards/s/SpellContortion.java @@ -4,6 +4,7 @@ package mage.cards.s; import java.util.ArrayList; import java.util.List; import java.util.UUID; + import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.common.CounterUnlessPaysEffect; @@ -15,23 +16,21 @@ import mage.constants.CardType; import mage.target.TargetSpell; /** - * * @author jeffwadsworth */ public final class SpellContortion extends CardImpl { public SpellContortion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{U}"); // Multikicker {1}{U} this.addAbility(new MultikickerAbility("{1}{U}")); - + // Counter target spell unless its controller pays {2}. Draw a card for each time Spell Contortion was kicked. this.getSpellAbility().addEffect(new CounterUnlessPaysEffect(new GenericManaCost(2))); - this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(new MultikickerCount())); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(MultikickerCount.instance)); this.getSpellAbility().addTarget(new TargetSpell()); - } public SpellContortion(final SpellContortion card) { @@ -42,11 +41,4 @@ public final class SpellContortion extends CardImpl { public SpellContortion copy() { return new SpellContortion(this); } - - @Override - public List getRules() { - List rules = new ArrayList<>(); - rules.add("Counter target spell unless its controller pays {2}. Draw a card for each time Spell Contortion was kicked."); - return rules; - } } diff --git a/Mage.Sets/src/mage/cards/s/SpellQueller.java b/Mage.Sets/src/mage/cards/s/SpellQueller.java index c4a1fb4c42..4077e32f87 100644 --- a/Mage.Sets/src/mage/cards/s/SpellQueller.java +++ b/Mage.Sets/src/mage/cards/s/SpellQueller.java @@ -37,7 +37,7 @@ import org.apache.log4j.Logger; */ public final class SpellQueller extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell with converted mana cost 4 or less"); + private static final FilterSpell filter = new FilterSpell("spell with converted mana cost 4 or less"); static { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 5)); diff --git a/Mage.Sets/src/mage/cards/s/SpellRupture.java b/Mage.Sets/src/mage/cards/s/SpellRupture.java index 2be94526f5..81470aec9c 100644 --- a/Mage.Sets/src/mage/cards/s/SpellRupture.java +++ b/Mage.Sets/src/mage/cards/s/SpellRupture.java @@ -76,7 +76,7 @@ class SpellRuptureCounterUnlessPaysEffect extends OneShotEffect { } if (!cost.isPaid()) { if (game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { - game.informPlayers(new StringBuilder(sourceObject.getName()).append(": cost wasn't payed - countering ").append(spell.getName()).toString()); + game.informPlayers(sourceObject.getName() + ": cost wasn't payed - countering " + spell.getName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SpellShrivel.java b/Mage.Sets/src/mage/cards/s/SpellShrivel.java index 6ab606a199..bd58d7ab54 100644 --- a/Mage.Sets/src/mage/cards/s/SpellShrivel.java +++ b/Mage.Sets/src/mage/cards/s/SpellShrivel.java @@ -76,7 +76,7 @@ class SpellShrivelCounterUnlessPaysEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, source.getFirstTarget(), source.getSourceId(), stackObject.getControllerId()))) { game.informPlayers(sourceObject.getIdName() + ": cost wasn't payed - countering " + stackObject.getName()); - game.rememberLKI(source.getFirstTarget(), Zone.STACK, (Spell) stackObject); + game.rememberLKI(source.getFirstTarget(), Zone.STACK, stackObject); controller.moveCards((Spell) spell, Zone.EXILED, source, game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, source.getFirstTarget(), source.getSourceId(), stackObject.getControllerId())); return true; diff --git a/Mage.Sets/src/mage/cards/s/Spellbinder.java b/Mage.Sets/src/mage/cards/s/Spellbinder.java index 4782c704a0..bdedc54d13 100644 --- a/Mage.Sets/src/mage/cards/s/Spellbinder.java +++ b/Mage.Sets/src/mage/cards/s/Spellbinder.java @@ -165,7 +165,7 @@ class SpellbinderCopyEffect extends OneShotEffect { if (spellbinder != null && spellbinder.getImprinted() != null && !spellbinder.getImprinted().isEmpty()) { Card imprintedInstant = game.getCard(spellbinder.getImprinted().get(0)); if (imprintedInstant != null && game.getState().getZone(imprintedInstant.getId()) == Zone.EXILED) { - if (controller.chooseUse(outcome, new StringBuilder("Create a copy of ").append(imprintedInstant.getName()).append('?').toString(), source, game)) { + if (controller.chooseUse(outcome, "Create a copy of " + imprintedInstant.getName() + '?', source, game)) { Card copiedCard = game.copyCard(imprintedInstant, source, source.getControllerId()); if (copiedCard != null) { game.getExile().add(source.getSourceId(), "", copiedCard); diff --git a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java index 49b588390f..e7f03140a9 100644 --- a/Mage.Sets/src/mage/cards/s/SpellboundDragon.java +++ b/Mage.Sets/src/mage/cards/s/SpellboundDragon.java @@ -70,15 +70,17 @@ class SpellboundDragonEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player you = game.getPlayer(source.getControllerId()); Permanent dragon = game.getPermanent(source.getSourceId()); - you.drawCards(1, game); - TargetDiscard target = new TargetDiscard(you.getId()); - you.choose(Outcome.Discard, target, source.getSourceId(), game); - Card card = you.getHand().get(target.getFirstTarget(), game); - if (card != null && you.discard(card, source, game)) { - int cmc = card.getConvertedManaCost(); - if (dragon != null) { - game.addEffect(new BoostSourceEffect(cmc, 0, Duration.EndOfTurn), source); - return true; + if(you != null) { + you.drawCards(1, game); + TargetDiscard target = new TargetDiscard(you.getId()); + you.choose(Outcome.Discard, target, source.getSourceId(), game); + Card card = you.getHand().get(target.getFirstTarget(), game); + if (card != null && you.discard(card, source, game)) { + int cmc = card.getConvertedManaCost(); + if (dragon != null) { + game.addEffect(new BoostSourceEffect(cmc, 0, Duration.EndOfTurn), source); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/s/SpellgorgerWeird.java b/Mage.Sets/src/mage/cards/s/SpellgorgerWeird.java new file mode 100644 index 0000000000..263a47f6af --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpellgorgerWeird.java @@ -0,0 +1,41 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.common.SpellCastControllerTriggeredAbility; +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; + +/** + * @author TheElk801 + */ +public final class SpellgorgerWeird extends CardImpl { + + public SpellgorgerWeird(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}"); + + this.subtype.add(SubType.WEIRD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever you cast a noncreature spell, put a +1/+1 counter on Spellgorger Weird. + this.addAbility(new SpellCastControllerTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + StaticFilters.FILTER_SPELL_A_NON_CREATURE, false + )); + } + + private SpellgorgerWeird(final SpellgorgerWeird card) { + super(card); + } + + @Override + public SpellgorgerWeird copy() { + return new SpellgorgerWeird(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/Spelljack.java b/Mage.Sets/src/mage/cards/s/Spelljack.java index 5a752d2c04..f966eb2091 100644 --- a/Mage.Sets/src/mage/cards/s/Spelljack.java +++ b/Mage.Sets/src/mage/cards/s/Spelljack.java @@ -115,7 +115,9 @@ class SpelljackCastFromExileEffect extends AsThoughEffectImpl { if (card != null) { if (game.getState().getZone(sourceId) == Zone.EXILED) { Player player = game.getPlayer(affectedControllerId); - player.setCastSourceIdWithAlternateMana(sourceId, null, null); + if(player != null) { + player.setCastSourceIdWithAlternateMana(sourceId, null, null); + } return true; } else { this.discard(); diff --git a/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java b/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java new file mode 100644 index 0000000000..ec66f16cad --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpellkeeperWeird.java @@ -0,0 +1,53 @@ +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.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterInstantOrSorceryCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpellkeeperWeird extends CardImpl { + + private static final FilterCard filter + = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"); + + public SpellkeeperWeird(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + + this.subtype.add(SubType.WEIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(4); + + // {2}, {T}, Sacrifice Spellkeeper Weird: Return target instant or sorcery card from your graveyard to your hand. + Ability ability = new SimpleActivatedAbility( + new ReturnToHandTargetEffect(), new GenericManaCost(2) + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new SacrificeSourceCost()); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + private SpellkeeperWeird(final SpellkeeperWeird card) { + super(card); + } + + @Override + public SpellkeeperWeird copy() { + return new SpellkeeperWeird(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpellstutterSprite.java b/Mage.Sets/src/mage/cards/s/SpellstutterSprite.java index 2bfc12b77d..1126c9bcbc 100644 --- a/Mage.Sets/src/mage/cards/s/SpellstutterSprite.java +++ b/Mage.Sets/src/mage/cards/s/SpellstutterSprite.java @@ -1,40 +1,40 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; -import mage.abilities.Mode; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.keyword.FlashAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.FilterSpell; -import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.mageobject.SubtypePredicate; -import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; -import mage.game.stack.StackObject; import mage.target.TargetSpell; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SpellstutterSprite extends CardImpl { - - static final FilterPermanent filter = new FilterPermanent("number of Faeries you control"); + + private static final FilterSpell filter = new FilterSpell("spell with converted mana cost X or less, where X is the number of Faeries you control"); + static { - filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new SubtypePredicate(SubType.FAERIE)); + filter.add(SpellstutterSpritePredicate.instance); } public SpellstutterSprite(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.FAERIE); this.subtype.add(SubType.WIZARD); @@ -43,71 +43,37 @@ public final class SpellstutterSprite extends CardImpl { // Flash this.addAbility(FlashAbility.getInstance()); + // Flying this.addAbility(FlyingAbility.getInstance()); + // When Spellstutter Sprite enters the battlefield, counter target spell with converted mana cost X or less, where X is the number of Faeries you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SpellstutterSpriteCounterTargetEffect())); + Ability ability = new EntersBattlefieldTriggeredAbility(new CounterTargetEffect()); + ability.addTarget(new TargetSpell(filter)); + this.addAbility(ability); } public SpellstutterSprite(final SpellstutterSprite card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - int numberFaeries = game.getState().getBattlefield().countAll(filter, ability.getControllerId(), game); - FilterSpell xFilter = new FilterSpell(new StringBuilder("spell with converted mana cost ").append(numberFaeries).append(" or less").toString()); - xFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, numberFaeries + 1)); - ability.getTargets().clear(); - ability.addTarget(new TargetSpell(xFilter)); - } - } - @Override public SpellstutterSprite copy() { return new SpellstutterSprite(this); } } -class SpellstutterSpriteCounterTargetEffect extends OneShotEffect { +enum SpellstutterSpritePredicate implements ObjectSourcePlayerPredicate> { + instance; + private static final FilterPermanent filter = new FilterPermanent(); - public SpellstutterSpriteCounterTargetEffect() { - super(Outcome.Detriment); - } - - public SpellstutterSpriteCounterTargetEffect(final SpellstutterSpriteCounterTargetEffect effect) { - super(effect); + static { + filter.add(new SubtypePredicate(SubType.FAERIE)); } @Override - public SpellstutterSpriteCounterTargetEffect copy() { - return new SpellstutterSpriteCounterTargetEffect(this); + public boolean apply(ObjectSourcePlayer input, Game game) { + return input.getObject().getConvertedManaCost() <= + game.getBattlefield().countAll(filter, game.getControllerId(input.getSourceId()), game); } - - @Override - public boolean apply(Game game, Ability source) { - /* - * The value of X needs to be determined both when the ability triggers (so you can choose - * a target) and again when the ability resolves (to check if that target is still legal). - * If the number of Faeries you control has decreased enough in that time to make the target - * illegal, Spellstutter Sprite's ability will be countered (and the targeted spell will - * resolve as normal). - */ - int numberFaeries = game.getState().getBattlefield().countAll(SpellstutterSprite.filter, source.getControllerId(), game); - StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - // If do'nt have any spell targeted - if (stackObject != null && stackObject.getConvertedManaCost() <= numberFaeries) { - if (game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { - return true; - } - } - return false; - } - - @Override - public String getText(Mode mode) { - return "counter target spell with converted mana cost X or less, where X is the number of Faeries you control"; - } - -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java b/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java index af15968334..3114e8cf72 100644 --- a/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java +++ b/Mage.Sets/src/mage/cards/s/SpellweaverDuo.java @@ -24,7 +24,7 @@ public final class SpellweaverDuo extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SpellweaverDuo(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java b/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java index f276a9393e..61f389621c 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java +++ b/Mage.Sets/src/mage/cards/s/SphinxAmbassador.java @@ -74,7 +74,7 @@ class SphinxAmbassadorEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && targetPlayer != null && sourcePermanent != null) { TargetCardInLibrary target = new TargetCardInLibrary(); - controller.searchLibrary(target, game, targetPlayer.getId()); + controller.searchLibrary(target, source, game, targetPlayer.getId()); Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfForesight.java b/Mage.Sets/src/mage/cards/s/SphinxOfForesight.java new file mode 100644 index 0000000000..a3aac1877c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxOfForesight.java @@ -0,0 +1,85 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.ChancellorAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxOfForesight extends CardImpl { + + public SphinxOfForesight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // You may reveal this card from your opening hand. If you do, scry 3 at the beginning of your first upkeep. + Ability ability = new ChancellorAbility( + new SphinxOfForesightDelayedTriggeredAbility(), + "scry 3 at the beginning of your first upkeep." + ); + ability.setRuleAtTheTop(true); + this.addAbility(ability); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // At the beginning of your upkeep, scry 1. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new ScryEffect(1), + TargetController.YOU, false + )); + } + + private SphinxOfForesight(final SphinxOfForesight card) { + super(card); + } + + @Override + public SphinxOfForesight copy() { + return new SphinxOfForesight(this); + } +} + +class SphinxOfForesightDelayedTriggeredAbility extends DelayedTriggeredAbility { + + SphinxOfForesightDelayedTriggeredAbility() { + super(new ScryEffect(3)); + } + + private SphinxOfForesightDelayedTriggeredAbility(SphinxOfForesightDelayedTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.UPKEEP_STEP_PRE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return game.getActivePlayerId().equals(this.controllerId); + } + + @Override + public SphinxOfForesightDelayedTriggeredAbility copy() { + return new SphinxOfForesightDelayedTriggeredAbility(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfJwarIsle.java b/Mage.Sets/src/mage/cards/s/SphinxOfJwarIsle.java index 49b8e776e4..cbde695d7f 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfJwarIsle.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfJwarIsle.java @@ -1,34 +1,24 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbilityImpl; -import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.ShroudAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.game.Game; -import mage.players.Player; + +import java.util.UUID; /** - * * @author North */ public final class SphinxOfJwarIsle extends CardImpl { public SphinxOfJwarIsle(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}{U}"); this.subtype.add(SubType.SPHINX); this.power = new MageInt(5); @@ -36,12 +26,10 @@ public final class SphinxOfJwarIsle extends CardImpl { this.addAbility(FlyingAbility.getInstance()); this.addAbility(ShroudAbility.getInstance()); - // TODO: this should be a static ability - this.addAbility(new SphinxOfJwarIsleLookAbility()); - + this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); } - public SphinxOfJwarIsle(final SphinxOfJwarIsle card) { + private SphinxOfJwarIsle(final SphinxOfJwarIsle card) { super(card); } @@ -50,57 +38,3 @@ public final class SphinxOfJwarIsle extends CardImpl { return new SphinxOfJwarIsle(this); } } - -class SphinxOfJwarIsleLookAbility extends ActivatedAbilityImpl { - - public SphinxOfJwarIsleLookAbility() { - super(Zone.BATTLEFIELD, new SphinxOfJwarIsleEffect(), new GenericManaCost(0)); - this.usesStack = false; - } - - public SphinxOfJwarIsleLookAbility(SphinxOfJwarIsleLookAbility ability) { - super(ability); - } - - @Override - public SphinxOfJwarIsleLookAbility copy() { - return new SphinxOfJwarIsleLookAbility(this); - } - -} - -class SphinxOfJwarIsleEffect extends OneShotEffect { - - public SphinxOfJwarIsleEffect() { - super(Outcome.Neutral); - this.staticText = "You may look at the top card of your library any time"; - } - - public SphinxOfJwarIsleEffect(final SphinxOfJwarIsleEffect effect) { - super(effect); - } - - @Override - public SphinxOfJwarIsleEffect copy() { - return new SphinxOfJwarIsleEffect(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) { - Cards cards = new CardsImpl(); - cards.add(card); - player.lookAtCards("Sphinx of Jwar Isle", cards, game); - } else { - return false; - } - - return true; - } -} diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java b/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java new file mode 100644 index 0000000000..690a8c7f3b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxOfNewPrahv.java @@ -0,0 +1,97 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.Target; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxOfNewPrahv extends CardImpl { + + public SphinxOfNewPrahv(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{U}{U}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Spells your opponents cast that target Sphinx of New Prahv cost {2} more to cast. + this.addAbility(new SimpleStaticAbility(new SphinxOfNewPrahvCostIncreaseEffect())); + } + + private SphinxOfNewPrahv(final SphinxOfNewPrahv card) { + super(card); + } + + @Override + public SphinxOfNewPrahv copy() { + return new SphinxOfNewPrahv(this); + } +} + +class SphinxOfNewPrahvCostIncreaseEffect extends CostModificationEffectImpl { + + SphinxOfNewPrahvCostIncreaseEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "Spells your opponents cast that target {this} cost {2} more to cast"; + } + + private SphinxOfNewPrahvCostIncreaseEffect(SphinxOfNewPrahvCostIncreaseEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -2); + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null + || !(abilityToModify instanceof SpellAbility) + || !controller.hasOpponent(abilityToModify.getControllerId(), game)) { + return false; + } + for (UUID modeId : abilityToModify.getModes().getSelectedModes()) { + Mode mode = abilityToModify.getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetUUID : target.getTargets()) { + if (targetUUID.equals(source.getSourceId())) { + return true; + } + } + } + } + return false; + } + + @Override + public SphinxOfNewPrahvCostIncreaseEffect copy() { + return new SphinxOfNewPrahvCostIncreaseEffect(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java index 5647a87704..07a1884826 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheChimes.java @@ -1,22 +1,12 @@ - package mage.cards.s; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardTargetCost; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.FlyingAbility; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; -import mage.cards.SplitCard; +import mage.cards.*; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; @@ -27,8 +17,12 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SphinxOfTheChimes extends CardImpl { @@ -91,6 +85,9 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { Set newPossibleTargets = new HashSet<>(); Set possibleTargets = new HashSet<>(); Player player = game.getPlayer(sourceControllerId); + if (player == null) { + return newPossibleTargets; + } for (Card card : player.getHand().getCards(filter, game)) { possibleTargets.add(card.getId()); } @@ -113,9 +110,11 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { for (UUID cardToCheck : cardsToCheck) { FilterCard nameFilter = new FilterCard(); Card card = game.getCard(cardToCheck); - nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); - if (cardsToCheck.count(nameFilter, game) > 1) { - newPossibleTargets.add(cardToCheck); + if (card != null) { + nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); + if (cardsToCheck.count(nameFilter, game) > 1) { + newPossibleTargets.add(cardToCheck); + } } } } @@ -126,6 +125,9 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { public boolean canChoose(UUID sourceControllerId, Game game) { Cards cardsToCheck = new CardsImpl(); Player player = game.getPlayer(sourceControllerId); + if (player == null) { + return false; + } for (Card card : player.getHand().getCards(filter, game)) { cardsToCheck.add(card.getId()); } @@ -147,16 +149,12 @@ class TargetTwoNonLandCardsWithSameNameInHand extends TargetCardInHand { if (card != null) { if (targets.size() == 1) { Card card2 = game.getCard(targets.entrySet().iterator().next().getKey()); - if (card2 != null && card2.getName().equals(card.getName())) { - return true; - } + return card2 != null && card2.getName().equals(card.getName()); } else { FilterCard nameFilter = new FilterCard(); nameFilter.add(new NamePredicate(card.isSplitCard() ? ((SplitCard) card).getLeftHalfCard().getName() : card.getName())); Player player = game.getPlayer(card.getOwnerId()); - if (player.getHand().getCards(nameFilter, game).size() > 1) { - return true; - } + return player != null && player.getHand().getCards(nameFilter, game).size() > 1; } } } diff --git a/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java b/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java new file mode 100644 index 0000000000..97c09111ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxOfTheGuildpact.java @@ -0,0 +1,51 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.HexproofFromMonocoloredAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxOfTheGuildpact extends CardImpl { + + public SphinxOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{7}"); + + this.subtype.add(SubType.SPHINX); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Sphinx of the Guildpact is all colors. + this.color.setWhite(true); + this.color.setBlue(true); + this.color.setBlack(true); + this.color.setRed(true); + this.color.setGreen(true); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this} is all colors"))); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Hexproof from mono colored + this.addAbility(HexproofFromMonocoloredAbility.getInstance()); + } + + private SphinxOfTheGuildpact(final SphinxOfTheGuildpact card) { + super(card); + } + + @Override + public SphinxOfTheGuildpact copy() { + return new SphinxOfTheGuildpact(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SphinxsDecree.java b/Mage.Sets/src/mage/cards/s/SphinxsDecree.java index 2b841942ca..eba89ba355 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxsDecree.java +++ b/Mage.Sets/src/mage/cards/s/SphinxsDecree.java @@ -111,7 +111,7 @@ class SphinxsDecreeCantCastEffect extends ContinuousRuleModifyingEffectImpl { if (opponentId.equals(event.getPlayerId())) { MageObject object = game.getObject(event.getSourceId()); if (event.getType() == GameEvent.EventType.CAST_SPELL) { - if (object.isInstant() || object.isSorcery()) { + if (object != null && (object.isInstant() || object.isSorcery())) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/SphinxsInsight.java b/Mage.Sets/src/mage/cards/s/SphinxsInsight.java new file mode 100644 index 0000000000..44f5a6d158 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SphinxsInsight.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SphinxsInsight extends CardImpl { + + public SphinxsInsight(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}{U}"); + + + // Draw two cards. + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); + + // Addendum — If you cast this spell during your main phase, you gain 2 life. + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GainLifeEffect(2), AddendumCondition.instance, + "
    Addendum — If you cast this spell during your main phase, you gain 2 life." + )); + } + + private SphinxsInsight(final SphinxsInsight card) { + super(card); + } + + @Override + public SphinxsInsight copy() { + return new SphinxsInsight(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SphinxsRevelation.java b/Mage.Sets/src/mage/cards/s/SphinxsRevelation.java index 4658f43450..9a982e8c06 100644 --- a/Mage.Sets/src/mage/cards/s/SphinxsRevelation.java +++ b/Mage.Sets/src/mage/cards/s/SphinxsRevelation.java @@ -21,7 +21,7 @@ public final class SphinxsRevelation extends CardImpl { // You gain X life and draw X cards. - ManacostVariableValue manaX = new ManacostVariableValue(); + ManacostVariableValue manaX = ManacostVariableValue.instance; this.getSpellAbility().addEffect(new GainLifeEffect(manaX)); this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(manaX)); } diff --git a/Mage.Sets/src/mage/cards/s/SpikewheelAcrobat.java b/Mage.Sets/src/mage/cards/s/SpikewheelAcrobat.java new file mode 100644 index 0000000000..fc751f4170 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpikewheelAcrobat.java @@ -0,0 +1,38 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.keyword.SpectacleAbility; +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 SpikewheelAcrobat extends CardImpl { + + public SpikewheelAcrobat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(5); + this.toughness = new MageInt(2); + + // Spectacle {2}{R} + this.addAbility(new SpectacleAbility(this, new ManaCostsImpl("{2}{R}"))); + } + + private SpikewheelAcrobat(final SpikewheelAcrobat card) { + super(card); + } + + @Override + public SpikewheelAcrobat copy() { + return new SpikewheelAcrobat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpinEngine.java b/Mage.Sets/src/mage/cards/s/SpinEngine.java index 0e2b04d548..009e732041 100644 --- a/Mage.Sets/src/mage/cards/s/SpinEngine.java +++ b/Mage.Sets/src/mage/cards/s/SpinEngine.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -10,21 +8,22 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class SpinEngine extends CardImpl { public SpinEngine(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add(SubType.CONSTRUCT); this.power = new MageInt(3); this.toughness = new MageInt(1); @@ -59,18 +58,13 @@ class SpinEngineEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { UUID targetId = source.getFirstTarget(); - if (targetId != null && blocker.getId().equals(targetId)) - return false; - return true; + return targetId == null || !blocker.getId().equals(targetId); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java b/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java index 2bbd0596be..b4f870c9e9 100644 --- a/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java +++ b/Mage.Sets/src/mage/cards/s/SpinerockKnoll.java @@ -68,7 +68,7 @@ class SpinerockKnollCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int maxDamageReceived = 0; - SpinerockKnollWatcher watcher = (SpinerockKnollWatcher) game.getState().getWatchers().get(SpinerockKnollWatcher.class.getSimpleName(), source.getSourceId()); + SpinerockKnollWatcher watcher = game.getState().getWatcher(SpinerockKnollWatcher.class, source.getSourceId()); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { int damageReceived = watcher.getDamageReceived(opponentId); @@ -91,7 +91,7 @@ class SpinerockKnollWatcher extends Watcher { private final Map amountOfDamageReceivedThisTurn = new HashMap<>(1); SpinerockKnollWatcher() { - super(SpinerockKnollWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } SpinerockKnollWatcher(final SpinerockKnollWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/SpinyStarfish.java b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java new file mode 100644 index 0000000000..e5c93b3751 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpinyStarfish.java @@ -0,0 +1,157 @@ +package mage.cards.s; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.Condition; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.RegenerateSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.StarfishToken; +import mage.watchers.Watcher; + +/** + * @author spike + */ +public final class SpinyStarfish extends CardImpl { + + public SpinyStarfish(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}"); + this.subtype.add(SubType.STARFISH); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // {U}: Regenerate Spiny Starfish. + this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new ManaCostsImpl("{U}"))); + + // At the beginning of each end step, if Spiny Starfish regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn. + this.addAbility( + new ConditionalInterveningIfTriggeredAbility( + new BeginningOfEndStepTriggeredAbility( + new CreateTokenEffect( + new StarfishToken(), + new SpinyStarfishDynamicValue()), + TargetController.ANY, + false), + SpinyStarfishCondition.instance, + "At the beginning of each end step, if {this} regenerated this turn, create a 0/1 blue Starfish creature token for each time it regenerated this turn."), + new SpinyStarfishWatcher()); + } + + public SpinyStarfish(final SpinyStarfish card) { + super(card); + } + + @Override + public SpinyStarfish copy() { + return new SpinyStarfish(this); + } +} + +enum SpinyStarfishCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + SpinyStarfishWatcher watcher = game.getState().getWatcher(SpinyStarfishWatcher.class); + return watcher != null && watcher.regeneratedCount(source.getSourceId()) != 0; + } + + @Override + public String toString() { + return "if Spiny Starfish regenerated this turn"; + } + +} + +class SpinyStarfishWatcher extends Watcher { + + // Probably dumb to record all regeneration events, could just record this, + // but not sure how to know what source this watcher is attached to. + private final Map regeneratedCount = new HashMap<>(); + + public SpinyStarfishWatcher() { + super(WatcherScope.GAME); + } + + public SpinyStarfishWatcher(final SpinyStarfishWatcher watcher) { + super(watcher); + this.regeneratedCount.putAll(watcher.regeneratedCount); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.REGENERATED) { + UUID regeneratedId = event.getTargetId(); + Integer count = regeneratedCount.get(regeneratedId); + if (count == null) { + count = 0; + } + regeneratedCount.put(regeneratedId, ++count); + } + } + + @Override + public void reset() { + super.reset(); + regeneratedCount.clear(); + } + + public int regeneratedCount(UUID sourceId) { + Integer count = regeneratedCount.get(sourceId); + if (count == null) { + return 0; + } + return count; + } + + @Override + public SpinyStarfishWatcher copy() { + return new SpinyStarfishWatcher(this); + } +} + +class SpinyStarfishDynamicValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + SpinyStarfishWatcher watcher = game.getState().getWatcher( + SpinyStarfishWatcher.class); + if (watcher != null) { + return watcher.regeneratedCount(sourceAbility.getSourceId()); + } + return 0; + } + + @Override + public SpinyStarfishDynamicValue copy() { + return new SpinyStarfishDynamicValue(); + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "time {this} regenerated this turn"; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpiralingEmbers.java b/Mage.Sets/src/mage/cards/s/SpiralingEmbers.java index 68696268ca..f6b5adc920 100644 --- a/Mage.Sets/src/mage/cards/s/SpiralingEmbers.java +++ b/Mage.Sets/src/mage/cards/s/SpiralingEmbers.java @@ -23,7 +23,7 @@ public final class SpiralingEmbers extends CardImpl { // Spiraling Embers deals damage to any target equal to the number of cards in your hand. - Effect effect = new DamageTargetEffect(new CardsInControllerHandCount()); + Effect effect = new DamageTargetEffect(CardsInControllerHandCount.instance); effect.setText("{this} deals damage to any target equal to the number of cards in your hand."); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SpireMangler.java b/Mage.Sets/src/mage/cards/s/SpireMangler.java new file mode 100644 index 0000000000..e5faeef3d6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpireMangler.java @@ -0,0 +1,59 @@ +package mage.cards.s; + +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.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SpireMangler extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledCreaturePermanent("creature with flying you control"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public SpireMangler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.INSECT); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // Flash + this.addAbility(FlashAbility.getInstance()); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // When Spire Mangler enters the battlefield, target creature with flying you control gets +2/+0 until end of turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0)); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private SpireMangler(final SpireMangler card) { + super(card); + } + + @Override + public SpireMangler copy() { + return new SpireMangler(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpireTracer.java b/Mage.Sets/src/mage/cards/s/SpireTracer.java index b248147116..b74f8a6fdc 100644 --- a/Mage.Sets/src/mage/cards/s/SpireTracer.java +++ b/Mage.Sets/src/mage/cards/s/SpireTracer.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -11,20 +9,21 @@ import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class SpireTracer extends CardImpl { public SpireTracer(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); this.subtype.add(SubType.ELF); this.subtype.add(SubType.SCOUT); @@ -59,19 +58,13 @@ class CantBeBlockedExceptByCreaturesWithFlyingOrReachEffect extends RestrictionE @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { - if (blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId()) - || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId())) { - return true; - } - return false; + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + return blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId()) + || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId()); } @Override diff --git a/Mage.Sets/src/mage/cards/s/SpireWinder.java b/Mage.Sets/src/mage/cards/s/SpireWinder.java index bf4965e077..e885d58acd 100644 --- a/Mage.Sets/src/mage/cards/s/SpireWinder.java +++ b/Mage.Sets/src/mage/cards/s/SpireWinder.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +7,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -18,8 +17,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SpireWinder extends CardImpl { @@ -41,7 +41,7 @@ public final class SpireWinder extends CardImpl { ContinuousEffect boostSource = new BoostSourceEffect(1, 1, Duration.WhileOnBattlefield); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, "{this} gets +1/+1 as long as you have the city's blessing"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java b/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java index 2508964cb9..c6651fc0fe 100644 --- a/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java +++ b/Mage.Sets/src/mage/cards/s/SpiresOfOrazca.java @@ -28,7 +28,7 @@ public final class SpiresOfOrazca extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature an opponent controls"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(new ControllerPredicate(TargetController.OPPONENT)); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritBonds.java b/Mage.Sets/src/mage/cards/s/SpiritBonds.java index 58d4d81762..6af79400d5 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritBonds.java +++ b/Mage.Sets/src/mage/cards/s/SpiritBonds.java @@ -39,7 +39,7 @@ public final class SpiritBonds extends CardImpl { static { filter.add(Predicates.not(new SubtypePredicate(SubType.SPIRIT))); filterSpirit.add(new SubtypePredicate(SubType.SPIRIT)); - filterNontoken.add(Predicates.not(new TokenPredicate())); + filterNontoken.add(Predicates.not(TokenPredicate.instance)); } public SpiritBonds(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SpiritMirror.java b/Mage.Sets/src/mage/cards/s/SpiritMirror.java index 136789f012..de02cbfc46 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritMirror.java +++ b/Mage.Sets/src/mage/cards/s/SpiritMirror.java @@ -29,7 +29,7 @@ public final class SpiritMirror extends CardImpl { static { filterToken.add(new SubtypePredicate(SubType.REFLECTION)); - filterToken.add(new TokenPredicate()); + filterToken.add(TokenPredicate.instance); filter.add(new SubtypePredicate(SubType.REFLECTION)); } diff --git a/Mage.Sets/src/mage/cards/s/SpiritOfTheLabyrinth.java b/Mage.Sets/src/mage/cards/s/SpiritOfTheLabyrinth.java index 31da7b75e8..9742ff206e 100644 --- a/Mage.Sets/src/mage/cards/s/SpiritOfTheLabyrinth.java +++ b/Mage.Sets/src/mage/cards/s/SpiritOfTheLabyrinth.java @@ -50,7 +50,7 @@ class SpiritOfTheLabyrinthWatcher extends Watcher { private final Set playersThatDrewCard; public SpiritOfTheLabyrinthWatcher() { - super(SpiritOfTheLabyrinthWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.playersThatDrewCard = new HashSet<>(); } @@ -113,7 +113,7 @@ class SpiritOfTheLabyrinthEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - SpiritOfTheLabyrinthWatcher watcher = (SpiritOfTheLabyrinthWatcher) game.getState().getWatchers().get(SpiritOfTheLabyrinthWatcher.class.getSimpleName()); + SpiritOfTheLabyrinthWatcher watcher = game.getState().getWatcher(SpiritOfTheLabyrinthWatcher.class); if (watcher != null && watcher.hasPlayerDrewCardThisTurn(event.getPlayerId())) { return true; } diff --git a/Mage.Sets/src/mage/cards/s/SpiritOfTheSpires.java b/Mage.Sets/src/mage/cards/s/SpiritOfTheSpires.java new file mode 100644 index 0000000000..796e7540af --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SpiritOfTheSpires.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; +import mage.abilities.effects.Effect; + +/** + * @author TheElk801 + */ +public final class SpiritOfTheSpires extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent(); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public SpiritOfTheSpires(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Other creatures you control with flying get +0/+1. + Effect effect = new BoostControlledEffect( + 0, 1, Duration.WhileOnBattlefield, filter, true + ); + effect.setText("Other creatures you control with flying get +0/+1"); + this.addAbility(new SimpleStaticAbility(effect)); + } + + private SpiritOfTheSpires(final SpiritOfTheSpires card) { + super(card); + } + + @Override + public SpiritOfTheSpires copy() { + return new SpiritOfTheSpires(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SpitefulReturned.java b/Mage.Sets/src/mage/cards/s/SpitefulReturned.java index 3bca683888..2d80ec8660 100644 --- a/Mage.Sets/src/mage/cards/s/SpitefulReturned.java +++ b/Mage.Sets/src/mage/cards/s/SpitefulReturned.java @@ -98,6 +98,6 @@ class SpitefulReturnedTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever {this} or enchanted creature attacks, ").append(super.getRule()).toString(); + return "Whenever {this} or enchanted creature attacks, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/s/SpitfireHandler.java b/Mage.Sets/src/mage/cards/s/SpitfireHandler.java index 6d4872d74f..d5da32d3f7 100644 --- a/Mage.Sets/src/mage/cards/s/SpitfireHandler.java +++ b/Mage.Sets/src/mage/cards/s/SpitfireHandler.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -9,18 +7,15 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ColoredManaCost; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.ColoredManaSymbol; -import mage.constants.Duration; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SpitfireHandler extends CardImpl { @@ -66,7 +61,10 @@ class SpitfireHandlerCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return (blocker.getPower().getValue() >= attacker.getPower().getValue()); } diff --git a/Mage.Sets/src/mage/cards/s/SplinteringWind.java b/Mage.Sets/src/mage/cards/s/SplinteringWind.java new file mode 100644 index 0000000000..e2b6571d51 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SplinteringWind.java @@ -0,0 +1,125 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageAllEffect; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.SplinterToken; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class SplinteringWind extends CardImpl { + + public SplinteringWind(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{G}"); + + // {2}{G}: Splintering Wind deals 1 damage to target creature. Create a 1/1 green Splinter creature token. It has flying and “Cumulative upkeep {G}.” When it leaves the battlefield, it deals 1 damage to you and each creature you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), new ManaCostsImpl("{2}{G}")); + ability.addEffect(new SplinteringWindCreateTokenEffect()); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public SplinteringWind(final SplinteringWind card) { + super(card); + } + + @Override + public SplinteringWind copy() { + return new SplinteringWind(this); + } +} + +class SplinteringWindCreateTokenEffect extends OneShotEffect { + + public SplinteringWindCreateTokenEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "create a 1/1 green Splinter creature token. It has flying and “Cumulative upkeep {G}.” When it leaves the battlefield, it deals 1 damage to you and each creature you control"; + } + + public SplinteringWindCreateTokenEffect(final SplinteringWindCreateTokenEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player sourceController = game.getPlayer(source.getControllerId()); + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourceController != null && sourceObject != null) { + CreateTokenEffect effect = new CreateTokenEffect(new SplinterToken()); + effect.apply(game, source); + game.getState().setValue(source.getSourceId() + "_token", effect.getLastAddedTokenIds()); + for (UUID addedTokenId : effect.getLastAddedTokenIds()) { + game.addDelayedTriggeredAbility(new SplinteringWindDelayedTriggeredAbility(addedTokenId), source); + } + return true; + } + return false; + } + + @Override + public SplinteringWindCreateTokenEffect copy() { + return new SplinteringWindCreateTokenEffect(this); + } +} + +class SplinteringWindDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private UUID tokenId; + + SplinteringWindDelayedTriggeredAbility(UUID tokenId) { + super(new DamageControllerEffect(1), Duration.OneUse); + this.addEffect(new DamageAllEffect(1, new FilterControlledCreaturePermanent())); + this.tokenId = tokenId; + } + + SplinteringWindDelayedTriggeredAbility(final SplinteringWindDelayedTriggeredAbility ability) { + super(ability); + this.tokenId = ability.tokenId; + } + + @Override + public SplinteringWindDelayedTriggeredAbility copy() { + return new SplinteringWindDelayedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getTargetId().equals(tokenId)) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone() == Zone.BATTLEFIELD) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "When it leaves the battlefield, it deals 1 damage to you and each creature you control."; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SplittingHeadache.java b/Mage.Sets/src/mage/cards/s/SplittingHeadache.java index 810a9ec595..8f2b2e0cd9 100644 --- a/Mage.Sets/src/mage/cards/s/SplittingHeadache.java +++ b/Mage.Sets/src/mage/cards/s/SplittingHeadache.java @@ -32,8 +32,8 @@ public final class SplittingHeadache extends CardImpl { this.getSpellAbility().addTarget(new TargetPlayer()); this.getSpellAbility().addEffect(new DiscardTargetEffect(2)); Mode mode = new Mode(); - mode.getEffects().add(new SplittingHeadacheEffect()); - mode.getTargets().add(new TargetPlayer()); + mode.addEffect(new SplittingHeadacheEffect()); + mode.addTarget(new TargetPlayer()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java b/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java index 4a056003b4..065afc0eaf 100644 --- a/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java +++ b/Mage.Sets/src/mage/cards/s/SpoilsOfBlood.java @@ -59,9 +59,9 @@ class SpoilsOfBloodEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - CreaturesDiedThisTurnWatcher watcher = (CreaturesDiedThisTurnWatcher) game.getState().getWatchers().get(CreaturesDiedThisTurnWatcher.class.getSimpleName()); + CreaturesDiedThisTurnWatcher watcher = game.getState().getWatcher(CreaturesDiedThisTurnWatcher.class); if (watcher != null) { - new CreateTokenEffect(new SpoilsOfBloodHorrorToken(watcher.creaturesDiedThisTurn)).apply(game, source); + new CreateTokenEffect(new SpoilsOfBloodHorrorToken(watcher.getCreaturesDiedThisTurn())).apply(game, source); } return true; } @@ -77,10 +77,14 @@ class SpoilsOfBloodEffect extends OneShotEffect { class CreaturesDiedThisTurnWatcher extends Watcher { - public int creaturesDiedThisTurn = 0; + public int getCreaturesDiedThisTurn() { + return creaturesDiedThisTurn; + } + + private int creaturesDiedThisTurn = 0; public CreaturesDiedThisTurnWatcher() { - super(CreaturesDiedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CreaturesDiedThisTurnWatcher(final CreaturesDiedThisTurnWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java index 622bf0c7f3..153bc570f7 100644 --- a/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java +++ b/Mage.Sets/src/mage/cards/s/SpoilsOfTheVault.java @@ -1,23 +1,20 @@ package mage.cards.s; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author Plopman */ public final class SpoilsOfTheVault extends CardImpl { @@ -71,7 +68,7 @@ class SpoilsOfTheVaultEffect extends OneShotEffect { for (Card card : controller.getLibrary().getCards(game)) { if (card != null) { cardsToReveal.add(card); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { controller.moveCards(card, Zone.HAND, source, game); break; } else { diff --git a/Mage.Sets/src/mage/cards/s/SpontaneousGeneration.java b/Mage.Sets/src/mage/cards/s/SpontaneousGeneration.java index eab38e464e..6820a1e7dd 100644 --- a/Mage.Sets/src/mage/cards/s/SpontaneousGeneration.java +++ b/Mage.Sets/src/mage/cards/s/SpontaneousGeneration.java @@ -19,7 +19,7 @@ public final class SpontaneousGeneration extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{G}"); // Create a 1/1 green Saproling creature token for each card in your hand. - this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new CardsInControllerHandCount())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), CardsInControllerHandCount.instance)); } public SpontaneousGeneration(final SpontaneousGeneration card) { diff --git a/Mage.Sets/src/mage/cards/s/SporeCloud.java b/Mage.Sets/src/mage/cards/s/SporeCloud.java index 02109f1035..c7c9d494a0 100644 --- a/Mage.Sets/src/mage/cards/s/SporeCloud.java +++ b/Mage.Sets/src/mage/cards/s/SporeCloud.java @@ -32,7 +32,7 @@ public final class SporeCloud extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking creatures"); static { - filter.add(new BlockingPredicate()); + filter.add(BlockingPredicate.instance); } public SporeCloud(UUID ownerId, CardSetInfo setInfo) { @@ -60,7 +60,7 @@ class SporeCloudEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Each attacking creature and each blocking creature"); static { - filter.add(Predicates.or(new AttackingPredicate(), new BlockingPredicate())); + filter.add(Predicates.or(AttackingPredicate.instance, BlockingPredicate.instance)); } public SporeCloudEffect() { diff --git a/Mage.Sets/src/mage/cards/s/Sporogenesis.java b/Mage.Sets/src/mage/cards/s/Sporogenesis.java index 99f5cee4dc..0d405c66b2 100644 --- a/Mage.Sets/src/mage/cards/s/Sporogenesis.java +++ b/Mage.Sets/src/mage/cards/s/Sporogenesis.java @@ -39,7 +39,7 @@ public final class Sporogenesis extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public Sporogenesis(UUID ownerId, CardSetInfo setInfo) { @@ -90,7 +90,7 @@ class SporogenesisTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); if (permanent != null && permanent.isCreature() diff --git a/Mage.Sets/src/mage/cards/s/SpreadTheSickness.java b/Mage.Sets/src/mage/cards/s/SpreadTheSickness.java index 1b56e195a4..eb97e23df1 100644 --- a/Mage.Sets/src/mage/cards/s/SpreadTheSickness.java +++ b/Mage.Sets/src/mage/cards/s/SpreadTheSickness.java @@ -1,8 +1,5 @@ - - package mage.cards.s; -import java.util.UUID; import mage.abilities.effects.common.DestroyTargetEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; @@ -10,21 +7,23 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class SpreadTheSickness extends CardImpl { - public SpreadTheSickness (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{B}"); + public SpreadTheSickness(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}"); + // Destroy target creature, then proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.getSpellAbility().addEffect(new DestroyTargetEffect()); - this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy(", then")); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } - public SpreadTheSickness (final SpreadTheSickness card) { + public SpreadTheSickness(final SpreadTheSickness card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SpringMind.java b/Mage.Sets/src/mage/cards/s/SpringMind.java index abd520704f..c1f4493fcb 100644 --- a/Mage.Sets/src/mage/cards/s/SpringMind.java +++ b/Mage.Sets/src/mage/cards/s/SpringMind.java @@ -29,7 +29,7 @@ public final class SpringMind extends SplitCard { // Mind // Aftermath // Draw two cards. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); } diff --git a/Mage.Sets/src/mage/cards/s/SpringjackPasture.java b/Mage.Sets/src/mage/cards/s/SpringjackPasture.java index c5f7f6a91a..d4ba3405d7 100644 --- a/Mage.Sets/src/mage/cards/s/SpringjackPasture.java +++ b/Mage.Sets/src/mage/cards/s/SpringjackPasture.java @@ -49,12 +49,12 @@ public final class SpringjackPasture extends CardImpl { // {tap}, Sacrifice X Goats: Add X mana of any one color. You gain X life. ability = new DynamicManaAbility( new Mana(0,0,0,0,0,0,1,0), - new GetXValue(), + GetXValue.instance, new TapSourceCost(), "Add X mana of any one color", true); ability.addCost(new SacrificeXTargetCost(filter)); - ability.addEffect(new GainLifeEffect(new GetXValue())); + ability.addEffect(new GainLifeEffect(GetXValue.instance)); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SpringleafDrum.java b/Mage.Sets/src/mage/cards/s/SpringleafDrum.java index 7bf0a7908f..b5c988ccb5 100644 --- a/Mage.Sets/src/mage/cards/s/SpringleafDrum.java +++ b/Mage.Sets/src/mage/cards/s/SpringleafDrum.java @@ -21,7 +21,7 @@ public final class SpringleafDrum extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SpringleafDrum(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SpurGrappler.java b/Mage.Sets/src/mage/cards/s/SpurGrappler.java index c0f048f886..fc6865d049 100644 --- a/Mage.Sets/src/mage/cards/s/SpurGrappler.java +++ b/Mage.Sets/src/mage/cards/s/SpurGrappler.java @@ -27,7 +27,7 @@ public final class SpurGrappler extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SpurGrappler(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SpurredWolverine.java b/Mage.Sets/src/mage/cards/s/SpurredWolverine.java index b21ef4ee91..016d81b072 100644 --- a/Mage.Sets/src/mage/cards/s/SpurredWolverine.java +++ b/Mage.Sets/src/mage/cards/s/SpurredWolverine.java @@ -30,7 +30,7 @@ public final class SpurredWolverine extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Beasts you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.BEAST)); } diff --git a/Mage.Sets/src/mage/cards/s/SpyNetwork.java b/Mage.Sets/src/mage/cards/s/SpyNetwork.java index daf78dbba8..c325541b6c 100644 --- a/Mage.Sets/src/mage/cards/s/SpyNetwork.java +++ b/Mage.Sets/src/mage/cards/s/SpyNetwork.java @@ -103,7 +103,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect { MageObject mageObject = game.getObject(source.getSourceId()); if (controller != null && player != null && mageObject != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("face down creature controlled by " + player.getLogName()); - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); filter.add(new ControllerIdPredicate(player.getId())); TargetCreaturePermanent target = new TargetCreaturePermanent(1, 1, filter, true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { @@ -116,8 +116,7 @@ class SpyNetworkFaceDownEffect extends OneShotEffect { if (faceDownCreature != null) { Permanent copyFaceDown = faceDownCreature.copy(); copyFaceDown.setFaceDown(false, game); - Cards cards = new CardsImpl(); - cards.add(copyFaceDown); + Cards cards = new CardsImpl(copyFaceDown); controller.lookAtCards("face down card - " + mageObject.getName(), cards, game); game.informPlayers(controller.getLogName() + " looks at a face down creature controlled by " + player.getLogName()); } diff --git a/Mage.Sets/src/mage/cards/s/SquallLine.java b/Mage.Sets/src/mage/cards/s/SquallLine.java index b2b8c82201..37e98c9e64 100644 --- a/Mage.Sets/src/mage/cards/s/SquallLine.java +++ b/Mage.Sets/src/mage/cards/s/SquallLine.java @@ -27,7 +27,7 @@ public final class SquallLine extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{G}"); // Squall Line deals X damage to each creature with flying and each player. - this.getSpellAbility().addEffect(new DamageEverythingEffect(new ManacostVariableValue(), filter)); } + this.getSpellAbility().addEffect(new DamageEverythingEffect(ManacostVariableValue.instance, filter)); } public SquallLine(final SquallLine card) { super(card); diff --git a/Mage.Sets/src/mage/cards/s/SquanderedResources.java b/Mage.Sets/src/mage/cards/s/SquanderedResources.java index 08222b4d80..9a51bf738a 100644 --- a/Mage.Sets/src/mage/cards/s/SquanderedResources.java +++ b/Mage.Sets/src/mage/cards/s/SquanderedResources.java @@ -108,6 +108,9 @@ class SquanderedResourcesEffect extends ManaEffect { Mana mana = new Mana(); if (!choice.getChoices().isEmpty()) { Player player = game.getPlayer(source.getControllerId()); + if(player == null){ + return mana; + } if (choice.getChoices().size() == 1) { choice.setChoice(choice.getChoices().iterator().next()); } else { diff --git a/Mage.Sets/src/mage/cards/s/SqueesRevenge.java b/Mage.Sets/src/mage/cards/s/SqueesRevenge.java index b999d68903..f30ec04673 100644 --- a/Mage.Sets/src/mage/cards/s/SqueesRevenge.java +++ b/Mage.Sets/src/mage/cards/s/SqueesRevenge.java @@ -56,7 +56,7 @@ class SqueesRevengeEffect extends OneShotEffect { int number = player.announceXMana(0, Integer.MAX_VALUE, "Choose how many times to flip a coin", game, source); game.informPlayers(player.getLogName() + " chooses " + number + '.'); for(int i = 0; i < number; i++) { - if(!player.flipCoin(game)) { + if(!player.flipCoin(source, game, true)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/s/StadiumVendors.java b/Mage.Sets/src/mage/cards/s/StadiumVendors.java index 04ebe8dad8..c95788ca69 100644 --- a/Mage.Sets/src/mage/cards/s/StadiumVendors.java +++ b/Mage.Sets/src/mage/cards/s/StadiumVendors.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.UUID; @@ -65,21 +64,22 @@ class StadiumVendorsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getSourceId()); + Player controller = game.getPlayer(source.getControllerId()); if (controller == null) { return false; } TargetPlayer target = new TargetPlayer(1, 1, true); - if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { - return false; + if (controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + Player player = game.getPlayer(target.getFirstTarget()); + ChoiceColor colorChoice = new ChoiceColor(true); + if (player == null + || !player.choose(Outcome.Benefit, colorChoice, game)) { + return false; + } + Effect effect = new AddManaToManaPoolTargetControllerEffect(colorChoice.getMana(2), "that player's"); + effect.setTargetPointer(new FixedTarget(player.getId(), game)); + return effect.apply(game, source); } - Player player = game.getPlayer(target.getFirstTarget()); - ChoiceColor colorChoice = new ChoiceColor(true); - if (player == null || !player.choose(Outcome.Benefit, colorChoice, game)) { - return false; - } - Effect effect = new AddManaToManaPoolTargetControllerEffect(colorChoice.getMana(2), "that player's"); - effect.setTargetPointer(new FixedTarget(player.getId(), game)); - return effect.apply(game, source); + return false; } } diff --git a/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java b/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java index b31f034cc6..8251a67122 100644 --- a/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java +++ b/Mage.Sets/src/mage/cards/s/StaffOfTheLetterMagus.java @@ -129,7 +129,7 @@ class StaffOfTheLetterMagusEffect extends OneShotEffect { int lifegainValue = 0; String spellName = spell.getName(); for (int i = 0; i < spellName.length(); i++) { - Character letter = spellName.charAt(i); + char letter = spellName.charAt(i); String chosenLetter = (String) game.getState().getValue(mageObject.getId() + "_letter"); if (Character.isLetter(letter) && Character.toUpperCase(letter) == chosenLetter.charAt(0)) { lifegainValue++; diff --git a/Mage.Sets/src/mage/cards/s/StagBeetle.java b/Mage.Sets/src/mage/cards/s/StagBeetle.java index 4918fae8bf..4da1d698ec 100644 --- a/Mage.Sets/src/mage/cards/s/StagBeetle.java +++ b/Mage.Sets/src/mage/cards/s/StagBeetle.java @@ -23,7 +23,7 @@ public final class StagBeetle extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public StagBeetle(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StalkingAssassin.java b/Mage.Sets/src/mage/cards/s/StalkingAssassin.java index ef7528461a..78a1c8bad5 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingAssassin.java +++ b/Mage.Sets/src/mage/cards/s/StalkingAssassin.java @@ -28,7 +28,7 @@ public final class StalkingAssassin extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public StalkingAssassin(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StalkingLeonin.java b/Mage.Sets/src/mage/cards/s/StalkingLeonin.java index 851483b435..2c5d8aec56 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingLeonin.java +++ b/Mage.Sets/src/mage/cards/s/StalkingLeonin.java @@ -17,7 +17,7 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.common.FilterCreatureAttackingYou; +import mage.filter.common.FilterCreatureAttackingYou; import mage.target.common.TargetCreaturePermanent; import java.util.UUID; diff --git a/Mage.Sets/src/mage/cards/s/StalkingVengeance.java b/Mage.Sets/src/mage/cards/s/StalkingVengeance.java index 5b1347dac6..b51f4e9fcc 100644 --- a/Mage.Sets/src/mage/cards/s/StalkingVengeance.java +++ b/Mage.Sets/src/mage/cards/s/StalkingVengeance.java @@ -31,7 +31,7 @@ public final class StalkingVengeance extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public StalkingVengeance(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java b/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java index fa8c460e58..cfc569df6f 100644 --- a/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java +++ b/Mage.Sets/src/mage/cards/s/StallionOfAshmouth.java @@ -1,12 +1,13 @@ - package mage.cards.s; import java.util.UUID; + import mage.MageInt; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,13 +16,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author fireshoes */ public final class StallionOfAshmouth extends CardImpl { public StallionOfAshmouth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.NIGHTMARE); this.subtype.add(SubType.HORSE); this.power = new MageInt(3); @@ -29,7 +29,12 @@ public final class StallionOfAshmouth extends CardImpl { // Delirium — {1}{B}: Stallion of Ashmouth gets +1/+1 until end of turn. Activate this ability only if there are // four or more card types among cards in your graveyard. - this.addAbility(new ConditionalActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{1}{B}"), DeliriumCondition.instance)); + this.addAbility(new ConditionalActivatedAbility( + Zone.BATTLEFIELD, + new BoostSourceEffect(1, 1, Duration.EndOfTurn), + new ManaCostsImpl("{1}{B}"), + DeliriumCondition.instance) + .addHint(DeliriumHint.instance)); } public StallionOfAshmouth(final StallionOfAshmouth card) { diff --git a/Mage.Sets/src/mage/cards/s/StampedingHorncrest.java b/Mage.Sets/src/mage/cards/s/StampedingHorncrest.java index 78d5d1f5ba..3a9cd4b932 100644 --- a/Mage.Sets/src/mage/cards/s/StampedingHorncrest.java +++ b/Mage.Sets/src/mage/cards/s/StampedingHorncrest.java @@ -27,7 +27,7 @@ public final class StampedingHorncrest extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Dinosaur"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DINOSAUR)); } diff --git a/Mage.Sets/src/mage/cards/s/StandOrFall.java b/Mage.Sets/src/mage/cards/s/StandOrFall.java new file mode 100644 index 0000000000..fcfe434040 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StandOrFall.java @@ -0,0 +1,131 @@ + +package mage.cards.s; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfCombatTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.RestrictionEffect; +import mage.abilities.effects.common.combat.CantBlockTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterCreaturePermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; + +/** + * + * @author LevelX2 & L_J + */ +public final class StandOrFall extends CardImpl { + + public StandOrFall(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}"); + + // At the beginning of combat on your turn, separate all creatures defending player controls into two piles. Only creatures in the pile of that player’s choice can block this turn. + this.addAbility(new BeginningOfCombatTriggeredAbility(new StandOrFallEffect(), TargetController.YOU, false)); + } + + public StandOrFall(final StandOrFall card) { + super(card); + } + + @Override + public StandOrFall copy() { + return new StandOrFall(this); + } +} + +class StandOrFallEffect extends OneShotEffect { + + public StandOrFallEffect() { + super(Outcome.Detriment); + this.staticText = "separate all creatures defending player controls into two piles. Only creatures in the pile of that player’s choice can block this turn"; + } + + public StandOrFallEffect(final StandOrFallEffect effect) { + super(effect); + } + + @Override + public StandOrFallEffect copy() { + return new StandOrFallEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + // 802.2. As the combat phase starts, the attacking player doesn’t choose an opponent to become the defending player. + // Instead, all the attacking player’s opponents are defending players during the combat phase. + // + // 802.2a Any rule, object, or effect that refers to a “defending player” refers to one specific defending player, not to all of the defending players. + // If an ability of an attacking creature refers to a defending player, or a spell or ability refers to both an attacking creature and a defending player, + // then unless otherwise specified, the defending player it’s referring to is the player that creature was attacking at the time it became an attacking + // creature that combat, or the controller of the planeswalker that creature was attacking at the time it became an attacking creature that combat. If a spell or ability + // could apply to multiple attacking creatures, the appropriate defending player is individually determined for each of those attacking creatures. + // If there are multiple defending players that could be chosen, the controller of the spell or ability chooses one. + // + // https://www.mtgsalvation.com/forums/magic-fundamentals/magic-rulings/756140-stand-or-fall-mechanics + Player player = game.getPlayer(source.getControllerId()); + Set opponents = game.getOpponents(source.getControllerId()); + if (!opponents.isEmpty()) { + Player targetPlayer = game.getPlayer(opponents.iterator().next()); + if (opponents.size() > 1) { + TargetOpponent targetOpponent = new TargetOpponent(true); + if (player != null && player.chooseTarget(Outcome.Neutral, targetOpponent, source, game)) { + targetPlayer = game.getPlayer(targetOpponent.getFirstTarget()); + game.informPlayers(player.getLogName() + " chose " + targetPlayer.getLogName() + " as the defending player"); + } + } + + if (player != null && targetPlayer != null) { + int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURES, targetPlayer.getId(), game); + TargetCreaturePermanent creatures = new TargetCreaturePermanent(0, count, new FilterCreaturePermanent("creatures to put in the first pile"), true); + List pile1 = new ArrayList<>(); + creatures.setRequired(false); + if (player.choose(Outcome.Neutral, creatures, source.getSourceId(), game)) { + List targets = creatures.getTargets(); + for (UUID targetId : targets) { + Permanent p = game.getPermanent(targetId); + if (p != null) { + pile1.add(p); + } + } + } + List pile2 = new ArrayList<>(); + for (Permanent p : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, targetPlayer.getId(), game)) { + if (!pile1.contains(p)) { + pile2.add(p); + } + } + + boolean choice = targetPlayer.choosePile(outcome, "Choose which pile can block this turn.", pile1, pile2, game); + List chosenPile = choice ? pile2 : pile1; + List otherPile = choice ? pile1 : pile2; + for (Permanent permanent : chosenPile) { + if (permanent != null) { + RestrictionEffect effect = new CantBlockTargetEffect(Duration.EndOfTurn); + effect.setText(""); + effect.setTargetPointer(new FixedTarget(permanent.getId())); + game.addEffect(effect, source); + } + } + game.informPlayers("Creatures that can block this turn: " + otherPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StandardBearer.java b/Mage.Sets/src/mage/cards/s/StandardBearer.java index ea49dd6852..941d862cb2 100644 --- a/Mage.Sets/src/mage/cards/s/StandardBearer.java +++ b/Mage.Sets/src/mage/cards/s/StandardBearer.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.ruleModifying.TargetsHaveToTargetPermanentIfAbleEffect; @@ -9,11 +8,10 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; -import mage.filter.FilterPermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class StandardBearer extends CardImpl { @@ -27,7 +25,7 @@ public final class StandardBearer extends CardImpl { this.toughness = new MageInt(1); // While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least one Flagbearer on the battlefield if able. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TargetsHaveToTargetPermanentIfAbleEffect(new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer")))); + this.addAbility(new SimpleStaticAbility(new TargetsHaveToTargetPermanentIfAbleEffect())); } public StandardBearer(final StandardBearer card) { diff --git a/Mage.Sets/src/mage/cards/s/StarCompass.java b/Mage.Sets/src/mage/cards/s/StarCompass.java index 707f220308..1cca2f5b2e 100644 --- a/Mage.Sets/src/mage/cards/s/StarCompass.java +++ b/Mage.Sets/src/mage/cards/s/StarCompass.java @@ -103,6 +103,9 @@ class StarCompassManaEffect extends ManaEffect { } if (!choice.getChoices().isEmpty()) { Player player = game.getPlayer(source.getControllerId()); + if(player == null){ + return false; + } if (choice.getChoices().size() == 1) { choice.setChoice(choice.getChoices().iterator().next()); } else { @@ -175,6 +178,9 @@ class StarCompassManaEffect extends ManaEffect { } if (!choice.getChoices().isEmpty()) { Player player = game.getPlayer(source.getControllerId()); + if(player == null){ + return null; + } if (choice.getChoices().size() == 1) { choice.setChoice(choice.getChoices().iterator().next()); } else { diff --git a/Mage.Sets/src/mage/cards/s/StarCrownedStag.java b/Mage.Sets/src/mage/cards/s/StarCrownedStag.java index e05d794229..6dc595c5d3 100644 --- a/Mage.Sets/src/mage/cards/s/StarCrownedStag.java +++ b/Mage.Sets/src/mage/cards/s/StarCrownedStag.java @@ -22,7 +22,7 @@ public final class StarCrownedStag extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public StarCrownedStag(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java b/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java index 8ab8ec89da..1ad2c7e2f3 100644 --- a/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java +++ b/Mage.Sets/src/mage/cards/s/StarfieldOfNyx.java @@ -80,7 +80,7 @@ class StarfieldOfNyxEffect extends ContinuousEffectImpl { static { filter.add(Predicates.not(new SubtypePredicate(SubType.AURA))); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/s/Starstorm.java b/Mage.Sets/src/mage/cards/s/Starstorm.java index 1d74ac89d2..bdf7d1c097 100644 --- a/Mage.Sets/src/mage/cards/s/Starstorm.java +++ b/Mage.Sets/src/mage/cards/s/Starstorm.java @@ -22,7 +22,7 @@ public final class Starstorm extends CardImpl { // Starstorm deals X damage to each creature. - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), new FilterCreaturePermanent())); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, new FilterCreaturePermanent())); // Cycling {3} this.addAbility(new CyclingAbility(new ManaCostsImpl("{3}"))); } diff --git a/Mage.Sets/src/mage/cards/s/StartFinish.java b/Mage.Sets/src/mage/cards/s/StartFinish.java index dba97d1e48..85890742ba 100644 --- a/Mage.Sets/src/mage/cards/s/StartFinish.java +++ b/Mage.Sets/src/mage/cards/s/StartFinish.java @@ -36,7 +36,7 @@ public final class StartFinish extends SplitCard { // Finish // Aftermath // As an additional cost to cast Finish, sacrifice a creature. Destroy target creature. - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); getRightHalfCard().getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); getRightHalfCard().getSpellAbility().addTarget(new TargetCreaturePermanent(new FilterCreaturePermanent("creature (to destoy)"))); getRightHalfCard().getSpellAbility().addEffect(new DestroyTargetEffect("Destroy target creature")); diff --git a/Mage.Sets/src/mage/cards/s/StasisSnare.java b/Mage.Sets/src/mage/cards/s/StasisSnare.java index 7dac21eb62..fe7447f46c 100644 --- a/Mage.Sets/src/mage/cards/s/StasisSnare.java +++ b/Mage.Sets/src/mage/cards/s/StasisSnare.java @@ -22,7 +22,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class StasisSnare extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/s/SteadyAim.java b/Mage.Sets/src/mage/cards/s/SteadyAim.java new file mode 100644 index 0000000000..ba8a85edfe --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteadyAim.java @@ -0,0 +1,44 @@ +package mage.cards.s; + +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ReachAbility; +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 SteadyAim extends CardImpl { + + public SteadyAim(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // Untap target creature. It gets +1/+4 and gains reach until end of turn. + this.getSpellAbility().addEffect(new UntapTargetEffect()); + this.getSpellAbility().addEffect(new BoostTargetEffect( + 1, 4, Duration.EndOfTurn + ).setText("It gets +1/+4")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + ReachAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains reach until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private SteadyAim(final SteadyAim card) { + super(card); + } + + @Override + public SteadyAim copy() { + return new SteadyAim(this); + } +} +// I'm labor ready Rhode Scholar for the dollar +// Work for mines pay me by the hour \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/StealthMission.java b/Mage.Sets/src/mage/cards/s/StealthMission.java new file mode 100644 index 0000000000..8befb349c1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StealthMission.java @@ -0,0 +1,39 @@ +package mage.cards.s; + +import mage.abilities.effects.common.combat.CantBeBlockedByAllTargetEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StealthMission extends CardImpl { + + public StealthMission(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}"); + + // Put two +1/+1 counters on target creature you control. That creature can't be blocked this turn. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))); + this.getSpellAbility().addEffect(new CantBeBlockedByAllTargetEffect( + StaticFilters.FILTER_PERMANENT_CREATURE, Duration.EndOfTurn + ).setText("That creature can't be blocked this turn.")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private StealthMission(final StealthMission card) { + super(card); + } + + @Override + public StealthMission copy() { + return new StealthMission(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SteamAugury.java b/Mage.Sets/src/mage/cards/s/SteamAugury.java index ae6183b7a8..54dd837bfd 100644 --- a/Mage.Sets/src/mage/cards/s/SteamAugury.java +++ b/Mage.Sets/src/mage/cards/s/SteamAugury.java @@ -71,8 +71,7 @@ class SteamAuguryEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.revealCards(sourceObject.getIdName(), cards, game); Player opponent; diff --git a/Mage.Sets/src/mage/cards/s/SteamCatapult.java b/Mage.Sets/src/mage/cards/s/SteamCatapult.java index 16402a4abd..8262509c4d 100644 --- a/Mage.Sets/src/mage/cards/s/SteamCatapult.java +++ b/Mage.Sets/src/mage/cards/s/SteamCatapult.java @@ -26,7 +26,7 @@ public final class SteamCatapult extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SteamCatapult(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SteamVines.java b/Mage.Sets/src/mage/cards/s/SteamVines.java index 3ea35f78e8..317d2ba47b 100644 --- a/Mage.Sets/src/mage/cards/s/SteamVines.java +++ b/Mage.Sets/src/mage/cards/s/SteamVines.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BecomesTappedAttachedTriggeredAbility; import mage.abilities.effects.Effect; @@ -24,8 +22,9 @@ import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth & L_J */ public final class SteamVines extends CardImpl { @@ -76,7 +75,6 @@ class SteamVinesEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent steamVines = game.getPermanentOrLKIBattlefield(source.getSourceId()); - Card steamVinesCard = game.getCard(source.getSourceId()); if (steamVines != null) { Permanent enchantedLand = game.getPermanentOrLKIBattlefield(steamVines.getAttachedTo()); Player controller = game.getPlayer(source.getControllerId()); @@ -85,13 +83,15 @@ class SteamVinesEffect extends OneShotEffect { Player landsController = game.getPlayer(enchantedLand.getControllerId()); if (game.getState().getZone(enchantedLand.getId()) == Zone.BATTLEFIELD) { // if 2 or more Steam Vines were on a land enchantedLand.destroy(source.getId(), game, false); - landsController.damage(1, source.getSourceId(), game, false, true); + if (landsController != null) { + landsController.damage(1, source.getSourceId(), game, false, true); + } } if (!game.getBattlefield().getAllActivePermanents(CardType.LAND).isEmpty()) { //lands are available on the battlefield Target target = new TargetLandPermanent(); target.setNotTarget(true); //not a target, it is chosen - if (steamVinesCard != null - && landsController != null) { + Card steamVinesCard = game.getCard(source.getSourceId()); + if (steamVinesCard != null && landsController != null) { if (landsController.choose(Outcome.DestroyPermanent, target, source.getId(), game)) { if (target.getFirstTarget() != null) { Permanent landChosen = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/s/SteelHellkite.java b/Mage.Sets/src/mage/cards/s/SteelHellkite.java index 694efcbf18..b114bfb4d6 100644 --- a/Mage.Sets/src/mage/cards/s/SteelHellkite.java +++ b/Mage.Sets/src/mage/cards/s/SteelHellkite.java @@ -84,7 +84,7 @@ class SteelHellkiteDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - SteelHellkiteWatcher watcher = (SteelHellkiteWatcher) game.getState().getWatchers().get(SteelHellkiteWatcher.class.getSimpleName()); + SteelHellkiteWatcher watcher = game.getState().getWatcher(SteelHellkiteWatcher.class); if (watcher == null || watcher.getDamagedPlayers(source.getSourceId()).isEmpty()) { return false; } @@ -104,7 +104,7 @@ class SteelHellkiteWatcher extends Watcher { private final Map> damageMap = new HashMap<>(); public SteelHellkiteWatcher() { - super(SteelHellkiteWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SteelHellkiteWatcher(final SteelHellkiteWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/SteelSabotage.java b/Mage.Sets/src/mage/cards/s/SteelSabotage.java index d8553c5e13..83982a6d7c 100644 --- a/Mage.Sets/src/mage/cards/s/SteelSabotage.java +++ b/Mage.Sets/src/mage/cards/s/SteelSabotage.java @@ -24,8 +24,8 @@ public final class SteelSabotage extends CardImpl { this.getSpellAbility().addEffect(new CounterTargetEffect()); this.getSpellAbility().addTarget(new TargetSpell(new FilterArtifactSpell())); Mode mode = new Mode(); - mode.getEffects().add(new ReturnToHandTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java b/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java index feeccfd132..2eb98aaa06 100644 --- a/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java +++ b/Mage.Sets/src/mage/cards/s/SteelcladSerpent.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,8 +7,8 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -18,14 +16,15 @@ import mage.filter.predicate.permanent.AnotherPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class SteelcladSerpent extends CardImpl { public SteelcladSerpent(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{5}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{5}{U}"); this.subtype.add(SubType.SERPENT); this.power = new MageInt(4); @@ -48,10 +47,10 @@ public final class SteelcladSerpent extends CardImpl { class SteelcladSerpentEffect extends RestrictionEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another artifact"); - + static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public SteelcladSerpentEffect() { @@ -69,18 +68,15 @@ class SteelcladSerpentEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (!game.getBattlefield().getActivePermanents(filter, source.getControllerId(), permanent.getId(), game).isEmpty()) { - return false; - } - return true; - } + return game.getBattlefield().getActivePermanents(filter, source.getControllerId(), permanent.getId(), game).isEmpty(); + } return false; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SteepleCreeper.java b/Mage.Sets/src/mage/cards/s/SteepleCreeper.java new file mode 100644 index 0000000000..ebb8958b1c --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SteepleCreeper.java @@ -0,0 +1,45 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SteepleCreeper extends CardImpl { + + public SteepleCreeper(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.FROG); + this.subtype.add(SubType.SNAKE); + this.power = new MageInt(4); + this.toughness = new MageInt(2); + + // {3}{U}: Steeple Creeper gains flying until end of turn. + this.addAbility(new SimpleActivatedAbility( + new GainAbilitySourceEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl("{3}{U}") + )); + } + + private SteepleCreeper(final SteepleCreeper card) { + super(card); + } + + @Override + public SteepleCreeper copy() { + return new SteepleCreeper(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StenchOfEvil.java b/Mage.Sets/src/mage/cards/s/StenchOfEvil.java new file mode 100644 index 0000000000..b85fcf0603 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StenchOfEvil.java @@ -0,0 +1,81 @@ +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.ManaCostsImpl; +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.filter.common.FilterLandPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class StenchOfEvil extends CardImpl { + + public StenchOfEvil(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); + + // Destroy all Plains. For each land destroyed this way, Stench of Evil deals 1 damage to that land's controller unless he or she pays {2}. + this.getSpellAbility().addEffect(new StenchOfEvilEffect()); + + } + + private StenchOfEvil(final StenchOfEvil card) { + super(card); + } + + @Override + public StenchOfEvil copy() { + return new StenchOfEvil(this); + } +} + +class StenchOfEvilEffect extends OneShotEffect { + + private static final FilterLandPermanent filter = new FilterLandPermanent(); + + static { + filter.add(new SubtypePredicate(SubType.PLAINS)); + } + + public StenchOfEvilEffect() { + super(Outcome.Benefit); + this.staticText = "Destroy all Plains. For each land destroyed this way, {this} deals 1 damage to that land's controller unless he or she pays {2}"; + } + + public StenchOfEvilEffect(final StenchOfEvilEffect effect) { + super(effect); + } + + @Override + public StenchOfEvilEffect copy() { + return new StenchOfEvilEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + for (Permanent land : game.getBattlefield().getAllActivePermanents(filter, game)) { + UUID landControllerId = land.getControllerId(); + if (land.destroy(source.getSourceId(), game, false)) { + Cost cost = new ManaCostsImpl("{2}"); + Player landController = game.getPlayer(landControllerId); + if (landController != null + && cost.canPay(source, source.getSourceId(), landControllerId, game) + && !cost.pay(source, game, source.getSourceId(), landControllerId, false)) { + landController.damage(1, source.getSourceId(), game, false, true); + } + } + } + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StensiaInnkeeper.java b/Mage.Sets/src/mage/cards/s/StensiaInnkeeper.java index dd254e1a64..f6c5033a8e 100644 --- a/Mage.Sets/src/mage/cards/s/StensiaInnkeeper.java +++ b/Mage.Sets/src/mage/cards/s/StensiaInnkeeper.java @@ -22,7 +22,7 @@ import mage.target.TargetPermanent; */ public final class StensiaInnkeeper extends CardImpl { - private final static FilterLandPermanent filter = new FilterLandPermanent("land an opponent controls"); + private static final FilterLandPermanent filter = new FilterLandPermanent("land an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java b/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java index 61f2a5dc8a..ee86d460f3 100644 --- a/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java +++ b/Mage.Sets/src/mage/cards/s/StensiaMasquerade.java @@ -35,7 +35,7 @@ public final class StensiaMasquerade extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public StensiaMasquerade(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StirTheGrave.java b/Mage.Sets/src/mage/cards/s/StirTheGrave.java index 39d56a262c..818993060f 100644 --- a/Mage.Sets/src/mage/cards/s/StirTheGrave.java +++ b/Mage.Sets/src/mage/cards/s/StirTheGrave.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect; import mage.cards.CardImpl; @@ -13,29 +12,21 @@ import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class StirTheGrave extends CardImpl { public StirTheGrave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}"); // Return target creature card with converted mana cost X or less from your graveyard to the battlefield. - this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterCreatureCard("creature card with converted mana cost X or less from your graveyard"))); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); - ability.getTargets().add(new TargetCardInYourGraveyard(filter)); + this.getSpellAbility().addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect().setText("return target creature card with converted mana cost X or less from your graveyard to the battlefield")); + this.getSpellAbility().setTargetAdjuster(StirTheGraveAdjuster.instance); } public StirTheGrave(final StirTheGrave card) { @@ -47,3 +38,16 @@ public final class StirTheGrave extends CardImpl { return new StirTheGrave(this); } } + +enum StirTheGraveAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less from your graveyard"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + ability.getTargets().add(new TargetCardInYourGraveyard(filter)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/StirThePride.java b/Mage.Sets/src/mage/cards/s/StirThePride.java index ef709d468c..4232e3c179 100644 --- a/Mage.Sets/src/mage/cards/s/StirThePride.java +++ b/Mage.Sets/src/mage/cards/s/StirThePride.java @@ -32,7 +32,7 @@ public final class StirThePride extends CardImpl { Mode mode = new Mode(); Effect effect = new GainAbilityControlledEffect(new DealsDamageGainLifeSourceTriggeredAbility(), Duration.EndOfTurn); effect.setText("until end of turn, creatures you control gain \"Whenever this creature deals damage, you gain that much life.\""); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().getModes().addMode(mode); // Entwine {1}{W} diff --git a/Mage.Sets/src/mage/cards/s/StitchInTime.java b/Mage.Sets/src/mage/cards/s/StitchInTime.java index 4bafd1b73b..c1dc506c43 100644 --- a/Mage.Sets/src/mage/cards/s/StitchInTime.java +++ b/Mage.Sets/src/mage/cards/s/StitchInTime.java @@ -52,7 +52,7 @@ class StitchInTimeEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (player.flipCoin(game)) { + if (player.flipCoin(source, game, true)) { game.getState().getTurnMods().add(new TurnMod(player.getId(), false)); return true; } diff --git a/Mage.Sets/src/mage/cards/s/StolenGoods.java b/Mage.Sets/src/mage/cards/s/StolenGoods.java index 2341ff2fa6..578d83d51f 100644 --- a/Mage.Sets/src/mage/cards/s/StolenGoods.java +++ b/Mage.Sets/src/mage/cards/s/StolenGoods.java @@ -2,6 +2,7 @@ package mage.cards.s; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousEffect; @@ -21,7 +22,6 @@ import mage.target.targetpointer.FixedTarget; import mage.util.CardUtil; /** - * * @author noxx */ public final class StolenGoods extends CardImpl { @@ -111,8 +111,10 @@ class StolenGoodsCastFromExileEffect extends AsThoughEffectImpl { Card card = game.getCard(sourceId); if (card != null && game.getState().getZone(sourceId) == Zone.EXILED) { Player player = game.getPlayer(affectedControllerId); - player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); - return true; + if (player != null) { + player.setCastSourceIdWithAlternateMana(sourceId, null, card.getSpellAbility().getCosts()); + return true; + } } } return false; diff --git a/Mage.Sets/src/mage/cards/s/StolenStrategy.java b/Mage.Sets/src/mage/cards/s/StolenStrategy.java index 18e0108846..e20f44395e 100644 --- a/Mage.Sets/src/mage/cards/s/StolenStrategy.java +++ b/Mage.Sets/src/mage/cards/s/StolenStrategy.java @@ -85,7 +85,7 @@ class StolenStrategyEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = damagedPlayer.getLibrary().getFromTop(game); - if (card != null) { + if (card != null && sourceObject != null) { // move card to exile controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); // Add effects only if the card has a spellAbility (e.g. not for lands). @@ -164,6 +164,7 @@ class StolenStrategySpendAnyManaEffect extends AsThoughEffectImpl implements AsT @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards return source.isControlledBy(affectedControllerId) && Objects.equals(objectId, ((FixedTarget) getTargetPointer()).getTarget()) && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) diff --git a/Mage.Sets/src/mage/cards/s/StompingSlabs.java b/Mage.Sets/src/mage/cards/s/StompingSlabs.java index a843ecf37b..2990e7bdb4 100644 --- a/Mage.Sets/src/mage/cards/s/StompingSlabs.java +++ b/Mage.Sets/src/mage/cards/s/StompingSlabs.java @@ -62,8 +62,7 @@ class StompingSlabsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 7)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); if (!cards.isEmpty()) { controller.revealCards("Stomping Slabs", cards, game); boolean stompingSlabsFound = false; diff --git a/Mage.Sets/src/mage/cards/s/StoneCatapult.java b/Mage.Sets/src/mage/cards/s/StoneCatapult.java index 594edb549f..9a2db55b70 100644 --- a/Mage.Sets/src/mage/cards/s/StoneCatapult.java +++ b/Mage.Sets/src/mage/cards/s/StoneCatapult.java @@ -29,7 +29,7 @@ public final class StoneCatapult extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped nonblack creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); } diff --git a/Mage.Sets/src/mage/cards/s/StoneHavenOutfitter.java b/Mage.Sets/src/mage/cards/s/StoneHavenOutfitter.java index da5f4c1571..99f376716e 100644 --- a/Mage.Sets/src/mage/cards/s/StoneHavenOutfitter.java +++ b/Mage.Sets/src/mage/cards/s/StoneHavenOutfitter.java @@ -27,7 +27,7 @@ public final class StoneHavenOutfitter extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("equipped creatures you control"); static { - filter.add(new EquippedPredicate()); + filter.add(EquippedPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java index ec70487013..3209b413c1 100644 --- a/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java +++ b/Mage.Sets/src/mage/cards/s/StoneIdolTrap.java @@ -51,7 +51,7 @@ class StoneIdolTrapCostReductionEffect extends CostModificationEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public StoneIdolTrapCostReductionEffect() { diff --git a/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java b/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java index 617c31166f..d4e82d39c8 100644 --- a/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java +++ b/Mage.Sets/src/mage/cards/s/StoneforgeAcolyte.java @@ -33,7 +33,7 @@ public final class StoneforgeAcolyte extends CardImpl { static { filterAlly.add(new SubtypePredicate(SubType.ALLY)); - filterAlly.add(Predicates.not(new TappedPredicate())); + filterAlly.add(Predicates.not(TappedPredicate.instance)); filterEquipment.add(new SubtypePredicate(SubType.EQUIPMENT)); } diff --git a/Mage.Sets/src/mage/cards/s/StonehewerGiant.java b/Mage.Sets/src/mage/cards/s/StonehewerGiant.java index 8fb3a3d39c..70de8c460b 100644 --- a/Mage.Sets/src/mage/cards/s/StonehewerGiant.java +++ b/Mage.Sets/src/mage/cards/s/StonehewerGiant.java @@ -88,7 +88,7 @@ class StonehewerGiantEffect extends OneShotEffect { FilterCard filter = new FilterCard("Equipment"); filter.add(new SubtypePredicate(SubType.EQUIPMENT)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/s/StonehoofChieftain.java b/Mage.Sets/src/mage/cards/s/StonehoofChieftain.java index cdfdd7e377..fbd63a49a5 100644 --- a/Mage.Sets/src/mage/cards/s/StonehoofChieftain.java +++ b/Mage.Sets/src/mage/cards/s/StonehoofChieftain.java @@ -29,7 +29,7 @@ public final class StonehoofChieftain extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public StonehoofChieftain(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StonehornDignitary.java b/Mage.Sets/src/mage/cards/s/StonehornDignitary.java index 3f92110a13..0443f4f16d 100644 --- a/Mage.Sets/src/mage/cards/s/StonehornDignitary.java +++ b/Mage.Sets/src/mage/cards/s/StonehornDignitary.java @@ -1,14 +1,14 @@ - package mage.cards.s; import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.effects.common.SkipNextCombatEffect; +import mage.abilities.effects.common.SkipCombatStepEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.Duration; import mage.constants.SubType; import mage.target.common.TargetOpponent; @@ -17,27 +17,27 @@ import mage.target.common.TargetOpponent; * @author nantuko */ public final class StonehornDignitary extends CardImpl { - + public StonehornDignitary(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.RHINO); this.subtype.add(SubType.SOLDIER); - + this.power = new MageInt(1); this.toughness = new MageInt(4); // When Stonehorn Dignitary enters the battlefield, target opponent skips their next combat phase. - Ability ability = new EntersBattlefieldTriggeredAbility(new SkipNextCombatEffect()); + Ability ability = new EntersBattlefieldTriggeredAbility(new SkipCombatStepEffect(Duration.OneUse).setText("target opponent skips their next combat phase.")); ability.addTarget(new TargetOpponent()); this.addAbility(ability); } - + public StonehornDignitary(final StonehornDignitary card) { super(card); } - + @Override public StonehornDignitary copy() { return new StonehornDignitary(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/s/StoneshakerShaman.java b/Mage.Sets/src/mage/cards/s/StoneshakerShaman.java index 75802aa16d..3454de1198 100644 --- a/Mage.Sets/src/mage/cards/s/StoneshakerShaman.java +++ b/Mage.Sets/src/mage/cards/s/StoneshakerShaman.java @@ -23,7 +23,7 @@ public final class StoneshakerShaman extends CardImpl { private static final FilterLandPermanent filter = new FilterLandPermanent("untapped land"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public StoneshakerShaman(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java index 54bd8c9708..67848f60fa 100644 --- a/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java +++ b/Mage.Sets/src/mage/cards/s/StonewiseFortifier.java @@ -77,10 +77,10 @@ class StonewiseFortifierPreventAllDamageToEffect extends PreventionEffectImpl { MageObject damageSource = game.getObject(event.getSourceId()); MageObject preventionSource = game.getObject(source.getSourceId()); if (damageSource != null && preventionSource != null) { - StringBuilder message = new StringBuilder(preventedDamage).append(" damage from "); - message.append(damageSource.getName()).append(" prevented "); - message.append('(').append(preventionSource).append(')'); - game.informPlayers(message.toString()); + String message = " damage from " + + damageSource.getName() + " prevented " + + '(' + preventionSource + ')'; + game.informPlayers(message); } event.setAmount(0); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.PREVENTED_DAMAGE, event.getTargetId(), source.getSourceId(), source.getControllerId(), preventedDamage)); diff --git a/Mage.Sets/src/mage/cards/s/StonySilence.java b/Mage.Sets/src/mage/cards/s/StonySilence.java index 6c7fdc4274..0aca8dc253 100644 --- a/Mage.Sets/src/mage/cards/s/StonySilence.java +++ b/Mage.Sets/src/mage/cards/s/StonySilence.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -13,14 +11,15 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class StonySilence extends CardImpl { public StonySilence(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); // Activated abilities of artifacts can't be activated. @@ -55,7 +54,7 @@ class StonySilenceCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/StonyStrength.java b/Mage.Sets/src/mage/cards/s/StonyStrength.java new file mode 100644 index 0000000000..643b81cd9d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StonyStrength.java @@ -0,0 +1,35 @@ +package mage.cards.s; + +import mage.abilities.effects.common.UntapTargetEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StonyStrength extends CardImpl { + + public StonyStrength(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Put a +1/+1 counter on target creature you control. Untap that creature. + this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance())); + this.getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap that creature")); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + } + + private StonyStrength(final StonyStrength card) { + super(card); + } + + @Override + public StonyStrength copy() { + return new StonyStrength(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StorageMatrix.java b/Mage.Sets/src/mage/cards/s/StorageMatrix.java index e2283a6073..6face1e494 100644 --- a/Mage.Sets/src/mage/cards/s/StorageMatrix.java +++ b/Mage.Sets/src/mage/cards/s/StorageMatrix.java @@ -1,9 +1,5 @@ - package mage.cards.s; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -19,8 +15,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class StorageMatrix extends CardImpl { @@ -53,6 +52,7 @@ class StorageMatrixRestrictionEffect extends RestrictionEffect { choice.add(CardType.CREATURE.toString()); choice.add(CardType.LAND.toString()); } + private CardType type; public StorageMatrixRestrictionEffect() { @@ -104,7 +104,7 @@ class StorageMatrixRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/StormElemental.java b/Mage.Sets/src/mage/cards/s/StormElemental.java new file mode 100644 index 0000000000..77d417757f --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormElemental.java @@ -0,0 +1,155 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.common.FilterLandCard; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 & L_J + */ +public final class StormElemental extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with flying"); + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public StormElemental(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{U}"); + this.subtype.add(SubType.ELEMENTAL); + this.power = new MageInt(3); + this.toughness = new MageInt(4); + + // {U}, Exile the top card of your library: Tap target creature with flying. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new TapTargetEffect(), new ManaCostsImpl("{U}")); + ability.addCost(new ExileTopCardLibraryCost()); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + + // {U}, Exile the top card of your library: If the exiled card is a snow land, Storm Elemental gets +1/+1 until end of turn. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new StormElementalEffect(), new ManaCostsImpl("{U}")); + ability2.addCost(new ExileTopCardLibraryCost()); + this.addAbility(ability2); + } + + public StormElemental(final StormElemental card) { + super(card); + } + + @Override + public StormElemental copy() { + return new StormElemental(this); + } +} + +class StormElementalEffect extends OneShotEffect { + + private static final FilterLandCard filter = new FilterLandCard("snow land"); + static { + filter.add(new SupertypePredicate(SuperType.SNOW)); + } + + public StormElementalEffect() { + super(Outcome.BoostCreature); + this.staticText = "If the exiled card is a snow land, {this} gets +1/+1 until end of turn"; + } + + public StormElementalEffect(final StormElementalEffect effect) { + super(effect); + } + + @Override + public StormElementalEffect copy() { + return new StormElementalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Card card = null; + for (Cost cost : source.getCosts()) { + if (cost instanceof ExileTopCardLibraryCost) { + card = ((ExileTopCardLibraryCost) cost).getCard(); + } + } + if (card != null) { + if (filter.match(card, game)) { + game.addEffect(new BoostSourceEffect(1, 1, Duration.EndOfTurn), source); + } + } + return true; + } + return false; + } +} + +class ExileTopCardLibraryCost extends CostImpl { + + Card card; + + public ExileTopCardLibraryCost() { + this.text = "Exile the top card of your library"; + } + + public ExileTopCardLibraryCost(final ExileTopCardLibraryCost cost) { + super(cost); + this.card = cost.getCard(); + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + Player controller = game.getPlayer(controllerId); + if (controller != null) { + card = controller.getLibrary().getFromTop(game); + if (card != null) { + paid = controller.moveCards(card, Zone.EXILED, ability, game); + } + } + return paid; + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + Player controller = game.getPlayer(controllerId); + if (controller != null) { + return controller.getLibrary().hasCards(); + } + return false; + } + + @Override + public ExileTopCardLibraryCost copy() { + return new ExileTopCardLibraryCost(this); + } + + public Card getCard() { + return card; + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormEntity.java b/Mage.Sets/src/mage/cards/s/StormEntity.java index e0a2f1adf0..33516f8d26 100644 --- a/Mage.Sets/src/mage/cards/s/StormEntity.java +++ b/Mage.Sets/src/mage/cards/s/StormEntity.java @@ -54,8 +54,11 @@ class OtherSpellsCastThisTurnCount implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); - return watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn() - 1; + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if(watcher != null ) { + return watcher.getAmountOfSpellsAllPlayersCastOnCurrentTurn() - 1; + } + return 0; } @Override diff --git a/Mage.Sets/src/mage/cards/s/StormFleetSwashbuckler.java b/Mage.Sets/src/mage/cards/s/StormFleetSwashbuckler.java index bfcb93d8e4..fae7b70ebb 100644 --- a/Mage.Sets/src/mage/cards/s/StormFleetSwashbuckler.java +++ b/Mage.Sets/src/mage/cards/s/StormFleetSwashbuckler.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +7,7 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.DoubleStrikeAbility; import mage.cards.CardImpl; @@ -18,8 +17,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class StormFleetSwashbuckler extends CardImpl { @@ -39,7 +39,7 @@ public final class StormFleetSwashbuckler extends CardImpl { ContinuousEffect boostSource = new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.WhileOnBattlefield); ConditionalContinuousEffect effect = new ConditionalContinuousEffect(boostSource, CitysBlessingCondition.instance, "{this} has double strike as long as you have the city's blessing"); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect).addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/StormHerd.java b/Mage.Sets/src/mage/cards/s/StormHerd.java index 9ba7cb1bc3..c2fac4e69c 100644 --- a/Mage.Sets/src/mage/cards/s/StormHerd.java +++ b/Mage.Sets/src/mage/cards/s/StormHerd.java @@ -19,7 +19,7 @@ public final class StormHerd extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{8}{W}{W}"); // create X 1/1 white Pegasus creature tokens with flying, where X is your life total. - this.getSpellAbility().addEffect(new CreateTokenEffect(new PegasusToken(), new ControllerLifeCount())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new PegasusToken(), ControllerLifeCount.instance)); } public StormHerd(final StormHerd card) { diff --git a/Mage.Sets/src/mage/cards/s/StormSeeker.java b/Mage.Sets/src/mage/cards/s/StormSeeker.java index 63460d878c..173b24552c 100644 --- a/Mage.Sets/src/mage/cards/s/StormSeeker.java +++ b/Mage.Sets/src/mage/cards/s/StormSeeker.java @@ -20,7 +20,7 @@ public final class StormSeeker extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{3}{G}"); // Storm Seeker deals damage to target player equal to the number of cards in that player's hand. - Effect effect = new DamageTargetEffect(new CardsInTargetHandCount()); + Effect effect = new DamageTargetEffect(CardsInTargetHandCount.instance); effect.setText("{this} deals damage to target player equal to the number of cards in that player's hand."); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/s/StormStrike.java b/Mage.Sets/src/mage/cards/s/StormStrike.java new file mode 100644 index 0000000000..bfccf2c590 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormStrike.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.FirstStrikeAbility; +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 StormStrike extends CardImpl { + + public StormStrike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); + + // Target creature gets +1/+0 and gains first strike until end of turn. Scry 1. + this.getSpellAbility().addEffect( + new BoostTargetEffect(1, 0) + .setText("target creature gets +1/+0") + ); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + FirstStrikeAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains first strike until end of turn")); + this.getSpellAbility().addEffect(new ScryEffect(1)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private StormStrike(final StormStrike card) { + super(card); + } + + @Override + public StormStrike copy() { + return new StormStrike(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormTheCitadel.java b/Mage.Sets/src/mage/cards/s/StormTheCitadel.java new file mode 100644 index 0000000000..0b7f2266d8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StormTheCitadel.java @@ -0,0 +1,65 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.DefendingPlayerControlsPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StormTheCitadel extends CardImpl { + + private static final FilterPermanent filter + = new FilterPermanent("artifact or enchantment defending player controls"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.ENCHANTMENT) + )); + filter.add(DefendingPlayerControlsPredicate.instance); + } + + public StormTheCitadel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{G}"); + + // Until end of turn, creatures you control get +2/+2 and gain "Whenever this creature deals combat damage to a creature or planeswalker, destroy target artifact or enchantment defending player controls." + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new DestroyTargetEffect(), false + ).setOrPlaneswalker(true); + ability.addTarget(new TargetPermanent(filter)); + + this.getSpellAbility().addEffect(new BoostControlledEffect( + 2, 2, Duration.EndOfTurn + ).setText("Until end of turn, creatures you control get +2/+2")); + + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + ability, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURE + ).setText("and gain \"Whenever this creature deals combat damage to a player or planeswalker, " + + "destroy target artifact or enchantment defending player controls.\"" + )); + } + + private StormTheCitadel(final StormTheCitadel card) { + super(card); + } + + @Override + public StormTheCitadel copy() { + return new StormTheCitadel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StormwingDragon.java b/Mage.Sets/src/mage/cards/s/StormwingDragon.java index c03b2124fd..b5d8949245 100644 --- a/Mage.Sets/src/mage/cards/s/StormwingDragon.java +++ b/Mage.Sets/src/mage/cards/s/StormwingDragon.java @@ -27,7 +27,7 @@ public final class StormwingDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("other Dragon creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.DRAGON)); } diff --git a/Mage.Sets/src/mage/cards/s/StorrevDevkarinLich.java b/Mage.Sets/src/mage/cards/s/StorrevDevkarinLich.java new file mode 100644 index 0000000000..1190dcee43 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/StorrevDevkarinLich.java @@ -0,0 +1,134 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.target.common.TargetCardInYourGraveyard; +import mage.watchers.Watcher; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class StorrevDevkarinLich extends CardImpl { + + private static final FilterCard filter = new FilterCard( + "creature or planeswalker card in your graveyard that wasn't put there this combat" + ); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); + filter.add(StorrevDevkarinLichPredicate.instance); + } + + public StorrevDevkarinLich(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(5); + this.toughness = new MageInt(4); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // Whenever Storrev, Devkarin Lich deals combat damage to a player or planeswalker, return to your hand target creature or planeswalker card in your graveyard that wasn't put there this combat. + Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility( + new ReturnToHandTargetEffect(), false + ).setOrPlaneswalker(true); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability, new StorrevDevkarinLichWatcher()); + } + + private StorrevDevkarinLich(final StorrevDevkarinLich card) { + super(card); + } + + @Override + public StorrevDevkarinLich copy() { + return new StorrevDevkarinLich(this); + } +} + +enum StorrevDevkarinLichPredicate implements Predicate { + instance; + + @Override + public boolean apply(Card input, Game game) { + StorrevDevkarinLichWatcher watcher = game.getState().getWatcher(StorrevDevkarinLichWatcher.class); + if (watcher == null) { + return false; + } + return !watcher.wasPutInAGraveyardThisCombat(input.getId(), game); + } +} + +class StorrevDevkarinLichWatcher extends Watcher { + + private final Set cards = new HashSet<>(); + + StorrevDevkarinLichWatcher() { + super(WatcherScope.GAME); + } + + private StorrevDevkarinLichWatcher(final StorrevDevkarinLichWatcher watcher) { + super(watcher); + this.cards.addAll(watcher.cards); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.BEGIN_COMBAT_STEP_PRE) { + cards.clear(); + } + if (event.getType() == GameEvent.EventType.ZONE_CHANGE + && ((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) { + Card card = game.getCard(event.getTargetId()); + if (card != null && (card.isCreature() || card.isPlaneswalker())) { + cards.add(new MageObjectReference(card, game)); + } + } + } + + @Override + public StorrevDevkarinLichWatcher copy() { + return new StorrevDevkarinLichWatcher(this); + } + + boolean wasPutInAGraveyardThisCombat(UUID cardId, Game game) { + for (MageObjectReference mor : cards) { + if (mor.refersTo(cardId, game)) { + return true; + } + } + return false; + } + + @Override + public void reset() { + super.reset(); + cards.clear(); + } +} diff --git a/Mage.Sets/src/mage/cards/s/StrangeAugmentation.java b/Mage.Sets/src/mage/cards/s/StrangeAugmentation.java index e635930915..d348784e50 100644 --- a/Mage.Sets/src/mage/cards/s/StrangeAugmentation.java +++ b/Mage.Sets/src/mage/cards/s/StrangeAugmentation.java @@ -1,13 +1,14 @@ - package mage.cards.s; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,13 +20,12 @@ import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author LevelX2 */ public final class StrangeAugmentation extends CardImpl { public StrangeAugmentation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{B}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -40,7 +40,8 @@ public final class StrangeAugmentation extends CardImpl { // Delirium &mdash Enchanted creature gets an additional +2/+2 as long as there are four or more card types among cards in your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(new BoostEnchantedEffect(2, 2), DeliriumCondition.instance, - "Delirium — Enchanted creature gets an additional +2/+2 as long as there are four or more card types among cards in your graveyard."))); + "Delirium — Enchanted creature gets an additional +2/+2 as long as there are four or more card types among cards in your graveyard.")) + .addHint(DeliriumHint.instance)); } public StrangeAugmentation(final StrangeAugmentation card) { diff --git a/Mage.Sets/src/mage/cards/s/StrataScythe.java b/Mage.Sets/src/mage/cards/s/StrataScythe.java index 21f8c0645e..9e362b19ff 100644 --- a/Mage.Sets/src/mage/cards/s/StrataScythe.java +++ b/Mage.Sets/src/mage/cards/s/StrataScythe.java @@ -69,7 +69,7 @@ class StrataScytheImprintEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard()); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { UUID cardId = target.getTargets().get(0); Card card = player.getLibrary().remove(cardId, game); diff --git a/Mage.Sets/src/mage/cards/s/StreamOfLife.java b/Mage.Sets/src/mage/cards/s/StreamOfLife.java index 97e91d04b3..51924a217b 100644 --- a/Mage.Sets/src/mage/cards/s/StreamOfLife.java +++ b/Mage.Sets/src/mage/cards/s/StreamOfLife.java @@ -20,7 +20,7 @@ public final class StreamOfLife extends CardImpl { // Target player gains X life. - this.getSpellAbility().addEffect(new GainLifeTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new GainLifeTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/s/StreetSpasm.java b/Mage.Sets/src/mage/cards/s/StreetSpasm.java index fa0f2d43e8..e10d340862 100644 --- a/Mage.Sets/src/mage/cards/s/StreetSpasm.java +++ b/Mage.Sets/src/mage/cards/s/StreetSpasm.java @@ -37,10 +37,10 @@ public final class StreetSpasm extends CardImpl { // Street Spasm deals X damage to target creature without flying you don't control. this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); // Overload {X}{X}{R}{R} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") - this.addAbility(new OverloadAbility(this, new DamageAllEffect(new ManacostVariableValue(), filter), new ManaCostsImpl("{X}{X}{R}{R}"))); + this.addAbility(new OverloadAbility(this, new DamageAllEffect(ManacostVariableValue.instance, filter), new ManaCostsImpl("{X}{X}{R}{R}"))); } public StreetSpasm(final StreetSpasm card) { diff --git a/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java b/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java index 93d7d0d141..73a007d69f 100644 --- a/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java +++ b/Mage.Sets/src/mage/cards/s/StrengthOfTheTajuru.java @@ -1,9 +1,7 @@ - package mage.cards.s; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.MultikickerAbility; @@ -16,7 +14,7 @@ import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; - +import mage.target.targetadjustment.TargetAdjuster; /** * @author noxx @@ -24,7 +22,7 @@ import mage.target.common.TargetCreaturePermanent; public final class StrengthOfTheTajuru extends CardImpl { public StrengthOfTheTajuru(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}{G}"); // Multikicker (You may pay an additional {1} any number of times as you cast this spell.) this.addAbility(new MultikickerAbility("{1}")); @@ -32,15 +30,7 @@ public final class StrengthOfTheTajuru extends CardImpl { // Choose target creature, then choose another target creature for each time Strength of the Tajuru was kicked. Put X +1/+1 counters on each of them. this.getSpellAbility().addEffect(new StrengthOfTheTajuruAddCountersTargetEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, Integer.MAX_VALUE)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numbTargets = new MultikickerCount().calculate(game, ability, null) + 1; - ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); - } + this.getSpellAbility().setTargetAdjuster(StrengthOfTheTajuruAdjuster.instance); } public StrengthOfTheTajuru(final StrengthOfTheTajuru card) { @@ -53,6 +43,17 @@ public final class StrengthOfTheTajuru extends CardImpl { } } +enum StrengthOfTheTajuruAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = MultikickerCount.instance.calculate(game, ability, null) + 1; + ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); + } +} + class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { public StrengthOfTheTajuruAddCountersTargetEffect() { @@ -73,7 +74,7 @@ class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { Permanent permanent = game.getPermanent(uuid); if (permanent != null) { permanent.addCounters(counter.copy(), source, game); - affectedTargets ++; + affectedTargets++; } } return affectedTargets > 0; @@ -84,5 +85,4 @@ class StrengthOfTheTajuruAddCountersTargetEffect extends OneShotEffect { return new StrengthOfTheTajuruAddCountersTargetEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/s/StrionicResonator.java b/Mage.Sets/src/mage/cards/s/StrionicResonator.java index 0c587fb086..e6ffbba49a 100644 --- a/Mage.Sets/src/mage/cards/s/StrionicResonator.java +++ b/Mage.Sets/src/mage/cards/s/StrionicResonator.java @@ -78,8 +78,6 @@ class StrionicResonatorEffect extends OneShotEffect { @Override public String getText(Mode mode) { - StringBuilder sb = new StringBuilder(); - sb.append("Copy ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); - return sb.toString(); + return "Copy " + mode.getTargets().get(0).getTargetName() + ". You may choose new targets for the copy"; } } diff --git a/Mage.Sets/src/mage/cards/s/StrokeOfGenius.java b/Mage.Sets/src/mage/cards/s/StrokeOfGenius.java index f9d0145f2c..8effb65627 100644 --- a/Mage.Sets/src/mage/cards/s/StrokeOfGenius.java +++ b/Mage.Sets/src/mage/cards/s/StrokeOfGenius.java @@ -21,7 +21,7 @@ public final class StrokeOfGenius extends CardImpl { // Target player draws X cards. - this.getSpellAbility().addEffect(new DrawCardTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DrawCardTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetPlayer()); } diff --git a/Mage.Sets/src/mage/cards/s/StromkirkMentor.java b/Mage.Sets/src/mage/cards/s/StromkirkMentor.java index 7dc780d5d6..187ba8c438 100644 --- a/Mage.Sets/src/mage/cards/s/StromkirkMentor.java +++ b/Mage.Sets/src/mage/cards/s/StromkirkMentor.java @@ -25,7 +25,7 @@ public final class StromkirkMentor extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another target Vampire you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java b/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java index ff3405bd2a..66f4c3618c 100644 --- a/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java +++ b/Mage.Sets/src/mage/cards/s/StromkirkOccultist.java @@ -81,7 +81,7 @@ class StromkirkOccultistExileEffect extends OneShotEffect { if (sourcePermanent != null && controller != null && controller.getLibrary().hasCards()) { Card card = controller.getLibrary().getFromTop(game); if (card != null) { - String exileName = new StringBuilder(sourcePermanent.getIdName()).append(" ").toString(); + String exileName = sourcePermanent.getIdName() + " "; if (controller.moveCardToExileWithInfo(card, source.getSourceId(), exileName, source.getSourceId(), game, Zone.LIBRARY, true)) { ContinuousEffect effect = new StromkirkOccultistPlayFromExileEffect(); effect.setTargetPointer(new FixedTarget(card.getId())); diff --git a/Mage.Sets/src/mage/cards/s/StrongarmTactics.java b/Mage.Sets/src/mage/cards/s/StrongarmTactics.java index b0acc08d9b..62676daaf8 100644 --- a/Mage.Sets/src/mage/cards/s/StrongarmTactics.java +++ b/Mage.Sets/src/mage/cards/s/StrongarmTactics.java @@ -68,9 +68,9 @@ class StrongarmTacticsEffect extends OneShotEffect { Player player = game.getPlayer(playerId); if (player != null) { int numberOfCardsToDiscard = Math.min(1, player.getHand().size()); - Cards cards = new CardsImpl(); Target target = new TargetDiscard(numberOfCardsToDiscard, numberOfCardsToDiscard, new FilterCard(), playerId); player.chooseTarget(outcome, target, source, game); + Cards cards = new CardsImpl(); cards.addAll(target.getTargets()); cardsToDiscard.put(playerId, cards); } diff --git a/Mage.Sets/src/mage/cards/s/StruggleSurvive.java b/Mage.Sets/src/mage/cards/s/StruggleSurvive.java index 5eb205a59b..fbe4e1050e 100644 --- a/Mage.Sets/src/mage/cards/s/StruggleSurvive.java +++ b/Mage.Sets/src/mage/cards/s/StruggleSurvive.java @@ -39,7 +39,7 @@ public final class StruggleSurvive extends SplitCard { // Survive // Aftermath - ((CardImpl) (getRightHalfCard())).addAbility(new AftermathAbility().setRuleAtTheTop(true)); + getRightHalfCard().addAbility(new AftermathAbility().setRuleAtTheTop(true)); // Each player shuffles his or graveyard into their library. getRightHalfCard().getSpellAbility().addEffect(new SurviveEffect()); @@ -69,13 +69,17 @@ class SurviveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player sourcePlayer = game.getPlayer(source.getControllerId()); - for (UUID playerId : game.getState().getPlayersInRange(sourcePlayer.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - for (Card card : player.getGraveyard().getCards(game)) { - card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + if(sourcePlayer != null) { + for (UUID playerId : game.getState().getPlayersInRange(sourcePlayer.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + for (Card card : player.getGraveyard().getCards(game)) { + if(card != null) { + card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + } + player.shuffleLibrary(source, game); } - player.shuffleLibrary(source, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/s/StubbornDenial.java b/Mage.Sets/src/mage/cards/s/StubbornDenial.java index 7b4d2c1f40..8ae807c321 100644 --- a/Mage.Sets/src/mage/cards/s/StubbornDenial.java +++ b/Mage.Sets/src/mage/cards/s/StubbornDenial.java @@ -1,13 +1,12 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.CounterUnlessPaysEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -16,31 +15,35 @@ import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.TargetSpell; +import java.util.UUID; + /** - * * @author emerald000 */ public final class StubbornDenial extends CardImpl { - + private static final FilterSpell filter = new FilterSpell("noncreature spell"); + static { filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); } - + public StubbornDenial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}"); // Counter target noncreature spell unless its controller pays {1}. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CounterUnlessPaysEffect(new GenericManaCost(1)), new InvertCondition(FerociousCondition.instance), "Counter target noncreature spell unless its controller pays {1}.")); + // Ferocious — If you control a creature with power 4 or greater, counter that spell instead. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new CounterTargetEffect(), FerociousCondition.instance, "
    Ferocious &mdash If you control a creature with power 4 or greater, counter that spell instead")); this.getSpellAbility().addTarget(new TargetSpell(filter)); + this.getSpellAbility().addHint(FerociousHint.instance); } public StubbornDenial(final StubbornDenial card) { diff --git a/Mage.Sets/src/mage/cards/s/StupefyingTouch.java b/Mage.Sets/src/mage/cards/s/StupefyingTouch.java index b2d9bdcfc7..fc19ee7966 100644 --- a/Mage.Sets/src/mage/cards/s/StupefyingTouch.java +++ b/Mage.Sets/src/mage/cards/s/StupefyingTouch.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -11,24 +9,21 @@ import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author fireshoes */ public final class StupefyingTouch extends CardImpl { public StupefyingTouch(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -37,10 +32,10 @@ public final class StupefyingTouch extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); - + // When Stupefying Touch enters the battlefield, draw a card. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); - + // Enchanted creature's activated abilities can't be activated. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantActivateAbilitiesAttachedEffect())); } @@ -70,15 +65,13 @@ class CantActivateAbilitiesAttachedEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { - if (permanent.getId().equals(enchantment.getAttachedTo())) { - return true; - } + return permanent.getId().equals(enchantment.getAttachedTo()); } return false; } - + @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/s/Sturmgeist.java b/Mage.Sets/src/mage/cards/s/Sturmgeist.java index 6bc161a0d4..f21efdda14 100644 --- a/Mage.Sets/src/mage/cards/s/Sturmgeist.java +++ b/Mage.Sets/src/mage/cards/s/Sturmgeist.java @@ -31,7 +31,7 @@ public final class Sturmgeist extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // Sturmgeist's power and toughness are each equal to the number of cards in your hand. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new CardsInControllerHandCount(), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame))); // Whenever Sturmgeist deals combat damage to a player, draw a card. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), false)); } diff --git a/Mage.Sets/src/mage/cards/s/Subdue.java b/Mage.Sets/src/mage/cards/s/Subdue.java new file mode 100644 index 0000000000..970e3df788 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/Subdue.java @@ -0,0 +1,39 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.TargetConvertedManaCost; +import mage.abilities.effects.common.PreventDamageByTargetEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class Subdue extends CardImpl { + + public Subdue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}"); + + // Prevent all combat damage that would be dealt by target creature this turn. That creature gets +0/+X until end of turn, where X is its converted mana cost. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new PreventDamageByTargetEffect(Duration.EndOfTurn, true)); + this.getSpellAbility().addEffect(new BoostTargetEffect(new StaticValue(0), TargetConvertedManaCost.instance, Duration.EndOfTurn, true) + .setText("That creature gets +0/+X until end of turn, where X is its converted mana cost")); + } + + public Subdue(final Subdue card) { + super(card); + } + + @Override + public Subdue copy() { + return new Subdue(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SubterraneanHangar.java b/Mage.Sets/src/mage/cards/s/SubterraneanHangar.java index 9676c73977..9ddc675a34 100644 --- a/Mage.Sets/src/mage/cards/s/SubterraneanHangar.java +++ b/Mage.Sets/src/mage/cards/s/SubterraneanHangar.java @@ -34,7 +34,7 @@ public final class SubterraneanHangar extends CardImpl { // {tap}, Remove any number of storage counters from Subterranean Hangar: Add {B} for each storage counter removed this way. Ability ability = new DynamicManaAbility( Mana.BlackMana(1), - new RemovedCountersForCostValue(), + RemovedCountersForCostValue.instance, new TapSourceCost(), "Add {B} for each storage counter removed this way", true, new CountersSourceCount(CounterType.STORAGE)); diff --git a/Mage.Sets/src/mage/cards/s/SubterraneanShambler.java b/Mage.Sets/src/mage/cards/s/SubterraneanShambler.java index 29004308bd..37166d93da 100644 --- a/Mage.Sets/src/mage/cards/s/SubterraneanShambler.java +++ b/Mage.Sets/src/mage/cards/s/SubterraneanShambler.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class SubterraneanShambler extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); static { filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); diff --git a/Mage.Sets/src/mage/cards/s/SubtleStrike.java b/Mage.Sets/src/mage/cards/s/SubtleStrike.java index 4709d7ad8b..78e8b675cf 100644 --- a/Mage.Sets/src/mage/cards/s/SubtleStrike.java +++ b/Mage.Sets/src/mage/cards/s/SubtleStrike.java @@ -1,7 +1,5 @@ - package mage.cards.s; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; @@ -12,14 +10,15 @@ import mage.constants.Duration; import mage.counters.CounterType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SubtleStrike extends CardImpl { public SubtleStrike(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); // Choose one or both — this.getSpellAbility().getModes().setMinModes(1); @@ -28,15 +27,14 @@ public final class SubtleStrike extends CardImpl { BoostTargetEffect minusOneMinusOne = new BoostTargetEffect(-1, -1, Duration.EndOfTurn); minusOneMinusOne.setText("Target creature gets -1/-1 until end of turn"); this.getSpellAbility().addEffect(minusOneMinusOne); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("gets -1/-1 until end of turn")); // • Put a +1/+1 counter on target creature. Mode mode1 = new Mode(); AddCountersTargetEffect plusOnePlusOneCounter = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); plusOnePlusOneCounter.setText("Put a +1/+1 counter on target creature"); - mode1.getEffects().add(plusOnePlusOneCounter); - mode1.getTargets().add(new TargetCreaturePermanent()); + mode1.addEffect(plusOnePlusOneCounter); + mode1.addTarget(new TargetCreaturePermanent().withChooseHint("gets +1/+1 counter")); this.getSpellAbility().addMode(mode1); - } public SubtleStrike(final SubtleStrike card) { diff --git a/Mage.Sets/src/mage/cards/s/SuddenImpact.java b/Mage.Sets/src/mage/cards/s/SuddenImpact.java index b3affd2363..6f889719a2 100644 --- a/Mage.Sets/src/mage/cards/s/SuddenImpact.java +++ b/Mage.Sets/src/mage/cards/s/SuddenImpact.java @@ -21,7 +21,7 @@ public final class SuddenImpact extends CardImpl { // Sudden Impact deals damage to target player equal to the number of cards in that player's hand. - Effect effect = new DamageTargetEffect(new CardsInTargetHandCount()); + Effect effect = new DamageTargetEffect(CardsInTargetHandCount.instance); effect.setText("{this} deals damage to target player equal to the number of cards in that player's hand."); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/s/SulfurousBlast.java b/Mage.Sets/src/mage/cards/s/SulfurousBlast.java index cb0bab1e20..3c1d0eda7f 100644 --- a/Mage.Sets/src/mage/cards/s/SulfurousBlast.java +++ b/Mage.Sets/src/mage/cards/s/SulfurousBlast.java @@ -2,7 +2,7 @@ package mage.cards.s; import java.util.UUID; -import mage.abilities.condition.common.MyMainPhaseCondition; +import mage.abilities.condition.common.AddendumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.DamageEverythingEffect; import mage.cards.CardImpl; @@ -22,7 +22,7 @@ public final class SulfurousBlast extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageEverythingEffect(3), new DamageEverythingEffect(2), - MyMainPhaseCondition.instance, + AddendumCondition.instance, "Sulfurous Blast deals 2 damage to each creature and each player. If you cast this spell during your main phase, Sulfurous Blast deals 3 damage to each creature and each player instead")); } diff --git a/Mage.Sets/src/mage/cards/s/SultaiCharm.java b/Mage.Sets/src/mage/cards/s/SultaiCharm.java index b645b15e99..f0e4f8f083 100644 --- a/Mage.Sets/src/mage/cards/s/SultaiCharm.java +++ b/Mage.Sets/src/mage/cards/s/SultaiCharm.java @@ -25,7 +25,7 @@ public final class SultaiCharm extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("monocolored creature"); static { - filter.add(new MonocoloredPredicate()); + filter.add(MonocoloredPredicate.instance); } public SultaiCharm(UUID ownerId, CardSetInfo setInfo) { @@ -38,13 +38,13 @@ public final class SultaiCharm extends CardImpl { // * Destroy target artifact or enchantment. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT)); this.getSpellAbility().addMode(mode); // * Draw two cards, then discard a card. mode = new Mode(); - mode.getEffects().add(new DrawDiscardControllerEffect(2,1)); + mode.addEffect(new DrawDiscardControllerEffect(2,1)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java b/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java index 258cf03467..dd6a0db960 100644 --- a/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java +++ b/Mage.Sets/src/mage/cards/s/SumalaWoodshaper.java @@ -1,6 +1,5 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; @@ -14,8 +13,9 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class SumalaWoodshaper extends CardImpl { @@ -40,8 +40,9 @@ public final class SumalaWoodshaper extends CardImpl { // When Sumala Woodshaper enters the battlefield, look at the top four cards of your library. You may reveal a creature or enchantment card from among them and put it into your hand. Put the rest on the bottom of your library in a random order. this.addAbility(new EntersBattlefieldTriggeredAbility(new LookLibraryAndPickControllerEffect( - new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, true, false, Zone.HAND, false, false, false - ), false)); + new StaticValue(4), false, new StaticValue(1), filter, Zone.LIBRARY, false, + true, false, Zone.HAND, false, false, false + ).setBackInRandomOrder(true), false)); } public SumalaWoodshaper(final SumalaWoodshaper card) { diff --git a/Mage.Sets/src/mage/cards/s/SummaryDismissal.java b/Mage.Sets/src/mage/cards/s/SummaryDismissal.java index 6b49a28762..e695e38f29 100644 --- a/Mage.Sets/src/mage/cards/s/SummaryDismissal.java +++ b/Mage.Sets/src/mage/cards/s/SummaryDismissal.java @@ -66,7 +66,7 @@ class SummaryDismissalEffect extends OneShotEffect { ((Spell) stackObject).moveToExile(null, "", null, game); } if (stackObject instanceof Ability) { - game.getStack().counter(((Ability) stackObject).getId(), source.getSourceId(), game); + game.getStack().counter(stackObject.getId(), source.getSourceId(), game); } } return true; diff --git a/Mage.Sets/src/mage/cards/s/SummaryJudgment.java b/Mage.Sets/src/mage/cards/s/SummaryJudgment.java new file mode 100644 index 0000000000..5e2cc2ee4b --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SummaryJudgment.java @@ -0,0 +1,79 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.TappedPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SummaryJudgment extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("tapped creature"); + + static { + filter.add(TappedPredicate.instance); + } + + public SummaryJudgment(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{W}"); + + // Summary Judgement deals 3 damage to target tapped creature. + // Addendum — If you cast this spell during your main phase, it deals 5 damage to that creature instead. + this.getSpellAbility().addEffect(new SummaryJudgementEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + } + + private SummaryJudgment(final SummaryJudgment card) { + super(card); + } + + @Override + public SummaryJudgment copy() { + return new SummaryJudgment(this); + } +} + +class SummaryJudgementEffect extends OneShotEffect { + + SummaryJudgementEffect() { + super(Outcome.Benefit); + staticText = "{this} deals 3 damage to target tapped creature." + + "
    Addendum — If you cast this spell during your main phase, " + + "it deals 5 damage to that creature instead."; + } + + private SummaryJudgementEffect(final SummaryJudgementEffect effect) { + super(effect); + } + + @Override + public SummaryJudgementEffect copy() { + return new SummaryJudgementEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + int damage = 3; + if (AddendumCondition.instance.apply(game, source)) { + damage = 5; + } + return permanent.damage(damage, source.getSourceId(), game) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SummonTheSchool.java b/Mage.Sets/src/mage/cards/s/SummonTheSchool.java index 8c7f797016..eaccfa4c28 100644 --- a/Mage.Sets/src/mage/cards/s/SummonTheSchool.java +++ b/Mage.Sets/src/mage/cards/s/SummonTheSchool.java @@ -27,7 +27,7 @@ public final class SummonTheSchool extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Merfolk you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.MERFOLK)); } diff --git a/Mage.Sets/src/mage/cards/s/SummoningTrap.java b/Mage.Sets/src/mage/cards/s/SummoningTrap.java index 8bc4391c42..f7d55ddde2 100644 --- a/Mage.Sets/src/mage/cards/s/SummoningTrap.java +++ b/Mage.Sets/src/mage/cards/s/SummoningTrap.java @@ -55,7 +55,7 @@ enum SummoningTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - SummoningTrapWatcher watcher = (SummoningTrapWatcher) game.getState().getWatchers().get(SummoningTrapWatcher.class.getSimpleName()); + SummoningTrapWatcher watcher = game.getState().getWatcher(SummoningTrapWatcher.class); return watcher != null && watcher.creatureSpellOfPlayerWasCountered(source.getControllerId()); } @@ -67,10 +67,10 @@ enum SummoningTrapCondition implements Condition { class SummoningTrapWatcher extends Watcher { - Set players = new HashSet<>(); + private Set players = new HashSet<>(); public SummoningTrapWatcher() { - super(SummoningTrapWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SummoningTrapWatcher(final SummoningTrapWatcher watcher) { @@ -133,8 +133,7 @@ class SummoningTrapEffect extends OneShotEffect { if (controller == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 7)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); if (!cards.isEmpty()) { TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCreatureCard( diff --git a/Mage.Sets/src/mage/cards/s/SunBlessedMount.java b/Mage.Sets/src/mage/cards/s/SunBlessedMount.java index 2e94ae4ef0..0a8b7f4f88 100644 --- a/Mage.Sets/src/mage/cards/s/SunBlessedMount.java +++ b/Mage.Sets/src/mage/cards/s/SunBlessedMount.java @@ -18,7 +18,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class SunBlessedMount extends CardImpl { - private final static FilterCard filter = new FilterCard("Huatli, Dinosaur Knight"); + private static final FilterCard filter = new FilterCard("Huatli, Dinosaur Knight"); static { filter.add(new NamePredicate("Huatli, Dinosaur Knight")); diff --git a/Mage.Sets/src/mage/cards/s/SunClasp.java b/Mage.Sets/src/mage/cards/s/SunClasp.java index d48b9bf7e5..7ca4f36f6c 100644 --- a/Mage.Sets/src/mage/cards/s/SunClasp.java +++ b/Mage.Sets/src/mage/cards/s/SunClasp.java @@ -71,7 +71,7 @@ class SunClaspReturnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) game.getPermanentOrLKIBattlefield(source.getSourceId()); + Permanent permanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && permanent != null && permanent.getAttachedTo() != null) { Permanent enchantedCreature = game.getPermanent(permanent.getAttachedTo()); diff --git a/Mage.Sets/src/mage/cards/s/SunCrestedPterodon.java b/Mage.Sets/src/mage/cards/s/SunCrestedPterodon.java index 9d1cd7d205..55157dfa6e 100644 --- a/Mage.Sets/src/mage/cards/s/SunCrestedPterodon.java +++ b/Mage.Sets/src/mage/cards/s/SunCrestedPterodon.java @@ -29,7 +29,7 @@ public final class SunCrestedPterodon extends CardImpl { private static final FilterControlledCreaturePermanent filterAnotherDino = new FilterControlledCreaturePermanent(); static { - filterAnotherDino.add(new AnotherPredicate()); + filterAnotherDino.add(AnotherPredicate.instance); filterAnotherDino.add(new SubtypePredicate(SubType.DINOSAUR)); } diff --git a/Mage.Sets/src/mage/cards/s/SunDroplet.java b/Mage.Sets/src/mage/cards/s/SunDroplet.java index 6ff432b37d..08b3f4e79c 100644 --- a/Mage.Sets/src/mage/cards/s/SunDroplet.java +++ b/Mage.Sets/src/mage/cards/s/SunDroplet.java @@ -1,22 +1,15 @@ package mage.cards.s; -import java.util.UUID; -import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; -import mage.abilities.condition.common.SourceHasCounterCondition; import mage.abilities.costs.common.RemoveCountersSourceCost; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; import mage.counters.CounterType; @@ -24,26 +17,28 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class SunDroplet extends CardImpl { public SunDroplet(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); // Whenever you're dealt damage, put that many charge counters on Sun Droplet. this.addAbility(new SunDropletTriggeredAbility()); + // At the beginning of each upkeep, you may remove a charge counter from Sun Droplet. If you do, you gain 1 life. - //TODO this shouldn't be conditional because you can respond to the trigger by adding counters. - Effect effect = new DoIfCostPaid(new GainLifeEffect(1), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance(1))); - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(effect, TargetController.ANY, false), - new SourceHasCounterCondition(CounterType.CHARGE, 1), - "At the beginning of each upkeep, you may remove a charge counter from Sun Droplet. If you do, you gain 1 life")); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DoIfCostPaid( + new GainLifeEffect(1), new RemoveCountersSourceCost(CounterType.CHARGE.createInstance()) + ), TargetController.ANY, false + )); } - public SunDroplet(final SunDroplet card) { + private SunDroplet(final SunDroplet card) { super(card); } @@ -55,11 +50,11 @@ public final class SunDroplet extends CardImpl { class SunDropletTriggeredAbility extends TriggeredAbilityImpl { - public SunDropletTriggeredAbility() { - super(Zone.BATTLEFIELD, new SunDropletEffect(), false); + SunDropletTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.CHARGE.createInstance()), false); } - public SunDropletTriggeredAbility(final SunDropletTriggeredAbility ability) { + private SunDropletTriggeredAbility(final SunDropletTriggeredAbility ability) { super(ability); } @@ -76,7 +71,8 @@ class SunDropletTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(this.getControllerId())) { - this.getEffects().get(0).setValue("damageAmount", event.getAmount()); + this.getEffects().clear(); + this.addEffect(new AddCountersSourceEffect(CounterType.CHARGE.createInstance(event.getAmount()))); return true; } return false; @@ -87,24 +83,3 @@ class SunDropletTriggeredAbility extends TriggeredAbilityImpl { return "Whenever you're dealt damage, put that many charge counters on {this}."; } } - -class SunDropletEffect extends OneShotEffect { - - public SunDropletEffect() { - super(Outcome.Benefit); - } - - public SunDropletEffect(final SunDropletEffect effect) { - super(effect); - } - - @Override - public SunDropletEffect copy() { - return new SunDropletEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - return new AddCountersSourceEffect(CounterType.CHARGE.createInstance((Integer) this.getValue("damageAmount"))).apply(game, source); - } -} diff --git a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java index 10dcad1ec4..0d5e1540dc 100644 --- a/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java +++ b/Mage.Sets/src/mage/cards/s/SunbirdsInvocation.java @@ -117,8 +117,7 @@ class SunbirdsInvocationEffect extends OneShotEffect { return false; } int xValue = spell.getConvertedManaCost(); - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, xValue)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, xValue)); if (!cards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/s/SunbladeAngel.java b/Mage.Sets/src/mage/cards/s/SunbladeAngel.java new file mode 100644 index 0000000000..4959a4d793 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunbladeAngel.java @@ -0,0 +1,48 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +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 SunbladeAngel extends CardImpl { + + public SunbladeAngel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + + this.subtype.add(SubType.ANGEL); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // First strike + this.addAbility(FirstStrikeAbility.getInstance()); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + } + + private SunbladeAngel(final SunbladeAngel card) { + super(card); + } + + @Override + public SunbladeAngel copy() { + return new SunbladeAngel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunblastAngel.java b/Mage.Sets/src/mage/cards/s/SunblastAngel.java index 16d1491dcd..a089f3485d 100644 --- a/Mage.Sets/src/mage/cards/s/SunblastAngel.java +++ b/Mage.Sets/src/mage/cards/s/SunblastAngel.java @@ -24,7 +24,7 @@ public final class SunblastAngel extends CardImpl { private static final FilterPermanent tappedFilter = new FilterCreaturePermanent("tapped creatures"); static { - tappedFilter.add(new TappedPredicate()); + tappedFilter.add(TappedPredicate.instance); } public SunblastAngel (UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SunbringersTouch.java b/Mage.Sets/src/mage/cards/s/SunbringersTouch.java index d1a1104cd4..1cca7cfa8c 100644 --- a/Mage.Sets/src/mage/cards/s/SunbringersTouch.java +++ b/Mage.Sets/src/mage/cards/s/SunbringersTouch.java @@ -30,7 +30,7 @@ public final class SunbringersTouch extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{G}{G}"); // Bolster X, where X is the number of cards in your hand. - this.getSpellAbility().addEffect(new BolsterEffect(new CardsInControllerHandCount())); + this.getSpellAbility().addEffect(new BolsterEffect(CardsInControllerHandCount.instance)); // Each creature you control with a +1/+1 counter on it gains trample until end of turn. Effect effect = new GainAbilityControlledEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter); diff --git a/Mage.Sets/src/mage/cards/s/Suncleanser.java b/Mage.Sets/src/mage/cards/s/Suncleanser.java index 8575b71920..a1ec53e415 100644 --- a/Mage.Sets/src/mage/cards/s/Suncleanser.java +++ b/Mage.Sets/src/mage/cards/s/Suncleanser.java @@ -45,9 +45,9 @@ public final class Suncleanser extends CardImpl { // • Target opponent loses all counters. That player can't get counters for as long as Suncleanser remains on the battlefield. Mode mode = new Mode(); - mode.getEffects().add(new SuncleanserRemoveCountersEffect(true)); - mode.getEffects().add(new SuncleanserPreventCountersEffect(true)); - mode.getTargets().add(new TargetOpponent()); + mode.addEffect(new SuncleanserRemoveCountersEffect(true)); + mode.addEffect(new SuncleanserPreventCountersEffect(true)); + mode.addTarget(new TargetOpponent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/s/SunderShaman.java b/Mage.Sets/src/mage/cards/s/SunderShaman.java new file mode 100644 index 0000000000..c60b70ff8d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SunderShaman.java @@ -0,0 +1,92 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.combat.CantBeBlockedByMoreThanOneSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SunderShaman extends CardImpl { + + public SunderShaman(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}{G}{G}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.SHAMAN); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // Sunder Shaman can't be blocked by more than one creature. + this.addAbility(new SimpleStaticAbility(new CantBeBlockedByMoreThanOneSourceEffect())); + + // Whenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls. + this.addAbility(new SunderShamanTriggeredAbility()); + } + + private SunderShaman(final SunderShaman card) { + super(card); + } + + @Override + public SunderShaman copy() { + return new SunderShaman(this); + } +} + +class SunderShamanTriggeredAbility extends TriggeredAbilityImpl { + + SunderShamanTriggeredAbility() { + super(Zone.BATTLEFIELD, new DestroyTargetEffect(), false); + } + + private SunderShamanTriggeredAbility(final SunderShamanTriggeredAbility ability) { + super(ability); + } + + @Override + public SunderShamanTriggeredAbility copy() { + return new SunderShamanTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Player opponent = game.getPlayer(event.getPlayerId()); + if (opponent != null && event.getSourceId().equals(this.sourceId)) { + FilterPermanent filter = StaticFilters.FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT.copy(); + filter.setMessage("artifact or enchantment controlled by" + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponent.getId())); + this.getTargets().clear(); + this.addTarget(new TargetPermanent(filter)); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage to a player, " + + "destroy target artifact or enchantment that player controls."; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SunderingTitan.java b/Mage.Sets/src/mage/cards/s/SunderingTitan.java index 16e7eb3356..df2e165460 100644 --- a/Mage.Sets/src/mage/cards/s/SunderingTitan.java +++ b/Mage.Sets/src/mage/cards/s/SunderingTitan.java @@ -1,4 +1,3 @@ - package mage.cards.s; import mage.MageInt; @@ -23,13 +22,12 @@ import java.util.Set; import java.util.UUID; /** - * * @author LevelX2 */ public final class SunderingTitan extends CardImpl { public SunderingTitan(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{8}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{8}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(7); @@ -71,7 +69,7 @@ class SunderingTitanDestroyLandEffect extends OneShotEffect { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); Set lands = new HashSet<>(); if (controller != null && sourcePermanent != null) { - for (SubType landName : SubType.getBasicLands(false)) { + for (SubType landName : SubType.getBasicLands()) { FilterLandPermanent filter = new FilterLandPermanent(landName + " to destroy"); filter.add(new SubtypePredicate(landName)); Target target = new TargetLandPermanent(1, 1, filter, true); diff --git a/Mage.Sets/src/mage/cards/s/Sunforger.java b/Mage.Sets/src/mage/cards/s/Sunforger.java index f6bc12430a..fe70654e64 100644 --- a/Mage.Sets/src/mage/cards/s/Sunforger.java +++ b/Mage.Sets/src/mage/cards/s/Sunforger.java @@ -104,7 +104,7 @@ class SunforgerEffect extends OneShotEffect { filter.add(new CardTypePredicate(CardType.INSTANT)); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 5)); filter.add(new CardCanBeCastPredicate(source.getControllerId())); - if (controller.searchLibrary(target, game, controller.getId())) { + if (controller.searchLibrary(target, source, game, controller.getId())) { UUID targetId = target.getFirstTarget(); Card card = game.getCard(targetId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java b/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java index 2817418444..08eb558a54 100644 --- a/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java +++ b/Mage.Sets/src/mage/cards/s/SunspireGatekeepers.java @@ -1,12 +1,12 @@ - - package mage.cards.s; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.ConditionHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -19,7 +19,6 @@ import mage.game.permanent.token.KnightToken; import java.util.UUID; /** - * * @author LevelX2 */ @@ -27,12 +26,15 @@ import java.util.UUID; public final class SunspireGatekeepers extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + static { filter.add(new SubtypePredicate(SubType.GATE)); } - public SunspireGatekeepers (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); + private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + + public SunspireGatekeepers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SOLDIER); @@ -42,11 +44,12 @@ public final class SunspireGatekeepers extends CardImpl { // When Sunspire Gatekeepers enter the battlefield, if you control two or more Gates, create a 2/2 white Knight creature token with vigilance. this.addAbility(new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightToken())), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), - "When {this} enters the battlefield, if you control two or more Gates, create a 2/2 white Knight creature token with vigilance.")); + gatesCondition, + "When {this} enters the battlefield, if you control two or more Gates, create a 2/2 white Knight creature token with vigilance.") + .addHint(new ConditionHint(gatesCondition, "you control two or more Gates"))); } - public SunspireGatekeepers (final SunspireGatekeepers card) { + public SunspireGatekeepers(final SunspireGatekeepers card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java b/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java index 38d7bedb37..e9a0bec6af 100644 --- a/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java +++ b/Mage.Sets/src/mage/cards/s/SunstrikeLegionnaire.java @@ -32,7 +32,7 @@ public final class SunstrikeLegionnaire extends CardImpl { private static final FilterCreaturePermanent tapFilter = new FilterCreaturePermanent("creature with converted mana cost 3 or less"); static { - untapFilter.add(new AnotherPredicate()); + untapFilter.add(AnotherPredicate.instance); tapFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } diff --git a/Mage.Sets/src/mage/cards/s/SuperiorNumbers.java b/Mage.Sets/src/mage/cards/s/SuperiorNumbers.java new file mode 100644 index 0000000000..d2caee1ab8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuperiorNumbers.java @@ -0,0 +1,76 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SuperiorNumbers extends CardImpl { + + public SuperiorNumbers(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}{G}"); + + // Superior Numbers deals damage to target creature equal to the number of creatures you control in excess of the number of creatures target opponent controls. + this.getSpellAbility().addEffect(new SuperiorNumbersEffect()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetOpponent()); + } + + private SuperiorNumbers(final SuperiorNumbers card) { + super(card); + } + + @Override + public SuperiorNumbers copy() { + return new SuperiorNumbers(this); + } +} + +class SuperiorNumbersEffect extends OneShotEffect { + + SuperiorNumbersEffect() { + super(Outcome.Benefit); + staticText = "{this} deals damage to target creature equal to the number of creatures you control " + + "in excess of the number of creatures target opponent controls."; + } + + private SuperiorNumbersEffect(final SuperiorNumbersEffect effect) { + super(effect); + } + + @Override + public SuperiorNumbersEffect copy() { + return new SuperiorNumbersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent creature = game.getPermanent(source.getFirstTarget()); + Player opponent = game.getPlayer(source.getTargets().get(1).getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (creature == null || opponent == null || controller == null) { + return false; + } + int controllerCreatures = game.getBattlefield().countAll( + StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game + ); + int opponentCreatures = game.getBattlefield().countAll( + StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game + ); + int damage = Math.max(controllerCreatures - opponentCreatures, 0); + return creature.damage(damage, source.getSourceId(), game) > 0; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/s/SupplyCaravan.java b/Mage.Sets/src/mage/cards/s/SupplyCaravan.java index cb76066914..763394039d 100644 --- a/Mage.Sets/src/mage/cards/s/SupplyCaravan.java +++ b/Mage.Sets/src/mage/cards/s/SupplyCaravan.java @@ -25,7 +25,7 @@ public final class SupplyCaravan extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SupplyCaravan(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SupplyDemand.java b/Mage.Sets/src/mage/cards/s/SupplyDemand.java index deec3a02d5..a9ca239a28 100644 --- a/Mage.Sets/src/mage/cards/s/SupplyDemand.java +++ b/Mage.Sets/src/mage/cards/s/SupplyDemand.java @@ -23,7 +23,7 @@ public final class SupplyDemand extends SplitCard { private static final FilterCard filter = new FilterCard("multicolored card"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public SupplyDemand(UUID ownerId, CardSetInfo setInfo) { @@ -31,7 +31,7 @@ public final class SupplyDemand extends SplitCard { // Supply // create X 1/1 green Saproling creature tokens. - getLeftHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), new ManacostVariableValue())); + getLeftHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new SaprolingToken(), ManacostVariableValue.instance)); // Demand // Search your library for a multicolored card, reveal it, and put it into your hand. Then shuffle your library. diff --git a/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java b/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java index aef0f732e9..e2a16b7fde 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java +++ b/Mage.Sets/src/mage/cards/s/SupremeInquisitor.java @@ -36,7 +36,7 @@ public final class SupremeInquisitor extends CardImpl { static { filter.add(new SubtypePredicate(SubType.WIZARD)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SupremeInquisitor(UUID ownerId, CardSetInfo setInfo) { @@ -87,7 +87,7 @@ class SupremeInquisitorEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); if (player != null && targetPlayer != null) { TargetCardInLibrary target = new TargetCardInLibrary(0, 5, filter); - if (player.searchLibrary(target, game, targetPlayer.getId())) { + if (player.searchLibrary(target, source, game, targetPlayer.getId())) { List targetId = target.getTargets(); for (UUID targetCard : targetId) { Card card = targetPlayer.getLibrary().remove(targetCard, game); diff --git a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java index c894340e3a..4ddba10eb0 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java +++ b/Mage.Sets/src/mage/cards/s/SupremeLeaderSnoke.java @@ -11,13 +11,16 @@ import mage.abilities.costs.common.PayVariableLoyaltyCost; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.*; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.abilities.effects.common.UntapTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.abilities.keyword.HasteAbility; -import mage.constants.*; import mage.cards.CardImpl; import mage.cards.CardSetInfo; +import mage.constants.*; import mage.counters.Counter; import mage.counters.CounterType; import mage.filter.StaticFilters; @@ -26,19 +29,17 @@ import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; import mage.watchers.common.PlayerLostLifeNonCombatWatcher; /** - * * @author NinthWorld */ public final class SupremeLeaderSnoke extends CardImpl { - UUID ability3Id; - public SupremeLeaderSnoke(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{U}{B}{R}"); - + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.SNOKE); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); @@ -54,35 +55,17 @@ public final class SupremeLeaderSnoke extends CardImpl { // -X: Gain control of target creature with converted mana cost X. Untap that creature. It gains haste. Sacrifice that creature at the beginning of the next end step. Ability ability3 = new LoyaltyAbility(new GainControlTargetEffect(Duration.WhileOnBattlefield) - .setText("Gain control of target creature with converted mana cost X")); + .setText("Gain control of target creature with converted mana cost X")); ability3.addEffect(new UntapTargetEffect().setText("Untap that creature")); ability3.addEffect(new GainAbilityTargetEffect(HasteAbility.getInstance(), Duration.WhileOnBattlefield).setText("It gains haste")); ability3.addEffect(new GainAbilityTargetEffect(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()), Duration.WhileOnBattlefield) - .setText("Sacrifice that creature at the beginning of the next end step")); - ability3Id = ability3.getOriginalId(); - ability3.addTarget(new TargetCreaturePermanent()); + .setText("Sacrifice that creature at the beginning of the next end step")); + ability3.setTargetAdjuster(SupremeLeaderSnokeAdjuster.instance); this.addAbility(ability3); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(ability3Id)) { - int cmc = 0; - for (Cost cost : ability.getCosts()) { - if (cost instanceof PayVariableLoyaltyCost) { - cmc = ((PayVariableLoyaltyCost) cost).getAmount(); - } - } - FilterCreaturePermanent newFilter = StaticFilters.FILTER_PERMANENT_CREATURE.copy(); - newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(newFilter)); - } - } - public SupremeLeaderSnoke(final SupremeLeaderSnoke card) { super(card); - this.ability3Id = card.ability3Id; } @Override @@ -91,11 +74,29 @@ public final class SupremeLeaderSnoke extends CardImpl { } } +enum SupremeLeaderSnokeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + int cmc = 0; + for (Cost cost : ability.getCosts()) { + if (cost instanceof PayVariableLoyaltyCost) { + cmc = ((PayVariableLoyaltyCost) cost).getAmount(); + } + } + FilterCreaturePermanent newFilter = StaticFilters.FILTER_PERMANENT_CREATURE.copy(); + newFilter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, cmc)); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(newFilter)); + } +} + class OpponentNoncombatLostLifeCount implements DynamicValue { @Override public int calculate(Game game, Ability source, Effect effect) { - PlayerLostLifeNonCombatWatcher watcher = (PlayerLostLifeNonCombatWatcher) game.getState().getWatchers().get(PlayerLostLifeNonCombatWatcher.class.getSimpleName()); + PlayerLostLifeNonCombatWatcher watcher = game.getState().getWatcher(PlayerLostLifeNonCombatWatcher.class); if(watcher != null) { return watcher.getAllOppLifeLost(source.getControllerId(), game); } @@ -131,9 +132,9 @@ class SupremeLeaderSnokeCounterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(source.getSourceId()); - if(permanent != null) { + if (permanent != null) { int amount = new OpponentNoncombatLostLifeCount().calculate(game, source, this); - if(amount > 0) { + if (amount > 0) { Counter counterToAdd = counter.copy(); counterToAdd.add(amount - counter.getCount()); permanent.addCounters(counterToAdd, source, game); diff --git a/Mage.Sets/src/mage/cards/s/SupremeWill.java b/Mage.Sets/src/mage/cards/s/SupremeWill.java index d2e6a25e69..3cf8a608f6 100644 --- a/Mage.Sets/src/mage/cards/s/SupremeWill.java +++ b/Mage.Sets/src/mage/cards/s/SupremeWill.java @@ -29,7 +29,7 @@ public final class SupremeWill extends CardImpl { // or Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in any order. Mode mode = new Mode(); - mode.getEffects().add(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false)); + mode.addEffect(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), StaticFilters.FILTER_CARD, Zone.LIBRARY, false, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/s/SurgeOfStrength.java b/Mage.Sets/src/mage/cards/s/SurgeOfStrength.java index 7a9a5d7924..d71e125bb6 100644 --- a/Mage.Sets/src/mage/cards/s/SurgeOfStrength.java +++ b/Mage.Sets/src/mage/cards/s/SurgeOfStrength.java @@ -42,7 +42,7 @@ public final class SurgeOfStrength extends CardImpl { Effect effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("Target creature gains trample"); this.getSpellAbility().addEffect(effect); - effect = new BoostTargetEffect(new TargetConvertedManaCost(), new StaticValue(0), Duration.EndOfTurn, true); + effect = new BoostTargetEffect(TargetConvertedManaCost.instance, new StaticValue(0), Duration.EndOfTurn, true); effect.setText("and gets +X/+0 until end of turn, where X is that creature's converted mana cost"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); diff --git a/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java b/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java index 723ea2cc6e..b660eb088e 100644 --- a/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java +++ b/Mage.Sets/src/mage/cards/s/SurgicalExtraction.java @@ -1,11 +1,11 @@ - package mage.cards.s; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SuperType; @@ -21,8 +21,10 @@ import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import java.util.List; +import java.util.UUID; + /** - * * @author North */ public final class SurgicalExtraction extends CardImpl { @@ -71,12 +73,12 @@ class SurgicalExtractionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card chosenCard = game.getCard(source.getFirstTarget()); - Player controller = game.getPlayer(source.getControllerId()); - // 6/1/2011 "Any number of cards" means just that. If you wish, you can choose to // leave some or all of the cards with the same name as the targeted card, // including that card, in the zone they're in. + + Card chosenCard = game.getCard(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); if (chosenCard != null && controller != null) { Player owner = game.getPlayer(chosenCard.getOwnerId()); if (owner != null) { @@ -116,7 +118,7 @@ class SurgicalExtractionEffect extends OneShotEffect { // cards in Library filterNamedCard.setMessage("card named " + nameToSearch + " in the library of " + owner.getName()); TargetCardInLibrary targetCardInLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCard); - if (controller.searchLibrary(targetCardInLibrary, game, owner.getId())) { + if (controller.searchLibrary(targetCardInLibrary, source, game, owner.getId())) { List targets = targetCardInLibrary.getTargets(); for (UUID targetId : targets) { Card targetCard = owner.getLibrary().getCard(targetId, game); diff --git a/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java b/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java index a52604f754..94db2f7664 100644 --- a/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java +++ b/Mage.Sets/src/mage/cards/s/SurrakarBanisher.java @@ -23,7 +23,7 @@ public final class SurrakarBanisher extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SurrakarBanisher(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SurveyorsScope.java b/Mage.Sets/src/mage/cards/s/SurveyorsScope.java index aa0c1ee550..a3c878d150 100644 --- a/Mage.Sets/src/mage/cards/s/SurveyorsScope.java +++ b/Mage.Sets/src/mage/cards/s/SurveyorsScope.java @@ -74,7 +74,7 @@ class SurveyorsScopeEffect extends OneShotEffect { } } } - game.informPlayers(new StringBuilder("Surveyor's Scope: X = ").append(numberOfLands).toString()); + game.informPlayers("Surveyor's Scope: X = " + numberOfLands); // 10/17/2013 If no players control at least two more lands than you when the ability resolves, you'll still search and shuffle your library. return new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, numberOfLands, StaticFilters.FILTER_CARD_BASIC_LAND)).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/s/SurvivorsEncampment.java b/Mage.Sets/src/mage/cards/s/SurvivorsEncampment.java index b50fa4d148..aae6ff535e 100644 --- a/Mage.Sets/src/mage/cards/s/SurvivorsEncampment.java +++ b/Mage.Sets/src/mage/cards/s/SurvivorsEncampment.java @@ -24,7 +24,7 @@ public final class SurvivorsEncampment extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("an untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SurvivorsEncampment(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SuspensionField.java b/Mage.Sets/src/mage/cards/s/SuspensionField.java index e7a8c8e5ce..77cc6b30af 100644 --- a/Mage.Sets/src/mage/cards/s/SuspensionField.java +++ b/Mage.Sets/src/mage/cards/s/SuspensionField.java @@ -26,7 +26,7 @@ import mage.util.CardUtil; */ public final class SuspensionField extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with toughness 3 or greater"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature with toughness 3 or greater"); static { filter.add(new ToughnessPredicate(ComparisonType.MORE_THAN, 2)); diff --git a/Mage.Sets/src/mage/cards/s/SuturedGhoul.java b/Mage.Sets/src/mage/cards/s/SuturedGhoul.java index 0a79824eac..1bca0b0157 100644 --- a/Mage.Sets/src/mage/cards/s/SuturedGhoul.java +++ b/Mage.Sets/src/mage/cards/s/SuturedGhoul.java @@ -78,7 +78,7 @@ class SuturedGhoulEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if (permanent == null) { + if (permanent == null || controller == null) { return false; } if (!controller.getGraveyard().isEmpty()) { diff --git a/Mage.Sets/src/mage/cards/s/SwallowingPlague.java b/Mage.Sets/src/mage/cards/s/SwallowingPlague.java index 9b17abee58..7392aca66b 100644 --- a/Mage.Sets/src/mage/cards/s/SwallowingPlague.java +++ b/Mage.Sets/src/mage/cards/s/SwallowingPlague.java @@ -23,8 +23,8 @@ public final class SwallowingPlague extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{B}{B}"); this.subtype.add(SubType.ARCANE); - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); - this.getSpellAbility().addEffect(new GainLifeEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); + this.getSpellAbility().addEffect(new GainLifeEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/s/SwansOfBrynArgoll.java b/Mage.Sets/src/mage/cards/s/SwansOfBrynArgoll.java index 728dbe7a80..c97e5c4338 100644 --- a/Mage.Sets/src/mage/cards/s/SwansOfBrynArgoll.java +++ b/Mage.Sets/src/mage/cards/s/SwansOfBrynArgoll.java @@ -79,17 +79,23 @@ class SwansOfBrynArgollEffect extends PreventionEffectImpl { CommandObject emblem = (CommandObject)game.getEmblem(sourceOfDamage.getId()); if (spell != null) { Player controllerOfSpell = game.getPlayer(spell.getControllerId()); - controllerOfSpell.drawCards(preventionEffectData.getPreventedDamage(), game); - passed = true; + if(controllerOfSpell != null) { + controllerOfSpell.drawCards(preventionEffectData.getPreventedDamage(), game); + passed = true; + } } if (permanent != null) { Player controllerOfPermanent = game.getPlayer(permanent.getControllerId()); - controllerOfPermanent.drawCards(preventionEffectData.getPreventedDamage(), game); - passed = true; + if(controllerOfPermanent != null) { + controllerOfPermanent.drawCards(preventionEffectData.getPreventedDamage(), game); + passed = true; + } } if (emblem != null) { Player controllerOfEmblem = game.getPlayer(emblem.getControllerId()); - controllerOfEmblem.drawCards(preventionEffectData.getPreventedDamage(), game); + if(controllerOfEmblem != null) { + controllerOfEmblem.drawCards(preventionEffectData.getPreventedDamage(), game); + } passed = true; } if (!passed) { diff --git a/Mage.Sets/src/mage/cards/s/SwarmSurge.java b/Mage.Sets/src/mage/cards/s/SwarmSurge.java index 2bf4f0104e..74c0ca260d 100644 --- a/Mage.Sets/src/mage/cards/s/SwarmSurge.java +++ b/Mage.Sets/src/mage/cards/s/SwarmSurge.java @@ -23,7 +23,7 @@ public final class SwarmSurge extends CardImpl { private static final FilterCreaturePermanent FILTER = new FilterCreaturePermanent("Colorless creatures you control"); static { - FILTER.add(new ColorlessPredicate()); + FILTER.add(ColorlessPredicate.instance); } public SwarmSurge(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java b/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java index 12282fe8e7..7379681a6e 100644 --- a/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java +++ b/Mage.Sets/src/mage/cards/s/SwayOfTheStars.java @@ -2,6 +2,7 @@ package mage.cards.s; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -19,13 +20,12 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author LevelX2 */ public final class SwayOfTheStars extends CardImpl { public SwayOfTheStars(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{8}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{8}{U}{U}"); // Each player shuffles their hand, graveyard, and permanents he or she owns into their library, then draws seven cards. Each player's life total becomes 7. this.getSpellAbility().addEffect(new SwayOfTheStarsEffect()); @@ -60,18 +60,19 @@ class SwayOfTheStarsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - player.moveCards(player.getHand(), Zone.LIBRARY, source, game); - player.moveCards(player.getGraveyard(), Zone.LIBRARY, source, game); - FilterPermanent filter = new FilterPermanent(); - filter.add(new OwnerIdPredicate(playerId)); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { - permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + if (controller != null) { + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player != null) { + player.moveCards(player.getHand(), Zone.LIBRARY, source, game); + player.moveCards(player.getGraveyard(), Zone.LIBRARY, source, game); + FilterPermanent filter = new FilterPermanent(); + filter.add(new OwnerIdPredicate(playerId)); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { + permanent.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } + player.shuffleLibrary(source, game); } - player.shuffleLibrary(source, game); } } return true; diff --git a/Mage.Sets/src/mage/cards/s/SwellOfCourage.java b/Mage.Sets/src/mage/cards/s/SwellOfCourage.java index 372a09d6c5..457048a651 100644 --- a/Mage.Sets/src/mage/cards/s/SwellOfCourage.java +++ b/Mage.Sets/src/mage/cards/s/SwellOfCourage.java @@ -24,7 +24,7 @@ public final class SwellOfCourage extends CardImpl { // Creatures you control get +2/+2 until end of turn. this.getSpellAbility().addEffect(new BoostControlledEffect(2,2, Duration.EndOfTurn)); // Reinforce X-{X}{W}{W} - this.addAbility(new ReinforceAbility(new ManacostVariableValue(), new ManaCostsImpl("{X}{W}{W}"))); + this.addAbility(new ReinforceAbility(ManacostVariableValue.instance, new ManaCostsImpl("{X}{W}{W}"))); } public SwellOfCourage(final SwellOfCourage card) { diff --git a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java index b2034ce917..c0b12aa484 100644 --- a/Mage.Sets/src/mage/cards/s/SwiftReckoning.java +++ b/Mage.Sets/src/mage/cards/s/SwiftReckoning.java @@ -23,10 +23,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class SwiftReckoning extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public SwiftReckoning(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SwirlingTorrent.java b/Mage.Sets/src/mage/cards/s/SwirlingTorrent.java new file mode 100644 index 0000000000..4514148335 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwirlingTorrent.java @@ -0,0 +1,43 @@ +package mage.cards.s; + +import mage.abilities.Mode; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SwirlingTorrent extends CardImpl { + + public SwirlingTorrent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{5}{U}"); + + // Choose one or both — + this.getSpellAbility().getModes().setMinModes(1); + this.getSpellAbility().getModes().setMaxModes(2); + + // • Put target creature on top of its owner's library. + this.getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("put on library top")); + + // • Return target creature to its owner's hand. + Mode mode = new Mode(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCreaturePermanent().withChooseHint("return to hand")); + this.getSpellAbility().addMode(mode); + } + + private SwirlingTorrent(final SwirlingTorrent card) { + super(card); + } + + @Override + public SwirlingTorrent copy() { + return new SwirlingTorrent(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SwordOfTheParuns.java b/Mage.Sets/src/mage/cards/s/SwordOfTheParuns.java index a8581ef580..5c610773a7 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfTheParuns.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfTheParuns.java @@ -37,8 +37,8 @@ public final class SwordOfTheParuns extends CardImpl { private static final FilterCreaturePermanent filterTapped = new FilterCreaturePermanent(); private static final FilterCreaturePermanent filterUntapped = new FilterCreaturePermanent(); static { - filterTapped.add(new TappedPredicate()); - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterTapped.add(TappedPredicate.instance); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } public SwordOfTheParuns(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java b/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java index d003579100..9968d14771 100644 --- a/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java +++ b/Mage.Sets/src/mage/cards/s/SwordOfWarAndPeace.java @@ -69,7 +69,7 @@ class SwordOfWarAndPeaceAbility extends TriggeredAbilityImpl { public SwordOfWarAndPeaceAbility() { super(Zone.BATTLEFIELD, new SwordOfWarAndPeaceDamageEffect()); - this.addEffect(new GainLifeEffect(new CardsInControllerHandCount())); + this.addEffect(new GainLifeEffect(CardsInControllerHandCount.instance)); } public SwordOfWarAndPeaceAbility(final SwordOfWarAndPeaceAbility ability) { diff --git a/Mage.Sets/src/mage/cards/s/SwornDefender.java b/Mage.Sets/src/mage/cards/s/SwornDefender.java new file mode 100644 index 0000000000..b46b26f1bf --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SwornDefender.java @@ -0,0 +1,90 @@ + +package mage.cards.s; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; +import mage.util.CardUtil; + +/** + * + * @author LevelX2 & L_J + */ +public final class SwornDefender extends CardImpl { + + public SwornDefender(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{W}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.KNIGHT); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking or blocked by SwornDefender"); + filter.add(Predicates.or(new BlockedByIdPredicate(this.getId()), + new BlockingAttackerIdPredicate(this.getId()))); + // {1}: Sworn Defender’s power becomes the toughness of target creature blocking or being blocked by Sworn Defender minus 1 until end of turn, and Sworn Defender’s toughness becomes 1 plus the power of that creature until end of turn. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new SwornDefenderEffect(), new GenericManaCost(1)); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + + } + + public SwornDefender(final SwornDefender card) { + super(card); + } + + @Override + public SwornDefender copy() { + return new SwornDefender(this); + } +} + +class SwornDefenderEffect extends OneShotEffect { + + public SwornDefenderEffect() { + super(Outcome.Detriment); + this.staticText = "{this}'s power becomes the toughness of target creature blocking or being blocked by {this} minus 1 until end of turn, and {this}’s toughness becomes 1 plus the power of that creature until end of turn"; + } + + public SwornDefenderEffect(final SwornDefenderEffect effect) { + super(effect); + } + + @Override + public SwornDefenderEffect copy() { + return new SwornDefenderEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Permanent targetPermanent = game.getPermanentOrLKIBattlefield(targetPointer.getFirst(game, source)); + if (controller != null && targetPermanent != null) { + int newPower = CardUtil.subtractWithOverflowCheck(targetPermanent.getToughness().getValue(), 1); + int newToughness = CardUtil.addWithOverflowCheck(targetPermanent.getPower().getValue(), 1); + game.addEffect(new SetPowerToughnessSourceEffect(newPower, newToughness, Duration.EndOfTurn, SubLayer.SetPT_7b), source); + return true; + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/s/SylvanBrushstrider.java b/Mage.Sets/src/mage/cards/s/SylvanBrushstrider.java new file mode 100644 index 0000000000..c7182ee0d9 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SylvanBrushstrider.java @@ -0,0 +1,37 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.GainLifeEffect; +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 SylvanBrushstrider extends CardImpl { + + public SylvanBrushstrider(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Sylvan Brushstrider enters the battlefield, you gain 2 life. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainLifeEffect(2))); + } + + private SylvanBrushstrider(final SylvanBrushstrider card) { + super(card); + } + + @Override + public SylvanBrushstrider copy() { + return new SylvanBrushstrider(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SylvanHierophant.java b/Mage.Sets/src/mage/cards/s/SylvanHierophant.java new file mode 100644 index 0000000000..80555a1adc --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SylvanHierophant.java @@ -0,0 +1,57 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.ExileSourceEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.AnotherCardPredicate; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + + +/** + * + * @author jmharmon + */ + +public final class SylvanHierophant extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("another target creature card from your graveyard"); + + static { + filter.add(new AnotherCardPredicate()); + } + + public SylvanHierophant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Sylvan Hierophant dies, exile Sylvan Hierophant, then return another target creature card from your graveyard to your hand. + Effect effect = new ReturnFromGraveyardToHandTargetEffect(); + Ability ability = new DiesTriggeredAbility(new ExileSourceEffect(), false); + ability.addEffect(effect); + ability.addTarget(new TargetCardInYourGraveyard(filter)); + this.addAbility(ability); + } + + public SylvanHierophant(final SylvanHierophant card) { + super(card); + } + + @Override + public SylvanHierophant copy() { + return new SylvanHierophant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java index 97a7e02a0b..259f1d9622 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanLibrary.java +++ b/Mage.Sets/src/mage/cards/s/SylvanLibrary.java @@ -1,4 +1,3 @@ - package mage.cards.s; import java.util.HashMap; @@ -73,7 +72,7 @@ class SylvanLibraryEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { controller.drawCards(2, game); - SylvanLibraryCardsDrawnThisTurnWatcher watcher = (SylvanLibraryCardsDrawnThisTurnWatcher) game.getState().getWatchers().get(SylvanLibraryCardsDrawnThisTurnWatcher.class.getSimpleName()); + SylvanLibraryCardsDrawnThisTurnWatcher watcher = game.getState().getWatcher(SylvanLibraryCardsDrawnThisTurnWatcher.class); if (watcher != null) { Cards cards = new CardsImpl(); Set cardsDrawnThisTurn = watcher.getCardsDrawnThisTurn(controller.getId()); @@ -106,7 +105,7 @@ class SylvanLibraryEffect extends OneShotEffect { } } } - controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, false); + controller.putCardsOnTopOfLibrary(cardsPutBack, game, source, true); } } return true; @@ -120,7 +119,7 @@ class SylvanLibraryCardsDrawnThisTurnWatcher extends Watcher { private final Map> cardsDrawnThisTurn = new HashMap<>(); public SylvanLibraryCardsDrawnThisTurnWatcher() { - super(SylvanLibraryCardsDrawnThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SylvanLibraryCardsDrawnThisTurnWatcher(final SylvanLibraryCardsDrawnThisTurnWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/s/SylvanPrimordial.java b/Mage.Sets/src/mage/cards/s/SylvanPrimordial.java index 625bcf609b..b6c63993d5 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanPrimordial.java +++ b/Mage.Sets/src/mage/cards/s/SylvanPrimordial.java @@ -1,7 +1,6 @@ package mage.cards.s; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -25,15 +24,17 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.common.TargetCardInLibrary; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class SylvanPrimordial extends CardImpl { public SylvanPrimordial(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{G}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); this.subtype.add(SubType.AVATAR); this.power = new MageInt(6); @@ -43,24 +44,9 @@ public final class SylvanPrimordial extends CardImpl { this.addAbility(ReachAbility.getInstance()); // When Sylvan Primordial enters the battlefield, for each opponent, destroy target noncreature permanent that player controls. For each permanent destroyed this way, search your library for a Forest card and put that card onto the battlefield tapped. Then shuffle your library. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SylvanPrimordialEffect(),false)); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - ability.getTargets().clear(); - for(UUID opponentId : game.getOpponents(ability.getControllerId())) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null) { - FilterPermanent filter = new FilterPermanent("noncreature permanent from opponent " + opponent.getLogName()); - filter.add(new ControllerIdPredicate(opponentId)); - filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); - TargetPermanent target = new TargetPermanent(0,1, filter,false); - ability.addTarget(target); - } - } - } + Ability ability = new EntersBattlefieldTriggeredAbility(new SylvanPrimordialEffect(), false); + ability.setTargetAdjuster(SylvanPrimordialAdjuster.instance); + this.addAbility(ability); } public SylvanPrimordial(final SylvanPrimordial card) { @@ -73,10 +59,30 @@ public final class SylvanPrimordial extends CardImpl { } } +enum SylvanPrimordialAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + for (UUID opponentId : game.getOpponents(ability.getControllerId())) { + Player opponent = game.getPlayer(opponentId); + if (opponent != null) { + FilterPermanent filter = new FilterPermanent("noncreature permanent from opponent " + opponent.getLogName()); + filter.add(new ControllerIdPredicate(opponentId)); + filter.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + TargetPermanent target = new TargetPermanent(0, 1, filter, false); + ability.addTarget(target); + } + } + } +} + class SylvanPrimordialEffect extends OneShotEffect { private static final FilterLandCard filterForest = new FilterLandCard("Forest"); - static{ + + static { filterForest.add(new SubtypePredicate(SubType.FOREST)); } @@ -98,7 +104,7 @@ class SylvanPrimordialEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { boolean result = false; int destroyedCreatures = 0; - for (Target target: source.getTargets()) { + for (Target target : source.getTargets()) { if (target instanceof TargetPermanent) { Permanent targetPermanent = game.getPermanent(target.getFirstTarget()); if (targetPermanent != null) { @@ -109,7 +115,7 @@ class SylvanPrimordialEffect extends OneShotEffect { } } if (destroyedCreatures > 0) { - new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(destroyedCreatures,filterForest), true, true).apply(game, source); + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(destroyedCreatures, filterForest), true, true).apply(game, source); } return result; } diff --git a/Mage.Sets/src/mage/cards/s/SylvanYeti.java b/Mage.Sets/src/mage/cards/s/SylvanYeti.java index 688718f865..d402b7450b 100644 --- a/Mage.Sets/src/mage/cards/s/SylvanYeti.java +++ b/Mage.Sets/src/mage/cards/s/SylvanYeti.java @@ -27,7 +27,7 @@ public final class SylvanYeti extends CardImpl { this.toughness = new MageInt(4); // Sylvan Yeti's power is equal to the number of cards in your hand. - Effect effect = new SetPowerSourceEffect(new CardsInControllerHandCount(), Duration.EndOfGame); + Effect effect = new SetPowerSourceEffect(CardsInControllerHandCount.instance, Duration.EndOfGame); this.addAbility(new SimpleStaticAbility(Zone.ALL, effect)); } diff --git a/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java b/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java index 55000ba822..3cb81da2ec 100644 --- a/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java +++ b/Mage.Sets/src/mage/cards/s/SymbioticDeployment.java @@ -27,7 +27,7 @@ public final class SymbioticDeployment extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public SymbioticDeployment(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/s/Syncopate.java b/Mage.Sets/src/mage/cards/s/Syncopate.java index 01dd9e8825..76c656fa77 100644 --- a/Mage.Sets/src/mage/cards/s/Syncopate.java +++ b/Mage.Sets/src/mage/cards/s/Syncopate.java @@ -71,7 +71,7 @@ class SyncopateCounterUnlessPaysEffect extends OneShotEffect { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); if (stackObject != null && !game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.COUNTER, source.getFirstTarget(), source.getSourceId(), stackObject.getControllerId()))) { game.informPlayers(sourceObject.getIdName() + ": cost wasn't payed - countering " + stackObject.getName()); - game.rememberLKI(source.getFirstTarget(), Zone.STACK, (Spell) stackObject); + game.rememberLKI(source.getFirstTarget(), Zone.STACK, stackObject); controller.moveCards((Spell) spell, Zone.EXILED, source, game); game.fireEvent(GameEvent.getEvent(GameEvent.EventType.COUNTERED, source.getFirstTarget(), source.getSourceId(), stackObject.getControllerId())); return true; diff --git a/Mage.Sets/src/mage/cards/s/SyndicateGuildmage.java b/Mage.Sets/src/mage/cards/s/SyndicateGuildmage.java new file mode 100644 index 0000000000..2103a1c94a --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyndicateGuildmage.java @@ -0,0 +1,67 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +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.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetOpponentOrPlaneswalker; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class SyndicateGuildmage extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public SyndicateGuildmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.CLERIC); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // {1}{W}, {T}: Tap target creature with power 4 or greater. + Ability ability = new SimpleActivatedAbility( + new TapTargetEffect(), new ManaCostsImpl("{1}{W}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + + // {4}{B}, {T}: Syndicate Guildmage deals 2 damage to target opponent or planeswalker. + ability = new SimpleActivatedAbility( + new DamageTargetEffect(2), new ManaCostsImpl("{4}{B}") + ); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + private SyndicateGuildmage(final SyndicateGuildmage card) { + super(card); + } + + @Override + public SyndicateGuildmage copy() { + return new SyndicateGuildmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SyndicateMessenger.java b/Mage.Sets/src/mage/cards/s/SyndicateMessenger.java new file mode 100644 index 0000000000..1450ab1d26 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SyndicateMessenger.java @@ -0,0 +1,40 @@ +package mage.cards.s; + +import mage.MageInt; +import mage.abilities.keyword.AfterlifeAbility; +import mage.abilities.keyword.FlyingAbility; +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 SyndicateMessenger extends CardImpl { + + public SyndicateMessenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + private SyndicateMessenger(final SyndicateMessenger card) { + super(card); + } + + @Override + public SyndicateMessenger copy() { + return new SyndicateMessenger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java b/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java new file mode 100644 index 0000000000..c9605157db --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TacticalAdvantage.java @@ -0,0 +1,51 @@ +package mage.cards.t; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.BlockedPredicate; +import mage.filter.predicate.permanent.BlockingPredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class TacticalAdvantage extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("blocking or blocked creature you control"); + + static { + filter.add( + Predicates.or( + BlockingPredicate.instance, + BlockedPredicate.instance + + )); + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public TacticalAdvantage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}"); + + // Target blocking or blocked creature you control gets +2/+2 until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn)); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + public TacticalAdvantage(final TacticalAdvantage card) { + super(card); + } + + @Override + public TacticalAdvantage copy() { + return new TacticalAdvantage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java index 2ea1bd128e..24ac35adcd 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java +++ b/Mage.Sets/src/mage/cards/t/TaigamOjutaiMaster.java @@ -1,4 +1,3 @@ - package mage.cards.t; import mage.MageInt; @@ -16,7 +15,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.FilterSpell; -import mage.filter.FilterStackObject; +import mage.filter.StaticFilters; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -30,7 +29,6 @@ import mage.watchers.common.AttackedThisTurnWatcher; import java.util.UUID; /** - * * @author spjspj */ public final class TaigamOjutaiMaster extends CardImpl { @@ -57,8 +55,8 @@ public final class TaigamOjutaiMaster extends CardImpl { this.toughness = new MageInt(4); // Instant, sorcery, and Dragon spells you control can't be countered. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeCounteredControlledEffect(filter, new FilterStackObject(), Duration.WhileOnBattlefield))); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeCounteredControlledEffect(filter, StaticFilters.FILTER_SPELL_OR_ABILITY, Duration.WhileOnBattlefield))); + // Whenever you cast an instant or sorcery spell from your hand, if Taigam, Ojutai Master attacked this turn, that spell gains rebound. Ability ability = new ConditionalInterveningIfTriggeredAbility(new TaigamOjutaiMasterTriggeredAbility(), AttackedThisTurnSourceCondition.instance, diff --git a/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java b/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java index 86f837ebf1..10f37ba6ec 100644 --- a/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java +++ b/Mage.Sets/src/mage/cards/t/TaigamSidisisHand.java @@ -54,7 +54,7 @@ public final class TaigamSidisisHand extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SkipDrawStepEffect())); // At the beginning of your upkeep, look at the top three cards of your library. Put one of them into your hand and the rest into your graveyard. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new LookLibraryAndPickControllerEffect(new StaticValue(3), false, new StaticValue(1), StaticFilters.FILTER_CARD, Zone.GRAVEYARD, false, false, false, Zone.HAND, false), TargetController.YOU, false)); // {B}, {T}, Exile X cards from your graveyard: Target creature gets -X/-X until end of turn. diff --git a/Mage.Sets/src/mage/cards/t/TaintedPact.java b/Mage.Sets/src/mage/cards/t/TaintedPact.java index 211aea5fcd..bed5477236 100644 --- a/Mage.Sets/src/mage/cards/t/TaintedPact.java +++ b/Mage.Sets/src/mage/cards/t/TaintedPact.java @@ -73,7 +73,7 @@ class TaintedPactEffect extends OneShotEffect{ break; } names.add(card.getName()); - if (player.chooseUse(outcome, new StringBuilder("Put ").append(card.getName()).append("into your hand?").toString(), source, game)) { + if (player.chooseUse(outcome, "Put " + card.getName() + "into your hand?", source, game)) { //Adds the current card to hand if it is chosen. card.moveToZone(Zone.HAND, source.getSourceId(), game, true); break; diff --git a/Mage.Sets/src/mage/cards/t/TaintedSigil.java b/Mage.Sets/src/mage/cards/t/TaintedSigil.java index 18f6f77378..424a3d3191 100644 --- a/Mage.Sets/src/mage/cards/t/TaintedSigil.java +++ b/Mage.Sets/src/mage/cards/t/TaintedSigil.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeSourceCost; @@ -16,23 +15,22 @@ import mage.constants.Zone; import mage.game.Game; import mage.watchers.common.PlayerLostLifeWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class TaintedSigil extends CardImpl { - - String rule = "You gain life equal to the total life lost by all players this turn"; + + private static final String rule = "You gain life equal to the total life lost by all players this turn"; public TaintedSigil(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}{W}{B}"); - - - + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}{B}"); // {tap}, Sacrifice Tainted Sigil: You gain life equal to the total life lost by all players this turn. - AllPlayersLostLifeCount totalLifeLostThisTurn = new AllPlayersLostLifeCount(); - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new GainLifeEffect(totalLifeLostThisTurn, rule), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, new GainLifeEffect(AllPlayersLostLifeCount.instance, rule), new TapSourceCost() + ); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -48,7 +46,8 @@ public final class TaintedSigil extends CardImpl { } } -class AllPlayersLostLifeCount implements DynamicValue { +enum AllPlayersLostLifeCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -56,11 +55,11 @@ class AllPlayersLostLifeCount implements DynamicValue { } public int calculate(Game game, UUID controllerId) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { int amountLifeLost = 0; for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) { - amountLifeLost += watcher.getLiveLost(playerId); + amountLifeLost += watcher.getLifeLost(playerId); } return amountLifeLost; } @@ -69,7 +68,7 @@ class AllPlayersLostLifeCount implements DynamicValue { @Override public DynamicValue copy() { - return new AllPlayersLostLifeCount(); + return instance; } @Override diff --git a/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java b/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java index faa291400c..a396479913 100644 --- a/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java +++ b/Mage.Sets/src/mage/cards/t/TajicLegionsEdge.java @@ -30,7 +30,7 @@ public final class TajicLegionsEdge extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("other creatures you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TajicLegionsEdge(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TakeDown.java b/Mage.Sets/src/mage/cards/t/TakeDown.java index ead1cc694d..527cc1fad0 100644 --- a/Mage.Sets/src/mage/cards/t/TakeDown.java +++ b/Mage.Sets/src/mage/cards/t/TakeDown.java @@ -35,7 +35,7 @@ public final class TakeDown extends CardImpl { // • Take Down deals 1 damage to each creature with flying Mode mode = new Mode(); - mode.getEffects().add(new DamageAllEffect(1, filter)); + mode.addEffect(new DamageAllEffect(1, filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TakeHeart.java b/Mage.Sets/src/mage/cards/t/TakeHeart.java index b57596a363..cdf08b872c 100644 --- a/Mage.Sets/src/mage/cards/t/TakeHeart.java +++ b/Mage.Sets/src/mage/cards/t/TakeHeart.java @@ -23,7 +23,7 @@ public final class TakeHeart extends CardImpl { = new FilterControlledCreaturePermanent(); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public TakeHeart(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TakeVengeance.java b/Mage.Sets/src/mage/cards/t/TakeVengeance.java index 5a229b0ba1..e58e3d3f1b 100644 --- a/Mage.Sets/src/mage/cards/t/TakeVengeance.java +++ b/Mage.Sets/src/mage/cards/t/TakeVengeance.java @@ -18,7 +18,7 @@ public final class TakeVengeance extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public TakeVengeance(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TalarasBattalion.java b/Mage.Sets/src/mage/cards/t/TalarasBattalion.java index c7ea37d9da..cba7bb5c0f 100644 --- a/Mage.Sets/src/mage/cards/t/TalarasBattalion.java +++ b/Mage.Sets/src/mage/cards/t/TalarasBattalion.java @@ -94,7 +94,7 @@ class CastGreenSpellThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - TalarasBattalionWatcher watcher = (TalarasBattalionWatcher) game.getState().getWatchers().get(TalarasBattalionWatcher.class.getSimpleName(), source.getControllerId()); + TalarasBattalionWatcher watcher = game.getState().getWatcher(TalarasBattalionWatcher.class, source.getControllerId()); if (watcher != null) { return watcher.conditionMet(); } @@ -112,7 +112,7 @@ class TalarasBattalionWatcher extends Watcher { private final UUID cardId; public TalarasBattalionWatcher(UUID cardId) { - super(TalarasBattalionWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); this.cardId = cardId; } diff --git a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java index 03a409cb8d..5751791d2e 100644 --- a/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java +++ b/Mage.Sets/src/mage/cards/t/TalentOfTheTelepath.java @@ -75,10 +75,7 @@ class TalentOfTheTelepathEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObject(game); if (targetOpponent != null && sourceObject != null) { Set allCards = targetOpponent.getLibrary().getTopCards(game, 7); - Cards cards = new CardsImpl(); - for (Card card : allCards) { - cards.add(card); - } + Cards cards = new CardsImpl(allCards); targetOpponent.revealCards(sourceObject.getIdName() + " - " + targetOpponent.getName() + "'s top library cards", cards, game); for (Card card : allCards) { if (filter.match(card, game)) { diff --git a/Mage.Sets/src/mage/cards/t/TalonOfPain.java b/Mage.Sets/src/mage/cards/t/TalonOfPain.java index 0558c9b933..b6fa0d3724 100644 --- a/Mage.Sets/src/mage/cards/t/TalonOfPain.java +++ b/Mage.Sets/src/mage/cards/t/TalonOfPain.java @@ -42,7 +42,7 @@ public final class TalonOfPain extends CardImpl { this.addAbility(new TalonOfPainTriggeredAbility()); // {X}, {T}, Remove X charge counters from Talon of Pain: Talon of Pain deals X damage to any target. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new ManacostVariableValue()), new ManaCostsImpl("{X}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(ManacostVariableValue.instance), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); ability.addCost(new TalonOfPainRemoveVariableCountersSourceCost(CounterType.CHARGE.createInstance())); ability.addTarget(new TargetAnyTarget()); diff --git a/Mage.Sets/src/mage/cards/t/TalusPaladin.java b/Mage.Sets/src/mage/cards/t/TalusPaladin.java index 2619c545e0..65280dc6d6 100644 --- a/Mage.Sets/src/mage/cards/t/TalusPaladin.java +++ b/Mage.Sets/src/mage/cards/t/TalusPaladin.java @@ -112,10 +112,9 @@ class TalusPaladinEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent taluspPaladin = game.getPermanent(source.getSourceId()); - if (taluspPaladin != null) { - StringBuilder sb = new StringBuilder(); - sb.append("Put a +1/+1 counter on Talus Paladin?"); - if (!player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { + if (taluspPaladin != null && player != null) { + String question = "Put a +1/+1 counter on Talus Paladin?"; + if (!player.chooseUse(Outcome.Benefit, question, source, game)) { return false; } taluspPaladin.addCounters(CounterType.P1P1.createInstance(), source, game); diff --git a/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java new file mode 100644 index 0000000000..b2352caa2e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TamiyoCollectorOfTales.java @@ -0,0 +1,157 @@ +package mage.cards.t; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.*; +import mage.cards.repository.CardRepository; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.PermanentCard; +import mage.game.stack.Spell; +import mage.game.stack.StackAbility; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class TamiyoCollectorOfTales extends CardImpl { + + public TamiyoCollectorOfTales(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TAMIYO); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Spells and abilities your opponents control can't cause you to discard cards or sacrifice permanents. + this.addAbility(new SimpleStaticAbility(new TamiyoCollectorOfTalesRuleEffect())); + + // +1: Choose a nonland card name, then reveal the top four cards of your library. Put all cards with the chosen name from among them into your hand and the rest into your graveyard. + this.addAbility(new LoyaltyAbility(new TamiyoCollectorOfTalesEffect(), 1)); + + // -3: Return target card from your graveyard to your hand. + Ability ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); + ability.addTarget(new TargetCardInYourGraveyard()); + this.addAbility(ability); + } + + private TamiyoCollectorOfTales(final TamiyoCollectorOfTales card) { + super(card); + } + + @Override + public TamiyoCollectorOfTales copy() { + return new TamiyoCollectorOfTales(this); + } +} + +class TamiyoCollectorOfTalesRuleEffect extends ContinuousRuleModifyingEffectImpl { + + TamiyoCollectorOfTalesRuleEffect() { + super(Duration.WhileOnBattlefield, Benefit); + staticText = "Spells and abilities your opponents control can't " + + "cause you to discard cards or sacrifice permanents"; + } + + private TamiyoCollectorOfTalesRuleEffect(final TamiyoCollectorOfTalesRuleEffect effect) { + super(effect); + } + + @Override + public TamiyoCollectorOfTalesRuleEffect copy() { + return new TamiyoCollectorOfTalesRuleEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.SACRIFICE_PERMANENT + || event.getType() == GameEvent.EventType.DISCARD_CARD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event.getPlayerId().equals(source.getControllerId())) { + MageObject object = game.getObject(event.getSourceId()); + if (object instanceof PermanentCard) { + if (game.getOpponents(source.getControllerId()).contains(((PermanentCard) object).getControllerId())) { + return true; + } + } + if (object instanceof Spell) { + if (game.getOpponents(source.getControllerId()).contains(((Spell) object).getControllerId())) { + return true; + } + } + if (object instanceof Card) { + if (game.getOpponents(source.getControllerId()).contains(((Card) object).getOwnerId())) { + return true; + } + } + if (object instanceof StackAbility) { + if (game.getOpponents(source.getControllerId()).contains(((StackAbility) object).getControllerId())) { + return true; + } + } + } + return false; + } +} + +class TamiyoCollectorOfTalesEffect extends OneShotEffect { + + TamiyoCollectorOfTalesEffect() { + super(Outcome.Benefit); + staticText = "Choose a nonland card name, then reveal the top four cards of your library. " + + "Put all cards with the chosen name from among them into your hand and the rest into your graveyard."; + } + + private TamiyoCollectorOfTalesEffect(final TamiyoCollectorOfTalesEffect effect) { + super(effect); + } + + @Override + public TamiyoCollectorOfTalesEffect copy() { + return new TamiyoCollectorOfTalesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Choice choice = new ChoiceImpl(); + choice.setChoices(CardRepository.instance.getNonLandNames()); + choice.setMessage("Choose a nonland card name"); + if (!player.choose(outcome, choice, game)) { + return false; + } + game.informPlayers(source.getSourceObject(game).getLogName() + ", chosen name: [" + choice.getChoice() + ']'); + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 4)); + Cards cards2 = new CardsImpl(); + player.revealCards(source, cards, game); + for (Card card : cards.getCards(game)) { + if (card.getName().equals(choice.getChoice())) { + cards2.add(card); + } + } + cards.removeAll(cards2); + player.moveCards(cards, Zone.GRAVEYARD, source, game); + player.moveCards(cards2, Zone.HAND, source, game); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java index 1df9e2de40..17039e4b9c 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoFieldResearcher.java @@ -41,7 +41,7 @@ import mage.constants.SuperType; */ public final class TamiyoFieldResearcher extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("nonland permanent"); + private static final FilterPermanent filter = new FilterPermanent("nonland permanent"); static { filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); diff --git a/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java b/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java index 6239f76dff..06ef55dadf 100644 --- a/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java +++ b/Mage.Sets/src/mage/cards/t/TamiyoTheMoonSage.java @@ -68,7 +68,7 @@ class TappedCreaturesControlledByTargetCount implements DynamicValue { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TamiyosEpiphany.java b/Mage.Sets/src/mage/cards/t/TamiyosEpiphany.java new file mode 100644 index 0000000000..bd626fa4f0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TamiyosEpiphany.java @@ -0,0 +1,32 @@ +package mage.cards.t; + +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TamiyosEpiphany extends CardImpl { + + public TamiyosEpiphany(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U}"); + + // Scry 4, then draw two cards. + this.getSpellAbility().addEffect(new ScryEffect(4).setText("scry 4,")); + this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2).setText("then draw two cards")); + } + + private TamiyosEpiphany(final TamiyosEpiphany card) { + super(card); + } + + @Override + public TamiyosEpiphany copy() { + return new TamiyosEpiphany(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Tangle.java b/Mage.Sets/src/mage/cards/t/Tangle.java index 17631aca5e..5efd00ec70 100644 --- a/Mage.Sets/src/mage/cards/t/Tangle.java +++ b/Mage.Sets/src/mage/cards/t/Tangle.java @@ -52,7 +52,7 @@ class TangleEffect extends OneShotEffect { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public TangleEffect() { diff --git a/Mage.Sets/src/mage/cards/t/TangleKelp.java b/Mage.Sets/src/mage/cards/t/TangleKelp.java index d4dde772df..710dbc4dd7 100644 --- a/Mage.Sets/src/mage/cards/t/TangleKelp.java +++ b/Mage.Sets/src/mage/cards/t/TangleKelp.java @@ -107,7 +107,7 @@ class DontUntapIfAttackedLastTurnEnchantedEffect extends ContinuousRuleModifying if (enchantment != null && enchantment.getAttachedTo() != null && event.getTargetId().equals(enchantment.getAttachedTo())) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); if (permanent != null && permanent.isControlledBy(game.getActivePlayerId())) { - AttackedLastTurnWatcher watcher = (AttackedLastTurnWatcher) game.getState().getWatchers().get(AttackedLastTurnWatcher.class.getSimpleName()); + AttackedLastTurnWatcher watcher = game.getState().getWatcher(AttackedLastTurnWatcher.class); if (watcher != null) { Set attackingCreatures = watcher.getAttackedLastTurnCreatures(permanent.getControllerId()); MageObjectReference mor = new MageObjectReference(permanent, game); diff --git a/Mage.Sets/src/mage/cards/t/TangleWire.java b/Mage.Sets/src/mage/cards/t/TangleWire.java index 54128b1f59..befb444899 100644 --- a/Mage.Sets/src/mage/cards/t/TangleWire.java +++ b/Mage.Sets/src/mage/cards/t/TangleWire.java @@ -51,7 +51,7 @@ class TangleWireEffect extends OneShotEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped artifact, creature, or land he or she controls"); static{ - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), diff --git a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java index 2cccde96c9..f73f6f4151 100644 --- a/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java +++ b/Mage.Sets/src/mage/cards/t/TapestryOfTheAges.java @@ -56,7 +56,7 @@ enum PlayerCastNonCreatureSpellCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerCastNonCreatureSpellWatcher watcher = (PlayerCastNonCreatureSpellWatcher) game.getState().getWatchers().get(PlayerCastNonCreatureSpellWatcher.class.getSimpleName()); + PlayerCastNonCreatureSpellWatcher watcher = game.getState().getWatcher(PlayerCastNonCreatureSpellWatcher.class); return watcher != null && watcher.playerDidCastNonCreatureSpellThisTurn(source.getControllerId()); } @@ -68,10 +68,10 @@ enum PlayerCastNonCreatureSpellCondition implements Condition { class PlayerCastNonCreatureSpellWatcher extends Watcher { - Set playerIds = new HashSet<>(); + private Set playerIds = new HashSet<>(); public PlayerCastNonCreatureSpellWatcher() { - super(PlayerCastNonCreatureSpellWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerCastNonCreatureSpellWatcher(final PlayerCastNonCreatureSpellWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/Tariff.java b/Mage.Sets/src/mage/cards/t/Tariff.java index d2e42f109c..04ca7709ae 100644 --- a/Mage.Sets/src/mage/cards/t/Tariff.java +++ b/Mage.Sets/src/mage/cards/t/Tariff.java @@ -85,20 +85,18 @@ class TariffEffect extends OneShotEffect { Permanent creatureToPayFor = chooseOnePermanent(game, player, creatures); - if (creatureToPayFor != null) { + if (creatureToPayFor != null && sourceObject != null) { ManaCosts manaCost = ManaCosts.removeVariableManaCost(creatureToPayFor.getManaCost()); - String message = new StringBuilder("Pay ").append(manaCost.getText()).append(" (otherwise sacrifice ") - .append(creatureToPayFor.getName()).append(")?").toString(); + String message = "Pay " + manaCost.getText() + " (otherwise sacrifice " + + creatureToPayFor.getName() + ")?"; if (player.chooseUse(Outcome.Benefit, message, source, game)) { if (manaCost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { - game.informPlayers(new StringBuilder(sourceObject != null ? sourceObject.getName() : "") - .append(": ").append(player.getLogName()).append(" has paid").toString()); + game.informPlayers(sourceObject.getName() + ": " + player.getLogName() + " has paid"); return; } } - game.informPlayers(new StringBuilder(sourceObject != null ? sourceObject.getName() : "") - .append(": ").append(player.getLogName()).append(" hasn't paid").toString()); + game.informPlayers(sourceObject.getName() + ": " + player.getLogName() + " hasn't paid"); creatureToPayFor.sacrifice(source.getSourceId(), game); } } diff --git a/Mage.Sets/src/mage/cards/t/TasigurTheGoldenFang.java b/Mage.Sets/src/mage/cards/t/TasigurTheGoldenFang.java index 43755421d8..814b97225b 100644 --- a/Mage.Sets/src/mage/cards/t/TasigurTheGoldenFang.java +++ b/Mage.Sets/src/mage/cards/t/TasigurTheGoldenFang.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -12,11 +11,7 @@ import mage.abilities.keyword.DelveAbility; import mage.cards.Card; 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.Zone; +import mage.constants.*; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.other.OwnerIdPredicate; import mage.game.Game; @@ -25,14 +20,15 @@ import mage.target.Target; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TasigurTheGoldenFang extends CardImpl { public TasigurTheGoldenFang(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); @@ -42,12 +38,12 @@ public final class TasigurTheGoldenFang extends CardImpl { // Delve this.addAbility(new DelveAbility()); // {2}{G/U}{G/U}: Put the top two cards of your library into your graveyard, then return a nonland card of an opponent's choice from your graveyard to your hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutTopCardOfLibraryIntoGraveControllerEffect(2), new ManaCostsImpl("{2}{G/U}{G/U}")); + Ability ability = new SimpleActivatedAbility(new PutTopCardOfLibraryIntoGraveControllerEffect(2), new ManaCostsImpl("{2}{G/U}{G/U}")); ability.addEffect(new TasigurTheGoldenFangEffect()); this.addAbility(ability); } - public TasigurTheGoldenFang(final TasigurTheGoldenFang card) { + private TasigurTheGoldenFang(final TasigurTheGoldenFang card) { super(card); } @@ -59,12 +55,12 @@ public final class TasigurTheGoldenFang extends CardImpl { class TasigurTheGoldenFangEffect extends OneShotEffect { - public TasigurTheGoldenFangEffect() { + TasigurTheGoldenFangEffect() { super(Outcome.ReturnToHand); this.staticText = ", then return a nonland card of an opponent's choice from your graveyard to your hand"; } - public TasigurTheGoldenFangEffect(final TasigurTheGoldenFangEffect effect) { + private TasigurTheGoldenFangEffect(final TasigurTheGoldenFangEffect effect) { super(effect); } @@ -92,6 +88,7 @@ class TasigurTheGoldenFangEffect extends OneShotEffect { FilterNonlandCard filter = new FilterNonlandCard("nonland card from " + controller.getLogName() + " graveyard"); filter.add(new OwnerIdPredicate(controller.getId())); Target target = new TargetCardInGraveyard(filter); + target.setNotTarget(true); opponent.chooseTarget(outcome, target, source, game); Card card = game.getCard(target.getFirstTarget()); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java b/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java index 1eb857cb95..d1e5947df3 100644 --- a/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java +++ b/Mage.Sets/src/mage/cards/t/TaskMageAssembly.java @@ -71,7 +71,7 @@ class TaskMageAssemblyStateTriggeredAbility extends StateTriggeredAbility { @Override public String getRule() { - return new StringBuilder("When there are no creatures on the battlefield, ").append(super.getRule()).toString() ; + return "When there are no creatures on the battlefield, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/t/TattermungeWitch.java b/Mage.Sets/src/mage/cards/t/TattermungeWitch.java index 123bf0fab7..58fb990feb 100644 --- a/Mage.Sets/src/mage/cards/t/TattermungeWitch.java +++ b/Mage.Sets/src/mage/cards/t/TattermungeWitch.java @@ -27,7 +27,7 @@ public final class TattermungeWitch extends CardImpl { static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("Each blocked creature"); static { - filter.add(new BlockedPredicate()); + filter.add(BlockedPredicate.instance); } public TattermungeWitch(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/Taunt.java b/Mage.Sets/src/mage/cards/t/Taunt.java index cff6d3e77c..56478052a3 100644 --- a/Mage.Sets/src/mage/cards/t/Taunt.java +++ b/Mage.Sets/src/mage/cards/t/Taunt.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.cards.CardImpl; @@ -13,14 +11,15 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; +import java.util.UUID; + /** - * * @author emerald000 */ public final class Taunt extends CardImpl { public Taunt(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}"); // During target player's next turn, creatures that player controls attack you if able. this.getSpellAbility().addEffect(new TauntEffect()); @@ -60,9 +59,9 @@ class TauntEffect extends RequirementEffect { @Override public boolean isInactive(Ability source, Game game) { - return startingTurn != game.getTurnNum() && + return getStartingTurnNum() != game.getTurnNum() && (game.getPhase().getType() == TurnPhase.END && - game.isActivePlayer(this.getTargetPointer().getFirst(game, source))); + game.isActivePlayer(this.getTargetPointer().getFirst(game, source))); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TavernSwindler.java b/Mage.Sets/src/mage/cards/t/TavernSwindler.java index 0c5645c802..e816947ea2 100644 --- a/Mage.Sets/src/mage/cards/t/TavernSwindler.java +++ b/Mage.Sets/src/mage/cards/t/TavernSwindler.java @@ -62,7 +62,7 @@ class TavernSwindlerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { game.informPlayers(controller.getLogName() + " got " + controller.gainLife(6, game, source)+ " live"); } } diff --git a/Mage.Sets/src/mage/cards/t/TawnosUrzasApprentice.java b/Mage.Sets/src/mage/cards/t/TawnosUrzasApprentice.java index e4db5140e7..7d3c450c2b 100644 --- a/Mage.Sets/src/mage/cards/t/TawnosUrzasApprentice.java +++ b/Mage.Sets/src/mage/cards/t/TawnosUrzasApprentice.java @@ -31,7 +31,7 @@ import mage.target.common.TargetActivatedOrTriggeredAbility; */ public final class TawnosUrzasApprentice extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("activated or triggered ability you control from an artifact source"); + private static final FilterStackObject filter = new FilterStackObject("activated or triggered ability you control from an artifact source"); static { filter.add(new ArtifactSourcePredicate()); diff --git a/Mage.Sets/src/mage/cards/t/TectonicBreak.java b/Mage.Sets/src/mage/cards/t/TectonicBreak.java index c8c47de18c..14bd9c3565 100644 --- a/Mage.Sets/src/mage/cards/t/TectonicBreak.java +++ b/Mage.Sets/src/mage/cards/t/TectonicBreak.java @@ -19,7 +19,7 @@ public final class TectonicBreak extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{R}{R}"); // Each player sacrifices X lands. - this.getSpellAbility().addEffect(new SacrificeAllEffect(new ManacostVariableValue(), new FilterControlledLandPermanent("lands"))); + this.getSpellAbility().addEffect(new SacrificeAllEffect(ManacostVariableValue.instance, new FilterControlledLandPermanent("lands"))); } public TectonicBreak(final TectonicBreak card) { diff --git a/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java b/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java index 5c10121651..572aee3ed2 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java +++ b/Mage.Sets/src/mage/cards/t/TeferiHeroOfDominaria.java @@ -19,11 +19,11 @@ import mage.constants.SubType; import mage.constants.SuperType; import mage.game.Game; import mage.game.command.emblems.TeferiHeroOfDominariaEmblem; -import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetNonlandPermanent; import java.util.UUID; +import mage.game.permanent.Permanent; /** * @author LevelX2 diff --git a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java index be586c41a5..cdc5ecb0c9 100644 --- a/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java +++ b/Mage.Sets/src/mage/cards/t/TeferiMageOfZhalfir.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -17,14 +15,15 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TeferiMageOfZhalfir extends CardImpl { public TeferiMageOfZhalfir(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{U}"); addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -76,14 +75,14 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl { // in graveyard for (UUID cardId : controller.getGraveyard()) { Card card = game.getCard(cardId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { game.getState().addOtherAbility(card, FlashAbility.getInstance()); } } // on Hand for (UUID cardId : controller.getHand()) { Card card = game.getCard(cardId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { game.getState().addOtherAbility(card, FlashAbility.getInstance()); } } @@ -103,7 +102,7 @@ class TeferiMageOfZhalfirAddFlashEffect extends ContinuousEffectImpl { for (UUID commanderId : controller.getCommandersIds()) { if (game.getState().getZone(commanderId) == Zone.COMMAND) { Card card = game.getCard(commanderId); - if (card.isCreature()) { + if (card != null && card.isCreature()) { game.getState().addOtherAbility(card, FlashAbility.getInstance()); } } @@ -118,7 +117,7 @@ class TeferiMageOfZhalfirReplacementEffect extends ContinuousRuleModifyingEffect TeferiMageOfZhalfirReplacementEffect() { super(Duration.WhileOnBattlefield, Outcome.Detriment); - staticText = "Each opponent can cast spells only any time he or she could cast a sorcery"; + staticText = "Each opponent can cast spells only any time they could cast a sorcery"; } TeferiMageOfZhalfirReplacementEffect(final TeferiMageOfZhalfirReplacementEffect effect) { diff --git a/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java b/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java new file mode 100644 index 0000000000..f35b55d7b4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeferiTimeRaveler.java @@ -0,0 +1,118 @@ +package mage.cards.t; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeferiTimeRaveler extends CardImpl { + + private static final FilterCard filter = new FilterCard("sorcery spells"); + public static final FilterPermanent filter2 = new FilterPermanent("artifact, creature, or enchantment"); + + static { + filter.add(new CardTypePredicate(CardType.SORCERY)); + filter2.add(Predicates.or( + new CardTypePredicate(CardType.ARTIFACT), + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.ENCHANTMENT) + )); + } + + public TeferiTimeRaveler(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{W}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TEFERI); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Each opponent can cast spells only any time they could cast a sorcery. + this.addAbility(new SimpleStaticAbility(new TeferiTimeRavelerReplacementEffect())); + + // +1: Until your next turn, you may cast sorcery spells as though they had flash. + this.addAbility(new LoyaltyAbility(new CastAsThoughItHadFlashAllEffect( + Duration.UntilYourNextTurn, filter + ).setText("Until your next turn, you may cast sorcery spells as though they had flash"), 1)); + + // -3: Return up to one target artifact, creature, or enchantment to its owner's hand. Draw a card. + Ability ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); + ability.addEffect(new DrawCardSourceControllerEffect(1).setText("Draw a card")); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private TeferiTimeRaveler(final TeferiTimeRaveler card) { + super(card); + } + + @Override + public TeferiTimeRaveler copy() { + return new TeferiTimeRaveler(this); + } +} + +class TeferiTimeRavelerReplacementEffect extends ContinuousRuleModifyingEffectImpl { + + TeferiTimeRavelerReplacementEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + staticText = "Each opponent can cast spells only any time they could cast a sorcery"; + } + + private TeferiTimeRavelerReplacementEffect(final TeferiTimeRavelerReplacementEffect effect) { + super(effect); + } + + @Override + public String getInfoMessage(Ability source, GameEvent event, Game game) { + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject != null) { + return "You can cast spells only any time you could cast a sorcery (" + mageObject.getIdName() + ")."; + } + return null; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.CAST_SPELL; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null && controller.hasOpponent(event.getPlayerId(), game)) { + return !game.canPlaySorcery(event.getPlayerId()); + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public TeferiTimeRavelerReplacementEffect copy() { + return new TeferiTimeRavelerReplacementEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeferisMoat.java b/Mage.Sets/src/mage/cards/t/TeferisMoat.java index 0b80baa251..fbdcd065ee 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisMoat.java +++ b/Mage.Sets/src/mage/cards/t/TeferisMoat.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAbility; @@ -18,16 +16,17 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author Markedagain */ public final class TeferisMoat extends CardImpl { public TeferisMoat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}{U}"); - + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}{U}"); + // As Teferi's Moat enters the battlefield, choose a color. this.addAbility(new EntersBattlefieldAbility(new ChooseColorEffect(Outcome.Neutral))); // Creatures of the chosen color without flying can't attack you. @@ -46,15 +45,15 @@ public final class TeferisMoat extends CardImpl { class TeferisMoatRestrictionEffect extends RestrictionEffect { - TeferisMoatRestrictionEffect(){ + TeferisMoatRestrictionEffect() { super(Duration.WhileOnBattlefield, Outcome.Benefit); staticText = "Creatures of the chosen color without flying can't attack you"; } - + TeferisMoatRestrictionEffect(final TeferisMoatRestrictionEffect effect) { super(effect); } - + @Override public boolean applies(Permanent permanent, Ability source, Game game) { ObjectColor chosenColor = (ObjectColor) game.getState().getValue(source.getSourceId() + "_color"); @@ -63,12 +62,15 @@ class TeferisMoatRestrictionEffect extends RestrictionEffect { permanent.getColor(game).shares(chosenColor) && permanent.isCreature(); } - + @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } return !defenderId.equals(source.getControllerId()); } - + @Override public TeferisMoatRestrictionEffect copy() { return new TeferisMoatRestrictionEffect(this); diff --git a/Mage.Sets/src/mage/cards/t/TeferisRealm.java b/Mage.Sets/src/mage/cards/t/TeferisRealm.java index 90c2734207..121ade4895 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisRealm.java +++ b/Mage.Sets/src/mage/cards/t/TeferisRealm.java @@ -90,7 +90,7 @@ class TeferisRealmEffect extends OneShotEffect { } String choosenType = choiceImpl.getChoice(); FilterPermanent filter = new FilterPermanent(); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); switch (choosenType) { case ARTIFACT: filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/t/TeferisResponse.java b/Mage.Sets/src/mage/cards/t/TeferisResponse.java index 02d0f25d55..7c9ad386ba 100644 --- a/Mage.Sets/src/mage/cards/t/TeferisResponse.java +++ b/Mage.Sets/src/mage/cards/t/TeferisResponse.java @@ -23,7 +23,7 @@ import mage.target.TargetStackObject; */ public final class TeferisResponse extends CardImpl { - private final static FilterStackObject filter = new FilterStackObject("spell or ability an opponent controls that targets a land you control"); + private static final FilterStackObject filter = new FilterStackObject("spell or ability an opponent controls that targets a land you control"); static { filter.add(new TargetsPermanentPredicate(new FilterControlledLandPermanent())); diff --git a/Mage.Sets/src/mage/cards/t/TeferisTimeTwist.java b/Mage.Sets/src/mage/cards/t/TeferisTimeTwist.java new file mode 100644 index 0000000000..a6395dd0dd --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeferisTimeTwist.java @@ -0,0 +1,123 @@ +package mage.cards.t; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeferisTimeTwist extends CardImpl { + + public TeferisTimeTwist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Exile target permanent you control. Return that card to the battlefield under its owner's control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it. + this.getSpellAbility().addEffect(new TeferisTimeTwistEffect()); + this.getSpellAbility().addTarget(new TargetControlledPermanent()); + } + + private TeferisTimeTwist(final TeferisTimeTwist card) { + super(card); + } + + @Override + public TeferisTimeTwist copy() { + return new TeferisTimeTwist(this); + } +} + +class TeferisTimeTwistEffect extends OneShotEffect { + + TeferisTimeTwistEffect() { + super(Outcome.Benefit); + staticText = "Exile target permanent you control. Return that card to the battlefield " + + "under its owner's control at the beginning of the next end step. " + + "If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it."; + } + + private TeferisTimeTwistEffect(final TeferisTimeTwistEffect effect) { + super(effect); + } + + @Override + public TeferisTimeTwistEffect copy() { + return new TeferisTimeTwistEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + Player player = game.getPlayer(source.getControllerId()); + if (permanent == null || player == null) { + return false; + } + Effect effect = new TeferisTimeTwistReturnEffect(new MageObjectReference( + permanent.getId(), permanent.getZoneChangeCounter(game) + 1, game + )); + if (!player.moveCards(permanent, Zone.EXILED, source, game)) { + return false; + } + game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect), source); + return true; + } +} + +class TeferisTimeTwistReturnEffect extends OneShotEffect { + + private final MageObjectReference mor; + + TeferisTimeTwistReturnEffect(MageObjectReference mor) { + super(Outcome.Benefit); + staticText = "return the exiled card to the battlefield"; + this.mor = mor; + } + + private TeferisTimeTwistReturnEffect(final TeferisTimeTwistReturnEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public TeferisTimeTwistReturnEffect copy() { + return new TeferisTimeTwistReturnEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Card card = mor.getCard(game); + if (card == null) { + return false; + } + Player player = game.getPlayer(card.getOwnerId()); + if (player == null) { + return false; + } + if (!player.moveCards(card, Zone.BATTLEFIELD, source, game)) { + return true; + } + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null && permanent.isCreature()) { + // TODO: This is technically wrong as it should enter with the counters, + // however there's currently no way to know that for sure + // this is similar to the blood moon issue + permanent.addCounters(CounterType.P1P1.createInstance(), source, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TelJiladStylus.java b/Mage.Sets/src/mage/cards/t/TelJiladStylus.java index 886fa089ec..5b252c5b96 100644 --- a/Mage.Sets/src/mage/cards/t/TelJiladStylus.java +++ b/Mage.Sets/src/mage/cards/t/TelJiladStylus.java @@ -22,7 +22,7 @@ import mage.target.TargetPermanent; */ public final class TelJiladStylus extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent(); + private static final FilterPermanent filter = new FilterPermanent(); static { filter.add(new OwnerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/t/TelJiladWolf.java b/Mage.Sets/src/mage/cards/t/TelJiladWolf.java index 77a3482fb5..92ea7f3f7e 100644 --- a/Mage.Sets/src/mage/cards/t/TelJiladWolf.java +++ b/Mage.Sets/src/mage/cards/t/TelJiladWolf.java @@ -19,7 +19,7 @@ import mage.filter.predicate.mageobject.CardTypePredicate; */ public final class TelJiladWolf extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("artifact creature"); static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); diff --git a/Mage.Sets/src/mage/cards/t/Telethopter.java b/Mage.Sets/src/mage/cards/t/Telethopter.java index 4ad2e92d22..06b7bdc3bb 100644 --- a/Mage.Sets/src/mage/cards/t/Telethopter.java +++ b/Mage.Sets/src/mage/cards/t/Telethopter.java @@ -26,7 +26,7 @@ public final class Telethopter extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public Telethopter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TelimTor.java b/Mage.Sets/src/mage/cards/t/TelimTor.java index de9ec08ea0..de1e858850 100644 --- a/Mage.Sets/src/mage/cards/t/TelimTor.java +++ b/Mage.Sets/src/mage/cards/t/TelimTor.java @@ -25,7 +25,7 @@ public final class TelimTor extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("all attacking creatures with flanking"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(new AbilityPredicate(FlankingAbility.class)); } diff --git a/Mage.Sets/src/mage/cards/t/TellingTime.java b/Mage.Sets/src/mage/cards/t/TellingTime.java index 0e4c928f0a..d73b1b5918 100644 --- a/Mage.Sets/src/mage/cards/t/TellingTime.java +++ b/Mage.Sets/src/mage/cards/t/TellingTime.java @@ -66,8 +66,7 @@ class TellingTimeEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 3)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 3)); controller.lookAtCards(sourceObject.getIdName(), cards, game); if (cards.isEmpty()) { return true; diff --git a/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java b/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java index 3b1325b477..41c7f0d70c 100644 --- a/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java +++ b/Mage.Sets/src/mage/cards/t/TemmetVizierOfNaktamun.java @@ -30,7 +30,7 @@ public final class TemmetVizierOfNaktamun extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature token you control"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public TemmetVizierOfNaktamun(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/Temper.java b/Mage.Sets/src/mage/cards/t/Temper.java index 7c02c03ebe..b0bdd776b1 100644 --- a/Mage.Sets/src/mage/cards/t/Temper.java +++ b/Mage.Sets/src/mage/cards/t/Temper.java @@ -26,7 +26,7 @@ public final class Temper extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{1}{W}"); // Prevent the next X damage that would be dealt to target creature this turn. For each 1 damage prevented this way, put a +1/+1 counter on that creature. - this.getSpellAbility().addEffect(new TemperPreventDamageTargetEffect(new ManacostVariableValue(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new TemperPreventDamageTargetEffect(ManacostVariableValue.instance, Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } @@ -98,7 +98,7 @@ class TemperPreventDamageTargetEffect extends PreventionEffectImpl { Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); if (targetPermanent != null) { targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source, game); - game.informPlayers(new StringBuilder("Temper: Prevented ").append(prevented).append(" damage ").toString()); + game.informPlayers("Temper: Prevented " + prevented + " damage "); game.informPlayers("Temper: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); } } diff --git a/Mage.Sets/src/mage/cards/t/TemporalAperture.java b/Mage.Sets/src/mage/cards/t/TemporalAperture.java index 3cb817280d..1bd65e5d27 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalAperture.java +++ b/Mage.Sets/src/mage/cards/t/TemporalAperture.java @@ -52,7 +52,11 @@ class TemporalApertureEffect extends OneShotEffect { public TemporalApertureEffect() { super(Outcome.Neutral); - staticText = "Shuffle your library, then reveal the top card. Until end of turn, for as long as that card remains on top of your library, play with the top card of your library revealed and you may play that card without paying its mana cost"; + staticText = "Shuffle your library, then reveal the top card. " + + "Until end of turn, for as long as that card remains on " + + "top of your library, play with the top card of your " + + "library revealed and you may play that card without " + + "paying its mana cost"; } public TemporalApertureEffect(final TemporalApertureEffect effect) { @@ -65,9 +69,8 @@ class TemporalApertureEffect extends OneShotEffect { if (controller != null) { controller.shuffleLibrary(source, game); Card topCard = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(); if (topCard != null) { - cards.add(topCard); + Cards cards = new CardsImpl(topCard); controller.revealCards("Top card of " + controller.getName() + "'s library revealed", cards, game); ContinuousEffect effect = new TemporalApertureTopCardCastEffect(topCard); game.addEffect(effect, source); @@ -90,7 +93,8 @@ class TemporalApertureTopCardCastEffect extends AsThoughEffectImpl { public TemporalApertureTopCardCastEffect(Card card) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); this.card = card; - staticText = "Until end of turn, for as long as that card is on top of your library, you may cast it without paying its mana costs"; + staticText = "Until end of turn, for as long as that card is on top " + + "of your library, you may cast it without paying its mana costs"; } public TemporalApertureTopCardCastEffect(final TemporalApertureTopCardCastEffect effect) { @@ -119,7 +123,8 @@ class TemporalApertureTopCardCastEffect extends AsThoughEffectImpl { if (controller.getLibrary().getFromTop(game).equals(card)) { if (objectCard == card && objectCard.getSpellAbility() != null - && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(controller.getId(), game)) { + && objectCard.getSpellAbility().spellCanBeActivatedRegularlyNow(controller.getId(), game) + || objectCard.isLand()) { controller.setCastSourceIdWithAlternateMana(objectId, null, null); return true; } diff --git a/Mage.Sets/src/mage/cards/t/TemporalCascade.java b/Mage.Sets/src/mage/cards/t/TemporalCascade.java index b25096b66e..dc8e42bed9 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalCascade.java +++ b/Mage.Sets/src/mage/cards/t/TemporalCascade.java @@ -28,7 +28,7 @@ public final class TemporalCascade extends CardImpl { // or each player draws seven cards. Mode mode = new Mode(); - mode.getEffects().add(new TemporalCascadeDrawEffect()); + mode.addEffect(new TemporalCascadeDrawEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/t/TemporalExtortion.java b/Mage.Sets/src/mage/cards/t/TemporalExtortion.java index b3555349f8..c71e1b9d9e 100644 --- a/Mage.Sets/src/mage/cards/t/TemporalExtortion.java +++ b/Mage.Sets/src/mage/cards/t/TemporalExtortion.java @@ -63,8 +63,8 @@ class TemporalExtortionCounterSourceEffect extends OneShotEffect { if (sourceObject != null) { for (UUID playerId : game.getState().getPlayerList(source.getControllerId())) { Player player = game.getPlayer(playerId); - if (player.chooseUse(outcome, "Pay half your life, rounded up to counter " + sourceObject.getIdName() + '?', source, game)) { - Integer amount = (int) Math.ceil(player.getLife() / 2f); + if (player != null && player.chooseUse(outcome, "Pay half your life, rounded up to counter " + sourceObject.getIdName() + '?', source, game)) { + int amount = (int) Math.ceil(player.getLife() / 2f); player.loseLife(amount, game, false); game.informPlayers(player.getLogName() + " pays half their life, rounded up to counter " + sourceObject.getIdName() + '.'); Spell spell = game.getStack().getSpell(source.getSourceId()); diff --git a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java index 4cec552117..2560ddfc08 100644 --- a/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java +++ b/Mage.Sets/src/mage/cards/t/TemporaryInsanity.java @@ -78,10 +78,12 @@ class TargetCreatureWithPowerLessThanNumberOfCardsInYourGraveyard extends Target @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { MageObject targetSource = game.getObject(sourceId); - for (Permanent permanent: game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { - if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { - if(permanent.getPower().getValue() < game.getPlayer(sourceControllerId).getGraveyard().size()) { - return true; + if(targetSource != null) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game)) { + if (permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) { + if (permanent.getPower().getValue() < game.getPlayer(sourceControllerId).getGraveyard().size()) { + return true; + } } } } diff --git a/Mage.Sets/src/mage/cards/t/TemptWithDiscovery.java b/Mage.Sets/src/mage/cards/t/TemptWithDiscovery.java index ae5e1b3c85..f1fb697b30 100644 --- a/Mage.Sets/src/mage/cards/t/TemptWithDiscovery.java +++ b/Mage.Sets/src/mage/cards/t/TemptWithDiscovery.java @@ -66,7 +66,7 @@ class TemptWithDiscoveryEffect extends OneShotEffect { Set playersShuffle = new LinkedHashSet<>(); playersShuffle.add(controller.getId()); TargetCardInLibrary target = new TargetCardInLibrary(new FilterLandCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { @@ -82,7 +82,7 @@ class TemptWithDiscoveryEffect extends OneShotEffect { target.clearChosen(); opponentsUsedSearch++; playersShuffle.add(playerId); - if (opponent.searchLibrary(target, game)) { + if (opponent.searchLibrary(target, source, game)) { for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { @@ -95,7 +95,7 @@ class TemptWithDiscoveryEffect extends OneShotEffect { } if (opponentsUsedSearch > 0) { target = new TargetCardInLibrary(0, opponentsUsedSearch, new FilterLandCard()); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/t/TemptWithReflections.java b/Mage.Sets/src/mage/cards/t/TemptWithReflections.java index c1ea128beb..7c644e6bd0 100644 --- a/Mage.Sets/src/mage/cards/t/TemptWithReflections.java +++ b/Mage.Sets/src/mage/cards/t/TemptWithReflections.java @@ -79,7 +79,7 @@ class TemptWithReflectionsEffect extends OneShotEffect { } else { decision = " won't copy "; } - game.informPlayers((new StringBuilder(player.getLogName()).append(decision).append(permanent.getName()).toString())); + game.informPlayers((player.getLogName() + decision + permanent.getName())); } player = playerList.getNext(game); } while (!player.getId().equals(game.getActivePlayerId())); diff --git a/Mage.Sets/src/mage/cards/t/TemurBattleRage.java b/Mage.Sets/src/mage/cards/t/TemurBattleRage.java index cd51ad863e..48b5c1d021 100644 --- a/Mage.Sets/src/mage/cards/t/TemurBattleRage.java +++ b/Mage.Sets/src/mage/cards/t/TemurBattleRage.java @@ -1,11 +1,10 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.keyword.DoubleStrikeAbility; import mage.abilities.keyword.TrampleAbility; import mage.cards.CardImpl; @@ -14,27 +13,28 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class TemurBattleRage extends CardImpl { - - private final static String rule = "
    Ferocious — That creature also gains trample until end of turn if you control a creature with power 4 or greater"; + + private static final String rule = "
    Ferocious — That creature also gains trample until end of turn if you control a creature with power 4 or greater"; public TemurBattleRage(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}"); // Target creature gains double strike until end of turn. this.getSpellAbility().addEffect(new GainAbilityTargetEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - + // Ferocious That creature also gains trample until end of turn if you control a creature with power 4 or greater. this.getSpellAbility().addEffect(new ConditionalContinuousEffect( new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn), new LockedInCondition(FerociousCondition.instance), rule)); - + this.getSpellAbility().addHint(FerociousHint.instance); } public TemurBattleRage(final TemurBattleRage card) { diff --git a/Mage.Sets/src/mage/cards/t/TemurCharm.java b/Mage.Sets/src/mage/cards/t/TemurCharm.java index b0189a94e8..eed374f43d 100644 --- a/Mage.Sets/src/mage/cards/t/TemurCharm.java +++ b/Mage.Sets/src/mage/cards/t/TemurCharm.java @@ -41,7 +41,7 @@ public final class TemurCharm extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{G}{U}{R}"); // Choose one - - // Target creature you control gets +1/+1 until end of turn. That creature fights target creature you don't control. + // Target creature you control gets +1/+1 until end of turn. That creature fights target creature you don't control. Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); this.getSpellAbility().addEffect(effect); effect = new FightTargetsEffect(); @@ -51,20 +51,20 @@ public final class TemurCharm extends CardImpl { Target target = new TargetCreaturePermanent(filter); this.getSpellAbility().addTarget(target); - // Counter target spell unless its controller pays {3}. + // Counter target spell unless its controller pays {3}. Mode mode = new Mode(); - mode.getEffects().add(new CounterUnlessPaysEffect(new GenericManaCost(3))); - mode.getTargets().add(new TargetSpell()); + mode.addEffect(new CounterUnlessPaysEffect(new GenericManaCost(3))); + mode.addTarget(new TargetSpell()); this.getSpellAbility().addMode(mode); - // Creatures with power 3 or less can't block this turn. + // Creatures with power 3 or less can't block this turn. mode = new Mode(); - mode.getEffects().add(new CantBlockAllEffect(filterCantBlock, Duration.EndOfTurn)); + mode.addEffect(new CantBlockAllEffect(filterCantBlock, Duration.EndOfTurn)); this.getSpellAbility().addMode(mode); } - public TemurCharm(final TemurCharm card) { + private TemurCharm(final TemurCharm card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/t/TemurSabertooth.java b/Mage.Sets/src/mage/cards/t/TemurSabertooth.java index 7a454c9851..f4802c7144 100644 --- a/Mage.Sets/src/mage/cards/t/TemurSabertooth.java +++ b/Mage.Sets/src/mage/cards/t/TemurSabertooth.java @@ -56,7 +56,7 @@ class TemurSabertoothEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TemurSabertoothEffect() { diff --git a/Mage.Sets/src/mage/cards/t/TemurWarShaman.java b/Mage.Sets/src/mage/cards/t/TemurWarShaman.java index c95e2f8279..96577ada39 100644 --- a/Mage.Sets/src/mage/cards/t/TemurWarShaman.java +++ b/Mage.Sets/src/mage/cards/t/TemurWarShaman.java @@ -14,6 +14,7 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Outcome; import mage.constants.TargetController; +import mage.constants.Zone; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -62,7 +63,7 @@ public final class TemurWarShaman extends CardImpl { class TemurWarShamanTriggeredAbility extends TurnedFaceUpAllTriggeredAbility { public TemurWarShamanTriggeredAbility() { - super(new TemurWarShamanFightEffect(), new FilterControlledCreaturePermanent(), true); + super(Zone.BATTLEFIELD, new TemurWarShamanFightEffect(), new FilterControlledCreaturePermanent(), true, true); } public TemurWarShamanTriggeredAbility(final TemurWarShamanTriggeredAbility ability) { diff --git a/Mage.Sets/src/mage/cards/t/TendershootDryad.java b/Mage.Sets/src/mage/cards/t/TendershootDryad.java index 44e27ae9d1..455bd92a12 100644 --- a/Mage.Sets/src/mage/cards/t/TendershootDryad.java +++ b/Mage.Sets/src/mage/cards/t/TendershootDryad.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -9,21 +7,19 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.permanent.token.SaprolingToken; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TendershootDryad extends CardImpl { @@ -55,8 +51,8 @@ public final class TendershootDryad extends CardImpl { new BoostControlledEffect(2, 2, Duration.WhileOnBattlefield, filter), CitysBlessingCondition.instance, "Saprolings you control get +2/+2 as long as you have the city's blessing." - ) - )); + )) + .addHint(CitysBlessingHint.instance)); } public TendershootDryad(final TendershootDryad card) { diff --git a/Mage.Sets/src/mage/cards/t/TenthDistrictLegionnaire.java b/Mage.Sets/src/mage/cards/t/TenthDistrictLegionnaire.java new file mode 100644 index 0000000000..3f1dd36652 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TenthDistrictLegionnaire.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.HeroicAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.counters.CounterType; + +/** + * @author TheElk801 + */ +public final class TenthDistrictLegionnaire extends CardImpl { + + public TenthDistrictLegionnaire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // Whenever you cast a spell that targets Tenth District Legionnaire, put a +1/+1 counter on Tenth District Legionnaire, then scry 1. + Ability ability = new HeroicAbility(new AddCountersSourceEffect( + CounterType.P1P1.createInstance() + ), false, false); + ability.addEffect(new ScryEffect(1).setText(", then scry 1")); + this.addAbility(ability); + } + + private TenthDistrictLegionnaire(final TenthDistrictLegionnaire card) { + super(card); + } + + @Override + public TenthDistrictLegionnaire copy() { + return new TenthDistrictLegionnaire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TenthDistrictVeteran.java b/Mage.Sets/src/mage/cards/t/TenthDistrictVeteran.java new file mode 100644 index 0000000000..53b0b20d97 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TenthDistrictVeteran.java @@ -0,0 +1,54 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.UntapTargetEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class TenthDistrictVeteran extends CardImpl { + + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); + + static { + filter.add(AnotherPredicate.instance); + } + + public TenthDistrictVeteran(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Vigilance + this.addAbility(VigilanceAbility.getInstance()); + + // Whenever Tenth District Veteran attacks, untap another target creature you control. + Ability ability = new AttacksTriggeredAbility(new UntapTargetEffect(), false); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + public TenthDistrictVeteran(final TenthDistrictVeteran card) { + super(card); + } + + @Override + public TenthDistrictVeteran copy() { + return new TenthDistrictVeteran(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Terrarion.java b/Mage.Sets/src/mage/cards/t/Terrarion.java index d768113a8f..19ea4ba0bd 100644 --- a/Mage.Sets/src/mage/cards/t/Terrarion.java +++ b/Mage.Sets/src/mage/cards/t/Terrarion.java @@ -1,37 +1,38 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.PutIntoGraveFromBattlefieldSourceTriggeredAbility; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.mana.AddManaInAnyCombinationEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.mana.AddManaInAnyCombinationEffect; import mage.abilities.mana.SimpleManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Terrarion extends CardImpl { public Terrarion(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{1}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}"); // Terrarion enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); + // {2}, {T}, Sacrifice Terrarion: Add two mana in any combination of colors. Ability ability = new SimpleManaAbility(Zone.BATTLEFIELD, new AddManaInAnyCombinationEffect(2), new GenericManaCost(2)); ability.addCost(new TapSourceCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); + // When Terrarion is put into a graveyard from the battlefield, draw a card. this.addAbility(new PutIntoGraveFromBattlefieldSourceTriggeredAbility(new DrawCardSourceControllerEffect(1))); } diff --git a/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java b/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java index b13f74ec87..7c748d0d62 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialAllosaurus.java @@ -39,7 +39,7 @@ public final class TerritorialAllosaurus extends CardImpl { Ability conditionalAbility = new ConditionalInterveningIfTriggeredAbility(ability, KickedCondition.instance, "When {this} enters the battlefield, if it was kicked, it fights another target creature."); FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); conditionalAbility.addTarget(new TargetCreaturePermanent(filter)); this.addAbility(conditionalAbility); } diff --git a/Mage.Sets/src/mage/cards/t/TerritorialBoar.java b/Mage.Sets/src/mage/cards/t/TerritorialBoar.java new file mode 100644 index 0000000000..7d66f4fba4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TerritorialBoar.java @@ -0,0 +1,58 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TerritorialBoar extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("a creature with power 4 or greater"); + + static { + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public TerritorialBoar(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + + this.subtype.add(SubType.BOAR); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Whenever a creature with power 4 or greater enters the battlefield under your control, Territorial Boar gets +1/+1 and gains vigilance until end of turn. + Ability ability = new EntersBattlefieldControlledTriggeredAbility(new BoostSourceEffect( + 1, 1, Duration.EndOfTurn + ).setText("{this} gets +1/+1"), filter); + ability.addEffect(new GainAbilitySourceEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains vigilance until end of turn")); + this.addAbility(ability); + } + + private TerritorialBoar(final TerritorialBoar card) { + super(card); + } + + @Override + public TerritorialBoar copy() { + return new TerritorialBoar(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TerritorialHellkite.java b/Mage.Sets/src/mage/cards/t/TerritorialHellkite.java index e5644379bc..6dfeef8232 100644 --- a/Mage.Sets/src/mage/cards/t/TerritorialHellkite.java +++ b/Mage.Sets/src/mage/cards/t/TerritorialHellkite.java @@ -70,7 +70,7 @@ class AttackedLastCombatWatcher extends Watcher { public final Map> attackedLastCombatPlayers = new HashMap<>(); public AttackedLastCombatWatcher() { - super(AttackedLastCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AttackedLastCombatWatcher(final AttackedLastCombatWatcher watcher) { @@ -132,7 +132,7 @@ class AttackIfAbleTargetRandoOpponentSourceEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - AttackedLastCombatWatcher watcher = (AttackedLastCombatWatcher) game.getState().getWatchers().get(AttackedLastCombatWatcher.class.getSimpleName()); + AttackedLastCombatWatcher watcher = game.getState().getWatcher(AttackedLastCombatWatcher.class); if (controller != null && sourcePermanent != null && watcher != null) { List opponents = new ArrayList<>(); Map attackedPlayers = watcher.getAttackedLastCombatPlayers(source.getControllerId()); diff --git a/Mage.Sets/src/mage/cards/t/TestOfFaith.java b/Mage.Sets/src/mage/cards/t/TestOfFaith.java index 62af94a72e..4314b4dea3 100644 --- a/Mage.Sets/src/mage/cards/t/TestOfFaith.java +++ b/Mage.Sets/src/mage/cards/t/TestOfFaith.java @@ -86,7 +86,7 @@ class TestOfFaithPreventDamageTargetEffect extends PreventionEffectImpl { Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); if (targetPermanent != null) { targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source, game); - game.informPlayers(new StringBuilder("Test of Faith: Prevented ").append(prevented).append(" damage ").toString()); + game.informPlayers("Test of Faith: Prevented " + prevented + " damage "); game.informPlayers("Test of Faith: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); } } diff --git a/Mage.Sets/src/mage/cards/t/Tetravus.java b/Mage.Sets/src/mage/cards/t/Tetravus.java index ace6165e8e..c0f8b59d44 100644 --- a/Mage.Sets/src/mage/cards/t/Tetravus.java +++ b/Mage.Sets/src/mage/cards/t/Tetravus.java @@ -155,7 +155,7 @@ class TetravusAddCountersEffect extends OneShotEffect { } FilterControlledPermanent filter = new FilterControlledPermanent("tokens created with " + permanent.getName()); filter.add(new TetravusPredicate(new MageObjectReference(permanent, game))); - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); ExileTargetCost cost = new ExileTargetCost(new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true)); if (cost.pay(source, game, source.getSourceId(), player.getId(), true)) { return new AddCountersSourceEffect(CounterType.P1P1.createInstance(cost.getPermanents().size())).apply(game, source); diff --git a/Mage.Sets/src/mage/cards/t/TetsuoUmezawa.java b/Mage.Sets/src/mage/cards/t/TetsuoUmezawa.java index ae0d4677a0..70827ef6f7 100644 --- a/Mage.Sets/src/mage/cards/t/TetsuoUmezawa.java +++ b/Mage.Sets/src/mage/cards/t/TetsuoUmezawa.java @@ -34,8 +34,8 @@ public final class TetsuoUmezawa extends CardImpl { static { creatureFilter.add(Predicates.or( - new TappedPredicate(), - new BlockingPredicate())); + TappedPredicate.instance, + BlockingPredicate.instance)); } public TetsuoUmezawa(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java b/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java new file mode 100644 index 0000000000..6a86256161 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeyoTheShieldmage.java @@ -0,0 +1,45 @@ +package mage.cards.t; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.GainAbilityControllerEffect; +import mage.abilities.keyword.HexproofAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.game.permanent.token.TeyoToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeyoTheShieldmage extends CardImpl { + + public TeyoTheShieldmage(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TEYO); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // You have hexproof. + this.addAbility(new SimpleStaticAbility(new GainAbilityControllerEffect(HexproofAbility.getInstance()))); + + // -2: Create a 0/3 white Wall creature token with defender. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new TeyoToken()), -2)); + } + + private TeyoTheShieldmage(final TeyoTheShieldmage card) { + super(card); + } + + @Override + public TeyoTheShieldmage copy() { + return new TeyoTheShieldmage(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeyosLightshield.java b/Mage.Sets/src/mage/cards/t/TeyosLightshield.java new file mode 100644 index 0000000000..84221eaecc --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeyosLightshield.java @@ -0,0 +1,44 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +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 TeyosLightshield extends CardImpl { + + public TeyosLightshield(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(0); + this.toughness = new MageInt(3); + + // When Teyo's Lightshield enters the battlefield, put a +1/+1 counter on target creature you control. + Ability ability = new EntersBattlefieldTriggeredAbility( + new AddCountersTargetEffect(CounterType.P1P1.createInstance()) + ); + ability.addTarget(new TargetControlledCreaturePermanent()); + this.addAbility(ability); + } + + private TeyosLightshield(final TeyosLightshield card) { + super(card); + } + + @Override + public TeyosLightshield copy() { + return new TeyosLightshield(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java b/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java index af3b6a7f7e..a5591d5c56 100644 --- a/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java +++ b/Mage.Sets/src/mage/cards/t/TeysaEnvoyOfGhosts.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.CreateTokenEffect; @@ -14,16 +13,18 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; import mage.constants.Zone; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; import mage.game.Game; import mage.game.events.DamagedPlayerEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.game.permanent.token.TeysaEnvoyOfGhostsToken; +import mage.game.permanent.token.WhiteBlackSpiritToken; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + +import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; + /** - * * @author LevelX2 */ public final class TeysaEnvoyOfGhosts extends CardImpl { @@ -60,7 +61,7 @@ class TeysaEnvoyOfGhostsTriggeredAbility extends TriggeredAbilityImpl { public TeysaEnvoyOfGhostsTriggeredAbility() { super(Zone.BATTLEFIELD, new DestroyTargetEffect()); - this.addEffect(new CreateTokenEffect(new TeysaEnvoyOfGhostsToken(), 1)); + this.addEffect(new CreateTokenEffect(new WhiteBlackSpiritToken(), 1)); } diff --git a/Mage.Sets/src/mage/cards/t/TeysaKarlov.java b/Mage.Sets/src/mage/cards/t/TeysaKarlov.java new file mode 100644 index 0000000000..4563c6a515 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TeysaKarlov.java @@ -0,0 +1,108 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.NumberOfTriggersEvent; +import mage.game.events.ZoneChangeEvent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TeysaKarlov extends CardImpl { + + public TeysaKarlov(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(4); + + // If a creature dying causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time. + this.addAbility(new SimpleStaticAbility(new TeysaKarlovEffect())); + + // Creature tokens you control have vigilance and lifelink. + Ability ability = new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), + Duration.WhileOnBattlefield, + StaticFilters.FILTER_CREATURE_TOKENS + ).setText("creature tokens you control have vigilance") + ); + ability.addEffect(new GainAbilityControlledEffect( + LifelinkAbility.getInstance(), + Duration.WhileOnBattlefield, + StaticFilters.FILTER_CREATURE_TOKENS + ).setText("and lifelink")); + this.addAbility(ability); + } + + private TeysaKarlov(final TeysaKarlov card) { + super(card); + } + + @Override + public TeysaKarlov copy() { + return new TeysaKarlov(this); + } +} + +class TeysaKarlovEffect extends ReplacementEffectImpl { + + TeysaKarlovEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a creature dying causes a triggered ability of a permanent you control to trigger, " + + "that ability triggers an additional time."; + } + + private TeysaKarlovEffect(final TeysaKarlovEffect effect) { + super(effect); + } + + @Override + public TeysaKarlovEffect copy() { + return new TeysaKarlovEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.NUMBER_OF_TRIGGERS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (event instanceof NumberOfTriggersEvent) { + NumberOfTriggersEvent numberOfTriggersEvent = (NumberOfTriggersEvent) event; + if (source.isControlledBy(event.getPlayerId()) + && game.getPermanentOrLKIBattlefield(numberOfTriggersEvent.getSourceId()) != null + && numberOfTriggersEvent.getSourceEvent() instanceof ZoneChangeEvent) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) numberOfTriggersEvent.getSourceEvent(); + return zEvent.isDiesEvent() + && zEvent.getTarget() != null + && zEvent.getTarget().isCreature(); + } + } + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + event.setAmount(event.getAmount() + 1); + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TeysaOrzhovScion.java b/Mage.Sets/src/mage/cards/t/TeysaOrzhovScion.java index ecf320e2bb..4a880fc119 100644 --- a/Mage.Sets/src/mage/cards/t/TeysaOrzhovScion.java +++ b/Mage.Sets/src/mage/cards/t/TeysaOrzhovScion.java @@ -32,12 +32,12 @@ import mage.target.common.TargetCreaturePermanent; */ public final class TeysaOrzhovScion extends CardImpl { - private final static FilterControlledCreaturePermanent filterWhite = new FilterControlledCreaturePermanent("three white creatures"); - private final static FilterCreaturePermanent filterBlack = new FilterCreaturePermanent("another black creature you control"); + private static final FilterControlledCreaturePermanent filterWhite = new FilterControlledCreaturePermanent("three white creatures"); + private static final FilterCreaturePermanent filterBlack = new FilterCreaturePermanent("another black creature you control"); static { filterWhite.add(new ColorPredicate(ObjectColor.WHITE)); filterBlack.add(new ColorPredicate(ObjectColor.BLACK)); - filterBlack.add(new AnotherPredicate()); + filterBlack.add(AnotherPredicate.instance); filterBlack.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java new file mode 100644 index 0000000000..5171330f06 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TezzeretMasterOfTheBridge.java @@ -0,0 +1,142 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledSpellsEffect; +import mage.abilities.keyword.AffinityForArtifactsAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.common.FilterArtifactCard; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TezzeretMasterOfTheBridge extends CardImpl { + + private static final FilterSpell filter = new FilterSpell("creature and planeswalker spells"); + + static { + filter.add(Predicates.or( + new CardTypePredicate(CardType.PLANESWALKER), + new CardTypePredicate(CardType.CREATURE) + )); + } + + private static final FilterCard filter2 = new FilterArtifactCard("artifact card from your graveyard"); + + public TezzeretMasterOfTheBridge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{4}{U}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TEZZERET); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Creature and planeswalker spells you cast have affinity for artifacts. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledSpellsEffect( + new AffinityForArtifactsAbility(), filter + ))); + + // +2: Tezzeret, Master of the Bridge deals X damage to each opponent, where X is the number of artifacts you control. You gain X life. + this.addAbility(new LoyaltyAbility(new TezzeretMasterOfTheBridgeEffect(), 2)); + + // -3: Return target artifact card from your graveyard to your hand. + Ability ability = new LoyaltyAbility(new ReturnToHandTargetEffect(), -3); + ability.addTarget(new TargetCardInYourGraveyard(filter2)); + this.addAbility(ability); + + // -8: Exile the top ten cards of your library. Put all artifact cards from among them onto the battlefield. + this.addAbility(new LoyaltyAbility(new TezzeretMasterOfTheBridgeEffect2(), -8)); + } + + private TezzeretMasterOfTheBridge(final TezzeretMasterOfTheBridge card) { + super(card); + } + + @Override + public TezzeretMasterOfTheBridge copy() { + return new TezzeretMasterOfTheBridge(this); + } +} + +class TezzeretMasterOfTheBridgeEffect extends OneShotEffect { + + TezzeretMasterOfTheBridgeEffect() { + super(Outcome.Benefit); + staticText = "{this} deals X damage to each opponent, " + + "where X is the number of artifacts you control. You gain X life"; + } + + private TezzeretMasterOfTheBridgeEffect(final TezzeretMasterOfTheBridgeEffect effect) { + super(effect); + } + + @Override + public TezzeretMasterOfTheBridgeEffect copy() { + return new TezzeretMasterOfTheBridgeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int artifactCount = new PermanentsOnBattlefieldCount( + StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT + ).calculate(game, source, this); + new DamagePlayersEffect(artifactCount, TargetController.OPPONENT).apply(game, source); + player.gainLife(artifactCount, game, source); + return true; + } +} + +class TezzeretMasterOfTheBridgeEffect2 extends OneShotEffect { + + TezzeretMasterOfTheBridgeEffect2() { + super(Outcome.Benefit); + staticText = "Exile the top ten cards of your library. " + + "Put all artifact cards from among them onto the battlefield."; + } + + private TezzeretMasterOfTheBridgeEffect2(final TezzeretMasterOfTheBridgeEffect2 effect) { + super(effect); + } + + @Override + public TezzeretMasterOfTheBridgeEffect2 copy() { + return new TezzeretMasterOfTheBridgeEffect2(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, 10)); + player.moveCards(cards, Zone.EXILED, source, game); + Cards cards2 = new CardsImpl(); + for (Card card : cards.getCards(game)) { + if (card.isArtifact()) { + cards2.add(card); + } + } + return player.moveCards(cards2, Zone.BATTLEFIELD, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java index c9f2ff0ed6..bf93fc6fb6 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretTheSeeker.java @@ -91,7 +91,7 @@ class TezzeretTheSeekerEffect2 extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, cmc + 1)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java b/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java index f1fc8b79ff..01e5a3be62 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretsBetrayal.java @@ -17,7 +17,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class TezzeretsBetrayal extends CardImpl { - private final static FilterCard filter = new FilterCard("Tezzeret, Master of Metal"); + private static final FilterCard filter = new FilterCard("Tezzeret, Master of Metal"); static { filter.add(new NamePredicate("Tezzeret, Master of Metal")); diff --git a/Mage.Sets/src/mage/cards/t/TezzeretsGambit.java b/Mage.Sets/src/mage/cards/t/TezzeretsGambit.java index d616e448d7..c481b3bc77 100644 --- a/Mage.Sets/src/mage/cards/t/TezzeretsGambit.java +++ b/Mage.Sets/src/mage/cards/t/TezzeretsGambit.java @@ -1,24 +1,24 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** - * * @author North */ public final class TezzeretsGambit extends CardImpl { public TezzeretsGambit(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{U/P}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{U/P}"); + // Draw two cards, then proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(2)); - this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy(", then")); } public TezzeretsGambit(final TezzeretsGambit card) { diff --git a/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java b/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java index e5777b82a6..e7e02a1e2c 100644 --- a/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java +++ b/Mage.Sets/src/mage/cards/t/ThadaAdelAcquisitor.java @@ -72,7 +72,7 @@ class ThadaAdelAcquisitorEffect extends OneShotEffect { return false; } TargetCardInLibrary target = new TargetCardInLibrary(new FilterArtifactCard()); - if (controller.searchLibrary(target, game, damagedPlayer.getId())) { + if (controller.searchLibrary(target, source, game, damagedPlayer.getId())) { if (!target.getTargets().isEmpty()) { Card card = damagedPlayer.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java b/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java index 2187bbb32c..27a8ccc862 100644 --- a/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java +++ b/Mage.Sets/src/mage/cards/t/ThaliasLieutenant.java @@ -25,7 +25,7 @@ public final class ThaliasLieutenant extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("each other Human you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.HUMAN)); } diff --git a/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java b/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java index 2849479564..cc66e70e13 100644 --- a/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java +++ b/Mage.Sets/src/mage/cards/t/ThatWhichWasTaken.java @@ -35,7 +35,7 @@ public final class ThatWhichWasTaken extends CardImpl { private static final FilterPermanent filterIndestructible = new FilterPermanent("Each permanent with a divinity counter on it"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filterIndestructible.add(new CounterPredicate(CounterType.DIVINITY)); } diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java b/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java index 6c6ee7f1a9..4362c26c53 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfEndor.java @@ -32,7 +32,7 @@ public final class TheBattleOfEndor extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{X}{G}{G}{G}"); // Create X 1/1 green Ewok creature tokens. - this.getSpellAbility().addEffect(new CreateTokenEffect(new EwokToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new EwokToken(), ManacostVariableValue.instance)); // Put X +1/+1 counters on each creature you control. this.getSpellAbility().addEffect(new TheBattleOfEndorEffect()); diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfGeonosis.java b/Mage.Sets/src/mage/cards/t/TheBattleOfGeonosis.java index 5c8f41b4c3..7207f52b1a 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfGeonosis.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfGeonosis.java @@ -27,15 +27,15 @@ public final class TheBattleOfGeonosis extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{R}{R}"); // The Battle of Geonosis deals X + 1 damage to each opponent and each creature your opponents control. - Effect effect = new DamagePlayersEffect(Outcome.Damage, new IntPlusDynamicValue(1, new ManacostVariableValue()), TargetController.OPPONENT); + Effect effect = new DamagePlayersEffect(Outcome.Damage, new IntPlusDynamicValue(1, ManacostVariableValue.instance), TargetController.OPPONENT); effect.setText("The Battle of Geonosis deals X plus 1 damage to each opponent"); this.getSpellAbility().addEffect(effect); - effect = new DamageAllEffect(new IntPlusDynamicValue(1, new ManacostVariableValue()), new FilterOpponentsCreaturePermanent()); + effect = new DamageAllEffect(new IntPlusDynamicValue(1, ManacostVariableValue.instance), new FilterOpponentsCreaturePermanent()); effect.setText("and each creature your opponents control"); this.getSpellAbility().addEffect(effect); // Creatures you control get +X/+0 until end of turn. - this.getSpellAbility().addEffect(new BoostControlledEffect(new ManacostVariableValue(), new StaticValue(0), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostControlledEffect(ManacostVariableValue.instance, new StaticValue(0), Duration.EndOfTurn)); } diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfHoth.java b/Mage.Sets/src/mage/cards/t/TheBattleOfHoth.java index 3ce64d602b..dda5b9c9b6 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfHoth.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfHoth.java @@ -19,7 +19,7 @@ public final class TheBattleOfHoth extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{W}{W}{W}"); // Create X 5/5 white artifact AT-AT creature tokens wiht "When this creature dies, create two 1/1 white Trooper creature tokens." - this.getSpellAbility().addEffect(new CreateTokenEffect(new ATATToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new ATATToken(), ManacostVariableValue.instance)); } public TheBattleOfHoth(final TheBattleOfHoth card) { diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfNaboo.java b/Mage.Sets/src/mage/cards/t/TheBattleOfNaboo.java index 6945d84d35..75e60e1bf5 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfNaboo.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfNaboo.java @@ -1,7 +1,6 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; @@ -13,28 +12,24 @@ import mage.constants.Outcome; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author Styxo */ public final class TheBattleOfNaboo extends CardImpl { public TheBattleOfNaboo(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{X}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{X}{U}{U}"); // Return X target creatures to their owner's hands. Draw twice that many cards. Effect effect = new ReturnToHandTargetEffect(); effect.setText("Return X target creatures to their owner's hands"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addEffect(new TheBattleOfNabooEffect()); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + this.getSpellAbility().setTargetAdjuster(TheBattleOfNabooAdjuster.instance); } public TheBattleOfNaboo(final TheBattleOfNaboo card) { @@ -47,6 +42,16 @@ public final class TheBattleOfNaboo extends CardImpl { } } +enum TheBattleOfNabooAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} + class TheBattleOfNabooEffect extends OneShotEffect { public TheBattleOfNabooEffect() { @@ -72,9 +77,7 @@ class TheBattleOfNabooEffect extends OneShotEffect { player.drawCards(2 * x, game); } return true; - } return false; } - } diff --git a/Mage.Sets/src/mage/cards/t/TheBattleOfYavin.java b/Mage.Sets/src/mage/cards/t/TheBattleOfYavin.java index 5377a77dc8..90ec0851cd 100644 --- a/Mage.Sets/src/mage/cards/t/TheBattleOfYavin.java +++ b/Mage.Sets/src/mage/cards/t/TheBattleOfYavin.java @@ -65,7 +65,7 @@ class TheBattleOfYavinEffect extends OneShotEffect { return false; } - int amount = (new ManacostVariableValue()).calculate(game, source, this); + int amount = (ManacostVariableValue.instance).calculate(game, source, this); if (amount > 0) { LinkedList sacrifices = new LinkedList<>(); diff --git a/Mage.Sets/src/mage/cards/t/TheBigIdea.java b/Mage.Sets/src/mage/cards/t/TheBigIdea.java index 6bb1285d16..8a3a85ea19 100644 --- a/Mage.Sets/src/mage/cards/t/TheBigIdea.java +++ b/Mage.Sets/src/mage/cards/t/TheBigIdea.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -13,12 +11,7 @@ import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.CreateTokenEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TappedPredicate; @@ -29,8 +22,9 @@ import mage.game.permanent.token.BrainiacToken; import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; +import java.util.UUID; + /** - * * @author spjspj */ public final class TheBigIdea extends CardImpl { @@ -38,7 +32,7 @@ public final class TheBigIdea extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(SubType.BRAINIAC, "Brainiac creatures"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public TheBigIdea(UUID ownerId, CardSetInfo setInfo) { @@ -72,7 +66,7 @@ public final class TheBigIdea extends CardImpl { class TheBigIdeaReplacementEffect extends ReplacementEffectImpl { TheBigIdeaReplacementEffect() { - super(Duration.EndOfTurn, Outcome.Damage); + super(Duration.OneUse, Outcome.Damage); staticText = "The next time you would roll a six-sided die, instead roll two six-sided dice and use the total of those results"; } diff --git a/Mage.Sets/src/mage/cards/t/TheChainVeil.java b/Mage.Sets/src/mage/cards/t/TheChainVeil.java index 21b0484c36..972b89e991 100644 --- a/Mage.Sets/src/mage/cards/t/TheChainVeil.java +++ b/Mage.Sets/src/mage/cards/t/TheChainVeil.java @@ -60,7 +60,7 @@ class ActivatedLoyaltyAbilityWatcher extends Watcher { private final Set playerIds = new HashSet<>(); public ActivatedLoyaltyAbilityWatcher() { - super(ActivatedLoyaltyAbilityWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ActivatedLoyaltyAbilityWatcher(final ActivatedLoyaltyAbilityWatcher watcher) { @@ -139,7 +139,7 @@ enum TheChainVeilCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - ActivatedLoyaltyAbilityWatcher watcher = (ActivatedLoyaltyAbilityWatcher) game.getState().getWatchers().get(ActivatedLoyaltyAbilityWatcher.class.getSimpleName()); + ActivatedLoyaltyAbilityWatcher watcher = game.getState().getWatcher(ActivatedLoyaltyAbilityWatcher.class); if (watcher != null) { if (!watcher.activatedLoyaltyAbility(source.getControllerId())) { return true; diff --git a/Mage.Sets/src/mage/cards/t/TheCrowdGoesWild.java b/Mage.Sets/src/mage/cards/t/TheCrowdGoesWild.java index 6a8cc6ccb9..52ad0363c3 100644 --- a/Mage.Sets/src/mage/cards/t/TheCrowdGoesWild.java +++ b/Mage.Sets/src/mage/cards/t/TheCrowdGoesWild.java @@ -1,9 +1,7 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.abilities.keyword.AssistAbility; @@ -17,9 +15,11 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.CounterPredicate; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class TheCrowdGoesWild extends CardImpl { @@ -41,6 +41,7 @@ public final class TheCrowdGoesWild extends CardImpl { .setText("Support X (Put a +1/+1 counter on each of up to X target creatures.)
    ") ); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().setTargetAdjuster(TheCrowdGoesWildAdjuster.instance); // Each creature with a +1/+1 counter on it gains trample until end of turn. this.getSpellAbility().addEffect(new GainAbilityAllEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, filter)); @@ -50,17 +51,18 @@ public final class TheCrowdGoesWild extends CardImpl { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetCreaturePermanent(0, xValue)); - } - } - @Override public TheCrowdGoesWild copy() { return new TheCrowdGoesWild(this); } } + +enum TheCrowdGoesWildAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(0, ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TheElderspell.java b/Mage.Sets/src/mage/cards/t/TheElderspell.java new file mode 100644 index 0000000000..0251cb9377 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheElderspell.java @@ -0,0 +1,87 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledPlaneswalkerPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheElderspell extends CardImpl { + + public TheElderspell(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{B}{B}"); + + // Destroy any number of target planeswalkers. Choose a planeswalker you control. Put two loyalty counters on it for each planeswalker destroyed this way. + this.getSpellAbility().addEffect(new TheElderspellEffect()); + this.getSpellAbility().addTarget(new TargetPermanent( + 0, Integer.MAX_VALUE, StaticFilters.FILTER_PERMANENT_PLANESWALKERS, false + )); + } + + private TheElderspell(final TheElderspell card) { + super(card); + } + + @Override + public TheElderspell copy() { + return new TheElderspell(this); + } +} + +class TheElderspellEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPlaneswalkerPermanent(); + + TheElderspellEffect() { + super(Outcome.Benefit); + staticText = "Destroy any number of target planeswalkers. Choose a planeswalker you control. " + + "Put two loyalty counters on it for each planeswalker destroyed this way."; + } + + private TheElderspellEffect(final TheElderspellEffect effect) { + super(effect); + } + + @Override + public TheElderspellEffect copy() { + return new TheElderspellEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int count = 0; + for (UUID permId : source.getTargets().get(0).getTargets()) { + Permanent permanent = game.getPermanent(permId); + if (permanent != null && permanent.destroy(source.getSourceId(), game, false)) { + count++; + } + } + TargetPermanent targetPermanent = new TargetPermanent(filter); + if (!player.choose(outcome, targetPermanent, source.getSourceId(), game)) { + return false; + } + Permanent permanent = game.getPermanent(targetPermanent.getFirstTarget()); + if (permanent == null) { + return false; + } + return permanent.addCounters(CounterType.LOYALTY.createInstance(2 * count), source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TheEldestReborn.java b/Mage.Sets/src/mage/cards/t/TheEldestReborn.java index 666e52d657..c8120d042e 100644 --- a/Mage.Sets/src/mage/cards/t/TheEldestReborn.java +++ b/Mage.Sets/src/mage/cards/t/TheEldestReborn.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -13,7 +12,6 @@ import mage.constants.SagaChapter; import mage.constants.SubType; import mage.constants.TargetController; import mage.filter.FilterCard; -import mage.filter.StaticFilters; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -35,11 +33,12 @@ public final class TheEldestReborn extends CardImpl { } private static final FilterControlledPermanent filterSacrifice = new FilterControlledPermanent("creature or planeswalker"); + static { filterSacrifice.add(Predicates.or( - new CardTypePredicate(CardType.CREATURE), - new CardTypePredicate(CardType.PLANESWALKER) - )); + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER) + )); } diff --git a/Mage.Sets/src/mage/cards/t/TheFallen.java b/Mage.Sets/src/mage/cards/t/TheFallen.java index 8676d61c57..1696dd0d6d 100644 --- a/Mage.Sets/src/mage/cards/t/TheFallen.java +++ b/Mage.Sets/src/mage/cards/t/TheFallen.java @@ -62,7 +62,7 @@ class TheFallenEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - TheFallenWatcher watcher = (TheFallenWatcher) game.getState().getWatchers().get(TheFallenWatcher.class.getSimpleName()); + TheFallenWatcher watcher = game.getState().getWatcher(TheFallenWatcher.class); if (watcher != null && watcher.getPlayersAndWalkersDealtDamageThisGame(source.getSourceId()) != null) { for (UUID playerId : watcher.getPlayersAndWalkersDealtDamageThisGame(source.getSourceId())) { if (!source.isControlledBy(playerId)) { @@ -80,7 +80,7 @@ class TheFallenWatcher extends Watcher { private Map> playersAndWalkersDealtDamageThisGame = new HashMap<>(); // Map> public TheFallenWatcher() { - super(TheFallenWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public TheFallenWatcher(final TheFallenWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TheFallenApart.java b/Mage.Sets/src/mage/cards/t/TheFallenApart.java index 66f887455a..1159b50b5a 100644 --- a/Mage.Sets/src/mage/cards/t/TheFallenApart.java +++ b/Mage.Sets/src/mage/cards/t/TheFallenApart.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -12,18 +10,15 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author L_J */ public final class TheFallenApart extends CardImpl { @@ -162,7 +157,7 @@ class TheFallenApartRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { return (Integer) game.getState().getValue(mageObject.getId() + "_arms") > 0; @@ -171,7 +166,7 @@ class TheFallenApartRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { MageObject mageObject = game.getObject(source.getSourceId()); if (mageObject != null) { return (Integer) game.getState().getValue(mageObject.getId() + "_legs") > 0; diff --git a/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java b/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java new file mode 100644 index 0000000000..d759f6d49c --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheHauntOfHightower.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.common.PutCardIntoGraveFromAnywhereAllTriggeredAbility; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheHauntOfHightower extends CardImpl { + + public TheHauntOfHightower(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // Whenever The Haunt of Hightower attacks, defending player discards a card. + this.addAbility(new AttacksTriggeredAbility( + new DiscardTargetEffect(1), false, + "Whenever {this} attacks, defending player discards a card", SetTargetPointer.PLAYER + )); + + // Whenever a card is put into an opponent's graveyard from anywhere, put a +1/+1 counter on The Haunt of Hightower. + this.addAbility(new PutCardIntoGraveFromAnywhereAllTriggeredAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance()), + false, TargetController.OPPONENT + )); + } + + public TheHauntOfHightower(final TheHauntOfHightower card) { + super(card); + } + + @Override + public TheHauntOfHightower copy() { + return new TheHauntOfHightower(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java b/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java index e30d3e8cda..888e1b8beb 100644 --- a/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java +++ b/Mage.Sets/src/mage/cards/t/TheMimeoplasm.java @@ -70,12 +70,14 @@ class TheMimeoplasmEffect extends OneShotEffect { if (new CardsInAllGraveyardsCount(new FilterCreatureCard()).calculate(game, source, this) >= 2) { if (controller.chooseUse(Outcome.Benefit, "Do you want to exile two creature cards from graveyards?", source, game)) { TargetCardInGraveyard targetCopy = new TargetCardInGraveyard(new FilterCreatureCard("creature card to become a copy of")); + targetCopy.setNotTarget(true); if (controller.choose(Outcome.Copy, targetCopy, source.getSourceId(), game)) { Card cardToCopy = game.getCard(targetCopy.getFirstTarget()); if (cardToCopy != null) { FilterCreatureCard filter = new FilterCreatureCard("creature card to determine amount of additional +1/+1 counters"); filter.add(Predicates.not(new CardIdPredicate(cardToCopy.getId()))); TargetCardInGraveyard targetCounters = new TargetCardInGraveyard(filter); + targetCounters.setNotTarget(true); if (controller.choose(Outcome.Copy, targetCounters, source.getSourceId(), game)) { Card cardForCounters = game.getCard(targetCounters.getFirstTarget()); if (cardForCounters != null) { diff --git a/Mage.Sets/src/mage/cards/t/TheRack.java b/Mage.Sets/src/mage/cards/t/TheRack.java index b6e85eb33b..6b5ea4a93d 100644 --- a/Mage.Sets/src/mage/cards/t/TheRack.java +++ b/Mage.Sets/src/mage/cards/t/TheRack.java @@ -64,7 +64,7 @@ class TheRackTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getPlayerId().equals((UUID) game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); + return event.getPlayerId().equals(game.getState().getValue(this.getSourceId().toString() + ChooseOpponentEffect.VALUE_KEY)); } @Override diff --git a/Mage.Sets/src/mage/cards/t/TheScorpionGod.java b/Mage.Sets/src/mage/cards/t/TheScorpionGod.java index 5a8d67ad42..b973513f0e 100644 --- a/Mage.Sets/src/mage/cards/t/TheScorpionGod.java +++ b/Mage.Sets/src/mage/cards/t/TheScorpionGod.java @@ -43,7 +43,7 @@ public final class TheScorpionGod extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TheScorpionGod(UUID ownerId, CardSetInfo setInfo) { @@ -99,7 +99,7 @@ class TheScorpionGodTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = game.getPermanentOrLKIBattlefield(zEvent.getTargetId()); if (permanent != null && permanent.isCreature() diff --git a/Mage.Sets/src/mage/cards/t/TheTabernacleAtPendrellVale.java b/Mage.Sets/src/mage/cards/t/TheTabernacleAtPendrellVale.java index 62f6fcf3a2..161c21967e 100644 --- a/Mage.Sets/src/mage/cards/t/TheTabernacleAtPendrellVale.java +++ b/Mage.Sets/src/mage/cards/t/TheTabernacleAtPendrellVale.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -8,12 +7,11 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -29,14 +27,10 @@ public final class TheTabernacleAtPendrellVale extends CardImpl { addSuperType(SuperType.LEGENDARY); // All creatures have "At the beginning of your upkeep, destroy this creature unless you pay {1}." - Ability ability = new BeginningOfUpkeepTriggeredAbility(new DestroySourceUnlessPaysEffect(new ManaCostsImpl("{1}")), TargetController.YOU, false); - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new GainAbilityAllEffect( - ability, - Duration.WhileOnBattlefield, - new FilterCreaturePermanent("All creatures") - ) - )); + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new TheTabernacleAtPendrellValeEffect()) + ); } public TheTabernacleAtPendrellVale(final TheTabernacleAtPendrellVale card) { @@ -49,6 +43,59 @@ public final class TheTabernacleAtPendrellVale extends CardImpl { } } +class TheTabernacleAtPendrellValeEffect extends ContinuousEffectImpl { + + Ability ability = new BeginningOfUpkeepTriggeredAbility( + new DestroySourceUnlessPaysEffect( + new ManaCostsImpl("{1}")), + TargetController.YOU, + false); + + public TheTabernacleAtPendrellValeEffect() { + super(Duration.WhileOnBattlefield, Outcome.AddAbility); + ability = ability.copy(); + this.ability.newId(); + staticText = "All creatures have \"At the beginning of your upkeep, destroy this creature unless you pay {1}"; + } + + public TheTabernacleAtPendrellValeEffect(final TheTabernacleAtPendrellValeEffect effect) { + super(effect); + this.ability = effect.ability.copy(); + } + + @Override + public TheTabernacleAtPendrellValeEffect copy() { + return new TheTabernacleAtPendrellValeEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(CardType.CREATURE)) { + if (permanent != null) { + switch (layer) { + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA + && !permanent.getAbilities().contains(ability)) { + permanent.addAbility(ability, source.getSourceId(), game); + } + break; + } + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.AbilityAddingRemovingEffects_6; + } +} + class DestroySourceUnlessPaysEffect extends OneShotEffect { protected Cost cost; @@ -67,7 +114,9 @@ class DestroySourceUnlessPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); - if (player != null && permanent != null && source.getSourceObjectZoneChangeCounter() == permanent.getZoneChangeCounter(game)) { + if (player != null + && permanent != null + && source.getSourceObjectZoneChangeCounter() == permanent.getZoneChangeCounter(game)) { if (player.chooseUse(Outcome.Benefit, "Pay " + cost.getText() + '?', source, game)) { cost.clearPaid(); if (cost.pay(source, game, source.getSourceId(), source.getControllerId(), false, null)) { diff --git a/Mage.Sets/src/mage/cards/t/TheWanderer.java b/Mage.Sets/src/mage/cards/t/TheWanderer.java new file mode 100644 index 0000000000..4bdfe787fc --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheWanderer.java @@ -0,0 +1,66 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.PreventAllNonCombatDamageToAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheWanderer extends CardImpl { + + private static final FilterPermanent filter + = new FilterControlledPermanent("other permanents you control"); + private static final FilterPermanent filter2 + = new FilterCreaturePermanent("creature with power 4 or greater"); + + static { + filter.add(AnotherPredicate.instance); + filter2.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public TheWanderer(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{3}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Prevent all noncombat damage that would be dealt to you and other permanents you control. + this.addAbility(new SimpleStaticAbility( + new PreventAllNonCombatDamageToAllEffect( + Duration.WhileOnBattlefield, filter, true + ) + )); + + // -2: Exile target creature with power 4 or greater. + Ability ability = new LoyaltyAbility(new ExileTargetEffect(), -2); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private TheWanderer(final TheWanderer card) { + super(card); + } + + @Override + public TheWanderer copy() { + return new TheWanderer(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java b/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java new file mode 100644 index 0000000000..b046462d3f --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java @@ -0,0 +1,127 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.ExileZone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponentOrPlaneswalker; +import mage.util.CardUtil; +import mage.watchers.common.PlayerLostLifeWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TheaterOfHorrors extends CardImpl { + + public TheaterOfHorrors(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{R}"); + + // At the beginning of your upkeep, exile the top card of your library. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new TheaterOfHorrorsExileEffect(), + TargetController.YOU, false + )); + + // During your turn, if an opponent lost life this turn, you may play cards exiled with Theater of Horrors. + this.addAbility(new SimpleStaticAbility(new TheaterOfHorrorsCastEffect())); + + // {3}{R}: Theater of Horrors deals 1 damage to target opponent or planeswalker. + Ability ability = new SimpleActivatedAbility( + new DamageTargetEffect(1), + new ManaCostsImpl("{3}{R}") + ); + ability.addTarget(new TargetOpponentOrPlaneswalker()); + this.addAbility(ability); + } + + private TheaterOfHorrors(final TheaterOfHorrors card) { + super(card); + } + + @Override + public TheaterOfHorrors copy() { + return new TheaterOfHorrors(this); + } +} + +class TheaterOfHorrorsExileEffect extends OneShotEffect { + + TheaterOfHorrorsExileEffect() { + super(Outcome.Benefit); + staticText = "exile the top card of your library."; + } + + private TheaterOfHorrorsExileEffect(final TheaterOfHorrorsExileEffect effect) { + super(effect); + } + + @Override + public TheaterOfHorrorsExileEffect copy() { + return new TheaterOfHorrorsExileEffect(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; + } + return player.moveCardsToExile( + card, source, game, true, CardUtil.getCardExileZoneId(game, source), + CardUtil.createObjectRealtedWindowTitle(source, game, null) + ); + } +} + +class TheaterOfHorrorsCastEffect extends AsThoughEffectImpl { + + TheaterOfHorrorsCastEffect() { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit); + staticText = "During your turn, if an opponent lost life this turn, " + + "you may play cards exiled with {this}"; + } + + private TheaterOfHorrorsCastEffect(final TheaterOfHorrorsCastEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public TheaterOfHorrorsCastEffect copy() { + return new TheaterOfHorrorsCastEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); + if (watcher != null && game.isActivePlayer(source.getControllerId()) + && watcher.getAllOppLifeLost(source.getControllerId(), game) > 0 + && affectedControllerId.equals(source.getControllerId()) + && game.getState().getZone(objectId) == Zone.EXILED) { + ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source)); + return zone != null && zone.contains(objectId); + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TheftOfDreams.java b/Mage.Sets/src/mage/cards/t/TheftOfDreams.java index 3b7cf159f2..e226a53c67 100644 --- a/Mage.Sets/src/mage/cards/t/TheftOfDreams.java +++ b/Mage.Sets/src/mage/cards/t/TheftOfDreams.java @@ -61,7 +61,7 @@ class TheftOfDreamsEffect extends OneShotEffect { Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (opponent != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ControllerIdPredicate(opponent.getId())); return new DrawCardSourceControllerEffect(game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game)).apply(game, source); } diff --git a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java index 9aeaf81971..07ebd1cf24 100644 --- a/Mage.Sets/src/mage/cards/t/ThelonsCurse.java +++ b/Mage.Sets/src/mage/cards/t/ThelonsCurse.java @@ -64,7 +64,7 @@ class ThelonsCurseEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("tapped blue creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(new ColorPredicate(ObjectColor.BLUE)); } diff --git a/Mage.Sets/src/mage/cards/t/ThermalFlux.java b/Mage.Sets/src/mage/cards/t/ThermalFlux.java index 718cd1b439..f9c1c8e3e5 100644 --- a/Mage.Sets/src/mage/cards/t/ThermalFlux.java +++ b/Mage.Sets/src/mage/cards/t/ThermalFlux.java @@ -50,9 +50,9 @@ public final class ThermalFlux extends CardImpl { // Target snow permanent isn't snow until end of turn. // Draw a card at the beginning of the next turn's upkeep. Mode mode = new Mode(); - mode.getTargets().add(new TargetPermanent(filterSnow)); - mode.getEffects().add(new ThermalFluxEffect(false)); - mode.getEffects().add(new CreateDelayedTriggeredAbilityEffect( + mode.addTarget(new TargetPermanent(filterSnow)); + mode.addEffect(new ThermalFluxEffect(false)); + mode.addEffect(new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new DrawCardSourceControllerEffect(1)), false)); this.getSpellAbility().addMode(mode); diff --git a/Mage.Sets/src/mage/cards/t/ThiefOfSanity.java b/Mage.Sets/src/mage/cards/t/ThiefOfSanity.java index f0db706fc4..818970680f 100644 --- a/Mage.Sets/src/mage/cards/t/ThiefOfSanity.java +++ b/Mage.Sets/src/mage/cards/t/ThiefOfSanity.java @@ -7,7 +7,6 @@ import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; -import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughManaEffect; import mage.abilities.effects.ContinuousEffect; @@ -26,7 +25,6 @@ import mage.constants.Outcome; import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterCard; -import mage.game.ExileZone; import mage.game.Game; import mage.players.ManaPoolItem; import mage.players.Player; @@ -54,10 +52,6 @@ public final class ThiefOfSanity extends CardImpl { // Whenever Thief of Sanity deals combat damage to a player, look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it. this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ThiefOfSanityEffect(), false, true)); - - Ability ability = new SimpleStaticAbility(Zone.ALL, new ThiefOfSanityLookEffect()); - ability.setRuleVisible(false); - this.addAbility(ability); } public ThiefOfSanity(final ThiefOfSanity card) { @@ -74,7 +68,8 @@ class ThiefOfSanityEffect extends OneShotEffect { public ThiefOfSanityEffect() { super(Outcome.Benefit); - this.staticText = "look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it"; + this.staticText = "look at the top three cards of that player's library, exile one of them face down, then put the rest into their graveyard. " + + "For as long as that card remains exiled, you may look at it, you may cast it, and you may spend mana as though it were mana of any type to cast it"; } public ThiefOfSanityEffect(final ThiefOfSanityEffect effect) { @@ -102,7 +97,7 @@ class ThiefOfSanityEffect extends OneShotEffect { // move card to exile UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); card.setFaceDown(true, game); - if (controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName())) { + if (controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName() + " (" + controller.getName() + ")")) { card.setFaceDown(true, game); Set exileZones = (Set) game.getState().getValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString()); if (exileZones == null) { @@ -110,12 +105,17 @@ class ThiefOfSanityEffect extends OneShotEffect { game.getState().setValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString(), exileZones); } exileZones.add(exileZoneId); + // rule information: https://blogs.magicjudges.org/rulestips/2018/11/thief-of-sanity-and-control-changing/ // allow to cast the card - ContinuousEffect effect = new ThiefOfSanityCastFromExileEffect(); + ContinuousEffect effect = new ThiefOfSanityCastFromExileEffect(controller.getId()); effect.setTargetPointer(new FixedTarget(card.getId(), game)); game.addEffect(effect, source); // and you may spend mana as though it were mana of any color to cast it - effect = new ThiefOfSanitySpendAnyManaEffect(); + effect = new ThiefOfSanitySpendAnyManaEffect(controller.getId()); + effect.setTargetPointer(new FixedTarget(card.getId(), game)); + game.addEffect(effect, source); + // For as long as that card remains exiled, you may look at it + effect = new ThiefOfSanityLookEffect(controller.getId()); effect.setTargetPointer(new FixedTarget(card.getId(), game)); game.addEffect(effect, source); } @@ -132,13 +132,17 @@ class ThiefOfSanityEffect extends OneShotEffect { class ThiefOfSanityCastFromExileEffect extends AsThoughEffectImpl { - public ThiefOfSanityCastFromExileEffect() { + final UUID authorizedPlayerId; + + public ThiefOfSanityCastFromExileEffect(UUID authorizedPlayerId) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); - staticText = "You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell"; + this.authorizedPlayerId = authorizedPlayerId; + staticText = "For as long as that card remains exiled, you may cast it"; } public ThiefOfSanityCastFromExileEffect(final ThiefOfSanityCastFromExileEffect effect) { super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; } @Override @@ -153,11 +157,11 @@ class ThiefOfSanityCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - UUID targetId = getTargetPointer().getFirst(game, source); - if (targetId == null) { - this.discard(); - } else if (objectId.equals(targetId) - && affectedControllerId.equals(source.getControllerId())) { + UUID cardId = getTargetPointer().getFirst(game, source); + if (cardId == null) { + this.discard(); // card is no longer in the origin zone, effect can be discarded + } else if (objectId.equals(cardId) + && affectedControllerId.equals(authorizedPlayerId)) { Card card = game.getCard(objectId); // TODO: Allow to cast Zoetic Cavern face down return card != null && !card.isLand(); @@ -168,13 +172,17 @@ class ThiefOfSanityCastFromExileEffect extends AsThoughEffectImpl { class ThiefOfSanitySpendAnyManaEffect extends AsThoughEffectImpl implements AsThoughManaEffect { - public ThiefOfSanitySpendAnyManaEffect() { + final UUID authorizedPlayerId; + + public ThiefOfSanitySpendAnyManaEffect(UUID authorizedPlayerId) { super(AsThoughEffectType.SPEND_OTHER_MANA, Duration.Custom, Outcome.Benefit); - staticText = "you may spend mana as though it were mana of any color to cast it"; + this.authorizedPlayerId = authorizedPlayerId; + staticText = "For as long as that card remains exiled, you may spend mana as though it were mana of any color to cast it"; } public ThiefOfSanitySpendAnyManaEffect(final ThiefOfSanitySpendAnyManaEffect effect) { super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; } @Override @@ -189,16 +197,15 @@ class ThiefOfSanitySpendAnyManaEffect extends AsThoughEffectImpl implements AsTh @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards if (objectId.equals(((FixedTarget) getTargetPointer()).getTarget()) && game.getState().getZoneChangeCounter(objectId) <= ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { - - if (affectedControllerId.equals(source.getControllerId())) { - // if the card moved from exile to spell the zone change counter is increased by 1 + if (affectedControllerId.equals(authorizedPlayerId)) { + // if the card moved from exile to stack the zone change counter is increased by 1 if (game.getState().getZoneChangeCounter(objectId) == ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1) { return true; } } - } else if (((FixedTarget) getTargetPointer()).getTarget().equals(objectId)) { // object has moved zone so effect can be discarted this.discard(); @@ -214,13 +221,17 @@ class ThiefOfSanitySpendAnyManaEffect extends AsThoughEffectImpl implements AsTh class ThiefOfSanityLookEffect extends AsThoughEffectImpl { - public ThiefOfSanityLookEffect() { + final UUID authorizedPlayerId; + + public ThiefOfSanityLookEffect(UUID authorizedPlayerId) { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); - staticText = "You may look at the cards exiled with {this}"; + this.authorizedPlayerId = authorizedPlayerId; + staticText = "For as long as that card remains exiled, you may look at it"; } public ThiefOfSanityLookEffect(final ThiefOfSanityLookEffect effect) { super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; } @Override @@ -235,26 +246,11 @@ class ThiefOfSanityLookEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId()) && game.getState().getZone(objectId) == Zone.EXILED) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card card = game.getCard(objectId); - if (card != null && card.isFaceDown(game)) { - Set exileZones = (Set) game.getState().getValue(ThiefOfSanity.VALUE_PREFIX + source.getSourceId().toString()); - if (exileZones != null) { - for (ExileZone exileZone : game.getExile().getExileZones()) { - if (exileZone.contains(objectId)) { - if (!exileZones.contains(exileZone.getId())) { - return false; - } - } - } - return true; - } - } - } + UUID cardId = getTargetPointer().getFirst(game, source); + if (cardId == null) { + this.discard(); // card is no longer in the origin zone, effect can be discarded } - return false; + return affectedControllerId.equals(authorizedPlayerId) + && objectId.equals(cardId); } } diff --git a/Mage.Sets/src/mage/cards/t/ThievesAuction.java b/Mage.Sets/src/mage/cards/t/ThievesAuction.java index e95351a1a0..b9b27cf743 100644 --- a/Mage.Sets/src/mage/cards/t/ThievesAuction.java +++ b/Mage.Sets/src/mage/cards/t/ThievesAuction.java @@ -52,7 +52,7 @@ class ThievesAuctionEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterPermanent("nontoken permanents"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } ThievesAuctionEffect() { diff --git a/Mage.Sets/src/mage/cards/t/ThirstingAxe.java b/Mage.Sets/src/mage/cards/t/ThirstingAxe.java index e5da2e1873..7462f5396c 100644 --- a/Mage.Sets/src/mage/cards/t/ThirstingAxe.java +++ b/Mage.Sets/src/mage/cards/t/ThirstingAxe.java @@ -72,8 +72,8 @@ class EquippedDealtCombatDamageToCreatureCondition implements Condition { Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { CombatDamageToCreatureWatcher watcher = - (CombatDamageToCreatureWatcher) game.getState().getWatchers().get(CombatDamageToCreatureWatcher.BASIC_KEY); - return watcher.dealtDamage(equipment.getAttachedTo(), equipment.getAttachedToZoneChangeCounter(), game); + game.getState().getWatcher(CombatDamageToCreatureWatcher.class); + return watcher != null && watcher.dealtDamage(equipment.getAttachedTo(), equipment.getAttachedToZoneChangeCounter(), game); } return false; } @@ -83,12 +83,11 @@ class EquippedDealtCombatDamageToCreatureCondition implements Condition { class CombatDamageToCreatureWatcher extends Watcher { // which objects dealt combat damage to creature during the turn - public final Set dealtCombatDamageToCreature; + private final Set dealtCombatDamageToCreature; - final static String BASIC_KEY = "CombatDamageToCreatureWatcher"; public CombatDamageToCreatureWatcher() { - super(BASIC_KEY, WatcherScope.GAME); + super(WatcherScope.GAME); dealtCombatDamageToCreature = new HashSet<>(); } diff --git a/Mage.Sets/src/mage/cards/t/ThirstingShade.java b/Mage.Sets/src/mage/cards/t/ThirstingShade.java new file mode 100644 index 0000000000..4bc4ae12c0 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThirstingShade.java @@ -0,0 +1,45 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.LifelinkAbility; +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 ThirstingShade extends CardImpl { + + public ThirstingShade(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}"); + + this.subtype.add(SubType.SHADE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + + // {2}{B}: Thirsting Shade gets +1/+1 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(1, 1, Duration.EndOfTurn), new ManaCostsImpl("{2}{B}") + )); + } + + private ThirstingShade(final ThirstingShade card) { + super(card); + } + + @Override + public ThirstingShade copy() { + return new ThirstingShade(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThopterArrest.java b/Mage.Sets/src/mage/cards/t/ThopterArrest.java index 292158dab1..a5b154d32f 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterArrest.java +++ b/Mage.Sets/src/mage/cards/t/ThopterArrest.java @@ -23,7 +23,7 @@ import mage.target.TargetPermanent; */ public final class ThopterArrest extends CardImpl { - private final static FilterPermanent filter = new FilterPermanent("artifact or creature"); + private static final FilterPermanent filter = new FilterPermanent("artifact or creature"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/t/ThopterAssembly.java b/Mage.Sets/src/mage/cards/t/ThopterAssembly.java index e75e7c18d5..4d7b3a8254 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterAssembly.java +++ b/Mage.Sets/src/mage/cards/t/ThopterAssembly.java @@ -57,7 +57,7 @@ class ThopterAssemblyTriggeredAbility extends TriggeredAbilityImpl { private static final FilterPermanent filter = new FilterPermanent(); static { filter.add(new SubtypePredicate(SubType.THOPTER)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } ThopterAssemblyTriggeredAbility() { diff --git a/Mage.Sets/src/mage/cards/t/ThopterFoundry.java b/Mage.Sets/src/mage/cards/t/ThopterFoundry.java index 77043b03a1..2c5a4c93c5 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterFoundry.java +++ b/Mage.Sets/src/mage/cards/t/ThopterFoundry.java @@ -29,7 +29,7 @@ public final class ThopterFoundry extends CardImpl { static { filter.add(new CardTypePredicate(CardType.ARTIFACT)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public ThopterFoundry(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThopterSquadron.java b/Mage.Sets/src/mage/cards/t/ThopterSquadron.java index a87ca4db82..924f154435 100644 --- a/Mage.Sets/src/mage/cards/t/ThopterSquadron.java +++ b/Mage.Sets/src/mage/cards/t/ThopterSquadron.java @@ -34,7 +34,7 @@ public final class ThopterSquadron extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Thopter"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.THOPTER)); } diff --git a/Mage.Sets/src/mage/cards/t/ThornbowArcher.java b/Mage.Sets/src/mage/cards/t/ThornbowArcher.java index b2ceb7a5ce..6122a804c1 100644 --- a/Mage.Sets/src/mage/cards/t/ThornbowArcher.java +++ b/Mage.Sets/src/mage/cards/t/ThornbowArcher.java @@ -45,7 +45,7 @@ public final class ThornbowArcher extends CardImpl { class ThornbowArcherEffect extends OneShotEffect { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new SubtypePredicate(SubType.ELF)); diff --git a/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java b/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java new file mode 100644 index 0000000000..e09ad3f024 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThoughtCollapse.java @@ -0,0 +1,66 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CounterTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetSpell; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThoughtCollapse extends CardImpl { + + public ThoughtCollapse(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{U}"); + + // Counter target spell. Its controller puts the top three cards of their library into their graveyard. + this.getSpellAbility().addEffect(new ThoughtCollapseEffect()); + this.getSpellAbility().addTarget(new TargetSpell()); + } + + private ThoughtCollapse(final ThoughtCollapse card) { + super(card); + } + + @Override + public ThoughtCollapse copy() { + return new ThoughtCollapse(this); + } +} + +class ThoughtCollapseEffect extends OneShotEffect { + + ThoughtCollapseEffect() { + super(Outcome.Benefit); + staticText = "Counter target spell. Its controller puts " + + "the top three cards of their library into their graveyard."; + } + + private ThoughtCollapseEffect(final ThoughtCollapseEffect effect) { + super(effect); + } + + @Override + public ThoughtCollapseEffect copy() { + return new ThoughtCollapseEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getControllerId(source.getFirstTarget())); + if (player == null) { + return false; + } + player.moveCards(player.getLibrary().getTopCards(game, 3), Zone.GRAVEYARD, source, game); + return new CounterTargetEffect().apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThoughtDissector.java b/Mage.Sets/src/mage/cards/t/ThoughtDissector.java index 2238235f42..f817054089 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtDissector.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtDissector.java @@ -49,7 +49,7 @@ public final class ThoughtDissector extends CardImpl { class ThoughtDissectorEffect extends OneShotEffect { - private static final ManacostVariableValue amount = new ManacostVariableValue(); + private static final ManacostVariableValue amount = ManacostVariableValue.instance; public ThoughtDissectorEffect() { super(Outcome.Detriment); diff --git a/Mage.Sets/src/mage/cards/t/ThoughtHarvester.java b/Mage.Sets/src/mage/cards/t/ThoughtHarvester.java index 051a00cc43..1b3cf72dc3 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtHarvester.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtHarvester.java @@ -25,7 +25,7 @@ public final class ThoughtHarvester extends CardImpl { private static final FilterSpell filter = new FilterSpell("a colorless spell"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public ThoughtHarvester(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java index bec111276c..04f7a06f21 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtHemorrhage.java @@ -1,9 +1,5 @@ package mage.cards.t; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -21,9 +17,14 @@ import mage.players.Player; import mage.target.TargetPlayer; import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInLibrary; +import mage.util.CardUtil; + +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class ThoughtHemorrhage extends CardImpl { @@ -74,7 +75,7 @@ class ThoughtHemorrhageEffect extends OneShotEffect { targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game); int cardsFound = 0; for (Card card : targetPlayer.getHand().getCards(game)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { cardsFound++; } } @@ -111,7 +112,7 @@ class ThoughtHemorrhageEffect extends OneShotEffect { // search cards in Library // If the player has no nonland cards in their hand, you can still search that player's library and have him or her shuffle it. TargetCardInLibrary targetCardsLibrary = new TargetCardInLibrary(0, Integer.MAX_VALUE, filterNamedCards); - controller.searchLibrary(targetCardsLibrary, game, targetPlayer.getId()); + controller.searchLibrary(targetCardsLibrary, source, game, targetPlayer.getId()); for (UUID cardId : targetCardsLibrary.getTargets()) { Card card = game.getCard(cardId); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/t/ThoughtLash.java b/Mage.Sets/src/mage/cards/t/ThoughtLash.java index f8e53fb8f9..46663adb7c 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtLash.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtLash.java @@ -102,8 +102,7 @@ class ThoughtLashExileLibraryEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, controller.getLibrary().size())); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, controller.getLibrary().size())); controller.moveCards(cards, Zone.EXILED, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java index 7eef4e4083..825e82e084 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtPrison.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtPrison.java @@ -94,7 +94,7 @@ class ThoughtPrisonImprintEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { permanent.imprint(card.getId(), game); - permanent.addInfo("imprint", new StringBuilder("[Exiled card - ").append(card.getName()).append(']').toString(), game); + permanent.addInfo("imprint", "[Exiled card - " + card.getName() + ']', game); } return true; } diff --git a/Mage.Sets/src/mage/cards/t/ThoughtpickerWitch.java b/Mage.Sets/src/mage/cards/t/ThoughtpickerWitch.java index 1cbef42ad6..6ee29633cf 100644 --- a/Mage.Sets/src/mage/cards/t/ThoughtpickerWitch.java +++ b/Mage.Sets/src/mage/cards/t/ThoughtpickerWitch.java @@ -78,8 +78,7 @@ class ThoughtpickerWitchEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (controller != null && opponent != null) { - Cards cards = new CardsImpl(); - cards.addAll(opponent.getLibrary().getTopCards(game, 2)); + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, 2)); if (!cards.isEmpty()) { TargetCard target = new TargetCardInLibrary(new FilterCard("card to exile")); if (controller.choose(Outcome.Exile, cards, target, game)) { diff --git a/Mage.Sets/src/mage/cards/t/ThousandWinds.java b/Mage.Sets/src/mage/cards/t/ThousandWinds.java index 5cdbcdf9f9..c9b591a169 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandWinds.java +++ b/Mage.Sets/src/mage/cards/t/ThousandWinds.java @@ -25,8 +25,8 @@ public final class ThousandWinds extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other tapped creatures"); static { - filter.add(new AnotherPredicate()); - filter.add(new TappedPredicate()); + filter.add(AnotherPredicate.instance); + filter.add(TappedPredicate.instance); } public ThousandWinds(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java b/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java index 83c624009a..77f82d9ddd 100644 --- a/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java +++ b/Mage.Sets/src/mage/cards/t/ThousandYearStorm.java @@ -1,9 +1,5 @@ package mage.cards.t; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; @@ -18,8 +14,12 @@ import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class ThousandYearStorm extends CardImpl { @@ -63,9 +63,14 @@ class ThousandYearStormEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Spell spell = game.getSpellOrLKIStack(getTargetPointer().getFirst(game, source)); if (spell != null) { - ThousandYearWatcher watcher = (ThousandYearWatcher) game.getState().getWatchers().get(ThousandYearWatcher.class.getSimpleName()); + ThousandYearWatcher watcher = game.getState().getWatcher(ThousandYearWatcher.class); if (watcher != null) { - int numberOfCopies = watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) - 1; + String stateSearchId = spell.getId().toString() + source.getSourceId().toString(); + // recall only the spells cast before it + int numberOfCopies = 0; + if (game.getState().getValue(stateSearchId) != null) { + numberOfCopies = (int) game.getState().getValue(stateSearchId); + } if (numberOfCopies > 0) { for (int i = 0; i < numberOfCopies; i++) { spell.createCopyOnStack(game, source, source.getControllerId(), true); @@ -83,7 +88,7 @@ class ThousandYearWatcher extends Watcher { private final Map amountOfInstantSorcerySpellsCastOnCurrentTurn = new HashMap<>(); public ThousandYearWatcher() { - super(ThousandYearWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ThousandYearWatcher(final ThousandYearWatcher watcher) { @@ -95,13 +100,17 @@ class ThousandYearWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.SPELL_CAST) { + if (event.getType() == GameEvent.EventType.SPELL_CAST && !sourceId.equals(event.getTargetId())) { Spell spell = game.getSpellOrLKIStack(event.getTargetId()); if (spell != null && spell.isInstantOrSorcery()) { UUID playerId = event.getPlayerId(); if (playerId != null) { + String stateSearchId = spell.getId().toString() + sourceId.toString(); + // calc current spell amountOfInstantSorcerySpellsCastOnCurrentTurn.putIfAbsent(playerId, 0); amountOfInstantSorcerySpellsCastOnCurrentTurn.compute(playerId, (k, a) -> a + 1); + // remember only the spells cast before it + game.getState().setValue(stateSearchId, amountOfInstantSorcerySpellsCastOnCurrentTurn.get(playerId) - 1); } } } diff --git a/Mage.Sets/src/mage/cards/t/ThrabenFoulbloods.java b/Mage.Sets/src/mage/cards/t/ThrabenFoulbloods.java index d5d2c42ad5..e7a0d49026 100644 --- a/Mage.Sets/src/mage/cards/t/ThrabenFoulbloods.java +++ b/Mage.Sets/src/mage/cards/t/ThrabenFoulbloods.java @@ -1,7 +1,7 @@ - package mage.cards.t; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -9,6 +9,7 @@ import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.MenaceAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,13 +19,12 @@ import mage.constants.Duration; import mage.constants.Zone; /** - * * @author LevelX2 */ public final class ThrabenFoulbloods extends CardImpl { public ThrabenFoulbloods(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.HOUND); this.power = new MageInt(3); @@ -35,6 +35,7 @@ public final class ThrabenFoulbloods extends CardImpl { Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); ability.addEffect(new ConditionalContinuousEffect(new GainAbilitySourceEffect(new MenaceAbility()), DeliriumCondition.instance, "and has menace as long as there are four or more card types among cards in your graveyard. (A creature with menace can't be blocked except by two or more creatures.)")); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ThranTemporalGateway.java b/Mage.Sets/src/mage/cards/t/ThranTemporalGateway.java index cc8b7e96ad..a8bf44ce26 100644 --- a/Mage.Sets/src/mage/cards/t/ThranTemporalGateway.java +++ b/Mage.Sets/src/mage/cards/t/ThranTemporalGateway.java @@ -23,7 +23,7 @@ public final class ThranTemporalGateway extends CardImpl { private static final FilterPermanentCard filter = new FilterPermanentCard("a historic permanent card"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public ThranTemporalGateway(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThrashOfRaptors.java b/Mage.Sets/src/mage/cards/t/ThrashOfRaptors.java index eadd8fee03..e4267e9f10 100644 --- a/Mage.Sets/src/mage/cards/t/ThrashOfRaptors.java +++ b/Mage.Sets/src/mage/cards/t/ThrashOfRaptors.java @@ -30,7 +30,7 @@ public final class ThrashOfRaptors extends CardImpl { static { filter.add(new SubtypePredicate(SubType.DINOSAUR)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public ThrashOfRaptors(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThrashThreat.java b/Mage.Sets/src/mage/cards/t/ThrashThreat.java new file mode 100644 index 0000000000..1c23dbe0f2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThrashThreat.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.DamageWithPowerTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.permanent.token.RedGreenBeastToken; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThrashThreat extends SplitCard { + + private static final FilterPermanent filter + = new FilterCreatureOrPlaneswalkerPermanent("creature or planeswalker you don't control"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + } + + public ThrashThreat(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{R/G}{R/G}", "{2}{R}{G}", SpellAbilityType.SPLIT); + + // Thrash + // Target creature you control deals damage equal to its power to target creature or planeswalker you don't control. + this.getLeftHalfCard().getSpellAbility().addEffect( + new DamageWithPowerTargetEffect() + .setText("Target creature you control deals damage equal to its power " + + "to target creature or planeswalker you don't control.") + ); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetPermanent(filter)); + + // Threat + // Create a 4/4 red and green Beast creature token with trample. + this.getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new RedGreenBeastToken())); + } + + private ThrashThreat(final ThrashThreat card) { + super(card); + } + + @Override + public ThrashThreat copy() { + return new ThrashThreat(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ThrillingEncore.java b/Mage.Sets/src/mage/cards/t/ThrillingEncore.java index 67043f5be8..9a5335ceed 100644 --- a/Mage.Sets/src/mage/cards/t/ThrillingEncore.java +++ b/Mage.Sets/src/mage/cards/t/ThrillingEncore.java @@ -58,7 +58,7 @@ class ThrillingEncoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); if (watcher != null) { for (MageObjectReference mor : watcher.getCardsPutToGraveyardFromBattlefield()) { if (game.getState().getZoneChangeCounter(mor.getSourceId()) == mor.getZoneChangeCounter()) { diff --git a/Mage.Sets/src/mage/cards/t/Thrive.java b/Mage.Sets/src/mage/cards/t/Thrive.java index 0ef155b6a8..d4d640ab23 100644 --- a/Mage.Sets/src/mage/cards/t/Thrive.java +++ b/Mage.Sets/src/mage/cards/t/Thrive.java @@ -1,9 +1,7 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.counter.AddCountersTargetEffect; import mage.cards.CardImpl; @@ -12,21 +10,23 @@ import mage.constants.CardType; import mage.counters.CounterType; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author emerald000 */ public final class Thrive extends CardImpl { public Thrive(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}"); // Put a +1/+1 counter on each of X target creatures. Effect effect = new AddCountersTargetEffect(CounterType.P1P1.createInstance()); effect.setText("Put a +1/+1 counter on each of X target creatures"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1)); + this.getSpellAbility().setTargetAdjuster(ThriveAdjuster.instance); } public Thrive(final Thrive card) { @@ -37,13 +37,14 @@ public final class Thrive extends CardImpl { public Thrive copy() { return new Thrive(this); } - +} + +enum ThriveAdjuster implements TargetAdjuster { + instance; + @Override public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetCreaturePermanent(xValue)); - } + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); } -} +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/ThroneOfGeth.java b/Mage.Sets/src/mage/cards/t/ThroneOfGeth.java index 329851cf1b..b71086bd71 100644 --- a/Mage.Sets/src/mage/cards/t/ThroneOfGeth.java +++ b/Mage.Sets/src/mage/cards/t/ThroneOfGeth.java @@ -1,8 +1,5 @@ - - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.SacrificeTargetCost; @@ -16,8 +13,9 @@ import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author Loki */ public final class ThroneOfGeth extends CardImpl { @@ -30,9 +28,9 @@ public final class ThroneOfGeth extends CardImpl { public ThroneOfGeth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{2}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); - // {T}, Sacrifice an artifact: Proliferate. + // {T}, Sacrifice an artifact: Proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ProliferateEffect(), new TapSourceCost()); ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(filter))); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/ThroneOfTheGodPharaoh.java b/Mage.Sets/src/mage/cards/t/ThroneOfTheGodPharaoh.java index 747ddcd3f4..4c485da646 100644 --- a/Mage.Sets/src/mage/cards/t/ThroneOfTheGodPharaoh.java +++ b/Mage.Sets/src/mage/cards/t/ThroneOfTheGodPharaoh.java @@ -23,7 +23,7 @@ public final class ThroneOfTheGodPharaoh extends CardImpl { private static final FilterPermanent filter = new FilterControlledCreaturePermanent("tapped creature you control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public ThroneOfTheGodPharaoh(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/Thrummingbird.java b/Mage.Sets/src/mage/cards/t/Thrummingbird.java index 9156fc33e5..15be366d09 100644 --- a/Mage.Sets/src/mage/cards/t/Thrummingbird.java +++ b/Mage.Sets/src/mage/cards/t/Thrummingbird.java @@ -1,8 +1,5 @@ - - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.effects.common.counter.ProliferateEffect; @@ -12,20 +9,25 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import java.util.UUID; + /** * @author Loki, nantuko, North */ public final class Thrummingbird extends CardImpl { public Thrummingbird(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.BIRD); this.subtype.add(SubType.HORROR); this.power = new MageInt(1); this.toughness = new MageInt(1); + // Flying this.addAbility(FlyingAbility.getInstance()); + + // Whenever Thrummingbird deals combat damage to a player, proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ProliferateEffect(), false)); } diff --git a/Mage.Sets/src/mage/cards/t/Thud.java b/Mage.Sets/src/mage/cards/t/Thud.java index 54c775bc20..cdcc431c5b 100644 --- a/Mage.Sets/src/mage/cards/t/Thud.java +++ b/Mage.Sets/src/mage/cards/t/Thud.java @@ -26,7 +26,7 @@ public final class Thud extends CardImpl { )); // Thud deals damage equal to the sacrificed creature's power to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new SacrificeCostCreaturesPower())); + this.getSpellAbility().addEffect(new DamageTargetEffect(SacrificeCostCreaturesPower.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/t/ThunderDrake.java b/Mage.Sets/src/mage/cards/t/ThunderDrake.java new file mode 100644 index 0000000000..6ee8ae338e --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThunderDrake.java @@ -0,0 +1,84 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +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.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.watchers.common.CastSpellLastTurnWatcher; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThunderDrake extends CardImpl { + + public ThunderDrake(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.ELEMENTAL); + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever you cast you cast your second spell each turn, put a +1/+1 counter on Thunder Drake. + this.addAbility(new ThunderDrakeTriggeredAbility(), new CastSpellLastTurnWatcher()); + } + + private ThunderDrake(final ThunderDrake card) { + super(card); + } + + @Override + public ThunderDrake copy() { + return new ThunderDrake(this); + } +} + +class ThunderDrakeTriggeredAbility extends TriggeredAbilityImpl { + + ThunderDrakeTriggeredAbility() { + super(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance())); + } + + private ThunderDrakeTriggeredAbility(final ThunderDrakeTriggeredAbility ability) { + super(ability); + } + + @Override + public ThunderDrakeTriggeredAbility copy() { + return new ThunderDrakeTriggeredAbility(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 (event.getPlayerId().equals(controllerId)) { + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 2) { + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever you cast your second spell each turn, put a +1/+1 counter on {this}"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/Thunderbolt.java b/Mage.Sets/src/mage/cards/t/Thunderbolt.java index c1a0951191..29e4d37fe6 100644 --- a/Mage.Sets/src/mage/cards/t/Thunderbolt.java +++ b/Mage.Sets/src/mage/cards/t/Thunderbolt.java @@ -32,8 +32,8 @@ public final class Thunderbolt extends CardImpl { this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addTarget(new TargetPlayerOrPlaneswalker()); Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(4)); - mode.getTargets().add(new TargetCreaturePermanent(filter)); + mode.addEffect(new DamageTargetEffect(4)); + mode.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/ThundercloudElemental.java b/Mage.Sets/src/mage/cards/t/ThundercloudElemental.java index 6d47ec49c5..da507b1d91 100644 --- a/Mage.Sets/src/mage/cards/t/ThundercloudElemental.java +++ b/Mage.Sets/src/mage/cards/t/ThundercloudElemental.java @@ -31,7 +31,7 @@ public final class ThundercloudElemental extends CardImpl { static { toughnessFilter.add(new ToughnessPredicate(ComparisonType.FEWER_THAN, 3)); - flyingFilter.add(new AnotherPredicate()); + flyingFilter.add(AnotherPredicate.instance); } public ThundercloudElemental(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThunderingCeratok.java b/Mage.Sets/src/mage/cards/t/ThunderingCeratok.java new file mode 100644 index 0000000000..6d5ec6a0b6 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ThunderingCeratok.java @@ -0,0 +1,46 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ThunderingCeratok extends CardImpl { + + public ThunderingCeratok(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.RHINO); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + + // When Thundering Ceratok enters the battlefield, other creatures you control gain trample until end of turn. + this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect( + TrampleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURES, true + ))); + } + + private ThunderingCeratok(final ThunderingCeratok card) { + super(card); + } + + @Override + public ThunderingCeratok copy() { + return new ThunderingCeratok(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Thundermare.java b/Mage.Sets/src/mage/cards/t/Thundermare.java index 4ceaec8706..e62e638d66 100644 --- a/Mage.Sets/src/mage/cards/t/Thundermare.java +++ b/Mage.Sets/src/mage/cards/t/Thundermare.java @@ -22,7 +22,7 @@ public final class Thundermare extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Thundermare(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java b/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java index dfd5ac5b25..24fdde1e70 100644 --- a/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java +++ b/Mage.Sets/src/mage/cards/t/ThundermawHellkite.java @@ -27,7 +27,7 @@ import mage.game.permanent.Permanent; */ public final class ThundermawHellkite extends CardImpl { - final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with flying your opponents control"); + static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures with flying your opponents control"); static { filter.add(new AbilityPredicate(FlyingAbility.class)); diff --git a/Mage.Sets/src/mage/cards/t/Thunderstaff.java b/Mage.Sets/src/mage/cards/t/Thunderstaff.java index 7e6da62765..0436b5a396 100644 --- a/Mage.Sets/src/mage/cards/t/Thunderstaff.java +++ b/Mage.Sets/src/mage/cards/t/Thunderstaff.java @@ -28,7 +28,7 @@ public final class Thunderstaff extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Attacking creatures"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Thunderstaff(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java b/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java new file mode 100644 index 0000000000..a7b685b0da --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TibaltRakishInstigator.java @@ -0,0 +1,48 @@ +package mage.cards.t; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.continuous.CantGainLifeAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.permanent.token.DevilToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TibaltRakishInstigator extends CardImpl { + + public TibaltRakishInstigator(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.TIBALT); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Your opponents can't gain life. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new CantGainLifeAllEffect( + Duration.WhileOnBattlefield, + TargetController.OPPONENT + ) + )); + + // -2: Create a 1/1 red Devil creature token with "Whenever this creature dies, it deals 1 damage to any target. + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new DevilToken()), -2)); + } + + private TibaltRakishInstigator(final TibaltRakishInstigator card) { + super(card); + } + + @Override + public TibaltRakishInstigator copy() { + return new TibaltRakishInstigator(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java b/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java index a83deed0d4..5805188ef9 100644 --- a/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java +++ b/Mage.Sets/src/mage/cards/t/TibaltTheFiendBlooded.java @@ -53,7 +53,7 @@ public final class TibaltTheFiendBlooded extends CardImpl { ability.addEffect(effect); this.addAbility(ability); // -4: Tibalt, the Fiend-Blooded deals damage equal to the number of cards in target player's hand to that player. - effect = new DamageTargetEffect(new CardsInTargetHandCount(), true); + effect = new DamageTargetEffect(CardsInTargetHandCount.instance, true); effect.setText("{this} deals damage equal to the number of cards in target player's hand to that player"); ability = new LoyaltyAbility(effect, -4); ability.addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/t/TibaltsRager.java b/Mage.Sets/src/mage/cards/t/TibaltsRager.java new file mode 100644 index 0000000000..26d3282571 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TibaltsRager.java @@ -0,0 +1,50 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.target.common.TargetAnyTarget; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TibaltsRager extends CardImpl { + + public TibaltsRager(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); + + this.subtype.add(SubType.DEVIL); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // When Tibalt's Rager dies, it deals 1 damage to any target. + Ability ability = new DiesTriggeredAbility(new DamageTargetEffect(1, "it")); + ability.addTarget(new TargetAnyTarget()); + this.addAbility(ability); + + // {1}{R}: Tibalt's Rager gets +2/+0 until end of turn. + this.addAbility(new SimpleActivatedAbility( + new BoostSourceEffect(2, 0, Duration.EndOfTurn), new ManaCostsImpl("{1}{R}") + )); + } + + private TibaltsRager(final TibaltsRager card) { + super(card); + } + + @Override + public TibaltsRager copy() { + return new TibaltsRager(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TideDrifter.java b/Mage.Sets/src/mage/cards/t/TideDrifter.java index 143baaff6d..e27e0d84c5 100644 --- a/Mage.Sets/src/mage/cards/t/TideDrifter.java +++ b/Mage.Sets/src/mage/cards/t/TideDrifter.java @@ -24,7 +24,7 @@ public final class TideDrifter extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("colorless creatures"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public TideDrifter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TideOfWar.java b/Mage.Sets/src/mage/cards/t/TideOfWar.java index 3cc8d25e62..6c48d0af6b 100644 --- a/Mage.Sets/src/mage/cards/t/TideOfWar.java +++ b/Mage.Sets/src/mage/cards/t/TideOfWar.java @@ -101,7 +101,7 @@ class TideOfWarEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Set toSacrifice = new HashSet<>(); - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { // each blocking creature is sacrificed by its controller for (CombatGroup combatGroup: game.getCombat().getGroups()) { for (UUID blockerId: combatGroup.getBlockers()) { @@ -124,7 +124,7 @@ class TideOfWarEffect extends OneShotEffect { creature.sacrifice(source.getSourceId(), game); Player player = game.getPlayer(creature.getControllerId()); if (player != null) { - game.informPlayers(new StringBuilder(player.getLogName()).append(" sacrifices ").append(creature.getName()).toString()); + game.informPlayers(player.getLogName() + " sacrifices " + creature.getName()); } } } diff --git a/Mage.Sets/src/mage/cards/t/TidebinderMage.java b/Mage.Sets/src/mage/cards/t/TidebinderMage.java index bc6348a859..c4f3efa11b 100644 --- a/Mage.Sets/src/mage/cards/t/TidebinderMage.java +++ b/Mage.Sets/src/mage/cards/t/TidebinderMage.java @@ -130,7 +130,7 @@ class TidebinderMageEffect extends ContinuousRuleModifyingEffectImpl { class TidebinderMageWatcher extends Watcher { TidebinderMageWatcher () { - super("ControlLost", WatcherScope.CARD); + super(WatcherScope.CARD); } TidebinderMageWatcher(TidebinderMageWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TideforceElemental.java b/Mage.Sets/src/mage/cards/t/TideforceElemental.java index 61a0188763..bad10be690 100644 --- a/Mage.Sets/src/mage/cards/t/TideforceElemental.java +++ b/Mage.Sets/src/mage/cards/t/TideforceElemental.java @@ -29,7 +29,7 @@ public final class TideforceElemental extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TideforceElemental(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TidehollowSculler.java b/Mage.Sets/src/mage/cards/t/TidehollowSculler.java index 7b2acc5c85..b1e2bacc96 100644 --- a/Mage.Sets/src/mage/cards/t/TidehollowSculler.java +++ b/Mage.Sets/src/mage/cards/t/TidehollowSculler.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -32,7 +31,7 @@ import mage.util.CardUtil; public final class TidehollowSculler extends CardImpl { public TidehollowSculler(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{W}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}{B}"); this.subtype.add(SubType.ZOMBIE); this.power = new MageInt(2); @@ -80,23 +79,30 @@ class TidehollowScullerExileEffect extends OneShotEffect { // 6/7/2013 If Tidehollow Sculler leaves the battlefield before its first ability has resolved, // its second ability will trigger. This ability will do nothing when it resolves. // Then its first ability will resolve and exile the chosen card forever. - Permanent sourcePermanent = (Permanent) source.getSourceObject(game); - if (controller != null && opponent != null && sourcePermanent != null) { + Permanent sourcePermanent = (Permanent) source.getSourcePermanentIfItStillExists(game); + if (controller != null + && opponent != null + && sourcePermanent != null) { opponent.revealCards(sourcePermanent.getName(), opponent.getHand(), game); - TargetCard target = new TargetCard(Zone.HAND, new FilterNonlandCard("nonland card to exile")); if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) { Card card = opponent.getHand().get(target.getFirstTarget(), game); if (card != null) { - controller.moveCardToExileWithInfo(card, CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.HAND, true); + controller.moveCardsToExile( + card, + source, + game, + true, + CardUtil.getExileZoneId(game, + source.getSourceId(), + source.getSourceObjectZoneChangeCounter()), + sourcePermanent.getIdName()); } } - return true; } return false; } - } class TidehollowScullerLeaveEffect extends OneShotEffect { @@ -120,8 +126,11 @@ class TidehollowScullerLeaveEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = source.getSourceObject(game); if (controller != null && sourceObject != null) { - int zoneChangeCounter = (sourceObject instanceof PermanentToken) ? source.getSourceObjectZoneChangeCounter() : source.getSourceObjectZoneChangeCounter() - 1; - ExileZone exZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); + int zoneChangeCounter = (sourceObject instanceof PermanentToken) + ? source.getSourceObjectZoneChangeCounter() + : source.getSourceObjectZoneChangeCounter() - 1; + ExileZone exZone = game.getExile().getExileZone( + CardUtil.getExileZoneId(game, source.getSourceId(), zoneChangeCounter)); if (exZone != null) { controller.moveCards(exZone, Zone.HAND, source, game); } diff --git a/Mage.Sets/src/mage/cards/t/TilonallisSkinshifter.java b/Mage.Sets/src/mage/cards/t/TilonallisSkinshifter.java index 10785877a3..7b07d3e74a 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisSkinshifter.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisSkinshifter.java @@ -34,8 +34,8 @@ public final class TilonallisSkinshifter extends CardImpl { static { filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); - filter.add(new AttackingPredicate()); - filter.add(new AnotherPredicate()); + filter.add(AttackingPredicate.instance); + filter.add(AnotherPredicate.instance); } public TilonallisSkinshifter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java index a9082d7749..4da45717a2 100644 --- a/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java +++ b/Mage.Sets/src/mage/cards/t/TilonallisSummoner.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; @@ -15,22 +13,20 @@ import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; 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.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.token.TilonallisSummonerElementalToken; import mage.players.Player; import mage.target.targetpointer.FixedTargets; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TilonallisSummoner extends CardImpl { @@ -47,7 +43,7 @@ public final class TilonallisSummoner extends CardImpl { this.addAbility(new AscendAbility()); // Whenever Tilonalli's Summoner attacks, you may pay {X}{R}. If you do, create X 1/1 red Elemental creature tokens that are tapped and attacking. At the beginning of the next end step, exile those tokens unless you have the city's blessing. - this.addAbility(new AttacksTriggeredAbility(new TilonallisSummonerEffect(), false)); + this.addAbility(new AttacksTriggeredAbility(new TilonallisSummonerEffect(), false).addHint(CitysBlessingHint.instance)); } public TilonallisSummoner(final TilonallisSummoner card) { diff --git a/Mage.Sets/src/mage/cards/t/TimberProtector.java b/Mage.Sets/src/mage/cards/t/TimberProtector.java index dd89cb5e59..05cb0d722e 100644 --- a/Mage.Sets/src/mage/cards/t/TimberProtector.java +++ b/Mage.Sets/src/mage/cards/t/TimberProtector.java @@ -34,7 +34,7 @@ public final class TimberProtector extends CardImpl { filterBoth.add(Predicates.or( new SubtypePredicate(SubType.TREEFOLK), new SubtypePredicate(SubType.FOREST))); - filterBoth.add(new AnotherPredicate()); + filterBoth.add(AnotherPredicate.instance); } public TimberProtector(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/Timbermare.java b/Mage.Sets/src/mage/cards/t/Timbermare.java index 6cbecc485f..db606b0db4 100644 --- a/Mage.Sets/src/mage/cards/t/Timbermare.java +++ b/Mage.Sets/src/mage/cards/t/Timbermare.java @@ -23,7 +23,7 @@ public final class Timbermare extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public Timbermare(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TimberpackWolf.java b/Mage.Sets/src/mage/cards/t/TimberpackWolf.java index fb0bf03059..7ad215889f 100644 --- a/Mage.Sets/src/mage/cards/t/TimberpackWolf.java +++ b/Mage.Sets/src/mage/cards/t/TimberpackWolf.java @@ -69,7 +69,7 @@ public final class TimberpackWolf extends CardImpl { public boolean apply(Game game, Ability source) { int count = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game) - 1; if (count > 0) { - Permanent target = (Permanent) game.getPermanent(source.getSourceId()); + Permanent target = game.getPermanent(source.getSourceId()); if (target != null) { target.addPower(count); target.addToughness(count); diff --git a/Mage.Sets/src/mage/cards/t/TimeElemental.java b/Mage.Sets/src/mage/cards/t/TimeElemental.java index 30f7e61094..da36a63b46 100644 --- a/Mage.Sets/src/mage/cards/t/TimeElemental.java +++ b/Mage.Sets/src/mage/cards/t/TimeElemental.java @@ -34,7 +34,7 @@ public final class TimeElemental extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("permanent that isn't enchanted"); static { - filter.add(Predicates.not(new EnchantedPredicate())); + filter.add(Predicates.not(EnchantedPredicate.instance)); } public TimeElemental(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TimeOfIce.java b/Mage.Sets/src/mage/cards/t/TimeOfIce.java index 10780d7b64..580d0b9c17 100644 --- a/Mage.Sets/src/mage/cards/t/TimeOfIce.java +++ b/Mage.Sets/src/mage/cards/t/TimeOfIce.java @@ -37,7 +37,7 @@ public final class TimeOfIce extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creatures"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public TimeOfIce(UUID ownerId, CardSetInfo setInfo) { @@ -141,7 +141,7 @@ class TimeOfIceEffect extends ContinuousRuleModifyingEffectImpl { class TimeOfIceWatcher extends Watcher { TimeOfIceWatcher() { - super("ControlLost", WatcherScope.CARD); + super(WatcherScope.CARD); } TimeOfIceWatcher(TimeOfIceWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TimeToReflect.java b/Mage.Sets/src/mage/cards/t/TimeToReflect.java index 3ac0599ba4..8dfd1c7131 100644 --- a/Mage.Sets/src/mage/cards/t/TimeToReflect.java +++ b/Mage.Sets/src/mage/cards/t/TimeToReflect.java @@ -1,9 +1,7 @@ - package mage.cards.t; import mage.MageObjectReference; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,8 +17,8 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; import mage.watchers.Watcher; - import java.util.*; +import mage.target.targetadjustment.TargetAdjuster; /** * @author jeffwadsworth @@ -34,27 +32,7 @@ public final class TimeToReflect extends CardImpl { this.getSpellAbility().addEffect(new ExileTargetEffect()); this.getSpellAbility().addTarget(new TargetPermanent(new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn."))); this.getSpellAbility().addWatcher(new BlockedOrWasBlockedByAZombieWatcher()); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - List creaturesThatBlockedOrWereBlockedByAZombie = new ArrayList<>(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn.").copy(); - BlockedOrWasBlockedByAZombieWatcher watcher = (BlockedOrWasBlockedByAZombieWatcher) game.getState().getWatchers().get(BlockedOrWasBlockedByAZombieWatcher.class.getSimpleName()); - if (watcher != null) { - for (MageObjectReference mor : watcher.getBlockedThisTurnCreatures()) { - Permanent permanent = mor.getPermanent(game); - if (permanent != null) { - creaturesThatBlockedOrWereBlockedByAZombie.add(new PermanentIdPredicate(permanent.getId())); - } - } - } - filter.add(Predicates.or(creaturesThatBlockedOrWereBlockedByAZombie)); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(filter)); - } + this.getSpellAbility().setTargetAdjuster(TimeToReflectAdjuster.instance); } public TimeToReflect(final TimeToReflect card) { @@ -67,12 +45,34 @@ public final class TimeToReflect extends CardImpl { } } +enum TimeToReflectAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + List creaturesThatBlockedOrWereBlockedByAZombie = new ArrayList<>(); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that blocked or was blocked by a Zombie this turn.").copy(); + BlockedOrWasBlockedByAZombieWatcher watcher = game.getState().getWatcher(BlockedOrWasBlockedByAZombieWatcher.class); + if (watcher != null) { + for (MageObjectReference mor : watcher.getBlockedThisTurnCreatures()) { + Permanent permanent = mor.getPermanent(game); + if (permanent != null) { + creaturesThatBlockedOrWereBlockedByAZombie.add(new PermanentIdPredicate(permanent.getId())); + } + } + } + filter.add(Predicates.or(creaturesThatBlockedOrWereBlockedByAZombie)); + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(filter)); + } +} + class BlockedOrWasBlockedByAZombieWatcher extends Watcher { private final Set blockedOrWasBlockedByAZombieWatcher; public BlockedOrWasBlockedByAZombieWatcher() { - super(BlockedOrWasBlockedByAZombieWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); blockedOrWasBlockedByAZombieWatcher = new HashSet<>(); } diff --git a/Mage.Sets/src/mage/cards/t/TimeWipe.java b/Mage.Sets/src/mage/cards/t/TimeWipe.java new file mode 100644 index 0000000000..3f339ac7f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TimeWipe.java @@ -0,0 +1,74 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyAllEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TimeWipe extends CardImpl { + + public TimeWipe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{W}{W}{U}"); + + // Return a creature you control to its owner's hand, then destroy all creatures. + this.getSpellAbility().addEffect(new TimeWipeEffect()); + } + + private TimeWipe(final TimeWipe card) { + super(card); + } + + @Override + public TimeWipe copy() { + return new TimeWipe(this); + } +} + +class TimeWipeEffect extends OneShotEffect { + + TimeWipeEffect() { + super(Outcome.Benefit); + staticText = "Return a creature you control to its owner's hand, then destroy all creatures."; + } + + private TimeWipeEffect(final TimeWipeEffect effect) { + super(effect); + } + + @Override + public TimeWipeEffect copy() { + return new TimeWipeEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Target target = new TargetControlledCreaturePermanent(); + target.setNotTarget(true); + if (player.choose(outcome, target, source.getSourceId(), game)) { + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + player.moveCards(permanent, Zone.HAND, source, game); + } + } + return new DestroyAllEffect(StaticFilters.FILTER_PERMANENT_A_CREATURE).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/Timebender.java b/Mage.Sets/src/mage/cards/t/Timebender.java index f1fe760838..ec61a8517d 100644 --- a/Mage.Sets/src/mage/cards/t/Timebender.java +++ b/Mage.Sets/src/mage/cards/t/Timebender.java @@ -43,8 +43,8 @@ public final class Timebender extends CardImpl { // Put two time counters on target permanent with a time counter on it or suspended card. Mode mode = new Mode(); - mode.getEffects().add(new TimebenderEffect(true)); - mode.getTargets().add(new TargetPermanentOrSuspendedCard()); + mode.addEffect(new TimebenderEffect(true)); + mode.addTarget(new TargetPermanentOrSuspendedCard()); ability.addMode(mode); ability.getModes().addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/Timecrafting.java b/Mage.Sets/src/mage/cards/t/Timecrafting.java index ca3d035621..ff24030202 100644 --- a/Mage.Sets/src/mage/cards/t/Timecrafting.java +++ b/Mage.Sets/src/mage/cards/t/Timecrafting.java @@ -38,8 +38,8 @@ public final class Timecrafting extends CardImpl { // or put X time counters on target permanent with a time counter on it or suspended card. Mode mode = new Mode(); - mode.getEffects().add(new TimecraftingAddEffect()); - mode.getTargets().add(new TargetPermanentOrSuspendedCard(filter, false)); + mode.addEffect(new TimecraftingAddEffect()); + mode.addTarget(new TargetPermanentOrSuspendedCard(filter, false)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java b/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java index dcc7ad3574..19281b2448 100644 --- a/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java +++ b/Mage.Sets/src/mage/cards/t/TimestreamNavigator.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.condition.common.CitysBlessingCondition; @@ -10,6 +8,7 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.decorator.ConditionalActivatedAbility; import mage.abilities.effects.common.turn.AddExtraTurnControllerEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -17,8 +16,9 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TimestreamNavigator extends CardImpl { @@ -42,6 +42,7 @@ public final class TimestreamNavigator extends CardImpl { CitysBlessingCondition.instance); ability.addCost(new TapSourceCost()); ability.addCost(new PutSourceOnBottomOwnerLibraryCost()); + ability.addHint(CitysBlessingHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TimidDrake.java b/Mage.Sets/src/mage/cards/t/TimidDrake.java index 9dbbb37c52..bc6f6b50aa 100644 --- a/Mage.Sets/src/mage/cards/t/TimidDrake.java +++ b/Mage.Sets/src/mage/cards/t/TimidDrake.java @@ -23,7 +23,7 @@ public final class TimidDrake extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TimidDrake(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TinStreetDodger.java b/Mage.Sets/src/mage/cards/t/TinStreetDodger.java new file mode 100644 index 0000000000..064a804c41 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TinStreetDodger.java @@ -0,0 +1,57 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.abilities.keyword.HasteAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TinStreetDodger extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("except by creatures with defender"); + + static { + filter.add(Predicates.not(new AbilityPredicate(DefenderAbility.class))); + } + + public TinStreetDodger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.ROGUE); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Haste + this.addAbility(HasteAbility.getInstance()); + + // {R}: Tin Street Dodger can't be blocked this turn except by creatures with defender. + this.addAbility(new SimpleActivatedAbility( + new CantBeBlockedByCreaturesSourceEffect(filter, Duration.EndOfTurn), new ManaCostsImpl("{R}") + )); + } + + private TinStreetDodger(final TinStreetDodger card) { + super(card); + } + + @Override + public TinStreetDodger copy() { + return new TinStreetDodger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TishanaVoiceOfThunder.java b/Mage.Sets/src/mage/cards/t/TishanaVoiceOfThunder.java index 50ec788f1a..dc58159593 100644 --- a/Mage.Sets/src/mage/cards/t/TishanaVoiceOfThunder.java +++ b/Mage.Sets/src/mage/cards/t/TishanaVoiceOfThunder.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; @@ -14,15 +12,12 @@ import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.SuperType; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.*; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author spjspj */ public final class TishanaVoiceOfThunder extends CardImpl { @@ -37,7 +32,7 @@ public final class TishanaVoiceOfThunder extends CardImpl { this.toughness = new MageInt(0); // Tishana, Voice of Thunder's power and toughness are each equal to the number of cards in your hand. - DynamicValue xValue = new CardsInControllerHandCount(); + DynamicValue xValue = CardsInControllerHandCount.instance; this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(xValue, Duration.EndOfGame))); // You have no maximum hand size. @@ -45,7 +40,7 @@ public final class TishanaVoiceOfThunder extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); // When Tishana enters the battlefield, draw a card for each creature you control. - this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent())))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_CREATURE)))); } public TishanaVoiceOfThunder(final TishanaVoiceOfThunder card) { diff --git a/Mage.Sets/src/mage/cards/t/TitaniasBoon.java b/Mage.Sets/src/mage/cards/t/TitaniasBoon.java index 706e2a9fab..a957266968 100644 --- a/Mage.Sets/src/mage/cards/t/TitaniasBoon.java +++ b/Mage.Sets/src/mage/cards/t/TitaniasBoon.java @@ -8,6 +8,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.counters.CounterType; +import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; /** @@ -21,7 +22,7 @@ public final class TitaniasBoon extends CardImpl { // Put a +1/+1 counter on each creature you control. - this.getSpellAbility().addEffect(new AddCountersAllEffect(CounterType.P1P1.createInstance(), new FilterControlledCreaturePermanent("creature you control"))); + this.getSpellAbility().addEffect(new AddCountersAllEffect(CounterType.P1P1.createInstance(), StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED)); } public TitaniasBoon(final TitaniasBoon card) { diff --git a/Mage.Sets/src/mage/cards/t/TitanicBrawl.java b/Mage.Sets/src/mage/cards/t/TitanicBrawl.java new file mode 100644 index 0000000000..4a5aaf85cd --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TitanicBrawl.java @@ -0,0 +1,63 @@ +package mage.cards.t; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.SourceTargetsPermanentCondition; +import mage.abilities.effects.common.FightTargetsEffect; +import mage.abilities.effects.common.cost.SpellCostReductionSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.CounterPredicate; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TitanicBrawl extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent("creature you don't control"); + private static final FilterPermanent filter2 + = new FilterControlledCreaturePermanent("a creature you control with a +1/+1 counter on it"); + + static { + filter.add(new ControllerPredicate(TargetController.NOT_YOU)); + filter2.add(new CounterPredicate(CounterType.P1P1)); + } + + private static final Condition condition = new SourceTargetsPermanentCondition(filter2); + + public TitanicBrawl(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); + + // This spell costs {1} less to cast if it targets a creature you control with a +1/+1 counter on it. + this.addAbility(new SimpleStaticAbility( + Zone.STACK, new SpellCostReductionSourceEffect(1, condition) + ).setRuleAtTheTop(true)); + + // Target creature you control fights target creature you don't control. + this.getSpellAbility().addEffect(new FightTargetsEffect()); + this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); + this.getSpellAbility().addTarget(new TargetCreaturePermanent(filter)); + } + + private TitanicBrawl(final TitanicBrawl card) { + super(card); + } + + @Override + public TitanicBrawl copy() { + return new TitanicBrawl(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TitanicPelagosaur.java b/Mage.Sets/src/mage/cards/t/TitanicPelagosaur.java new file mode 100644 index 0000000000..221dfc8945 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TitanicPelagosaur.java @@ -0,0 +1,32 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class TitanicPelagosaur extends CardImpl { + + public TitanicPelagosaur(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); + this.subtype.add(SubType.DINOSAUR); + + this.power = new MageInt(4); + this.toughness = new MageInt(6); + } + + public TitanicPelagosaur(final TitanicPelagosaur card) { + super(card); + } + + @Override + public TitanicPelagosaur copy() { + return new TitanicPelagosaur(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TitansPresence.java b/Mage.Sets/src/mage/cards/t/TitansPresence.java index 797104f9f0..fc2c7c08dc 100644 --- a/Mage.Sets/src/mage/cards/t/TitansPresence.java +++ b/Mage.Sets/src/mage/cards/t/TitansPresence.java @@ -29,7 +29,7 @@ public final class TitansPresence extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("a colorless creature card from your hand"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public TitansPresence(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TitansRevenge.java b/Mage.Sets/src/mage/cards/t/TitansRevenge.java index 0ce6a02ea8..37529c2469 100644 --- a/Mage.Sets/src/mage/cards/t/TitansRevenge.java +++ b/Mage.Sets/src/mage/cards/t/TitansRevenge.java @@ -21,7 +21,7 @@ public final class TitansRevenge extends CardImpl { // Titan's Revenge deals X damage to any target. Clash with an opponent. If you win, return Titan's Revenge to its owner's hand. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); this.getSpellAbility().addEffect(ClashWinReturnToHandSpellEffect.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/t/TitheTaker.java b/Mage.Sets/src/mage/cards/t/TitheTaker.java new file mode 100644 index 0000000000..c5f184deb4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TitheTaker.java @@ -0,0 +1,89 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.MyTurnCondition; +import mage.abilities.effects.common.cost.CostModificationEffectImpl; +import mage.abilities.keyword.AfterlifeAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.game.Game; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TitheTaker extends CardImpl { + + public TitheTaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // During your turn, spells your opponents cast cost {1} more to cast and abilities your opponents activate cost {1} more to activate unless they're mana abilities. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new TitheTakerCostReductionEffect())); + + // Afterlife 1 + this.addAbility(new AfterlifeAbility(1)); + } + + private TitheTaker(final TitheTaker card) { + super(card); + } + + @Override + public TitheTaker copy() { + return new TitheTaker(this); + } +} + +class TitheTakerCostReductionEffect extends CostModificationEffectImpl { + + TitheTakerCostReductionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.INCREASE_COST); + staticText = "During your turn, spells your opponents cast cost {1} more to cast " + + "and abilities your opponents activate cost {1} more to activate unless they're mana abilities."; + } + + private TitheTakerCostReductionEffect(TitheTakerCostReductionEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + if (abilityToModify.getAbilityType() == AbilityType.SPELL) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + CardUtil.adjustCost(spellAbility, -1); + } + if (abilityToModify.getAbilityType() == AbilityType.ACTIVATED) { + CardUtil.increaseCost(abilityToModify, 1); + } + return true; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + if (!MyTurnCondition.instance.apply(game, source)) { + return false; + } + if (!(abilityToModify.getAbilityType() == AbilityType.SPELL) + && !(abilityToModify.getAbilityType() == AbilityType.ACTIVATED)) { + return false; + } + return game.getOpponents(source.getControllerId()).contains(abilityToModify.getControllerId()); + } + + @Override + public TitheTakerCostReductionEffect copy() { + return new TitheTakerCostReductionEffect(this); + } + +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TithebearerGiant.java b/Mage.Sets/src/mage/cards/t/TithebearerGiant.java new file mode 100644 index 0000000000..b3ba27a062 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TithebearerGiant.java @@ -0,0 +1,44 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +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 TithebearerGiant extends CardImpl { + + public TithebearerGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(5); + + // When Tithebearer Giant enters the battlefield, you draw a card and you lose 1 life. + Ability ability = new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ); + ability.addEffect(new LoseLifeSourceControllerEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private TithebearerGiant(final TithebearerGiant card) { + super(card); + } + + @Override + public TithebearerGiant copy() { + return new TithebearerGiant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java b/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java index 05004a8cfa..8365b17b83 100644 --- a/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java +++ b/Mage.Sets/src/mage/cards/t/ToTheSlaughter.java @@ -1,11 +1,12 @@ - package mage.cards.t; import java.util.UUID; + import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -14,7 +15,6 @@ import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.target.TargetPlayer; /** - * * @author fireshoes */ public final class ToTheSlaughter extends CardImpl { @@ -37,6 +37,7 @@ public final class ToTheSlaughter extends CardImpl { new SacrificeEffect(StaticFilters.FILTER_PERMANENT_PLANESWALKER, 1, "Target player"), DeliriumCondition.instance, "and a planeswalker.")); this.getSpellAbility().addTarget(new TargetPlayer()); + this.getSpellAbility().addHint(DeliriumHint.instance); } public ToTheSlaughter(final ToTheSlaughter card) { diff --git a/Mage.Sets/src/mage/cards/t/TobiasBeckett.java b/Mage.Sets/src/mage/cards/t/TobiasBeckett.java index 041b8a6e1f..e258e5078d 100644 --- a/Mage.Sets/src/mage/cards/t/TobiasBeckett.java +++ b/Mage.Sets/src/mage/cards/t/TobiasBeckett.java @@ -81,7 +81,7 @@ class TobiasBeckettEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); UUID exileId = CardUtil.getCardExileZoneId(game, source); Card card = opponent.getLibrary().getFromTop(game); - if (card != null) { + if (card != null && sourceObject != null) { // move card to exile controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source.getSourceId(), game, Zone.LIBRARY, true); // Add effects only if the card has a spellAbility (e.g. not for lands). @@ -170,6 +170,7 @@ class TobiasBeckettSpendAnyManaEffect extends AsThoughEffectImpl implements AsTh @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + objectId = game.getCard(objectId).getMainCard().getId(); // for split cards return source.isControlledBy(affectedControllerId) && Objects.equals(objectId, ((FixedTarget) getTargetPointer()).getTarget()) && ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(objectId) diff --git a/Mage.Sets/src/mage/cards/t/TogetherForever.java b/Mage.Sets/src/mage/cards/t/TogetherForever.java index 97e35cbbe4..ed2a9aca89 100644 --- a/Mage.Sets/src/mage/cards/t/TogetherForever.java +++ b/Mage.Sets/src/mage/cards/t/TogetherForever.java @@ -106,7 +106,7 @@ class TogetherForeverDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(target)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/t/Togglodyte.java b/Mage.Sets/src/mage/cards/t/Togglodyte.java index ff3df93bd9..41f03d62dc 100644 --- a/Mage.Sets/src/mage/cards/t/Togglodyte.java +++ b/Mage.Sets/src/mage/cards/t/Togglodyte.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -16,18 +14,15 @@ import mage.abilities.effects.PreventionEffectImpl; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author L_J */ public final class Togglodyte extends CardImpl { @@ -144,12 +139,12 @@ class TogglodyteRestrictionEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @@ -178,9 +173,7 @@ class TogglodytePreventionEffect extends PreventionEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { if (super.applies(event, source, game)) { - if (event.getSourceId().equals(source.getSourceId())) { - return true; - } + return event.getSourceId().equals(source.getSourceId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/t/ToilToRenown.java b/Mage.Sets/src/mage/cards/t/ToilToRenown.java index 3ea6fd3ba5..41b1971317 100644 --- a/Mage.Sets/src/mage/cards/t/ToilToRenown.java +++ b/Mage.Sets/src/mage/cards/t/ToilToRenown.java @@ -23,7 +23,7 @@ public final class ToilToRenown extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("tapped artifact, creature, and land you control"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(Predicates.or( new CardTypePredicate(CardType.ARTIFACT), new CardTypePredicate(CardType.CREATURE), diff --git a/Mage.Sets/src/mage/cards/t/ToilTrouble.java b/Mage.Sets/src/mage/cards/t/ToilTrouble.java index c3783993f1..7a18f7047c 100644 --- a/Mage.Sets/src/mage/cards/t/ToilTrouble.java +++ b/Mage.Sets/src/mage/cards/t/ToilTrouble.java @@ -26,7 +26,7 @@ public final class ToilTrouble extends SplitCard { // Trouble // Trouble deals damage to target player equal to the number of cards in that player's hand. - Effect effect = new DamageTargetEffect(new CardsInTargetHandCount()); + Effect effect = new DamageTargetEffect(CardsInTargetHandCount.instance); effect.setText("Trouble deals damage to target player equal to the number of cards in that player's hand"); getRightHalfCard().getSpellAbility().addEffect(effect); getRightHalfCard().getSpellAbility().addTarget(new TargetPlayer()); diff --git a/Mage.Sets/src/mage/cards/t/ToilsOfNightAndDay.java b/Mage.Sets/src/mage/cards/t/ToilsOfNightAndDay.java index e01e8be6c2..7935690413 100644 --- a/Mage.Sets/src/mage/cards/t/ToilsOfNightAndDay.java +++ b/Mage.Sets/src/mage/cards/t/ToilsOfNightAndDay.java @@ -64,9 +64,9 @@ public final class ToilsOfNightAndDay extends CardImpl { for (UUID targetId : source.getTargets().get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); if (permanent != null) { - if (player.chooseUse(Outcome.Tap, new StringBuilder("Tap ").append(permanent.getName()).append('?').toString(), source, game)) { + if (player.chooseUse(Outcome.Tap, "Tap " + permanent.getName() + '?', source, game)) { permanent.tap(game); - } else if (player.chooseUse(Outcome.Untap, new StringBuilder("Untap ").append(permanent.getName()).append('?').toString(), source, game)) { + } else if (player.chooseUse(Outcome.Untap, "Untap " + permanent.getName() + '?', source, game)) { permanent.untap(game); } } diff --git a/Mage.Sets/src/mage/cards/t/Tolaria.java b/Mage.Sets/src/mage/cards/t/Tolaria.java new file mode 100644 index 0000000000..24543958ca --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Tolaria.java @@ -0,0 +1,52 @@ + +package mage.cards.t; + +import java.util.UUID; +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.condition.common.IsStepCondition; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.decorator.ConditionalActivatedAbility; +import mage.abilities.effects.common.continuous.LoseAbilityTargetEffect; +import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.abilities.mana.BlueManaAbility; +import mage.constants.SuperType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author L_J + */ +public final class Tolaria extends CardImpl { + + public Tolaria(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + this.addSuperType(SuperType.LEGENDARY); + + // {T}: Add {U}. + this.addAbility(new BlueManaAbility()); + + // {T}: Target creature loses banding and all "bands with other" abilities until end of turn. Activate this ability only during any upkeep step. + ActivatedAbilityImpl ability = new ConditionalActivatedAbility(Zone.BATTLEFIELD, + new LoseAbilityTargetEffect(BandingAbility.getInstance(), Duration.EndOfTurn), new TapSourceCost(), new IsStepCondition(PhaseStep.UPKEEP, false), + "{T}: Target creature loses banding and all \"bands with other\" abilities until end of turn. Activate this ability only during any upkeep step."); + ability.addEffect(new LoseAbilityTargetEffect(new BandsWithOtherAbility(), Duration.EndOfTurn)); + ability.addTarget(new TargetCreaturePermanent()); + this.addAbility(ability); + } + + public Tolaria(final Tolaria card) { + super(card); + } + + @Override + public Tolaria copy() { + return new Tolaria(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TollOfTheInvasion.java b/Mage.Sets/src/mage/cards/t/TollOfTheInvasion.java new file mode 100644 index 0000000000..88a1bf0e13 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TollOfTheInvasion.java @@ -0,0 +1,40 @@ +package mage.cards.t; + +import mage.abilities.effects.common.discard.DiscardCardYouChooseTargetEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TollOfTheInvasion extends CardImpl { + + public TollOfTheInvasion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}"); + + // Target opponent reveals their hand. You choose a nonland card from it. That player discards that card. + this.getSpellAbility().addEffect(new DiscardCardYouChooseTargetEffect( + StaticFilters.FILTER_CARD_NON_LAND, TargetController.OPPONENT + )); + this.getSpellAbility().addTarget(new TargetOpponent()); + + // Amass 1. + this.getSpellAbility().addEffect(new AmassEffect(1)); + } + + private TollOfTheInvasion(final TollOfTheInvasion card) { + super(card); + } + + @Override + public TollOfTheInvasion copy() { + return new TollOfTheInvasion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TolsimirFriendToWolves.java b/Mage.Sets/src/mage/cards/t/TolsimirFriendToWolves.java new file mode 100644 index 0000000000..45f202a641 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TolsimirFriendToWolves.java @@ -0,0 +1,132 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.VojaFriendToElvesToken; +import mage.target.common.TargetOpponentsCreaturePermanent; + +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class TolsimirFriendToWolves extends CardImpl { + + public TolsimirFriendToWolves(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{G}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.ELF); + this.subtype.add(SubType.SCOUT); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Tolsimir, Friend to Wolves enters the battlefield, create Voja, Friend to Elves, a legendary 3/3 green and white Wolf creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new VojaFriendToElvesToken()))); + + // Whenever a Wolf enters the battlefield under your control, you gain 3 life and that creature fights up to one target creature an opponent controls. + this.addAbility(new TolsimirFriendToWolvesTriggeredAbility()); + } + + private TolsimirFriendToWolves(final TolsimirFriendToWolves card) { + super(card); + } + + @Override + public TolsimirFriendToWolves copy() { + return new TolsimirFriendToWolves(this); + } +} + +class TolsimirFriendToWolvesTriggeredAbility extends TriggeredAbilityImpl { + + TolsimirFriendToWolvesTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + this.addTarget(new TargetOpponentsCreaturePermanent(0, 1)); + } + + private TolsimirFriendToWolvesTriggeredAbility(final TolsimirFriendToWolvesTriggeredAbility ability) { + super(ability); + } + + @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()); + if (permanent == null + || !permanent.isControlledBy(getControllerId()) + || !permanent.hasSubtype(SubType.WOLF, game)) { + return false; + } + this.getEffects().clear(); + this.addEffect(new TolsimirFriendToWolvesEffect(new MageObjectReference(permanent, game))); + return true; + } + + @Override + public TolsimirFriendToWolvesTriggeredAbility copy() { + return new TolsimirFriendToWolvesTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever a Wolf enters the battlefield under your control, " + + "you gain 3 life and that creature fights up to one target creature an opponent controls."; + } + +} + +class TolsimirFriendToWolvesEffect extends OneShotEffect { + + private final MageObjectReference wolfMor; + + TolsimirFriendToWolvesEffect(MageObjectReference wolfMor) { + super(Benefit); + this.wolfMor = wolfMor; + } + + private TolsimirFriendToWolvesEffect(final TolsimirFriendToWolvesEffect effect) { + super(effect); + this.wolfMor = effect.wolfMor; + } + + @Override + public TolsimirFriendToWolvesEffect copy() { + return new TolsimirFriendToWolvesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + new GainLifeEffect(3).apply(game, source); + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return true; + } + Permanent wolf = wolfMor.getPermanent(game); + if (wolf == null) { + return false; + } + return wolf.fight(permanent, source, game); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TombOfTheSpiritDragon.java b/Mage.Sets/src/mage/cards/t/TombOfTheSpiritDragon.java index 6f4cebe7c3..5a7d449015 100644 --- a/Mage.Sets/src/mage/cards/t/TombOfTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/t/TombOfTheSpiritDragon.java @@ -25,7 +25,7 @@ public final class TombOfTheSpiritDragon extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("colorless creature you control"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public TombOfTheSpiritDragon(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TomeOfTheGuildpact.java b/Mage.Sets/src/mage/cards/t/TomeOfTheGuildpact.java new file mode 100644 index 0000000000..46f978a713 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TomeOfTheGuildpact.java @@ -0,0 +1,39 @@ +package mage.cards.t; + +import mage.abilities.common.SpellCastControllerTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.mana.AnyColorManaAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TomeOfTheGuildpact extends CardImpl { + + public TomeOfTheGuildpact(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); + + // Whenever you cast a multicolored spell, draw a card. + this.addAbility(new SpellCastControllerTriggeredAbility( + new DrawCardSourceControllerEffect(1), + StaticFilters.FILTER_SPELL_A_MULTICOLORED, false + )); + + // {T}: Add one mana of any color. + this.addAbility(new AnyColorManaAbility()); + } + + private TomeOfTheGuildpact(final TomeOfTheGuildpact card) { + super(card); + } + + @Override + public TomeOfTheGuildpact copy() { + return new TomeOfTheGuildpact(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java b/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java new file mode 100644 index 0000000000..90d1b60e49 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TomikDistinguishedAdvokist.java @@ -0,0 +1,160 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.common.CantBeTargetedAllEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterObject; +import mage.filter.FilterStackObject; +import mage.filter.StaticFilters; +import mage.filter.predicate.Predicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TomikDistinguishedAdvokist extends CardImpl { + + public TomikDistinguishedAdvokist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.HUMAN); + this.subtype.add(SubType.ADVISOR); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Lands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control. + FilterObject filter = new FilterStackObject(); + filter.add(new TargetedByOpponentsPredicate(this.getId())); + Ability ability = new SimpleStaticAbility(new CantBeTargetedAllEffect( + StaticFilters.FILTER_LANDS, filter, Duration.WhileOnBattlefield + ).setText("lands on the battlefield")); + ability.addEffect(new TomikDistinguishedAdvokistTargetEffect()); + this.addAbility(ability); + + // Your opponents can't play land cards from graveyards. + this.addAbility(new SimpleStaticAbility(new TomikDistinguishedAdvokistRestrictionEffect())); + } + + private TomikDistinguishedAdvokist(final TomikDistinguishedAdvokist card) { + super(card); + } + + @Override + public TomikDistinguishedAdvokist copy() { + return new TomikDistinguishedAdvokist(this); + } +} + +class TargetedByOpponentsPredicate implements Predicate { + + private final UUID sourceId; + + public TargetedByOpponentsPredicate(UUID sourceId) { + this.sourceId = sourceId; + } + + @Override + public boolean apply(MageObject input, Game game) { + StackObject stackObject = game.getStack().getStackObject(input.getId()); + Permanent source = game.getPermanentOrLKIBattlefield(this.sourceId); + if (stackObject != null && source != null) { + Player controller = game.getPlayer(source.getControllerId()); + return controller != null && game.isOpponent(controller, stackObject.getControllerId()); + } + return false; + } + + @Override + public String toString() { + return "targeted spells or abilities your opponents control"; + } +} + +class TomikDistinguishedAdvokistTargetEffect extends ContinuousRuleModifyingEffectImpl { + + TomikDistinguishedAdvokistTargetEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "and land cards in graveyards can't be the targets of spells or abilities your opponents control"; + } + + private TomikDistinguishedAdvokistTargetEffect(final TomikDistinguishedAdvokistTargetEffect effect) { + super(effect); + } + + @Override + public TomikDistinguishedAdvokistTargetEffect copy() { + return new TomikDistinguishedAdvokistTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TARGET; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Card targetCard = game.getCard(event.getTargetId()); + StackObject stackObject = game.getStack().getStackObject(event.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + return targetCard != null && stackObject != null && player != null + && player.hasOpponent(stackObject.getControllerId(), game) + && game.getState().getZone(targetCard.getId()) == Zone.GRAVEYARD; + } +} + +class TomikDistinguishedAdvokistRestrictionEffect extends ContinuousRuleModifyingEffectImpl { + + TomikDistinguishedAdvokistRestrictionEffect() { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.staticText = "Your opponents can't play land cards from graveyards"; + } + + private TomikDistinguishedAdvokistRestrictionEffect(final TomikDistinguishedAdvokistRestrictionEffect effect) { + super(effect); + } + + @Override + public TomikDistinguishedAdvokistRestrictionEffect copy() { + return new TomikDistinguishedAdvokistRestrictionEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.PLAY_LAND; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + Player player = game.getPlayer(source.getControllerId()); + return player != null && player.hasOpponent(event.getPlayerId(), game) + && game.getState().getZone(event.getSourceId()) == Zone.GRAVEYARD; + } +} diff --git a/Mage.Sets/src/mage/cards/t/ToothAndNail.java b/Mage.Sets/src/mage/cards/t/ToothAndNail.java index 445320af93..9059f778c3 100644 --- a/Mage.Sets/src/mage/cards/t/ToothAndNail.java +++ b/Mage.Sets/src/mage/cards/t/ToothAndNail.java @@ -33,7 +33,7 @@ public final class ToothAndNail extends CardImpl { this.getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 2, new FilterCreatureCard()), true)); // or put up to two creature cards from your hand onto the battlefield. Mode mode = new Mode(); - mode.getEffects().add(new ToothAndNailPutCreatureOnBattlefieldEffect()); + mode.addEffect(new ToothAndNailPutCreatureOnBattlefieldEffect()); this.getSpellAbility().getModes().addMode(mode); // Entwine {2} diff --git a/Mage.Sets/src/mage/cards/t/ToothCollector.java b/Mage.Sets/src/mage/cards/t/ToothCollector.java index ff87e8bff2..f96313eabb 100644 --- a/Mage.Sets/src/mage/cards/t/ToothCollector.java +++ b/Mage.Sets/src/mage/cards/t/ToothCollector.java @@ -1,7 +1,7 @@ - package mage.cards.t; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -9,6 +9,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -26,7 +27,6 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** - * * @author fireshoes */ public final class ToothCollector extends CardImpl { @@ -38,7 +38,7 @@ public final class ToothCollector extends CardImpl { } public ToothCollector(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(3); @@ -56,6 +56,7 @@ public final class ToothCollector extends CardImpl { DeliriumCondition.instance, "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " + "target creature that player controls gets -1/-1 until end of turn."); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ToothyImaginaryFriend.java b/Mage.Sets/src/mage/cards/t/ToothyImaginaryFriend.java index 80c0823228..7924cb3be6 100644 --- a/Mage.Sets/src/mage/cards/t/ToothyImaginaryFriend.java +++ b/Mage.Sets/src/mage/cards/t/ToothyImaginaryFriend.java @@ -1,11 +1,12 @@ - package mage.cards.t; import java.util.UUID; import mage.MageInt; +import mage.abilities.Ability; import mage.abilities.common.DrawCardControllerTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; -import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.keyword.PartnerWithAbility; @@ -14,7 +15,10 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; +import mage.constants.Zone; import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; /** * @@ -38,7 +42,7 @@ public final class ToothyImaginaryFriend extends CardImpl { // When Toothy leaves the battlefield, draw a card for each +1/+1 counter on it. this.addAbility(new LeavesBattlefieldTriggeredAbility( - new DrawCardSourceControllerEffect(new CountersSourceCount(CounterType.P1P1)) + new DrawCardSourceControllerEffect(new ToothyImaginaryFriendCountersCount(CounterType.P1P1)) .setText("draw a card for each +1/+1 counter on it"), false)); } @@ -51,3 +55,40 @@ public final class ToothyImaginaryFriend extends CardImpl { return new ToothyImaginaryFriend(this); } } + +class ToothyImaginaryFriendCountersCount implements DynamicValue { + + private final String counterName; + + public ToothyImaginaryFriendCountersCount(CounterType counter) { + this.counterName = counter.getName(); + } + + public ToothyImaginaryFriendCountersCount(final ToothyImaginaryFriendCountersCount countersCount) { + this.counterName = countersCount.counterName; + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Permanent permanent = (Permanent) game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.BATTLEFIELD); + if (permanent != null) { + return permanent.getCounters(game).getCount(counterName); + } + return 0; + } + + @Override + public ToothyImaginaryFriendCountersCount copy() { + return new ToothyImaginaryFriendCountersCount(this); + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return counterName + " counter on {this}"; + } +} diff --git a/Mage.Sets/src/mage/cards/t/TopanAscetic.java b/Mage.Sets/src/mage/cards/t/TopanAscetic.java index f4d1de3e1e..402ed8687f 100644 --- a/Mage.Sets/src/mage/cards/t/TopanAscetic.java +++ b/Mage.Sets/src/mage/cards/t/TopanAscetic.java @@ -25,7 +25,7 @@ public final class TopanAscetic extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static{ - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } diff --git a/Mage.Sets/src/mage/cards/t/Topple.java b/Mage.Sets/src/mage/cards/t/Topple.java index 9c888e6de3..40ea412678 100644 --- a/Mage.Sets/src/mage/cards/t/Topple.java +++ b/Mage.Sets/src/mage/cards/t/Topple.java @@ -72,6 +72,9 @@ class ToppleTargetCreature extends TargetCreaturePermanent { List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game); Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); + if(targetSource == null){ + return possibleTargets; + } for (Permanent permanent : activePermanents) { if (permanent.getPower().getValue() > maxPower) { maxPower = permanent.getPower().getValue(); diff --git a/Mage.Sets/src/mage/cards/t/ToppleTheStatue.java b/Mage.Sets/src/mage/cards/t/ToppleTheStatue.java new file mode 100644 index 0000000000..f00e5f258d --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/ToppleTheStatue.java @@ -0,0 +1,68 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ToppleTheStatue extends CardImpl { + + public ToppleTheStatue(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Tap target permanent. If it's an artifact, destroy it. + // Draw a card. + this.getSpellAbility().addEffect(new ToppleTheStatueEffect()); + this.getSpellAbility().addTarget(new TargetPermanent()); + } + + private ToppleTheStatue(final ToppleTheStatue card) { + super(card); + } + + @Override + public ToppleTheStatue copy() { + return new ToppleTheStatue(this); + } +} + +class ToppleTheStatueEffect extends OneShotEffect { + + ToppleTheStatueEffect() { + super(Outcome.Benefit); + staticText = "Tap target permanent. If it's an artifact, destroy it.
    Draw a card."; + } + + private ToppleTheStatueEffect(final ToppleTheStatueEffect effect) { + super(effect); + } + + @Override + public ToppleTheStatueEffect copy() { + return new ToppleTheStatueEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.tap(game); + if (permanent.isArtifact()) { + permanent.destroy(source.getSourceId(), game, false); + } + return new DrawCardSourceControllerEffect(1).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/Topplegeist.java b/Mage.Sets/src/mage/cards/t/Topplegeist.java index daf722048d..4cbff55fb4 100644 --- a/Mage.Sets/src/mage/cards/t/Topplegeist.java +++ b/Mage.Sets/src/mage/cards/t/Topplegeist.java @@ -1,7 +1,7 @@ - package mage.cards.t; import java.util.UUID; + import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; @@ -9,6 +9,7 @@ import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -26,7 +27,6 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; /** - * * @author fireshoes */ public final class Topplegeist extends CardImpl { @@ -38,7 +38,7 @@ public final class Topplegeist extends CardImpl { } public Topplegeist(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.SPIRIT); this.power = new MageInt(1); this.toughness = new MageInt(1); @@ -58,6 +58,7 @@ public final class Topplegeist extends CardImpl { DeliriumCondition.instance, "Delirium — At the beginning of each opponent's upkeep, if there are four or more card types among cards in your graveyard, " + "tap target creature that player controls."); + ability.addHint(DeliriumHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TorchCourier.java b/Mage.Sets/src/mage/cards/t/TorchCourier.java index 24566bcde9..a6588460f4 100644 --- a/Mage.Sets/src/mage/cards/t/TorchCourier.java +++ b/Mage.Sets/src/mage/cards/t/TorchCourier.java @@ -27,7 +27,7 @@ public final class TorchCourier extends CardImpl { = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TorchCourier(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java index 11112392a2..244ba82794 100644 --- a/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java +++ b/Mage.Sets/src/mage/cards/t/TormentOfHailfire.java @@ -1,4 +1,3 @@ - package mage.cards.t; import java.util.UUID; @@ -20,19 +19,19 @@ import mage.target.TargetPermanent; * @author LevelX2 */ public final class TormentOfHailfire extends CardImpl { - + public TormentOfHailfire(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{B}{B}"); // Repeat the following process X times. Each opponent loses 3 life unless he or she sacrifices a nonland permanent or discards a card. this.getSpellAbility().addEffect(new TormentOfHailfireEffect()); - + } - + public TormentOfHailfire(final TormentOfHailfire card) { super(card); } - + @Override public TormentOfHailfire copy() { return new TormentOfHailfire(this); @@ -40,21 +39,21 @@ public final class TormentOfHailfire extends CardImpl { } class TormentOfHailfireEffect extends OneShotEffect { - + public TormentOfHailfireEffect() { super(Outcome.LoseLife); this.staticText = "Repeat the following process X times. Each opponent loses 3 life unless he or she sacrifices a nonland permanent or discards a card"; } - + public TormentOfHailfireEffect(final TormentOfHailfireEffect effect) { super(effect); } - + @Override public TormentOfHailfireEffect copy() { return new TormentOfHailfireEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -68,6 +67,7 @@ class TormentOfHailfireEffect extends OneShotEffect { if (permanents > 0 && opponent.chooseUse(outcome, "Sacrifices a nonland permanent? (Iteration " + i + " of " + repeat + ")", "Otherwise you have to discard a card or lose 3 life.", "Sacrifice", "Discard or life loss", source, game)) { Target target = new TargetPermanent(StaticFilters.FILTER_CONTROLLED_PERMANENT_NON_LAND); + target.setNotTarget(true); if (opponent.choose(outcome, target, source.getSourceId(), game)) { Permanent permanent = game.getPermanent(target.getFirstTarget()); if (permanent != null) { @@ -85,7 +85,7 @@ class TormentOfHailfireEffect extends OneShotEffect { opponent.loseLife(3, game, false); } } - + } return true; } diff --git a/Mage.Sets/src/mage/cards/t/TormentorExarch.java b/Mage.Sets/src/mage/cards/t/TormentorExarch.java index d7d36a1854..968a8f742e 100644 --- a/Mage.Sets/src/mage/cards/t/TormentorExarch.java +++ b/Mage.Sets/src/mage/cards/t/TormentorExarch.java @@ -30,8 +30,8 @@ public final class TormentorExarch extends CardImpl { Ability ability = new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(2, 0, Duration.EndOfTurn), false); ability.addTarget(new TargetCreaturePermanent()); Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(0, -2, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(0, -2, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java index 1dba874cc1..3dff803720 100644 --- a/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java +++ b/Mage.Sets/src/mage/cards/t/ToshiroUmezawa.java @@ -119,11 +119,11 @@ class ToshiroUmezawaReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - UUID eventObject = ((ZoneChangeEvent) event).getTargetId(); + UUID eventObject = event.getTargetId(); StackObject stackObject = game.getStack().getStackObject(eventObject); if (stackObject != null) { if (stackObject instanceof Spell) { - game.rememberLKI(stackObject.getId(), Zone.STACK, (Spell) stackObject); + game.rememberLKI(stackObject.getId(), Zone.STACK, stackObject); } if (stackObject instanceof Card && eventObject.equals(cardId)) { ((Card) stackObject).moveToExile(null, null, source.getSourceId(), game); @@ -142,6 +142,6 @@ class ToshiroUmezawaReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId().equals(cardId); + && event.getTargetId().equals(cardId); } } diff --git a/Mage.Sets/src/mage/cards/t/TotalWar.java b/Mage.Sets/src/mage/cards/t/TotalWar.java index 9527151324..ab124ae9b9 100644 --- a/Mage.Sets/src/mage/cards/t/TotalWar.java +++ b/Mage.Sets/src/mage/cards/t/TotalWar.java @@ -107,7 +107,7 @@ class TotalWarDestroyEffect extends OneShotEffect { continue; } // Creatures that attacked are safe. - AttackedOrBlockedThisCombatWatcher watcher = (AttackedOrBlockedThisCombatWatcher) game.getState().getWatchers().get(AttackedOrBlockedThisCombatWatcher.class.getSimpleName()); + AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class); if (watcher != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { continue; diff --git a/Mage.Sets/src/mage/cards/t/TouchOfMoonglove.java b/Mage.Sets/src/mage/cards/t/TouchOfMoonglove.java index 995385da7d..f7353561b4 100644 --- a/Mage.Sets/src/mage/cards/t/TouchOfMoonglove.java +++ b/Mage.Sets/src/mage/cards/t/TouchOfMoonglove.java @@ -105,7 +105,7 @@ class TouchOfMoongloveDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD + if (zEvent.isDiesEvent() && zEvent.getTarget().isCreature()) { boolean damageDealt = false; for (MageObjectReference mor : zEvent.getTarget().getDealtDamageByThisTurn()) { diff --git a/Mage.Sets/src/mage/cards/t/TourachsGate.java b/Mage.Sets/src/mage/cards/t/TourachsGate.java index ac99921086..72912a4b95 100644 --- a/Mage.Sets/src/mage/cards/t/TourachsGate.java +++ b/Mage.Sets/src/mage/cards/t/TourachsGate.java @@ -53,12 +53,12 @@ public final class TourachsGate extends CardImpl { private static final FilterPermanent filterUntapped = new FilterPermanent("enchanted land is untapped"); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } private static final FilterCreaturePermanent filterAttackingCreatures = new FilterCreaturePermanent("attacking creatures you control"); static { - filterAttackingCreatures.add(new AttackingPredicate()); + filterAttackingCreatures.add(AttackingPredicate.instance); filterAttackingCreatures.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/t/TowerDefense.java b/Mage.Sets/src/mage/cards/t/TowerDefense.java index 659efcdee4..9cf9e70bd7 100644 --- a/Mage.Sets/src/mage/cards/t/TowerDefense.java +++ b/Mage.Sets/src/mage/cards/t/TowerDefense.java @@ -1,39 +1,33 @@ - package mage.cards.t; -import java.util.UUID; -import mage.abilities.effects.common.continuous.BoostAllEffect; -import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.constants.TargetController; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.ControllerPredicate; + +import java.util.UUID; /** - * * @author Plopman */ public final class TowerDefense extends CardImpl { - - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control"); - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } public TowerDefense(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Creatures you control get +0/+5 and gain reach until end of turn. - this.getSpellAbility().addEffect(new BoostAllEffect(0, 5, Duration.EndOfTurn, filter , false)); - this.getSpellAbility().addEffect(new GainAbilityAllEffect(ReachAbility.getInstance(), Duration.EndOfTurn, filter)); + this.getSpellAbility().addEffect(new BoostControlledEffect( + 0, 5, Duration.EndOfTurn + ).setText("creatures you control get +0/+5")); + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + ReachAbility.getInstance(), Duration.EndOfTurn + ).setText("and gain reach until end of turn")); } - public TowerDefense(final TowerDefense card) { + private TowerDefense(final TowerDefense card) { super(card); } diff --git a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java index 8d53546072..b0b6c94785 100644 --- a/Mage.Sets/src/mage/cards/t/TownGossipmonger.java +++ b/Mage.Sets/src/mage/cards/t/TownGossipmonger.java @@ -28,7 +28,7 @@ public final class TownGossipmonger extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public TownGossipmonger(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/ToxicDeluge.java b/Mage.Sets/src/mage/cards/t/ToxicDeluge.java index b3f9b3e9e4..ec64b49f4f 100644 --- a/Mage.Sets/src/mage/cards/t/ToxicDeluge.java +++ b/Mage.Sets/src/mage/cards/t/ToxicDeluge.java @@ -26,7 +26,7 @@ public final class ToxicDeluge extends CardImpl { // As an additional cost to cast Toxic Deluge, pay X life. this.getSpellAbility().addCost(new PayVariableLifeCost(true)); // All creatures get -X/-X until end of turn. - DynamicValue xValue = new SignInversionDynamicValue(new GetXValue()); + DynamicValue xValue = new SignInversionDynamicValue(GetXValue.instance); this.getSpellAbility().addEffect(new BoostAllEffect(xValue, xValue, Duration.EndOfTurn, new FilterCreaturePermanent("All creatures"), false, null, true)); } diff --git a/Mage.Sets/src/mage/cards/t/TraceOfAbundance.java b/Mage.Sets/src/mage/cards/t/TraceOfAbundance.java index 3b01224026..361826e348 100644 --- a/Mage.Sets/src/mage/cards/t/TraceOfAbundance.java +++ b/Mage.Sets/src/mage/cards/t/TraceOfAbundance.java @@ -1,23 +1,17 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.mana.AddManaAnyColorAttachedControllerEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; +import mage.abilities.effects.mana.AddManaAnyColorAttachedControllerEffect; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.ShroudAbility; import mage.abilities.mana.TriggeredManaAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -25,16 +19,17 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class TraceOfAbundance extends CardImpl { - private String rule = "Enchanted land has shroud"; + private static final String rule = "Enchanted land has shroud"; public TraceOfAbundance(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{R/W}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{R/W}{G}"); this.subtype.add(SubType.AURA); // Enchant land diff --git a/Mage.Sets/src/mage/cards/t/TradewindRider.java b/Mage.Sets/src/mage/cards/t/TradewindRider.java index d2e39d8ab5..794922dfec 100644 --- a/Mage.Sets/src/mage/cards/t/TradewindRider.java +++ b/Mage.Sets/src/mage/cards/t/TradewindRider.java @@ -28,7 +28,7 @@ public final class TradewindRider extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creatures you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public TradewindRider(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TrailOfMystery.java b/Mage.Sets/src/mage/cards/t/TrailOfMystery.java index 767196131c..544fb5147a 100644 --- a/Mage.Sets/src/mage/cards/t/TrailOfMystery.java +++ b/Mage.Sets/src/mage/cards/t/TrailOfMystery.java @@ -27,7 +27,7 @@ public final class TrailOfMystery extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a face-down creature"); static { - filter.add(new FaceDownPredicate()); + filter.add(FaceDownPredicate.instance); } public TrailOfMystery(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TrainedCondor.java b/Mage.Sets/src/mage/cards/t/TrainedCondor.java index 5e81c9de5d..b9e4259faa 100644 --- a/Mage.Sets/src/mage/cards/t/TrainedCondor.java +++ b/Mage.Sets/src/mage/cards/t/TrainedCondor.java @@ -26,7 +26,7 @@ public final class TrainedCondor extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TrainedCondor(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}"); diff --git a/Mage.Sets/src/mage/cards/t/TrainingDrone.java b/Mage.Sets/src/mage/cards/t/TrainingDrone.java index 6b56d1a7fd..50c94111a3 100644 --- a/Mage.Sets/src/mage/cards/t/TrainingDrone.java +++ b/Mage.Sets/src/mage/cards/t/TrainingDrone.java @@ -1,8 +1,5 @@ - package mage.cards.t; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,20 +7,22 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.List; +import java.util.UUID; + /** - * * @author North */ public final class TrainingDrone extends CardImpl { public TrainingDrone(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{3}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}"); this.subtype.add(SubType.DRONE); this.power = new MageInt(4); @@ -71,12 +70,12 @@ class TrainingDroneEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TrainingGrounds.java b/Mage.Sets/src/mage/cards/t/TrainingGrounds.java index 8a3b02c03a..663138e691 100644 --- a/Mage.Sets/src/mage/cards/t/TrainingGrounds.java +++ b/Mage.Sets/src/mage/cards/t/TrainingGrounds.java @@ -1,9 +1,6 @@ package mage.cards.t; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; @@ -12,20 +9,17 @@ import mage.abilities.effects.common.cost.CostModificationEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.choices.ChoiceImpl; -import mage.constants.AbilityType; -import mage.constants.CardType; -import mage.constants.CostModificationType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author maurer.it_at_gmail.com */ public final class TrainingGrounds extends CardImpl { @@ -49,15 +43,15 @@ public final class TrainingGrounds extends CardImpl { class TrainingGroundsEffect extends CostModificationEffectImpl { - private static final String effectText = "Activated abilities of creatures you control cost up to {2} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana"; - private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + private static final String effectText = "Activated abilities of creatures you control cost {2} less to activate. " + + "This effect can't reduce the amount of mana an ability costs to activate to less than one mana"; - public TrainingGroundsEffect() { + TrainingGroundsEffect() { super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); staticText = effectText; } - public TrainingGroundsEffect(final TrainingGroundsEffect effect) { + private TrainingGroundsEffect(final TrainingGroundsEffect effect) { super(effect); } @@ -100,7 +94,7 @@ class TrainingGroundsEffect extends CostModificationEffectImpl { || (abilityToModify.getAbilityType() == AbilityType.MANA && (abilityToModify instanceof ActivatedAbility))) { //Activated abilities of creatures you control Permanent permanent = game.getPermanent(abilityToModify.getSourceId()); - if (permanent != null && filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + if (permanent != null && permanent.isControlledBy(source.getControllerId())) { return true; } } diff --git a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java index 460722bc43..2201993bec 100644 --- a/Mage.Sets/src/mage/cards/t/TraitorsRoar.java +++ b/Mage.Sets/src/mage/cards/t/TraitorsRoar.java @@ -26,7 +26,7 @@ public final class TraitorsRoar extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("untapped creature"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public TraitorsRoar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TranquilGrove.java b/Mage.Sets/src/mage/cards/t/TranquilGrove.java index c8f3a0a629..7687d4b236 100644 --- a/Mage.Sets/src/mage/cards/t/TranquilGrove.java +++ b/Mage.Sets/src/mage/cards/t/TranquilGrove.java @@ -22,7 +22,7 @@ public final class TranquilGrove extends CardImpl { private static final FilterPermanent filter = new FilterEnchantmentPermanent("other enchantments"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public TranquilGrove(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TransguildCourier.java b/Mage.Sets/src/mage/cards/t/TransguildCourier.java index b480250f6b..2161aa0e94 100644 --- a/Mage.Sets/src/mage/cards/t/TransguildCourier.java +++ b/Mage.Sets/src/mage/cards/t/TransguildCourier.java @@ -1,30 +1,34 @@ package mage.cards.t; -import java.util.UUID; import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.InfoEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.Zone; + +import java.util.UUID; /** - * * @author Wehk */ public final class TransguildCourier extends CardImpl { public TransguildCourier(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.GOLEM); this.power = new MageInt(3); this.toughness = new MageInt(3); - + this.color.setWhite(true); this.color.setBlue(true); this.color.setBlack(true); this.color.setRed(true); this.color.setGreen(true); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new InfoEffect("{this} is all colors"))); } public TransguildCourier(final TransguildCourier card) { diff --git a/Mage.Sets/src/mage/cards/t/TransguildPromenade.java b/Mage.Sets/src/mage/cards/t/TransguildPromenade.java index ff55723a9a..856480fe33 100644 --- a/Mage.Sets/src/mage/cards/t/TransguildPromenade.java +++ b/Mage.Sets/src/mage/cards/t/TransguildPromenade.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.common.EntersBattlefieldTappedAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.costs.mana.GenericManaCost; @@ -11,18 +9,24 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import java.util.UUID; + /** * @author LevelX2 */ public final class TransguildPromenade extends CardImpl { public TransguildPromenade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.LAND},""); + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); // Transguild Promenade enters the battlefield tapped. this.addAbility(new EntersBattlefieldTappedAbility()); + // When Transguild Promenade enters the battlefield, sacrifice it unless you pay {1}. - this.addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1)))); + this.addAbility(new EntersBattlefieldTriggeredAbility( + new SacrificeSourceUnlessPaysEffect(new GenericManaCost(1)).setText("sacrifice it unless you pay {1}") + )); + // {T}: Add one mana of any color. this.addAbility(new AnyColorManaAbility()); } diff --git a/Mage.Sets/src/mage/cards/t/TransmuteArtifact.java b/Mage.Sets/src/mage/cards/t/TransmuteArtifact.java index 416828bc92..5c781ad298 100644 --- a/Mage.Sets/src/mage/cards/t/TransmuteArtifact.java +++ b/Mage.Sets/src/mage/cards/t/TransmuteArtifact.java @@ -78,7 +78,7 @@ class TransmuteArtifactEffect extends SearchEffect { return true; } //If you do, search your library for an artifact card. - if (sacrifice && controller.searchLibrary(target, game)) { + if (sacrifice && controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { for (UUID cardId : target.getTargets()) { Card card = controller.getLibrary().getCard(cardId, game); diff --git a/Mage.Sets/src/mage/cards/t/TrapRunner.java b/Mage.Sets/src/mage/cards/t/TrapRunner.java index 54f0da4cd4..6d4b06b2f5 100644 --- a/Mage.Sets/src/mage/cards/t/TrapRunner.java +++ b/Mage.Sets/src/mage/cards/t/TrapRunner.java @@ -36,8 +36,8 @@ public final class TrapRunner extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked attacking creature"); static { - filter.add(new AttackingPredicate()); - filter.add(Predicates.not(new BlockedPredicate())); + filter.add(AttackingPredicate.instance); + filter.add(Predicates.not(BlockedPredicate.instance)); } public TrapRunner(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TrapjawTyrant.java b/Mage.Sets/src/mage/cards/t/TrapjawTyrant.java index dbe78a6668..c1ad6180aa 100644 --- a/Mage.Sets/src/mage/cards/t/TrapjawTyrant.java +++ b/Mage.Sets/src/mage/cards/t/TrapjawTyrant.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class TrapjawTyrant extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/t/TravelingPlague.java b/Mage.Sets/src/mage/cards/t/TravelingPlague.java index d079c2c44b..fdc09f1d2c 100644 --- a/Mage.Sets/src/mage/cards/t/TravelingPlague.java +++ b/Mage.Sets/src/mage/cards/t/TravelingPlague.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; @@ -18,12 +16,7 @@ import mage.abilities.keyword.EnchantAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.counters.CounterType; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; @@ -34,8 +27,9 @@ import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class TravelingPlague extends CardImpl { @@ -130,10 +124,10 @@ class TravelingPlagueEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card travelingPlague = game.getCard(source.getSourceId()); Permanent enchantedCreature = (Permanent) game.getState().getValue("travelingPlague" + source.getSourceId()); if (enchantedCreature != null) { Player controllerOfEnchantedCreature = game.getPlayer(enchantedCreature.getControllerId()); + Card travelingPlague = game.getCard(source.getSourceId()); if (travelingPlague != null && game.getState().getZone(travelingPlague.getId()) == Zone.GRAVEYARD // aura must come from the graveyard && controllerOfEnchantedCreature != null) { diff --git a/Mage.Sets/src/mage/cards/t/TraverseTheOutlands.java b/Mage.Sets/src/mage/cards/t/TraverseTheOutlands.java index 0fc284773f..bf4c0b41ea 100644 --- a/Mage.Sets/src/mage/cards/t/TraverseTheOutlands.java +++ b/Mage.Sets/src/mage/cards/t/TraverseTheOutlands.java @@ -78,7 +78,7 @@ class TraverseTheOutlandsEffect extends OneShotEffect { } TargetCardInLibrary target = new TargetCardInLibrary(0, amount, StaticFilters.FILTER_CARD_BASIC_LAND); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { controller.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); } controller.shuffleLibrary(source, game); diff --git a/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java b/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java index 06864b369a..33285349e6 100644 --- a/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java +++ b/Mage.Sets/src/mage/cards/t/TraverseTheUlvenwald.java @@ -1,10 +1,10 @@ - package mage.cards.t; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -17,7 +17,6 @@ import mage.target.common.TargetCardInLibrary; import java.util.UUID; /** - * * @author fireshoes */ public final class TraverseTheUlvenwald extends CardImpl { @@ -29,7 +28,7 @@ public final class TraverseTheUlvenwald extends CardImpl { } public TraverseTheUlvenwald(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{G}"); // Search your library for a basic land card, reveal it, put it into your hand, then shuffle your library. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( @@ -44,6 +43,7 @@ public final class TraverseTheUlvenwald extends CardImpl { DeliriumCondition.instance, "
    Delirium — If there are four or more card types among cards in your graveyard, instead search your library for a creature or land card, " + "reveal it, put it into your hand, then shuffle your library.")); + this.getSpellAbility().addHint(DeliriumHint.instance); } public TraverseTheUlvenwald(final TraverseTheUlvenwald card) { diff --git a/Mage.Sets/src/mage/cards/t/TreasureNabber.java b/Mage.Sets/src/mage/cards/t/TreasureNabber.java index 9a62b20545..ba23895c9d 100644 --- a/Mage.Sets/src/mage/cards/t/TreasureNabber.java +++ b/Mage.Sets/src/mage/cards/t/TreasureNabber.java @@ -1,21 +1,12 @@ package mage.cards.t; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; @@ -23,8 +14,10 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTargets; +import java.util.List; +import java.util.UUID; + /** - * * @author spjspj */ public final class TreasureNabber extends CardImpl { @@ -92,21 +85,10 @@ class TreasureNabberAbility extends TriggeredAbilityImpl { class TreasureNabberEffect extends ContinuousEffectImpl { protected FixedTargets fixedTargets; - protected int startingTurn; TreasureNabberEffect() { - super(Duration.Custom, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); + super(Duration.UntilEndOfYourNextTurn, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); this.staticText = "gain control of that artifact until the end of your next turn"; - startingTurn = 0; - } - - @Override - public void init(Ability source, Game game) { - super.init(source, game); - startingTurn = game.getTurnNum(); - if (game.getPhase().getStep().getType() == PhaseStep.END_TURN) { - startingTurn = game.getTurnNum() + 1; - } } TreasureNabberEffect(final TreasureNabberEffect effect) { @@ -119,16 +101,6 @@ class TreasureNabberEffect extends ContinuousEffectImpl { return new TreasureNabberEffect(this); } - @Override - public boolean isInactive(Ability source, Game game) { - if (startingTurn != 0 && game.getTurnNum() >= startingTurn && game.getPhase().getStep().getType() == PhaseStep.END_TURN) { - if (game.isActivePlayer(source.getControllerId())) { - return true; - } - } - return false; - } - @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); diff --git a/Mage.Sets/src/mage/cards/t/TreefolkSeedlings.java b/Mage.Sets/src/mage/cards/t/TreefolkSeedlings.java index 46e8aa7f4f..94bc6cf9f1 100644 --- a/Mage.Sets/src/mage/cards/t/TreefolkSeedlings.java +++ b/Mage.Sets/src/mage/cards/t/TreefolkSeedlings.java @@ -21,7 +21,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public final class TreefolkSeedlings extends CardImpl { - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); diff --git a/Mage.Sets/src/mage/cards/t/TreetopBracers.java b/Mage.Sets/src/mage/cards/t/TreetopBracers.java index a1bcb1f242..b92dd5f7dd 100644 --- a/Mage.Sets/src/mage/cards/t/TreetopBracers.java +++ b/Mage.Sets/src/mage/cards/t/TreetopBracers.java @@ -1,6 +1,5 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.RestrictionEffect; @@ -17,10 +16,10 @@ import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Jason E. Wall - * */ public final class TreetopBracers extends CardImpl { @@ -67,15 +66,13 @@ class TreetopBracersRestrictEffect extends RestrictionEffect { Permanent equipment = game.getPermanent(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { Permanent equipped = game.getPermanent(equipment.getAttachedTo()); - if (permanent != null && permanent.getId().equals(equipped.getId())) { - return true; - } + return permanent != null && permanent.getId().equals(equipped.getId()); } return false; } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().contains(FlyingAbility.getInstance()) || blocker.getAbilities().contains(ReachAbility.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/t/TreetopRangers.java b/Mage.Sets/src/mage/cards/t/TreetopRangers.java index 647b8b9934..63f331dea0 100644 --- a/Mage.Sets/src/mage/cards/t/TreetopRangers.java +++ b/Mage.Sets/src/mage/cards/t/TreetopRangers.java @@ -22,7 +22,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class TreetopRangers extends CardImpl { - private final static FilterCreaturePermanent onlyFlyingCreatures = new FilterCreaturePermanent("except by creatures with flying"); + private static final FilterCreaturePermanent onlyFlyingCreatures = new FilterCreaturePermanent("except by creatures with flying"); static { onlyFlyingCreatures.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); diff --git a/Mage.Sets/src/mage/cards/t/TreetopScout.java b/Mage.Sets/src/mage/cards/t/TreetopScout.java index ea02bc2b9e..52068cc52f 100644 --- a/Mage.Sets/src/mage/cards/t/TreetopScout.java +++ b/Mage.Sets/src/mage/cards/t/TreetopScout.java @@ -22,7 +22,7 @@ import mage.filter.predicate.mageobject.AbilityPredicate; */ public final class TreetopScout extends CardImpl { - private final static FilterCreaturePermanent onlyFlyingCreatures = new FilterCreaturePermanent("except by creatures with flying"); + private static final FilterCreaturePermanent onlyFlyingCreatures = new FilterCreaturePermanent("except by creatures with flying"); static { onlyFlyingCreatures.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); diff --git a/Mage.Sets/src/mage/cards/t/TreetopWarden.java b/Mage.Sets/src/mage/cards/t/TreetopWarden.java new file mode 100644 index 0000000000..2b4b7d2b30 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TreetopWarden.java @@ -0,0 +1,32 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class TreetopWarden extends CardImpl { + + public TreetopWarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); + this.subtype.add(SubType.ELF, SubType.WARRIOR); + + this.power = new MageInt(2); + this.toughness = new MageInt(2); + } + + public TreetopWarden(final TreetopWarden card) { + super(card); + } + + @Override + public TreetopWarden copy() { + return new TreetopWarden(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TrenchGorger.java b/Mage.Sets/src/mage/cards/t/TrenchGorger.java index fd5692290f..6b2b53ec04 100644 --- a/Mage.Sets/src/mage/cards/t/TrenchGorger.java +++ b/Mage.Sets/src/mage/cards/t/TrenchGorger.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -11,25 +9,21 @@ import mage.abilities.keyword.TrampleAbility; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TrenchGorger extends CardImpl { public TrenchGorger(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{6}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{6}{U}{U}"); this.subtype.add(SubType.LEVIATHAN); this.power = new MageInt(6); @@ -77,8 +71,10 @@ class TrenchGorgerEffect extends OneShotEffect { int count = 0; for (UUID cardId : target.getTargets()) { Card card = game.getCard(cardId); - controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true); - count++; + if (card != null) { + controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.LIBRARY, true); + count++; + } } controller.shuffleLibrary(source, game); game.addEffect(new SetPowerToughnessSourceEffect(count, count, Duration.EndOfGame, SubLayer.SetPT_7b), source); diff --git a/Mage.Sets/src/mage/cards/t/TrespassersCurse.java b/Mage.Sets/src/mage/cards/t/TrespassersCurse.java index 49b3dbdc6a..7e84ea248e 100644 --- a/Mage.Sets/src/mage/cards/t/TrespassersCurse.java +++ b/Mage.Sets/src/mage/cards/t/TrespassersCurse.java @@ -86,7 +86,7 @@ class TrespassersCurseTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever a creature enters the battlefield under enchanted player's control, ").append(super.getRule()).toString(); + return "Whenever a creature enters the battlefield under enchanted player's control, " + super.getRule(); } @Override @@ -116,7 +116,7 @@ class TrespassersCurseEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controllerOfCreature = game.getPlayer(this.getTargetPointer().getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - if (controllerOfCreature != null) { + if (controllerOfCreature != null && controller != null) { controllerOfCreature.loseLife(1, game, false); controller.gainLife(1, game, source); return true; diff --git a/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java b/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java index 67c34ed9bb..4134a6ffbf 100644 --- a/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java +++ b/Mage.Sets/src/mage/cards/t/TrevaTheRenewer.java @@ -75,7 +75,7 @@ class TrevaTheRenewerEffect extends OneShotEffect { } ChoiceColor choice = new ChoiceColor(); if (controller.choose(outcome, choice, game)) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" chooses ").append(choice.getColor()).toString()); + game.informPlayers(controller.getLogName() + " chooses " + choice.getColor()); FilterPermanent filter = new FilterPermanent(); filter.add(new ColorPredicate(choice.getColor())); int cardsWithColor = game.getBattlefield().count(filter, source.getSourceId(), controller.getId(), game); diff --git a/Mage.Sets/src/mage/cards/t/TrevasCharm.java b/Mage.Sets/src/mage/cards/t/TrevasCharm.java index 20a1418af0..d4ea792153 100644 --- a/Mage.Sets/src/mage/cards/t/TrevasCharm.java +++ b/Mage.Sets/src/mage/cards/t/TrevasCharm.java @@ -27,13 +27,13 @@ public final class TrevasCharm extends CardImpl { // or exile target attacking creature; Mode mode = new Mode(); - mode.getEffects().add(new ExileTargetEffect()); - mode.getTargets().add(new TargetAttackingCreature()); + mode.addEffect(new ExileTargetEffect()); + mode.addTarget(new TargetAttackingCreature()); this.getSpellAbility().addMode(mode); // or draw a card, then discard a card. mode = new Mode(); - mode.getEffects().add(new DrawDiscardControllerEffect()); + mode.addEffect(new DrawDiscardControllerEffect()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/TriadOfFates.java b/Mage.Sets/src/mage/cards/t/TriadOfFates.java index c77fe608b6..472b1da334 100644 --- a/Mage.Sets/src/mage/cards/t/TriadOfFates.java +++ b/Mage.Sets/src/mage/cards/t/TriadOfFates.java @@ -39,7 +39,7 @@ public final class TriadOfFates extends CardImpl { private static final FilterCreaturePermanent filterCounter = new FilterCreaturePermanent("creature that has a fate counter on it"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filterCounter.add(new CounterPredicate(CounterType.FATE)); } diff --git a/Mage.Sets/src/mage/cards/t/TrialError.java b/Mage.Sets/src/mage/cards/t/TrialError.java index a27bd50f60..490b6b3f2e 100644 --- a/Mage.Sets/src/mage/cards/t/TrialError.java +++ b/Mage.Sets/src/mage/cards/t/TrialError.java @@ -32,7 +32,7 @@ public final class TrialError extends SplitCard { private static final FilterSpell filter = new FilterSpell("multicolored spell"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public TrialError(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TriassicEgg.java b/Mage.Sets/src/mage/cards/t/TriassicEgg.java index 473393daf3..cd4ff60832 100644 --- a/Mage.Sets/src/mage/cards/t/TriassicEgg.java +++ b/Mage.Sets/src/mage/cards/t/TriassicEgg.java @@ -47,9 +47,9 @@ public final class TriassicEgg extends CardImpl { // or return target creature card from your graveyard to the battlefield. Activate this ability only if two or more hatchling counters are on Triassic Egg. Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToBattlefieldTargetEffect()); + mode.addEffect(new ReturnFromGraveyardToBattlefieldTargetEffect()); Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD); - mode.getTargets().add(target); + mode.addTarget(target); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/t/TribalUnity.java b/Mage.Sets/src/mage/cards/t/TribalUnity.java index bb468b356d..8d03dd0471 100644 --- a/Mage.Sets/src/mage/cards/t/TribalUnity.java +++ b/Mage.Sets/src/mage/cards/t/TribalUnity.java @@ -30,7 +30,7 @@ public final class TribalUnity extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{2}{G}"); // Creatures of the creature type of your choice get +X/+X until end of turn. - this.getSpellAbility().addEffect(new TribalUnityEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new TribalUnityEffect(ManacostVariableValue.instance)); } public TribalUnity(final TribalUnity card) { diff --git a/Mage.Sets/src/mage/cards/t/Trickbind.java b/Mage.Sets/src/mage/cards/t/Trickbind.java index 4baf9227c9..46619fded7 100644 --- a/Mage.Sets/src/mage/cards/t/Trickbind.java +++ b/Mage.Sets/src/mage/cards/t/Trickbind.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; @@ -17,14 +15,15 @@ import mage.game.stack.StackObject; import mage.target.common.TargetActivatedOrTriggeredAbility; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Trickbind extends CardImpl { public Trickbind(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Split second @@ -64,7 +63,7 @@ class TrickbindCounterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { StackObject stackObject = game.getStack().getStackObject(source.getFirstTarget()); - if(stackObject != null && game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { + if (stackObject != null && game.getStack().counter(source.getFirstTarget(), source.getSourceId(), game)) { TrickbindCantActivateEffect effect = new TrickbindCantActivateEffect(); effect.setTargetPointer(new FixedTarget(stackObject.getSourceId())); game.getContinuousEffects().addEffect(effect, source); @@ -92,7 +91,7 @@ class TrickbindCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/t/TrickeryCharm.java b/Mage.Sets/src/mage/cards/t/TrickeryCharm.java index 610317ade8..9b46bd3d8d 100644 --- a/Mage.Sets/src/mage/cards/t/TrickeryCharm.java +++ b/Mage.Sets/src/mage/cards/t/TrickeryCharm.java @@ -27,12 +27,12 @@ public final class TrickeryCharm extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or target creature becomes the creature type of your choice until end of turn Mode mode = new Mode(); - mode.getEffects().add(new BecomesChosenCreatureTypeTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BecomesChosenCreatureTypeTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or look at the top four cards of your library, then put them back in any order. mode = new Mode(); - mode.getEffects().add(new LookLibraryControllerEffect(4)); + mode.addEffect(new LookLibraryControllerEffect(4)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java index 35fd5e92f8..878f22d48b 100644 --- a/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java +++ b/Mage.Sets/src/mage/cards/t/Triskaidekaphobia.java @@ -28,7 +28,7 @@ public final class Triskaidekaphobia extends CardImpl { // Each player with exactly 13 life loses the game, then each player loses 1 life. Ability ability = new BeginningOfUpkeepTriggeredAbility(new TriskaidekaphobiaGainLifeEffect(), TargetController.YOU, false); Mode mode = new Mode(); - mode.getEffects().add(new TriskaidekaphobiaLoseLifeEffect()); + mode.addEffect(new TriskaidekaphobiaLoseLifeEffect()); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/t/TritonTactics.java b/Mage.Sets/src/mage/cards/t/TritonTactics.java index 1823c39c19..f5f5a68fb8 100644 --- a/Mage.Sets/src/mage/cards/t/TritonTactics.java +++ b/Mage.Sets/src/mage/cards/t/TritonTactics.java @@ -164,7 +164,7 @@ class TritonTacticsEndOfCombatEffect extends OneShotEffect { // tap creature and add the not untap effect creature.tap(game); doNotUntapNextUntapStep.add(creature); - game.informPlayers(new StringBuilder("Triton Tactics: ").append(creature.getName()).append(" doesn't untap during its controller's next untap step").toString()); + game.informPlayers("Triton Tactics: " + creature.getName() + " doesn't untap during its controller's next untap step"); } } if (!doNotUntapNextUntapStep.isEmpty()) { @@ -185,7 +185,7 @@ class TritonTacticsEndOfCombatEffect extends OneShotEffect { class BlockedCreaturesWatcher extends Watcher { public BlockedCreaturesWatcher() { - super("BlockedCreatures", WatcherScope.CARD); + super(WatcherScope.CARD); } public BlockedCreaturesWatcher(final BlockedCreaturesWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java b/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java index f9c97e72b3..91364091eb 100644 --- a/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java +++ b/Mage.Sets/src/mage/cards/t/TriumphOfGerrard.java @@ -107,6 +107,9 @@ class TriumphOfGerrardTargetCreature extends TargetControlledCreaturePermanent { List activePermanents = game.getBattlefield().getActivePermanents(filter, sourceControllerId, sourceId, game); Set possibleTargets = new HashSet<>(); MageObject targetSource = game.getObject(sourceId); + if(targetSource == null){ + return possibleTargets; + } for (Permanent permanent : activePermanents) { if (permanent.getPower().getValue() > maxPower) { maxPower = permanent.getPower().getValue(); diff --git a/Mage.Sets/src/mage/cards/t/TrollbredGuardian.java b/Mage.Sets/src/mage/cards/t/TrollbredGuardian.java new file mode 100644 index 0000000000..cd19748370 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrollbredGuardian.java @@ -0,0 +1,64 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.CounterPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrollbredGuardian extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + } + + public TrollbredGuardian(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.TROLL); + this.subtype.add(SubType.FROG); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(5); + this.toughness = new MageInt(5); + + // {2}{G}: Adapt 2. + this.addAbility(new AdaptAbility(2, "{2}{G}")); + + // Each creature you control with a +1/+1 counter on it has trample. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAllEffect( + TrampleAbility.getInstance(), + Duration.WhileOnBattlefield, + filter, "Each creature you control " + + "with a +1/+1 counter on it has trample" + ) + )); + } + + private TrollbredGuardian(final TrollbredGuardian card) { + super(card); + } + + @Override + public TrollbredGuardian copy() { + return new TrollbredGuardian(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Tromokratis.java b/Mage.Sets/src/mage/cards/t/Tromokratis.java index 6c40ba960b..9590fd92d3 100644 --- a/Mage.Sets/src/mage/cards/t/Tromokratis.java +++ b/Mage.Sets/src/mage/cards/t/Tromokratis.java @@ -1,9 +1,5 @@ - package mage.cards.t; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -24,8 +20,11 @@ import mage.game.Game; import mage.game.combat.CombatGroup; import mage.game.permanent.Permanent; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Tromokratis extends CardImpl { @@ -78,7 +77,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { // check if all creatures of defender are able to block this permanent // permanent.canBlock() can't be used because causing recursive call for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, blocker.getControllerId(), game)) { @@ -88,7 +87,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect { // check blocker restrictions for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).entrySet()) { for (Ability ability : entry.getValue()) { - if (!entry.getKey().canBlock(attacker, permanent, ability, game)) { + if (!entry.getKey().canBlock(attacker, permanent, ability, game, canUseChooseDialogs)) { return false; } } @@ -97,7 +96,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect { for (Map.Entry> restrictionEntry : game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) { for (Ability ability : restrictionEntry.getValue()) { if (!(restrictionEntry.getKey() instanceof CantBeBlockedUnlessAllEffect) - && !restrictionEntry.getKey().canBeBlocked(attacker, permanent, ability, game)) { + && !restrictionEntry.getKey().canBeBlocked(attacker, permanent, ability, game, canUseChooseDialogs)) { return false; } } @@ -110,7 +109,7 @@ class CantBeBlockedUnlessAllEffect extends RestrictionEffect { } @Override - public boolean canBeBlockedCheckAfter(Permanent attacker, Ability source, Game game) { + public boolean canBeBlockedCheckAfter(Permanent attacker, Ability source, Game game, boolean canUseChooseDialogs) { for (CombatGroup combatGroup : game.getCombat().getGroups()) { if (combatGroup.getAttackers().contains(source.getSourceId())) { for (UUID blockerId : combatGroup.getBlockers()) { diff --git a/Mage.Sets/src/mage/cards/t/TropicalStorm.java b/Mage.Sets/src/mage/cards/t/TropicalStorm.java index b85d7c05d0..0178952b1a 100644 --- a/Mage.Sets/src/mage/cards/t/TropicalStorm.java +++ b/Mage.Sets/src/mage/cards/t/TropicalStorm.java @@ -31,7 +31,7 @@ public final class TropicalStorm extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}"); // Tropical Storm deals X damage to each creature with flying and 1 additional damage to each blue creature. - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filter)); this.getSpellAbility().addEffect(new DamageAllEffect(1, filter2).setText("and 1 additional damage to each blue creature")); } diff --git a/Mage.Sets/src/mage/cards/t/TrostaniSelesnyasVoice.java b/Mage.Sets/src/mage/cards/t/TrostaniSelesnyasVoice.java index 5d1a729b30..d6ff2a36a3 100644 --- a/Mage.Sets/src/mage/cards/t/TrostaniSelesnyasVoice.java +++ b/Mage.Sets/src/mage/cards/t/TrostaniSelesnyasVoice.java @@ -77,7 +77,8 @@ class TrostaniSelesnyasVoiceTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent.isCreature() + if (permanent != null + && permanent.isCreature() && permanent.isControlledBy(this.controllerId) && !Objects.equals(event.getTargetId(), this.getSourceId())) { Effect effect = this.getEffects().get(0); diff --git a/Mage.Sets/src/mage/cards/t/TrustedPegasus.java b/Mage.Sets/src/mage/cards/t/TrustedPegasus.java new file mode 100644 index 0000000000..612d7f6fde --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TrustedPegasus.java @@ -0,0 +1,62 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +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.filter.FilterPermanent; +import mage.filter.common.FilterAttackingCreature; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TrustedPegasus extends CardImpl { + + private static final FilterPermanent filter + = new FilterAttackingCreature("attacking creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public TrustedPegasus(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); + + this.subtype.add(SubType.PEGASUS); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Whenever Trusted Pegasus attacks, target attacking creature without flying gains flying until end of turn. + Ability ability = new AttacksTriggeredAbility( + new GainAbilityTargetEffect( + FlyingAbility.getInstance(), + Duration.EndOfTurn + ), false + ); + ability.addTarget(new TargetPermanent(filter)); + addAbility(ability); + } + + private TrustedPegasus(final TrustedPegasus card) { + super(card); + } + + @Override + public TrustedPegasus copy() { + return new TrustedPegasus(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TruthOrTale.java b/Mage.Sets/src/mage/cards/t/TruthOrTale.java index f76c7eed66..ebf295088d 100644 --- a/Mage.Sets/src/mage/cards/t/TruthOrTale.java +++ b/Mage.Sets/src/mage/cards/t/TruthOrTale.java @@ -66,8 +66,7 @@ class TruthOrTaleEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 5)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 5)); controller.revealCards(sourceObject.getIdName(), cards, game); Player opponent; diff --git a/Mage.Sets/src/mage/cards/t/TsabosDecree.java b/Mage.Sets/src/mage/cards/t/TsabosDecree.java index 422d34b075..45a9835c66 100644 --- a/Mage.Sets/src/mage/cards/t/TsabosDecree.java +++ b/Mage.Sets/src/mage/cards/t/TsabosDecree.java @@ -64,31 +64,33 @@ class TsabosDecreeEffect extends OneShotEffect { Player targetPlayer = game.getPlayer(targetPointer.getFirst(game, source)); MageObject sourceObject = game.getObject(source.getSourceId()); if (player != null) { - Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (!player.choose(outcome, typeChoice, game)) { - return false; - } - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game); - FilterCard filterCard = new FilterCard(); - filterCard.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - List toDiscard = new ArrayList<>(); - for (Card card : targetPlayer.getHand().getCards(game)) { - if (filterCard.match(card, game)) { - toDiscard.add(card); + if(sourceObject != null) { + Choice typeChoice = new ChoiceCreatureType(sourceObject); + if (!player.choose(outcome, typeChoice, game)) { + return false; } - } - for (Card card : toDiscard) { - targetPlayer.discard(card, source, game); - } - FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); - filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { - if (creature.isControlledBy(targetPlayer.getId())) { - creature.destroy(source.getSourceId(), game, true); + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + targetPlayer.revealCards("hand of " + targetPlayer.getName(), targetPlayer.getHand(), game); + FilterCard filterCard = new FilterCard(); + filterCard.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + List toDiscard = new ArrayList<>(); + for (Card card : targetPlayer.getHand().getCards(game)) { + if (filterCard.match(card, game)) { + toDiscard.add(card); + } } + for (Card card : toDiscard) { + targetPlayer.discard(card, source, game); + } + FilterCreaturePermanent filterCreaturePermanent = new FilterCreaturePermanent(); + filterCreaturePermanent.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + for (Permanent creature : game.getBattlefield().getActivePermanents(filterCreaturePermanent, source.getSourceId(), game)) { + if (creature.isControlledBy(targetPlayer.getId())) { + creature.destroy(source.getSourceId(), game, true); + } + } + return true; } - return true; } return false; } diff --git a/Mage.Sets/src/mage/cards/t/TunnelIgnus.java b/Mage.Sets/src/mage/cards/t/TunnelIgnus.java index 56eb26d80f..7de16b3c3e 100644 --- a/Mage.Sets/src/mage/cards/t/TunnelIgnus.java +++ b/Mage.Sets/src/mage/cards/t/TunnelIgnus.java @@ -1,10 +1,5 @@ - package mage.cards.t; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -22,6 +17,11 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; import mage.watchers.Watcher; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.UUID; + /** * @author Loki */ @@ -53,7 +53,7 @@ class TunnelIgnusWatcher extends Watcher { protected Map counts = new HashMap<>(); public TunnelIgnusWatcher() { - super(TunnelIgnusWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } public TunnelIgnusWatcher(final TunnelIgnusWatcher watcher) { @@ -72,8 +72,7 @@ class TunnelIgnusWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent.isLand() && game.getOpponents(this.controllerId).contains(permanent.getControllerId())) { - + if (permanent != null && permanent.isLand() && game.getOpponents(this.controllerId).contains(permanent.getControllerId())) { int count = counts.getOrDefault(permanent.getControllerId(), 0); counts.put(permanent.getControllerId(), count + 1); } @@ -111,7 +110,7 @@ class TunnelIgnusTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); if (permanent != null && permanent.isLand() && game.getOpponents(this.controllerId).contains(permanent.getControllerId())) { - TunnelIgnusWatcher watcher = (TunnelIgnusWatcher) game.getState().getWatchers().get(TunnelIgnusWatcher.class.getSimpleName(), this.controllerId); + TunnelIgnusWatcher watcher = game.getState().getWatcher(TunnelIgnusWatcher.class, this.controllerId); if (watcher != null && watcher.counts.get(permanent.getControllerId()) > 1) { for (Effect effect : this.getEffects()) { effect.setTargetPointer(new FixedTarget(permanent.getControllerId())); diff --git a/Mage.Sets/src/mage/cards/t/TunnelVision.java b/Mage.Sets/src/mage/cards/t/TunnelVision.java index e7b2e0d9bc..33b58c266c 100644 --- a/Mage.Sets/src/mage/cards/t/TunnelVision.java +++ b/Mage.Sets/src/mage/cards/t/TunnelVision.java @@ -1,23 +1,20 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ChooseACardNameEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; -import mage.cards.Cards; -import mage.cards.CardsImpl; +import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class TunnelVision extends CardImpl { @@ -76,7 +73,7 @@ class TunnelVisionEffect extends OneShotEffect { for (Card card : targetPlayer.getLibrary().getCards(game)) { cardsToReveal.add(card); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { namedCard = card; break; } diff --git a/Mage.Sets/src/mage/cards/t/TurbulentDreams.java b/Mage.Sets/src/mage/cards/t/TurbulentDreams.java index cd595d460e..6dcdd74d69 100644 --- a/Mage.Sets/src/mage/cards/t/TurbulentDreams.java +++ b/Mage.Sets/src/mage/cards/t/TurbulentDreams.java @@ -1,60 +1,58 @@ package mage.cards.t; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.DiscardXTargetCost; -import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.filter.FilterCard; import mage.filter.FilterPermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.StaticFilters; +import mage.filter.common.FilterNonlandPermanent; import mage.game.Game; import mage.target.Target; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class TurbulentDreams extends CardImpl { - - private static final FilterPermanent filter = new FilterPermanent("nonland permanents"); - - static { - filter.add(Predicates.not(new CardTypePredicate(CardType.LAND))); - } public TurbulentDreams(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{U}{U}"); // As an additional cost to cast Turbulent Dreams, discard X cards. - this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); - + this.getSpellAbility().addCost(new DiscardXTargetCost(StaticFilters.FILTER_CARD_CARDS, true)); + // Return X target nonland permanents to their owners' hands. Effect effect = new ReturnToHandTargetEffect(); effect.setText("Return X target nonland permanents to their owners' hands"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(TurbulentDreamsAdjuster.instance); } public TurbulentDreams(final TurbulentDreams card) { super(card); } - - @Override - public void adjustTargets(Ability ability, Game game) { - int xValue = new GetXValue().calculate(game, ability, null); - Target target = new TargetPermanent(0, xValue, filter, false); - ability.addTarget(target); - } @Override public TurbulentDreams copy() { return new TurbulentDreams(this); } } + +enum TurbulentDreamsAdjuster implements TargetAdjuster { + instance; + private static final FilterPermanent filter = new FilterNonlandPermanent("nonland permanents"); + + @Override + public void adjustTargets(Ability ability, Game game) { + Target target = new TargetPermanent(0, ability.getManaCostsToPay().getX(), filter, false); + ability.addTarget(target); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/t/TurnAside.java b/Mage.Sets/src/mage/cards/t/TurnAside.java index 600493961b..245b76b035 100644 --- a/Mage.Sets/src/mage/cards/t/TurnAside.java +++ b/Mage.Sets/src/mage/cards/t/TurnAside.java @@ -18,7 +18,7 @@ import mage.target.TargetSpell; */ public final class TurnAside extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); + private static final FilterSpell filter = new FilterSpell("spell that targets a permanent you control"); static { filter.add(new TargetsPermanentPredicate(new FilterControlledPermanent())); diff --git a/Mage.Sets/src/mage/cards/t/Turnabout.java b/Mage.Sets/src/mage/cards/t/Turnabout.java index 47e2ae27a8..968a0cd1bb 100644 --- a/Mage.Sets/src/mage/cards/t/Turnabout.java +++ b/Mage.Sets/src/mage/cards/t/Turnabout.java @@ -110,14 +110,14 @@ class TurnaboutEffect extends OneShotEffect { filter.add(new CardTypePredicate(type)); if (choiceImpl.getChoice().equals("Untap")) { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { if (permanent.isControlledBy(target)) { permanent.untap(game); } } } else { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { if (permanent.isControlledBy(target)) { permanent.tap(game); diff --git a/Mage.Sets/src/mage/cards/t/TurretOgre.java b/Mage.Sets/src/mage/cards/t/TurretOgre.java new file mode 100644 index 0000000000..c632896837 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TurretOgre.java @@ -0,0 +1,61 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.keyword.ReachAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.mageobject.PowerPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TurretOgre extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + filter.add(new PowerPredicate(ComparisonType.MORE_THAN, 3)); + } + + public TurretOgre(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // Reach + this.addAbility(ReachAbility.getInstance()); + + // When Turret Ogre enters the battlefield, if you control another creature with power 4 or greater, Turret Ogre deals 2 damage to each opponent. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility(new DamagePlayersEffect(2, TargetController.OPPONENT)), + new PermanentsOnTheBattlefieldCondition(filter), "When {this} enters the battlefield, " + + "if you control another creature with power 4 or greater, {this} deals 2 damage to each opponent." + )); + } + + private TurretOgre(final TurretOgre card) { + super(card); + } + + @Override + public TurretOgre copy() { + return new TurretOgre(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java b/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java index 5af7d2b974..3cda3fa397 100644 --- a/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java +++ b/Mage.Sets/src/mage/cards/t/TuvasaTheSunlit.java @@ -95,10 +95,10 @@ class TuvasaTheSunlitTriggeredAbility extends SpellCastControllerTriggeredAbilit @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - TuvasaTheSunlitWatcher watcher = (TuvasaTheSunlitWatcher) game.getState().getWatchers().get( - TuvasaTheSunlitWatcher.class.getSimpleName() + TuvasaTheSunlitWatcher watcher = game.getState().getWatcher( + TuvasaTheSunlitWatcher.class ); - return event.getTargetId().equals(watcher.getFirstEnchantmentThisTurn(this.getControllerId())); + return watcher != null && event.getTargetId().equals(watcher.getFirstEnchantmentThisTurn(this.getControllerId())); } return false; } @@ -116,10 +116,10 @@ class TuvasaTheSunlitTriggeredAbility extends SpellCastControllerTriggeredAbilit class TuvasaTheSunlitWatcher extends Watcher { - private final Map firstEnchantmentThisTurn = new HashMap(); + private final Map firstEnchantmentThisTurn = new HashMap<>(); public TuvasaTheSunlitWatcher() { - super(TuvasaTheSunlitWatcher.class.getSimpleName(), WatcherScope.GAME); + super( WatcherScope.GAME); } public TuvasaTheSunlitWatcher(final TuvasaTheSunlitWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TwilightDrover.java b/Mage.Sets/src/mage/cards/t/TwilightDrover.java index 95a2edf861..9b230eea48 100644 --- a/Mage.Sets/src/mage/cards/t/TwilightDrover.java +++ b/Mage.Sets/src/mage/cards/t/TwilightDrover.java @@ -29,7 +29,7 @@ public final class TwilightDrover extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature token"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public TwilightDrover(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TwilightPanther.java b/Mage.Sets/src/mage/cards/t/TwilightPanther.java new file mode 100644 index 0000000000..68955242d3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TwilightPanther.java @@ -0,0 +1,43 @@ +package mage.cards.t; + +import mage.MageInt; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.abilities.keyword.DeathtouchAbility; +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 TwilightPanther extends CardImpl { + + public TwilightPanther(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); + + this.subtype.add(SubType.CAT); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(1); + this.toughness = new MageInt(2); + + // {B}: Twilight Panther gains deathtouch until end of turn. + this.addAbility(new SimpleActivatedAbility(new GainAbilitySourceEffect( + DeathtouchAbility.getInstance(), Duration.EndOfTurn + ), new ManaCostsImpl("{B}"))); + } + + private TwilightPanther(final TwilightPanther card) { + super(card); + } + + @Override + public TwilightPanther copy() { + return new TwilightPanther(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/TwilightProphet.java b/Mage.Sets/src/mage/cards/t/TwilightProphet.java index cced90fe5d..1d09e42beb 100644 --- a/Mage.Sets/src/mage/cards/t/TwilightProphet.java +++ b/Mage.Sets/src/mage/cards/t/TwilightProphet.java @@ -1,7 +1,5 @@ - package mage.cards.t; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -10,22 +8,20 @@ import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.abilities.keyword.FlyingAbility; 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.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class TwilightProphet extends CardImpl { @@ -49,7 +45,8 @@ public final class TwilightProphet extends CardImpl { this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility( new TwilightProphetEffect(), TargetController.YOU, false), CitysBlessingCondition.instance, "At the beginning of your upkeep, if you have the city's blessing, reveal the top card of your library and put it into your hand." - + "Each opponent loses X life and you gain X life, where X is that card's converted mana cost.")); + + "Each opponent loses X life and you gain X life, where X is that card's converted mana cost.") + .addHint(CitysBlessingHint.instance)); } diff --git a/Mage.Sets/src/mage/cards/t/TwilightShepherd.java b/Mage.Sets/src/mage/cards/t/TwilightShepherd.java index fe12c72f72..ec90fbcd72 100644 --- a/Mage.Sets/src/mage/cards/t/TwilightShepherd.java +++ b/Mage.Sets/src/mage/cards/t/TwilightShepherd.java @@ -81,7 +81,7 @@ class TwilightShepherdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - CardsPutIntoGraveyardWatcher watcher = (CardsPutIntoGraveyardWatcher) game.getState().getWatchers().get(CardsPutIntoGraveyardWatcher.class.getSimpleName()); + CardsPutIntoGraveyardWatcher watcher = game.getState().getWatcher(CardsPutIntoGraveyardWatcher.class); Player controller = game.getPlayer(source.getControllerId()); if (controller != null && watcher != null) { Set cardsInGraveyard = watcher.getCardsPutToGraveyardFromBattlefield(); diff --git a/Mage.Sets/src/mage/cards/t/TwinningGlass.java b/Mage.Sets/src/mage/cards/t/TwinningGlass.java index 71c723922f..71646c16ac 100644 --- a/Mage.Sets/src/mage/cards/t/TwinningGlass.java +++ b/Mage.Sets/src/mage/cards/t/TwinningGlass.java @@ -75,7 +75,7 @@ class TwinningGlassEffect extends OneShotEffect { filterCard.add(Predicates.not(new CardTypePredicate(CardType.LAND))); Permanent twinningGlass = game.getPermanent(source.getSourceId()); Player controller = game.getPlayer(source.getControllerId()); - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (twinningGlass == null) { twinningGlass = (Permanent) game.getLastKnownInformation(source.getSourceId(), Zone.BATTLEFIELD); } diff --git a/Mage.Sets/src/mage/cards/t/TwoHeadedGiant.java b/Mage.Sets/src/mage/cards/t/TwoHeadedGiant.java index 996d78d67b..e786e0bb8e 100644 --- a/Mage.Sets/src/mage/cards/t/TwoHeadedGiant.java +++ b/Mage.Sets/src/mage/cards/t/TwoHeadedGiant.java @@ -69,8 +69,8 @@ class TwoHeadedGiantEffect extends OneShotEffect { if (player == null) { return false; } - boolean head1 = player.flipCoin(game); - boolean head2 = player.flipCoin(game); + boolean head1 = player.flipCoin(source, game, false); + boolean head2 = player.flipCoin(source, game, false); if (head1 == head2) { if (head1) { game.addEffect(new GainAbilitySourceEffect(DoubleStrikeAbility.getInstance(), Duration.EndOfTurn), source); diff --git a/Mage.Sets/src/mage/cards/t/TymnaTheWeaver.java b/Mage.Sets/src/mage/cards/t/TymnaTheWeaver.java index 087b53f304..648aa4891d 100644 --- a/Mage.Sets/src/mage/cards/t/TymnaTheWeaver.java +++ b/Mage.Sets/src/mage/cards/t/TymnaTheWeaver.java @@ -76,7 +76,7 @@ class TymnaTheWeaverEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - TymnaTheWeaverWatcher watcher = (TymnaTheWeaverWatcher) game.getState().getWatchers().get(TymnaTheWeaverWatcher.class.getSimpleName()); + TymnaTheWeaverWatcher watcher = game.getState().getWatcher(TymnaTheWeaverWatcher.class); if (watcher != null) { int cardsToDraw = watcher.opponentsThatGotCombatDamage(source.getControllerId(), game); Cost cost = new PayLifeCost(cardsToDraw); @@ -97,7 +97,7 @@ class TymnaTheWeaverWatcher extends Watcher { private final Map> players = new HashMap<>(); public TymnaTheWeaverWatcher() { - super(TymnaTheWeaverWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public TymnaTheWeaverWatcher(final TymnaTheWeaverWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/t/TyrantsFamiliar.java b/Mage.Sets/src/mage/cards/t/TyrantsFamiliar.java index d52c153360..a0cd5f7018 100644 --- a/Mage.Sets/src/mage/cards/t/TyrantsFamiliar.java +++ b/Mage.Sets/src/mage/cards/t/TyrantsFamiliar.java @@ -30,7 +30,7 @@ public final class TyrantsFamiliar extends CardImpl { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public TyrantsFamiliar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/t/TyrantsScorn.java b/Mage.Sets/src/mage/cards/t/TyrantsScorn.java new file mode 100644 index 0000000000..0b082c9478 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/TyrantsScorn.java @@ -0,0 +1,52 @@ +package mage.cards.t; + +import mage.abilities.Mode; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class TyrantsScorn extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("creature with converted mana cost 3 or less"); + + static { + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); + } + + public TyrantsScorn(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{U}{B}"); + + // Choose one — + // • Destroy target creature with converted mana cost 3 or less. + this.getSpellAbility().addEffect(new DestroyTargetEffect()); + this.getSpellAbility().addTarget(new TargetPermanent(filter)); + + // • Return target creature to its owner's hand. + Mode mode = new Mode(new ReturnToHandTargetEffect()); + mode.addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addMode(mode); + } + + private TyrantsScorn(final TyrantsScorn card) { + super(card); + } + + @Override + public TyrantsScorn copy() { + return new TyrantsScorn(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UbaMask.java b/Mage.Sets/src/mage/cards/u/UbaMask.java index 94e4fdad29..9f56aea2ef 100644 --- a/Mage.Sets/src/mage/cards/u/UbaMask.java +++ b/Mage.Sets/src/mage/cards/u/UbaMask.java @@ -68,7 +68,7 @@ class UbaMaskReplacementEffect extends ReplacementEffectImpl { Card card = player.getLibrary().getFromTop(game); if (card != null) { if (player.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName())) { - UbaMaskExiledCardsWatcher watcher = (UbaMaskExiledCardsWatcher) game.getState().getWatchers().get(UbaMaskExiledCardsWatcher.class.getSimpleName()); + UbaMaskExiledCardsWatcher watcher = game.getState().getWatcher(UbaMaskExiledCardsWatcher.class); if (watcher != null) { watcher.addExiledCard(event.getPlayerId(), card, game); } @@ -116,7 +116,7 @@ class UbaMaskPlayEffect extends AsThoughEffectImpl { if (card != null && affectedControllerId.equals(card.getOwnerId()) && game.getState().getZone(card.getId()) == Zone.EXILED) { - UbaMaskExiledCardsWatcher watcher = (UbaMaskExiledCardsWatcher) game.getState().getWatchers().get(UbaMaskExiledCardsWatcher.class.getSimpleName()); + UbaMaskExiledCardsWatcher watcher = game.getState().getWatcher(UbaMaskExiledCardsWatcher.class); if (watcher != null) { List exiledThisTurn = watcher.getUbaMaskExiledCardsThisTurn(affectedControllerId); return exiledThisTurn != null @@ -132,7 +132,7 @@ class UbaMaskExiledCardsWatcher extends Watcher { private final Map> exiledCards = new HashMap<>(); public UbaMaskExiledCardsWatcher() { - super(UbaMaskExiledCardsWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public UbaMaskExiledCardsWatcher(final UbaMaskExiledCardsWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java b/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java index 7dcfd6782f..fe7e7d09ab 100644 --- a/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java +++ b/Mage.Sets/src/mage/cards/u/UbulSarGatekeepers.java @@ -1,13 +1,13 @@ - package mage.cards.u; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.hint.ConditionHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; @@ -18,8 +18,9 @@ import mage.filter.predicate.permanent.ControllerPredicate; import mage.target.Target; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class UbulSarGatekeepers extends CardImpl { @@ -32,8 +33,10 @@ public final class UbulSarGatekeepers extends CardImpl { targetFilter.add(new ControllerPredicate(TargetController.OPPONENT)); } + private static final Condition gatesCondition = new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1); + public UbulSarGatekeepers(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); this.subtype.add(SubType.ZOMBIE); this.subtype.add(SubType.SOLDIER); @@ -43,10 +46,11 @@ public final class UbulSarGatekeepers extends CardImpl { // Whenever Ubul Sar Gatekeepers enters the battlefield, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn. Ability ability = new ConditionalInterveningIfTriggeredAbility( new EntersBattlefieldTriggeredAbility(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)), - new PermanentsOnTheBattlefieldCondition(filter, ComparisonType.MORE_THAN, 1), + gatesCondition, "Whenever {this} enters the battlefield, if you control two or more Gates, target creature an opponent controls gets -2/-2 until end of turn."); Target target = new TargetCreaturePermanent(targetFilter); ability.addTarget(target); + ability.addHint(new ConditionHint(gatesCondition, "You control two or more Gates")); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/u/UginTheIneffable.java b/Mage.Sets/src/mage/cards/u/UginTheIneffable.java new file mode 100644 index 0000000000..c8f079335d --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UginTheIneffable.java @@ -0,0 +1,169 @@ +package mage.cards.u; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.DelayedTriggeredAbility; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.ReturnToHandTargetEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.ColorlessPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.Token; +import mage.game.permanent.token.UginTheIneffableToken; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.targetpointer.FixedTarget; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; + +/** + * @author TheElk801 + */ +public final class UginTheIneffable extends CardImpl { + + private static final FilterCard filter = new FilterCard(); + private static final FilterPermanent filter2 = new FilterPermanent("permanent that's one or more colors"); + + static { + filter.add(ColorlessPredicate.instance); + filter2.add(Predicates.not(ColorlessPredicate.instance)); + } + + public UginTheIneffable(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{6}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.UGIN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // Colorless spells you cast cost {2} less to cast. + this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect( + filter, 2 + ).setText("Colorless spells you cast cost {2} less to cast."))); + + // +1: Exile the top card of your library face down and look at it. Create a 2/2 colorless Spirit creature token. When that token leaves the battlefield, put the exiled card into your hand. + this.addAbility(new LoyaltyAbility(new UginTheIneffableEffect(), 1)); + + // -3: Destroy target permanent that's one or more colors. + Ability ability = new LoyaltyAbility(new DestroyTargetEffect(), -3); + ability.addTarget(new TargetPermanent(filter2)); + this.addAbility(ability); + } + + private UginTheIneffable(final UginTheIneffable card) { + super(card); + } + + @Override + public UginTheIneffable copy() { + return new UginTheIneffable(this); + } +} + +class UginTheIneffableEffect extends OneShotEffect { + + UginTheIneffableEffect() { + super(Benefit); + staticText = "Exile the top card of your library face down and look at it. " + + "Create a 2/2 colorless Spirit creature token. When that token leaves the battlefield, " + + "put the exiled card into your hand."; + } + + private UginTheIneffableEffect(final UginTheIneffableEffect effect) { + super(effect); + } + + @Override + public UginTheIneffableEffect copy() { + return new UginTheIneffableEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = player.getLibrary().getFromTop(game); + player.lookAtCards(sourcePermanent.getIdName(), card, game); + player.moveCards(card, Zone.EXILED, source, game); + card.turnFaceDown(game, source.getControllerId()); + Token token = new UginTheIneffableToken(); + token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId()); + Set tokenObjs = new HashSet<>(); + for (UUID tokenId : token.getLastAddedTokenIds()) { + tokenObjs.add(new MageObjectReference(tokenId, game)); + } + game.addDelayedTriggeredAbility(new UginTheIneffableDelayedTriggeredAbility( + tokenObjs, new MageObjectReference(card, game) + ), source); + return true; + } +} + +class UginTheIneffableDelayedTriggeredAbility extends DelayedTriggeredAbility { + + private final Set tokenRefs; + private final MageObjectReference cardRef; + + UginTheIneffableDelayedTriggeredAbility(Set tokens, MageObjectReference card) { + super(null, Duration.Custom, true); + this.tokenRefs = tokens; + this.cardRef = card; + } + + private UginTheIneffableDelayedTriggeredAbility(final UginTheIneffableDelayedTriggeredAbility ability) { + super(ability); + this.tokenRefs = ability.tokenRefs; + this.cardRef = ability.cardRef; + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = ((ZoneChangeEvent) event); + if (zEvent.getToZone() == Zone.BATTLEFIELD + || tokenRefs.stream().noneMatch(tokenRef -> tokenRef.refersTo(zEvent.getTarget(), game))) { + return false; + } + this.getEffects().clear(); + Effect effect = new ReturnToHandTargetEffect(); + effect.setTargetPointer(new FixedTarget(cardRef)); + this.addEffect(effect); + return true; + } + + @Override + public UginTheIneffableDelayedTriggeredAbility copy() { + return new UginTheIneffableDelayedTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When this token leaves the battlefield, put the exiled card into your hand."; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java b/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java index d508d489b3..880666f4e9 100644 --- a/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java +++ b/Mage.Sets/src/mage/cards/u/UginTheSpiritDragon.java @@ -100,7 +100,7 @@ class UginTheSpiritDragonEffect2 extends OneShotEffect { FilterPermanent filter = new FilterPermanent("permanent with converted mana cost X or less that's one or more colors"); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, cmc + 1)); - filter.add(Predicates.not(new ColorlessPredicate())); + filter.add(Predicates.not(ColorlessPredicate.instance)); Set permanentsToExile = new HashSet<>(); permanentsToExile.addAll(game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)); controller.moveCards(permanentsToExile, Zone.EXILED, source, game); diff --git a/Mage.Sets/src/mage/cards/u/UginsConjurant.java b/Mage.Sets/src/mage/cards/u/UginsConjurant.java new file mode 100644 index 0000000000..a633fbff27 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UginsConjurant.java @@ -0,0 +1,45 @@ +package mage.cards.u; + +import java.util.UUID; +import mage.MageInt; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.effects.common.EntersBattlefieldWithXCountersEffect; +import mage.abilities.effects.PreventDamageAndRemoveCountersEffect; +import mage.abilities.common.SimpleStaticAbility; +import mage.counters.CounterType; +import mage.constants.Zone; + +/** + * + * @author antoni-g + */ +public final class UginsConjurant extends CardImpl { + + public UginsConjurant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{X}"); + + this.subtype.add(SubType.SPIRIT); + this.subtype.add(SubType.MONK); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Ugin’s Conjurant enters the battlefield with X +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility(new EntersBattlefieldWithXCountersEffect(CounterType.P1P1.createInstance()))); + // If damage would be dealt to Ugin’s Conjurant while it has a +1/+1 counter on it, prevent that damage and remove that many +1/+1 counters from Ugin’s Conjurant. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PreventDamageAndRemoveCountersEffect())); + } + + private UginsConjurant(final UginsConjurant card) { + super(card); + } + + @Override + public UginsConjurant copy() { + return new UginsConjurant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UginsConstruct.java b/Mage.Sets/src/mage/cards/u/UginsConstruct.java index f0b36c2eaf..39e1b789dc 100644 --- a/Mage.Sets/src/mage/cards/u/UginsConstruct.java +++ b/Mage.Sets/src/mage/cards/u/UginsConstruct.java @@ -22,7 +22,7 @@ public final class UginsConstruct extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("permanent that's one or more colors"); static { - filter.add(Predicates.not(new ColorlessPredicate())); + filter.add(Predicates.not(ColorlessPredicate.instance)); } public UginsConstruct(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UktabiKong.java b/Mage.Sets/src/mage/cards/u/UktabiKong.java index d3e92b6b97..1d2f31e7eb 100644 --- a/Mage.Sets/src/mage/cards/u/UktabiKong.java +++ b/Mage.Sets/src/mage/cards/u/UktabiKong.java @@ -31,7 +31,7 @@ public final class UktabiKong extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Apes you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.APE)); } diff --git a/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java b/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java index 2852a71044..8db6e24f69 100644 --- a/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java +++ b/Mage.Sets/src/mage/cards/u/UlamogsDespoiler.java @@ -54,7 +54,7 @@ public final class UlamogsDespoiler extends CardImpl { class UlamogsDespoilerEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("cards your opponents own from exile"); + private static final FilterCard filter = new FilterCard("cards your opponents own from exile"); static { filter.add(new OwnerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java b/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java index 730bf0835e..3490922e62 100644 --- a/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java +++ b/Mage.Sets/src/mage/cards/u/UlamogsNullifier.java @@ -68,7 +68,7 @@ public final class UlamogsNullifier extends CardImpl { class UlamogsNullifierEffect extends OneShotEffect { - private final static FilterCard filter = new FilterCard("cards your opponents own from exile"); + private static final FilterCard filter = new FilterCard("cards your opponents own from exile"); static { filter.add(new OwnerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java b/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java index 264ea4f936..aa1c8b6ab3 100644 --- a/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java +++ b/Mage.Sets/src/mage/cards/u/UlashtTheHateSeed.java @@ -57,7 +57,7 @@ public final class UlashtTheHateSeed extends CardImpl { Mode mode = new Mode(); Effect effect = new CreateTokenEffect(new SaprolingToken()); effect.setText("Create a 1/1 green Saproling creature token."); - mode.getEffects().add(effect); + mode.addEffect(effect); ability.addMode(mode); this.addAbility(ability); } @@ -78,9 +78,9 @@ class UlashtTheHateSeedEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filterRed = new FilterControlledCreaturePermanent(); static { - filterGreen.add(new AnotherPredicate()); + filterGreen.add(AnotherPredicate.instance); filterGreen.add(new ColorPredicate(ObjectColor.GREEN)); - filterRed.add(new AnotherPredicate()); + filterRed.add(AnotherPredicate.instance); filterRed.add(new ColorPredicate(ObjectColor.RED)); } diff --git a/Mage.Sets/src/mage/cards/u/UlrichsKindred.java b/Mage.Sets/src/mage/cards/u/UlrichsKindred.java index dc00e936dc..898256c9e7 100644 --- a/Mage.Sets/src/mage/cards/u/UlrichsKindred.java +++ b/Mage.Sets/src/mage/cards/u/UlrichsKindred.java @@ -30,7 +30,7 @@ public final class UlrichsKindred extends CardImpl { static { filter.add(Predicates.or(new SubtypePredicate(SubType.WOLF), new SubtypePredicate(SubType.WEREWOLF))); - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public UlrichsKindred(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UltimatePrice.java b/Mage.Sets/src/mage/cards/u/UltimatePrice.java index 7eee79cde8..5b37471c23 100644 --- a/Mage.Sets/src/mage/cards/u/UltimatePrice.java +++ b/Mage.Sets/src/mage/cards/u/UltimatePrice.java @@ -19,7 +19,7 @@ public final class UltimatePrice extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("monocolored creature"); static { - filter.add(new MonocoloredPredicate()); + filter.add(MonocoloredPredicate.instance); } public UltimatePrice(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java b/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java index d130f99fd0..36d32c3d71 100644 --- a/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java +++ b/Mage.Sets/src/mage/cards/u/UlvenwaldMysteries.java @@ -34,7 +34,7 @@ public final class UlvenwaldMysteries extends CardImpl { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); filterClue.add(new SubtypePredicate(SubType.CLUE)); } diff --git a/Mage.Sets/src/mage/cards/u/UmezawasJitte.java b/Mage.Sets/src/mage/cards/u/UmezawasJitte.java index 6e065b4bca..a7b26b40ca 100644 --- a/Mage.Sets/src/mage/cards/u/UmezawasJitte.java +++ b/Mage.Sets/src/mage/cards/u/UmezawasJitte.java @@ -45,13 +45,13 @@ public final class UmezawasJitte extends CardImpl { // Target creature gets -1/-1 until end of turn. Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-1, -1, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); ability.addMode(mode); // You gain 2 life. mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(2)); + mode.addEffect(new GainLifeEffect(2)); ability.addMode(mode); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/u/UnbenderTine.java b/Mage.Sets/src/mage/cards/u/UnbenderTine.java index b2b522d3b0..8e76b2c3e4 100644 --- a/Mage.Sets/src/mage/cards/u/UnbenderTine.java +++ b/Mage.Sets/src/mage/cards/u/UnbenderTine.java @@ -26,7 +26,7 @@ public final class UnbenderTine extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public UnbenderTine(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UnbreakableFormation.java b/Mage.Sets/src/mage/cards/u/UnbreakableFormation.java new file mode 100644 index 0000000000..62ced3ec1d --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnbreakableFormation.java @@ -0,0 +1,80 @@ +package mage.cards.u; + +import mage.abilities.Ability; +import mage.abilities.condition.common.AddendumCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.common.counter.AddCountersAllEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.filter.StaticFilters; +import mage.game.Game; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UnbreakableFormation extends CardImpl { + + public UnbreakableFormation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{W}"); + + // Creatures you control gain indestructible until end of turn. + this.getSpellAbility().addEffect(new GainAbilityControlledEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + )); + + // Addendum — If you cast this spell during your main phase, put a +1/+1 counter on each of those creatures, and they also gain vigilance until end of turn. + this.getSpellAbility().addEffect(new UnbreakableFormationEffect()); + } + + private UnbreakableFormation(final UnbreakableFormation card) { + super(card); + } + + @Override + public UnbreakableFormation copy() { + return new UnbreakableFormation(this); + } +} + +class UnbreakableFormationEffect extends OneShotEffect { + + UnbreakableFormationEffect() { + super(Outcome.Benefit); + staticText = "
    Addendum — If you cast this spell during your main phase, " + + "put a +1/+1 counter on each of those creatures, and they also gain vigilance until end of turn."; + } + + private UnbreakableFormationEffect(final UnbreakableFormationEffect effect) { + super(effect); + } + + @Override + public UnbreakableFormationEffect copy() { + return new UnbreakableFormationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + if (!AddendumCondition.instance.apply(game, source)) { + return false; + } + game.addEffect(new GainAbilityControlledEffect( + VigilanceAbility.getInstance(), Duration.EndOfTurn, + StaticFilters.FILTER_PERMANENT_CREATURE + ), source); + return new AddCountersAllEffect( + CounterType.P1P1.createInstance(), + StaticFilters.FILTER_CONTROLLED_CREATURE + ).apply(game, source); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java b/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java index a002a14dce..840fbbe22e 100644 --- a/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java +++ b/Mage.Sets/src/mage/cards/u/UncageTheMenagerie.java @@ -75,7 +75,7 @@ class UncageTheMenagerieEffect extends OneShotEffect { int xValue = source.getManaCostsToPay().getX(); UncageTheMenagerieTarget target = new UncageTheMenagerieTarget(xValue); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java b/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java index 9b3cd9cc20..393374047a 100644 --- a/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java +++ b/Mage.Sets/src/mage/cards/u/UnclaimedTerritory.java @@ -104,7 +104,7 @@ class UnclaimedTerritoryManaCondition extends CreatureCastManaCondition { if (super.apply(game, source)) { // check: ... of the chosen type MageObject object = game.getObject(source.getSourceId()); - if (creatureType != null && object.hasSubtype(creatureType, game)) { + if (creatureType != null && object != null && object.hasSubtype(creatureType, game)) { return true; } } diff --git a/Mage.Sets/src/mage/cards/u/UndercityNecrolisk.java b/Mage.Sets/src/mage/cards/u/UndercityNecrolisk.java index f1adb8461a..d90196c35f 100644 --- a/Mage.Sets/src/mage/cards/u/UndercityNecrolisk.java +++ b/Mage.Sets/src/mage/cards/u/UndercityNecrolisk.java @@ -31,7 +31,7 @@ public final class UndercityNecrolisk extends CardImpl { = new FilterControlledCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public UndercityNecrolisk(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UndercityScavenger.java b/Mage.Sets/src/mage/cards/u/UndercityScavenger.java new file mode 100644 index 0000000000..a985d82e08 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UndercityScavenger.java @@ -0,0 +1,55 @@ +package mage.cards.u; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.effects.common.DoIfCostPaid; +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 mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.target.common.TargetControlledPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UndercityScavenger extends CardImpl { + + private static final FilterControlledPermanent filter = new FilterControlledCreaturePermanent("another creature"); + + static { + filter.add(AnotherPredicate.instance); + } + + public UndercityScavenger(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.OGRE); + this.subtype.add(SubType.WARRIOR); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // When Undercity Scavenger enters the battlefield, you may sacrifice another creature. If you do, put two +1/+1 counters on Undercity Scavenger, then scry 2. + this.addAbility(new EntersBattlefieldTriggeredAbility(new DoIfCostPaid( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), + new SacrificeTargetCost(new TargetControlledPermanent(filter)) + ).addEffect(new ScryEffect(2).concatBy(", then")))); + } + + private UndercityScavenger(final UndercityScavenger card) { + super(card); + } + + @Override + public UndercityScavenger copy() { + return new UndercityScavenger(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UndercitysEmbrace.java b/Mage.Sets/src/mage/cards/u/UndercitysEmbrace.java new file mode 100644 index 0000000000..9e74e52157 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UndercitysEmbrace.java @@ -0,0 +1,44 @@ +package mage.cards.u; + +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.SacrificeEffect; +import mage.abilities.hint.common.FerociousHint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.filter.StaticFilters; +import mage.target.common.TargetOpponent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class UndercitysEmbrace extends CardImpl { + + public UndercitysEmbrace(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{B}"); + + // Target opponent sacrifices a creature. If you control a creature with power 4 or greater, you gain 4 life. + this.getSpellAbility().addEffect(new SacrificeEffect( + StaticFilters.FILTER_PERMANENT_A_CREATURE, 1, "target player" + )); + this.getSpellAbility().addTarget(new TargetOpponent()); + this.getSpellAbility().addEffect(new ConditionalOneShotEffect( + new GainLifeEffect(4), FerociousCondition.instance, + "If you control a creature with power 4 or greater, you gain 4 life." + )); + this.getSpellAbility().addHint(FerociousHint.instance); + } + + private UndercitysEmbrace(final UndercitysEmbrace card) { + super(card); + } + + @Override + public UndercitysEmbrace copy() { + return new UndercitysEmbrace(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java index 168d212a47..17500870e0 100644 --- a/Mage.Sets/src/mage/cards/u/UnderworldDreams.java +++ b/Mage.Sets/src/mage/cards/u/UnderworldDreams.java @@ -18,7 +18,7 @@ public final class UnderworldDreams extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{B}{B}{B}"); // Whenever an opponent draws a card, Underworld Dreams deals 1 damage to him or her. - this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "him or her"), false, true)); + this.addAbility(new DrawCardOpponentTriggeredAbility(new DamageTargetEffect(1, true, "that player"), false, true)); } public UnderworldDreams(final UnderworldDreams card) { diff --git a/Mage.Sets/src/mage/cards/u/UndyingBeast.java b/Mage.Sets/src/mage/cards/u/UndyingBeast.java index d7117e01ea..20bf25c5a6 100644 --- a/Mage.Sets/src/mage/cards/u/UndyingBeast.java +++ b/Mage.Sets/src/mage/cards/u/UndyingBeast.java @@ -63,8 +63,10 @@ class UndyingBeastEffect extends OneShotEffect { Card card = game.getCard(source.getSourceId()); if (card != null && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { Player owner = game.getPlayer(card.getOwnerId()); - owner.getGraveyard().remove(card); - return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + if(owner != null) { + owner.getGraveyard().remove(card); + return card.moveToZone(Zone.LIBRARY, source.getSourceId(), game, true); + } } return true; } diff --git a/Mage.Sets/src/mage/cards/u/UneshCriosphinxSovereign.java b/Mage.Sets/src/mage/cards/u/UneshCriosphinxSovereign.java index d48aeec950..c30f25ae5b 100644 --- a/Mage.Sets/src/mage/cards/u/UneshCriosphinxSovereign.java +++ b/Mage.Sets/src/mage/cards/u/UneshCriosphinxSovereign.java @@ -108,7 +108,7 @@ class UneshCriosphinxSovereignTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever {this} or another Sphinx enters the battlefield under your control, ").append(super.getRule()).toString(); + return "Whenever {this} or another Sphinx enters the battlefield under your control, " + super.getRule(); } @Override @@ -141,8 +141,7 @@ class UneshCriosphinxSovereignEffect extends OneShotEffect { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); controller.revealCards(sourceObject.getName(), cards, game); Set opponents = game.getOpponents(source.getControllerId()); @@ -150,7 +149,7 @@ class UneshCriosphinxSovereignEffect extends OneShotEffect { Player opponent = game.getPlayer(opponents.iterator().next()); TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard("cards to put in the first pile")); List pile1 = new ArrayList<>(); - if (opponent.choose(Outcome.Neutral, cards, target, game)) { + if (opponent != null && opponent.choose(Outcome.Neutral, cards, target, game)) { List targets = target.getTargets(); for (UUID targetId : targets) { Card card = cards.get(targetId, game); diff --git a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java index c7c062ec94..6a879dbdfd 100644 --- a/Mage.Sets/src/mage/cards/u/UnexpectedResults.java +++ b/Mage.Sets/src/mage/cards/u/UnexpectedResults.java @@ -100,7 +100,7 @@ class UnexpectedResultEffect extends OneShotEffect { return true; } } else { - if (controller.chooseUse(outcome, new StringBuilder("Cast ").append(card.getName()).append(" without paying its mana cost?").toString(), source, game)) { + if (controller.chooseUse(outcome, "Cast " + card.getName() + " without paying its mana cost?", source, game)) { return controller.cast(card.getSpellAbility(), game, true, new MageObjectReference(source.getSourceObject(game), game)); } } diff --git a/Mage.Sets/src/mage/cards/u/UnholyCitadel.java b/Mage.Sets/src/mage/cards/u/UnholyCitadel.java new file mode 100644 index 0000000000..7153b14a32 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnholyCitadel.java @@ -0,0 +1,47 @@ + +package mage.cards.u; + +import java.util.UUID; +import mage.ObjectColor; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.BandsWithOtherAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ColorPredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; + +/** + * + * @author L_J + */ +public final class UnholyCitadel extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Black legendary creatures"); + + static { + filter.add(new ColorPredicate(ObjectColor.BLACK)); + filter.add(new SupertypePredicate(SuperType.LEGENDARY)); + } + + public UnholyCitadel(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); + + // Black legendary creatures you control have "bands with other legendary creatures." + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new GainAbilityControlledEffect(new BandsWithOtherAbility(SuperType.LEGENDARY), Duration.WhileOnBattlefield, filter))); + } + + public UnholyCitadel(final UnholyCitadel card) { + super(card); + } + + @Override + public UnholyCitadel copy() { + return new UnholyCitadel(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java index c5cda6e791..cd333a0bec 100644 --- a/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java +++ b/Mage.Sets/src/mage/cards/u/UnityOfTheDroids.java @@ -42,13 +42,13 @@ public final class UnityOfTheDroids extends CardImpl { // Look at the top four cards of your library. Put one of them into your hand and the rest into your graveyard. Mode mode = new Mode(); - mode.getEffects().add(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), new FilterCard(), Zone.GRAVEYARD, false, false)); + mode.addEffect(new LookLibraryAndPickControllerEffect(new StaticValue(4), false, new StaticValue(1), new FilterCard(), Zone.GRAVEYARD, false, false)); this.getSpellAbility().addMode(mode); // Destroy target nonartifact creature. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(nonArtifactCreatureFilter)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(nonArtifactCreatureFilter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/u/UnlikelyAid.java b/Mage.Sets/src/mage/cards/u/UnlikelyAid.java new file mode 100644 index 0000000000..39f4478ca8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UnlikelyAid.java @@ -0,0 +1,40 @@ +package mage.cards.u; + +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.IndestructibleAbility; +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 UnlikelyAid extends CardImpl { + + public UnlikelyAid(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{B}"); + + // Target creature gets +2/+0 and gains indestructible until end of turn. + this.getSpellAbility().addEffect(new BoostTargetEffect( + 2, 0, Duration.EndOfTurn + ).setText("Target creature gets +2/+0")); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect( + IndestructibleAbility.getInstance(), Duration.EndOfTurn + ).setText("and gains indestructable until end of turn")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private UnlikelyAid(final UnlikelyAid card) { + super(card); + } + + @Override + public UnlikelyAid copy() { + return new UnlikelyAid(this); + } +} diff --git a/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java b/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java index 169e39d2d9..7e36f41f16 100644 --- a/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java +++ b/Mage.Sets/src/mage/cards/u/UnlikelyAlliance.java @@ -26,8 +26,8 @@ public final class UnlikelyAlliance extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nonattacking, nonblocking creature"); static { - filter.add(Predicates.not(new AttackingPredicate())); - filter.add(Predicates.not(new BlockingPredicate())); + filter.add(Predicates.not(AttackingPredicate.instance)); + filter.add(Predicates.not(BlockingPredicate.instance)); } public UnlikelyAlliance(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UnravelingMummy.java b/Mage.Sets/src/mage/cards/u/UnravelingMummy.java index 4320bfa1e4..b995e43ca5 100644 --- a/Mage.Sets/src/mage/cards/u/UnravelingMummy.java +++ b/Mage.Sets/src/mage/cards/u/UnravelingMummy.java @@ -27,10 +27,10 @@ import mage.target.common.TargetCreaturePermanent; */ public final class UnravelingMummy extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking Zombie"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking Zombie"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); filter.add(new SubtypePredicate(SubType.ZOMBIE)); } diff --git a/Mage.Sets/src/mage/cards/u/UnrulyMob.java b/Mage.Sets/src/mage/cards/u/UnrulyMob.java index 6ae0fb3482..7777945b62 100644 --- a/Mage.Sets/src/mage/cards/u/UnrulyMob.java +++ b/Mage.Sets/src/mage/cards/u/UnrulyMob.java @@ -24,7 +24,7 @@ public final class UnrulyMob extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage.Sets/src/mage/cards/u/UnstableFooting.java b/Mage.Sets/src/mage/cards/u/UnstableFooting.java index 3682d933e1..898570d5a5 100644 --- a/Mage.Sets/src/mage/cards/u/UnstableFooting.java +++ b/Mage.Sets/src/mage/cards/u/UnstableFooting.java @@ -1,9 +1,7 @@ package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.condition.common.KickedCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.ReplacementEffectImpl; @@ -18,9 +16,11 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.target.common.TargetPlayerOrPlaneswalker; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class UnstableFooting extends CardImpl { @@ -36,20 +36,12 @@ public final class UnstableFooting extends CardImpl { this.getSpellAbility().addEffect(new ConditionalOneShotEffect( new DamageTargetEffect(5), KickedCondition.instance, - "If this spell was kicked, it deals 5 damage to target player or planeswalker")); + "If this spell was kicked, it deals 5 damage to target player or planeswalker") + ); + this.getSpellAbility().setTargetAdjuster(UnstableFootingAdjuster.instance); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - if (KickedCondition.instance.apply(game, ability)) { - ability.addTarget(new TargetPlayerOrPlaneswalker()); - } - } - } - public UnstableFooting(final UnstableFooting card) { super(card); } @@ -60,6 +52,18 @@ public final class UnstableFooting extends CardImpl { } } +enum UnstableFootingAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + if (KickedCondition.instance.apply(game, ability)) { + ability.addTarget(new TargetPlayerOrPlaneswalker()); + } + } +} + class UnstableFootingEffect extends ReplacementEffectImpl { public UnstableFootingEffect() { diff --git a/Mage.Sets/src/mage/cards/u/UnstableShapeshifter.java b/Mage.Sets/src/mage/cards/u/UnstableShapeshifter.java index 99bf874862..d91b45043f 100644 --- a/Mage.Sets/src/mage/cards/u/UnstableShapeshifter.java +++ b/Mage.Sets/src/mage/cards/u/UnstableShapeshifter.java @@ -27,10 +27,10 @@ import mage.util.functions.EmptyApplyToPermanent; */ public final class UnstableShapeshifter extends CardImpl { - final static FilterCreaturePermanent filterAnotherCreature = new FilterCreaturePermanent("another creature"); + static final FilterCreaturePermanent filterAnotherCreature = new FilterCreaturePermanent("another creature"); static { - filterAnotherCreature.add(new AnotherPredicate()); + filterAnotherCreature.add(AnotherPredicate.instance); } public UnstableShapeshifter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java b/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java index 6ab5dcab8e..791a81e9be 100644 --- a/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java +++ b/Mage.Sets/src/mage/cards/u/UnstoppableAsh.java @@ -25,7 +25,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class UnstoppableAsh extends CardImpl { - final static private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); + static final private FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature you control"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/u/UntamedMight.java b/Mage.Sets/src/mage/cards/u/UntamedMight.java index 3d887eced9..9ae6aca3a4 100644 --- a/Mage.Sets/src/mage/cards/u/UntamedMight.java +++ b/Mage.Sets/src/mage/cards/u/UntamedMight.java @@ -20,7 +20,7 @@ public final class UntamedMight extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}"); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BoostTargetEffect(new ManacostVariableValue(), new ManacostVariableValue(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(ManacostVariableValue.instance, ManacostVariableValue.instance, Duration.EndOfTurn)); } public UntamedMight(final UntamedMight card) { diff --git a/Mage.Sets/src/mage/cards/u/UnwindingClock.java b/Mage.Sets/src/mage/cards/u/UnwindingClock.java index 4c0b876739..13f76f9525 100644 --- a/Mage.Sets/src/mage/cards/u/UnwindingClock.java +++ b/Mage.Sets/src/mage/cards/u/UnwindingClock.java @@ -1,32 +1,25 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterArtifactPermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward */ public final class UnwindingClock extends CardImpl { public UnwindingClock(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // Untap all artifacts you control during each other player's untap step. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new UnwindingClockEffect())); @@ -72,7 +65,7 @@ class UnwindingClockEffect extends ContinuousEffectImpl { for (Permanent artifact : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(artifact, game).keySet()) { - untap &= effect.canBeUntapped(artifact, source, game); + untap &= effect.canBeUntapped(artifact, source, game, true); } if (untap) { artifact.untap(game); diff --git a/Mage.Sets/src/mage/cards/u/UphillBattle.java b/Mage.Sets/src/mage/cards/u/UphillBattle.java index c64a2c8085..de4f6e2521 100644 --- a/Mage.Sets/src/mage/cards/u/UphillBattle.java +++ b/Mage.Sets/src/mage/cards/u/UphillBattle.java @@ -46,11 +46,11 @@ public final class UphillBattle extends CardImpl { class PlayCreatureLandWatcher extends Watcher { - final Set playerPlayedLand = new HashSet<>(); // player that played land - final Set landPlayed = new HashSet<>(); // land played + private final Set playerPlayedLand = new HashSet<>(); // player that played land + private final Set landPlayed = new HashSet<>(); // land played public PlayCreatureLandWatcher() { - super(PlayCreatureLandWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayCreatureLandWatcher(final PlayCreatureLandWatcher watcher) { @@ -108,8 +108,8 @@ class UphillBattleTapEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Permanent target = ((EntersTheBattlefieldEvent) event).getTarget(); - CreatureWasCastWatcher creatureSpellWatcher = (CreatureWasCastWatcher) game.getState().getWatchers().get(CreatureWasCastWatcher.class.getSimpleName()); - PlayCreatureLandWatcher landWatcher = (PlayCreatureLandWatcher) game.getState().getWatchers().get(PlayCreatureLandWatcher.class.getSimpleName()); + CreatureWasCastWatcher creatureSpellWatcher = game.getState().getWatcher(CreatureWasCastWatcher.class); + PlayCreatureLandWatcher landWatcher = game.getState().getWatcher(PlayCreatureLandWatcher.class); if (target != null && ((creatureSpellWatcher != null && creatureSpellWatcher.wasCreatureCastThisTurn(target.getId())) diff --git a/Mage.Sets/src/mage/cards/u/UrbanBurgeoning.java b/Mage.Sets/src/mage/cards/u/UrbanBurgeoning.java index 2b9c1d2c91..e02e3c9596 100644 --- a/Mage.Sets/src/mage/cards/u/UrbanBurgeoning.java +++ b/Mage.Sets/src/mage/cards/u/UrbanBurgeoning.java @@ -1,7 +1,5 @@ - package mage.cards.u; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ContinuousEffectImpl; @@ -11,22 +9,15 @@ import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPermanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class UrbanBurgeoning extends CardImpl { @@ -34,7 +25,7 @@ public final class UrbanBurgeoning extends CardImpl { static final String rule = "Enchanted land has \"Untap this land during each other player's untap step.\""; public UrbanBurgeoning(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{G}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}"); this.subtype.add(SubType.AURA); // Enchant land @@ -87,7 +78,7 @@ class UrbanBurgeoningUntapEffect extends ContinuousEffectImpl { Permanent land = game.getPermanent(source.getSourceId()); boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(land, game).keySet()) { - untap &= effect.canBeUntapped(land, source, game); + untap &= effect.canBeUntapped(land, source, game, true); } if (untap) { land.untap(game); diff --git a/Mage.Sets/src/mage/cards/u/UrborgJustice.java b/Mage.Sets/src/mage/cards/u/UrborgJustice.java index 526a940374..b2a73dfa77 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgJustice.java +++ b/Mage.Sets/src/mage/cards/u/UrborgJustice.java @@ -61,7 +61,7 @@ class UrborgJusticeDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CreaturesDiedWatcher watcher = (CreaturesDiedWatcher) game.getState().getWatchers().get(CreaturesDiedWatcher.class.getSimpleName()); + CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class); if (watcher != null) { return watcher.getAmountOfCreaturesDiedThisTurnByOwner(sourceAbility.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/u/UrborgPanther.java b/Mage.Sets/src/mage/cards/u/UrborgPanther.java new file mode 100644 index 0000000000..657d34d585 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UrborgPanther.java @@ -0,0 +1,81 @@ +package mage.cards.u; + +import java.util.UUID; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.common.SacrificeTargetCost; +import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ColoredManaSymbol; +import mage.constants.SubType; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.permanent.BlockingAttackerIdPredicate; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetControlledCreaturePermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author Ketsuban + */ +public class UrborgPanther extends CardImpl { + + private static final FilterControlledCreaturePermanent filter1 = new FilterControlledCreaturePermanent("creature named Feral Shadow"); + private static final FilterControlledCreaturePermanent filter2 = new FilterControlledCreaturePermanent("creature named Breathstealer"); + + private static final FilterCard filterCard = new FilterCreatureCard("card named Spirit of the Night"); + + static { + filter1.add(new NamePredicate("Feral Shadow")); + filter2.add(new NamePredicate("Breathstealer")); + filterCard.add(new NamePredicate("Spirit of the Night")); + } + + public UrborgPanther(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[] { CardType.CREATURE }, "{2}{B}"); + this.subtype.add(SubType.NIGHTSTALKER); + this.subtype.add(SubType.CAT); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // B, Sacrifice Urborg Panther: Destroy target creature blocking Urborg Panther. + Ability ability1 = new SimpleActivatedAbility(new DestroyTargetEffect(), + new ColoredManaCost(ColoredManaSymbol.B)); + ability1.addCost(new SacrificeSourceCost()); + FilterCreaturePermanent filter = new FilterCreaturePermanent("creature blocking {this}"); + filter.add(new BlockingAttackerIdPredicate(this.getId())); + ability1.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability1); + + // Sacrifice a creature named Feral Shadow, a creature named Breathstealer, and + // Urborg Panther: Search your library for a card named Spirit of the Night and + // put that card onto the battlefield. Then shuffle your library. + Ability ability2 = new SimpleActivatedAbility( + new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(1, 1, new FilterCard(filterCard))), + new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter1, true))); + ability2.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter2, true))); + ability2.addCost(new SacrificeSourceCost()); + this.addAbility(ability2); + } + + public UrborgPanther(final UrborgPanther card) { + super(card); + } + + @Override + public UrborgPanther copy() { + return new UrborgPanther(this); + } + +} diff --git a/Mage.Sets/src/mage/cards/u/UrborgSyphonMage.java b/Mage.Sets/src/mage/cards/u/UrborgSyphonMage.java index 94145a9ebe..b8374ff492 100644 --- a/Mage.Sets/src/mage/cards/u/UrborgSyphonMage.java +++ b/Mage.Sets/src/mage/cards/u/UrborgSyphonMage.java @@ -40,7 +40,7 @@ public final class UrborgSyphonMage extends CardImpl { this.addAbility(ability); } - public UrborgSyphonMage(final UrborgSyphonMage card) { + private UrborgSyphonMage(final UrborgSyphonMage card) { super(card); } @@ -57,7 +57,7 @@ class UrborgSyphonMageEffect extends OneShotEffect { staticText = "Each other player loses 2 life. You gain life equal to the life lost this way"; } - public UrborgSyphonMageEffect(final UrborgSyphonMageEffect effect) { + private UrborgSyphonMageEffect(final UrborgSyphonMageEffect effect) { super(effect); } @@ -67,10 +67,10 @@ class UrborgSyphonMageEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (!Objects.equals(playerId, source.getControllerId())) { + if (!source.isControlledBy(playerId)) { Player player = game.getPlayer(playerId); if (player != null) { - damage += player.damage(2, source.getSourceId(), game, false, true); + damage += player.loseLife(2, game, false); } } } diff --git a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java index ca6852a51c..e5fbd52a95 100644 --- a/Mage.Sets/src/mage/cards/u/UrgeToFeed.java +++ b/Mage.Sets/src/mage/cards/u/UrgeToFeed.java @@ -50,7 +50,7 @@ class UrgeToFeedEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.VAMPIRE)); } diff --git a/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java new file mode 100644 index 0000000000..fca36bf6e5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/u/UrzaAcademyHeadmaster.java @@ -0,0 +1,573 @@ +package mage.cards.u; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.dynamicvalue.common.ControllerLifeCount; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.PermanentsTargetOpponentControlsCount; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.Effect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.continuous.*; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.DistributeCountersEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; +import mage.abilities.effects.common.turn.ControlTargetPlayerNextTurnEffect; +import mage.abilities.keyword.FirstStrikeAbility; +import mage.abilities.keyword.LifelinkAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.choices.Choice; +import mage.choices.ChoiceImpl; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.common.*; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.game.command.emblems.*; +import mage.game.permanent.token.*; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.common.*; +import mage.util.RandomUtil; + +import java.util.*; + +/** + * @author L_J + */ +public final class UrzaAcademyHeadmaster extends CardImpl { + + public UrzaAcademyHeadmaster(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{W}{U}{B}{R}{G}"); + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.URZA); + + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // +1: Head to AskUrza.com and click +1. + this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(1, setInfo), 1)); + + // -1: Head to AskUrza.com and click -1. + this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(2, setInfo), -1)); + + // -6: Head to AskUrza.com and click -6. + this.addAbility(new LoyaltyAbility(new UrzaAcademyHeadmasterRandomEffect(3, setInfo), -6)); + + } + + public UrzaAcademyHeadmaster(final UrzaAcademyHeadmaster card) { + super(card); + } + + @Override + public UrzaAcademyHeadmaster copy() { + return new UrzaAcademyHeadmaster(this); + } +} + +class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect { + + private int selection; + private CardSetInfo setInfo; + private static final FilterCreaturePermanent filter1 = new FilterCreaturePermanent("creatures you control"); + private static final FilterPermanent filter2 = new FilterPermanent("noncreature permanent"); + private static final FilterCard filter3 = new FilterCard("creature and/or land cards"); + private static final FilterPermanent filter4 = new FilterPermanent("creatures and/or planeswalkers"); + + static { + filter1.add(new ControllerPredicate(TargetController.YOU)); + filter2.add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + filter3.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.LAND))); + filter4.add(Predicates.or( + new CardTypePredicate(CardType.CREATURE), + new CardTypePredicate(CardType.PLANESWALKER))); + } + + public UrzaAcademyHeadmasterRandomEffect(int selection, CardSetInfo setInfo) { + super(Outcome.Neutral); + this.selection = selection; + this.setInfo = setInfo.copy(); + switch (selection) { + case 1: + staticText = "Head to AskUrza.com and click +1"; + break; + case 2: + staticText = "Head to AskUrza.com and click -1"; + break; + case 3: + staticText = "Head to AskUrza.com and click -6"; + } + } + + public UrzaAcademyHeadmasterRandomEffect(final UrzaAcademyHeadmasterRandomEffect effect) { + super(effect); + this.selection = effect.selection; + this.setInfo = effect.setInfo.copy(); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + int result = RandomUtil.nextInt(20) + 1; + List effects = new ArrayList<>(); + Target target = null; + StringBuilder sb = new StringBuilder("[URZA] "); + + while (true) { + switch (selection) { + + // ABILITY +1 + case 1: + switch (result) { + case 1: // AJANI STEADFAST 1 + sb.append("Until end of turn, up to one target creature gets +1/+1 and gains first strike, vigilance, and lifelink."); + effects.add(new BoostTargetEffect(1, 1, Duration.EndOfTurn)); + effects.add(new GainAbilityTargetEffect(FirstStrikeAbility.getInstance(), Duration.EndOfTurn)); + effects.add(new GainAbilityTargetEffect(VigilanceAbility.getInstance(), Duration.EndOfTurn)); + effects.add(new GainAbilityTargetEffect(LifelinkAbility.getInstance(), Duration.EndOfTurn)); + target = new TargetCreaturePermanent(0, 1); + break; + case 2: // AJANI MENTOR OF HEROES 1 + sb.append("Distribute three +1/+1 counters among one, two, or three target creatures you control."); + effects.add(new DistributeCountersEffect(CounterType.P1P1, 3, false, "one, two, or three target creatures you control")); + target = new TargetCreaturePermanentAmount(3, filter1); + break; + case 3: // NICOL BOLAS PLANESWALKER 1 + sb.append("Destroy target noncreature permanent."); + effects.add(new DestroyTargetEffect()); + target = new TargetPermanent(filter2); + break; + case 4: // CHANDRA FLAMECALLER 1 + // TODO: replace ALL new mage.cards.* code with abilities index CONST or add tests to ensure about names nad abilities + sb.append("Create two 3/1 red Elemental creature tokens with haste. Exile them at the beginning of the next end step."); + effects.add(new mage.cards.c.ChandraFlamecaller(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 5: // ELSPETH SUNS CHAMPION 1 + sb.append("Create three 1/1 white Soldier creature tokens."); + effects.add(new CreateTokenEffect(new SoldierToken(), 3)); + break; + case 6: // GARRUK APEX PREDATOR 2 + sb.append("Create a 3/3 black Beast creature token with deathtouch."); + effects.add(new CreateTokenEffect(new GarrukApexPredatorBeastToken())); + break; + case 7: // GARRUK CALLER OF BEASTS 1 + sb.append("Reveal the top five cards of your library. Put all creature cards revealed this way into your hand and the rest on the bottom of your library in any order."); + effects.add(new RevealLibraryPutIntoHandEffect(5, new FilterCreatureCard("creature cards"), Zone.LIBRARY)); + break; + case 8: // GIDEON JURA 1 + sb.append("During target opponent’s next turn, creatures that player controls attack Urza if able."); + effects.add(new mage.cards.g.GideonJura(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + target = new TargetOpponent(); + break; + case 9: // GIDEON CHAMPION OF JUSTICE 1 + sb.append("Put a loyalty counter on Urza for each creature target opponent controls."); + effects.add(new AddCountersSourceEffect(CounterType.LOYALTY.createInstance(0), new PermanentsTargetOpponentControlsCount(new FilterCreaturePermanent()), true)); + target = new TargetOpponent(); + break; + case 10: // JACE ARCHITECT OF THOUGHT 1 + sb.append("Until your next turn, whenever a creature an opponent controls attacks, it gets -1/-0 until end of turn."); + effects.add(new mage.cards.j.JaceArchitectOfThought(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 11: // KARN LIBERATED 1 + sb.append("Target player exiles a card from his or her hand."); + effects.add(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard())); + target = new TargetPlayer(); + break; + case 12: // NISSA SAGE ANIMIST 1 + sb.append("Reveal the top card of your library. If it’s a land card, put it onto the battlefield. Otherwise, put it into your hand."); + effects.add(new mage.cards.n.NissaSageAnimist(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 13: // NISSA WORLDWAKER 1 + sb.append("Target land you control becomes a 4/4 Elemental creature with trample. It’s still a land."); + effects.add(new mage.cards.n.NissaWorldwaker(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + target = new TargetPermanent(new FilterControlledLandPermanent()); + break; + case 14: // SARKHAN UNBROKEN 1 + sb.append("Draw a card, then add one mana of any color to your mana pool."); + effects.add(new mage.cards.s.SarkhanUnbroken(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 15: // SARKHAN THE DRAGONSPEAKER 1 + sb.append("Until end of turn, Urza becomes a legendary 4/4 red Dragon creature with flying, indestructible, and haste. (He doesn’t lose loyalty while he’s not a planeswalker.)"); + effects.add(new mage.cards.s.SarkhanTheDragonspeaker(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 16: // SORIN SOLEMN VISITOR 1 + sb.append("Until your next turn, creatures you control get +1/+0 and gain lifelink."); + effects.add(new BoostControlledEffect(1, 0, Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES)); + effects.add(new GainAbilityControlledEffect(LifelinkAbility.getInstance(), Duration.UntilYourNextTurn, StaticFilters.FILTER_PERMANENT_CREATURES)); + break; + case 17: // TEZZERET AGENT OF BOLAS 1 + sb.append("Look at the top five cards of your library. You may reveal an artifact card from among them and put it into your hand. Put the rest on the bottom of your library in any order."); + effects.add(new LookLibraryAndPickControllerEffect(5, 1, new FilterArtifactCard(), true)); + break; + case 18: // UGIN 1 + sb.append("Urza deals 3 damage to any target."); + effects.add(new DamageTargetEffect(3)); + target = new TargetAnyTarget(); + break; + case 19: // VRASKA 1 + sb.append("Until your next turn, whenever a creature deals combat damage to Urza, destroy that creature."); + effects.add(new mage.cards.v.VraskaTheUnseen(controller.getId(), setInfo).getAbilities().get(2).getEffects().get(0)); + break; + case 20: // (altered) XENAGOS 1 + sb.append("Add X mana in any combination of colors to your mana pool, where X is the number of creatures you control."); + effects.add(new UrzaAcademyHeadmasterManaEffect()); + break; + } + break; + + // ABILITY -1 + case 2: + switch (result) { + case 1: // (altered) CHANDRA FLAMECALLER 3 + sb.append("Urza deals 3 damage to each creature."); + effects.add(new DamageAllEffect(3, StaticFilters.FILTER_PERMANENT_CREATURE)); + break; + case 2: // NICOL BOLAS PLANESWALKER 2 + sb.append("Gain control of target creature."); + effects.add(new GainControlTargetEffect(Duration.Custom)); + target = new TargetCreaturePermanent(); + break; + case 3: // (double) SORIN MARKOV 1 + sb.append("Urza deals 4 damage to target creature or player and you gain 4 life."); + effects.add(new DamageTargetEffect(4)); + effects.add(new GainLifeEffect(4)); + target = new TargetAnyTarget(); + break; + case 4: // GARRUK APEX PREDATOR 3 + sb.append("Destroy target creature. You gain life equal to its toughness."); + effects.add(new DestroyTargetEffect()); + effects.add(new mage.cards.g.GarrukApexPredator(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(1)); + target = new TargetCreaturePermanent(); + break; + case 5: // GIDEON ALLY OF ZENDIKAR 3 + sb.append("You get an emblem with “Creatures you control get +1/+1.”"); + effects.add(new GetEmblemEffect(new GideonAllyOfZendikarEmblem())); + break; + case 6: // (altered) GARRUK CALLER OF BEASTS 2 + sb.append("You may put a creature card from your hand onto the battlefield."); + effects.add(new PutCardFromHandOntoBattlefieldEffect(new FilterCreatureCard())); + break; + case 7: // (altered) JACE THE MIND SCULPTOR 2 + sb.append("Draw three cards, then put a card from your hand on top of your library."); + effects.add(new UrzaAcademyHeadmasterBrainstormEffect()); + break; + case 8: // JACE MEMORY ADEPT 2 + sb.append("Target player puts the top ten cards of his or her library into his or her graveyard."); + effects.add(new PutLibraryIntoGraveTargetEffect(10)); + target = new TargetPlayer(); + break; + case 9: // JACE ARCHITECT OF THOUGHT 2 + sb.append("Reveal the top five cards of your library. An opponent separates those cards into two piles. Put one pile into your hand and the other on the bottom of your library in any order."); + effects.add(new mage.cards.j.JaceArchitectOfThought(controller.getId(), setInfo).getAbilities().get(3).getEffects().get(0)); + break; + case 10: // KARN LIBERATED 2 + sb.append("Exile target permanent."); + effects.add(new ExileTargetEffect()); + target = new TargetPermanent(); + break; + case 11: // (altered) GARRUK CALLER OF BEASTS 1 + sb.append("Reveal the top five cards of your library. You may put all creature cards and/or land cards from among them into your hand. Put the rest into your graveyard."); + effects.add(new RevealLibraryPutIntoHandEffect(5, filter3, Zone.LIBRARY)); + break; + case 12: // (altered) LILIANA VESS 2 + sb.append("Search your library for a card and put that card into your hand. Then shuffle your library."); + effects.add(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(new FilterCard("a card")), false, true)); + break; + case 13: // (double) LILIANA OF THE VEIL 2 + sb.append("Target player sacrifices two creatures."); + effects.add(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 2, "Target player")); + target = new TargetPlayer(); + break; + case 14: // OB NIXILIS OF THE BLACK OATH 2 + sb.append("Create a 5/5 black Demon creature token with flying. You lose 2 life."); + effects.add(new CreateTokenEffect(new DemonToken())); + effects.add(new LoseLifeSourceControllerEffect(2)); + break; + case 15: // (gold) SARKHAN UNBROKEN 2 + sb.append("Create a 4/4 gold Dragon creature token with flying."); + effects.add(new CreateTokenEffect(new DragonTokenGold(), 1)); + break; + case 16: // SORIN MARKOV 2 + sb.append("Target player’s life total becomes 10."); + effects.add(new mage.cards.s.SorinMarkov(controller.getId(), setInfo).getAbilities().get(3).getEffects().get(0)); + target = new TargetPlayer(); + break; + case 17: // VRASKA 2 + sb.append("Destroy target nonland permanent."); + effects.add(new DestroyTargetEffect()); + target = new TargetNonlandPermanent(); + break; + case 18: // UNIQUE + sb.append("Return target permanent from a graveyard to the battlefield under your control."); + effects.add(new ReturnFromGraveyardToBattlefieldTargetEffect()); + target = new TargetCardInGraveyard(new FilterPermanentCard()); + break; + case 19: // (double) GARRUK WILDSPEAKER 2 + sb.append("Create two 3/3 green Beast creature tokens."); + effects.add(new CreateTokenEffect(new BeastToken(), 2)); + break; + case 20: // UNIQUE + sb.append("Draw four cards and discard two cards."); + effects.add(new DrawCardSourceControllerEffect(4)); + effects.add(new DiscardControllerEffect(2)); + break; + } + break; + + // ABILITY -6 + case 3: + switch (result) { + case 1: // NICOL BOLAS PLANESWALKER 3 + sb.append("Urza deals 7 damage to target player. That player discards seven cards, then sacrifices seven permanents."); + effects.add(new DamageTargetEffect(7)); + effects.add(new DiscardTargetEffect(7)); + effects.add(new SacrificeEffect(new FilterPermanent(), 7, "then")); + target = new TargetPlayerOrPlaneswalker(); + break; + case 2: // AJANI STEADFAST 3 + sb.append("You get an emblem with “If a source would deal damage to you or a planeswalker you control, prevent all but 1 of that damage.”"); + effects.add(new GetEmblemEffect(new AjaniSteadfastEmblem())); + break; + case 3: // AJANI VENGEANT 3 + sb.append("Destroy all lands target player controls."); + effects.add(new DestroyAllControlledTargetEffect(new FilterLandPermanent())); + target = new TargetPlayer(); + break; + case 4: // AJANI CALLER OF THE PRIDE 3 + sb.append("Create X 2/2 white Cat creature tokens, where X is your life total."); + effects.add(new CreateTokenEffect(new CatToken(), ControllerLifeCount.instance)); + break; + case 5: // AJANI MENTOR OF HEROES 3 + sb.append("You gain 100 life."); + effects.add(new GainLifeEffect(100)); + break; + case 6: // CHANDRA NALAAR 3 + sb.append("Urza deals 10 damage to target player and each creature he or she controls."); + effects.add(new DamageTargetEffect(10)); + effects.add(new DamageAllControlledTargetEffect(10, new FilterCreaturePermanent())); + target = new TargetPlayerOrPlaneswalker(); + break; + case 7: // DOMRI RADE 3 + sb.append("You get an emblem with “Creatures you control have double strike, trample, hexproof, and haste.”"); + effects.add(new GetEmblemEffect(new DomriRadeEmblem())); + break; + case 8: // ELSPETH KNIGHT ERRANT 3 + sb.append("You get an emblem with “Artifacts, creatures, enchantments, and lands you control have indestructible.”"); + effects.add(new GetEmblemEffect(new ElspethKnightErrantEmblem())); + break; + case 9: // GARRUK PRIMAL HUNTER 3 + sb.append("Create a 6/6 green Wurm creature token for each land you control."); + effects.add(new CreateTokenEffect(new WurmToken(), new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent()))); + break; + case 10: // JACE THE LIVING GUILDPACT 3 + sb.append("Each player shuffles his or her hand and graveyard into his or her library. You draw seven cards."); + effects.add(new ShuffleHandGraveyardAllEffect()); + effects.add(new DrawCardSourceControllerEffect(7)); + break; + case 11: // SORIN LORD OF INNISTRAD 3 + sb.append("Destroy up to three target creatures and/or other planeswalkers. Return each card put into a graveyard this way to the battlefield under your control."); + effects.add(new mage.cards.s.SorinLordOfInnistrad(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0)); + target = new TargetPermanent(0, 3, filter4, false); + break; + case 12: // VENSER 3 + sb.append("You get an emblem with “Whenever you cast a spell, exile target permanent.”"); + effects.add(new GetEmblemEffect(new VenserTheSojournerEmblem())); + break; + case 13: // KIORA MASTER OF THE DEPTHS 3 + sb.append("You get an emblem with “Whenever a creature enters the battlefield under your control, you may have it fight target creature.” Then create three 8/8 blue Octopus creature tokens."); + effects.add(new CreateTokenEffect(new OctopusToken(), 3)); + effects.add(new GetEmblemEffect(new KioraMasterOfTheDepthsEmblem())); + break; + case 14: // SORIN MARKOV 3 + sb.append("You control target player during that player’s next turn."); + effects.add(new ControlTargetPlayerNextTurnEffect()); + target = new TargetPlayer(); + break; + case 15: // JACE THE MIND SCULPTOR 4 + sb.append("Exile all cards from target player’s library, then that player shuffles his or her hand into his or her library."); + effects.add(new mage.cards.j.JaceTheMindSculptor(controller.getId(), setInfo).getAbilities().get(5).getEffects().get(0)); + target = new TargetPlayer(); + break; + case 16: // VRASKA 3 + sb.append("Create three 1/1 black Assassin creature tokens with “Whenever this creature deals combat damage to a player, that player loses the game.”"); + effects.add(new CreateTokenEffect(new AssassinToken())); + break; + case 17: // LILIANA VESS 3 + sb.append("Put all creature cards from all graveyards onto the battlefield under your control."); + effects.add(new mage.cards.l.LilianaVess(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0)); + break; + case 18: // NISSA VOICE OF ZENDIKAR 3 + sb.append("You gain X life and draw X cards, where X is the number of lands you control."); + effects.add(new GainLifeEffect(new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent()))); + effects.add(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledLandPermanent()))); + break; + case 19: // RAL ZAREK 3 + sb.append("Flip five coins. Take an extra turn after this one for each coin that comes up heads."); + effects.add(new mage.cards.r.RalZarek(controller.getId(), setInfo).getAbilities().get(4).getEffects().get(0)); + break; + case 20: // UGIN 3 + sb.append("You gain 7 life, draw seven cards, then put up to seven permanent cards from your hand onto the battlefield."); + effects.add(new mage.cards.u.UginTheSpiritDragonEffect3()); + break; + } + break; + } + + game.informPlayers(sb.toString()); + if (target != null) { + if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.canRespond()) { + target.chooseTarget(outcome, controller.getId(), source, game); + } else { + // 1/19/2018 (...) If the ability that comes up requires a target and there are no legal targets available, click again until that’s not true. + game.informPlayers("[URZA] Target can't be chosen, picking next ability..."); + result = RandomUtil.nextInt(20) + 1; + effects.clear(); + target = null; + sb = new StringBuilder("[URZA] "); + continue; + } + source.addTarget(target); + } + if (target == null || target.isChosen()) { + for (Effect effect : effects) { + if (effect instanceof ContinuousEffect) { + game.addEffect((ContinuousEffect) effect, source); + } else { + effect.apply(game, source); + } + } + return true; + } + break; + } + } + + return false; + } + + @Override + public UrzaAcademyHeadmasterRandomEffect copy() { + return new UrzaAcademyHeadmasterRandomEffect(this); + } +} + +class UrzaAcademyHeadmasterManaEffect extends OneShotEffect { + + public UrzaAcademyHeadmasterManaEffect() { + super(Outcome.PutManaInPool); + } + + public UrzaAcademyHeadmasterManaEffect(final UrzaAcademyHeadmasterManaEffect effect) { + super(effect); + } + + @Override + public UrzaAcademyHeadmasterManaEffect copy() { + return new UrzaAcademyHeadmasterManaEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + int x = game.getBattlefield().count(new FilterControlledCreaturePermanent(), source.getSourceId(), source.getControllerId(), game); + Choice manaChoice = new ChoiceImpl(); + Set choices = new LinkedHashSet<>(); + choices.add("White"); + choices.add("Blue"); + choices.add("Black"); + choices.add("Red"); + choices.add("Green"); + manaChoice.setChoices(choices); + manaChoice.setMessage("Select color of mana to add"); + + for (int i = 0; i < x; i++) { + Mana mana = new Mana(); + if (!player.choose(Outcome.Benefit, manaChoice, game)) { + return false; + } + if (manaChoice.getChoice() == null) { // can happen if player leaves game + return false; + } + switch (manaChoice.getChoice()) { + case "White": + mana.increaseWhite(); + break; + case "Blue": + mana.increaseBlue(); + break; + case "Black": + mana.increaseBlack(); + break; + case "Red": + mana.increaseRed(); + break; + case "Green": + mana.increaseGreen(); + break; + } + player.getManaPool().addMana(mana, game, source); + } + return true; + } + return false; + } +} + +class UrzaAcademyHeadmasterBrainstormEffect extends OneShotEffect { + + public UrzaAcademyHeadmasterBrainstormEffect() { + super(Outcome.DrawCard); + staticText = "draw three cards, then put a card from your hand on top of your library"; + } + + public UrzaAcademyHeadmasterBrainstormEffect(final UrzaAcademyHeadmasterBrainstormEffect effect) { + super(effect); + } + + @Override + public UrzaAcademyHeadmasterBrainstormEffect copy() { + return new UrzaAcademyHeadmasterBrainstormEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player != null) { + player.drawCards(3, game); + putOnLibrary(player, source, game); + return true; + } + return false; + } + + private boolean putOnLibrary(Player player, Ability source, Game game) { + TargetCardInHand target = new TargetCardInHand(); + if (target.canChoose(source.getSourceId(), player.getId(), game)) { + player.chooseTarget(Outcome.ReturnToHand, target, source, game); + Card card = player.getHand().get(target.getFirstTarget(), game); + if (card != null) { + return player.moveCardToLibraryWithInfo(card, source.getSourceId(), game, Zone.HAND, true, false); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/u/UrzasBauble.java b/Mage.Sets/src/mage/cards/u/UrzasBauble.java index 4975d5af23..31f43a7691 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasBauble.java +++ b/Mage.Sets/src/mage/cards/u/UrzasBauble.java @@ -72,13 +72,13 @@ class LookAtRandomCardEffect extends OneShotEffect { Player you = game.getPlayer(source.getControllerId()); Player targetPlayer = game.getPlayer(source.getFirstTarget()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (you != null && targetPlayer != null) { + if (you != null && targetPlayer != null && sourceObject != null) { if(!targetPlayer.getHand().isEmpty()) { Cards randomCard = new CardsImpl(); Card card = targetPlayer.getHand().getRandom(game); randomCard.add(card); - you.lookAtCards(sourceObject != null ? sourceObject.getName() : null, randomCard, game); + you.lookAtCards(sourceObject.getName(), randomCard, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/u/UrzasFilter.java b/Mage.Sets/src/mage/cards/u/UrzasFilter.java index b9fd9d10cf..fb3d990ecd 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasFilter.java +++ b/Mage.Sets/src/mage/cards/u/UrzasFilter.java @@ -20,7 +20,7 @@ public final class UrzasFilter extends CardImpl { private static final FilterCard filter = new FilterCard("multicolored spells"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public UrzasFilter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/u/UrzasMiter.java b/Mage.Sets/src/mage/cards/u/UrzasMiter.java index d65cdd52c5..9294d12231 100644 --- a/Mage.Sets/src/mage/cards/u/UrzasMiter.java +++ b/Mage.Sets/src/mage/cards/u/UrzasMiter.java @@ -60,10 +60,10 @@ class UrzasMiterDoIfCostPaid extends DoIfCostPaid { @Override public boolean apply(Game game, Ability source) { - UrzasMiterWatcher watcher = (UrzasMiterWatcher) game.getState().getWatchers().get(UrzasMiterWatcher.class.getSimpleName()); - if(!watcher.cards.contains(source.getFirstTarget())) + UrzasMiterWatcher watcher = game.getState().getWatcher(UrzasMiterWatcher.class); + if(watcher != null && !watcher.cards.contains(source.getFirstTarget())) { return super.apply(game, source); - + } return false; } @@ -74,7 +74,7 @@ class UrzasMiterWatcher extends Watcher { List cards; public UrzasMiterWatcher() { - super(UrzasMiterWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); this.cards = new ArrayList<>(); } diff --git a/Mage.Sets/src/mage/cards/v/VadersCommand.java b/Mage.Sets/src/mage/cards/v/VadersCommand.java index d9facdc1ba..69208f4bc3 100644 --- a/Mage.Sets/src/mage/cards/v/VadersCommand.java +++ b/Mage.Sets/src/mage/cards/v/VadersCommand.java @@ -47,19 +47,19 @@ public final class VadersCommand extends CardImpl { // Destroy target planeswalker. Mode mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetPermanent(filterPlaneswalker)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetPermanent(filterPlaneswalker)); this.getSpellAbility().addMode(mode); // Destroy target nonartifact creature. mode = new Mode(); - mode.getEffects().add(new DestroyTargetEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filterNonArtifact)); + mode.addEffect(new DestroyTargetEffect()); + mode.addTarget(new TargetCreaturePermanent(filterNonArtifact)); this.getSpellAbility().addMode(mode); // Gain 5 life. mode = new Mode(); - mode.getEffects().add(new GainLifeEffect(5).setText("Gain 5 life")); + mode.addEffect(new GainLifeEffect(5).setText("Gain 5 life")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VaevictisAsmadiTheDire.java b/Mage.Sets/src/mage/cards/v/VaevictisAsmadiTheDire.java index 70cdd36379..500691eb9c 100644 --- a/Mage.Sets/src/mage/cards/v/VaevictisAsmadiTheDire.java +++ b/Mage.Sets/src/mage/cards/v/VaevictisAsmadiTheDire.java @@ -128,7 +128,7 @@ class VaevictisAsmadiTheDireEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - List playersToFlip = new ArrayList(); + List playersToFlip = new ArrayList<>(); for (Target target : source.getTargets()) { for (UUID permId : target.getTargets()) { Permanent permanent = game.getPermanent(permId); diff --git a/Mage.Sets/src/mage/cards/v/ValorInAkros.java b/Mage.Sets/src/mage/cards/v/ValorInAkros.java index 851ff2e66a..3f778cba22 100644 --- a/Mage.Sets/src/mage/cards/v/ValorInAkros.java +++ b/Mage.Sets/src/mage/cards/v/ValorInAkros.java @@ -1,25 +1,32 @@ package mage.cards.v; -import java.util.UUID; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; 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.Zone; +import mage.filter.StaticFilters; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class ValorInAkros extends CardImpl { public ValorInAkros(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); // Whenever a creature enters the battlefield under your control, creatures you control get +1/+1 until end of turn. - this.addAbility(new CreatureEntersBattlefieldTriggeredAbility(new BoostControlledEffect(1,1,Duration.EndOfTurn))); + this.addAbility(new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new BoostControlledEffect(1, 1, Duration.EndOfTurn), + StaticFilters.FILTER_PERMANENT_CREATURE_A, + false) + ); } public ValorInAkros(final ValorInAkros card) { diff --git a/Mage.Sets/src/mage/cards/v/ValorousStance.java b/Mage.Sets/src/mage/cards/v/ValorousStance.java index ddfdbb669b..8dcc1cb28a 100644 --- a/Mage.Sets/src/mage/cards/v/ValorousStance.java +++ b/Mage.Sets/src/mage/cards/v/ValorousStance.java @@ -36,8 +36,8 @@ public final class ValorousStance extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent()); // or destroy target creature with toughness 4 or greater. Mode mode1 = new Mode(); - mode1.getEffects().add(new DestroyTargetEffect()); - mode1.getTargets().add(new TargetCreaturePermanent(filter)); + mode1.addEffect(new DestroyTargetEffect()); + mode1.addTarget(new TargetCreaturePermanent(filter)); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/v/VampireOpportunist.java b/Mage.Sets/src/mage/cards/v/VampireOpportunist.java new file mode 100644 index 0000000000..d515ad02bc --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VampireOpportunist.java @@ -0,0 +1,44 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.LoseLifeOpponentsEffect; +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 VampireOpportunist extends CardImpl { + + public VampireOpportunist(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(2); + this.toughness = new MageInt(1); + + // {6}{B}: Each opponent loses 2 life and you gain 2 life. + Ability ability = new SimpleActivatedAbility( + new LoseLifeOpponentsEffect(2), new ManaCostsImpl("{6}{B}") + ); + ability.addEffect(new GainLifeEffect(2).concatBy("and")); + this.addAbility(ability); + } + + private VampireOpportunist(final VampireOpportunist card) { + super(card); + } + + @Override + public VampireOpportunist copy() { + return new VampireOpportunist(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java b/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java index e69e0dc634..ec03cc2a0d 100644 --- a/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java +++ b/Mage.Sets/src/mage/cards/v/VancesBlastingCannons.java @@ -152,7 +152,7 @@ class VancesBlastingCannonsFlipTrigger extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) == 3) { return true; } diff --git a/Mage.Sets/src/mage/cards/v/Vandalize.java b/Mage.Sets/src/mage/cards/v/Vandalize.java index 83c699fb8c..622feb14ea 100644 --- a/Mage.Sets/src/mage/cards/v/Vandalize.java +++ b/Mage.Sets/src/mage/cards/v/Vandalize.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; @@ -10,25 +8,26 @@ import mage.constants.CardType; import mage.target.common.TargetArtifactPermanent; import mage.target.common.TargetLandPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Vandalize extends CardImpl { public Vandalize(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{4}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}"); // Choose one or both - Destroy target artifact; or Destroy target land. this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - - this.getSpellAbility().addTarget(new TargetArtifactPermanent()); + // Destroy target artifact this.getSpellAbility().addEffect(new DestroyTargetEffect()); - + this.getSpellAbility().addTarget(new TargetArtifactPermanent().withChooseHint("destroy")); + // Destroy target land Mode mode1 = new Mode(); - mode1.getTargets().add(new TargetLandPermanent()); - mode1.getEffects().add(new DestroyTargetEffect()); + mode1.addEffect(new DestroyTargetEffect()); + mode1.addTarget(new TargetLandPermanent().withChooseHint("destroy")); this.getSpellAbility().addMode(mode1); } diff --git a/Mage.Sets/src/mage/cards/v/VanquishersBanner.java b/Mage.Sets/src/mage/cards/v/VanquishersBanner.java index 63a8cfd65d..9c935e622c 100644 --- a/Mage.Sets/src/mage/cards/v/VanquishersBanner.java +++ b/Mage.Sets/src/mage/cards/v/VanquishersBanner.java @@ -29,7 +29,7 @@ import mage.game.stack.Spell; */ public final class VanquishersBanner extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control of the chosen type"); static { filter.add(new ControllerPredicate(TargetController.YOU)); diff --git a/Mage.Sets/src/mage/cards/v/VaporSnare.java b/Mage.Sets/src/mage/cards/v/VaporSnare.java index a06a1a75f0..cbf801fdf0 100644 --- a/Mage.Sets/src/mage/cards/v/VaporSnare.java +++ b/Mage.Sets/src/mage/cards/v/VaporSnare.java @@ -79,7 +79,7 @@ class VaporSnareEffect extends OneShotEffect { Player player = game.getPlayer(source.getControllerId()); TargetPermanent target = new TargetPermanent(1, 1, filter, false); - if (target.canChoose(player.getId(), game)) { + if (player != null && target.canChoose(player.getId(), game)) { player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); Permanent permanent = game.getPermanent(target.getFirstTarget()); diff --git a/Mage.Sets/src/mage/cards/v/VastwoodAnimist.java b/Mage.Sets/src/mage/cards/v/VastwoodAnimist.java index c2de9d7915..cf9572a593 100644 --- a/Mage.Sets/src/mage/cards/v/VastwoodAnimist.java +++ b/Mage.Sets/src/mage/cards/v/VastwoodAnimist.java @@ -54,7 +54,7 @@ public final class VastwoodAnimist extends CardImpl { class VastwoodAnimistEffect extends OneShotEffect { - final static FilterControlledPermanent filterAllies = new FilterControlledPermanent("allies you control"); + static final FilterControlledPermanent filterAllies = new FilterControlledPermanent("allies you control"); static { filterAllies.add(new SubtypePredicate(SubType.ALLY)); diff --git a/Mage.Sets/src/mage/cards/v/VectisDominator.java b/Mage.Sets/src/mage/cards/v/VectisDominator.java index b2b966c541..22deeb8810 100644 --- a/Mage.Sets/src/mage/cards/v/VectisDominator.java +++ b/Mage.Sets/src/mage/cards/v/VectisDominator.java @@ -77,8 +77,8 @@ class VectisDominatorEffect extends OneShotEffect { Player player = game.getPlayer(targetCreature.getControllerId()); if (player != null) { cost.clearPaid(); - final StringBuilder sb = new StringBuilder("Pay 2 life? (Otherwise ").append(targetCreature.getName()).append(" will be tapped)"); - if (player.chooseUse(Outcome.Benefit, sb.toString(), source, game)) { + String question = "Pay 2 life? (Otherwise " + targetCreature.getName()+" will be tapped)"; + if (player.chooseUse(Outcome.Benefit, question, source, game)) { cost.pay(source, game, targetCreature.getControllerId(), targetCreature.getControllerId(), true, null); } if (!cost.isPaid()) { diff --git a/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java b/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java index 3d07356eb4..5b573e53f2 100644 --- a/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java +++ b/Mage.Sets/src/mage/cards/v/VedalkenEngineer.java @@ -1,6 +1,7 @@ - package mage.cards.v; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; import mage.ConditionalMana; import mage.MageInt; @@ -36,7 +37,7 @@ public final class VedalkenEngineer extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // {tap}: Add two mana of any one color. Spend this mana only to cast artifact spells or activate abilities of artifacts. + // {T}: Add two mana of any one color. Spend this mana only to cast artifact spells or activate abilities of artifacts. this.addAbility(new SimpleManaAbility(Zone.BATTLEFIELD, new VedalkenEngineerEffect(2, new VedalkenEngineerManaBuilder()), new TapSourceCost())); } @@ -76,10 +77,7 @@ class VedalkenEngineerManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); - if (object != null && object.isArtifact()) { - return true; - } - return false; + return object != null && object.isArtifact(); } } @@ -87,11 +85,17 @@ class VedalkenEngineerEffect extends ManaEffect { private final int amount; private final ConditionalManaBuilder manaBuilder; + protected final ArrayList netMana = new ArrayList<>(); public VedalkenEngineerEffect(int amount, ConditionalManaBuilder manaBuilder) { super(); this.amount = amount; this.manaBuilder = manaBuilder; + netMana.add(Mana.GreenMana(amount)); + netMana.add(Mana.BlueMana(amount)); + netMana.add(Mana.BlackMana(amount)); + netMana.add(Mana.WhiteMana(amount)); + netMana.add(Mana.RedMana(amount)); staticText = "Add " + amount + " mana of any one color. " + manaBuilder.getRule(); } @@ -99,6 +103,7 @@ class VedalkenEngineerEffect extends ManaEffect { super(effect); this.amount = effect.amount; this.manaBuilder = effect.manaBuilder; + this.netMana.addAll(effect.netMana); } @Override @@ -117,12 +122,16 @@ class VedalkenEngineerEffect extends ManaEffect { return false; } + @Override + public List getNetMana(Game game, Ability source) { + return netMana; + } + @Override public Mana produceMana(boolean netMana, Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); ChoiceColor choiceColor = new ChoiceColor(true); if (controller != null && controller.choose(Outcome.Benefit, choiceColor, game)) { - Mana condMana = manaBuilder.setMana(choiceColor.getMana(amount), source, game).build(); return condMana; } diff --git a/Mage.Sets/src/mage/cards/v/VeilOfBirds.java b/Mage.Sets/src/mage/cards/v/VeilOfBirds.java new file mode 100644 index 0000000000..53e476fca4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeilOfBirds.java @@ -0,0 +1,66 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +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.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class VeilOfBirds extends CardImpl { + + private static final FilterSpell filter = new FilterSpell(); + + public VeilOfBirds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + // When an opponent casts a spell, if Veil of Birds is an enchantment, Veil of Birds becomes a 1/1 Bird creature with flying. + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeilOfBirdsToken(), "", Duration.WhileOnBattlefield, true, false), + filter, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever an opponent casts a spell, if Veil of Birds is an enchantment, Veil of Birds becomes a 1/1 Bird creature with flying.")); + } + + public VeilOfBirds(final VeilOfBirds card) { + super(card); + } + + @Override + public VeilOfBirds copy() { + return new VeilOfBirds(this); + } +} + +class VeilOfBirdsToken extends TokenImpl { + + public VeilOfBirdsToken() { + super("Bird", "1/1 creature with flying"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.BIRD); + power = new MageInt(1); + toughness = new MageInt(1); + this.addAbility(FlyingAbility.getInstance()); + } + + public VeilOfBirdsToken(final VeilOfBirdsToken token) { + super(token); + } + + public VeilOfBirdsToken copy() { + return new VeilOfBirdsToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeiledApparition.java b/Mage.Sets/src/mage/cards/v/VeiledApparition.java new file mode 100644 index 0000000000..2bf24f1339 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeiledApparition.java @@ -0,0 +1,74 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.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.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class VeiledApparition extends CardImpl { + + private static final FilterSpell filter = new FilterSpell(); + + public VeiledApparition(UUID ownerId, CardSetInfo setInfo) { + 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(), "", Duration.WhileOnBattlefield, true, false), + filter, false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever 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}.")); + + } + + public VeiledApparition(final VeiledApparition card) { + super(card); + } + + @Override + public VeiledApparition copy() { + return new VeiledApparition(this); + } +} + +class VeilApparitionToken extends TokenImpl { + + public VeilApparitionToken() { + 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}")), TargetController.YOU, false); + this.addAbility(ability); + } + + public VeilApparitionToken(final VeilApparitionToken token) { + super(token); + } + + public VeilApparitionToken copy() { + return new VeilApparitionToken(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java b/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java new file mode 100644 index 0000000000..3c9bb1d674 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeiledCrocodile.java @@ -0,0 +1,130 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.StateTriggeredAbility; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.token.TokenImpl; +import mage.players.Player; + +/** + * + * @author jeffwadsworth + */ +public final class VeiledCrocodile extends CardImpl { + + public VeiledCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // When a player has no cards in hand, if Veiled Crocodile is an enchantment, Veiled Crocodile becomes a 4/4 Crocodile creature. + this.addAbility(new VeiledCrocodileStateTriggeredAbility()); + } + + public VeiledCrocodile(final VeiledCrocodile card) { + super(card); + } + + @Override + public VeiledCrocodile copy() { + return new VeiledCrocodile(this); + } +} + +class VeiledCrocodileStateTriggeredAbility extends StateTriggeredAbility { + + public VeiledCrocodileStateTriggeredAbility() { + super(Zone.BATTLEFIELD, new BecomesCreatureSourceEffect(new VeilCrocodileToken(), "", Duration.Custom, true, false)); + } + + public VeiledCrocodileStateTriggeredAbility(final VeiledCrocodileStateTriggeredAbility ability) { + super(ability); + } + + @Override + public VeiledCrocodileStateTriggeredAbility copy() { + return new VeiledCrocodileStateTriggeredAbility(this); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + for (UUID playerId : game.getState().getPlayersInRange(controllerId, game)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.getHand().isEmpty()) { + return true; + } + } + return false; + } + + @Override + public boolean checkInterveningIfClause(Game game) { + if (getSourcePermanentIfItStillExists(game) != null) { + return getSourcePermanentIfItStillExists(game).isEnchantment(); + } + return false; + } + + @Override + public boolean canTrigger(Game game) { + //20100716 - 603.8 + Boolean triggered = (Boolean) game.getState().getValue(getSourceId().toString() + "triggered"); + if (triggered == null) { + triggered = Boolean.FALSE; + } + return !triggered; + } + + @Override + public void trigger(Game game, UUID controllerId) { + //20100716 - 603.8 + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.TRUE); + super.trigger(game, controllerId); + } + + @Override + public boolean resolve(Game game) { + //20100716 - 603.8 + boolean result = super.resolve(game); + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + return result; + } + + @Override + public void counter(Game game) { + game.getState().setValue(this.getSourceId().toString() + "triggered", Boolean.FALSE); + } + + @Override + public String getRule() { + return "When a player has no cards in hand, if {this} is an enchantment, " + super.getRule(); + } + +} + +class VeilCrocodileToken extends TokenImpl { + + public VeilCrocodileToken() { + super("Crocodile", "4/4 Crocodile creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.CROCODILE); + power = new MageInt(4); + toughness = new MageInt(4); + } + + public VeilCrocodileToken(final VeilCrocodileToken token) { + super(token); + } + + public VeilCrocodileToken copy() { + return new VeilCrocodileToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeiledSentry.java b/Mage.Sets/src/mage/cards/v/VeiledSentry.java new file mode 100644 index 0000000000..3c6ce6f61e --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeiledSentry.java @@ -0,0 +1,115 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.SpellCastOpponentTriggeredAbility; +import mage.abilities.condition.common.SourceMatchesFilterCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Layer; +import static mage.constants.Layer.PTChangingEffects_7; +import static mage.constants.Layer.TypeChangingEffects_4; +import mage.constants.Outcome; +import mage.constants.SetTargetPointer; +import mage.constants.SubLayer; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.Spell; + +/** + * + * @author jeffwadsworth + */ +public final class VeiledSentry extends CardImpl { + + public VeiledSentry(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{U}"); + + // When an opponent casts a spell, if Veiled Sentry is an enchantment, Veiled Sentry becomes an Illusion creature with power and toughness each equal to that spell's converted mana cost. + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(Zone.BATTLEFIELD, new VeiledSentryEffect(), new FilterSpell(), false, SetTargetPointer.SPELL); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever an opponent casts a spell, if Veiled Sentry is an enchantment, Veil Sentry becomes an Illusion creature with power and toughness equal to that spell's converted mana cost.")); + + } + + public VeiledSentry(final VeiledSentry card) { + super(card); + } + + @Override + public VeiledSentry copy() { + return new VeiledSentry(this); + } +} + +class VeiledSentryEffect extends ContinuousEffectImpl { + + public VeiledSentryEffect() { + super(Duration.Custom, Outcome.BecomeCreature); + staticText = "{this} becomes an Illusion creature with power and toughness equal to that spell's converted mana cost"; + } + + public VeiledSentryEffect(final VeiledSentryEffect effect) { + super(effect); + } + + @Override + public VeiledSentryEffect copy() { + return new VeiledSentryEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent veiledSentry = game.getPermanent(source.getSourceId()); + Spell spellCast = game.getSpell(targetPointer.getFirst(game, source)); + if (spellCast != null) { + game.getState().setValue(source + "cmcSpell", spellCast.getConvertedManaCost()); + } + if (veiledSentry == null) { + return false; + } + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + veiledSentry.getCardType().clear(); + if (!veiledSentry.isCreature()) { + veiledSentry.addCardType(CardType.CREATURE); + } + if (!veiledSentry.getSubtype(game).contains(SubType.ILLUSION)) { + veiledSentry.getSubtype(game).add(SubType.ILLUSION); + } + } + break; + + case PTChangingEffects_7: + if (game.getState().getValue(source + "cmcSpell") != null) { + int cmc = (int) game.getState().getValue(source + "cmcSpell"); + if (sublayer == SubLayer.SetPT_7b) { + veiledSentry.addPower(cmc); + veiledSentry.addToughness(cmc); + } + } + } + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.PTChangingEffects_7 + || layer == Layer.TypeChangingEffects_4; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeiledSerpent.java b/Mage.Sets/src/mage/cards/v/VeiledSerpent.java new file mode 100644 index 0000000000..216133ebfd --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VeiledSerpent.java @@ -0,0 +1,75 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.TriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +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.combat.CantAttackUnlessDefenderControllsPermanent; +import mage.abilities.effects.common.continuous.BecomesCreatureSourceEffect; +import mage.abilities.keyword.CyclingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterSpell; +import mage.filter.StaticFilters; +import mage.filter.common.FilterLandPermanent; +import mage.game.permanent.token.TokenImpl; + +/** + * + * @author jeffwadsworth + */ +public final class VeiledSerpent extends CardImpl { + + public VeiledSerpent(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // When an opponent casts a spell, if Veiled Serpent is an enchantment, Veiled Serpent becomes a 4/4 Serpent creature that can't attack unless defending player controls an Island. + TriggeredAbility ability = new SpellCastOpponentTriggeredAbility(new BecomesCreatureSourceEffect(new VeiledSerpentToken(), "", Duration.WhileOnBattlefield, true, false), + new FilterSpell(), false); + this.addAbility(new ConditionalInterveningIfTriggeredAbility(ability, new SourceMatchesFilterCondition(StaticFilters.FILTER_ENCHANTMENT_PERMANENT), + "Whenever an opponent casts a spell, if Veiled Serpent is an enchantment, Veiled Serpent becomes a 4/4 Serpent creature that can't attack unless defending player controls an Island.")); + + // Cycling {2} + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + + } + + public VeiledSerpent(final VeiledSerpent card) { + super(card); + } + + @Override + public VeiledSerpent copy() { + return new VeiledSerpent(this); + } +} + +class VeiledSerpentToken extends TokenImpl { + + public VeiledSerpentToken() { + super("Serpent", "4/4 Serpent creature"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SERPENT); + power = new MageInt(4); + toughness = new MageInt(4); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, + new CantAttackUnlessDefenderControllsPermanent( + new FilterLandPermanent(SubType.ISLAND, "an Island")))); + } + + public VeiledSerpentToken(final VeiledSerpentToken token) { + super(token); + } + + public VeiledSerpentToken copy() { + return new VeiledSerpentToken(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VelaTheNightClad.java b/Mage.Sets/src/mage/cards/v/VelaTheNightClad.java index 299bbcb1a5..8e9015bf3f 100644 --- a/Mage.Sets/src/mage/cards/v/VelaTheNightClad.java +++ b/Mage.Sets/src/mage/cards/v/VelaTheNightClad.java @@ -22,7 +22,7 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class VelaTheNightClad extends CardImpl { - private final static String rule = "Whenever {this} or another creature you control leaves the battlefield, "; + private static final String rule = "Whenever {this} or another creature you control leaves the battlefield, "; private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); static { diff --git a/Mage.Sets/src/mage/cards/v/VenarianGold.java b/Mage.Sets/src/mage/cards/v/VenarianGold.java new file mode 100644 index 0000000000..3de871a055 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenarianGold.java @@ -0,0 +1,94 @@ + +package mage.cards.v; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.AttachedToCounterCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepEnchantedEffect; +import mage.abilities.effects.common.TapEnchantedEffect; +import mage.abilities.effects.common.counter.AddCountersAttachedEffect; +import mage.abilities.effects.common.counter.RemoveCountersAttachedEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +/** + * @author L_J + */ +public final class VenarianGold extends CardImpl { + + public VenarianGold(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{X}{U}{U}"); + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.Detriment)); + this.addAbility(new EnchantAbility(auraTarget.getTargetName())); + + // When Venarian Gold enters the battlefield, tap enchanted creature and put a number of sleep counters on it equal to the value of X as you cast Venarian Gold. + Ability ability = new EntersBattlefieldTriggeredAbility(new TapEnchantedEffect()); + ability.addEffect(new AddCountersAttachedEffect(CounterType.SLEEP.createInstance(), new VenarianGoldValue(), "it equal to the value of X as you cast {this}")); + this.addAbility(ability); + + // Enchanted creature doesn’t untap during its controller’s untap step if it has a sleep counter on it. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousRuleModifyingEffect(new DontUntapInControllersUntapStepEnchantedEffect(), + new AttachedToCounterCondition(CounterType.SLEEP, 1)).setText("Enchanted creature doesn't untap during its controller's untap step if it has a sleep counter on it"))); + + // At the beginning of the upkeep of enchanted creature’s controller, remove a sleep counter from that creature. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new RemoveCountersAttachedEffect(CounterType.SLEEP.createInstance(), "that creature"), + TargetController.CONTROLLER_ATTACHED_TO, false)); + + } + + public VenarianGold(final VenarianGold card) { + super(card); + } + + @Override + public VenarianGold copy() { + return new VenarianGold(this); + } +} + +class VenarianGoldValue implements DynamicValue { + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + MageObject mageObject = game.getLastKnownInformation(sourceAbility.getSourceId(), Zone.STACK); + if (mageObject instanceof StackObject) { + return ((StackObject) mageObject).getStackAbility().getManaCostsToPay().getX(); + } + return 0; + } + + @Override + public VenarianGoldValue copy() { + return new VenarianGoldValue(); + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return ""; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java b/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java index 34a41b9ab4..b1696346d9 100644 --- a/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java +++ b/Mage.Sets/src/mage/cards/v/VeneratedLoxodon.java @@ -74,7 +74,7 @@ class VeneratedLoxodonEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - VeneratedLoxodonWatcher watcher = (VeneratedLoxodonWatcher) game.getState().getWatchers().get(VeneratedLoxodonWatcher.class.getSimpleName()); + VeneratedLoxodonWatcher watcher = game.getState().getWatcher(VeneratedLoxodonWatcher.class); if (watcher != null) { MageObjectReference mor = new MageObjectReference(source.getSourceId(), source.getSourceObjectZoneChangeCounter() - 1, game); // -1 because of spell on the stack Set creatures = watcher.getConvokingCreatures(mor); @@ -97,7 +97,7 @@ class VeneratedLoxodonWatcher extends Watcher { private final Map> convokingCreatures = new HashMap<>(); public VeneratedLoxodonWatcher() { - super(VeneratedLoxodonWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public VeneratedLoxodonWatcher(final VeneratedLoxodonWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/v/Vengeance.java b/Mage.Sets/src/mage/cards/v/Vengeance.java index 10a628cdff..297badfe89 100644 --- a/Mage.Sets/src/mage/cards/v/Vengeance.java +++ b/Mage.Sets/src/mage/cards/v/Vengeance.java @@ -18,7 +18,7 @@ public final class Vengeance extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("tapped creature"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } public Vengeance(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VengefulArchon.java b/Mage.Sets/src/mage/cards/v/VengefulArchon.java index 6921e84308..c271f2e00d 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulArchon.java +++ b/Mage.Sets/src/mage/cards/v/VengefulArchon.java @@ -56,7 +56,7 @@ public final class VengefulArchon extends CardImpl { class VengefulArchonEffect extends PreventDamageToControllerEffect { public VengefulArchonEffect() { - super(Duration.EndOfTurn, false, true, new ManacostVariableValue()); + super(Duration.EndOfTurn, false, true, ManacostVariableValue.instance); staticText = "Prevent the next X damage that would be dealt to you this turn. If damage is prevented this way, {this} deals that much damage to target player or planeswalker"; } diff --git a/Mage.Sets/src/mage/cards/v/VengefulDreams.java b/Mage.Sets/src/mage/cards/v/VengefulDreams.java index 93f6a61452..073079d0a4 100644 --- a/Mage.Sets/src/mage/cards/v/VengefulDreams.java +++ b/Mage.Sets/src/mage/cards/v/VengefulDreams.java @@ -1,10 +1,8 @@ - package mage.cards.v; import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.common.DiscardXTargetCost; -import mage.abilities.dynamicvalue.common.GetXValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.CardImpl; @@ -14,39 +12,43 @@ import mage.filter.FilterCard; import mage.filter.common.FilterAttackingCreature; import mage.game.Game; import mage.target.Target; -import mage.target.common.TargetCreaturePermanent; +import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** - * * @author fireshoes */ public final class VengefulDreams extends CardImpl { public VengefulDreams(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{W}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{W}{W}"); // As an additional cost to cast Vengeful Dreams, discard X cards. this.getSpellAbility().addCost(new DiscardXTargetCost(new FilterCard("cards"), true)); - + // Exile X target attacking creatures. Effect effect = new ExileTargetEffect(); effect.setText("Exile X target attacking creatures"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(VengefulDreamsAdjuster.instance); } public VengefulDreams(final VengefulDreams card) { super(card); } - - @Override - public void adjustTargets(Ability ability, Game game) { - int xValue = new GetXValue().calculate(game, ability, null); - Target target = new TargetCreaturePermanent(0, xValue, new FilterAttackingCreature(), false); - ability.addTarget(target); - } @Override public VengefulDreams copy() { return new VengefulDreams(this); } } + +enum VengefulDreamsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + Target target = new TargetPermanent(ability.getCosts().getVariableCosts().get(0).getAmount(), new FilterAttackingCreature()); + ability.addTarget(target); + } +} diff --git a/Mage.Sets/src/mage/cards/v/Vengevine.java b/Mage.Sets/src/mage/cards/v/Vengevine.java index 4c179aaedd..925fe3fc64 100644 --- a/Mage.Sets/src/mage/cards/v/Vengevine.java +++ b/Mage.Sets/src/mage/cards/v/Vengevine.java @@ -70,7 +70,7 @@ class VengevineAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(controllerId)) { - Watcher watcher = game.getState().getWatchers().get(VengevineWatcher.class.getSimpleName(), controllerId); + Watcher watcher = game.getState().getWatcher(VengevineWatcher.class, controllerId); if (watcher != null && watcher.conditionMet()) { return true; } @@ -88,10 +88,10 @@ class VengevineAbility extends TriggeredAbilityImpl { class VengevineWatcher extends Watcher { - int creatureSpellCount = 0; + private int creatureSpellCount = 0; public VengevineWatcher() { - super(VengevineWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); } public VengevineWatcher(final VengevineWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/v/VenomousBreath.java b/Mage.Sets/src/mage/cards/v/VenomousBreath.java index 5741e3df3a..4561377e44 100644 --- a/Mage.Sets/src/mage/cards/v/VenomousBreath.java +++ b/Mage.Sets/src/mage/cards/v/VenomousBreath.java @@ -97,7 +97,7 @@ class VenomousBreathEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null && targetCreature != null) { - BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { List toDestroy = new ArrayList<>(); for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { diff --git a/Mage.Sets/src/mage/cards/v/VenomousFangs.java b/Mage.Sets/src/mage/cards/v/VenomousFangs.java new file mode 100644 index 0000000000..1be68f955f --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VenomousFangs.java @@ -0,0 +1,48 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.constants.SubType; +import mage.target.common.TargetCreaturePermanent; +import mage.abilities.Ability; +import mage.abilities.common.DealsDamageToACreatureAttachedTriggeredAbility; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.constants.Outcome; +import mage.target.TargetPermanent; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; + +/** + * + * @author jeffwadsworth + */ +public final class VenomousFangs extends CardImpl { + + public VenomousFangs(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}"); + + this.subtype.add(SubType.AURA); + + // Enchant creature + TargetPermanent auraTarget = new TargetCreaturePermanent(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // Whenever enchanted creature deals damage to a creature, destroy the other creature. + this.addAbility(new DealsDamageToACreatureAttachedTriggeredAbility(new DestroyTargetEffect(), false, "enchanted creature", false, true)); + + } + + public VenomousFangs(final VenomousFangs card) { + super(card); + } + + @Override + public VenomousFangs copy() { + return new VenomousFangs(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VenomousVines.java b/Mage.Sets/src/mage/cards/v/VenomousVines.java index 1b12f3b785..9016551b5e 100644 --- a/Mage.Sets/src/mage/cards/v/VenomousVines.java +++ b/Mage.Sets/src/mage/cards/v/VenomousVines.java @@ -19,7 +19,7 @@ public final class VenomousVines extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("enchanted permanent"); static { - filter.add(new EnchantedPredicate()); + filter.add(EnchantedPredicate.instance); } public VenomousVines(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VensersJournal.java b/Mage.Sets/src/mage/cards/v/VensersJournal.java index f3b19c26e9..6bfa3dc7b0 100644 --- a/Mage.Sets/src/mage/cards/v/VensersJournal.java +++ b/Mage.Sets/src/mage/cards/v/VensersJournal.java @@ -30,7 +30,7 @@ public final class VensersJournal extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, effect)); // At the beginning of your upkeep, you gain 1 life for each card in your hand. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(new CardsInControllerHandCount()), TargetController.YOU, false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new GainLifeEffect(CardsInControllerHandCount.instance), TargetController.YOU, false)); } public VensersJournal(final VensersJournal card) { diff --git a/Mage.Sets/src/mage/cards/v/VentifactBottle.java b/Mage.Sets/src/mage/cards/v/VentifactBottle.java index 92e69ef651..4b0c2db6e5 100644 --- a/Mage.Sets/src/mage/cards/v/VentifactBottle.java +++ b/Mage.Sets/src/mage/cards/v/VentifactBottle.java @@ -36,7 +36,7 @@ public final class VentifactBottle extends CardImpl { // {X}{1}, {tap}: Put X charge counters on Ventifact Bottle. Activate this ability only any time you could cast a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), new ManacostVariableValue(), true), + new AddCountersSourceEffect(CounterType.CHARGE.createInstance(), ManacostVariableValue.instance, true), new ManaCostsImpl("{1}{X}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/v/VerdantConfluence.java b/Mage.Sets/src/mage/cards/v/VerdantConfluence.java index 3697552a79..d37e8797d3 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantConfluence.java +++ b/Mage.Sets/src/mage/cards/v/VerdantConfluence.java @@ -37,14 +37,14 @@ public final class VerdantConfluence extends CardImpl { // Return target permanent card from your graveyard to your hand; Mode mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(new FilterPermanentCard())); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(new FilterPermanentCard())); this.getSpellAbility().getModes().addMode(mode); // Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library. TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND); mode = new Mode(); - mode.getEffects().add(new SearchLibraryPutInPlayEffect(target, true)); + mode.addEffect(new SearchLibraryPutInPlayEffect(target, true)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VerdantCrescendo.java b/Mage.Sets/src/mage/cards/v/VerdantCrescendo.java index 868a1eebd2..6f4ae19b5d 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantCrescendo.java +++ b/Mage.Sets/src/mage/cards/v/VerdantCrescendo.java @@ -19,7 +19,7 @@ import java.util.UUID; */ public final class VerdantCrescendo extends CardImpl { - private final static FilterCard filter = new FilterCard("Nissa, Nature's Artisan"); + private static final FilterCard filter = new FilterCard("Nissa, Nature's Artisan"); static { filter.add(new NamePredicate("Nissa, Nature's Artisan")); diff --git a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java index 94ca35d03a..cd0e14e0e4 100644 --- a/Mage.Sets/src/mage/cards/v/VerdantSuccession.java +++ b/Mage.Sets/src/mage/cards/v/VerdantSuccession.java @@ -56,7 +56,7 @@ class VerdantSuccessionTriggeredAbility extends TriggeredAbilityImpl { static { filter.add(new ColorPredicate(ObjectColor.GREEN)); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } public VerdantSuccessionTriggeredAbility() { @@ -84,7 +84,7 @@ class VerdantSuccessionTriggeredAbility extends TriggeredAbilityImpl { && ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); MageObject mageObject = game.getObject(sourceId); - if (permanent != null + if (permanent != null && mageObject != null && filter.match(permanent, game)) { game.getState().setValue("verdantSuccession" + mageObject, permanent); return true; @@ -119,21 +119,23 @@ class VerdantSuccessionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { MageObject mageObject = game.getObject(source.getSourceId()); - permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject); - if (permanent != null) { - Player controller = game.getPlayer(permanent.getControllerId()); - if (controller != null) { - FilterCard filterCard = new FilterCard("Card named " + permanent.getName()); - filterCard.add(new NamePredicate(permanent.getName())); - TargetCardInLibrary target = new TargetCardInLibrary(filterCard); - controller.searchLibrary(target, game); - if (!target.getTargets().isEmpty()) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { - controller.shuffleLibrary(source, game); + if(mageObject != null) { + permanent = (Permanent) game.getState().getValue("verdantSuccession" + mageObject); + if (permanent != null) { + Player controller = game.getPlayer(permanent.getControllerId()); + if (controller != null) { + FilterCard filterCard = new FilterCard("Card named " + permanent.getName()); + filterCard.add(new NamePredicate(permanent.getName())); + TargetCardInLibrary target = new TargetCardInLibrary(filterCard); + controller.searchLibrary(target, source, game); + if (!target.getTargets().isEmpty()) { + Card card = game.getCard(target.getFirstTarget()); + if (card != null + && controller.moveCards(card, Zone.BATTLEFIELD, source, game)) { + controller.shuffleLibrary(source, game); + } + return true; } - return true; } } } diff --git a/Mage.Sets/src/mage/cards/v/VerityCircle.java b/Mage.Sets/src/mage/cards/v/VerityCircle.java new file mode 100644 index 0000000000..73f08b397f --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VerityCircle.java @@ -0,0 +1,94 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.TapTargetEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VerityCircle extends CardImpl { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature without flying"); + + static { + filter.add(Predicates.not(new AbilityPredicate(FlyingAbility.class))); + } + + public VerityCircle(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}"); + + // Whenever a creature an opponent controls becomes tapped, if it isn't being declared as an attacker, you may draw a card. + this.addAbility(new VerityCircleTriggeredAbility()); + + // {4}{U}: Tap target creature without flying. + Ability ability = new SimpleActivatedAbility(new TapTargetEffect(), new ManaCostsImpl("{4}{U}")); + ability.addTarget(new TargetCreaturePermanent(filter)); + this.addAbility(ability); + } + + private VerityCircle(final VerityCircle card) { + super(card); + } + + @Override + public VerityCircle copy() { + return new VerityCircle(this); + } +} + +class VerityCircleTriggeredAbility extends TriggeredAbilityImpl { + + VerityCircleTriggeredAbility() { + super(Zone.BATTLEFIELD, new DrawCardSourceControllerEffect(1), true); + } + + private VerityCircleTriggeredAbility(final VerityCircleTriggeredAbility ability) { + super(ability); + } + + @Override + public VerityCircleTriggeredAbility copy() { + return new VerityCircleTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.TAPPED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getFlag()) { + return false; + } + Permanent permanent = game.getPermanent(event.getTargetId()); + Player player = game.getPlayer(controllerId); + return permanent != null && player != null && permanent.isCreature() + && player.hasOpponent(permanent.getControllerId(), game); + } + + @Override + public String getRule() { + return "Whenever a creature an opponent controls becomes tapped, " + + "if it isn't being declared as an attacker, you may draw a card."; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java index 10de4b9f8e..412e468a95 100644 --- a/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java +++ b/Mage.Sets/src/mage/cards/v/VeryCrypticCommandD.java @@ -40,7 +40,7 @@ public final class VeryCrypticCommandD extends CardImpl { static { filter.add(new NumberOfTargetsPredicate(1)); - filter2.add(Predicates.not(new TokenPredicate())); + filter2.add(Predicates.not(TokenPredicate.instance)); } public VeryCrypticCommandD(UUID ownerId, CardSetInfo setInfo) { @@ -56,22 +56,22 @@ public final class VeryCrypticCommandD extends CardImpl { // Draw two cards, then discard a card. Mode mode = new Mode(); - mode.getEffects().add(new DrawCardSourceControllerEffect(2)); + mode.addEffect(new DrawCardSourceControllerEffect(2)); Effect effect = new DiscardControllerEffect(1); effect.setText(", then discard a card"); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().getModes().addMode(mode); // Change the target of target spell with a single target. mode = new Mode(); - mode.getEffects().add(new ChooseNewTargetsTargetEffect(true, true)); - mode.getTargets().add(new TargetStackObject(filter)); + mode.addEffect(new ChooseNewTargetsTargetEffect(true, true)); + mode.addTarget(new TargetStackObject(filter)); this.getSpellAbility().getModes().addMode(mode); // Turn over target nontoken creature. mode = new Mode(); - mode.getEffects().add(new TurnOverEffect()); - mode.getTargets().add(new TargetCreaturePermanent(filter2)); + mode.addEffect(new TurnOverEffect()); + mode.addTarget(new TargetCreaturePermanent(filter2)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VesselOfNascency.java b/Mage.Sets/src/mage/cards/v/VesselOfNascency.java index 68591eb695..8113992126 100644 --- a/Mage.Sets/src/mage/cards/v/VesselOfNascency.java +++ b/Mage.Sets/src/mage/cards/v/VesselOfNascency.java @@ -81,8 +81,7 @@ class VesselOfNascencyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 4)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 4)); boolean properCardFound = cards.count(filterPutInHand, source.getControllerId(), source.getSourceId(), game) > 0; if (!cards.isEmpty()) { controller.revealCards(sourceObject.getName(), cards, game); diff --git a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java index 404b0334c3..e7723d4f9f 100644 --- a/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java +++ b/Mage.Sets/src/mage/cards/v/VesuvanShapeshifter.java @@ -1,7 +1,6 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -17,12 +16,7 @@ import mage.abilities.effects.common.CopyPermanentEffect; import mage.abilities.keyword.MorphAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.AnotherPredicate; @@ -32,14 +26,13 @@ import mage.players.Player; import mage.target.common.TargetCreaturePermanent; import mage.util.functions.ApplyToPermanent; +import java.util.UUID; + /** * @author spjspj */ public final class VesuvanShapeshifter extends CardImpl { - protected Ability turnFaceUpAbility = null; - private static final String effectText = "as a copy of any creature on the battlefield until {this} is turned faced down"; - public VesuvanShapeshifter(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}{U}"); this.subtype.add(SubType.SHAPESHIFTER); @@ -53,7 +46,7 @@ public final class VesuvanShapeshifter extends CardImpl { // As Vesuvan Shapeshifter etbs, you may choose another creature. If you do, until Vesuvan Shapeshifter is turned face down, it becomes a copy of that creature Effect effect = new CopyPermanentEffect(StaticFilters.FILTER_PERMANENT_CREATURE, new VesuvanShapeShifterFaceUpApplier()); - effect.setText(effectText); + effect.setText("as a copy of any creature on the battlefield until {this} is turned faced down"); ability = new EntersBattlefieldAbility(effect, true); ability.setWorksFaceDown(false); this.addAbility(ability); @@ -121,11 +114,11 @@ class VesuvanShapeshifterEffect extends OneShotEffect { Permanent copyToCreature = game.getPermanent(source.getSourceId()); if (copyToCreature != null) { FilterCreaturePermanent filter = new FilterCreaturePermanent("another creature"); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); TargetCreaturePermanent target = new TargetCreaturePermanent(0, 1, filter, false); - if (controller.chooseTarget(Outcome.BecomeCreature, target, source, game) && !target.getTargets().isEmpty()) { + if (controller != null && controller.chooseTarget(Outcome.BecomeCreature, target, source, game) && !target.getTargets().isEmpty()) { Permanent copyFromCreature = game.getPermanentOrLKIBattlefield(target.getFirstTarget()); if (copyFromCreature != null) { game.copyPermanent(Duration.Custom, copyFromCreature, copyToCreature.getId(), source, new VesuvanShapeShifterFaceUpApplier()); diff --git a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java index 7f90224c3f..d1442674c9 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java +++ b/Mage.Sets/src/mage/cards/v/VeteranBodyguard.java @@ -56,7 +56,7 @@ class VeteranBodyguardEffect extends ReplacementEffectImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("unblocked creatures"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } VeteranBodyguardEffect() { diff --git a/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java b/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java index 5d58d133fd..a8c49a2a8a 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java +++ b/Mage.Sets/src/mage/cards/v/VeteranBrawlers.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,8 +8,8 @@ import mage.abilities.effects.common.combat.CantAttackIfDefenderControlsPermanen import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; @@ -21,17 +19,20 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** * @author L_J */ public final class VeteranBrawlers extends CardImpl { static final private FilterLandPermanent filter = new FilterLandPermanent("an untapped land"); + static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } - - final static private String rule = "{this} can't block if you control an untapped land"; + + static final private String rule = "{this} can't block if you control an untapped land"; public VeteranBrawlers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}"); @@ -64,7 +65,7 @@ class VeteranBrawlersCantBlockEffect extends RestrictionEffect { public VeteranBrawlersCantBlockEffect(FilterPermanent filter) { super(Duration.WhileOnBattlefield); this.filter = filter; - staticText = new StringBuilder("{this} can't attack if you control ").append(filter.getMessage()).toString(); + staticText = "{this} can't attack if you control " + filter.getMessage(); } public VeteranBrawlersCantBlockEffect(final VeteranBrawlersCantBlockEffect effect) { @@ -78,12 +79,10 @@ class VeteranBrawlersCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { Player player = game.getPlayer(blocker.getControllerId()); if (player != null) { - if (game.getBattlefield().countAll(filter, player.getId(), game) > 0) { - return false; - } + return game.getBattlefield().countAll(filter, player.getId(), game) <= 0; } return true; } diff --git a/Mage.Sets/src/mage/cards/v/VeteranExplorer.java b/Mage.Sets/src/mage/cards/v/VeteranExplorer.java index 81b84fa827..0e34e7fb8c 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranExplorer.java +++ b/Mage.Sets/src/mage/cards/v/VeteranExplorer.java @@ -91,7 +91,7 @@ class VeteranExplorerEffect extends OneShotEffect { if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up to two basic land cards and put them onto the battlefield?", source, game)) { usingPlayers.add(player); TargetCardInLibrary target = new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LAND); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { player.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java index c2ec926461..84944b2fa0 100644 --- a/Mage.Sets/src/mage/cards/v/VeteranWarleader.java +++ b/Mage.Sets/src/mage/cards/v/VeteranWarleader.java @@ -1,20 +1,17 @@ - package mage.cards.v; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapTargetCost; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.keyword.FirstStrikeAbility; import mage.abilities.keyword.TrampleAbility; import mage.abilities.keyword.VigilanceAbility; @@ -23,7 +20,6 @@ import mage.cards.CardSetInfo; import mage.choices.Choice; import mage.choices.ChoiceImpl; import mage.constants.*; -import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.SubtypePredicate; @@ -33,8 +29,11 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author fireshoes */ public final class VeteranWarleader extends CardImpl { @@ -42,9 +41,9 @@ public final class VeteranWarleader extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("another untapped Ally you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public VeteranWarleader(UUID ownerId, CardSetInfo setInfo) { @@ -57,7 +56,8 @@ public final class VeteranWarleader extends CardImpl { // Veteran Warleader's power and toughness are each equal to the number of creatures you control. this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect( - new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); // Tap another untapped Ally you control: Veteran Warleader gains your choice of first strike, vigilance, or trample until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, diff --git a/Mage.Sets/src/mage/cards/v/VeteransVoice.java b/Mage.Sets/src/mage/cards/v/VeteransVoice.java index d49a943f00..ef9a5d895b 100644 --- a/Mage.Sets/src/mage/cards/v/VeteransVoice.java +++ b/Mage.Sets/src/mage/cards/v/VeteransVoice.java @@ -35,7 +35,7 @@ public final class VeteransVoice extends CardImpl { private static final FilterCreaturePermanent filterUntapped = new FilterCreaturePermanent("enchanted creature is untapped"); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } public VeteransVoice(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VexingArcanix.java b/Mage.Sets/src/mage/cards/v/VexingArcanix.java index 3ca378b7ed..61ec771008 100644 --- a/Mage.Sets/src/mage/cards/v/VexingArcanix.java +++ b/Mage.Sets/src/mage/cards/v/VexingArcanix.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; @@ -18,9 +16,11 @@ import mage.constants.Zone; import mage.game.Game; import mage.players.Player; import mage.target.TargetPlayer; +import mage.util.CardUtil; + +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com & L_J */ public final class VexingArcanix extends CardImpl { @@ -74,7 +74,7 @@ class VexingArcanixEffect extends OneShotEffect { if (card != null) { Cards cards = new CardsImpl(card); player.revealCards(sourceObject.getIdName(), cards, game); - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { player.moveCards(cards, Zone.HAND, source, game); } else { player.moveCards(cards, Zone.GRAVEYARD, source, game); diff --git a/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java b/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java index 2f6d1d3d3f..14928db6af 100644 --- a/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java +++ b/Mage.Sets/src/mage/cards/v/VialSmasherTheFierce.java @@ -78,7 +78,7 @@ class VialSmasherTheFierceTriggeredAbility extends SpellCastControllerTriggeredA @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(event.getPlayerId()); if (spells != null && spells.size() == 1) { diff --git a/Mage.Sets/src/mage/cards/v/ViashinoBey.java b/Mage.Sets/src/mage/cards/v/ViashinoBey.java new file mode 100644 index 0000000000..d3471e16e4 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ViashinoBey.java @@ -0,0 +1,94 @@ +package mage.cards.v; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.AttacksTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * + * @author jeffwadsworth + */ +public final class ViashinoBey extends CardImpl { + + private static final String rule = "If {this} attacks, all creatures you control attack if able."; + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public ViashinoBey(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{R}"); + + this.subtype.add(SubType.VIASHINO); + this.power = new MageInt(4); + this.toughness = new MageInt(3); + + // If Viashino Bey attacks, all creatures you control attack if able. + this.addAbility(new AttacksTriggeredAbility(new ViashinoBeyEffect(), false, rule)); + + } + + public ViashinoBey(final ViashinoBey card) { + super(card); + } + + @Override + public ViashinoBey copy() { + return new ViashinoBey(this); + } +} + +class ViashinoBeyEffect extends OneShotEffect { + + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + + static { + filter.add(new ControllerPredicate(TargetController.YOU)); + } + + public ViashinoBeyEffect() { + super(Outcome.Benefit); + } + + public ViashinoBeyEffect(final ViashinoBeyEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + TargetOpponent targetDefender = new TargetOpponent(); + if (controller != null) { + game.getBattlefield().getAllActivePermanents(CardType.CREATURE).stream().filter((permanent) -> (filter.match(permanent, source.getSourceId(), source.getControllerId(), game))).forEachOrdered((permanent) -> { + if (game.getOpponents(controller.getId()).size() > 1) { + controller.choose(outcome.Benefit, targetDefender, source.getSourceId(), game); + } else { + targetDefender.add(game.getOpponents(controller.getId()).iterator().next(), game); + } + if (permanent.canAttack(targetDefender.getFirstTarget(), game)) { + controller.declareAttacker(permanent.getId(), targetDefender.getFirstTarget(), game, false); + } + }); + } + return false; + } + + @Override + public ViashinoBeyEffect copy() { + return new ViashinoBeyEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/ViashinoSandswimmer.java b/Mage.Sets/src/mage/cards/v/ViashinoSandswimmer.java index 6668c1ff62..bed9581368 100644 --- a/Mage.Sets/src/mage/cards/v/ViashinoSandswimmer.java +++ b/Mage.Sets/src/mage/cards/v/ViashinoSandswimmer.java @@ -61,7 +61,7 @@ class ViashinoSandswimmerEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { new ReturnToHandSourceEffect().apply(game, source); return true; } else { diff --git a/Mage.Sets/src/mage/cards/v/ViciousBetrayal.java b/Mage.Sets/src/mage/cards/v/ViciousBetrayal.java index 3d5faf818a..526707fa82 100644 --- a/Mage.Sets/src/mage/cards/v/ViciousBetrayal.java +++ b/Mage.Sets/src/mage/cards/v/ViciousBetrayal.java @@ -1,7 +1,6 @@ package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.VariableCost; import mage.abilities.costs.common.SacrificeXTargetCost; @@ -16,21 +15,22 @@ import mage.filter.common.FilterControlledCreaturePermanent; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author Plopman */ public final class ViciousBetrayal extends CardImpl { public ViciousBetrayal(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}{B}"); // As an additional cost to cast Vicious Betrayal, sacrifice any number of creatures. this.getSpellAbility().addCost(new SacrificeXTargetCost(new FilterControlledCreaturePermanent())); // Target creature gets +2/+2 until end of turn for each creature sacrificed this way. this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - this.getSpellAbility().addEffect(new BoostTargetEffect(new GetXValue(), new GetXValue(), Duration.EndOfTurn)); + this.getSpellAbility().addEffect(new BoostTargetEffect(GetXValue.instance, GetXValue.instance, Duration.EndOfTurn)); } public ViciousBetrayal(final ViciousBetrayal card) { @@ -43,19 +43,21 @@ public final class ViciousBetrayal extends CardImpl { } } -class GetXValue implements DynamicValue { +enum GetXValue implements DynamicValue { + instance; + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { int amount = 0; - for (VariableCost cost: sourceAbility.getCosts().getVariableCosts()) { + for (VariableCost cost : sourceAbility.getCosts().getVariableCosts()) { amount += cost.getAmount(); } - return 2*amount; + return 2 * amount; } @Override public GetXValue copy() { - return new GetXValue(); + return GetXValue.instance; } @Override diff --git a/Mage.Sets/src/mage/cards/v/ViciousShadows.java b/Mage.Sets/src/mage/cards/v/ViciousShadows.java index 273cd5bf24..c65f819cf8 100644 --- a/Mage.Sets/src/mage/cards/v/ViciousShadows.java +++ b/Mage.Sets/src/mage/cards/v/ViciousShadows.java @@ -22,7 +22,7 @@ public final class ViciousShadows extends CardImpl { // Whenever a creature dies, you may have Vicious Shadows deal damage to target player equal to the number of cards in that player's hand. - Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(new CardsInTargetHandCount()), true); + Ability ability = new DiesCreatureTriggeredAbility(new DamageTargetEffect(CardsInTargetHandCount.instance), true); ability.addTarget(new TargetPlayer()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VigeanHydropon.java b/Mage.Sets/src/mage/cards/v/VigeanHydropon.java index 5c86441c89..344c0abcf2 100644 --- a/Mage.Sets/src/mage/cards/v/VigeanHydropon.java +++ b/Mage.Sets/src/mage/cards/v/VigeanHydropon.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -10,20 +8,21 @@ import mage.abilities.keyword.GraftAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author JotaPeRL */ public final class VigeanHydropon extends CardImpl { public VigeanHydropon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{U}"); this.subtype.add(SubType.PLANT); this.subtype.add(SubType.MUTANT); this.power = new MageInt(0); @@ -31,7 +30,7 @@ public final class VigeanHydropon extends CardImpl { // Graft 5 this.addAbility(new GraftAbility(this, 5)); - + // Vigean Hydropon can't attack or block. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VigeanHydroponEffect())); } @@ -63,20 +62,17 @@ class VigeanHydroponEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { - if (permanent.getId().equals(source.getSourceId())) { - return true; - } - return false; + return permanent.getId().equals(source.getSourceId()); } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/VigilForTheLost.java b/Mage.Sets/src/mage/cards/v/VigilForTheLost.java index b5de68f55e..41b030ed94 100644 --- a/Mage.Sets/src/mage/cards/v/VigilForTheLost.java +++ b/Mage.Sets/src/mage/cards/v/VigilForTheLost.java @@ -3,6 +3,7 @@ package mage.cards.v; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.costs.mana.ManaCostsImpl; @@ -20,18 +21,17 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author Loki */ public final class VigilForTheLost extends CardImpl { - public VigilForTheLost (UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{W}"); + public VigilForTheLost(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{W}"); this.addAbility(new VigilForTheLostTriggeredAbility()); } - public VigilForTheLost (final VigilForTheLost card) { + public VigilForTheLost(final VigilForTheLost card) { super(card); } @@ -63,8 +63,8 @@ class VigilForTheLostTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent)event).getToZone() == Zone.GRAVEYARD && - ((ZoneChangeEvent)event).getFromZone() == Zone.BATTLEFIELD) { + if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD && + ((ZoneChangeEvent) event).getFromZone() == Zone.BATTLEFIELD) { Permanent p = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (p.isControlledBy(this.getControllerId()) && p.isCreature()) { return true; @@ -95,11 +95,13 @@ class VigilForTheLostEffect extends OneShotEffect { cost.clearPaid(); if (cost.payOrRollback(source, game, source.getSourceId(), source.getControllerId())) { Player player = game.getPlayer(source.getControllerId()); - player.gainLife(cost.getX(), game, source); - return true; - } else { - return false; + if (player != null) { + player.gainLife(cost.getX(), game, source); + return true; + } } + return false; + } @Override diff --git a/Mage.Sets/src/mage/cards/v/VigilantMartyr.java b/Mage.Sets/src/mage/cards/v/VigilantMartyr.java index e2c4475a47..91c80f9f9a 100644 --- a/Mage.Sets/src/mage/cards/v/VigilantMartyr.java +++ b/Mage.Sets/src/mage/cards/v/VigilantMartyr.java @@ -28,7 +28,7 @@ import java.util.UUID; */ public final class VigilantMartyr extends CardImpl { - private final static FilterSpell filter = new FilterSpell("spell that targets an enchantment"); + private static final FilterSpell filter = new FilterSpell("spell that targets an enchantment"); static { filter.add(new TargetsPermanentPredicate(StaticFilters.FILTER_ENCHANTMENT_PERMANENT)); diff --git a/Mage.Sets/src/mage/cards/v/VigilanteJustice.java b/Mage.Sets/src/mage/cards/v/VigilanteJustice.java index e99e223b5f..791642147b 100644 --- a/Mage.Sets/src/mage/cards/v/VigilanteJustice.java +++ b/Mage.Sets/src/mage/cards/v/VigilanteJustice.java @@ -1,9 +1,8 @@ package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.CreatureEntersBattlefieldTriggeredAbility; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.effects.common.DamageTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,24 +13,30 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author Loki */ public final class VigilanteJustice extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Human"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a Human"); static { - filter.add(new SubtypePredicate(SubType.HUMAN)); + filter.add(new SubtypePredicate(SubType.HUMAN)); } public VigilanteJustice(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{R}"); // Whenever a Human enters the battlefield under your control, Vigilante Justice deals 1 damage to any target. - Ability ability = new CreatureEntersBattlefieldTriggeredAbility(Zone.BATTLEFIELD, new DamageTargetEffect(1), filter, false, false); + Ability ability = new EntersBattlefieldControlledTriggeredAbility( + Zone.BATTLEFIELD, + new DamageTargetEffect(1), + filter, + false + ); ability.addTarget(new TargetAnyTarget()); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VigorousCharge.java b/Mage.Sets/src/mage/cards/v/VigorousCharge.java new file mode 100644 index 0000000000..fccee6d9cb --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VigorousCharge.java @@ -0,0 +1,95 @@ + +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.condition.LockedInCondition; +import mage.abilities.condition.common.KickedCondition; +import mage.abilities.decorator.ConditionalContinuousEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.KickerAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.DamagedEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.target.common.TargetCreaturePermanent; + +/** + * + * @author LevelX2 & L_J + */ +public final class VigorousCharge extends CardImpl { + + private static final String staticText = "Whenever that creature deals combat damage this turn, if this spell was kicked, you gain life equal to that damage"; + + public VigorousCharge(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{G}"); + + // Kicker {W} (You may pay an additional {W} as you cast this spell.) + this.addAbility(new KickerAbility("{W}")); + // Target creature gains trample until end of turn. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn)); + // Whenever that creature deals combat damage this turn, if this spell was kicked, you gain life equal to that damage. + this.getSpellAbility().addEffect(new ConditionalContinuousEffect(new GainAbilityTargetEffect(new VigorousChargeTriggeredAbility(), Duration.EndOfTurn), + new LockedInCondition(KickedCondition.instance), staticText)); + + } + + public VigorousCharge(final VigorousCharge card) { + super(card); + } + + @Override + public VigorousCharge copy() { + return new VigorousCharge(this); + } +} + +class VigorousChargeTriggeredAbility extends TriggeredAbilityImpl { + + public VigorousChargeTriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + public VigorousChargeTriggeredAbility(final VigorousChargeTriggeredAbility ability) { + super(ability); + } + + @Override + public VigorousChargeTriggeredAbility copy() { + return new VigorousChargeTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.DAMAGED_CREATURE + || event.getType() == EventType.DAMAGED_PLAYER + || event.getType() == EventType.DAMAGED_PLANESWALKER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + DamagedEvent damageEvent = (DamagedEvent) event; + if (damageEvent.isCombatDamage()) { + if (event.getSourceId().equals(this.sourceId)) { + this.getEffects().clear(); + this.getEffects().add(new GainLifeEffect(damageEvent.getAmount())); + return true; + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} deals combat damage, you gain that much life."; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VileAggregate.java b/Mage.Sets/src/mage/cards/v/VileAggregate.java index bd4cbb2e7b..a8313c09f9 100644 --- a/Mage.Sets/src/mage/cards/v/VileAggregate.java +++ b/Mage.Sets/src/mage/cards/v/VileAggregate.java @@ -25,10 +25,10 @@ import mage.filter.predicate.mageobject.ColorlessPredicate; */ public final class VileAggregate extends CardImpl { - private final static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("colorless creatures you control"); + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("colorless creatures you control"); static { - filter.add(new ColorlessPredicate()); + filter.add(ColorlessPredicate.instance); } public VileAggregate(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VileManifestation.java b/Mage.Sets/src/mage/cards/v/VileManifestation.java index f0f82e9914..85e6119b50 100644 --- a/Mage.Sets/src/mage/cards/v/VileManifestation.java +++ b/Mage.Sets/src/mage/cards/v/VileManifestation.java @@ -1,4 +1,3 @@ - package mage.cards.v; import java.util.UUID; @@ -9,7 +8,9 @@ import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.Effect; import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.keyword.BasicLandcyclingAbility; import mage.abilities.keyword.CyclingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,33 +26,38 @@ import mage.filter.predicate.mageobject.AbilityPredicate; * @author spjspj */ public final class VileManifestation extends CardImpl { - + private static final FilterCard filter = new FilterCard(); - + static { - filter.add(new AbilityPredicate(CyclingAbility.class)); + filter.add(mage.filter.predicate.Predicates.or( + new AbilityPredicate(CyclingAbility.class), + new AbilityPredicate(BasicLandcyclingAbility.class))); } - + public VileManifestation(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}"); - + this.subtype.add(SubType.HORROR); this.power = new MageInt(0); this.toughness = new MageInt(4); // Vile Manifestation gets +1/+0 for each card with cycling in your graveyard. DynamicValue amount = new CardsInControllerGraveyardCount(new FilterCard(filter)); - Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostSourceEffect(amount, new StaticValue(0), Duration.WhileOnBattlefield)); + Effect effect = new BoostSourceEffect(amount, new StaticValue(0), Duration.WhileOnBattlefield); + effect.setText("Vile Manifestation gets +1/+0 for each card with cycling in your graveyard."); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, effect); this.addAbility(ability); // Cycling {2} - this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + this.addAbility(new CyclingAbility(new ManaCostsImpl("{2}"))); + } - + public VileManifestation(final VileManifestation card) { super(card); } - + @Override public VileManifestation copy() { return new VileManifestation(this); diff --git a/Mage.Sets/src/mage/cards/v/VileRedeemer.java b/Mage.Sets/src/mage/cards/v/VileRedeemer.java index 134fb3934d..c766a49f45 100644 --- a/Mage.Sets/src/mage/cards/v/VileRedeemer.java +++ b/Mage.Sets/src/mage/cards/v/VileRedeemer.java @@ -79,7 +79,7 @@ class VileRedeemerEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - VileRedeemerNonTokenCreaturesDiedWatcher watcher = (VileRedeemerNonTokenCreaturesDiedWatcher) game.getState().getWatchers().get(VileRedeemerNonTokenCreaturesDiedWatcher.class.getSimpleName()); + VileRedeemerNonTokenCreaturesDiedWatcher watcher = game.getState().getWatcher(VileRedeemerNonTokenCreaturesDiedWatcher.class); if (watcher != null) { int amount = watcher.getAmountOfNontokenCreatureDiedThisTurn(controller.getId()); if (amount > 0) { @@ -97,7 +97,7 @@ class VileRedeemerNonTokenCreaturesDiedWatcher extends Watcher { private final Map amountOfCreaturesThatDied = new HashMap<>(); public VileRedeemerNonTokenCreaturesDiedWatcher() { - super(VileRedeemerNonTokenCreaturesDiedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public VileRedeemerNonTokenCreaturesDiedWatcher(final VileRedeemerNonTokenCreaturesDiedWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/v/VillageCannibals.java b/Mage.Sets/src/mage/cards/v/VillageCannibals.java index 4e58de77ed..ea6af443dd 100644 --- a/Mage.Sets/src/mage/cards/v/VillageCannibals.java +++ b/Mage.Sets/src/mage/cards/v/VillageCannibals.java @@ -67,7 +67,7 @@ class VillageCannibalsTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); if (permanent != null && permanent.isCreature() && permanent.hasSubtype(SubType.HUMAN, game) && !permanent.getId().equals(this.getSourceId())) { diff --git a/Mage.Sets/src/mage/cards/v/VillainousWealth.java b/Mage.Sets/src/mage/cards/v/VillainousWealth.java index 2945165687..e45e4eded9 100644 --- a/Mage.Sets/src/mage/cards/v/VillainousWealth.java +++ b/Mage.Sets/src/mage/cards/v/VillainousWealth.java @@ -65,7 +65,7 @@ class VillainousWealthEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject mageObject = game.getObject(source.getSourceId()); - if (controller != null) { + if (controller != null && mageObject != null) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); FilterCard filter = new FilterNonlandCard(); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); diff --git a/Mage.Sets/src/mage/cards/v/VindictiveLich.java b/Mage.Sets/src/mage/cards/v/VindictiveLich.java index 4d4ffeb4ba..281345c030 100644 --- a/Mage.Sets/src/mage/cards/v/VindictiveLich.java +++ b/Mage.Sets/src/mage/cards/v/VindictiveLich.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.Mode; @@ -19,8 +17,9 @@ import mage.filter.predicate.mageobject.AnotherTargetPredicate; import mage.target.Target; import mage.target.common.TargetOpponent; +import java.util.UUID; + /** - * * @author anonymous */ public final class VindictiveLich extends CardImpl { @@ -33,37 +32,37 @@ public final class VindictiveLich extends CardImpl { this.toughness = new MageInt(1); // When Vindictive Lich dies, choose one or more. Each mode must target a different player. - // *Target opponent sacrifices a creature. + + // * Target opponent sacrifices a creature. Ability ability = new DiesTriggeredAbility(new SacrificeEffect(StaticFilters.FILTER_PERMANENT_CREATURE, 1, "target opponent")); ability.getModes().setMinModes(1); ability.getModes().setMaxModes(3); ability.getModes().setEachModeOnlyOnce(true); ability.getModes().setMaxModesFilter(new FilterOpponent("a different player")); - - FilterOpponent filter = new FilterOpponent("opponent (sacrifice)"); + FilterOpponent filter = new FilterOpponent(); filter.add(new AnotherTargetPredicate(1, true)); - Target target = new TargetOpponent(filter, false); + Target target = new TargetOpponent(filter, false).withChooseHint("who sacrifice a creature"); target.setTargetTag(1); ability.addTarget(target); - // *Target opponent discards two cards. + // * Target opponent discards two cards. Mode mode = new Mode(); - mode.getEffects().add(new DiscardTargetEffect(2, false)); - filter = new FilterOpponent("opponent (discard)"); + mode.addEffect(new DiscardTargetEffect(2, false)); + filter = new FilterOpponent(); filter.add(new AnotherTargetPredicate(2, true)); target = new TargetOpponent(filter, false); target.setTargetTag(2); - mode.getTargets().add(target); + mode.addTarget(target.withChooseHint("who discard a card")); ability.addMode(mode); - // *Target opponent loses 5 life. + // * Target opponent loses 5 life. mode = new Mode(); - mode.getEffects().add(new LoseLifeTargetEffect(5)); - filter = new FilterOpponent("opponent (life loss)"); + mode.addEffect(new LoseLifeTargetEffect(5)); + filter = new FilterOpponent(); filter.add(new AnotherTargetPredicate(3, true)); target = new TargetOpponent(filter, false); target.setTargetTag(3); - mode.getTargets().add(target); + mode.addTarget(target.withChooseHint("who lose 5 life")); ability.addMode(mode); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VindictiveVampire.java b/Mage.Sets/src/mage/cards/v/VindictiveVampire.java new file mode 100644 index 0000000000..1a49b81e00 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VindictiveVampire.java @@ -0,0 +1,54 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.effects.common.DamagePlayersEffect; +import mage.abilities.effects.common.GainLifeEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VindictiveVampire extends CardImpl { + + private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); + + static { + filter.add(AnotherPredicate.instance); + } + + public VindictiveVampire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // Whenever another creature you control dies, Vindictive Vampire deals 1 damage to each opponent and you gain 1 life. + Ability ability = new DiesCreatureTriggeredAbility( + new DamagePlayersEffect(1, TargetController.OPPONENT), false, + filter, true + ); + ability.addEffect(new GainLifeEffect(1).concatBy("and")); + this.addAbility(ability); + } + + private VindictiveVampire(final VindictiveVampire card) { + super(card); + } + + @Override + public VindictiveVampire copy() { + return new VindictiveVampire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VintaraSnapper.java b/Mage.Sets/src/mage/cards/v/VintaraSnapper.java index b4b16b30f3..68f6d77c7b 100644 --- a/Mage.Sets/src/mage/cards/v/VintaraSnapper.java +++ b/Mage.Sets/src/mage/cards/v/VintaraSnapper.java @@ -28,7 +28,7 @@ public final class VintaraSnapper extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public VintaraSnapper(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/ViralDrake.java b/Mage.Sets/src/mage/cards/v/ViralDrake.java index 251ae89246..ea734a75cb 100644 --- a/Mage.Sets/src/mage/cards/v/ViralDrake.java +++ b/Mage.Sets/src/mage/cards/v/ViralDrake.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.mana.ManaCostsImpl; @@ -14,21 +12,27 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author North */ public final class ViralDrake extends CardImpl { public ViralDrake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.DRAKE); this.power = new MageInt(1); this.toughness = new MageInt(4); + // Flying this.addAbility(FlyingAbility.getInstance()); + + // Infect (This creature deals damage to creatures in the form of -1/-1 counters and to players in the form of poison counters.) this.addAbility(InfectAbility.getInstance()); + + // {3}{U}: Proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new ProliferateEffect(), new ManaCostsImpl("{3}{U}"))); } diff --git a/Mage.Sets/src/mage/cards/v/VirtussManeuver.java b/Mage.Sets/src/mage/cards/v/VirtussManeuver.java index 70880e200f..e122eaf4de 100644 --- a/Mage.Sets/src/mage/cards/v/VirtussManeuver.java +++ b/Mage.Sets/src/mage/cards/v/VirtussManeuver.java @@ -69,7 +69,7 @@ class VirtussManeuverEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); ChooseFriendsAndFoes choice = new ChooseFriendsAndFoes(); - if (!choice.chooseFriendOrFoe(controller, source, game)) { + if (controller != null && !choice.chooseFriendOrFoe(controller, source, game)) { return false; } Map getBackMap = new HashMap<>(); diff --git a/Mage.Sets/src/mage/cards/v/VirulentPlague.java b/Mage.Sets/src/mage/cards/v/VirulentPlague.java index 7dc9190f92..450da3f816 100644 --- a/Mage.Sets/src/mage/cards/v/VirulentPlague.java +++ b/Mage.Sets/src/mage/cards/v/VirulentPlague.java @@ -20,7 +20,7 @@ public final class VirulentPlague extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creature tokens"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); } public VirulentPlague(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VirulentWound.java b/Mage.Sets/src/mage/cards/v/VirulentWound.java index 8f80610989..da3fa83f05 100644 --- a/Mage.Sets/src/mage/cards/v/VirulentWound.java +++ b/Mage.Sets/src/mage/cards/v/VirulentWound.java @@ -93,7 +93,7 @@ class VirulentWoundDelayedTriggeredAbility extends DelayedTriggeredAbility { public boolean checkTrigger(GameEvent event, Game game) { if (event.getTargetId().equals(target)) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } diff --git a/Mage.Sets/src/mage/cards/v/VisageOfBolas.java b/Mage.Sets/src/mage/cards/v/VisageOfBolas.java index 965540ce1e..cb15e7252c 100644 --- a/Mage.Sets/src/mage/cards/v/VisageOfBolas.java +++ b/Mage.Sets/src/mage/cards/v/VisageOfBolas.java @@ -19,7 +19,7 @@ import mage.filter.predicate.mageobject.NamePredicate; */ public final class VisageOfBolas extends CardImpl { - private final static FilterCard filter = new FilterCard("Nicol Bolas, the Deceiver"); + private static final FilterCard filter = new FilterCard("Nicol Bolas, the Deceiver"); static { filter.add(new NamePredicate("Nicol Bolas, the Deceiver")); diff --git a/Mage.Sets/src/mage/cards/v/VishKalBloodArbiter.java b/Mage.Sets/src/mage/cards/v/VishKalBloodArbiter.java index 948eb6ae9e..dc3d414a5d 100644 --- a/Mage.Sets/src/mage/cards/v/VishKalBloodArbiter.java +++ b/Mage.Sets/src/mage/cards/v/VishKalBloodArbiter.java @@ -51,7 +51,7 @@ public final class VishKalBloodArbiter extends CardImpl { this.addAbility(LifelinkAbility.getInstance()); // Sacrifice a creature: Put X +1/+1 counters on Vish Kal, Blood Arbiter, where X is the sacrificed creature's power. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, - new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), new SacrificeCostCreaturesPower(), true), + new AddCountersSourceEffect(CounterType.P1P1.createInstance(0), SacrificeCostCreaturesPower.instance, true), new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT)))); // Remove all +1/+1 counters from Vish Kal: Target creature gets -1/-1 until end of turn for each +1/+1 counter removed this way. DynamicValue removedCounters = new SignInversionDynamicValue(new VishKalBloodArbiterDynamicValue()); diff --git a/Mage.Sets/src/mage/cards/v/VisionCharm.java b/Mage.Sets/src/mage/cards/v/VisionCharm.java index b59693f08e..356ff7802a 100644 --- a/Mage.Sets/src/mage/cards/v/VisionCharm.java +++ b/Mage.Sets/src/mage/cards/v/VisionCharm.java @@ -44,13 +44,13 @@ public final class VisionCharm extends CardImpl { // or choose a land type and a basic land type. Each land of the first chosen type becomes the second chosen type until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new VisionCharmEffect()); + mode.addEffect(new VisionCharmEffect()); this.getSpellAbility().addMode(mode); // or target artifact phases out. mode = new Mode(); - mode.getEffects().add(new PhaseOutTargetEffect()); - mode.getTargets().add(new TargetArtifactPermanent()); + mode.addEffect(new PhaseOutTargetEffect()); + mode.addTarget(new TargetArtifactPermanent()); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VitalityCharm.java b/Mage.Sets/src/mage/cards/v/VitalityCharm.java index adfce993fd..a77e23ba67 100644 --- a/Mage.Sets/src/mage/cards/v/VitalityCharm.java +++ b/Mage.Sets/src/mage/cards/v/VitalityCharm.java @@ -41,16 +41,16 @@ public final class VitalityCharm extends CardImpl { Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("target creature gets +1/+1"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); effect.setText("and gains trample until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(effect); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().addMode(mode); // or regenerate target Beast. mode = new Mode(); - mode.getEffects().add(new RegenerateTargetEffect()); - mode.getTargets().add(new TargetPermanent(filter)); + mode.addEffect(new RegenerateTargetEffect()); + mode.addTarget(new TargetPermanent(filter)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/v/VitalizingCascade.java b/Mage.Sets/src/mage/cards/v/VitalizingCascade.java index bb1b0f5288..2cf7940398 100644 --- a/Mage.Sets/src/mage/cards/v/VitalizingCascade.java +++ b/Mage.Sets/src/mage/cards/v/VitalizingCascade.java @@ -1,9 +1,8 @@ package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.ManacostVariableValue; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; @@ -11,17 +10,18 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.game.Game; +import java.util.UUID; + /** - * * @author LoneFox */ public final class VitalizingCascade extends CardImpl { public VitalizingCascade(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{G}{W}"); // You gain X plus 3 life. - this.getSpellAbility().addEffect(new GainLifeEffect(new VitalizingCascadeValue())); + this.getSpellAbility().addEffect(new GainLifeEffect(VitalizingCascadeValue.instance)); } public VitalizingCascade(final VitalizingCascade card) { @@ -34,16 +34,22 @@ public final class VitalizingCascade extends CardImpl { } } -class VitalizingCascadeValue extends ManacostVariableValue { +enum VitalizingCascadeValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return super.calculate(game, sourceAbility, effect) + 3; + return sourceAbility.getManaCosts().getX() + 3; } @Override public VitalizingCascadeValue copy() { - return new VitalizingCascadeValue(); + return instance; + } + + @Override + public String getMessage() { + return ""; } @Override diff --git a/Mage.Sets/src/mage/cards/v/VividRevival.java b/Mage.Sets/src/mage/cards/v/VividRevival.java index 267bf076bb..98cea2f988 100644 --- a/Mage.Sets/src/mage/cards/v/VividRevival.java +++ b/Mage.Sets/src/mage/cards/v/VividRevival.java @@ -19,7 +19,7 @@ public final class VividRevival extends CardImpl { private static final FilterCard filter = new FilterCard("multicolored cards from your graveyard"); static { - filter.add(new MulticoloredPredicate()); + filter.add(MulticoloredPredicate.instance); } public VividRevival(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java b/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java new file mode 100644 index 0000000000..f08781e6df --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VivienChampionOfTheWilds.java @@ -0,0 +1,210 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.AsThoughEffectImpl; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.CastAsThoughItHadFlashAllEffect; +import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; +import mage.abilities.keyword.ReachAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; +import mage.target.common.TargetCreaturePermanent; +import mage.target.targetpointer.FixedTarget; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VivienChampionOfTheWilds extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature spells"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public VivienChampionOfTheWilds(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VIVIEN); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(4)); + + // You may cast creature spells as though they had flash. + this.addAbility(new SimpleStaticAbility(new CastAsThoughItHadFlashAllEffect( + Duration.WhileOnBattlefield, filter + ))); + + // +1: Until your next turn, up to one target creature gains vigilance and reach. + Ability ability = new LoyaltyAbility(new GainAbilityTargetEffect( + VigilanceAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("Until your next turn, up to one target creature gains vigilance"), 1); + ability.addEffect(new GainAbilityTargetEffect( + ReachAbility.getInstance(), Duration.UntilYourNextTurn + ).setText("and reach")); + ability.addTarget(new TargetCreaturePermanent(0, 1)); + this.addAbility(ability); + + // -2: Look at the top three cards of your library. Exile one face down and put the rest on the bottom of your library in any order. + // For as long as it remains exiled, you may look at that card and you may cast it if it's a creature card. + this.addAbility(new LoyaltyAbility(new VivienChampionOfTheWildsEffect(), -2)); + } + + private VivienChampionOfTheWilds(final VivienChampionOfTheWilds card) { + super(card); + } + + @Override + public VivienChampionOfTheWilds copy() { + return new VivienChampionOfTheWilds(this); + } +} + +class VivienChampionOfTheWildsEffect extends OneShotEffect { + + VivienChampionOfTheWildsEffect() { + super(Outcome.Benefit); + staticText = "Look at the top three cards of your library. " + + "Exile one face down and put the rest on the bottom of your library in any order. " + + "For as long as it remains exiled, you may look at that card " + + "and you may cast it if it's a creature card."; + } + + private VivienChampionOfTheWildsEffect(final VivienChampionOfTheWildsEffect effect) { + super(effect); + } + + @Override + public VivienChampionOfTheWildsEffect copy() { + return new VivienChampionOfTheWildsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + + // select + Cards cardsToLook = new CardsImpl(player.getLibrary().getTopCards(game, 3)); + FilterCard filter = new FilterCard("card to exile face down"); + TargetCard target = new TargetCardInLibrary(filter); + if (!player.choose(outcome, cardsToLook, target, game)) { + return false; + } + + // exile + Card cardToExile = game.getCard(target.getFirstTarget()); + if (!player.moveCardsToExile(cardToExile, source, game, false, + CardUtil.getCardExileZoneId(game, source), + CardUtil.createObjectRealtedWindowTitle(source, game, " (look and cast)"))) { + return false; + } + cardToExile.setFaceDown(true, game); + + // look and cast + ContinuousEffect effect = new VivienChampionOfTheWildsLookEffect(player.getId()); + effect.setTargetPointer(new FixedTarget(cardToExile, game)); + game.addEffect(effect, source); + if (cardToExile.isCreature()) { + effect = new VivienChampionOfTheWildsCastFromExileEffect(player.getId()); + effect.setTargetPointer(new FixedTarget(cardToExile, game)); + game.addEffect(effect, source); + } + + // put the rest on the bottom of your library in any order + Cards cardsToBottom = new CardsImpl(cardsToLook); + cardsToBottom.remove(cardToExile); + player.putCardsOnBottomOfLibrary(cardsToBottom, game, source, true); + + return true; + } +} + +class VivienChampionOfTheWildsLookEffect extends AsThoughEffectImpl { + + private final UUID authorizedPlayerId; + + VivienChampionOfTheWildsLookEffect(UUID authorizedPlayerId) { + super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); + this.authorizedPlayerId = authorizedPlayerId; + } + + private VivienChampionOfTheWildsLookEffect(final VivienChampionOfTheWildsLookEffect effect) { + super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public VivienChampionOfTheWildsLookEffect copy() { + return new VivienChampionOfTheWildsLookEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + UUID cardId = getTargetPointer().getFirst(game, source); + if (cardId == null) { + this.discard(); // card is no longer in the origin zone, effect can be discarded + } + return affectedControllerId.equals(authorizedPlayerId) + && objectId.equals(cardId); + } +} + +class VivienChampionOfTheWildsCastFromExileEffect extends AsThoughEffectImpl { + + private final UUID authorizedPlayerId; + + VivienChampionOfTheWildsCastFromExileEffect(UUID authorizedPlayerId) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit); + this.authorizedPlayerId = authorizedPlayerId; + } + + private VivienChampionOfTheWildsCastFromExileEffect(final VivienChampionOfTheWildsCastFromExileEffect effect) { + super(effect); + this.authorizedPlayerId = effect.authorizedPlayerId; + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public VivienChampionOfTheWildsCastFromExileEffect copy() { + return new VivienChampionOfTheWildsCastFromExileEffect(this); + } + + @Override + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + UUID cardId = getTargetPointer().getFirst(game, source); + if (cardId == null) { + this.discard(); // card is no longer in the origin zone, effect can be discarded + } else if (objectId.equals(cardId) + && affectedControllerId.equals(authorizedPlayerId)) { + Card card = game.getCard(objectId); + // TODO: Allow to cast Zoetic Cavern face down + return card != null && !card.isLand(); + } + return false; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/ViviensArkbow.java b/Mage.Sets/src/mage/cards/v/ViviensArkbow.java new file mode 100644 index 0000000000..0db7847a76 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ViviensArkbow.java @@ -0,0 +1,90 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ViviensArkbow extends CardImpl { + + public ViviensArkbow(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}"); + + this.addSuperType(SuperType.LEGENDARY); + + // {X}, {T}, Discard a card: Look at the top X cards of your library. You may put a creature card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order. + Ability ability = new SimpleActivatedAbility( + new ViviensArkbowEffect(), new ManaCostsImpl("{X}") + ); + ability.addCost(new TapSourceCost()); + ability.addCost(new DiscardCardCost()); + this.addAbility(ability); + } + + private ViviensArkbow(final ViviensArkbow card) { + super(card); + } + + @Override + public ViviensArkbow copy() { + return new ViviensArkbow(this); + } +} + +class ViviensArkbowEffect extends OneShotEffect { + + ViviensArkbowEffect() { + super(Outcome.Benefit); + staticText = "Look at the top X cards of your library. " + + "You may put a creature card with converted mana cost X or less " + + "from among them onto the battlefield. Put the rest on the bottom of your library in a random order."; + } + + private ViviensArkbowEffect(final ViviensArkbowEffect effect) { + super(effect); + } + + @Override + public ViviensArkbowEffect copy() { + return new ViviensArkbowEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + int xValue = source.getManaCostsToPay().getX(); + Cards cards = new CardsImpl(player.getLibrary().getTopCards(game, xValue)); + player.lookAtCards(source, null, cards, game); + + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost " + xValue + " or less"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, xValue + 1)); + TargetCard target = new TargetCardInHand(0, 1, filter); + + if (player.choose(outcome, cards, target, game)) { + Card card = game.getCard(target.getFirstTarget()); + if (player.moveCards(card, Zone.BATTLEFIELD, source, game)) { + cards.remove(card); + } + } + return player.putCardsOnBottomOfLibrary(cards, game, source, false); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/ViviensGrizzly.java b/Mage.Sets/src/mage/cards/v/ViviensGrizzly.java new file mode 100644 index 0000000000..769942ef6e --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/ViviensGrizzly.java @@ -0,0 +1,85 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.*; +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 ViviensGrizzly extends CardImpl { + + public ViviensGrizzly(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}"); + + this.subtype.add(SubType.BEAR); + this.subtype.add(SubType.SPIRIT); + this.power = new MageInt(2); + this.toughness = new MageInt(3); + + // {3}{G}: Look at the top card of your library. If it's a creature or planeswalker card, you may reveal it and put it into your hand. If you don't put the card into your hand, put it on the bottom of your library. + this.addAbility(new SimpleActivatedAbility( + new ViviensGrizzlyEffect(), new ManaCostsImpl("{3}{G}") + )); + } + + private ViviensGrizzly(final ViviensGrizzly card) { + super(card); + } + + @Override + public ViviensGrizzly copy() { + return new ViviensGrizzly(this); + } +} + +class ViviensGrizzlyEffect extends OneShotEffect { + + ViviensGrizzlyEffect() { + super(Outcome.Benefit); + staticText = "Look at the top card of your library. " + + "If it's a creature or planeswalker card, " + + "you may reveal it and put it into your hand. " + + "If you don't put the card into your hand, " + + "put it on the bottom of your library."; + } + + private ViviensGrizzlyEffect(final ViviensGrizzlyEffect effect) { + super(effect); + } + + @Override + public ViviensGrizzlyEffect copy() { + return new ViviensGrizzlyEffect(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); + Cards cards = new CardsImpl(card); + player.lookAtCards(source, null, cards, game); + if ((!card.isPlaneswalker() && !card.isCreature()) + || !player.chooseUse(outcome, "Put this card in your hand?", source, game)) { + player.putCardsOnBottomOfLibrary(cards, game, source, false); + } else { + player.revealCards(source, cards, game); + player.moveCards(card, Zone.HAND, source, game); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/ViviensInvocation.java b/Mage.Sets/src/mage/cards/v/ViviensInvocation.java index dec4018466..7eacc7e747 100644 --- a/Mage.Sets/src/mage/cards/v/ViviensInvocation.java +++ b/Mage.Sets/src/mage/cards/v/ViviensInvocation.java @@ -67,8 +67,7 @@ class ViviensInvocationEffect extends OneShotEffect { if (controller == null) { return false; } - Cards cards = new CardsImpl(); - cards.addAll(controller.getLibrary().getTopCards(game, 7)); + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); if (!cards.isEmpty()) { TargetCard target = new TargetCard( Zone.LIBRARY, diff --git a/Mage.Sets/src/mage/cards/v/VizierOfDeferment.java b/Mage.Sets/src/mage/cards/v/VizierOfDeferment.java index 227ecc40a8..e7b275a073 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfDeferment.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfDeferment.java @@ -1,11 +1,7 @@ package mage.cards.v; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageInt; -import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; @@ -16,12 +12,9 @@ import mage.abilities.keyword.FlashAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Outcome; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -30,8 +23,9 @@ import mage.target.targetpointer.FixedTarget; import mage.watchers.common.AttackedThisTurnWatcher; import mage.watchers.common.BlockedThisTurnWatcher; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class VizierOfDeferment extends CardImpl { @@ -49,39 +43,10 @@ public final class VizierOfDeferment extends CardImpl { // When Vizier of Deferment enters the battlefield, you may exile target creature if it attacked or blocked this turn. Return that card to the battlefield under its owner's control at the beginning of the next end step. Ability ability = new EntersBattlefieldTriggeredAbility(new VizierOfDefermentEffect(), true); + ability.addTarget(new TargetCreaturePermanent()); ability.addWatcher(new AttackedThisTurnWatcher()); ability.addWatcher(new BlockedThisTurnWatcher()); this.addAbility(ability); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof EntersBattlefieldTriggeredAbility) { - List creaturesThatCanBeTargeted = new ArrayList<>(); - FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that attacked or blocked this turn."); - AttackedThisTurnWatcher watcherAttacked = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - BlockedThisTurnWatcher watcherBlocked = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); - if (watcherAttacked != null) { - for (MageObjectReference mor : watcherAttacked.getAttackedThisTurnCreatures()) { - Permanent permanent = mor.getPermanent(game); - if (permanent != null) { - creaturesThatCanBeTargeted.add(new PermanentIdPredicate(permanent.getId())); - } - } - if (watcherBlocked != null) { - for (MageObjectReference mor : watcherBlocked.getBlockedThisTurnCreatures()) { - Permanent permanent = mor.getPermanent(game); - if (permanent != null) { - creaturesThatCanBeTargeted.add(new PermanentIdPredicate(permanent.getId())); - } - } - } - filter.add(Predicates.or(creaturesThatCanBeTargeted)); - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(filter)); - } - } } public VizierOfDeferment(final VizierOfDeferment card) { @@ -98,7 +63,8 @@ class VizierOfDefermentEffect extends OneShotEffect { public VizierOfDefermentEffect() { super(Outcome.Detriment); - staticText = "you may exile target creature if it attacked or blocked this turn. Return that card to the battlefield under its owner's control at the beginning of the next end step"; + staticText = "you may exile target creature if it attacked or blocked this turn. " + + "Return that card to the battlefield under its owner's control at the beginning of the next end step"; } public VizierOfDefermentEffect(final VizierOfDefermentEffect effect) { @@ -110,8 +76,17 @@ class VizierOfDefermentEffect extends OneShotEffect { Permanent permanent = game.getPermanent(source.getFirstTarget()); Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); + AttackedThisTurnWatcher watcherAttacked = game.getState().getWatcher(AttackedThisTurnWatcher.class); + BlockedThisTurnWatcher watcherBlocked = game.getState().getWatcher(BlockedThisTurnWatcher.class); + boolean attackedOrBlocked = false; + if (watcherAttacked != null && watcherAttacked.checkIfAttacked(permanent, game)) { + attackedOrBlocked = true; + } + if (watcherBlocked != null && watcherBlocked.checkIfBlocked(permanent, game)) { + attackedOrBlocked = true; + } if (controller != null - && permanent != null + && attackedOrBlocked && sourcePermanent != null) { if (controller.moveCardToExileWithInfo(permanent, source.getSourceId(), sourcePermanent.getIdName(), source.getSourceId(), game, Zone.BATTLEFIELD, true)) { Effect effect = new ReturnToBattlefieldUnderOwnerControlTargetEffect(); diff --git a/Mage.Sets/src/mage/cards/v/VizierOfManyFaces.java b/Mage.Sets/src/mage/cards/v/VizierOfManyFaces.java index 39c9d7a529..27efbbf652 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfManyFaces.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfManyFaces.java @@ -72,7 +72,7 @@ class VizierOfManyFacesApplyToPermanent extends ApplyToPermanent { for (Permanent entering : game.getPermanentsEntering().values()) { if (entering.getId().equals(copyToObjectId) && entering instanceof PermanentToken) { UUID originalCardId = ((PermanentToken) entering).getToken().getCopySourceCard().getId(); - EmbalmedThisTurnWatcher watcher = (EmbalmedThisTurnWatcher) game.getState().getWatchers().get(EmbalmedThisTurnWatcher.class.getSimpleName()); + EmbalmedThisTurnWatcher watcher = game.getState().getWatcher(EmbalmedThisTurnWatcher.class); if (watcher != null) { for (MageObjectReference mor : watcher.getEmbalmedThisTurnCards()) { if (mor.getSourceId().equals(originalCardId) && game.getState().getZoneChangeCounter(originalCardId) == mor.getZoneChangeCounter()) { @@ -97,7 +97,7 @@ class EmbalmedThisTurnWatcher extends Watcher { private final Set embalmedThisTurnTokens; public EmbalmedThisTurnWatcher() { - super(EmbalmedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); embalmedThisTurnTokens = new HashSet<>(); } diff --git a/Mage.Sets/src/mage/cards/v/VizierOfTheAnointed.java b/Mage.Sets/src/mage/cards/v/VizierOfTheAnointed.java index 34df5d8b55..a65c5e5d5d 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfTheAnointed.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfTheAnointed.java @@ -150,7 +150,7 @@ class SearchLibraryPutInGraveyard extends SearchEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java b/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java index 4df002baa7..a51a1e68b5 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java @@ -7,7 +7,7 @@ import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughManaEffect; -import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -31,7 +31,7 @@ public final class VizierOfTheMenagerie extends CardImpl { this.toughness = new MageInt(4); // You may look at the top card of your library. (You may do this at any time.) - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VizierOfTheMenagerieTopCardRevealedEffect())); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LookAtTopCardOfLibraryAnyTimeEffect())); // You may cast the top card of your library if it's a creature card. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VizierOfTheMenagerieTopCardCastEffect())); @@ -51,38 +51,6 @@ public final class VizierOfTheMenagerie extends CardImpl { } } -class VizierOfTheMenagerieTopCardRevealedEffect extends ContinuousEffectImpl { - - public VizierOfTheMenagerieTopCardRevealedEffect() { - super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "You may look at the top card of your library any time"; - } - - public VizierOfTheMenagerieTopCardRevealedEffect(final VizierOfTheMenagerieTopCardRevealedEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card topCard = controller.getLibrary().getFromTop(game); - if (topCard != null) { - MageObject vizierOfTheMenagerie = source.getSourceObject(game); - if (vizierOfTheMenagerie != null) { - controller.lookAtCards("Top card of " + vizierOfTheMenagerie.getIdName() + " controller's library", topCard, game); - } - } - } - return true; - } - - @Override - public VizierOfTheMenagerieTopCardRevealedEffect copy() { - return new VizierOfTheMenagerieTopCardRevealedEffect(this); - } -} - class VizierOfTheMenagerieTopCardCastEffect extends AsThoughEffectImpl { public VizierOfTheMenagerieTopCardCastEffect() { diff --git a/Mage.Sets/src/mage/cards/v/VizierOfTheScorpion.java b/Mage.Sets/src/mage/cards/v/VizierOfTheScorpion.java new file mode 100644 index 0000000000..fba4ca9269 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VizierOfTheScorpion.java @@ -0,0 +1,55 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.effects.keyword.AmassEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.predicate.permanent.TokenPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VizierOfTheScorpion extends CardImpl { + + private static final FilterPermanent filter = new FilterPermanent(SubType.ZOMBIE, "Zombie tokens"); + + static { + filter.add(TokenPredicate.instance); + } + + public VizierOfTheScorpion(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.ZOMBIE); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // When Vizier of the Scorpion enters the battlefield, amass 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new AmassEffect(1))); + + // Zombie tokens you control have deathtouch. + this.addAbility(new SimpleStaticAbility(new GainAbilityControlledEffect( + DeathtouchAbility.getInstance(), Duration.WhileOnBattlefield, filter + ))); + } + + private VizierOfTheScorpion(final VizierOfTheScorpion card) { + super(card); + } + + @Override + public VizierOfTheScorpion copy() { + return new VizierOfTheScorpion(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VizierOfTumblingSands.java b/Mage.Sets/src/mage/cards/v/VizierOfTumblingSands.java index 8ffc9d4ec9..3b02d878dd 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfTumblingSands.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfTumblingSands.java @@ -29,7 +29,7 @@ public final class VizierOfTumblingSands extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public VizierOfTumblingSands(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VizkopaConfessor.java b/Mage.Sets/src/mage/cards/v/VizkopaConfessor.java index acf0af6309..f9d392e22c 100644 --- a/Mage.Sets/src/mage/cards/v/VizkopaConfessor.java +++ b/Mage.Sets/src/mage/cards/v/VizkopaConfessor.java @@ -82,7 +82,7 @@ class VizkopaConfessorEffect extends OneShotEffect { int payLife = controller.getAmount(0, controller.getLife(),"Pay how many life?", game); if (payLife > 0) { controller.loseLife(payLife, game, false); - game.informPlayers(new StringBuilder(sourceCard.getName()).append(": ").append(controller.getLogName()).append(" pays ").append(payLife).append(" life").toString()); + game.informPlayers(sourceCard.getName() + ": " + controller.getLogName() + " pays " + payLife + " life"); Cards cardsInHand = new CardsImpl(); cardsInHand.addAll(targetPlayer.getHand()); diff --git a/Mage.Sets/src/mage/cards/v/VizkopaVampire.java b/Mage.Sets/src/mage/cards/v/VizkopaVampire.java new file mode 100644 index 0000000000..a8ca550db3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VizkopaVampire.java @@ -0,0 +1,36 @@ +package mage.cards.v; + +import mage.MageInt; +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 VizkopaVampire extends CardImpl { + + public VizkopaVampire(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W/B}"); + + this.subtype.add(SubType.VAMPIRE); + this.power = new MageInt(3); + this.toughness = new MageInt(1); + + // Lifelink + this.addAbility(LifelinkAbility.getInstance()); + } + + private VizkopaVampire(final VizkopaVampire card) { + super(card); + } + + @Override + public VizkopaVampire copy() { + return new VizkopaVampire(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java index 85ee063331..8c925e69cc 100644 --- a/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java +++ b/Mage.Sets/src/mage/cards/v/VodalianWarMachine.java @@ -48,7 +48,7 @@ public final class VodalianWarMachine extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped Merfolk you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.MERFOLK)); } @@ -143,7 +143,7 @@ class VodalianWarMachineEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourcePermanent != null) { - VodalianWarMachineWatcher watcher = (VodalianWarMachineWatcher) game.getState().getWatchers().get(VodalianWarMachineWatcher.class.getSimpleName()); + VodalianWarMachineWatcher watcher = game.getState().getWatcher(VodalianWarMachineWatcher.class); if (watcher != null && watcher.getTappedMerfolkIds(sourcePermanent, game) != null) { for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { if (watcher.getTappedMerfolkIds(sourcePermanent, game).contains(new MageObjectReference(permanent, game))) { @@ -163,7 +163,7 @@ class VodalianWarMachineWatcher extends Watcher { public Map> tappedMerfolkIds = new HashMap<>(); public VodalianWarMachineWatcher() { - super(VodalianWarMachineWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public VodalianWarMachineWatcher(final VodalianWarMachineWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/v/VoiceOfResurgence.java b/Mage.Sets/src/mage/cards/v/VoiceOfResurgence.java index 08b9cd0334..a3ec477ec0 100644 --- a/Mage.Sets/src/mage/cards/v/VoiceOfResurgence.java +++ b/Mage.Sets/src/mage/cards/v/VoiceOfResurgence.java @@ -1,4 +1,3 @@ - package mage.cards.v; import mage.MageInt; @@ -7,6 +6,7 @@ import mage.abilities.common.SpellCastOpponentTriggeredAbility; import mage.abilities.condition.common.MyTurnCondition; import mage.abilities.decorator.ConditionalTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.abilities.meta.OrTriggeredAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -19,7 +19,6 @@ import mage.game.permanent.token.VoiceOfResurgenceToken; import java.util.UUID; /** - * * @author jeffwadsworth */ public final class VoiceOfResurgence extends CardImpl { @@ -39,6 +38,7 @@ public final class VoiceOfResurgence extends CardImpl { "Whenever an opponent casts a spell during your turn, "), new DiesTriggeredAbility(null, false)); ability.setLeavesTheBattlefieldTrigger(true); + ability.addHint(CreaturesYouControlHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/v/VoiceOfTheWoods.java b/Mage.Sets/src/mage/cards/v/VoiceOfTheWoods.java index 1539f1eef8..5094e7e299 100644 --- a/Mage.Sets/src/mage/cards/v/VoiceOfTheWoods.java +++ b/Mage.Sets/src/mage/cards/v/VoiceOfTheWoods.java @@ -28,7 +28,7 @@ public final class VoiceOfTheWoods extends CardImpl { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Elves you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.ELF)); } diff --git a/Mage.Sets/src/mage/cards/v/VoidGrafter.java b/Mage.Sets/src/mage/cards/v/VoidGrafter.java index af9e959b4e..c4b6d62e0f 100644 --- a/Mage.Sets/src/mage/cards/v/VoidGrafter.java +++ b/Mage.Sets/src/mage/cards/v/VoidGrafter.java @@ -27,7 +27,7 @@ public final class VoidGrafter extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public VoidGrafter(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VoidWinnower.java b/Mage.Sets/src/mage/cards/v/VoidWinnower.java index 2a8e84ed30..704de660dc 100644 --- a/Mage.Sets/src/mage/cards/v/VoidWinnower.java +++ b/Mage.Sets/src/mage/cards/v/VoidWinnower.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -10,25 +8,22 @@ import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.GameEvent.EventType; import mage.game.permanent.Permanent; import mage.game.stack.Spell; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class VoidWinnower extends CardImpl { public VoidWinnower(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{9}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{9}"); this.subtype.add(SubType.ELDRAZI); this.power = new MageInt(11); @@ -125,7 +120,7 @@ class VoidWinnowerCantBlockEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } } diff --git a/Mage.Sets/src/mage/cards/v/VolatileRig.java b/Mage.Sets/src/mage/cards/v/VolatileRig.java index 6ec037917f..ec5ba97d61 100644 --- a/Mage.Sets/src/mage/cards/v/VolatileRig.java +++ b/Mage.Sets/src/mage/cards/v/VolatileRig.java @@ -130,7 +130,7 @@ class VolatileRigEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { return permanent.sacrifice(source.getSourceId(), game); @@ -161,7 +161,7 @@ class VolatileRigEffect2 extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { List permanents = game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), game); for (Permanent permanent : permanents) { diff --git a/Mage.Sets/src/mage/cards/v/VolcanicEruption.java b/Mage.Sets/src/mage/cards/v/VolcanicEruption.java index 8f2514123f..cf6c04bafe 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanicEruption.java +++ b/Mage.Sets/src/mage/cards/v/VolcanicEruption.java @@ -1,10 +1,8 @@ - package mage.cards.v; import java.util.List; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -18,6 +16,7 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetLandPermanent; +import mage.target.targetadjustment.TargetAdjuster; /** * @@ -25,23 +24,12 @@ import mage.target.common.TargetLandPermanent; */ public final class VolcanicEruption extends CardImpl { - private static final FilterLandPermanent filter = new FilterLandPermanent(SubType.MOUNTAIN, "Mountain"); - public VolcanicEruption(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}{U}"); // Destroy X target Mountains. Volcanic Eruption deals damage to each creature and each player equal to the number of Mountains put into a graveyard this way. - this.getSpellAbility().addTarget(new TargetLandPermanent(filter)); this.getSpellAbility().addEffect(new VolcanicEruptionEffect()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetLandPermanent(xValue, xValue, filter, false)); - } + this.getSpellAbility().setTargetAdjuster(VolcanicEruptionAdjuster.instance); } public VolcanicEruption(final VolcanicEruption card) { @@ -54,6 +42,19 @@ public final class VolcanicEruption extends CardImpl { } } +enum VolcanicEruptionAdjuster implements TargetAdjuster { + instance; + private static final FilterLandPermanent filter + = new FilterLandPermanent(SubType.MOUNTAIN, "Mountain"); + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int xValue = ability.getManaCostsToPay().getX(); + ability.addTarget(new TargetLandPermanent(xValue, xValue, filter, false)); + } +} + class VolcanicEruptionEffect extends OneShotEffect { public VolcanicEruptionEffect() { diff --git a/Mage.Sets/src/mage/cards/v/VolcanicGeyser.java b/Mage.Sets/src/mage/cards/v/VolcanicGeyser.java index 85a3f91712..1f13748ea7 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanicGeyser.java +++ b/Mage.Sets/src/mage/cards/v/VolcanicGeyser.java @@ -20,7 +20,7 @@ public final class VolcanicGeyser extends CardImpl { // Volcanic Geyser deals X damage to any target. - this.getSpellAbility().addEffect(new DamageTargetEffect(new ManacostVariableValue())); + this.getSpellAbility().addEffect(new DamageTargetEffect(ManacostVariableValue.instance)); this.getSpellAbility().addTarget(new TargetAnyTarget()); } diff --git a/Mage.Sets/src/mage/cards/v/VolcanicOffering.java b/Mage.Sets/src/mage/cards/v/VolcanicOffering.java index 9037d6ea45..3c9d41e2ee 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanicOffering.java +++ b/Mage.Sets/src/mage/cards/v/VolcanicOffering.java @@ -1,9 +1,7 @@ package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -22,30 +20,22 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetOpponentsChoicePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class VolcanicOffering extends CardImpl { - private static final FilterLandPermanent filterLand = new FilterLandPermanent("nonbasic land you don't control"); - private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature you don't control"); - static { - filterLand.add(new ControllerPredicate(TargetController.NOT_YOU)); - filterLand.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); - filterCreature.add(new ControllerPredicate(TargetController.NOT_YOU)); - } public VolcanicOffering(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{4}{R}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{R}"); // Destroy target nonbasic land you don't control and target nonbasic land of an opponent's choice you don't control. // Volcanic Offering deals 7 damage to target creature you don't control and 7 damage to target creature of an opponent's choice you don't control. this.getSpellAbility().addEffect(new VolcanicOfferingEffect()); - this.getSpellAbility().addTarget(new TargetPermanent(filterLand)); - this.getSpellAbility().addTarget(new TargetPermanent(filterCreature)); - + this.getSpellAbility().setTargetAdjuster(VolcanicOfferingAdjuster.instance); } public VolcanicOffering(final VolcanicOffering card) { @@ -53,27 +43,39 @@ public final class VolcanicOffering extends CardImpl { } @Override - public void adjustTargets(Ability ability, Game game) { - Player controller = game.getPlayer(ability.getControllerId()); - if (controller != null && (ability instanceof SpellAbility)) { - ability.getTargets().clear(); - ability.addTarget(new TargetPermanent(filterLand)); - FilterLandPermanent filterLandForOpponent = new FilterLandPermanent("nonbasic land not controlled by " + controller.getLogName()); - filterLandForOpponent.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); - filterLandForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); - ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterLandForOpponent, false, true)); + public VolcanicOffering copy() { + return new VolcanicOffering(this); + } +} - ability.addTarget(new TargetPermanent(filterCreature)); - FilterCreaturePermanent filterCreatureForOpponent = new FilterCreaturePermanent("creature not controlled by " + controller.getLogName()); - filterCreatureForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); - ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterCreatureForOpponent, false, true)); - } +enum VolcanicOfferingAdjuster implements TargetAdjuster { + instance; + private static final FilterLandPermanent filterLand = new FilterLandPermanent("nonbasic land you don't control"); + private static final FilterCreaturePermanent filterCreature = new FilterCreaturePermanent("creature you don't control"); + static { + filterLand.add(new ControllerPredicate(TargetController.NOT_YOU)); + filterLand.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); + filterCreature.add(new ControllerPredicate(TargetController.NOT_YOU)); } @Override - public VolcanicOffering copy() { - return new VolcanicOffering(this); + public void adjustTargets(Ability ability, Game game) { + Player controller = game.getPlayer(ability.getControllerId()); + if (controller == null) { + return; + } + ability.getTargets().clear(); + ability.addTarget(new TargetPermanent(filterLand)); + FilterLandPermanent filterLandForOpponent = new FilterLandPermanent("nonbasic land not controlled by " + controller.getLogName()); + filterLandForOpponent.add(Predicates.not(new SupertypePredicate(SuperType.BASIC))); + filterLandForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterLandForOpponent, false, true)); + + ability.addTarget(new TargetPermanent(filterCreature)); + FilterCreaturePermanent filterCreatureForOpponent = new FilterCreaturePermanent("creature not controlled by " + controller.getLogName()); + filterCreatureForOpponent.add(Predicates.not(new ControllerIdPredicate(controller.getId()))); + ability.addTarget(new TargetOpponentsChoicePermanent(1, 1, filterCreatureForOpponent, false, true)); } } diff --git a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java index de37cde0ff..b8bd54d50e 100644 --- a/Mage.Sets/src/mage/cards/v/VolcanoHellion.java +++ b/Mage.Sets/src/mage/cards/v/VolcanoHellion.java @@ -32,7 +32,7 @@ public final class VolcanoHellion extends CardImpl { this.toughness = new MageInt(5); // Volcano Hellion has echo {X}, where X is your life total. - this.addAbility(new EchoAbility(new ControllerLifeCount(), "{this} has echo {X}, where X is your life total.")); + this.addAbility(new EchoAbility(ControllerLifeCount.instance, "{this} has echo {X}, where X is your life total.")); // When Volcano Hellion enters the battlefield, it deals an amount of damage of your choice to you and target creature. The damage can't be prevented. Ability ability = new EntersBattlefieldTriggeredAbility(new VolcanoHellionEffect(), false); diff --git a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java index 1f4be360d2..f810467d90 100644 --- a/Mage.Sets/src/mage/cards/v/VoldarenPariah.java +++ b/Mage.Sets/src/mage/cards/v/VoldarenPariah.java @@ -28,7 +28,7 @@ public final class VoldarenPariah extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("three other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public VoldarenPariah(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java b/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java index 3e8ebbb7e5..d7344404e4 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java +++ b/Mage.Sets/src/mage/cards/v/VolrathTheFallen.java @@ -34,7 +34,7 @@ public final class VolrathTheFallen extends CardImpl { // {1}{B}, Discard a creature card: // Volrath the Fallen gets +X/+X until end of turn, where X is the discarded card's converted mana cost. - Effect effect = new BoostSourceEffect(new DiscardCostCardConvertedMana(),new DiscardCostCardConvertedMana(),Duration.EndOfTurn); + Effect effect = new BoostSourceEffect(DiscardCostCardConvertedMana.instance,DiscardCostCardConvertedMana.instance,Duration.EndOfTurn); effect.setText("{this} gets +X/+X until end of turn, where X is the discarded card's converted mana cost"); Ability ability = new SimpleActivatedAbility( diff --git a/Mage.Sets/src/mage/cards/v/VolrathsCurse.java b/Mage.Sets/src/mage/cards/v/VolrathsCurse.java index c9e64d9c20..5382f26e9d 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathsCurse.java +++ b/Mage.Sets/src/mage/cards/v/VolrathsCurse.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.SpecialAction; @@ -17,13 +15,7 @@ import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import static mage.cards.v.VolrathsCurse.keyString; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; @@ -31,8 +23,11 @@ import mage.target.TargetPermanent; import mage.target.common.TargetControlledPermanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + +import static mage.cards.v.VolrathsCurse.keyString; + /** - * * @author LevelX2 */ public final class VolrathsCurse extends CardImpl { @@ -40,7 +35,7 @@ public final class VolrathsCurse extends CardImpl { static final String keyString = "_ignoreEffectForTurn"; public VolrathsCurse(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{U}"); this.subtype.add(SubType.AURA); // Enchant creature @@ -94,12 +89,12 @@ class VolrathsCurseRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @@ -188,8 +183,8 @@ class VolrathsCurseIgnoreEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - String key = source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter() + keyString + game.getTurnNum() + ((ActivatedAbilityImpl)source).getActivatorId(); - game.getState().setValue(key,true); + String key = source.getSourceId().toString() + source.getSourceObjectZoneChangeCounter() + keyString + game.getTurnNum() + ((ActivatedAbilityImpl) source).getActivatorId(); + game.getState().setValue(key, true); return true; } } diff --git a/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java b/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java new file mode 100644 index 0000000000..3c8444a70e --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VolrathsDungeon.java @@ -0,0 +1,135 @@ +package mage.cards.v; + +import mage.abilities.Ability; +import mage.abilities.ActivatedAbility; +import mage.abilities.common.ActivateAsSorceryActivatedAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.abilities.costs.common.DiscardCardCost; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author jeffwadsworth + */ +public final class VolrathsDungeon extends CardImpl { + + public VolrathsDungeon(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}"); + + // Pay 5 life: Destroy Volrath's Dungeon. Any player may activate this ability but only during their turn. + ActivatedAbility ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new DestroySourceEffect().setText("Destroy {this}. Any player may activate this ability but only during their turn."), + new PayLifeActivePlayerCost(5)); + ability.setMayActivate(TargetController.ACTIVE); + this.addAbility(ability); + + // Discard a card: Target player puts a card from their hand on top of their library. Activate this ability only any time you could cast a sorcery. + FilterCard filter = new FilterCard("a card for payment"); + Ability ability2 = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, new VolrathsDungeonEffect(), new DiscardCardCost(filter)); + ability2.addTarget(new TargetPlayer()); + this.addAbility(ability2); + } + + public VolrathsDungeon(final VolrathsDungeon card) { + super(card); + } + + @Override + public VolrathsDungeon copy() { + return new VolrathsDungeon(this); + } +} + +class PayLifeActivePlayerCost extends CostImpl { + + private final DynamicValue amount; + + public PayLifeActivePlayerCost(int amount) { + this.amount = new StaticValue(amount); + this.text = "Pay " + amount + " life"; + } + + public PayLifeActivePlayerCost(DynamicValue amount, String text) { + this.amount = amount.copy(); + this.text = "Pay " + text; + } + + public PayLifeActivePlayerCost(PayLifeActivePlayerCost cost) { + super(cost); + this.amount = cost.amount.copy(); + } + + @Override + public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { + int lifeToPayAmount = amount.calculate(game, ability, null); + return game.getPlayer(game.getActivePlayerId()).getLife() >= lifeToPayAmount; + } + + @Override + public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { + int lifeToPayAmount = amount.calculate(game, ability, null); + Player activatingPlayer = game.getPlayer(game.getActivePlayerId()); + if (activatingPlayer != null + && activatingPlayer.chooseUse(Outcome.LoseLife, "Do you wish to pay " + lifeToPayAmount + " life?", ability, game)) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player != null) { + this.paid = player.loseLife(lifeToPayAmount, game, false) == lifeToPayAmount; + } + } + return paid; + } + + @Override + public PayLifeActivePlayerCost copy() { + return new PayLifeActivePlayerCost(this); + } +} + +class VolrathsDungeonEffect extends OneShotEffect { + + public VolrathsDungeonEffect() { + super(Outcome.Detriment); + this.staticText = "Target player puts a card from their hand on top of their library"; + } + + public VolrathsDungeonEffect(final VolrathsDungeonEffect effect) { + super(effect); + } + + @Override + public VolrathsDungeonEffect copy() { + return new VolrathsDungeonEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player targetedPlayer = game.getPlayer(source.getFirstTarget()); + if (targetedPlayer != null) { + TargetCardInHand target = new TargetCardInHand(); + if (targetedPlayer.choose(Outcome.Detriment, targetedPlayer.getHand(), target, game)) { + Card card = game.getCard(target.getFirstTarget()); + return card != null && targetedPlayer.putCardOnTopXOfLibrary(card, game, source, 0); + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/v/VolrathsGardens.java b/Mage.Sets/src/mage/cards/v/VolrathsGardens.java index e7a9f62da5..b6378c084f 100644 --- a/Mage.Sets/src/mage/cards/v/VolrathsGardens.java +++ b/Mage.Sets/src/mage/cards/v/VolrathsGardens.java @@ -25,7 +25,7 @@ public final class VolrathsGardens extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public VolrathsGardens(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/v/VoltCharge.java b/Mage.Sets/src/mage/cards/v/VoltCharge.java index 06cf552162..4a711c47c5 100644 --- a/Mage.Sets/src/mage/cards/v/VoltCharge.java +++ b/Mage.Sets/src/mage/cards/v/VoltCharge.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.counter.ProliferateEffect; import mage.cards.CardImpl; @@ -9,19 +7,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author North */ public final class VoltCharge extends CardImpl { public VoltCharge(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}"); - - this.getSpellAbility().addTarget(new TargetAnyTarget()); + // Volt Charge deals 3 damage to any target. Proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.) this.getSpellAbility().addEffect(new DamageTargetEffect(3)); this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addTarget(new TargetAnyTarget()); } public VoltCharge(final VoltCharge card) { diff --git a/Mage.Sets/src/mage/cards/v/VonasHunger.java b/Mage.Sets/src/mage/cards/v/VonasHunger.java index 07e06bb034..3d4c435349 100644 --- a/Mage.Sets/src/mage/cards/v/VonasHunger.java +++ b/Mage.Sets/src/mage/cards/v/VonasHunger.java @@ -1,9 +1,5 @@ - package mage.cards.v; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.CitysBlessingCondition; @@ -11,6 +7,7 @@ import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.SacrificeOpponentsEffect; import mage.abilities.effects.keyword.AscendEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -21,8 +18,11 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class VonasHunger extends CardImpl { @@ -43,6 +43,7 @@ public final class VonasHunger extends CardImpl { new VonasHungerEffect(), CitysBlessingCondition.instance, "If you have the city's blessing, instead each opponent sacrifices half the creatures he or she controls rounded up")); + this.getSpellAbility().addHint(CitysBlessingHint.instance); } public VonasHunger(final VonasHunger card) { diff --git a/Mage.Sets/src/mage/cards/v/VoodooDoll.java b/Mage.Sets/src/mage/cards/v/VoodooDoll.java new file mode 100644 index 0000000000..b1828f6a0b --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VoodooDoll.java @@ -0,0 +1,80 @@ + +package mage.cards.v; + +import java.util.UUID; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.condition.InvertCondition; +import mage.abilities.condition.common.SourceTappedCondition; +import mage.abilities.costs.VariableCost; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.costs.mana.VariableManaCost; +import mage.abilities.dynamicvalue.common.CountersSourceCount; +import mage.abilities.effects.common.DamageControllerEffect; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.DestroySourceEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.target.common.TargetAnyTarget; + +/** + * + * @author L_J + */ +public final class VoodooDoll extends CardImpl { + + public VoodooDoll(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{6}"); + + // At the beginning of your upkeep, put a pin counter on Voodoo Doll. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.PIN.createInstance()), TargetController.YOU, false)); + // At the beginning of your end step, if Voodoo Doll is untapped, destroy Voodoo Doll and it deals damage to you equal to the number of pin counters on it. + Ability ability = new BeginningOfEndStepTriggeredAbility(Zone.BATTLEFIELD, new DestroySourceEffect(), TargetController.YOU, + new InvertCondition(SourceTappedCondition.instance), false); + ability.addEffect(new DamageControllerEffect(new CountersSourceCount(CounterType.PIN))); + this.addAbility(ability); + // {X}{X}, {T}: Voodoo Doll deals damage equal to the number of pin counters on it to any target. X is the number of pin counters on Voodoo Doll. + Ability ability2 = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new CountersSourceCount(CounterType.PIN)), new ManaCostsImpl("{X}{X}")); + ability2.addCost(new TapSourceCost()); + ability2.addTarget(new TargetAnyTarget()); + for (VariableCost cost : ability2.getManaCosts().getVariableCosts()) { + if (cost instanceof VariableManaCost) { + ((VariableManaCost) cost).setMaxX(0); + break; + } + } + this.addAbility(ability2); + } + + @Override + public void adjustCosts(Ability ability, Game game) { + if (ability instanceof SimpleActivatedAbility) { + Permanent sourcePermanent = game.getPermanent(ability.getSourceId()); + if (sourcePermanent != null) { + int pin = sourcePermanent.getCounters(game).getCount(CounterType.PIN); + ability.getManaCostsToPay().clear(); + ability.getManaCostsToPay().add(0, new GenericManaCost(pin * 2)); + } + } + } + + public VoodooDoll(final VoodooDoll card) { + super(card); + } + + @Override + public VoodooDoll copy() { + return new VoodooDoll(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java b/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java index 20c2459b9a..01dbf3b1bf 100644 --- a/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java +++ b/Mage.Sets/src/mage/cards/v/VorelOfTheHullClade.java @@ -29,7 +29,7 @@ import mage.target.TargetPermanent; */ public final class VorelOfTheHullClade extends CardImpl { - final static private FilterPermanent filter = new FilterPermanent("artifact, creature, or land"); + static final private FilterPermanent filter = new FilterPermanent("artifact, creature, or land"); static { filter.add(Predicates.or( diff --git a/Mage.Sets/src/mage/cards/v/VoyagerDrake.java b/Mage.Sets/src/mage/cards/v/VoyagerDrake.java index 3db5967e0f..058ab18bf9 100644 --- a/Mage.Sets/src/mage/cards/v/VoyagerDrake.java +++ b/Mage.Sets/src/mage/cards/v/VoyagerDrake.java @@ -1,12 +1,9 @@ package mage.cards.v; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; -import mage.abilities.condition.common.KickedCondition; -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.dynamicvalue.common.MultikickerCount; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; import mage.abilities.keyword.FlyingAbility; @@ -14,21 +11,21 @@ import mage.abilities.keyword.MultikickerAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author jeffwadsworth */ public final class VoyagerDrake extends CardImpl { - private final UUID originalId; - public VoyagerDrake(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); this.subtype.add(SubType.DRAKE); this.power = new MageInt(3); @@ -41,29 +38,18 @@ public final class VoyagerDrake extends CardImpl { this.addAbility(FlyingAbility.getInstance()); // When Voyager Drake enters the battlefield, up to X target creatures gain flying until end of turn, where X is the number of times Voyager Drake was kicked. - //TODO this should trigger even if it wasn't kicked at all - Ability ability = new ConditionalInterveningIfTriggeredAbility( - new EntersBattlefieldTriggeredAbility(new GainAbilityTargetEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), false), - KickedCondition.instance, - "When {this} enters the battlefield, up to X target creatures gain flying until end of turn, where X is the number of times {this} was kicked."); - originalId = ability.getOriginalId(); + Ability ability = new EntersBattlefieldTriggeredAbility( + new GainAbilityTargetEffect( + FlyingAbility.getInstance(), Duration.EndOfTurn + ).setText("up to X target creatures gain flying until end of turn, " + + "where X is the number of times {this} was kicked.") + ); + ability.setTargetAdjuster(VoyagerDrakeAdjuster.instance); this.addAbility(ability); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability.getOriginalId().equals(originalId)) { - ability.getTargets().clear(); - int numbTargets = new MultikickerCount().calculate(game, ability, null); - if (numbTargets > 0) { - ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); - } - } - } - public VoyagerDrake(final VoyagerDrake card) { super(card); - this.originalId = card.originalId; } @Override @@ -71,3 +57,16 @@ public final class VoyagerDrake extends CardImpl { return new VoyagerDrake(this); } } + +enum VoyagerDrakeAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + int numbTargets = MultikickerCount.instance.calculate(game, ability, null); + if (numbTargets > 0) { + ability.addTarget(new TargetCreaturePermanent(0, numbTargets)); + } + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java index bb15a7f722..538c3b2f5d 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java +++ b/Mage.Sets/src/mage/cards/v/VraskaGolgariQueen.java @@ -37,7 +37,7 @@ public final class VraskaGolgariQueen extends CardImpl { = new FilterNonlandPermanent("nonland permanent with converted mana cost 3 or less"); static { - filter1.add(new AnotherPredicate()); + filter1.add(AnotherPredicate.instance); filter2.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); } diff --git a/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java b/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java new file mode 100644 index 0000000000..e1a7d3f2a5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskaSwarmsEminence.java @@ -0,0 +1,62 @@ +package mage.cards.v; + +import mage.abilities.LoyaltyAbility; +import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; +import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SetTargetPointer; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.game.permanent.token.AssassinToken2; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VraskaSwarmsEminence extends CardImpl { + + private static final FilterPermanent filter = new FilterCreaturePermanent("creature you control with deathtouch"); + + static { + filter.add(new AbilityPredicate(DeathtouchAbility.class)); + } + + public VraskaSwarmsEminence(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B/G}{B/G}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.VRASKA); + this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(5)); + + // Whenever a creature you control with deathtouch deals damage to a player or planeswalker, put a +1/+1 counter on that creature. + // TODO: make this trigger on planeswalkers + this.addAbility(new DealsDamageToAPlayerAllTriggeredAbility( + new AddCountersTargetEffect( + CounterType.P1P1.createInstance() + ).setText("put a +1/+1 counter on that creature"), + filter, false, SetTargetPointer.PERMANENT, false) + ); + + // -2: Create a 1/1 black Assassin creature token with deathtouch and "Whenever this creature deals damage to a planeswalker, destroy that planeswalker." + this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new AssassinToken2()), -2)); + } + + private VraskaSwarmsEminence(final VraskaSwarmsEminence card) { + super(card); + } + + @Override + public VraskaSwarmsEminence copy() { + return new VraskaSwarmsEminence(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java b/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java index 9ba830b1fa..a5edd3bed0 100644 --- a/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java +++ b/Mage.Sets/src/mage/cards/v/VraskaTheUnseen.java @@ -1,7 +1,5 @@ - package mage.cards.v; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.TriggeredAbilityImpl; @@ -12,14 +10,7 @@ import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.DamagedPlaneswalkerEvent; import mage.game.events.GameEvent; @@ -29,15 +20,15 @@ import mage.game.permanent.token.AssassinToken; import mage.target.common.TargetNonlandPermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * If an effect creates a copy of one of the Assassin creature tokens, the copy * will also have the triggered ability. - * + *

    * Each Assassin token's triggered ability will trigger whenever it deals combat * damage to any player, including you. * - * * @author LevelX2 */ public final class VraskaTheUnseen extends CardImpl { @@ -74,13 +65,11 @@ public final class VraskaTheUnseen extends CardImpl { class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { protected Ability ability; - protected int startingTurn; public VraskaTheUnseenGainAbilityEffect(Ability ability) { super(Duration.Custom, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); this.ability = ability; staticText = "Until your next turn, whenever a creature deals combat damage to {this}, destroy that creature"; - startingTurn = 0; } public VraskaTheUnseenGainAbilityEffect(final VraskaTheUnseenGainAbilityEffect effect) { @@ -88,12 +77,6 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { this.ability = effect.ability.copy(); } - @Override - public void init(Ability source, Game game) { - super.init(source, game); //To change body of generated methods, choose Tools | Templates. - startingTurn = game.getTurnNum(); - } - @Override public VraskaTheUnseenGainAbilityEffect copy() { return new VraskaTheUnseenGainAbilityEffect(this); @@ -111,10 +94,8 @@ class VraskaTheUnseenGainAbilityEffect extends ContinuousEffectImpl { @Override public boolean isInactive(Ability source, Game game) { - if (startingTurn != 0 && game.getTurnNum() != startingTurn) { - if (game.isActivePlayer(source.getControllerId())) { - return true; - } + if (getStartingTurnNum() != 0 && game.getTurnNum() != getStartingTurnNum()) { + return game.isActivePlayer(source.getControllerId()); } return false; } diff --git a/Mage.Sets/src/mage/cards/v/VraskasFinisher.java b/Mage.Sets/src/mage/cards/v/VraskasFinisher.java new file mode 100644 index 0000000000..1019d30af2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/v/VraskasFinisher.java @@ -0,0 +1,56 @@ +package mage.cards.v; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.TargetController; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.filter.predicate.permanent.ControllerPredicate; +import mage.filter.predicate.permanent.WasDealtDamageThisTurnPredicate; +import mage.target.TargetPermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class VraskasFinisher extends CardImpl { + + private static final FilterPermanent filter = new FilterCreatureOrPlaneswalkerPermanent( + "creature or planeswalker an opponent controls that was dealt damage this turn" + ); + + static { + filter.add(new WasDealtDamageThisTurnPredicate()); + filter.add(new ControllerPredicate(TargetController.OPPONENT)); + } + + public VraskasFinisher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); + + this.subtype.add(SubType.GORGON); + this.subtype.add(SubType.ASSASSIN); + this.power = new MageInt(3); + this.toughness = new MageInt(2); + + // When Vraska's Finisher enters the battlefield, destroy target creature or planeswalker an opponent controls that was dealt damage this turn. + Ability ability = new EntersBattlefieldTriggeredAbility(new DestroyTargetEffect()); + ability.addTarget(new TargetPermanent(filter)); + this.addAbility(ability); + } + + private VraskasFinisher(final VraskasFinisher card) { + super(card); + } + + @Override + public VraskasFinisher copy() { + return new VraskasFinisher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/v/VraskasScorn.java b/Mage.Sets/src/mage/cards/v/VraskasScorn.java index 1b8b257537..96871bf15b 100644 --- a/Mage.Sets/src/mage/cards/v/VraskasScorn.java +++ b/Mage.Sets/src/mage/cards/v/VraskasScorn.java @@ -17,7 +17,7 @@ import mage.target.common.TargetOpponent; */ public final class VraskasScorn extends CardImpl { - private final static FilterCard filter = new FilterCard("Vraska, Scheming Gorgon"); + private static final FilterCard filter = new FilterCard("Vraska, Scheming Gorgon"); static { filter.add(new NamePredicate(filter.getMessage())); diff --git a/Mage.Sets/src/mage/cards/v/VraskasStoneglare.java b/Mage.Sets/src/mage/cards/v/VraskasStoneglare.java index 853236eb45..7c849798bc 100644 --- a/Mage.Sets/src/mage/cards/v/VraskasStoneglare.java +++ b/Mage.Sets/src/mage/cards/v/VraskasStoneglare.java @@ -21,7 +21,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class VraskasStoneglare extends CardImpl { - private final static FilterCard filter = new FilterCard("Vraska, Regal Gorgon"); + private static final FilterCard filter = new FilterCard("Vraska, Regal Gorgon"); static { filter.add(new NamePredicate("Vraska, Regal Gorgon")); diff --git a/Mage.Sets/src/mage/cards/w/WailOfTheNim.java b/Mage.Sets/src/mage/cards/w/WailOfTheNim.java index 3b57263b08..a1440a01bb 100644 --- a/Mage.Sets/src/mage/cards/w/WailOfTheNim.java +++ b/Mage.Sets/src/mage/cards/w/WailOfTheNim.java @@ -25,7 +25,7 @@ public final class WailOfTheNim extends CardImpl { // or Wail of the Nim deals 1 damage to each creature and each player. Mode mode = new Mode(); - mode.getEffects().add(new DamageEverythingEffect(1)); + mode.addEffect(new DamageEverythingEffect(1)); this.getSpellAbility().getModes().addMode(mode); // Entwine {B} diff --git a/Mage.Sets/src/mage/cards/w/WaitingInTheWeeds.java b/Mage.Sets/src/mage/cards/w/WaitingInTheWeeds.java index 727d9642ef..fe4bc24294 100644 --- a/Mage.Sets/src/mage/cards/w/WaitingInTheWeeds.java +++ b/Mage.Sets/src/mage/cards/w/WaitingInTheWeeds.java @@ -48,7 +48,7 @@ class WaitingInTheWeedsEffect extends OneShotEffect { static { filter.add(new SubtypePredicate(SubType.FOREST)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public WaitingInTheWeedsEffect() { diff --git a/Mage.Sets/src/mage/cards/w/WakeTheDead.java b/Mage.Sets/src/mage/cards/w/WakeTheDead.java index 49f0cb0087..b4c6f60a72 100644 --- a/Mage.Sets/src/mage/cards/w/WakeTheDead.java +++ b/Mage.Sets/src/mage/cards/w/WakeTheDead.java @@ -3,7 +3,6 @@ package mage.cards.w; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; -import mage.abilities.SpellAbility; import mage.abilities.common.CastOnlyDuringPhaseStepSourceAbility; import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility; import mage.abilities.condition.common.OnOpponentsTurnCondition; @@ -18,11 +17,13 @@ import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.TurnPhase; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.common.FilterCreatureCard; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; import mage.target.targetpointer.FixedTargets; import java.util.ArrayList; @@ -30,29 +31,19 @@ import java.util.List; import java.util.UUID; /** - * * @author LevelX2 */ public final class WakeTheDead extends CardImpl { public WakeTheDead(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{X}{B}{B}"); // Cast Wake the Dead only during combat on an opponent's turn. this.addAbility(new CastOnlyDuringPhaseStepSourceAbility(TurnPhase.COMBAT, OnOpponentsTurnCondition.instance)); // Return X target creature cards from your graveyard to the battlefield. Sacrifice those creatures at the beginning of the next end step. this.getSpellAbility().addEffect(new WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(0, Integer.MAX_VALUE, new FilterCreatureCard("creature cards from your graveyard"))); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(xValue, xValue, new FilterCreatureCard("creature cards from your graveyard"))); - } + this.getSpellAbility().setTargetAdjuster(WakeTheDeadAdjuster.instance); } public WakeTheDead(final WakeTheDead card) { @@ -65,6 +56,17 @@ public final class WakeTheDead extends CardImpl { } } +enum WakeTheDeadAdjuster implements TargetAdjuster { + instance; + private static final FilterCard filter = new FilterCreatureCard("creature cards from your graveyard"); + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard(ability.getManaCostsToPay().getX(), filter)); + } +} + class WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect { public WakeTheDeadReturnFromGraveyardToBattlefieldTargetEffect() { diff --git a/Mage.Sets/src/mage/cards/w/WakerOfTheWilds.java b/Mage.Sets/src/mage/cards/w/WakerOfTheWilds.java index 77d38291e9..1504be0bf4 100644 --- a/Mage.Sets/src/mage/cards/w/WakerOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/w/WakerOfTheWilds.java @@ -40,7 +40,7 @@ public final class WakerOfTheWilds extends CardImpl { Zone.BATTLEFIELD, new AddCountersTargetEffect( CounterType.P1P1.createInstance(0), - new ManacostVariableValue() + ManacostVariableValue.instance ).setText("Put X +1/+1 counters on target land you control."), new ManaCostsImpl("{X}{G}{G}") ); diff --git a/Mage.Sets/src/mage/cards/w/WalkThePlank.java b/Mage.Sets/src/mage/cards/w/WalkThePlank.java index 3981e5f198..e4a61b8b6c 100644 --- a/Mage.Sets/src/mage/cards/w/WalkThePlank.java +++ b/Mage.Sets/src/mage/cards/w/WalkThePlank.java @@ -19,7 +19,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class WalkThePlank extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Merfolk creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("non-Merfolk creature"); static { filter.add(new CardTypePredicate(CardType.CREATURE)); diff --git a/Mage.Sets/src/mage/cards/w/WalkingDesecration.java b/Mage.Sets/src/mage/cards/w/WalkingDesecration.java index 59dea99b8c..3993a5594d 100644 --- a/Mage.Sets/src/mage/cards/w/WalkingDesecration.java +++ b/Mage.Sets/src/mage/cards/w/WalkingDesecration.java @@ -2,6 +2,7 @@ package mage.cards.w; import java.util.UUID; + import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -22,7 +23,6 @@ import mage.game.Game; import mage.players.Player; /** - * * @author fireshoes */ public final class WalkingDesecration extends CardImpl { @@ -64,14 +64,18 @@ class WalkingDesecrationEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (player != null && player.choose(outcome, typeChoice, game)) { - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); - RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn); - game.addEffect(effect, source); - return true; + if (player != null) { + if (sourceObject != null) { + Choice typeChoice = new ChoiceCreatureType(sourceObject); + if (player.choose(outcome, typeChoice, game)) { + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new SubtypePredicate(SubType.byDescription(typeChoice.getChoice()))); + RequirementEffect effect = new AttacksIfAbleAllEffect(filter, Duration.EndOfTurn); + game.addEffect(effect, source); + return true; + } + } } return false; } diff --git a/Mage.Sets/src/mage/cards/w/WalkingDream.java b/Mage.Sets/src/mage/cards/w/WalkingDream.java new file mode 100644 index 0000000000..30cacb3dae --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WalkingDream.java @@ -0,0 +1,59 @@ +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.OpponentControlsPermanentCondition; +import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; +import mage.abilities.effects.ContinuousRuleModifyingEffect; +import mage.abilities.effects.common.DontUntapInControllersUntapStepSourceEffect; +import mage.abilities.keyword.CantBeBlockedSourceAbility; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.ComparisonType; +import mage.constants.Zone; +import mage.filter.common.FilterCreaturePermanent; + +/** + * + * @author jeffwadsworth + */ +public final class WalkingDream extends CardImpl { + + private static final String rule = "{this} doesn't untap during your untap step if an opponent controls two or more creatures."; + + public WalkingDream(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}"); + + this.subtype.add(SubType.ILLUSION); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Walking Dream is unblockable. + this.addAbility(new CantBeBlockedSourceAbility()); + + // Walking Dream doesn't untap during your untap step if an opponent controls two or more creatures. + ContinuousRuleModifyingEffect dontUntap = new DontUntapInControllersUntapStepSourceEffect(false, true); + dontUntap.setText(rule); + Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, + new ConditionalContinuousRuleModifyingEffect( + dontUntap, + new OpponentControlsPermanentCondition( + new FilterCreaturePermanent(), + ComparisonType.MORE_THAN, 1))); + this.addAbility(ability); + + } + + public WalkingDream(final WalkingDream card) { + super(card); + } + + @Override + public WalkingDream copy() { + return new WalkingDream(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfDust.java b/Mage.Sets/src/mage/cards/w/WallOfDust.java index 5998d54a4c..7db60d9e58 100644 --- a/Mage.Sets/src/mage/cards/w/WallOfDust.java +++ b/Mage.Sets/src/mage/cards/w/WallOfDust.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.MageObjectReference; import mage.abilities.Ability; @@ -11,14 +9,15 @@ import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.TurnPhase; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author L_J (based on LevelX2) */ public final class WallOfDust extends CardImpl { @@ -76,7 +75,7 @@ class WallOfDustRestrictionEffect extends RestrictionEffect { if (targetPermanent == null) { return true; } - if (nextTurnTargetController == 0 && startingTurn != game.getTurnNum() && game.isActivePlayer(targetPermanent.getControllerId())) { + if (nextTurnTargetController == 0 && getStartingTurnNum() != game.getTurnNum() && game.isActivePlayer(targetPermanent.getControllerId())) { nextTurnTargetController = game.getTurnNum(); } return game.getPhase().getType() == TurnPhase.END && nextTurnTargetController > 0 && game.getTurnNum() > nextTurnTargetController; @@ -95,14 +94,12 @@ class WallOfDustRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(getTargetPointer().getFirst(game, source))) { - if (game.isActivePlayer(permanent.getControllerId())) { - return true; - } + return game.isActivePlayer(permanent.getControllerId()); } return false; } - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } } diff --git a/Mage.Sets/src/mage/cards/w/WallOfLostThoughts.java b/Mage.Sets/src/mage/cards/w/WallOfLostThoughts.java new file mode 100644 index 0000000000..94f2236dd2 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfLostThoughts.java @@ -0,0 +1,45 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.PutLibraryIntoGraveTargetEffect; +import mage.abilities.keyword.DefenderAbility; +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 WallOfLostThoughts extends CardImpl { + + public WallOfLostThoughts(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // When Wall of Lost Thoughts enters the battlefield, target player puts the top four cards of their library into their graveyard. + Ability ability = new EntersBattlefieldTriggeredAbility(new PutLibraryIntoGraveTargetEffect(4)); + ability.addTarget(new TargetPlayer()); + this.addAbility(ability); + } + + private WallOfLostThoughts(final WallOfLostThoughts card) { + super(card); + } + + @Override + public WallOfLostThoughts copy() { + return new WallOfLostThoughts(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfRunes.java b/Mage.Sets/src/mage/cards/w/WallOfRunes.java new file mode 100644 index 0000000000..47957d38b1 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfRunes.java @@ -0,0 +1,41 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.keyword.ScryEffect; +import mage.abilities.keyword.DefenderAbility; +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 WallOfRunes extends CardImpl { + + public WallOfRunes(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(4); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // When Wall of Runes enters the battlefield, scry 1. + this.addAbility(new EntersBattlefieldTriggeredAbility(new ScryEffect(1))); + } + + private WallOfRunes(final WallOfRunes card) { + super(card); + } + + @Override + public WallOfRunes copy() { + return new WallOfRunes(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfShadows.java b/Mage.Sets/src/mage/cards/w/WallOfShadows.java new file mode 100644 index 0000000000..248b0bf21e --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfShadows.java @@ -0,0 +1,138 @@ + +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.PreventionEffectImpl; +import mage.abilities.effects.common.CantBeTargetedSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.Filter; +import mage.filter.FilterObject; +import mage.filter.FilterPermanent; +import mage.filter.FilterStackObject; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.permanent.BlockedByIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.DamageCreatureEvent; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; + +/** + * + * @author L_J + */ +public final class WallOfShadows extends CardImpl { + + private static final FilterObject filter = new FilterStackObject("spells that can target only Walls or of abilities that can target only Walls"); + static { + filter.add(new CanTargetOnlyWallsPredicate()); + } + + public WallOfShadows(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // Prevent all damage that would be dealt to Wall of Vapor by creatures it's blocking. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WallOfShadowsEffect())); + + // Wall of Shadows can't be the target of spells that can target only Walls or of abilities that can target only Walls. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantBeTargetedSourceEffect(filter, Duration.WhileOnBattlefield))); + } + + public WallOfShadows(final WallOfShadows card) { + super(card); + } + + @Override + public WallOfShadows copy() { + return new WallOfShadows(this); + } +} + +class WallOfShadowsEffect extends PreventionEffectImpl { + + WallOfShadowsEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false); + staticText = "Prevent all damage that would be dealt to {this} by creatures it's blocking"; + } + + WallOfShadowsEffect(final WallOfShadowsEffect effect) { + super(effect); + } + + @Override + public WallOfShadowsEffect copy() { + return new WallOfShadowsEffect(this); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game) && event instanceof DamageCreatureEvent && event.getAmount() > 0) { + DamageCreatureEvent damageEvent = (DamageCreatureEvent) event; + if (event.getTargetId().equals(source.getSourceId())) { + Permanent permanent = game.getPermanentOrLKIBattlefield(damageEvent.getSourceId()); + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new BlockedByIdPredicate(source.getSourceId())); + if (permanent != null && filter.match(permanent, game)) { + return true; + } + } + } + return false; + } +} + +class CanTargetOnlyWallsPredicate implements Predicate { + + @Override + public boolean apply(MageObject input, Game game) { + boolean canTargetOnlyWalls = false; + StackObject stackObject = game.getStack().getSpell(input.getId()); + if (stackObject != null) { + for (Mode mode : stackObject.getStackAbility().getModes().values()) { + for (Target target : mode.getTargets()) { + Filter filter = target.getFilter(); + if (filter instanceof FilterPermanent) { + for (Object predicate : filter.getPredicates()) { + if (predicate instanceof SubtypePredicate) { + if (predicate.toString().equals("Subtype(Wall)")) { + canTargetOnlyWalls = true; // can target a Wall + } else { + return false; // can target a non-Wall permanent + } + } + // no return statement here, as different predicates might still apply (e.g. "blocking Wall") + } + } else { + return false; // can target non-permanents (i.e. not Walls) + } + } + } + } + return canTargetOnlyWalls; + } + + @Override + public String toString() { + return "can target only Walls"; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WallOfTombstones.java b/Mage.Sets/src/mage/cards/w/WallOfTombstones.java new file mode 100644 index 0000000000..16abfc19f7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WallOfTombstones.java @@ -0,0 +1,77 @@ + +package mage.cards.w; + +import java.util.UUID; +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.dynamicvalue.common.CardsInControllerGraveyardCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.SetToughnessSourceEffect; +import mage.abilities.keyword.DefenderAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.constants.TargetController; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.util.CardUtil; + +/** + * + * @author L_J + */ +public final class WallOfTombstones extends CardImpl { + + public WallOfTombstones(UUID ownerId, CardSetInfo setInfo) { + super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); + this.subtype.add(SubType.WALL); + this.power = new MageInt(0); + this.toughness = new MageInt(1); + + // Defender + this.addAbility(DefenderAbility.getInstance()); + + // At the beginning of your upkeep, change Wall of Tombstones’s base toughness to 1 plus the number of creature cards in your graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility(new WallOfTombstonesEffect(), TargetController.YOU, false)); + + } + + public WallOfTombstones(final WallOfTombstones card) { + super(card); + } + + @Override + public WallOfTombstones copy() { + return new WallOfTombstones(this); + } +} + +class WallOfTombstonesEffect extends OneShotEffect { + + public WallOfTombstonesEffect() { + super(Outcome.Detriment); + this.staticText = "change {this}’s base toughness to 1 plus the number of creature cards in your graveyard"; + } + + public WallOfTombstonesEffect(final WallOfTombstonesEffect effect) { + super(effect); + } + + @Override + public WallOfTombstonesEffect copy() { + return new WallOfTombstonesEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int newToughness = CardUtil.addWithOverflowCheck(1, new CardsInControllerGraveyardCount(StaticFilters.FILTER_CARD_CREATURE).calculate(game, source, this)); + game.addEffect(new SetToughnessSourceEffect(new StaticValue(newToughness), Duration.Custom, SubLayer.SetPT_7b), source); + return true; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WanderersStrike.java b/Mage.Sets/src/mage/cards/w/WanderersStrike.java new file mode 100644 index 0000000000..e707faed14 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WanderersStrike.java @@ -0,0 +1,35 @@ +package mage.cards.w; + +import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WanderersStrike extends CardImpl { + + public WanderersStrike(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{W}"); + + + // Exile target creature, then proliferate. + this.getSpellAbility().addEffect(new ExileTargetEffect()); + this.getSpellAbility().addEffect(new ProliferateEffect().concatBy("then")); + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + } + + private WanderersStrike(final WanderersStrike card) { + super(card); + } + + @Override + public WanderersStrike copy() { + return new WanderersStrike(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarCadence.java b/Mage.Sets/src/mage/cards/w/WarCadence.java index 57c5707a1c..a3864feb41 100644 --- a/Mage.Sets/src/mage/cards/w/WarCadence.java +++ b/Mage.Sets/src/mage/cards/w/WarCadence.java @@ -44,7 +44,7 @@ public final class WarCadence extends CardImpl { class WarCadenceReplacementEffect extends ReplacementEffectImpl { - DynamicValue xCosts = new ManacostVariableValue(); + DynamicValue xCosts = ManacostVariableValue.instance; WarCadenceReplacementEffect() { super(Duration.EndOfTurn, Outcome.Neutral); diff --git a/Mage.Sets/src/mage/cards/w/WarElemental.java b/Mage.Sets/src/mage/cards/w/WarElemental.java index fd2aa63c26..08fdeccdaa 100644 --- a/Mage.Sets/src/mage/cards/w/WarElemental.java +++ b/Mage.Sets/src/mage/cards/w/WarElemental.java @@ -116,8 +116,8 @@ class OpponentWasDealtDamageCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get(BloodthirstWatcher.class.getSimpleName(), source.getControllerId()); - return watcher.conditionMet(); + BloodthirstWatcher watcher = game.getState().getWatcher(BloodthirstWatcher.class, source.getControllerId()); + return watcher != null && watcher.conditionMet(); } @Override diff --git a/Mage.Sets/src/mage/cards/w/WarFalcon.java b/Mage.Sets/src/mage/cards/w/WarFalcon.java index ab819388aa..e1fc9ba972 100644 --- a/Mage.Sets/src/mage/cards/w/WarFalcon.java +++ b/Mage.Sets/src/mage/cards/w/WarFalcon.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; @@ -19,14 +17,15 @@ import mage.filter.predicate.mageobject.SubtypePredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class WarFalcon extends CardImpl { public WarFalcon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}"); this.subtype.add(SubType.BIRD); this.power = new MageInt(2); @@ -34,7 +33,7 @@ public final class WarFalcon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - + // War Falcon can't attack unless you control a Knight or a Soldier. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WarFalconEffect())); } @@ -52,11 +51,11 @@ public final class WarFalcon extends CardImpl { class WarFalconEffect extends RestrictionEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("Knight or a Soldier"); - + static { filter.add(Predicates.or( - new SubtypePredicate(SubType.KNIGHT), - new SubtypePredicate(SubType.SOLDIER))); + new SubtypePredicate(SubType.KNIGHT), + new SubtypePredicate(SubType.SOLDIER))); } public WarFalconEffect() { @@ -74,17 +73,14 @@ class WarFalconEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent.getId().equals(source.getSourceId())) { - if (game.getBattlefield().countAll(filter, source.getControllerId(), game) > 0) { - return false; - } - return true; + return game.getBattlefield().countAll(filter, source.getControllerId(), game) <= 0; } // do not apply to other creatures. return false; } diff --git a/Mage.Sets/src/mage/cards/w/WarScreecher.java b/Mage.Sets/src/mage/cards/w/WarScreecher.java new file mode 100644 index 0000000000..cc39efb675 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarScreecher.java @@ -0,0 +1,49 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WarScreecher extends CardImpl { + + public WarScreecher(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); + + this.subtype.add(SubType.BIRD); + this.power = new MageInt(1); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // {5}{W}, {T}: Other creatures you control get +1/+1 until end of turn. + Ability ability = new SimpleActivatedAbility(new BoostControlledEffect( + 1, 1, Duration.EndOfTurn, true + ), new ManaCostsImpl("{5}{W}")); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); + } + + private WarScreecher(final WarScreecher card) { + super(card); + } + + @Override + public WarScreecher copy() { + return new WarScreecher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarTax.java b/Mage.Sets/src/mage/cards/w/WarTax.java index 3f9fb3cf9d..e9d14ff822 100644 --- a/Mage.Sets/src/mage/cards/w/WarTax.java +++ b/Mage.Sets/src/mage/cards/w/WarTax.java @@ -45,7 +45,7 @@ public final class WarTax extends CardImpl { class WarTaxCantAttackUnlessPaysEffect extends PayCostToAttackBlockEffectImpl { - DynamicValue xCosts = new ManacostVariableValue(); + DynamicValue xCosts = ManacostVariableValue.instance; WarTaxCantAttackUnlessPaysEffect() { super(Duration.EndOfTurn, Outcome.Neutral, RestrictType.ATTACK); diff --git a/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java b/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java index 9bd8284627..6e801451f6 100644 --- a/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java +++ b/Mage.Sets/src/mage/cards/w/WarbreakTrumpeter.java @@ -31,7 +31,7 @@ public final class WarbreakTrumpeter extends CardImpl { this.addAbility(new MorphAbility(this, new ManaCostsImpl("{X}{X}{R}"))); // When Warbreak Trumpeter is turned face up, create X 1/1 red Goblin creature tokens. - DynamicValue morphX = new MorphManacostVariableValue(); + DynamicValue morphX = MorphManacostVariableValue.instance; this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new CreateTokenEffect(new GoblinToken(), morphX))); } diff --git a/Mage.Sets/src/mage/cards/w/WardscaleCrocodile.java b/Mage.Sets/src/mage/cards/w/WardscaleCrocodile.java new file mode 100644 index 0000000000..86ecea9fd7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WardscaleCrocodile.java @@ -0,0 +1,36 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.keyword.HexproofAbility; +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 WardscaleCrocodile extends CardImpl { + + public WardscaleCrocodile(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G}"); + + this.subtype.add(SubType.CROCODILE); + this.power = new MageInt(5); + this.toughness = new MageInt(3); + + // Hexproof + this.addAbility(HexproofAbility.getInstance()); + } + + private WardscaleCrocodile(final WardscaleCrocodile card) { + super(card); + } + + @Override + public WardscaleCrocodile copy() { + return new WardscaleCrocodile(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java b/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java index 69721f930a..be42a91567 100644 --- a/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java +++ b/Mage.Sets/src/mage/cards/w/WarkiteMarauder.java @@ -26,7 +26,7 @@ public final class WarkiteMarauder extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature defending player controls"); static { - filter.add(new DefendingPlayerControlsPredicate()); + filter.add(DefendingPlayerControlsPredicate.instance); } public WarkiteMarauder(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WarleadersHelix.java b/Mage.Sets/src/mage/cards/w/WarleadersHelix.java index 77b2feb5dd..769228823d 100644 --- a/Mage.Sets/src/mage/cards/w/WarleadersHelix.java +++ b/Mage.Sets/src/mage/cards/w/WarleadersHelix.java @@ -4,6 +4,7 @@ package mage.cards.w; import java.util.ArrayList; import java.util.List; import java.util.UUID; + import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.GainLifeEffect; import mage.cards.CardImpl; @@ -12,18 +13,16 @@ import mage.constants.CardType; import mage.target.common.TargetAnyTarget; /** - * * @author jeffwadsworth */ public final class WarleadersHelix extends CardImpl { public WarleadersHelix(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{2}{R}{W}"); - + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{R}{W}"); // Warleader's Helix deals 4 damage to any target and you gain 4 life. this.getSpellAbility().addEffect(new DamageTargetEffect(4)); - this.getSpellAbility().addEffect(new GainLifeEffect(4)); + this.getSpellAbility().addEffect(new GainLifeEffect(4).setText("and you gain 4 life")); this.getSpellAbility().addTarget(new TargetAnyTarget()); } @@ -35,11 +34,4 @@ public final class WarleadersHelix extends CardImpl { public WarleadersHelix copy() { return new WarleadersHelix(this); } - - @Override - public List getRules() { - List rules = new ArrayList<>(); - rules.add("Warleader's Helix deals 4 damage to any target and you gain 4 life."); - return rules; - } } diff --git a/Mage.Sets/src/mage/cards/w/Warpath.java b/Mage.Sets/src/mage/cards/w/Warpath.java index d7a20a8b16..6839eb4045 100644 --- a/Mage.Sets/src/mage/cards/w/Warpath.java +++ b/Mage.Sets/src/mage/cards/w/Warpath.java @@ -21,8 +21,8 @@ public final class Warpath extends CardImpl { static { filter.add(Predicates.or( - new BlockingPredicate(), - new BlockedPredicate())); + BlockingPredicate.instance, + BlockedPredicate.instance)); } public Warpath(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WarpedPhysique.java b/Mage.Sets/src/mage/cards/w/WarpedPhysique.java index 9cfa58584c..2f1fb5588a 100644 --- a/Mage.Sets/src/mage/cards/w/WarpedPhysique.java +++ b/Mage.Sets/src/mage/cards/w/WarpedPhysique.java @@ -26,7 +26,7 @@ public final class WarpedPhysique extends CardImpl { // Target creature gets +X/-X until end of turn, where X is the number of cards in your hand. - DynamicValue xValue = new CardsInControllerHandCount(); + DynamicValue xValue = CardsInControllerHandCount.instance; this.getSpellAbility().addEffect(new BoostTargetEffect(xValue, new SignInversionDynamicValue(xValue), Duration.EndOfTurn, true)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); } diff --git a/Mage.Sets/src/mage/cards/w/WarpingWail.java b/Mage.Sets/src/mage/cards/w/WarpingWail.java index 8b17bc27ee..34be0129c0 100644 --- a/Mage.Sets/src/mage/cards/w/WarpingWail.java +++ b/Mage.Sets/src/mage/cards/w/WarpingWail.java @@ -48,15 +48,15 @@ public final class WarpingWail extends CardImpl { // Counter target sorcery spell. Mode mode = new Mode(); - mode.getEffects().add(new CounterTargetEffect()); - mode.getTargets().add(new TargetSpell(filterSorcery)); + mode.addEffect(new CounterTargetEffect()); + mode.addTarget(new TargetSpell(filterSorcery)); this.getSpellAbility().addMode(mode); // Create a 1/1 colorless Eldrazi Scion creature token. It has "Sacrifice this creature: Add {C}." mode = new Mode(); effect = new CreateTokenEffect(new EldraziScionToken()); effect.setText("Create a 1/1 colorless Eldrazi Scion creature token. It has \"Sacrifice this creature: Add {C}.\""); - mode.getEffects().add(effect); + mode.addEffect(effect); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/w/WarrantWarden.java b/Mage.Sets/src/mage/cards/w/WarrantWarden.java new file mode 100644 index 0000000000..f115a5cd53 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WarrantWarden.java @@ -0,0 +1,40 @@ +package mage.cards.w; + +import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.effects.common.PutOnLibraryTargetEffect; +import mage.cards.CardSetInfo; +import mage.cards.SplitCard; +import mage.constants.CardType; +import mage.constants.SpellAbilityType; +import mage.game.permanent.token.WardenSphinxToken; +import mage.target.common.TargetAttackingOrBlockingCreature; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class WarrantWarden extends SplitCard { + + public WarrantWarden(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, new CardType[]{CardType.SORCERY}, "{W/U}{W/U}", "{3}{W}{U}", SpellAbilityType.SPLIT); + + // Warrant + // Put target attacking or blocking creature on top of its owner’s library. + this.getLeftHalfCard().getSpellAbility().addEffect(new PutOnLibraryTargetEffect(true)); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetAttackingOrBlockingCreature()); + + // Warden + // Create a 4/4 white and blue Sphinx creature token with flying and vigilance. + this.getRightHalfCard().getSpellAbility().addEffect(new CreateTokenEffect(new WardenSphinxToken())); + } + + private WarrantWarden(final WarrantWarden card) { + super(card); + } + + @Override + public WarrantWarden copy() { + return new WarrantWarden(this); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WarrenWeirding.java b/Mage.Sets/src/mage/cards/w/WarrenWeirding.java index 2e341db538..f3b2a62a0b 100644 --- a/Mage.Sets/src/mage/cards/w/WarrenWeirding.java +++ b/Mage.Sets/src/mage/cards/w/WarrenWeirding.java @@ -2,6 +2,7 @@ package mage.cards.w; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; @@ -31,13 +32,12 @@ import mage.target.common.TargetControlledPermanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public final class WarrenWeirding extends CardImpl { public WarrenWeirding(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.TRIBAL,CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.TRIBAL, CardType.SORCERY}, "{1}{B}"); this.subtype.add(SubType.GOBLIN); @@ -64,19 +64,21 @@ class WarrenWeirdingEffect extends OneShotEffect { filterGoblin.add(new SubtypePredicate(SubType.GOBLIN)); } - WarrenWeirdingEffect ( ) { + WarrenWeirdingEffect() { super(Outcome.Sacrifice); staticText = "Target player sacrifices a creature. If a Goblin is sacrificed this way, that player creates two 1/1 black Goblin Rogue creature tokens, and those tokens gain haste until end of turn"; } - WarrenWeirdingEffect ( WarrenWeirdingEffect effect ) { + WarrenWeirdingEffect(WarrenWeirdingEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); - + if (player == null) { + return false; + } FilterControlledPermanent filter = new FilterControlledPermanent("creature"); filter.add(new CardTypePredicate(CardType.CREATURE)); filter.add(new ControllerIdPredicate(player.getId())); diff --git a/Mage.Sets/src/mage/cards/w/WarsToll.java b/Mage.Sets/src/mage/cards/w/WarsToll.java index 01972bac1a..5bff2466a0 100644 --- a/Mage.Sets/src/mage/cards/w/WarsToll.java +++ b/Mage.Sets/src/mage/cards/w/WarsToll.java @@ -1,4 +1,3 @@ - package mage.cards.w; import java.util.UUID; @@ -26,8 +25,8 @@ import mage.players.Player; */ public final class WarsToll extends CardImpl { - private final static FilterCreaturePermanent filterOpponentCreature = new FilterCreaturePermanent("creature an opponent controls"); - private final static FilterLandPermanent filterOpponentLand = new FilterLandPermanent("an opponent taps a land"); + private static final FilterCreaturePermanent filterOpponentCreature = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterLandPermanent filterOpponentLand = new FilterLandPermanent("an opponent taps a land"); static { filterOpponentCreature.add(new ControllerPredicate(TargetController.OPPONENT)); @@ -103,7 +102,9 @@ class WarsTollEffect extends OneShotEffect { filterOpponentCreatures.add(new ControllerIdPredicate(opponent.getId())); game.getBattlefield().getAllActivePermanents(CardType.CREATURE).stream().filter((permanent) -> (filterOpponentCreatures.match(permanent, source.getSourceId(), source.getControllerId(), game))).forEachOrdered((permanent) -> { //TODO: allow the player to choose between a planeswalker and player - opponent.declareAttacker(permanent.getId(), source.getControllerId(), game, false); + if (permanent.canAttack(source.getControllerId(), game)) { + opponent.declareAttacker(permanent.getId(), source.getControllerId(), game, false); + } }); return true; } diff --git a/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java b/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java index e0a7d80cc2..8f7cc44265 100644 --- a/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java +++ b/Mage.Sets/src/mage/cards/w/WatcherOfTheRoost.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCardInHand; */ public final class WatcherOfTheRoost extends CardImpl { - private final static FilterCard filter = new FilterCard("a white card in your hand"); + private static final FilterCard filter = new FilterCard("a white card in your hand"); static { filter.add(new ColorPredicate(ObjectColor.WHITE)); } diff --git a/Mage.Sets/src/mage/cards/w/WatchfulGiant.java b/Mage.Sets/src/mage/cards/w/WatchfulGiant.java new file mode 100644 index 0000000000..3fdac8a046 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WatchfulGiant.java @@ -0,0 +1,39 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.game.permanent.token.HumanToken; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WatchfulGiant extends CardImpl { + + public WatchfulGiant(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}"); + + this.subtype.add(SubType.GIANT); + this.subtype.add(SubType.SOLDIER); + this.power = new MageInt(3); + this.toughness = new MageInt(6); + + // When Watchful Giant enters the battlefield, create a 1/1 white Human creature token. + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new HumanToken()))); + } + + private WatchfulGiant(final WatchfulGiant card) { + super(card); + } + + @Override + public WatchfulGiant copy() { + return new WatchfulGiant(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WaterspoutDjinn.java b/Mage.Sets/src/mage/cards/w/WaterspoutDjinn.java index b657f59730..2ccd435cb4 100644 --- a/Mage.Sets/src/mage/cards/w/WaterspoutDjinn.java +++ b/Mage.Sets/src/mage/cards/w/WaterspoutDjinn.java @@ -28,7 +28,7 @@ public final class WaterspoutDjinn extends CardImpl { static{ filter.add(new SubtypePredicate(SubType.ISLAND)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public WaterspoutDjinn(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java b/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java index 9db272b67c..aac8ad647b 100644 --- a/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java +++ b/Mage.Sets/src/mage/cards/w/WaterspoutElemental.java @@ -26,7 +26,7 @@ public final class WaterspoutElemental extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("other creatures"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WaterspoutElemental(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WaveOfIndifference.java b/Mage.Sets/src/mage/cards/w/WaveOfIndifference.java index 5ca08c5737..2ba1c6f4aa 100644 --- a/Mage.Sets/src/mage/cards/w/WaveOfIndifference.java +++ b/Mage.Sets/src/mage/cards/w/WaveOfIndifference.java @@ -1,21 +1,20 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.combat.CantBlockTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; -import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author emerald000 */ public final class WaveOfIndifference extends CardImpl { @@ -27,23 +26,25 @@ public final class WaveOfIndifference extends CardImpl { Effect effect = new CantBlockTargetEffect(Duration.EndOfTurn); effect.setText("X target creatures can't block this turn"); this.getSpellAbility().addEffect(effect); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE, false)); + this.getSpellAbility().setTargetAdjuster(WaveOfIndifferenceAdjuster.instance); } public WaveOfIndifference(final WaveOfIndifference card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); - } - } - @Override public WaveOfIndifference copy() { return new WaveOfIndifference(this); } } + +enum WaveOfIndifferenceAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WaveOfVitriol.java b/Mage.Sets/src/mage/cards/w/WaveOfVitriol.java index e29fbc5056..5b223ec862 100644 --- a/Mage.Sets/src/mage/cards/w/WaveOfVitriol.java +++ b/Mage.Sets/src/mage/cards/w/WaveOfVitriol.java @@ -100,7 +100,7 @@ class WaveOfVitriolEffect extends OneShotEffect { for (Map.Entry entry : sacrificedLands.entrySet()) { if (entry.getKey().chooseUse(Outcome.PutLandInPlay, "Search your library for up to " + entry.getValue() + " basic lands?", source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(0, entry.getValue(), StaticFilters.FILTER_CARD_BASIC_LAND); - if (entry.getKey().searchLibrary(target, game)) { + if (entry.getKey().searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { toBattlefield.addAll(target.getTargets()); playersToShuffle.add(entry.getKey()); diff --git a/Mage.Sets/src/mage/cards/w/WaxingMoon.java b/Mage.Sets/src/mage/cards/w/WaxingMoon.java index 7663d5fc9e..f23908c3bf 100644 --- a/Mage.Sets/src/mage/cards/w/WaxingMoon.java +++ b/Mage.Sets/src/mage/cards/w/WaxingMoon.java @@ -24,7 +24,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class WaxingMoon extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("Werewolf you control"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Werewolf you control"); static { filter.add(new SubtypePredicate(SubType.WEREWOLF)); diff --git a/Mage.Sets/src/mage/cards/w/WayfaringTemple.java b/Mage.Sets/src/mage/cards/w/WayfaringTemple.java index 77fc984065..ea77f210e9 100644 --- a/Mage.Sets/src/mage/cards/w/WayfaringTemple.java +++ b/Mage.Sets/src/mage/cards/w/WayfaringTemple.java @@ -1,37 +1,36 @@ - - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.PopulateEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class WayfaringTemple extends CardImpl { public WayfaringTemple(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}{W}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}{W}"); this.subtype.add(SubType.ELEMENTAL); this.power = new MageInt(0); this.toughness = new MageInt(0); // Wayfaring Temple's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + this.addAbility(new SimpleStaticAbility(Zone.ALL, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.EndOfGame)) + .addHint(CreaturesYouControlHint.instance)); // Whenever Wayfaring Temple deals combat damage to a player, populate. (Create a token that's a copy of a creature token you control.) this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new PopulateEffect(), false)); diff --git a/Mage.Sets/src/mage/cards/w/WaywardServant.java b/Mage.Sets/src/mage/cards/w/WaywardServant.java index a2ab801050..19a4b2ab1f 100644 --- a/Mage.Sets/src/mage/cards/w/WaywardServant.java +++ b/Mage.Sets/src/mage/cards/w/WaywardServant.java @@ -26,7 +26,7 @@ public final class WaywardServant extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private static final String rule = "Whenever another Zombie enters the battlefield under your control, each opponent loses 1 life and you gain 1 life."; diff --git a/Mage.Sets/src/mage/cards/w/WaywardSwordtooth.java b/Mage.Sets/src/mage/cards/w/WaywardSwordtooth.java index f26adf2969..d73baa3b7c 100644 --- a/Mage.Sets/src/mage/cards/w/WaywardSwordtooth.java +++ b/Mage.Sets/src/mage/cards/w/WaywardSwordtooth.java @@ -1,12 +1,11 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.condition.common.CitysBlessingCondition; import mage.abilities.effects.common.combat.CantAttackBlockUnlessConditionSourceEffect; import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect; +import mage.abilities.hint.common.CitysBlessingHint; import mage.abilities.keyword.AscendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -15,8 +14,9 @@ import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class WaywardSwordtooth extends CardImpl { @@ -36,8 +36,9 @@ public final class WaywardSwordtooth extends CardImpl { new PlayAdditionalLandsControllerEffect(1, Duration.WhileOnBattlefield))); // Wayward Sawtooth can't attack or block unless you have the city's blessing. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessConditionSourceEffect(CitysBlessingCondition.instance))); - + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantAttackBlockUnlessConditionSourceEffect(CitysBlessingCondition.instance)) + .addHint(CitysBlessingHint.instance) + ); } public WaywardSwordtooth(final WaywardSwordtooth card) { diff --git a/Mage.Sets/src/mage/cards/w/Weakstone.java b/Mage.Sets/src/mage/cards/w/Weakstone.java index 7bb3a10a78..e1a1b16be7 100644 --- a/Mage.Sets/src/mage/cards/w/Weakstone.java +++ b/Mage.Sets/src/mage/cards/w/Weakstone.java @@ -21,7 +21,7 @@ public final class Weakstone extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creatures"); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public Weakstone(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/Weatherlight.java b/Mage.Sets/src/mage/cards/w/Weatherlight.java index 3c55c668ae..64498880c3 100644 --- a/Mage.Sets/src/mage/cards/w/Weatherlight.java +++ b/Mage.Sets/src/mage/cards/w/Weatherlight.java @@ -1,24 +1,24 @@ package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.common.LookLibraryAndPickControllerEffect; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.CrewAbility; +import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.mageobject.HistoricPredicate; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class Weatherlight extends CardImpl { @@ -26,7 +26,7 @@ public final class Weatherlight extends CardImpl { private static final FilterCard filter = new FilterCard("a historic card"); static { - filter.add(new HistoricPredicate()); + filter.add(HistoricPredicate.instance); } public Weatherlight(UUID ownerId, CardSetInfo setInfo) { @@ -44,9 +44,11 @@ public final class Weatherlight extends CardImpl { this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility( new LookLibraryAndPickControllerEffect( new StaticValue(5), false, new StaticValue(1), filter, - Zone.LIBRARY, false, true, false, Zone.HAND, true, false, false - ), false + Zone.LIBRARY, false, true, false, Zone.HAND, + true, false, false + ).setBackInRandomOrder(true), false )); + // Crew 3 this.addAbility(new CrewAbility(3)); } diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java index 4dbfaad5ca..f306ff9c23 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfLies.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLies.java @@ -34,7 +34,7 @@ public final class WeaverOfLies extends CardImpl { static { filter.add(new AbilityPredicate(MorphAbility.class)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WeaverOfLies(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java b/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java index 8c5701f97b..818e403853 100644 --- a/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java +++ b/Mage.Sets/src/mage/cards/w/WeaverOfLightning.java @@ -23,7 +23,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class WeaverOfLightning extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/w/WebOfInertia.java b/Mage.Sets/src/mage/cards/w/WebOfInertia.java index 6739e5cf82..edaf46afe0 100644 --- a/Mage.Sets/src/mage/cards/w/WebOfInertia.java +++ b/Mage.Sets/src/mage/cards/w/WebOfInertia.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -12,18 +10,15 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; +import java.util.UUID; + /** - * * @author Styxo */ public final class WebOfInertia extends CardImpl { @@ -109,7 +104,10 @@ class WebOfInertiaRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } return !defenderId.equals(source.getControllerId()); } diff --git a/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java b/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java index af4efb00d1..b5a3dd962a 100644 --- a/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java +++ b/Mage.Sets/src/mage/cards/w/WeedPrunerPoplar.java @@ -25,7 +25,7 @@ public final class WeedPrunerPoplar extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature other than {this}"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WeedPrunerPoplar(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java index 43706f2580..815d0bee3d 100644 --- a/Mage.Sets/src/mage/cards/w/WeightOfConscience.java +++ b/Mage.Sets/src/mage/cards/w/WeightOfConscience.java @@ -94,7 +94,7 @@ class WeightOfConscienceTarget extends TargetControlledCreaturePermanent { private static final FilterControlledCreaturePermanent filterUntapped = new FilterControlledCreaturePermanent("untapped creatures you control that share a creature type"); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } WeightOfConscienceTarget() { diff --git a/Mage.Sets/src/mage/cards/w/WeirdHarvest.java b/Mage.Sets/src/mage/cards/w/WeirdHarvest.java index 4ee86327ac..ca1fa3a86f 100644 --- a/Mage.Sets/src/mage/cards/w/WeirdHarvest.java +++ b/Mage.Sets/src/mage/cards/w/WeirdHarvest.java @@ -88,7 +88,7 @@ class WeirdHarvestEffect extends OneShotEffect { if (player.chooseUse(Outcome.PutCardInPlay, "Search your library for up " + xValue + " creature cards and put them into your hand?", source, game)) { usingPlayers.add(player); TargetCardInLibrary target = new TargetCardInLibrary(0, xValue, new FilterCreatureCard()); - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(target.getTargets()); player.moveCards(cards, Zone.HAND, source, game); diff --git a/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java b/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java index ee3002f48b..e80ae567a6 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java +++ b/Mage.Sets/src/mage/cards/w/WellOfDiscovery.java @@ -24,7 +24,7 @@ public final class WellOfDiscovery extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public WellOfDiscovery(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WellOfLife.java b/Mage.Sets/src/mage/cards/w/WellOfLife.java index 775e1a02fd..c1e0f48441 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfLife.java +++ b/Mage.Sets/src/mage/cards/w/WellOfLife.java @@ -24,7 +24,7 @@ public final class WellOfLife extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public WellOfLife(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java b/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java index 897677bdf6..523c6df0cd 100644 --- a/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java +++ b/Mage.Sets/src/mage/cards/w/WellOfLostDreams.java @@ -61,7 +61,7 @@ class WellOfLostDreamsEffect extends OneShotEffect { int xValue = controller.announceXMana(0, amount, "Announce X Value", game, source); if (xValue > 0) { if (new GenericManaCost(xValue).pay(source, game, source.getSourceId(), controller.getId(), false)) { - game.informPlayers(new StringBuilder(controller.getLogName()).append(" payed {").append(xValue).append('}').toString()); + game.informPlayers(controller.getLogName() + " payed {" + xValue + '}'); controller.drawCards(xValue, game); } else { return false; diff --git a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java index edd0537a12..26800c0af0 100644 --- a/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java +++ b/Mage.Sets/src/mage/cards/w/WellgabberApothecary.java @@ -27,7 +27,7 @@ public final class WellgabberApothecary extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("target tapped Merfolk or Kithkin creature this turn"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); filter.add(Predicates.or(new SubtypePredicate(SubType.MERFOLK), new SubtypePredicate(SubType.KITHKIN))); } diff --git a/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java b/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java index b7df1697b4..61bdd50855 100644 --- a/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java +++ b/Mage.Sets/src/mage/cards/w/WerewolfOfAncientHunger.java @@ -48,7 +48,7 @@ public final class WerewolfOfAncientHunger extends CardImpl { // Werewolf of Ancient Hunger's power and toughness are each equal to the total number of cards in all players' hands. this.addAbility(new SimpleStaticAbility(Zone.ALL, - new ConditionalContinuousEffect(new SetPowerToughnessSourceEffect(new CardsInAllHandsCount(), Duration.EndOfGame), + new ConditionalContinuousEffect(new SetPowerToughnessSourceEffect(CardsInAllHandsCount.instance, Duration.EndOfGame), new TransformedCondition(false), "{this}'s power and toughness are each equal to the total number of cards in all players' hands"))); // At the beginning of each upkeep, if a player cast two or more spells last turn, transform Werewolf of Ancient Hunger. diff --git a/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java b/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java index 183b957665..64d5b69701 100644 --- a/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java +++ b/Mage.Sets/src/mage/cards/w/WestvaleCultLeader.java @@ -1,31 +1,24 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.BeginningOfEndStepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.TargetController; -import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.constants.*; import mage.game.permanent.token.HumanClericToken; +import java.util.UUID; + /** - * * @author fireshoes */ public final class WestvaleCultLeader extends CardImpl { - final private static FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control"); - public WestvaleCultLeader(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, ""); this.subtype.add(SubType.HUMAN); @@ -38,7 +31,8 @@ public final class WestvaleCultLeader extends CardImpl { this.nightCard = true; // Westvale Cult Leader's power and toughness are each equal to the number of creatures you control. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(new PermanentsOnBattlefieldCount(filter), Duration.WhileOnBattlefield))); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect(CreaturesYouControlCount.instance, Duration.WhileOnBattlefield)) + .addHint(CreaturesYouControlHint.instance)); // At the beginning of your end step, create a 1/1 white and black Human Cleric creature token. this.addAbility(new BeginningOfEndStepTriggeredAbility(new CreateTokenEffect(new HumanClericToken()), TargetController.YOU, false)); diff --git a/Mage.Sets/src/mage/cards/w/Whetwheel.java b/Mage.Sets/src/mage/cards/w/Whetwheel.java index bb37398d79..cc09655c80 100644 --- a/Mage.Sets/src/mage/cards/w/Whetwheel.java +++ b/Mage.Sets/src/mage/cards/w/Whetwheel.java @@ -26,7 +26,7 @@ public final class Whetwheel extends CardImpl { // {X}{X}, {tap}: Target player puts the top X cards of their library into their graveyard. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new PutLibraryIntoGraveTargetEffect( - new ManacostVariableValue()), new ManaCostsImpl("{X}{X}")); + ManacostVariableValue.instance), new ManaCostsImpl("{X}{X}")); ability.addCost(new TapSourceCost()); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java b/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java index b9334276a7..3f1006ece9 100644 --- a/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java +++ b/Mage.Sets/src/mage/cards/w/WhimsOfTheFates.java @@ -95,7 +95,7 @@ class WhimsOfTheFateEffect extends OneShotEffect { playerPermanents.put(currentPlayer.getId(), playerPiles); for (int i = 1; i < 3; i++) { FilterPermanent filter = new FilterPermanent( - new StringBuilder("the permanents for the ").append(i == 1 ? "first " : "second ").append("pile").toString()); + "the permanents for the " + (i == 1 ? "first " : "second ") + "pile"); filter.add(new ControllerIdPredicate(currentPlayer.getId())); Target target; if (i == 1) { @@ -141,7 +141,7 @@ class WhimsOfTheFateEffect extends OneShotEffect { if (player != null) { // decide which pile to sacrifice int sacrificePile = RandomUtil.nextInt(3) + 1; // random number from 1 - 3 - game.informPlayers(new StringBuilder(player.getLogName()).append(" sacrifices pile number ").append(sacrificePile).toString()); + game.informPlayers(player.getLogName() + " sacrifices pile number " + sacrificePile); for (UUID permanentId : playerPiles.getValue().get(sacrificePile)) { Permanent permanent = game.getPermanent(permanentId); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/w/WhiplashTrap.java b/Mage.Sets/src/mage/cards/w/WhiplashTrap.java index 0abe74629c..26be4131c9 100644 --- a/Mage.Sets/src/mage/cards/w/WhiplashTrap.java +++ b/Mage.Sets/src/mage/cards/w/WhiplashTrap.java @@ -52,7 +52,7 @@ enum WhiplashTrapCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PermanentsEnteredBattlefieldWatcher watcher = (PermanentsEnteredBattlefieldWatcher) game.getState().getWatchers().get(PermanentsEnteredBattlefieldWatcher.class.getSimpleName()); + PermanentsEnteredBattlefieldWatcher watcher = game.getState().getWatcher(PermanentsEnteredBattlefieldWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { List permanents = watcher.getThisTurnEnteringPermanents(opponentId); diff --git a/Mage.Sets/src/mage/cards/w/WhispererOfTheWilds.java b/Mage.Sets/src/mage/cards/w/WhispererOfTheWilds.java index b0191ab4b1..e461dc01ec 100644 --- a/Mage.Sets/src/mage/cards/w/WhispererOfTheWilds.java +++ b/Mage.Sets/src/mage/cards/w/WhispererOfTheWilds.java @@ -1,13 +1,12 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageInt; import mage.Mana; import mage.abilities.Ability; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.mana.BasicManaEffect; +import mage.abilities.hint.common.FerociousHint; import mage.abilities.mana.ActivateIfConditionManaAbility; import mage.abilities.mana.GreenManaAbility; import mage.cards.CardImpl; @@ -17,14 +16,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class WhispererOfTheWilds extends CardImpl { public WhispererOfTheWilds(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SHAMAN); this.power = new MageInt(0); @@ -36,6 +36,7 @@ public final class WhispererOfTheWilds extends CardImpl { // Ferocious - {T}: Add {G}{G}. Activate this ability only if you control a creature with power 4 or greater. Ability ability = new ActivateIfConditionManaAbility(Zone.BATTLEFIELD, new BasicManaEffect(Mana.GreenMana(2)), new TapSourceCost(), FerociousCondition.instance); ability.setAbilityWord(AbilityWord.FEROCIOUS); + ability.addHint(FerociousHint.instance); this.addAbility(ability); } diff --git a/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java b/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java index c28daf0841..3452d35243 100644 --- a/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java +++ b/Mage.Sets/src/mage/cards/w/WhisperingSnitch.java @@ -7,10 +7,10 @@ import mage.MageInt; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.common.DamagePlayersEffect; import mage.abilities.effects.common.GainLifeEffect; -import mage.constants.SubType; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.TargetController; import mage.constants.WatcherScope; import mage.constants.Zone; @@ -65,8 +65,11 @@ class WhisperingSnitchTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - WhisperingSnitchWatcher watcher = (WhisperingSnitchWatcher) game.getState().getWatchers().get(WhisperingSnitchWatcher.class.getSimpleName()); - return watcher != null && watcher.getTimesSurveiled(getControllerId()) == 1; + if (event.getPlayerId().equals(getControllerId())) { + WhisperingSnitchWatcher watcher = game.getState().getWatcher(WhisperingSnitchWatcher.class); + return watcher != null && watcher.getTimesSurveiled(getControllerId()) == 1; + } + return false; } @Override @@ -86,7 +89,7 @@ class WhisperingSnitchWatcher extends Watcher { private final Map timesSurveiled = new HashMap<>(); public WhisperingSnitchWatcher() { - super(WhisperingSnitchWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public WhisperingSnitchWatcher(final WhisperingSnitchWatcher watcher) { diff --git a/Mage.Sets/src/mage/cards/w/WhispersOfEmrakul.java b/Mage.Sets/src/mage/cards/w/WhispersOfEmrakul.java index b59ced4419..235e325f95 100644 --- a/Mage.Sets/src/mage/cards/w/WhispersOfEmrakul.java +++ b/Mage.Sets/src/mage/cards/w/WhispersOfEmrakul.java @@ -1,24 +1,24 @@ - package mage.cards.w; import java.util.UUID; + import mage.abilities.condition.InvertCondition; import mage.abilities.condition.common.DeliriumCondition; import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.effects.common.discard.DiscardTargetEffect; +import mage.abilities.hint.common.DeliriumHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetOpponent; /** - * * @author fireshoes */ public final class WhispersOfEmrakul extends CardImpl { public WhispersOfEmrakul(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{1}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}"); // Target opponent discards a card at random. this.getSpellAbility().addEffect(new ConditionalOneShotEffect( @@ -32,6 +32,7 @@ public final class WhispersOfEmrakul extends CardImpl { DeliriumCondition.instance, "
    Delirium — If there are four or more card types among cards in your graveyard, that player discards two cards at random instead")); this.getSpellAbility().addTarget(new TargetOpponent()); + this.getSpellAbility().addHint(DeliriumHint.instance); } public WhispersOfEmrakul(final WhispersOfEmrakul card) { diff --git a/Mage.Sets/src/mage/cards/w/WhisperwoodElemental.java b/Mage.Sets/src/mage/cards/w/WhisperwoodElemental.java index ca07645b87..52b1ca830c 100644 --- a/Mage.Sets/src/mage/cards/w/WhisperwoodElemental.java +++ b/Mage.Sets/src/mage/cards/w/WhisperwoodElemental.java @@ -32,8 +32,8 @@ public final class WhisperwoodElemental extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("face-up, nontoken creatures you control"); static { - filter.add(Predicates.not(new FaceDownPredicate())); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(FaceDownPredicate.instance)); + filter.add(Predicates.not(TokenPredicate.instance)); } public WhisperwoodElemental(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WhiteManaBattery.java b/Mage.Sets/src/mage/cards/w/WhiteManaBattery.java index d5d28212bb..b08a197b18 100644 --- a/Mage.Sets/src/mage/cards/w/WhiteManaBattery.java +++ b/Mage.Sets/src/mage/cards/w/WhiteManaBattery.java @@ -36,7 +36,7 @@ public final class WhiteManaBattery extends CardImpl { // {tap}, Remove any number of charge counters from White Mana Battery: Add {W}, then add an additional {W} for each charge counter removed this way. ability = new DynamicManaAbility( Mana.WhiteMana(1), - new IntPlusDynamicValue(1, new RemovedCountersForCostValue()), + new IntPlusDynamicValue(1, RemovedCountersForCostValue.instance), new TapSourceCost(), "Add {W}, then add {W} for each charge counter removed this way", true, new CountersSourceCount(CounterType.CHARGE)); diff --git a/Mage.Sets/src/mage/cards/w/WhiteSunsZenith.java b/Mage.Sets/src/mage/cards/w/WhiteSunsZenith.java index b13069cf27..772562ec28 100644 --- a/Mage.Sets/src/mage/cards/w/WhiteSunsZenith.java +++ b/Mage.Sets/src/mage/cards/w/WhiteSunsZenith.java @@ -20,7 +20,7 @@ public final class WhiteSunsZenith extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{W}{W}{W}"); // create X 2/2 white Cat creature tokens. Shuffle White Sun's Zenith into its owner's library. - this.getSpellAbility().addEffect(new CreateTokenEffect(new CatToken(), new ManacostVariableValue())); + this.getSpellAbility().addEffect(new CreateTokenEffect(new CatToken(), ManacostVariableValue.instance)); this.getSpellAbility().addEffect(ShuffleSpellEffect.getInstance()); } diff --git a/Mage.Sets/src/mage/cards/w/WickedAkuba.java b/Mage.Sets/src/mage/cards/w/WickedAkuba.java index 5b430956d8..48ca347de7 100644 --- a/Mage.Sets/src/mage/cards/w/WickedAkuba.java +++ b/Mage.Sets/src/mage/cards/w/WickedAkuba.java @@ -60,7 +60,7 @@ class WickedAkubaPredicate implements ObjectSourcePlayerPredicate input, Game game) { - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), input.getObject().getId()); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, input.getObject().getId()); if (watcher != null) { return watcher.hasSourceDoneDamage(input.getSourceId(), game); } diff --git a/Mage.Sets/src/mage/cards/w/WidespreadBrutality.java b/Mage.Sets/src/mage/cards/w/WidespreadBrutality.java new file mode 100644 index 0000000000..b6dd33e1fb --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WidespreadBrutality.java @@ -0,0 +1,73 @@ +package mage.cards.w; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.keyword.AmassEffect; +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 java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WidespreadBrutality extends CardImpl { + + public WidespreadBrutality(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{B}{R}{R}"); + + // Amass 2, then the Army you amassed deals damage equal to its power to each non-Army creature. + this.getSpellAbility().addEffect(new WidespreadBrutalityEffect()); + } + + private WidespreadBrutality(final WidespreadBrutality card) { + super(card); + } + + @Override + public WidespreadBrutality copy() { + return new WidespreadBrutality(this); + } +} + +class WidespreadBrutalityEffect extends OneShotEffect { + + WidespreadBrutalityEffect() { + super(Outcome.Benefit); + staticText = "Amass 2, then the Army you amassed deals damage equal to its power to each non-Army creature. " + + "(To amass 2, put two +1/+1 counters on an Army you control. " + + "If you don’t control one, create a 0/0 black Zombie Army creature token first.)"; + } + + private WidespreadBrutalityEffect(final WidespreadBrutalityEffect effect) { + super(effect); + } + + @Override + public WidespreadBrutalityEffect copy() { + return new WidespreadBrutalityEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + AmassEffect amassEffect = new AmassEffect(2); + amassEffect.apply(game, source); + Permanent amassedArmy = game.getPermanent(amassEffect.getAmassedCreatureId()); + if (amassedArmy == null) { + return false; + } + game.applyEffects(); + int power = amassedArmy.getPower().getValue(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { + if (permanent != null && permanent.isCreature() && !permanent.hasSubtype(SubType.ARMY, game)) { + permanent.damage(power, amassedArmy.getId(), game); + } + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WidespreadPanic.java b/Mage.Sets/src/mage/cards/w/WidespreadPanic.java index 22778340ac..5191dd05c3 100644 --- a/Mage.Sets/src/mage/cards/w/WidespreadPanic.java +++ b/Mage.Sets/src/mage/cards/w/WidespreadPanic.java @@ -75,7 +75,7 @@ class WidespreadPanicTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever a spell or ability causes its controller to shuffle their library, ").append(super.getRule()).toString(); + return "Whenever a spell or ability causes its controller to shuffle their library, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/w/Wiitigo.java b/Mage.Sets/src/mage/cards/w/Wiitigo.java new file mode 100644 index 0000000000..7493405c22 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/Wiitigo.java @@ -0,0 +1,136 @@ +package mage.cards.w; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import mage.MageInt; +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.EntersBattlefieldAbility; +import mage.abilities.condition.Condition; +import mage.abilities.decorator.ConditionalOneShotEffect; +import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; +import mage.constants.SubType; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.WatcherScope; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + +/** + * + * @author jeffwadsworth + */ +public final class Wiitigo extends CardImpl { + + public Wiitigo(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}{G}{G}"); + + this.subtype.add(SubType.YETI); + this.power = new MageInt(0); + this.toughness = new MageInt(0); + + // Wiitigo enters the battlefield with six +1/+1 counters on it. + this.addAbility(new EntersBattlefieldAbility( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(6)))); + + // At the beginning of your upkeep, put a +1/+1 counter on Wiitigo if it has blocked or been blocked since your last upkeep. Otherwise, remove a +1/+1 counter from it. + Ability triggeredAbility = new BeginningOfUpkeepTriggeredAbility( + new ConditionalOneShotEffect( + new AddCountersSourceEffect(CounterType.P1P1.createInstance(1)), + new RemoveCounterSourceEffect(CounterType.P1P1.createInstance(1)), + new BlockedOrBeenBlockedSinceYourLastUpkeepCondition(), + "put a +1/+1 counter on enchanted creature if it blocked or been blocked since your last " + + "upkeep. Otherwise, remove a +1/+1 counter from it"), + TargetController.YOU, + false); + triggeredAbility.addWatcher(new BlockedOrBeenBlockedSinceYourLastUpkeepWatcher()); + this.addAbility(triggeredAbility); + } + + private Wiitigo(final Wiitigo card) { + super(card); + } + + @Override + public Wiitigo copy() { + return new Wiitigo(this); + } +} + +class BlockedOrBeenBlockedSinceYourLastUpkeepCondition implements Condition { + + @Override + public boolean apply(Game game, Ability source) { + Permanent wiitigo = game.getBattlefield().getPermanent(source.getSourceId()); + BlockedOrBeenBlockedSinceYourLastUpkeepWatcher watcher = game.getState().getWatcher( + BlockedOrBeenBlockedSinceYourLastUpkeepWatcher.class); + if (wiitigo != null + && watcher != null) { + return watcher.blockedOrBeenBlockedSinceLastUpkeep( + new MageObjectReference(wiitigo.getId(), + wiitigo.getZoneChangeCounter(game), + game), + wiitigo.getControllerId()); + } + return false; + } + + @Override + public String toString() { + return "it blocked or was blocked since your last upkeep"; + } +} + +class BlockedOrBeenBlockedSinceYourLastUpkeepWatcher extends Watcher { + + private final Map> blockedOrBeenBlockedCreatures = new HashMap<>(); + + public BlockedOrBeenBlockedSinceYourLastUpkeepWatcher() { + super(WatcherScope.GAME); + } + + public BlockedOrBeenBlockedSinceYourLastUpkeepWatcher(BlockedOrBeenBlockedSinceYourLastUpkeepWatcher watcher) { + super(watcher); + for (Map.Entry> entry : watcher.blockedOrBeenBlockedCreatures.entrySet()) { + Set creaturesThatBlockedOrWereBlocked = new HashSet<>(entry.getValue()); + blockedOrBeenBlockedCreatures.put(entry.getKey(), creaturesThatBlockedOrWereBlocked); + } + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.UPKEEP_STEP_POST) { + blockedOrBeenBlockedCreatures.put(event.getPlayerId(), new HashSet<>()); // clear the watcher after upkeep + } else if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { + MageObjectReference morBlocker = new MageObjectReference(event.getSourceId(), game); // store blocker + MageObjectReference morAttackerBlocked = new MageObjectReference(event.getTargetId(), game); // store attacker blocked + for (UUID player : game.getPlayerList()) { + if (!blockedOrBeenBlockedCreatures.containsKey(player)) { + blockedOrBeenBlockedCreatures.put(player, new HashSet<>()); + } + blockedOrBeenBlockedCreatures.get(player).add(morBlocker); + blockedOrBeenBlockedCreatures.get(player).add(morAttackerBlocked); + } + } + } + + public boolean blockedOrBeenBlockedSinceLastUpkeep(MageObjectReference mor, UUID player) { + return (blockedOrBeenBlockedCreatures.get(player) != null) + && blockedOrBeenBlockedCreatures.get(player).contains(mor); + } + + @Override + public BlockedOrBeenBlockedSinceYourLastUpkeepWatcher copy() { + return new BlockedOrBeenBlockedSinceYourLastUpkeepWatcher(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildEvocation.java b/Mage.Sets/src/mage/cards/w/WildEvocation.java index 3278c01842..76ece70c23 100644 --- a/Mage.Sets/src/mage/cards/w/WildEvocation.java +++ b/Mage.Sets/src/mage/cards/w/WildEvocation.java @@ -64,8 +64,7 @@ class WildEvocationEffect extends OneShotEffect { if (player != null && sourceObject != null) { Card card = player.getHand().getRandom(game); if (card != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); player.revealCards(sourceObject.getIdName() + " Turn: " + game.getTurnNum(), cards, game); if (card.isLand()) { player.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/w/WildInstincts.java b/Mage.Sets/src/mage/cards/w/WildInstincts.java index cf6c797b69..7f9d727248 100644 --- a/Mage.Sets/src/mage/cards/w/WildInstincts.java +++ b/Mage.Sets/src/mage/cards/w/WildInstincts.java @@ -21,7 +21,7 @@ import mage.target.common.TargetCreaturePermanent; */ public final class WildInstincts extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls"); static { filter.add(new ControllerPredicate(TargetController.OPPONENT)); diff --git a/Mage.Sets/src/mage/cards/w/WildPair.java b/Mage.Sets/src/mage/cards/w/WildPair.java index ee5d269b22..6349ee4aed 100644 --- a/Mage.Sets/src/mage/cards/w/WildPair.java +++ b/Mage.Sets/src/mage/cards/w/WildPair.java @@ -29,7 +29,7 @@ import mage.watchers.common.CastFromHandWatcher; */ public final class WildPair extends CardImpl { - private final static FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a creature"); static { filter.add(new OwnerPredicate(TargetController.YOU)); @@ -82,7 +82,7 @@ class WildPairEffect extends OneShotEffect { FilterCreatureCard filter = new FilterCreatureCard("creature card with total power and toughness " + totalPT); filter.add(new TotalPowerAndToughnessPredicate(ComparisonType.EQUAL_TO, totalPT)); TargetCardInLibrary target = new TargetCardInLibrary(1, filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game); } @@ -135,7 +135,7 @@ class CastFromHandTargetCondition implements Condition { return false; } } - CastFromHandWatcher watcher = (CastFromHandWatcher) game.getState().getWatchers().get(CastFromHandWatcher.class.getSimpleName()); + CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); if (watcher != null && watcher.spellWasCastFromHand(targetId)) { return true; } diff --git a/Mage.Sets/src/mage/cards/w/WildResearch.java b/Mage.Sets/src/mage/cards/w/WildResearch.java index 44a6450c41..2eb4936c37 100644 --- a/Mage.Sets/src/mage/cards/w/WildResearch.java +++ b/Mage.Sets/src/mage/cards/w/WildResearch.java @@ -82,13 +82,12 @@ class WildResearchEffect extends OneShotEffect { MageObject sourceObject = game.getObject(source.getSourceId()); if (controller != null && sourceObject != null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().remove(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.HAND, source, game); - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.revealCards(sourceObject.getIdName(), cards, game, true); } } diff --git a/Mage.Sets/src/mage/cards/w/WildSlash.java b/Mage.Sets/src/mage/cards/w/WildSlash.java index 6917455ff6..f02f96a0bf 100644 --- a/Mage.Sets/src/mage/cards/w/WildSlash.java +++ b/Mage.Sets/src/mage/cards/w/WildSlash.java @@ -1,33 +1,34 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalContinuousRuleModifyingEffect; import mage.abilities.effects.ContinuousRuleModifyingEffect; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.continuous.DamageCantBePreventedEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Duration; import mage.target.common.TargetAnyTarget; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class WildSlash extends CardImpl { public WildSlash(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{R}"); // Ferocious If you control a creature with power 4 or greater, damage can't be prevented this turn. ContinuousRuleModifyingEffect effect = new DamageCantBePreventedEffect(Duration.EndOfTurn, "damage can't be prevented this turn", false, false); effect.setText("Ferocious — If you control a creature with power 4 or greater, damage can't be prevented this turn.
    "); this.getSpellAbility().addEffect(new ConditionalContinuousRuleModifyingEffect(effect, new LockedInCondition(FerociousCondition.instance))); + this.getSpellAbility().addHint(FerociousHint.instance); // Wild Slash deals 2 damage to any target. this.getSpellAbility().addEffect(new DamageTargetEffect(2)); diff --git a/Mage.Sets/src/mage/cards/w/WildWurm.java b/Mage.Sets/src/mage/cards/w/WildWurm.java index 84ee670948..c56dee1803 100644 --- a/Mage.Sets/src/mage/cards/w/WildWurm.java +++ b/Mage.Sets/src/mage/cards/w/WildWurm.java @@ -58,7 +58,7 @@ class WildWurmEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent permanent = game.getPermanent(source.getSourceId()); if (controller != null && permanent != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { return true; } else { new ReturnToHandSourceEffect().apply(game, source); diff --git a/Mage.Sets/src/mage/cards/w/WildernessReclamation.java b/Mage.Sets/src/mage/cards/w/WildernessReclamation.java new file mode 100644 index 0000000000..b15ee0e26f --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WildernessReclamation.java @@ -0,0 +1,36 @@ +package mage.cards.w; + +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.UntapAllControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.filter.StaticFilters; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class WildernessReclamation extends CardImpl { + + public WildernessReclamation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); + + // At the beginning of your end step, untap all lands you control. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new UntapAllControllerEffect(StaticFilters.FILTER_LANDS), + TargetController.YOU, false + )); + } + + private WildernessReclamation(final WildernessReclamation card) { + super(card); + } + + @Override + public WildernessReclamation copy() { + return new WildernessReclamation(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WildestDreams.java b/Mage.Sets/src/mage/cards/w/WildestDreams.java index c1623d2fe5..0f3dcf1b93 100644 --- a/Mage.Sets/src/mage/cards/w/WildestDreams.java +++ b/Mage.Sets/src/mage/cards/w/WildestDreams.java @@ -1,9 +1,7 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; @@ -13,9 +11,11 @@ import mage.constants.CardType; import mage.filter.StaticFilters; import mage.game.Game; import mage.target.common.TargetCardInYourGraveyard; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author LevelX2 */ public final class WildestDreams extends CardImpl { @@ -28,17 +28,8 @@ public final class WildestDreams extends CardImpl { Effect effect = new ReturnFromGraveyardToHandTargetEffect(); effect.setText("Return X target cards from your graveyard to your hand"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().setTargetAdjuster(WildestDreamsAdjuster.instance); this.getSpellAbility().addEffect(ExileSpellEffect.getInstance()); - - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - int xValue = ability.getManaCostsToPay().getX(); - ability.getTargets().clear(); - ability.addTarget(new TargetCardInYourGraveyard(xValue, StaticFilters.FILTER_CARD_FROM_YOUR_GRAVEYARD)); - } } public WildestDreams(final WildestDreams card) { @@ -50,3 +41,16 @@ public final class WildestDreams extends CardImpl { return new WildestDreams(this); } } + +enum WildestDreamsAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCardInYourGraveyard( + ability.getManaCostsToPay().getX(), + StaticFilters.FILTER_CARD_FROM_YOUR_GRAVEYARD + )); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java b/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java index 3ce85f81a3..106fe3c6bc 100644 --- a/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java +++ b/Mage.Sets/src/mage/cards/w/WildwoodRebirth.java @@ -1,16 +1,16 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.filter.StaticFilters; -import mage.target.common.TargetCardInGraveyard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; /** - * * @author Plopman */ public final class WildwoodRebirth extends CardImpl { @@ -20,7 +20,7 @@ public final class WildwoodRebirth extends CardImpl { // Return target creature card from your graveyard to your hand. this.getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect()); - this.getSpellAbility().addTarget(new TargetCardInGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + this.getSpellAbility().addTarget(new TargetCardInYourGraveyard()); } public WildwoodRebirth(final WildwoodRebirth card) { diff --git a/Mage.Sets/src/mage/cards/w/WillKenrith.java b/Mage.Sets/src/mage/cards/w/WillKenrith.java index e1d623e8fd..8a4c55d726 100644 --- a/Mage.Sets/src/mage/cards/w/WillKenrith.java +++ b/Mage.Sets/src/mage/cards/w/WillKenrith.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.CanBeYourCommanderAbility; @@ -16,11 +14,7 @@ import mage.abilities.effects.common.cost.SpellsCostReductionAllEffect; import mage.abilities.keyword.PartnerWithAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.CardTypePredicate; @@ -29,8 +23,9 @@ import mage.game.command.emblems.WillKenrithEmblem; import mage.target.TargetPlayer; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public final class WillKenrith extends CardImpl { @@ -60,11 +55,6 @@ public final class WillKenrith extends CardImpl { // -8: Target player gets an emblem with "Whenever you cast an instant or sorcery spell, copy it. You may choose new targets for the copy." Effect effect = new GetEmblemTargetPlayerEffect(new WillKenrithEmblem()); - effect.setText( - "Target player gets an emblem with " - + "\"Whenever you cast an instant or sorcery spell, " - + "copy it. You may choose new targets for the copy.\"" - ); ability = new LoyaltyAbility(effect, -8); ability.addTarget(new TargetPlayer()); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/w/WindbriskHeights.java b/Mage.Sets/src/mage/cards/w/WindbriskHeights.java index 6777d79f33..cad956630d 100644 --- a/Mage.Sets/src/mage/cards/w/WindbriskHeights.java +++ b/Mage.Sets/src/mage/cards/w/WindbriskHeights.java @@ -54,7 +54,7 @@ enum WindbriskHeightsAttackersCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerAttackedWatcher watcher = (PlayerAttackedWatcher) game.getState().getWatchers().get(PlayerAttackedWatcher.class.getSimpleName()); + PlayerAttackedWatcher watcher = game.getState().getWatcher(PlayerAttackedWatcher.class); return watcher != null && watcher.getNumberOfAttackersCurrentTurn(source.getControllerId()) >= 3; } diff --git a/Mage.Sets/src/mage/cards/w/WindbriskRaptor.java b/Mage.Sets/src/mage/cards/w/WindbriskRaptor.java index 1971335179..07be1f1d17 100644 --- a/Mage.Sets/src/mage/cards/w/WindbriskRaptor.java +++ b/Mage.Sets/src/mage/cards/w/WindbriskRaptor.java @@ -27,7 +27,7 @@ public final class WindbriskRaptor extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AttackingPredicate()); + filter.add(AttackingPredicate.instance); } public WindbriskRaptor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java b/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java index 77067c6f63..006688c784 100644 --- a/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java +++ b/Mage.Sets/src/mage/cards/w/WindgracesJudgment.java @@ -1,8 +1,6 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.DestroyTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -12,9 +10,11 @@ import mage.filter.predicate.permanent.ControllerIdPredicate; import mage.game.Game; import mage.players.Player; import mage.target.TargetPermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class WindgracesJudgment extends CardImpl { @@ -29,24 +29,7 @@ public final class WindgracesJudgment extends CardImpl { + "destroy target nonland permanent " + "that player controls") ); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - game.getOpponents(ability.getControllerId()).forEach(playerId -> { - Player player = game.getPlayer(playerId); - if (player != null) { - FilterNonlandPermanent filter = new FilterNonlandPermanent( - "nonland permanent controlled by " - + player.getLogName() - ); - filter.add(new ControllerIdPredicate(playerId)); - ability.addTarget(new TargetPermanent(0, 1, filter, false)); - } - }); - } + this.getSpellAbility().setTargetAdjuster(WindgracesJudgmentAdjuster.instance); } public WindgracesJudgment(final WindgracesJudgment card) { @@ -58,3 +41,23 @@ public final class WindgracesJudgment extends CardImpl { return new WindgracesJudgment(this); } } + +enum WindgracesJudgmentAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + game.getOpponents(ability.getControllerId()).forEach(playerId -> { + Player player = game.getPlayer(playerId); + if (player != null) { + FilterNonlandPermanent filter = new FilterNonlandPermanent( + "nonland permanent controlled by " + + player.getLogName() + ); + filter.add(new ControllerIdPredicate(playerId)); + ability.addTarget(new TargetPermanent(0, 1, filter, false)); + } + }); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java b/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java index 324891ba4f..715c7de787 100644 --- a/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java +++ b/Mage.Sets/src/mage/cards/w/WindsOfQalSisma.java @@ -1,12 +1,11 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.condition.LockedInCondition; import mage.abilities.condition.common.FerociousCondition; import mage.abilities.decorator.ConditionalReplacementEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.common.PreventAllDamageByAllPermanentsEffect; +import mage.abilities.hint.common.FerociousHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -15,8 +14,9 @@ import mage.constants.TargetController; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class WindsOfQalSisma extends CardImpl { @@ -28,7 +28,7 @@ public final class WindsOfQalSisma extends CardImpl { } public WindsOfQalSisma(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{G}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{G}"); // Prevent all combat damage that would be dealt this turn. // Ferocious - If you control a creature with power 4 or greater, instead prevent all combat damage that would be dealt this turn by creatures your opponents control. @@ -37,8 +37,9 @@ public final class WindsOfQalSisma extends CardImpl { new LockedInCondition(FerociousCondition.instance), new PreventAllDamageByAllPermanentsEffect(Duration.EndOfTurn, true)); effect.setText("Prevent all combat damage that would be dealt this turn.
    " + - "Ferocious — If you control a creature with power 4 or greater, instead prevent all combat damage that would be dealt this turn by creatures your opponents control"); + "Ferocious — If you control a creature with power 4 or greater, instead prevent all combat damage that would be dealt this turn by creatures your opponents control"); this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addHint(FerociousHint.instance); } public WindsOfQalSisma(final WindsOfQalSisma card) { diff --git a/Mage.Sets/src/mage/cards/w/WindsOfRath.java b/Mage.Sets/src/mage/cards/w/WindsOfRath.java index 559a4c83d9..84f591bef3 100644 --- a/Mage.Sets/src/mage/cards/w/WindsOfRath.java +++ b/Mage.Sets/src/mage/cards/w/WindsOfRath.java @@ -18,7 +18,7 @@ public final class WindsOfRath extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures that aren't enchanted"); static { - filter.add(Predicates.not(new EnchantedPredicate())); + filter.add(Predicates.not(EnchantedPredicate.instance)); } public WindsOfRath(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/Windstorm.java b/Mage.Sets/src/mage/cards/w/Windstorm.java index 8d4899a342..7ad059c67f 100644 --- a/Mage.Sets/src/mage/cards/w/Windstorm.java +++ b/Mage.Sets/src/mage/cards/w/Windstorm.java @@ -27,7 +27,7 @@ public final class Windstorm extends CardImpl { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{X}{G}"); - this.getSpellAbility().addEffect(new DamageAllEffect(new ManacostVariableValue(), filter)); + this.getSpellAbility().addEffect(new DamageAllEffect(ManacostVariableValue.instance, filter)); } public Windstorm(final Windstorm card) { diff --git a/Mage.Sets/src/mage/cards/w/WindstormDrake.java b/Mage.Sets/src/mage/cards/w/WindstormDrake.java new file mode 100644 index 0000000000..702a12621b --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WindstormDrake.java @@ -0,0 +1,56 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +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.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AbilityPredicate; + +import java.util.UUID; +import mage.abilities.effects.Effect; + +/** + * @author TheElk801 + */ +public final class WindstormDrake extends CardImpl { + + private static final FilterCreaturePermanent filter + = new FilterCreaturePermanent(); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + } + + public WindstormDrake(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{U}"); + + this.subtype.add(SubType.DRAKE); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Other creatures you control with flying get +1/+0. + Effect effect = new BoostControlledEffect( + 1, 0, Duration.WhileOnBattlefield, filter, true + ); + effect.setText("Other creatures you control with flying get +1/+0"); + this.addAbility(new SimpleStaticAbility(effect)); + } + + private WindstormDrake(final WindstormDrake card) { + super(card); + } + + @Override + public WindstormDrake copy() { + return new WindstormDrake(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WineOfBloodAndIron.java b/Mage.Sets/src/mage/cards/w/WineOfBloodAndIron.java index 47f98cbfd3..f5e9142898 100644 --- a/Mage.Sets/src/mage/cards/w/WineOfBloodAndIron.java +++ b/Mage.Sets/src/mage/cards/w/WineOfBloodAndIron.java @@ -29,7 +29,7 @@ public final class WineOfBloodAndIron extends CardImpl { // {4}: Target creature gets +X/+0 until end of turn, where X is its power. Sacrifice Wine of Blood and Iron at the beginning of the next end step. SimpleActivatedAbility ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, - new BoostTargetEffect(new TargetPermanentPowerCount(), new StaticValue(0), Duration.EndOfTurn, true), + new BoostTargetEffect(TargetPermanentPowerCount.instance, new StaticValue(0), Duration.EndOfTurn, true), new GenericManaCost(4)); Effect effect = new CreateDelayedTriggeredAbilityEffect( new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new SacrificeSourceEffect()), false); diff --git a/Mage.Sets/src/mage/cards/w/WingPuncture.java b/Mage.Sets/src/mage/cards/w/WingPuncture.java index e369c9664a..45b38fff9f 100644 --- a/Mage.Sets/src/mage/cards/w/WingPuncture.java +++ b/Mage.Sets/src/mage/cards/w/WingPuncture.java @@ -66,7 +66,7 @@ class WingPunctureEffect extends OneShotEffect { sourcePermanent = (Permanent) game.getLastKnownInformation(source.getFirstTarget(), Zone.BATTLEFIELD); } - Permanent targetPermanent = (Permanent) game.getPermanent(source.getTargets().get(1).getFirstTarget()); + Permanent targetPermanent = game.getPermanent(source.getTargets().get(1).getFirstTarget()); if (sourcePermanent != null && targetPermanent != null) { targetPermanent.damage(sourcePermanent.getPower().getValue(), sourcePermanent.getId(), game, false, true); return true; diff --git a/Mage.Sets/src/mage/cards/w/WinterBlast.java b/Mage.Sets/src/mage/cards/w/WinterBlast.java index 38eb6606bb..16f67ad957 100644 --- a/Mage.Sets/src/mage/cards/w/WinterBlast.java +++ b/Mage.Sets/src/mage/cards/w/WinterBlast.java @@ -1,9 +1,7 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.cards.CardImpl; @@ -13,9 +11,11 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class WinterBlast extends CardImpl { @@ -26,15 +26,7 @@ public final class WinterBlast extends CardImpl { // Tap X target creatures. Winter Blast deals 2 damage to each of those creatures with flying. this.getSpellAbility().addEffect(new WinterBlastEffect()); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - } - - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int xValue = ability.getManaCostsToPay().getX(); - ability.addTarget(new TargetCreaturePermanent(xValue)); - } + this.getSpellAbility().setTargetAdjuster(WinterBlastAdjuster.instance); } public WinterBlast(final WinterBlast card) { @@ -47,6 +39,16 @@ public final class WinterBlast extends CardImpl { } } +enum WinterBlastAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} + class WinterBlastEffect extends OneShotEffect { WinterBlastEffect() { diff --git a/Mage.Sets/src/mage/cards/w/WinterSky.java b/Mage.Sets/src/mage/cards/w/WinterSky.java index 31ac6526b5..6f728a8408 100644 --- a/Mage.Sets/src/mage/cards/w/WinterSky.java +++ b/Mage.Sets/src/mage/cards/w/WinterSky.java @@ -52,7 +52,7 @@ class WinterSkyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - if (controller.flipCoin(game)) { + if (controller.flipCoin(source, game, true)) { new DamageEverythingEffect(1).apply(game, source); return true; } else { diff --git a/Mage.Sets/src/mage/cards/w/Winterflame.java b/Mage.Sets/src/mage/cards/w/Winterflame.java index 30eee979e3..a78d177c03 100644 --- a/Mage.Sets/src/mage/cards/w/Winterflame.java +++ b/Mage.Sets/src/mage/cards/w/Winterflame.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.TapTargetEffect; @@ -10,26 +8,27 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class Winterflame extends CardImpl { public Winterflame(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{1}{U}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}{R}"); // Choose one or both - this.getSpellAbility().getModes().setMinModes(1); this.getSpellAbility().getModes().setMaxModes(2); - // *Tap target creature + // * Tap target creature this.getSpellAbility().addEffect(new TapTargetEffect()); - this.getSpellAbility().addTarget(new TargetCreaturePermanent()); - // *Winterflame deals 2 damage to target creature + this.getSpellAbility().addTarget(new TargetCreaturePermanent().withChooseHint("tap")); + // * Winterflame deals 2 damage to target creature Mode mode = new Mode(); - mode.getEffects().add(new DamageTargetEffect(2)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new DamageTargetEffect(2)); + mode.addTarget(new TargetCreaturePermanent().withChooseHint("deals 2 damage to")); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/w/Wirecat.java b/Mage.Sets/src/mage/cards/w/Wirecat.java index 9a9a9917e6..d7de3f3729 100644 --- a/Mage.Sets/src/mage/cards/w/Wirecat.java +++ b/Mage.Sets/src/mage/cards/w/Wirecat.java @@ -1,4 +1,3 @@ - package mage.cards.w; import mage.MageInt; @@ -8,8 +7,8 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.Game; @@ -18,13 +17,12 @@ import mage.game.permanent.Permanent; import java.util.UUID; /** - * * @author Derpthemeus */ public final class Wirecat extends CardImpl { public Wirecat(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT,CardType.CREATURE},"{4}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{4}"); this.subtype.add(SubType.CAT); this.power = new MageInt(4); this.toughness = new MageInt(3); @@ -59,12 +57,12 @@ public final class Wirecat extends CardImpl { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlockCheckAfter(Ability source, Game game) { + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/w/WirewoodHivemaster.java b/Mage.Sets/src/mage/cards/w/WirewoodHivemaster.java index 6f11431813..87d646142a 100644 --- a/Mage.Sets/src/mage/cards/w/WirewoodHivemaster.java +++ b/Mage.Sets/src/mage/cards/w/WirewoodHivemaster.java @@ -26,8 +26,8 @@ public final class WirewoodHivemaster extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another nontoken Elf"); static { filter.add(new SubtypePredicate(SubType.ELF)); - filter.add(new AnotherPredicate()); - filter.add(Predicates.not(new TokenPredicate())); + filter.add(AnotherPredicate.instance); + filter.add(Predicates.not(TokenPredicate.instance)); } public WirewoodHivemaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{G}"); diff --git a/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java b/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java index d1557d9ccd..1fba8725be 100644 --- a/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java +++ b/Mage.Sets/src/mage/cards/w/WisdomOfTheJedi.java @@ -40,17 +40,17 @@ public final class WisdomOfTheJedi extends CardImpl { Mode mode = new Mode(); Effect effect = new BoostTargetEffect(1, 1, Duration.EndOfTurn); effect.setText("Target creature you control gets +1/+1"); - mode.getEffects().add(effect); + mode.addEffect(effect); effect = new GainProtectionFromColorTargetEffect(Duration.EndOfTurn); effect.setText("and protection from the color of your choice until end of turn"); - mode.getEffects().add(effect); - mode.getTargets().add(new TargetControlledCreaturePermanent()); + mode.addEffect(effect); + mode.addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addMode(mode); // Counter target spell with converted mana cost of 3 or less. mode = new Mode(); - mode.getEffects().add(new CounterTargetEffect()); - mode.getTargets().add(new TargetSpell(filterSpell)); + mode.addEffect(new CounterTargetEffect()); + mode.addTarget(new TargetSpell(filterSpell)); this.getSpellAbility().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java index e52cbe13d4..2de4396f08 100644 --- a/Mage.Sets/src/mage/cards/w/WispweaverAngel.java +++ b/Mage.Sets/src/mage/cards/w/WispweaverAngel.java @@ -36,7 +36,7 @@ public final class WispweaverAngel extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WispweaverAngel(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WizardMentor.java b/Mage.Sets/src/mage/cards/w/WizardMentor.java index e2f67cfd06..580a69dbe6 100644 --- a/Mage.Sets/src/mage/cards/w/WizardMentor.java +++ b/Mage.Sets/src/mage/cards/w/WizardMentor.java @@ -26,7 +26,7 @@ public final class WizardMentor extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WizardMentor(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/Woeleecher.java b/Mage.Sets/src/mage/cards/w/Woeleecher.java index b2bf5484ba..4d72992df2 100644 --- a/Mage.Sets/src/mage/cards/w/Woeleecher.java +++ b/Mage.Sets/src/mage/cards/w/Woeleecher.java @@ -75,7 +75,7 @@ class WoeleecherEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Permanent target = game.getPermanent(source.getFirstTarget()); Player you = game.getPlayer(source.getControllerId()); - if (target != null) { + if (target != null && you != null) { numberCountersOriginal = target.getCounters(game).getCount(CounterType.M1M1); target.removeCounters(CounterType.M1M1.createInstance(), game); numberCountersAfter = target.getCounters(game).getCount(CounterType.M1M1); diff --git a/Mage.Sets/src/mage/cards/w/WojekSiren.java b/Mage.Sets/src/mage/cards/w/WojekSiren.java index 8a4dfd08d3..37185eb7e0 100644 --- a/Mage.Sets/src/mage/cards/w/WojekSiren.java +++ b/Mage.Sets/src/mage/cards/w/WojekSiren.java @@ -1,26 +1,20 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageObjectReference; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AbilityWord; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; +import mage.constants.*; import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class WojekSiren extends CardImpl { @@ -76,7 +70,8 @@ class WojekSirenBoostEffect extends ContinuousEffectImpl { for (MageObjectReference mageObjectReference : affectedObjectList) { Permanent permanent = mageObjectReference.getPermanent(game); if (permanent != null) { - permanent.addPower(2); + permanent.addPower(1); + permanent.addToughness(1); } } return true; diff --git a/Mage.Sets/src/mage/cards/w/WolfbriarElemental.java b/Mage.Sets/src/mage/cards/w/WolfbriarElemental.java index 93d321340d..4a96c707c5 100644 --- a/Mage.Sets/src/mage/cards/w/WolfbriarElemental.java +++ b/Mage.Sets/src/mage/cards/w/WolfbriarElemental.java @@ -31,7 +31,7 @@ public final class WolfbriarElemental extends CardImpl { this.addAbility(new MultikickerAbility("{G}")); // When Wolfbriar Elemental enters the battlefield, create a 2/2 green Wolf creature token for each time it was kicked. - this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WolfToken(), new MultikickerCount()))); + this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new WolfToken(), MultikickerCount.instance))); } public WolfbriarElemental(final WolfbriarElemental card) { diff --git a/Mage.Sets/src/mage/cards/w/WoodElemental.java b/Mage.Sets/src/mage/cards/w/WoodElemental.java index 5657c3a83a..39c7218a3e 100644 --- a/Mage.Sets/src/mage/cards/w/WoodElemental.java +++ b/Mage.Sets/src/mage/cards/w/WoodElemental.java @@ -62,7 +62,7 @@ class WoodElementalEffect extends OneShotEffect { private static final FilterControlledPermanent filter = new FilterControlledPermanent("untapped Forests you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SubtypePredicate(SubType.FOREST)); } diff --git a/Mage.Sets/src/mage/cards/w/WoodlandBellower.java b/Mage.Sets/src/mage/cards/w/WoodlandBellower.java index 9f8ff2a3bc..f7df876681 100644 --- a/Mage.Sets/src/mage/cards/w/WoodlandBellower.java +++ b/Mage.Sets/src/mage/cards/w/WoodlandBellower.java @@ -75,7 +75,7 @@ class WoodlandBellowerEffect extends OneShotEffect { filter.add(Predicates.not(new SupertypePredicate(SuperType.LEGENDARY))); filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, 4)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/w/WookieeMystic.java b/Mage.Sets/src/mage/cards/w/WookieeMystic.java index 1b82318eea..1d8f1d879d 100644 --- a/Mage.Sets/src/mage/cards/w/WookieeMystic.java +++ b/Mage.Sets/src/mage/cards/w/WookieeMystic.java @@ -78,7 +78,7 @@ class WookieeMysticWatcher extends Watcher { private final List creatures = new ArrayList<>(); WookieeMysticWatcher(Ability source) { - super("HallOfTheBanditLordWatcher", WatcherScope.CARD); + super(WatcherScope.CARD); this.source = source; } diff --git a/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java b/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java index cf262a7e39..4914fa1586 100644 --- a/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java +++ b/Mage.Sets/src/mage/cards/w/WookieeRaidleader.java @@ -25,7 +25,7 @@ public final class WookieeRaidleader extends CardImpl { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("another target creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WookieeRaidleader(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WordOfBinding.java b/Mage.Sets/src/mage/cards/w/WordOfBinding.java index 2364364447..9d6782945d 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfBinding.java +++ b/Mage.Sets/src/mage/cards/w/WordOfBinding.java @@ -1,19 +1,18 @@ package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.effects.common.TapTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import static mage.filter.StaticFilters.FILTER_PERMANENT_CREATURES; import mage.game.Game; import mage.target.common.TargetCreaturePermanent; +import mage.target.targetadjustment.TargetAdjuster; + +import java.util.UUID; /** - * * @author fireshoes */ public final class WordOfBinding extends CardImpl { @@ -23,25 +22,25 @@ public final class WordOfBinding extends CardImpl { // Tap X target creatures. this.getSpellAbility().addEffect(new TapTargetEffect("X target creatures")); - this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 1, FILTER_PERMANENT_CREATURES, false)); + this.getSpellAbility().setTargetAdjuster(WordOfBindingAdjuster.instance); } public WordOfBinding(final WordOfBinding card) { super(card); } - @Override - public void adjustTargets(Ability ability, Game game) { - if (ability instanceof SpellAbility) { - ability.getTargets().clear(); - int numberToTap = ability.getManaCostsToPay().getX(); - numberToTap = Math.min(game.getBattlefield().count(FILTER_PERMANENT_CREATURES, ability.getSourceId(), ability.getControllerId(), game), numberToTap); - ability.addTarget(new TargetCreaturePermanent(numberToTap, numberToTap, FILTER_PERMANENT_CREATURES, false)); - } - } - @Override public WordOfBinding copy() { return new WordOfBinding(this); } } + +enum WordOfBindingAdjuster implements TargetAdjuster { + instance; + + @Override + public void adjustTargets(Ability ability, Game game) { + ability.getTargets().clear(); + ability.addTarget(new TargetCreaturePermanent(ability.getManaCostsToPay().getX())); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/w/WordOfBlasting.java b/Mage.Sets/src/mage/cards/w/WordOfBlasting.java index e30c450431..ee30e19b78 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfBlasting.java +++ b/Mage.Sets/src/mage/cards/w/WordOfBlasting.java @@ -31,7 +31,7 @@ public final class WordOfBlasting extends CardImpl { // Destroy target Wall. It can't be regenerated. Word of Blasting deals damage equal to that Wall's converted mana cost to the Wall's controller. this.getSpellAbility().addEffect(new DestroyTargetEffect(true)); - Effect effect = new DamageTargetControllerEffect(new TargetConvertedManaCost()); + Effect effect = new DamageTargetControllerEffect(TargetConvertedManaCost.instance); effect.setText("{this} deals damage equal to that Wall's converted mana cost to the Wall's controller"); this.getSpellAbility().addEffect(effect); this.getSpellAbility().addTarget(new TargetPermanent(filter)); diff --git a/Mage.Sets/src/mage/cards/w/WordOfCommand.java b/Mage.Sets/src/mage/cards/w/WordOfCommand.java index a73cc01035..07823ab0a1 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfCommand.java +++ b/Mage.Sets/src/mage/cards/w/WordOfCommand.java @@ -1,7 +1,5 @@ - package mage.cards.w; -import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; @@ -14,11 +12,7 @@ import mage.abilities.effects.RestrictionEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -30,14 +24,15 @@ import mage.target.TargetCard; import mage.target.common.TargetOpponent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** - * * @author L_J */ public final class WordOfCommand extends CardImpl { public WordOfCommand(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{B}{B}"); // Look at target opponent's hand and choose a card from it. You control that player until Word of Command finishes resolving. The player plays that card if able. While doing so, the player can activate mana abilities only if they're from lands that player controls and only if mana they produce is spent to activate other mana abilities of lands the player controls and/or to play that card. If the chosen card is cast as a spell, you control the player while that spell is resolving. this.getSpellAbility().addEffect(new WordOfCommandEffect()); @@ -58,7 +53,7 @@ class WordOfCommandEffect extends OneShotEffect { public WordOfCommandEffect() { super(Outcome.GainControl); - this.staticText = "Look at target opponent's hand and choose a card from it. You control that player until Word of Command finishes resolving. The player plays that card if able. While doing so, the player can activate mana abilities only if they're from lands that player controls and only if mana they produce is spent to activate other mana abilities of lands the player controls and/or to play that card. If the chosen card is cast as a spell, you control the player while that spell is resolving"; + this.staticText = "Look at target opponent's hand and choose a card from it. You control that player until {this} finishes resolving. The player plays that card if able. While doing so, the player can activate mana abilities only if they're from lands that player controls and only if mana they produce is spent to activate other mana abilities of lands the player controls and/or to play that card. If the chosen card is cast as a spell, you control the player while that spell is resolving"; } public WordOfCommandEffect(final WordOfCommandEffect effect) { @@ -219,7 +214,7 @@ class WordOfCommandCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } } diff --git a/Mage.Sets/src/mage/cards/w/WordOfUndoing.java b/Mage.Sets/src/mage/cards/w/WordOfUndoing.java index af5518c6ff..7491e89247 100644 --- a/Mage.Sets/src/mage/cards/w/WordOfUndoing.java +++ b/Mage.Sets/src/mage/cards/w/WordOfUndoing.java @@ -64,7 +64,7 @@ class WordOfUndoingReturnToHandEffect extends OneShotEffect { Set attachments = new LinkedHashSet<>(); Player player = game.getPlayer(source.getControllerId()); Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (target != null) { + if (target != null && player != null) { for (UUID attachmentId : target.getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); if (attachment != null && attachment.isControlledBy(source.getControllerId()) diff --git a/Mage.Sets/src/mage/cards/w/WorldAtWar.java b/Mage.Sets/src/mage/cards/w/WorldAtWar.java index 0658ecda70..01dbdcae33 100644 --- a/Mage.Sets/src/mage/cards/w/WorldAtWar.java +++ b/Mage.Sets/src/mage/cards/w/WorldAtWar.java @@ -142,7 +142,7 @@ class UntapAttackingThisTurnEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + Watcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher instanceof AttackedThisTurnWatcher) { Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); for (MageObjectReference mor : attackedThisTurn) { diff --git a/Mage.Sets/src/mage/cards/w/WorldQueller.java b/Mage.Sets/src/mage/cards/w/WorldQueller.java index 20950189b1..a5c435a3a8 100644 --- a/Mage.Sets/src/mage/cards/w/WorldQueller.java +++ b/Mage.Sets/src/mage/cards/w/WorldQueller.java @@ -111,7 +111,7 @@ class WorldQuellerEffect extends OneShotEffect { type = CardType.TRIBAL; } if (type != null) { - FilterControlledPermanent filter = new FilterControlledPermanent(new StringBuilder("permanent you control of type ").append(type.toString()).toString()); + FilterControlledPermanent filter = new FilterControlledPermanent("permanent you control of type " + type.toString()); filter.add(new CardTypePredicate(type)); TargetPermanent target = new TargetControlledPermanent(1, 1, filter, false); @@ -119,7 +119,7 @@ class WorldQuellerEffect extends OneShotEffect { for (UUID playerId : game.getState().getPlayersInRange(source.getControllerId(), game)) { Player player2 = game.getPlayer(playerId); - if (target.canChoose(playerId, game)) { + if (player2 != null && target.canChoose(playerId, game)) { while (player2.canRespond() && !target.isChosen() && target.canChoose(playerId, game)) { player2.chooseTarget(Outcome.Sacrifice, target, source, game); } diff --git a/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java b/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java index dffcbeec04..e3f967b7e3 100644 --- a/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java +++ b/Mage.Sets/src/mage/cards/w/WorldgorgerDragon.java @@ -70,7 +70,7 @@ class WorldgorgerDragonEntersEffect extends OneShotEffect { static { filter.add(new ControllerPredicate(TargetController.YOU)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WorldgorgerDragonEntersEffect() { diff --git a/Mage.Sets/src/mage/cards/w/WormfangDrake.java b/Mage.Sets/src/mage/cards/w/WormfangDrake.java index bc3d0ffc5c..6888edf518 100644 --- a/Mage.Sets/src/mage/cards/w/WormfangDrake.java +++ b/Mage.Sets/src/mage/cards/w/WormfangDrake.java @@ -65,7 +65,7 @@ class WormfangDrakeExileCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WormfangDrakeExileCost() { diff --git a/Mage.Sets/src/mage/cards/w/WormfangNewt.java b/Mage.Sets/src/mage/cards/w/WormfangNewt.java index ebb66ead46..1a27dc96ab 100644 --- a/Mage.Sets/src/mage/cards/w/WormfangNewt.java +++ b/Mage.Sets/src/mage/cards/w/WormfangNewt.java @@ -25,7 +25,7 @@ public final class WormfangNewt extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WormfangNewt(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WormfangTurtle.java b/Mage.Sets/src/mage/cards/w/WormfangTurtle.java index b33bec0c8d..bee8704f5d 100644 --- a/Mage.Sets/src/mage/cards/w/WormfangTurtle.java +++ b/Mage.Sets/src/mage/cards/w/WormfangTurtle.java @@ -25,7 +25,7 @@ public final class WormfangTurtle extends CardImpl { private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent(); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WormfangTurtle(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WormsOfTheEarth.java b/Mage.Sets/src/mage/cards/w/WormsOfTheEarth.java index 35685256a9..128d05dbd8 100644 --- a/Mage.Sets/src/mage/cards/w/WormsOfTheEarth.java +++ b/Mage.Sets/src/mage/cards/w/WormsOfTheEarth.java @@ -1,38 +1,33 @@ - package mage.cards.w; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.common.SacrificeTargetCost; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; +import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.TargetController; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.common.FilterControlledLandPermanent; import mage.game.Game; -import mage.game.permanent.Permanent; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.common.TargetControlledPermanent; +import java.util.UUID; + /** - * * @author L_J */ public final class WormsOfTheEarth extends CardImpl { public WormsOfTheEarth(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{B}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{B}{B}"); // Players can't play lands. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new WormsOfTheEarthPlayEffect())); @@ -60,7 +55,7 @@ class WormsOfTheEarthPlayEffect extends ContinuousRuleModifyingEffectImpl { super(Duration.WhileOnBattlefield, Outcome.Neutral); this.staticText = "Players can't play lands"; } - + public WormsOfTheEarthPlayEffect(final WormsOfTheEarthPlayEffect effect) { super(effect); } @@ -69,7 +64,7 @@ class WormsOfTheEarthPlayEffect extends ContinuousRuleModifyingEffectImpl { public WormsOfTheEarthPlayEffect copy() { return new WormsOfTheEarthPlayEffect(this); } - + @Override public boolean apply(Game game, Ability source) { return true; @@ -104,7 +99,7 @@ class WormsOfTheEarthEnterEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return GameEvent.EventType.ZONE_CHANGE == event.getType(); + return event.getType() == GameEvent.EventType.ZONE_CHANGE; } @Override @@ -112,9 +107,7 @@ class WormsOfTheEarthEnterEffect extends ContinuousRuleModifyingEffectImpl { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; if (zEvent.getToZone() == Zone.BATTLEFIELD) { Card card = game.getCard(zEvent.getTargetId()); - if (card != null && card.isLand()) { - return true; - } + return card != null && card.isLand(); } return false; } @@ -142,7 +135,7 @@ class WormsOfTheEarthDestroyEffect extends OneShotEffect { if (player != null) { if (player.chooseUse(outcome, "Do you want to destroy " + sourcePermanent.getLogName() + "? (sacrifice two lands or have it deal 5 damage to you)", source, game)) { cost.clearPaid(); - if (cost.canPay(source, source.getSourceId(), player.getId(), game) + if (cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Sacrifice, "Will you sacrifice two lands? (otherwise you'll be dealt 5 damage)", source, game)) { if (!cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { player.damage(5, source.getSourceId(), game, false, true); diff --git a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java index 6fae146170..9e7608a8e1 100644 --- a/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java +++ b/Mage.Sets/src/mage/cards/w/WortTheRaidmother.java @@ -54,7 +54,7 @@ public final class WortTheRaidmother extends CardImpl { class WortGainConspireEffect extends ContinuousEffectImpl { - private final static FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); + private static final FilterInstantOrSorcerySpell filter = new FilterInstantOrSorcerySpell(); static { filter.add(Predicates.or(new ColorPredicate(ObjectColor.RED), new ColorPredicate(ObjectColor.GREEN))); diff --git a/Mage.Sets/src/mage/cards/w/WorthyCause.java b/Mage.Sets/src/mage/cards/w/WorthyCause.java index 4d196b4f2c..3564befc98 100644 --- a/Mage.Sets/src/mage/cards/w/WorthyCause.java +++ b/Mage.Sets/src/mage/cards/w/WorthyCause.java @@ -29,7 +29,7 @@ public final class WorthyCause extends CardImpl { this.getSpellAbility().addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(FILTER_CONTROLLED_CREATURE_SHORT_TEXT))); // You gain life equal to the sacrificed creature's toughness. - Effect effect = new GainLifeEffect(new SacrificeCostCreaturesToughness()); + Effect effect = new GainLifeEffect(SacrificeCostCreaturesToughness.instance); effect.setText("You gain life equal to the sacrificed creature's toughness"); this.getSpellAbility().addEffect(effect); } diff --git a/Mage.Sets/src/mage/cards/w/WoundReflection.java b/Mage.Sets/src/mage/cards/w/WoundReflection.java index 156d16384c..460acc927a 100644 --- a/Mage.Sets/src/mage/cards/w/WoundReflection.java +++ b/Mage.Sets/src/mage/cards/w/WoundReflection.java @@ -57,12 +57,12 @@ class WoundReflectionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (controller != null && watcher != null) { for (UUID playerId : game.getOpponents(controller.getId())) { Player opponent = game.getPlayer(playerId); if (opponent != null) { - int lifeLost = watcher.getLiveLost(playerId); + int lifeLost = watcher.getLifeLost(playerId); if (lifeLost > 0) { opponent.loseLife(lifeLost, game, false); } diff --git a/Mage.Sets/src/mage/cards/w/WreckingBeast.java b/Mage.Sets/src/mage/cards/w/WreckingBeast.java new file mode 100644 index 0000000000..f2c318e213 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WreckingBeast.java @@ -0,0 +1,40 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.keyword.RiotAbility; +import mage.abilities.keyword.TrampleAbility; +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 WreckingBeast extends CardImpl { + + public WreckingBeast(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{G}{G}"); + + this.subtype.add(SubType.BEAST); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Riot + this.addAbility(new RiotAbility()); + + // Trample + this.addAbility(TrampleAbility.getInstance()); + } + + private WreckingBeast(final WreckingBeast card) { + super(card); + } + + @Override + public WreckingBeast copy() { + return new WreckingBeast(this); + } +} diff --git a/Mage.Sets/src/mage/cards/w/WretchedAnurid.java b/Mage.Sets/src/mage/cards/w/WretchedAnurid.java index 5fe1aa0409..e78c9a68fa 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedAnurid.java +++ b/Mage.Sets/src/mage/cards/w/WretchedAnurid.java @@ -22,7 +22,7 @@ public final class WretchedAnurid extends CardImpl { private static final FilterPermanent filter = new FilterCreaturePermanent("another creature"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public WretchedAnurid(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java index 6fc463b28a..e8c979e5e8 100644 --- a/Mage.Sets/src/mage/cards/w/WretchedConfluence.java +++ b/Mage.Sets/src/mage/cards/w/WretchedConfluence.java @@ -40,14 +40,14 @@ public final class WretchedConfluence extends CardImpl { // Target creature gets -2/-2 until end of turn; Mode mode = new Mode(); - mode.getEffects().add(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); - mode.getTargets().add(new TargetCreaturePermanent()); + mode.addEffect(new BoostTargetEffect(-2, -2, Duration.EndOfTurn)); + mode.addTarget(new TargetCreaturePermanent()); this.getSpellAbility().getModes().addMode(mode); // Return target creature card from your graveyard to your hand. mode = new Mode(); - mode.getEffects().add(new ReturnFromGraveyardToHandTargetEffect()); - mode.getTargets().add(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); + mode.addEffect(new ReturnFromGraveyardToHandTargetEffect()); + mode.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD)); this.getSpellAbility().getModes().addMode(mode); } diff --git a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java index 5bb8dfcfd1..f30afcbf4c 100644 --- a/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java +++ b/Mage.Sets/src/mage/cards/w/WrexialTheRisenDeep.java @@ -169,12 +169,12 @@ class WrexialReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; return zEvent.getToZone() == Zone.GRAVEYARD - && ((ZoneChangeEvent) event).getTargetId().equals(cardid); + && event.getTargetId().equals(cardid); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { - UUID eventObject = ((ZoneChangeEvent) event).getTargetId(); + UUID eventObject = event.getTargetId(); StackObject card = game.getStack().getStackObject(eventObject); Player controller = game.getPlayer(source.getControllerId()); if (card != null && controller != null) { diff --git a/Mage.Sets/src/mage/cards/w/WritOfPassage.java b/Mage.Sets/src/mage/cards/w/WritOfPassage.java index 040f218574..d28aa0d50d 100644 --- a/Mage.Sets/src/mage/cards/w/WritOfPassage.java +++ b/Mage.Sets/src/mage/cards/w/WritOfPassage.java @@ -1,36 +1,29 @@ - package mage.cards.w; -import java.util.UUID; - -import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; -import mage.target.common.TargetCreaturePermanent; import mage.abilities.Ability; import mage.abilities.common.AttacksAttachedTriggeredAbility; import mage.abilities.condition.common.AttachedToMatchesFilterCondition; import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.combat.CantBeBlockedTargetEffect; -import mage.constants.Outcome; -import mage.target.TargetPermanent; import mage.abilities.keyword.EnchantAbility; import mage.abilities.keyword.ForecastAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.AttachmentType; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.ComparisonType; -import mage.constants.Duration; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.target.TargetPermanent; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; /** - * * @author TheElk801 */ public final class WritOfPassage extends CardImpl { @@ -89,13 +82,13 @@ class WritOfPassageAttachedEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override public boolean applies(Permanent permanent, Ability source, Game game) { Permanent attachment = game.getPermanent(source.getSourceId()); - return attachment != null && attachment.isAttachedTo(permanent.getId()); + return attachment != null && attachment.isAttachedTo(permanent.getId()); } } diff --git a/Mage.Sets/src/mage/cards/w/WuSpy.java b/Mage.Sets/src/mage/cards/w/WuSpy.java index ce091d87d9..a1edf88cf5 100644 --- a/Mage.Sets/src/mage/cards/w/WuSpy.java +++ b/Mage.Sets/src/mage/cards/w/WuSpy.java @@ -74,8 +74,7 @@ class WuSpyEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Player opponent = game.getPlayer(this.getTargetPointer().getFirst(game, source)); if (controller != null && opponent != null) { - Cards cards = new CardsImpl(); - cards.addAll(opponent.getLibrary().getTopCards(game, 2)); + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, 2)); if (!cards.isEmpty()) { TargetCard target = new TargetCardInLibrary(new FilterCard("card to put into graveyard")); controller.choose(Outcome.Benefit, cards, target, game); diff --git a/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java b/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java index a392f415b2..d0a35959e7 100644 --- a/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java +++ b/Mage.Sets/src/mage/cards/x/XantchaSleeperAgent.java @@ -1,35 +1,40 @@ package mage.cards.x; -import java.util.Objects; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.*; -import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; -import mage.abilities.effects.Effect; +import mage.abilities.common.AsEntersBattlefieldAbility; +import mage.abilities.common.AttacksEachCombatStaticAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.InfoEffect; import mage.abilities.effects.common.LoseLifePermanentControllerEffect; +import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.Target; import mage.target.common.TargetOpponent; +import mage.target.targetpointer.FixedTarget; +import java.util.Objects; +import java.util.UUID; + +import static mage.constants.Outcome.Benefit; /** - * * @author jesusjbr */ public final class XantchaSleeperAgent extends CardImpl { - - public XantchaSleeperAgent(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}"); @@ -39,30 +44,26 @@ public final class XantchaSleeperAgent extends CardImpl { this.toughness = new MageInt(5); // As Xantcha, Sleeper Agent enters the battlefield, an opponent of your choice gains control of it. - Ability ability = new EntersBattlefieldTriggeredAbility(new XantchaSleeperAgentChangeControlEffect()) ; - ability.addTarget(new TargetOpponent()); - this.addAbility(ability); + this.addAbility(new AsEntersBattlefieldAbility(new XantchaSleeperAgentChangeControlEffect())); // Xantcha attacks each combat if able and can’t attack its owner or planeswalkers its owner controls. - ability = new AttacksEachCombatStaticAbility(); - Effect effect = new XantchaSleeperAgentAttackRestrictionEffect(); - ability.addEffect(effect); + Ability ability = new AttacksEachCombatStaticAbility(); + ability.addEffect(new XantchaSleeperAgentAttackRestrictionEffect()); this.addAbility(ability); // {3}: Xantcha’s controller loses 2 life and you draw a card. Any player may activate this ability. - effect = new LoseLifePermanentControllerEffect(2); - effect.setText("Xantcha’s controller loses 2 life"); - SimpleActivatedAbility simpleAbility = new SimpleActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}")); - + SimpleActivatedAbility simpleAbility = new SimpleActivatedAbility( + new LoseLifePermanentControllerEffect(2) + .setText("{this}’s controller loses 2 life"), + new GenericManaCost(3) + ); simpleAbility.addEffect(new DrawCardSourceControllerEffect(1).setText("and you draw a card")); simpleAbility.addEffect(new InfoEffect("Any player may activate this ability")); simpleAbility.setMayActivate(TargetController.ANY); this.addAbility(simpleAbility); - - } - public XantchaSleeperAgent(final XantchaSleeperAgent card) { + private XantchaSleeperAgent(final XantchaSleeperAgent card) { super(card); } @@ -72,16 +73,14 @@ public final class XantchaSleeperAgent extends CardImpl { } } +class XantchaSleeperAgentChangeControlEffect extends OneShotEffect { - -class XantchaSleeperAgentChangeControlEffect extends ContinuousEffectImpl { - - public XantchaSleeperAgentChangeControlEffect() { - super(Duration.Custom, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); - staticText = "an opponent of your choice gains control of it"; + XantchaSleeperAgentChangeControlEffect() { + super(Benefit); + staticText = "an opponent of your choice gains control of it."; } - public XantchaSleeperAgentChangeControlEffect(final XantchaSleeperAgentChangeControlEffect effect) { + private XantchaSleeperAgentChangeControlEffect(final XantchaSleeperAgentChangeControlEffect effect) { super(effect); } @@ -92,13 +91,27 @@ class XantchaSleeperAgentChangeControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getSourceObjectIfItStillExists(game); - if (permanent != null) { - return permanent.changeControllerId(source.getFirstTarget(), game); - } else { - discard(); + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; } - return false; + Target target = new TargetOpponent(); + target.setNotTarget(true); + if (!controller.choose(Outcome.Benefit, target, source.getSourceId(), game)) { + return false; + } + Player player = game.getPlayer(target.getFirstTarget()); + if (player == null) { + return false; + } + ContinuousEffect continuousEffect = new GainControlTargetEffect( + Duration.WhileOnBattlefield, true, player.getId() + ); + continuousEffect.setTargetPointer(new FixedTarget( + source.getSourceId(), source.getSourceObjectZoneChangeCounter() + )); + game.addEffect(continuousEffect, source); + return true; } } @@ -109,7 +122,7 @@ class XantchaSleeperAgentAttackRestrictionEffect extends RestrictionEffect { staticText = "and can't attack its owner or planeswalkers its owner controls."; } - XantchaSleeperAgentAttackRestrictionEffect(final XantchaSleeperAgentAttackRestrictionEffect effect) { + private XantchaSleeperAgentAttackRestrictionEffect(final XantchaSleeperAgentAttackRestrictionEffect effect) { super(effect); } @@ -124,15 +137,17 @@ class XantchaSleeperAgentAttackRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } boolean allowAttack = true; UUID ownerPlayerId = source.getSourcePermanentIfItStillExists(game).getOwnerId(); if (defenderId.equals(ownerPlayerId)) { allowAttack = false; - } - else { + } else { Permanent planeswalker = game.getPermanent(defenderId); if (planeswalker != null && planeswalker.isControlledBy(ownerPlayerId)) { allowAttack = false; diff --git a/Mage.Sets/src/mage/cards/x/XantidSwarm.java b/Mage.Sets/src/mage/cards/x/XantidSwarm.java index 190fe2d739..20a9c4b348 100644 --- a/Mage.Sets/src/mage/cards/x/XantidSwarm.java +++ b/Mage.Sets/src/mage/cards/x/XantidSwarm.java @@ -83,7 +83,7 @@ class XantidSwarmTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever {this} attacks, ").append(super.getRule()).toString(); + return "Whenever {this} attacks, " + super.getRule(); } } diff --git a/Mage.Sets/src/mage/cards/x/XathridDemon.java b/Mage.Sets/src/mage/cards/x/XathridDemon.java index 5d229c1b8a..0e7c174c46 100644 --- a/Mage.Sets/src/mage/cards/x/XathridDemon.java +++ b/Mage.Sets/src/mage/cards/x/XathridDemon.java @@ -81,7 +81,7 @@ class XathridDemonEffect extends OneShotEffect { } FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creature other than " + sourcePermanent.getName()); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); Target target = new TargetControlledCreaturePermanent(1, 1, filter, true); if (target.canChoose(source.getSourceId(), controller.getId(), game)) { diff --git a/Mage.Sets/src/mage/cards/x/XathridGorgon.java b/Mage.Sets/src/mage/cards/x/XathridGorgon.java index e301d21358..adae2d237c 100644 --- a/Mage.Sets/src/mage/cards/x/XathridGorgon.java +++ b/Mage.Sets/src/mage/cards/x/XathridGorgon.java @@ -1,7 +1,5 @@ - package mage.cards.x; -import java.util.UUID; import mage.MageInt; import mage.ObjectColor; import mage.abilities.Ability; @@ -19,22 +17,23 @@ import mage.abilities.keyword.DefenderAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SubType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; import mage.counters.CounterType; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class XathridGorgon extends CardImpl { public XathridGorgon(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{B}"); this.subtype.add(SubType.GORGON); this.power = new MageInt(3); @@ -42,7 +41,7 @@ public final class XathridGorgon extends CardImpl { // Deathtouch this.addAbility(DeathtouchAbility.getInstance()); - + // {2}{B}, {tap}: Put a petrification counter on target creature. It gains defender and becomes a colorless artifact in addition to its other types. Its activated abilities can't be activated. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersTargetEffect(CounterType.PETRIFICATION.createInstance()), new ManaCostsImpl("{2}{B}")); ability.addCost(new TapSourceCost()); @@ -56,7 +55,7 @@ public final class XathridGorgon extends CardImpl { ability.addEffect(new BecomesColorTargetEffect(new ObjectColor(), Duration.Custom, "")); ability.addEffect(new XathridGorgonCantActivateEffect()); this.addAbility(ability); - + } public XathridGorgon(final XathridGorgon card) { @@ -91,7 +90,7 @@ class XathridGorgonCantActivateEffect extends RestrictionEffect { } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage.Sets/src/mage/cards/x/XenagosGodOfRevels.java b/Mage.Sets/src/mage/cards/x/XenagosGodOfRevels.java index 76662b8c00..3eada0b3a3 100644 --- a/Mage.Sets/src/mage/cards/x/XenagosGodOfRevels.java +++ b/Mage.Sets/src/mage/cards/x/XenagosGodOfRevels.java @@ -32,7 +32,7 @@ public final class XenagosGodOfRevels extends CardImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another target creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } public XenagosGodOfRevels(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java b/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java index e09453a139..a19ee5c37e 100644 --- a/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java +++ b/Mage.Sets/src/mage/cards/x/XenagosTheReveler.java @@ -1,26 +1,19 @@ - package mage.cards.x; -import java.util.LinkedHashSet; -import java.util.Set; -import java.util.UUID; import mage.Mana; import mage.abilities.Ability; import mage.abilities.LoyaltyAbility; import mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.CreateTokenEffect; +import mage.abilities.hint.common.CreaturesYouControlHint; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; import mage.cards.CardsImpl; import mage.choices.Choice; import mage.choices.ChoiceImpl; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.FilterCard; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.predicate.Predicates; @@ -30,8 +23,11 @@ import mage.game.permanent.token.XenagosSatyrToken; import mage.players.Player; import mage.target.TargetCard; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public final class XenagosTheReveler extends CardImpl { @@ -44,7 +40,8 @@ public final class XenagosTheReveler extends CardImpl { this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); // +1: Add X mana in any combination of {R} and/or {G}, where X is the number of creatures you control. - this.addAbility(new LoyaltyAbility(new XenagosManaEffect(), +1)); + this.addAbility(new LoyaltyAbility(new XenagosManaEffect(), +1) + .addHint(CreaturesYouControlHint.instance)); // 0: Create a 2/2 red and green Satyr creature token with haste. this.addAbility(new LoyaltyAbility(new CreateTokenEffect(new XenagosSatyrToken()), 0)); diff --git a/Mage.Sets/src/mage/cards/y/YavimayaDryad.java b/Mage.Sets/src/mage/cards/y/YavimayaDryad.java index 68944bf154..9890421bc8 100644 --- a/Mage.Sets/src/mage/cards/y/YavimayaDryad.java +++ b/Mage.Sets/src/mage/cards/y/YavimayaDryad.java @@ -80,7 +80,7 @@ class YavimayaDryadEffect extends SearchEffect { if (controller == null || targetPlayer == null) { return false; } - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { targetPlayer.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, true, false, false, null); diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java index a1d1d16c90..3670b8a32a 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsVileOffering.java @@ -1,7 +1,5 @@ package mage.cards.y; -import java.util.UUID; - import mage.abilities.Ability; import mage.abilities.common.LegendarySpellAbility; import mage.abilities.effects.OneShotEffect; @@ -9,7 +7,10 @@ import mage.abilities.effects.common.ExileSpellEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SuperType; +import mage.constants.Zone; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.filter.common.FilterPermanentCard; import mage.filter.predicate.Predicates; @@ -20,6 +21,8 @@ import mage.players.Player; import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCreatureOrPlaneswalker; +import java.util.UUID; + /** * @author JRHerlehy Created on 4/8/18. */ @@ -78,7 +81,6 @@ class YawgmothsVileOfferingEffect extends OneShotEffect { } Card returnCard = game.getCard(source.getTargets().getFirstTarget()); - if (returnCard != null) { controller.moveCards(returnCard, Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/y/YdwenEfreet.java b/Mage.Sets/src/mage/cards/y/YdwenEfreet.java index b1dd810f90..8f038cb3a2 100644 --- a/Mage.Sets/src/mage/cards/y/YdwenEfreet.java +++ b/Mage.Sets/src/mage/cards/y/YdwenEfreet.java @@ -60,12 +60,12 @@ class YdwenEfreetEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Permanent creature = game.getPermanent(source.getSourceId()); if (controller != null && creature != null) { - if (!controller.flipCoin(game)) { + if (!controller.flipCoin(source, game, true)) { creature.removeFromCombat(game); creature.setMaxBlocks(0); // Make blocked creatures unblocked - BlockedByOnlyOneCreatureThisCombatWatcher watcher = (BlockedByOnlyOneCreatureThisCombatWatcher) game.getState().getWatchers().get(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName()); + BlockedByOnlyOneCreatureThisCombatWatcher watcher = game.getState().getWatcher(BlockedByOnlyOneCreatureThisCombatWatcher.class); if (watcher != null) { Set combatGroups = watcher.getBlockedOnlyByCreature(creature.getId()); if (combatGroups != null) { diff --git a/Mage.Sets/src/mage/cards/y/YisanTheWandererBard.java b/Mage.Sets/src/mage/cards/y/YisanTheWandererBard.java index f06a2cf576..63cbad9cc5 100644 --- a/Mage.Sets/src/mage/cards/y/YisanTheWandererBard.java +++ b/Mage.Sets/src/mage/cards/y/YisanTheWandererBard.java @@ -85,7 +85,7 @@ class YisanTheWandererBardEffect extends OneShotEffect { filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, newConvertedCost)); filter.add(new CardTypePredicate(CardType.CREATURE)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); controller.moveCards(card, Zone.BATTLEFIELD, source, game); } diff --git a/Mage.Sets/src/mage/cards/y/YodaJediMaster.java b/Mage.Sets/src/mage/cards/y/YodaJediMaster.java index 94bd681f28..761caea8c7 100644 --- a/Mage.Sets/src/mage/cards/y/YodaJediMaster.java +++ b/Mage.Sets/src/mage/cards/y/YodaJediMaster.java @@ -16,6 +16,7 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; +import mage.constants.SuperType; import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; @@ -38,12 +39,13 @@ public final class YodaJediMaster extends CardImpl { private static final FilterPermanent filter = new FilterPermanent("another target permanent you own"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new OwnerPredicate(TargetController.YOU)); } public YodaJediMaster(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{1}{G}{U}"); + this.addSuperType(SuperType.LEGENDARY); this.subtype.add(SubType.YODA); this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility(3)); diff --git a/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java b/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java index a9cbc11f61..7834b9820c 100644 --- a/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java +++ b/Mage.Sets/src/mage/cards/y/YomijiWhoBarsTheWay.java @@ -31,7 +31,7 @@ public final class YomijiWhoBarsTheWay extends CardImpl { // Whenever a legendary permanent other than Yomiji, Who Bars the Way is put into a graveyard from the battlefield, return that card to its owner's hand. FilterPermanent filter = new FilterPermanent("a legendary permanent other than " + getName()); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(new SupertypePredicate(SuperType.LEGENDARY)); Effect effect = new ReturnToHandTargetEffect(); effect.setText("return that card to its owner's hand"); diff --git a/Mage.Sets/src/mage/cards/y/YoungPyromancer.java b/Mage.Sets/src/mage/cards/y/YoungPyromancer.java index 6f7b3b631f..d5e647087f 100644 --- a/Mage.Sets/src/mage/cards/y/YoungPyromancer.java +++ b/Mage.Sets/src/mage/cards/y/YoungPyromancer.java @@ -1,6 +1,5 @@ package mage.cards.y; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.common.CreateTokenEffect; @@ -11,8 +10,9 @@ import mage.constants.SubType; import mage.filter.StaticFilters; import mage.game.permanent.token.YoungPyromancerElementalToken; +import java.util.UUID; + /** - * * @author jeffwadsworth */ public final class YoungPyromancer extends CardImpl { @@ -28,7 +28,7 @@ public final class YoungPyromancer extends CardImpl { // Whenever you cast an instant or sorcery spell, create a 1/1 red Elemental creature token. this.addAbility(new SpellCastControllerTriggeredAbility( new CreateTokenEffect(new YoungPyromancerElementalToken()), - StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, false + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false )); } diff --git a/Mage.Sets/src/mage/cards/z/ZadasCommando.java b/Mage.Sets/src/mage/cards/z/ZadasCommando.java index 123eff9f26..ee55962b5f 100644 --- a/Mage.Sets/src/mage/cards/z/ZadasCommando.java +++ b/Mage.Sets/src/mage/cards/z/ZadasCommando.java @@ -32,7 +32,7 @@ public final class ZadasCommando extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ZadasCommando(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/z/ZahidDjinnOfTheLamp.java b/Mage.Sets/src/mage/cards/z/ZahidDjinnOfTheLamp.java index d621d2d23c..47144a1ce1 100644 --- a/Mage.Sets/src/mage/cards/z/ZahidDjinnOfTheLamp.java +++ b/Mage.Sets/src/mage/cards/z/ZahidDjinnOfTheLamp.java @@ -35,7 +35,7 @@ public final class ZahidDjinnOfTheLamp extends CardImpl { AlternativeCostSourceAbility alternativeCostSourceAbility = new AlternativeCostSourceAbility(new ManaCostsImpl("{3}{U}"), null, "You may pay {3}{U} and tap an untapped artifact you control rather than pay this spell's mana cost."); FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent("untapped artifact you control"); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); alternativeCostSourceAbility.addCost(new TapTargetCost(new TargetControlledPermanent(filter))); this.addAbility(alternativeCostSourceAbility); diff --git a/Mage.Sets/src/mage/cards/z/ZedruuTheGreathearted.java b/Mage.Sets/src/mage/cards/z/ZedruuTheGreathearted.java index 88c4dfcd3d..78c292f791 100644 --- a/Mage.Sets/src/mage/cards/z/ZedruuTheGreathearted.java +++ b/Mage.Sets/src/mage/cards/z/ZedruuTheGreathearted.java @@ -35,10 +35,10 @@ public final class ZedruuTheGreathearted extends CardImpl { this.toughness = new MageInt(4); // At the beginning of your upkeep, you gain X life and draw X cards, where X is the number of permanents you own that your opponents control. - Effect effect = new GainLifeEffect(new PermanentsYouOwnThatOpponentsControlCount()); + Effect effect = new GainLifeEffect(PermanentsYouOwnThatOpponentsControlCount.instance); effect.setText("you gain X life"); Ability ability = new BeginningOfUpkeepTriggeredAbility(effect, TargetController.YOU, false); - effect = new DrawCardSourceControllerEffect(new PermanentsYouOwnThatOpponentsControlCount()); + effect = new DrawCardSourceControllerEffect(PermanentsYouOwnThatOpponentsControlCount.instance); effect.setText("and draw X cards, where X is the number of permanents you own that your opponents control"); ability.addEffect(effect); this.addAbility(ability); diff --git a/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java new file mode 100644 index 0000000000..b05e459af5 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZeganaUtopianSpeaker.java @@ -0,0 +1,77 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.AdaptAbility; +import mage.abilities.keyword.TrampleAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.predicate.permanent.AnotherPredicate; +import mage.filter.predicate.permanent.CounterPredicate; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class ZeganaUtopianSpeaker extends CardImpl { + + private static final FilterPermanent filter = new FilterControlledCreaturePermanent(); + private static final FilterPermanent filter2 = new FilterControlledCreaturePermanent(); + + static { + filter.add(new CounterPredicate(CounterType.P1P1)); + filter.add(AnotherPredicate.instance); + filter2.add(new CounterPredicate(CounterType.P1P1)); + } + + public ZeganaUtopianSpeaker(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{G}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.MERFOLK); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(4); + this.toughness = new MageInt(4); + + // When Zegana, Utopian Speaker enters the battlefield, if you control another creature with a +1/+1 counter on it, draw a card. + this.addAbility(new ConditionalInterveningIfTriggeredAbility( + new EntersBattlefieldTriggeredAbility( + new DrawCardSourceControllerEffect(1), false + ), new PermanentsOnTheBattlefieldCondition(filter), + "When {this} enters the battlefield, " + + "if you control another creature " + + "with a +1/+1 counter on it, draw a card." + )); + + // {4}{G}{U}: Adapt 4. + this.addAbility(new AdaptAbility(4, "{4}{G}{U}")); + + // Each creature you control with a +1/+1 counter on it has trample. + this.addAbility(new SimpleStaticAbility( + Zone.BATTLEFIELD, + new GainAbilityAllEffect( + TrampleAbility.getInstance(), Duration.WhileOnBattlefield, + filter2, "Each creature you control with a +1/+1 counter on it has trample" + ) + )); + } + + public ZeganaUtopianSpeaker(final ZeganaUtopianSpeaker card) { + super(card); + } + + @Override + public ZeganaUtopianSpeaker copy() { + return new ZeganaUtopianSpeaker(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZephyrGull.java b/Mage.Sets/src/mage/cards/z/ZephyrGull.java new file mode 100644 index 0000000000..5b24699205 --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZephyrGull.java @@ -0,0 +1,36 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; + +import java.util.UUID; + +/** + * @author JayDi85 + */ +public final class ZephyrGull extends CardImpl { + + public ZephyrGull(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}"); + this.subtype.add(SubType.BIRD); + + this.power = new MageInt(1); + this.toughness = new MageInt(1); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + } + + public ZephyrGull(final ZephyrGull card) { + super(card); + } + + @Override + public ZephyrGull copy() { + return new ZephyrGull(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZhurTaaDruid.java b/Mage.Sets/src/mage/cards/z/ZhurTaaDruid.java index 395fc979f7..eca81b5aae 100644 --- a/Mage.Sets/src/mage/cards/z/ZhurTaaDruid.java +++ b/Mage.Sets/src/mage/cards/z/ZhurTaaDruid.java @@ -68,7 +68,7 @@ class ZhurTaaDruidAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever you tap {this} for mana, ").append(super.getRule()).toString() ; + return "Whenever you tap {this} for mana, " + super.getRule(); } @Override diff --git a/Mage.Sets/src/mage/cards/z/ZhurTaaGoblin.java b/Mage.Sets/src/mage/cards/z/ZhurTaaGoblin.java new file mode 100644 index 0000000000..79256c778a --- /dev/null +++ b/Mage.Sets/src/mage/cards/z/ZhurTaaGoblin.java @@ -0,0 +1,37 @@ +package mage.cards.z; + +import mage.MageInt; +import mage.abilities.keyword.RiotAbility; +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 ZhurTaaGoblin extends CardImpl { + + public ZhurTaaGoblin(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{G}"); + + this.subtype.add(SubType.GOBLIN); + this.subtype.add(SubType.BERSERKER); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Riot + this.addAbility(new RiotAbility()); + } + + private ZhurTaaGoblin(final ZhurTaaGoblin card) { + super(card); + } + + @Override + public ZhurTaaGoblin copy() { + return new ZhurTaaGoblin(this); + } +} diff --git a/Mage.Sets/src/mage/cards/z/ZirilanOfTheClaw.java b/Mage.Sets/src/mage/cards/z/ZirilanOfTheClaw.java index 68325e1e24..a014a518c6 100644 --- a/Mage.Sets/src/mage/cards/z/ZirilanOfTheClaw.java +++ b/Mage.Sets/src/mage/cards/z/ZirilanOfTheClaw.java @@ -80,7 +80,7 @@ class ZirilanOfTheClawEffect extends OneShotEffect { FilterPermanentCard filter = new FilterPermanentCard("a Dragon permanent card"); filter.add(new SubtypePredicate(SubType.DRAGON)); TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { controller.moveCards(card, Zone.BATTLEFIELD, source, game); diff --git a/Mage.Sets/src/mage/cards/z/ZombieMob.java b/Mage.Sets/src/mage/cards/z/ZombieMob.java index 7b2477ceaf..c37b4a18a7 100644 --- a/Mage.Sets/src/mage/cards/z/ZombieMob.java +++ b/Mage.Sets/src/mage/cards/z/ZombieMob.java @@ -73,8 +73,7 @@ class ZombieMobEffect extends OneShotEffect { if (amount > 0) { permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game); } - Cards cards = new CardsImpl(); - cards.addAll(controller.getGraveyard().getCards(filter, game)); + Cards cards = new CardsImpl(controller.getGraveyard().getCards(filter, game)); controller.moveCards(cards, Zone.EXILED, source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/z/ZombieTrailblazer.java b/Mage.Sets/src/mage/cards/z/ZombieTrailblazer.java index ea75ba5c22..6e8358a724 100644 --- a/Mage.Sets/src/mage/cards/z/ZombieTrailblazer.java +++ b/Mage.Sets/src/mage/cards/z/ZombieTrailblazer.java @@ -34,7 +34,7 @@ public final class ZombieTrailblazer extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ZOMBIE)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ZombieTrailblazer(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/z/ZulaportChainmage.java b/Mage.Sets/src/mage/cards/z/ZulaportChainmage.java index d18e9b05d0..0ad6f5d0ab 100644 --- a/Mage.Sets/src/mage/cards/z/ZulaportChainmage.java +++ b/Mage.Sets/src/mage/cards/z/ZulaportChainmage.java @@ -30,7 +30,7 @@ public final class ZulaportChainmage extends CardImpl { static { filter.add(new SubtypePredicate(SubType.ALLY)); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } public ZulaportChainmage(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/z/ZulaportCutthroat.java b/Mage.Sets/src/mage/cards/z/ZulaportCutthroat.java index 337d2f5b31..3d506d7e8c 100644 --- a/Mage.Sets/src/mage/cards/z/ZulaportCutthroat.java +++ b/Mage.Sets/src/mage/cards/z/ZulaportCutthroat.java @@ -13,6 +13,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.TargetController; +import mage.filter.StaticFilters; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; @@ -22,11 +23,6 @@ import mage.filter.predicate.permanent.ControllerPredicate; */ public final class ZulaportCutthroat extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature you control"); - - static { - filter.add(new ControllerPredicate(TargetController.YOU)); - } public ZulaportCutthroat(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{B}"); @@ -35,7 +31,7 @@ public final class ZulaportCutthroat extends CardImpl { this.toughness = new MageInt(1); // Whenever Zulaport Cutthroat or another creature you control dies, each opponent loses 1 life and you gain 1 life. - Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new LoseLifeOpponentsEffect(1), false, filter); + Ability ability = new DiesThisOrAnotherCreatureTriggeredAbility(new LoseLifeOpponentsEffect(1), false, StaticFilters.FILTER_PERMANENT_CREATURE_CONTROLLED); Effect effect = new GainLifeEffect(1); effect.setText("and you gain 1 life"); ability.addEffect(effect); diff --git a/Mage.Sets/src/mage/cards/z/ZulaportEnforcer.java b/Mage.Sets/src/mage/cards/z/ZulaportEnforcer.java index ff5d97542b..4ee33360d7 100644 --- a/Mage.Sets/src/mage/cards/z/ZulaportEnforcer.java +++ b/Mage.Sets/src/mage/cards/z/ZulaportEnforcer.java @@ -27,7 +27,7 @@ import mage.filter.predicate.mageobject.ColorPredicate; */ public final class ZulaportEnforcer extends LevelerCard { - private final static FilterCreaturePermanent notBlackCreatures = new FilterCreaturePermanent("except by black creatures"); + private static final FilterCreaturePermanent notBlackCreatures = new FilterCreaturePermanent("except by black creatures"); static { notBlackCreatures.add(Predicates.not(new ColorPredicate(ObjectColor.BLACK))); diff --git a/Mage.Sets/src/mage/sets/Alliances.java b/Mage.Sets/src/mage/sets/Alliances.java index e53b14b61d..a93161e725 100644 --- a/Mage.Sets/src/mage/sets/Alliances.java +++ b/Mage.Sets/src/mage/sets/Alliances.java @@ -1,195 +1,220 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -public final class Alliances extends ExpansionSet { - - private static final Alliances instance = new Alliances(); - - public static Alliances getInstance() { - return instance; - } - - private Alliances() { - super("Alliances", "ALL", ExpansionSet.buildDate(1996, 6, 10), SetType.EXPANSION); - this.blockName = "Ice Age"; - this.parentSet = IceAge.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 8; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Aesthir Glider", "116a", Rarity.COMMON, mage.cards.a.AesthirGlider.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Aesthir Glider", "116b", Rarity.COMMON, mage.cards.a.AesthirGlider.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Agent of Stromgald", "64a", Rarity.COMMON, mage.cards.a.AgentOfStromgald.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Agent of Stromgald", "64b", Rarity.COMMON, mage.cards.a.AgentOfStromgald.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arcane Denial", "22a", Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Arcane Denial", "22b", Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ashnod's Cylix", 117, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); - cards.add(new SetCardInfo("Astrolabe", "118a", Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Astrolabe", "118b", Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balduvian Dead", 43, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); - cards.add(new SetCardInfo("Balduvian Horde", 65, Rarity.RARE, mage.cards.b.BalduvianHorde.class)); - cards.add(new SetCardInfo("Balduvian Trading Post", 137, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); - cards.add(new SetCardInfo("Balduvian War-Makers", "66a", Rarity.COMMON, mage.cards.b.BalduvianWarMakers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Balduvian War-Makers", "66b", Rarity.COMMON, mage.cards.b.BalduvianWarMakers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bestial Fury", "67a", Rarity.COMMON, mage.cards.b.BestialFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bestial Fury", "67b", Rarity.COMMON, mage.cards.b.BestialFury.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Bounty of the Hunt", 85, Rarity.UNCOMMON, mage.cards.b.BountyOfTheHunt.class)); - cards.add(new SetCardInfo("Browse", 25, Rarity.UNCOMMON, mage.cards.b.Browse.class)); - cards.add(new SetCardInfo("Burnout", 68, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); - cards.add(new SetCardInfo("Carrier Pigeons", "1a", Rarity.COMMON, mage.cards.c.CarrierPigeons.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Carrier Pigeons", "1b", Rarity.COMMON, mage.cards.c.CarrierPigeons.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Casting of Bones", "44a", Rarity.COMMON, mage.cards.c.CastingOfBones.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Casting of Bones", "44b", Rarity.COMMON, mage.cards.c.CastingOfBones.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Chaos Harlequin", 69, Rarity.RARE, mage.cards.c.ChaosHarlequin.class)); - cards.add(new SetCardInfo("Contagion", 45, Rarity.UNCOMMON, mage.cards.c.Contagion.class)); - cards.add(new SetCardInfo("Deadly Insect", "86a", Rarity.COMMON, mage.cards.d.DeadlyInsect.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Deadly Insect", "86b", Rarity.COMMON, mage.cards.d.DeadlyInsect.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Death Spark", 70, Rarity.UNCOMMON, mage.cards.d.DeathSpark.class)); - cards.add(new SetCardInfo("Diminishing Returns", 26, Rarity.RARE, mage.cards.d.DiminishingReturns.class)); - cards.add(new SetCardInfo("Dystopia", 47, Rarity.RARE, mage.cards.d.Dystopia.class)); - cards.add(new SetCardInfo("Elvish Bard", 87, Rarity.UNCOMMON, mage.cards.e.ElvishBard.class)); - cards.add(new SetCardInfo("Elvish Ranger", "88a", Rarity.COMMON, mage.cards.e.ElvishRanger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Elvish Ranger", "88b", Rarity.COMMON, mage.cards.e.ElvishRanger.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Elvish Spirit Guide", 89, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); - cards.add(new SetCardInfo("Energy Arc", 106, Rarity.UNCOMMON, mage.cards.e.EnergyArc.class)); - cards.add(new SetCardInfo("Enslaved Scout", "71a", Rarity.COMMON, mage.cards.e.EnslavedScout.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Enslaved Scout", "71b", Rarity.COMMON, mage.cards.e.EnslavedScout.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Errand of Duty", "2a", Rarity.COMMON, mage.cards.e.ErrandOfDuty.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Errand of Duty", "2b", Rarity.COMMON, mage.cards.e.ErrandOfDuty.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Exile", 3, Rarity.RARE, mage.cards.e.Exile.class)); - cards.add(new SetCardInfo("False Demise", "27a", Rarity.COMMON, mage.cards.f.FalseDemise.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("False Demise", "27b", Rarity.COMMON, mage.cards.f.FalseDemise.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Feast or Famine", "49a", Rarity.COMMON, mage.cards.f.FeastOrFamine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Feast or Famine", "49b", Rarity.COMMON, mage.cards.f.FeastOrFamine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fevered Strength", "50a", Rarity.COMMON, mage.cards.f.FeveredStrength.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fevered Strength", "50b", Rarity.COMMON, mage.cards.f.FeveredStrength.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Floodwater Dam", 119, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); - cards.add(new SetCardInfo("Force of Will", 28, Rarity.UNCOMMON, mage.cards.f.ForceOfWill.class)); - cards.add(new SetCardInfo("Foresight", "29a", Rarity.COMMON, mage.cards.f.Foresight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Foresight", "29b", Rarity.COMMON, mage.cards.f.Foresight.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Berserkers", "93a", Rarity.COMMON, mage.cards.g.GorillaBerserkers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Berserkers", "93b", Rarity.COMMON, mage.cards.g.GorillaBerserkers.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Chieftain", "94a", Rarity.COMMON, mage.cards.g.GorillaChieftain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Chieftain", "94b", Rarity.COMMON, mage.cards.g.GorillaChieftain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Shaman", "72a", Rarity.COMMON, mage.cards.g.GorillaShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla Shaman", "72b", Rarity.COMMON, mage.cards.g.GorillaShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla War Cry", "73a", Rarity.COMMON, mage.cards.g.GorillaWarCry.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gorilla War Cry", "73b", Rarity.COMMON, mage.cards.g.GorillaWarCry.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Guerrilla Tactics", "74a", Rarity.COMMON, mage.cards.g.GuerrillaTactics.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Guerrilla Tactics", "74b", Rarity.COMMON, mage.cards.g.GuerrillaTactics.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Hail Storm", 95, Rarity.UNCOMMON, mage.cards.h.HailStorm.class)); - cards.add(new SetCardInfo("Heart of Yavimaya", 138, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); - cards.add(new SetCardInfo("Helm of Obedience", 121, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); - cards.add(new SetCardInfo("Inheritance", 4, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); - cards.add(new SetCardInfo("Insidious Bookworms", "51a", Rarity.COMMON, mage.cards.i.InsidiousBookworms.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Insidious Bookworms", "51b", Rarity.COMMON, mage.cards.i.InsidiousBookworms.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Gargoyle", 5, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); - cards.add(new SetCardInfo("Juniper Order Advocate", 6, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); - cards.add(new SetCardInfo("Kaysa", 96, Rarity.RARE, mage.cards.k.Kaysa.class)); - cards.add(new SetCardInfo("Keeper of Tresserhorn", 52, Rarity.RARE, mage.cards.k.KeeperOfTresserhorn.class)); - cards.add(new SetCardInfo("Kjeldoran Escort", "7a", Rarity.COMMON, mage.cards.k.KjeldoranEscort.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kjeldoran Escort", "7b", Rarity.COMMON, mage.cards.k.KjeldoranEscort.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Kjeldoran Home Guard", 8, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Outpost", 139, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); - cards.add(new SetCardInfo("Krovikan Horror", 53, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); - cards.add(new SetCardInfo("Krovikan Plague", 54, Rarity.UNCOMMON, mage.cards.k.KrovikanPlague.class)); - cards.add(new SetCardInfo("Lake of the Dead", 140, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); - cards.add(new SetCardInfo("Lat-Nam's Legacy", "30a", Rarity.COMMON, mage.cards.l.LatNamsLegacy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lat-Nam's Legacy", "30b", Rarity.COMMON, mage.cards.l.LatNamsLegacy.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Library of Lat-Nam", 31, Rarity.RARE, mage.cards.l.LibraryOfLatNam.class)); - cards.add(new SetCardInfo("Lim-Dul's High Guard", "55a", Rarity.COMMON, mage.cards.l.LimDulsHighGuard.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lim-Dul's High Guard", "55b", Rarity.COMMON, mage.cards.l.LimDulsHighGuard.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Lim-Dul's Paladin", 108, Rarity.UNCOMMON, mage.cards.l.LimDulsPaladin.class)); - cards.add(new SetCardInfo("Lim-Dul's Vault", 107, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); - cards.add(new SetCardInfo("Lodestone Bauble", 122, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); - cards.add(new SetCardInfo("Lord of Tresserhorn", 112, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); - cards.add(new SetCardInfo("Martyrdom", "10a", Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Martyrdom", "10b", Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mishra's Groundbreaker", 123, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); - cards.add(new SetCardInfo("Misinformation", 56, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); - cards.add(new SetCardInfo("Mystic Compass", 124, Rarity.UNCOMMON, mage.cards.m.MysticCompass.class)); - cards.add(new SetCardInfo("Nature's Blessing", 110, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); - cards.add(new SetCardInfo("Nature's Chosen", 97, Rarity.UNCOMMON, mage.cards.n.NaturesChosen.class)); - cards.add(new SetCardInfo("Nature's Wrath", 98, Rarity.RARE, mage.cards.n.NaturesWrath.class)); - cards.add(new SetCardInfo("Noble Steeds", "11a", Rarity.COMMON, mage.cards.n.NobleSteeds.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Noble Steeds", "11b", Rarity.COMMON, mage.cards.n.NobleSteeds.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Omen of Fire", 75, Rarity.RARE, mage.cards.o.OmenOfFire.class)); - cards.add(new SetCardInfo("Phantasmal Fiend", "57a", Rarity.COMMON, mage.cards.p.PhantasmalFiend.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phantasmal Fiend", "57b", Rarity.COMMON, mage.cards.p.PhantasmalFiend.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phelddagrif", 115, Rarity.RARE, mage.cards.p.Phelddagrif.class)); - cards.add(new SetCardInfo("Phyrexian Boon", "58a", Rarity.COMMON, mage.cards.p.PhyrexianBoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phyrexian Boon", "58b", Rarity.COMMON, mage.cards.p.PhyrexianBoon.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phyrexian Devourer", 125, Rarity.RARE, mage.cards.p.PhyrexianDevourer.class)); - cards.add(new SetCardInfo("Phyrexian War Beast", "127a", Rarity.COMMON, mage.cards.p.PhyrexianWarBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Phyrexian War Beast", "127b", Rarity.COMMON, mage.cards.p.PhyrexianWarBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Pillage", 76, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); - cards.add(new SetCardInfo("Pyrokinesis", 78, Rarity.UNCOMMON, mage.cards.p.Pyrokinesis.class)); - cards.add(new SetCardInfo("Reinforcements", "12a", Rarity.COMMON, mage.cards.r.Reinforcements.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reinforcements", "12b", Rarity.COMMON, mage.cards.r.Reinforcements.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reprisal", "13a", Rarity.COMMON, mage.cards.r.Reprisal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Reprisal", "13b", Rarity.COMMON, mage.cards.r.Reprisal.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ritual of the Machine", 59, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); - cards.add(new SetCardInfo("Royal Decree", 14, Rarity.RARE, mage.cards.r.RoyalDecree.class)); - cards.add(new SetCardInfo("Royal Herbalist", "15a", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Royal Herbalist", "15b", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("School of the Unseen", 141, Rarity.UNCOMMON, mage.cards.s.SchoolOfTheUnseen.class)); - cards.add(new SetCardInfo("Seasoned Tactician", 17, Rarity.UNCOMMON, mage.cards.s.SeasonedTactician.class)); - cards.add(new SetCardInfo("Sheltered Valley", 142, Rarity.RARE, mage.cards.s.ShelteredValley.class)); - cards.add(new SetCardInfo("Shield Sphere", 129, Rarity.UNCOMMON, mage.cards.s.ShieldSphere.class)); - cards.add(new SetCardInfo("Sol Grail", 130, Rarity.UNCOMMON, mage.cards.s.SolGrail.class)); - cards.add(new SetCardInfo("Soldevi Adnate", "60a", Rarity.COMMON, mage.cards.s.SoldeviAdnate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Adnate", "60b", Rarity.COMMON, mage.cards.s.SoldeviAdnate.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Digger", 131, Rarity.RARE, mage.cards.s.SoldeviDigger.class)); - cards.add(new SetCardInfo("Soldevi Excavations", 143, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); - cards.add(new SetCardInfo("Soldevi Heretic", "33a", Rarity.COMMON, mage.cards.s.SoldeviHeretic.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Heretic", "33b", Rarity.COMMON, mage.cards.s.SoldeviHeretic.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Sage", "34a", Rarity.COMMON, mage.cards.s.SoldeviSage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Sage", "34b", Rarity.COMMON, mage.cards.s.SoldeviSage.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Steam Beast", "133a", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldevi Steam Beast", "133b", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Soldier of Fortune", 80, Rarity.UNCOMMON, mage.cards.s.SoldierOfFortune.class)); - cards.add(new SetCardInfo("Stench of Decay", "61a", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Stench of Decay", "61b", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm Cauldron", 134, Rarity.RARE, mage.cards.s.StormCauldron.class)); - cards.add(new SetCardInfo("Storm Crow", "36a", Rarity.COMMON, mage.cards.s.StormCrow.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm Crow", "36b", Rarity.COMMON, mage.cards.s.StormCrow.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm Shaman", "81a", Rarity.COMMON, mage.cards.s.StormShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Storm Shaman", "81b", Rarity.COMMON, mage.cards.s.StormShaman.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Stromgald Spy", 62, Rarity.UNCOMMON, mage.cards.s.StromgaldSpy.class)); - cards.add(new SetCardInfo("Surge of Strength", 109, Rarity.UNCOMMON, mage.cards.s.SurgeOfStrength.class)); - cards.add(new SetCardInfo("Sustaining Spirit", 18, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); - cards.add(new SetCardInfo("Swamp Mosquito", "63a", Rarity.COMMON, mage.cards.s.SwampMosquito.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp Mosquito", "63b", Rarity.COMMON, mage.cards.s.SwampMosquito.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Thawing Glaciers", 144, Rarity.RARE, mage.cards.t.ThawingGlaciers.class)); - cards.add(new SetCardInfo("Thought Lash", 39, Rarity.RARE, mage.cards.t.ThoughtLash.class)); - cards.add(new SetCardInfo("Tidal Control", 40, Rarity.RARE, mage.cards.t.TidalControl.class)); - cards.add(new SetCardInfo("Tornado", 101, Rarity.RARE, mage.cards.t.Tornado.class)); - cards.add(new SetCardInfo("Unlikely Alliance", 20, Rarity.UNCOMMON, mage.cards.u.UnlikelyAlliance.class)); - cards.add(new SetCardInfo("Urza's Engine", 135, Rarity.UNCOMMON, mage.cards.u.UrzasEngine.class)); - cards.add(new SetCardInfo("Varchild's Crusader", "82a", Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Varchild's Crusader", "82b", Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Varchild's War-Riders", 83, Rarity.RARE, mage.cards.v.VarchildsWarRiders.class)); - cards.add(new SetCardInfo("Veteran's Voice", "84a", Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Veteran's Voice", "84b", Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Viscerid Armor", "41a", Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Viscerid Armor", "41b", Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Viscerid Drone", 42, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); - cards.add(new SetCardInfo("Wandering Mage", 111, Rarity.RARE, mage.cards.w.WanderingMage.class)); - cards.add(new SetCardInfo("Whip Vine", "103a", Rarity.COMMON, mage.cards.w.WhipVine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Whip Vine", "103b", Rarity.COMMON, mage.cards.w.WhipVine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Whirling Catapult", 136, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); - cards.add(new SetCardInfo("Wild Aesthir", "21a", Rarity.COMMON, mage.cards.w.WildAesthir.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Wild Aesthir", "21b", Rarity.COMMON, mage.cards.w.WildAesthir.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Winter's Night", 114, Rarity.RARE, mage.cards.w.WintersNight.class)); - cards.add(new SetCardInfo("Yavimaya Ancients", "104a", Rarity.COMMON, mage.cards.y.YavimayaAncients.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yavimaya Ancients", "104b", Rarity.COMMON, mage.cards.y.YavimayaAncients.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Yavimaya Ants", 105, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class Alliances extends ExpansionSet { + + private static final Alliances instance = new Alliances(); + + public static Alliances getInstance() { + return instance; + } + + private Alliances() { + super("Alliances", "ALL", ExpansionSet.buildDate(1996, 6, 10), SetType.EXPANSION); + this.blockName = "Ice Age"; + this.parentSet = IceAge.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 8; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Aesthir Glider", "116a", Rarity.COMMON, mage.cards.a.AesthirGlider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Aesthir Glider", "116b", Rarity.COMMON, mage.cards.a.AesthirGlider.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Agent of Stromgald", "64a", Rarity.COMMON, mage.cards.a.AgentOfStromgald.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Agent of Stromgald", "64b", Rarity.COMMON, mage.cards.a.AgentOfStromgald.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Denial", "22a", Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Arcane Denial", "22b", Rarity.COMMON, mage.cards.a.ArcaneDenial.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ashnod's Cylix", 117, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); + cards.add(new SetCardInfo("Astrolabe", "118a", Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Astrolabe", "118b", Rarity.COMMON, mage.cards.a.Astrolabe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Awesome Presence", "23a", Rarity.COMMON, mage.cards.a.AwesomePresence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Awesome Presence", "23b", Rarity.COMMON, mage.cards.a.AwesomePresence.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Balduvian Dead", 43, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); + cards.add(new SetCardInfo("Balduvian Horde", 65, Rarity.RARE, mage.cards.b.BalduvianHorde.class)); + cards.add(new SetCardInfo("Balduvian Trading Post", 137, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); + cards.add(new SetCardInfo("Balduvian War-Makers", "66a", Rarity.COMMON, mage.cards.b.BalduvianWarMakers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Balduvian War-Makers", "66b", Rarity.COMMON, mage.cards.b.BalduvianWarMakers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Benthic Explorers", "24a", Rarity.COMMON, mage.cards.b.BenthicExplorers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Benthic Explorers", "24b", Rarity.COMMON, mage.cards.b.BenthicExplorers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bestial Fury", "67a", Rarity.COMMON, mage.cards.b.BestialFury.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bestial Fury", "67b", Rarity.COMMON, mage.cards.b.BestialFury.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Bounty of the Hunt", 85, Rarity.UNCOMMON, mage.cards.b.BountyOfTheHunt.class)); + cards.add(new SetCardInfo("Browse", 25, Rarity.UNCOMMON, mage.cards.b.Browse.class)); + cards.add(new SetCardInfo("Burnout", 68, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); + cards.add(new SetCardInfo("Carrier Pigeons", "1a", Rarity.COMMON, mage.cards.c.CarrierPigeons.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Carrier Pigeons", "1b", Rarity.COMMON, mage.cards.c.CarrierPigeons.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Casting of Bones", "44a", Rarity.COMMON, mage.cards.c.CastingOfBones.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Casting of Bones", "44b", Rarity.COMMON, mage.cards.c.CastingOfBones.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Chaos Harlequin", 69, Rarity.RARE, mage.cards.c.ChaosHarlequin.class)); + cards.add(new SetCardInfo("Contagion", 45, Rarity.UNCOMMON, mage.cards.c.Contagion.class)); + cards.add(new SetCardInfo("Deadly Insect", "86a", Rarity.COMMON, mage.cards.d.DeadlyInsect.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Deadly Insect", "86b", Rarity.COMMON, mage.cards.d.DeadlyInsect.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Death Spark", 70, Rarity.UNCOMMON, mage.cards.d.DeathSpark.class)); + cards.add(new SetCardInfo("Diminishing Returns", 26, Rarity.RARE, mage.cards.d.DiminishingReturns.class)); + cards.add(new SetCardInfo("Diseased Vermin", 46, Rarity.UNCOMMON, mage.cards.d.DiseasedVermin.class)); + cards.add(new SetCardInfo("Dystopia", 47, Rarity.RARE, mage.cards.d.Dystopia.class)); + cards.add(new SetCardInfo("Elvish Bard", 87, Rarity.UNCOMMON, mage.cards.e.ElvishBard.class)); + cards.add(new SetCardInfo("Elvish Ranger", "88a", Rarity.COMMON, mage.cards.e.ElvishRanger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elvish Ranger", "88b", Rarity.COMMON, mage.cards.e.ElvishRanger.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Elvish Spirit Guide", 89, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); + cards.add(new SetCardInfo("Energy Arc", 106, Rarity.UNCOMMON, mage.cards.e.EnergyArc.class)); + cards.add(new SetCardInfo("Enslaved Scout", "71a", Rarity.COMMON, mage.cards.e.EnslavedScout.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Enslaved Scout", "71b", Rarity.COMMON, mage.cards.e.EnslavedScout.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Errand of Duty", "2a", Rarity.COMMON, mage.cards.e.ErrandOfDuty.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Errand of Duty", "2b", Rarity.COMMON, mage.cards.e.ErrandOfDuty.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Exile", 3, Rarity.RARE, mage.cards.e.Exile.class)); + cards.add(new SetCardInfo("False Demise", "27a", Rarity.COMMON, mage.cards.f.FalseDemise.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("False Demise", "27b", Rarity.COMMON, mage.cards.f.FalseDemise.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fatal Lore", 48, Rarity.RARE, mage.cards.f.FatalLore.class)); + cards.add(new SetCardInfo("Feast or Famine", "49a", Rarity.COMMON, mage.cards.f.FeastOrFamine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Feast or Famine", "49b", Rarity.COMMON, mage.cards.f.FeastOrFamine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fevered Strength", "50a", Rarity.COMMON, mage.cards.f.FeveredStrength.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fevered Strength", "50b", Rarity.COMMON, mage.cards.f.FeveredStrength.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Floodwater Dam", 119, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); + cards.add(new SetCardInfo("Force of Will", 28, Rarity.UNCOMMON, mage.cards.f.ForceOfWill.class)); + cards.add(new SetCardInfo("Foresight", "29a", Rarity.COMMON, mage.cards.f.Foresight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foresight", "29b", Rarity.COMMON, mage.cards.f.Foresight.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fyndhorn Druid", "90a", Rarity.COMMON, mage.cards.f.FyndhornDruid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fyndhorn Druid", "90b", Rarity.COMMON, mage.cards.f.FyndhornDruid.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gargantuan Gorilla", 91, Rarity.RARE, mage.cards.g.GargantuanGorilla.class)); + cards.add(new SetCardInfo("Gift of the Woods", "92a", Rarity.COMMON, mage.cards.g.GiftOfTheWoods.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gift of the Woods", "92b", Rarity.COMMON, mage.cards.g.GiftOfTheWoods.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Berserkers", "93a", Rarity.COMMON, mage.cards.g.GorillaBerserkers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Berserkers", "93b", Rarity.COMMON, mage.cards.g.GorillaBerserkers.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Chieftain", "94a", Rarity.COMMON, mage.cards.g.GorillaChieftain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Chieftain", "94b", Rarity.COMMON, mage.cards.g.GorillaChieftain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Shaman", "72a", Rarity.COMMON, mage.cards.g.GorillaShaman.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla Shaman", "72b", Rarity.COMMON, mage.cards.g.GorillaShaman.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla War Cry", "73a", Rarity.COMMON, mage.cards.g.GorillaWarCry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gorilla War Cry", "73b", Rarity.COMMON, mage.cards.g.GorillaWarCry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Guerrilla Tactics", "74a", Rarity.COMMON, mage.cards.g.GuerrillaTactics.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Guerrilla Tactics", "74b", Rarity.COMMON, mage.cards.g.GuerrillaTactics.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gustha's Scepter", 120, Rarity.RARE, mage.cards.g.GusthasScepter.class)); + cards.add(new SetCardInfo("Hail Storm", 95, Rarity.UNCOMMON, mage.cards.h.HailStorm.class)); + cards.add(new SetCardInfo("Heart of Yavimaya", 138, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); + cards.add(new SetCardInfo("Helm of Obedience", 121, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); + cards.add(new SetCardInfo("Inheritance", 4, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); + cards.add(new SetCardInfo("Insidious Bookworms", "51a", Rarity.COMMON, mage.cards.i.InsidiousBookworms.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Insidious Bookworms", "51b", Rarity.COMMON, mage.cards.i.InsidiousBookworms.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Gargoyle", 5, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); + cards.add(new SetCardInfo("Juniper Order Advocate", 6, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); + cards.add(new SetCardInfo("Kaysa", 96, Rarity.RARE, mage.cards.k.Kaysa.class)); + cards.add(new SetCardInfo("Keeper of Tresserhorn", 52, Rarity.RARE, mage.cards.k.KeeperOfTresserhorn.class)); + cards.add(new SetCardInfo("Kjeldoran Escort", "7a", Rarity.COMMON, mage.cards.k.KjeldoranEscort.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kjeldoran Escort", "7b", Rarity.COMMON, mage.cards.k.KjeldoranEscort.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kjeldoran Pride", "9a", Rarity.COMMON, mage.cards.k.KjeldoranPride.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kjeldoran Pride", "9b", Rarity.COMMON, mage.cards.k.KjeldoranPride.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Kjeldoran Home Guard", 8, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Outpost", 139, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); + cards.add(new SetCardInfo("Krovikan Horror", 53, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); + cards.add(new SetCardInfo("Krovikan Plague", 54, Rarity.UNCOMMON, mage.cards.k.KrovikanPlague.class)); + cards.add(new SetCardInfo("Lake of the Dead", 140, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); + cards.add(new SetCardInfo("Lat-Nam's Legacy", "30a", Rarity.COMMON, mage.cards.l.LatNamsLegacy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lat-Nam's Legacy", "30b", Rarity.COMMON, mage.cards.l.LatNamsLegacy.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Library of Lat-Nam", 31, Rarity.RARE, mage.cards.l.LibraryOfLatNam.class)); + cards.add(new SetCardInfo("Lim-Dul's High Guard", "55a", Rarity.COMMON, mage.cards.l.LimDulsHighGuard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lim-Dul's High Guard", "55b", Rarity.COMMON, mage.cards.l.LimDulsHighGuard.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Lim-Dul's Paladin", 108, Rarity.UNCOMMON, mage.cards.l.LimDulsPaladin.class)); + cards.add(new SetCardInfo("Lim-Dul's Vault", 107, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); + cards.add(new SetCardInfo("Lodestone Bauble", 122, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); + cards.add(new SetCardInfo("Lord of Tresserhorn", 112, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); + cards.add(new SetCardInfo("Martyrdom", "10a", Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Martyrdom", "10b", Rarity.COMMON, mage.cards.m.Martyrdom.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Misfortune", 113, Rarity.RARE, mage.cards.m.Misfortune.class)); + cards.add(new SetCardInfo("Mishra's Groundbreaker", 123, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); + cards.add(new SetCardInfo("Misinformation", 56, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); + cards.add(new SetCardInfo("Mystic Compass", 124, Rarity.UNCOMMON, mage.cards.m.MysticCompass.class)); + cards.add(new SetCardInfo("Nature's Blessing", 110, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); + cards.add(new SetCardInfo("Nature's Chosen", 97, Rarity.UNCOMMON, mage.cards.n.NaturesChosen.class)); + cards.add(new SetCardInfo("Nature's Wrath", 98, Rarity.RARE, mage.cards.n.NaturesWrath.class)); + cards.add(new SetCardInfo("Noble Steeds", "11a", Rarity.COMMON, mage.cards.n.NobleSteeds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Noble Steeds", "11b", Rarity.COMMON, mage.cards.n.NobleSteeds.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Omen of Fire", 75, Rarity.RARE, mage.cards.o.OmenOfFire.class)); + cards.add(new SetCardInfo("Phantasmal Fiend", "57a", Rarity.COMMON, mage.cards.p.PhantasmalFiend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phantasmal Fiend", "57b", Rarity.COMMON, mage.cards.p.PhantasmalFiend.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phantasmal Sphere", 32, Rarity.RARE, mage.cards.p.PhantasmalSphere.class)); + cards.add(new SetCardInfo("Phelddagrif", 115, Rarity.RARE, mage.cards.p.Phelddagrif.class)); + cards.add(new SetCardInfo("Phyrexian Boon", "58a", Rarity.COMMON, mage.cards.p.PhyrexianBoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phyrexian Boon", "58b", Rarity.COMMON, mage.cards.p.PhyrexianBoon.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phyrexian Devourer", 125, Rarity.RARE, mage.cards.p.PhyrexianDevourer.class)); + cards.add(new SetCardInfo("Phyrexian Portal", 126, Rarity.RARE, mage.cards.p.PhyrexianPortal.class)); + cards.add(new SetCardInfo("Phyrexian War Beast", "127a", Rarity.COMMON, mage.cards.p.PhyrexianWarBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Phyrexian War Beast", "127b", Rarity.COMMON, mage.cards.p.PhyrexianWarBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Pillage", 76, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); + cards.add(new SetCardInfo("Pyrokinesis", 78, Rarity.UNCOMMON, mage.cards.p.Pyrokinesis.class)); + cards.add(new SetCardInfo("Reinforcements", "12a", Rarity.COMMON, mage.cards.r.Reinforcements.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reinforcements", "12b", Rarity.COMMON, mage.cards.r.Reinforcements.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reprisal", "13a", Rarity.COMMON, mage.cards.r.Reprisal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reprisal", "13b", Rarity.COMMON, mage.cards.r.Reprisal.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ritual of the Machine", 59, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); + cards.add(new SetCardInfo("Rogue Skycaptain", 79, Rarity.RARE, mage.cards.r.RogueSkycaptain.class)); + cards.add(new SetCardInfo("Royal Decree", 14, Rarity.RARE, mage.cards.r.RoyalDecree.class)); + cards.add(new SetCardInfo("Royal Herbalist", "15a", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Royal Herbalist", "15b", Rarity.COMMON, mage.cards.r.RoyalHerbalist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Scarab of the Unseen", 128, Rarity.UNCOMMON, mage.cards.s.ScarabOfTheUnseen.class)); + cards.add(new SetCardInfo("School of the Unseen", 141, Rarity.UNCOMMON, mage.cards.s.SchoolOfTheUnseen.class)); + cards.add(new SetCardInfo("Seasoned Tactician", 17, Rarity.UNCOMMON, mage.cards.s.SeasonedTactician.class)); + cards.add(new SetCardInfo("Sheltered Valley", 142, Rarity.RARE, mage.cards.s.ShelteredValley.class)); + cards.add(new SetCardInfo("Shield Sphere", 129, Rarity.UNCOMMON, mage.cards.s.ShieldSphere.class)); + cards.add(new SetCardInfo("Sol Grail", 130, Rarity.UNCOMMON, mage.cards.s.SolGrail.class)); + cards.add(new SetCardInfo("Soldevi Adnate", "60a", Rarity.COMMON, mage.cards.s.SoldeviAdnate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Adnate", "60b", Rarity.COMMON, mage.cards.s.SoldeviAdnate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Digger", 131, Rarity.RARE, mage.cards.s.SoldeviDigger.class)); + cards.add(new SetCardInfo("Soldevi Excavations", 143, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); + cards.add(new SetCardInfo("Soldevi Heretic", "33a", Rarity.COMMON, mage.cards.s.SoldeviHeretic.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Heretic", "33b", Rarity.COMMON, mage.cards.s.SoldeviHeretic.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Sage", "34a", Rarity.COMMON, mage.cards.s.SoldeviSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Sage", "34b", Rarity.COMMON, mage.cards.s.SoldeviSage.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Sentry", "132a", Rarity.COMMON, mage.cards.s.SoldeviSentry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Sentry", "132b", Rarity.COMMON, mage.cards.s.SoldeviSentry.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Steam Beast", "133a", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldevi Steam Beast", "133b", Rarity.COMMON, mage.cards.s.SoldeviSteamBeast.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Soldier of Fortune", 80, Rarity.UNCOMMON, mage.cards.s.SoldierOfFortune.class)); + cards.add(new SetCardInfo("Spiny Starfish", 35, Rarity.UNCOMMON, mage.cards.s.SpinyStarfish.class)); + cards.add(new SetCardInfo("Splintering Wind", 99, Rarity.RARE, mage.cards.s.SplinteringWind.class)); + cards.add(new SetCardInfo("Stench of Decay", "61a", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Stench of Decay", "61b", Rarity.COMMON, mage.cards.s.StenchOfDecay.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm Cauldron", 134, Rarity.RARE, mage.cards.s.StormCauldron.class)); + cards.add(new SetCardInfo("Storm Crow", "36a", Rarity.COMMON, mage.cards.s.StormCrow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm Crow", "36b", Rarity.COMMON, mage.cards.s.StormCrow.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm Elemental", 37, Rarity.UNCOMMON, mage.cards.s.StormElemental.class)); + cards.add(new SetCardInfo("Storm Shaman", "81a", Rarity.COMMON, mage.cards.s.StormShaman.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Storm Shaman", "81b", Rarity.COMMON, mage.cards.s.StormShaman.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Stromgald Spy", 62, Rarity.UNCOMMON, mage.cards.s.StromgaldSpy.class)); + cards.add(new SetCardInfo("Surge of Strength", 109, Rarity.UNCOMMON, mage.cards.s.SurgeOfStrength.class)); + cards.add(new SetCardInfo("Sustaining Spirit", 18, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); + cards.add(new SetCardInfo("Swamp Mosquito", "63a", Rarity.COMMON, mage.cards.s.SwampMosquito.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp Mosquito", "63b", Rarity.COMMON, mage.cards.s.SwampMosquito.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sworn Defender", 19, Rarity.RARE, mage.cards.s.SwornDefender.class)); + cards.add(new SetCardInfo("Thawing Glaciers", 144, Rarity.RARE, mage.cards.t.ThawingGlaciers.class)); + cards.add(new SetCardInfo("Thought Lash", 39, Rarity.RARE, mage.cards.t.ThoughtLash.class)); + cards.add(new SetCardInfo("Tidal Control", 40, Rarity.RARE, mage.cards.t.TidalControl.class)); + cards.add(new SetCardInfo("Tornado", 101, Rarity.RARE, mage.cards.t.Tornado.class)); + cards.add(new SetCardInfo("Unlikely Alliance", 20, Rarity.UNCOMMON, mage.cards.u.UnlikelyAlliance.class)); + cards.add(new SetCardInfo("Urza's Engine", 135, Rarity.UNCOMMON, mage.cards.u.UrzasEngine.class)); + cards.add(new SetCardInfo("Varchild's Crusader", "82a", Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Varchild's Crusader", "82b", Rarity.COMMON, mage.cards.v.VarchildsCrusader.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Varchild's War-Riders", 83, Rarity.RARE, mage.cards.v.VarchildsWarRiders.class)); + cards.add(new SetCardInfo("Veteran's Voice", "84a", Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Veteran's Voice", "84b", Rarity.COMMON, mage.cards.v.VeteransVoice.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Viscerid Armor", "41a", Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Viscerid Armor", "41b", Rarity.COMMON, mage.cards.v.VisceridArmor.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Viscerid Drone", 42, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); + cards.add(new SetCardInfo("Wandering Mage", 111, Rarity.RARE, mage.cards.w.WanderingMage.class)); + cards.add(new SetCardInfo("Whip Vine", "103a", Rarity.COMMON, mage.cards.w.WhipVine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Whip Vine", "103b", Rarity.COMMON, mage.cards.w.WhipVine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Whirling Catapult", 136, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); + cards.add(new SetCardInfo("Wild Aesthir", "21a", Rarity.COMMON, mage.cards.w.WildAesthir.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Wild Aesthir", "21b", Rarity.COMMON, mage.cards.w.WildAesthir.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Winter's Night", 114, Rarity.RARE, mage.cards.w.WintersNight.class)); + cards.add(new SetCardInfo("Yavimaya Ancients", "104a", Rarity.COMMON, mage.cards.y.YavimayaAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Yavimaya Ancients", "104b", Rarity.COMMON, mage.cards.y.YavimayaAncients.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Yavimaya Ants", 105, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/ArenaNewPlayerExperience.java b/Mage.Sets/src/mage/sets/ArenaNewPlayerExperience.java new file mode 100644 index 0000000000..aaad1327f9 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ArenaNewPlayerExperience.java @@ -0,0 +1,63 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class ArenaNewPlayerExperience extends ExpansionSet { + + private static final ArenaNewPlayerExperience instance = new ArenaNewPlayerExperience(); + + public static ArenaNewPlayerExperience getInstance() { + return instance; + } + + private ArenaNewPlayerExperience() { + super("Arena New Player Experience", "ANA", ExpansionSet.buildDate(2018, 7, 29), SetType.MAGIC_ONLINE); + this.hasBoosters = false; + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Altar's Reap", 24, Rarity.COMMON, mage.cards.a.AltarsReap.class)); + cards.add(new SetCardInfo("Ambition's Cost", 25, Rarity.UNCOMMON, mage.cards.a.AmbitionsCost.class)); + cards.add(new SetCardInfo("Angelic Reward", 1, Rarity.UNCOMMON, mage.cards.a.AngelicReward.class)); + cards.add(new SetCardInfo("Blinding Radiance", 2, Rarity.UNCOMMON, mage.cards.b.BlindingRadiance.class)); + cards.add(new SetCardInfo("Chaos Maw", 36, Rarity.RARE, mage.cards.c.ChaosMaw.class)); + cards.add(new SetCardInfo("Confront the Assault", 3, Rarity.UNCOMMON, mage.cards.c.ConfrontTheAssault.class)); + cards.add(new SetCardInfo("Cruel Cut", 26, Rarity.COMMON, mage.cards.c.CruelCut.class)); + cards.add(new SetCardInfo("Divination", 14, Rarity.COMMON, mage.cards.d.Divination.class)); + cards.add(new SetCardInfo("Doublecast", 37, Rarity.UNCOMMON, mage.cards.d.Doublecast.class)); + cards.add(new SetCardInfo("Feral Roar", 46, Rarity.COMMON, mage.cards.f.FeralRoar.class)); + cards.add(new SetCardInfo("Goblin Bruiser", 39, Rarity.UNCOMMON, mage.cards.g.GoblinBruiser.class)); + cards.add(new SetCardInfo("Goblin Gang Leader", 40, Rarity.UNCOMMON, mage.cards.g.GoblinGangLeader.class)); + cards.add(new SetCardInfo("Goblin Grenade", 41, Rarity.UNCOMMON, mage.cards.g.GoblinGrenade.class)); + cards.add(new SetCardInfo("Inspiring Commander", 5, Rarity.RARE, mage.cards.i.InspiringCommander.class)); + cards.add(new SetCardInfo("Knight's Pledge", 6, Rarity.COMMON, mage.cards.k.KnightsPledge.class)); + cards.add(new SetCardInfo("Loxodon Line Breaker", 7, Rarity.COMMON, mage.cards.l.LoxodonLineBreaker.class)); + cards.add(new SetCardInfo("Miasmic Mummy", 29, Rarity.COMMON, mage.cards.m.MiasmicMummy.class)); + cards.add(new SetCardInfo("Nimble Pilferer", 31, Rarity.COMMON, mage.cards.n.NimblePilferer.class)); + cards.add(new SetCardInfo("Ogre Painbringer", 42, Rarity.RARE, mage.cards.o.OgrePainbringer.class)); + cards.add(new SetCardInfo("Overflowing Insight", 16, Rarity.MYTHIC, mage.cards.o.OverflowingInsight.class)); + cards.add(new SetCardInfo("Raging Goblin", 43, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); + cards.add(new SetCardInfo("Renegade Demon", 33, Rarity.COMMON, mage.cards.r.RenegadeDemon.class)); + cards.add(new SetCardInfo("Rise from the Grave", 34, Rarity.UNCOMMON, mage.cards.r.RiseFromTheGrave.class)); + cards.add(new SetCardInfo("River's Favor", 17, Rarity.COMMON, mage.cards.r.RiversFavor.class)); + cards.add(new SetCardInfo("Rumbling Baloth", 47, Rarity.COMMON, mage.cards.r.RumblingBaloth.class)); + cards.add(new SetCardInfo("Sanctuary Cat", 8, Rarity.COMMON, mage.cards.s.SanctuaryCat.class)); + cards.add(new SetCardInfo("Seismic Rupture", 44, Rarity.UNCOMMON, mage.cards.s.SeismicRupture.class)); + cards.add(new SetCardInfo("Serra Angel", 9, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); + cards.add(new SetCardInfo("Shorecomber Crab", 18, Rarity.COMMON, mage.cards.s.ShorecomberCrab.class)); + cards.add(new SetCardInfo("Shrine Keeper", 10, Rarity.COMMON, mage.cards.s.ShrineKeeper.class)); + cards.add(new SetCardInfo("Soulhunter Rakshasa", 35, Rarity.RARE, mage.cards.s.SoulhunterRakshasa.class)); + cards.add(new SetCardInfo("Spiritual Guardian", 11, Rarity.COMMON, mage.cards.s.SpiritualGuardian.class)); + cards.add(new SetCardInfo("Tactical Advantage", 12, Rarity.COMMON, mage.cards.t.TacticalAdvantage.class)); + cards.add(new SetCardInfo("Take Vengeance", 13, Rarity.COMMON, mage.cards.t.TakeVengeance.class)); + cards.add(new SetCardInfo("Titanic Pelagosaur", 19, Rarity.UNCOMMON, mage.cards.t.TitanicPelagosaur.class)); + cards.add(new SetCardInfo("Treetop Warden", 48, Rarity.COMMON, mage.cards.t.TreetopWarden.class)); + cards.add(new SetCardInfo("Volcanic Dragon", 45, Rarity.UNCOMMON, mage.cards.v.VolcanicDragon.class)); + cards.add(new SetCardInfo("Waterknot", 22, Rarity.COMMON, mage.cards.w.Waterknot.class)); + cards.add(new SetCardInfo("Zephyr Gull", 23, Rarity.COMMON, mage.cards.z.ZephyrGull.class)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/Chronicles.java b/Mage.Sets/src/mage/sets/Chronicles.java index 03cde6e56d..2d84e37739 100644 --- a/Mage.Sets/src/mage/sets/Chronicles.java +++ b/Mage.Sets/src/mage/sets/Chronicles.java @@ -1,147 +1,154 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author LevelX2 - */ -public final class Chronicles extends ExpansionSet { - - private static final Chronicles instance = new Chronicles(); - - public static Chronicles getInstance() { - return instance; - } - - private Chronicles() { - super("Chronicles", "CHR", ExpansionSet.buildDate(1995, 6, 1), SetType.SUPPLEMENTAL); - this.blockName = "Reprint"; - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 9; - this.numBoosterUncommon = 2; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abu Ja'far", 57, Rarity.UNCOMMON, mage.cards.a.AbuJafar.class)); - cards.add(new SetCardInfo("Active Volcano", 43, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); - cards.add(new SetCardInfo("Akron Legionnaire", 58, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); - cards.add(new SetCardInfo("Aladdin", 44, Rarity.UNCOMMON, mage.cards.a.Aladdin.class)); - cards.add(new SetCardInfo("Angelic Voices", 59, Rarity.RARE, mage.cards.a.AngelicVoices.class)); - cards.add(new SetCardInfo("Arcades Sabboth", 106, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); - cards.add(new SetCardInfo("Arena of the Ancients", 71, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); - cards.add(new SetCardInfo("Argothian Pixies", 29, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); - cards.add(new SetCardInfo("Ashnod's Altar", 72, Rarity.COMMON, mage.cards.a.AshnodsAltar.class)); - cards.add(new SetCardInfo("Ashnod's Transmogrant", 73, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); - cards.add(new SetCardInfo("Axelrod Gunnarson", 107, Rarity.RARE, mage.cards.a.AxelrodGunnarson.class)); - cards.add(new SetCardInfo("Ayesha Tanaka", 108, Rarity.RARE, mage.cards.a.AyeshaTanaka.class)); - cards.add(new SetCardInfo("Azure Drake", 15, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); - cards.add(new SetCardInfo("Banshee", 1, Rarity.UNCOMMON, mage.cards.b.Banshee.class)); - cards.add(new SetCardInfo("Barl's Cage", 74, Rarity.RARE, mage.cards.b.BarlsCage.class)); - cards.add(new SetCardInfo("Beasts of Bogardan", 45, Rarity.UNCOMMON, mage.cards.b.BeastsOfBogardan.class)); - cards.add(new SetCardInfo("Blood Moon", 46, Rarity.RARE, mage.cards.b.BloodMoon.class)); - cards.add(new SetCardInfo("Blood of the Martyr", 60, Rarity.UNCOMMON, mage.cards.b.BloodOfTheMartyr.class)); - cards.add(new SetCardInfo("Bog Rats", 2, Rarity.COMMON, mage.cards.b.BogRats.class)); - cards.add(new SetCardInfo("Book of Rass", 75, Rarity.RARE, mage.cards.b.BookOfRass.class)); - cards.add(new SetCardInfo("Boomerang", 16, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Cat Warriors", 30, Rarity.COMMON, mage.cards.c.CatWarriors.class)); - cards.add(new SetCardInfo("Chromium", 109, Rarity.RARE, mage.cards.c.Chromium.class)); - cards.add(new SetCardInfo("City of Brass", 92, Rarity.RARE, mage.cards.c.CityOfBrass.class)); - cards.add(new SetCardInfo("Concordant Crossroads", 32, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); - cards.add(new SetCardInfo("Craw Giant", 33, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); - cards.add(new SetCardInfo("Cuombajj Witches", 3, Rarity.COMMON, mage.cards.c.CuombajjWitches.class)); - cards.add(new SetCardInfo("Cyclone", 34, Rarity.RARE, mage.cards.c.Cyclone.class)); - cards.add(new SetCardInfo("Dakkon Blackblade", 110, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); - cards.add(new SetCardInfo("Dance of Many", 17, Rarity.RARE, mage.cards.d.DanceOfMany.class)); - cards.add(new SetCardInfo("Dandan", 18, Rarity.COMMON, mage.cards.d.Dandan.class)); - cards.add(new SetCardInfo("D'Avenant Archer", 61, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); - cards.add(new SetCardInfo("Divine Offering", 62, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Emerald Dragonfly", 35, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); - cards.add(new SetCardInfo("Erhnam Djinn", 36, Rarity.UNCOMMON, mage.cards.e.ErhnamDjinn.class)); - cards.add(new SetCardInfo("Fallen Angel", 4, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); - cards.add(new SetCardInfo("Feldon's Cane", 77, Rarity.COMMON, mage.cards.f.FeldonsCane.class)); - cards.add(new SetCardInfo("Fire Drake", 47, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); - cards.add(new SetCardInfo("Fishliver Oil", 20, Rarity.COMMON, mage.cards.f.FishliverOil.class)); - cards.add(new SetCardInfo("Flash Flood", 21, Rarity.COMMON, mage.cards.f.FlashFlood.class)); - cards.add(new SetCardInfo("Fountain of Youth", 78, Rarity.COMMON, mage.cards.f.FountainOfYouth.class)); - cards.add(new SetCardInfo("Gabriel Angelfire", 111, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); - cards.add(new SetCardInfo("Gauntlets of Chaos", 79, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); - cards.add(new SetCardInfo("Ghazban Ogre", 37, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); - cards.add(new SetCardInfo("Goblin Artisans", 48, Rarity.UNCOMMON, mage.cards.g.GoblinArtisans.class)); - cards.add(new SetCardInfo("Goblin Digging Team", 49, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); - cards.add(new SetCardInfo("Goblin Shrine", 50, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); - cards.add(new SetCardInfo("Goblins of the Flarg", 51, Rarity.COMMON, mage.cards.g.GoblinsOfTheFlarg.class)); - cards.add(new SetCardInfo("Hasran Ogress", 6, Rarity.COMMON, mage.cards.h.HasranOgress.class)); - cards.add(new SetCardInfo("Hell's Caretaker", 7, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); - cards.add(new SetCardInfo("Horn of Deafening", 80, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); - cards.add(new SetCardInfo("Indestructible Aura", 63, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); - cards.add(new SetCardInfo("Ivory Guardians", 64, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); - cards.add(new SetCardInfo("Jalum Tome", 81, Rarity.RARE, mage.cards.j.JalumTome.class)); - cards.add(new SetCardInfo("Johan", 112, Rarity.RARE, mage.cards.j.Johan.class)); - cards.add(new SetCardInfo("Juxtapose", 22, Rarity.RARE, mage.cards.j.Juxtapose.class)); - cards.add(new SetCardInfo("Keepers of the Faith", 65, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); - cards.add(new SetCardInfo("Kei Takahashi", 113, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); - cards.add(new SetCardInfo("Land's Edge", 52, Rarity.RARE, mage.cards.l.LandsEdge.class)); - cards.add(new SetCardInfo("Living Armor", 83, Rarity.COMMON, mage.cards.l.LivingArmor.class)); - cards.add(new SetCardInfo("Marhault Elsdragon", 114, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); - cards.add(new SetCardInfo("Metamorphosis", 38, Rarity.COMMON, mage.cards.m.Metamorphosis.class)); - cards.add(new SetCardInfo("Mountain Yeti", 53, Rarity.COMMON, mage.cards.m.MountainYeti.class)); - cards.add(new SetCardInfo("Nebuchadnezzar", 115, Rarity.RARE, mage.cards.n.Nebuchadnezzar.class)); - cards.add(new SetCardInfo("Nicol Bolas", 116, Rarity.RARE, mage.cards.n.NicolBolas.class)); - cards.add(new SetCardInfo("Obelisk of Undoing", 84, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); - cards.add(new SetCardInfo("Palladia-Mors", 117, Rarity.RARE, mage.cards.p.PalladiaMors.class)); - cards.add(new SetCardInfo("Petra Sphinx", 66, Rarity.RARE, mage.cards.p.PetraSphinx.class)); - cards.add(new SetCardInfo("Primordial Ooze", 54, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); - cards.add(new SetCardInfo("Rabid Wombat", 39, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); - cards.add(new SetCardInfo("Rakalite", 85, Rarity.RARE, mage.cards.r.Rakalite.class)); - cards.add(new SetCardInfo("Recall", 24, Rarity.UNCOMMON, mage.cards.r.Recall.class)); - cards.add(new SetCardInfo("Remove Soul", 25, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Repentant Blacksmith", 67, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); - cards.add(new SetCardInfo("Revelation", 40, Rarity.RARE, mage.cards.r.Revelation.class)); - cards.add(new SetCardInfo("Rubinia Soulsinger", 118, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); - cards.add(new SetCardInfo("Runesword", 86, Rarity.COMMON, mage.cards.r.Runesword.class)); - cards.add(new SetCardInfo("Safe Haven", 93, Rarity.RARE, mage.cards.s.SafeHaven.class)); - cards.add(new SetCardInfo("Scavenger Folk", 41, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); - cards.add(new SetCardInfo("Sentinel", 87, Rarity.RARE, mage.cards.s.Sentinel.class)); - cards.add(new SetCardInfo("Serpent Generator", 88, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); - cards.add(new SetCardInfo("Shield Wall", 68, Rarity.UNCOMMON, mage.cards.s.ShieldWall.class)); - cards.add(new SetCardInfo("Shimian Night Stalker", 8, Rarity.UNCOMMON, mage.cards.s.ShimianNightStalker.class)); - cards.add(new SetCardInfo("Sivitri Scarzam", 119, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); - cards.add(new SetCardInfo("Sol'kanar the Swamp King", 120, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); - cards.add(new SetCardInfo("Stangg", 121, Rarity.RARE, mage.cards.s.Stangg.class)); - cards.add(new SetCardInfo("Storm Seeker", 42, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); - cards.add(new SetCardInfo("Teleport", 26, Rarity.RARE, mage.cards.t.Teleport.class)); - cards.add(new SetCardInfo("The Fallen", 10, Rarity.UNCOMMON, mage.cards.t.TheFallen.class)); - cards.add(new SetCardInfo("The Wretched", 11, Rarity.RARE, mage.cards.t.TheWretched.class)); - cards.add(new SetCardInfo("Tobias Andrion", 122, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); - cards.add(new SetCardInfo("Tormod's Crypt", 89, Rarity.COMMON, mage.cards.t.TormodsCrypt.class)); - cards.add(new SetCardInfo("Tor Wauki", 123, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); - cards.add(new SetCardInfo("Transmutation", 12, Rarity.COMMON, mage.cards.t.Transmutation.class)); - cards.add(new SetCardInfo("Triassic Egg", 90, Rarity.RARE, mage.cards.t.TriassicEgg.class)); - cards.add(new SetCardInfo("Urza's Mine", 94, Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", 95, Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", 96, Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", 97, Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", 98, Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", 99, Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", 100, Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", 101, Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", 102, Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", 103, Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", 104, Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", 105, Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Vaevictis Asmadi", 124, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); - cards.add(new SetCardInfo("Wall of Heat", 55, Rarity.COMMON, mage.cards.w.WallOfHeat.class)); - cards.add(new SetCardInfo("Wall of Opposition", 56, Rarity.UNCOMMON, mage.cards.w.WallOfOpposition.class)); - cards.add(new SetCardInfo("Wall of Vapor", 27, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); - cards.add(new SetCardInfo("Wall of Wonder", 28, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); - cards.add(new SetCardInfo("War Elephant", 69, Rarity.COMMON, mage.cards.w.WarElephant.class)); - cards.add(new SetCardInfo("Witch Hunter", 70, Rarity.UNCOMMON, mage.cards.w.WitchHunter.class)); - cards.add(new SetCardInfo("Xira Arien", 125, Rarity.RARE, mage.cards.x.XiraArien.class)); - cards.add(new SetCardInfo("Yawgmoth Demon", 14, Rarity.RARE, mage.cards.y.YawgmothDemon.class)); - } - -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author LevelX2 + */ +public final class Chronicles extends ExpansionSet { + + private static final Chronicles instance = new Chronicles(); + + public static Chronicles getInstance() { + return instance; + } + + private Chronicles() { + super("Chronicles", "CHR", ExpansionSet.buildDate(1995, 6, 1), SetType.SUPPLEMENTAL); + this.blockName = "Reprint"; + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 9; + this.numBoosterUncommon = 2; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abu Ja'far", 1, Rarity.UNCOMMON, mage.cards.a.AbuJafar.class)); + cards.add(new SetCardInfo("Active Volcano", 43, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); + cards.add(new SetCardInfo("Akron Legionnaire", 2, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); + cards.add(new SetCardInfo("Aladdin", 44, Rarity.UNCOMMON, mage.cards.a.Aladdin.class)); + cards.add(new SetCardInfo("Angelic Voices", 3, Rarity.RARE, mage.cards.a.AngelicVoices.class)); + cards.add(new SetCardInfo("Arcades Sabboth", 71, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); + cards.add(new SetCardInfo("Arena of the Ancients", 91, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); + cards.add(new SetCardInfo("Argothian Pixies", 57, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); + cards.add(new SetCardInfo("Ashnod's Altar", 92, Rarity.COMMON, mage.cards.a.AshnodsAltar.class)); + cards.add(new SetCardInfo("Ashnod's Transmogrant", 93, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); + cards.add(new SetCardInfo("Axelrod Gunnarson", 72, Rarity.RARE, mage.cards.a.AxelrodGunnarson.class)); + cards.add(new SetCardInfo("Ayesha Tanaka", 73, Rarity.RARE, mage.cards.a.AyeshaTanaka.class)); + cards.add(new SetCardInfo("Azure Drake", 15, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); + cards.add(new SetCardInfo("Banshee", 29, Rarity.UNCOMMON, mage.cards.b.Banshee.class)); + cards.add(new SetCardInfo("Barl's Cage", 94, Rarity.RARE, mage.cards.b.BarlsCage.class)); + cards.add(new SetCardInfo("Beasts of Bogardan", 45, Rarity.UNCOMMON, mage.cards.b.BeastsOfBogardan.class)); + cards.add(new SetCardInfo("Blood Moon", 46, Rarity.RARE, mage.cards.b.BloodMoon.class)); + cards.add(new SetCardInfo("Blood of the Martyr", 4, Rarity.UNCOMMON, mage.cards.b.BloodOfTheMartyr.class)); + cards.add(new SetCardInfo("Bog Rats", 30, Rarity.COMMON, mage.cards.b.BogRats.class)); + cards.add(new SetCardInfo("Book of Rass", 95, Rarity.RARE, mage.cards.b.BookOfRass.class)); + cards.add(new SetCardInfo("Boomerang", 16, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Bronze Horse", 96, Rarity.RARE, mage.cards.b.BronzeHorse.class)); + cards.add(new SetCardInfo("Cat Warriors", 58, Rarity.COMMON, mage.cards.c.CatWarriors.class)); + cards.add(new SetCardInfo("Chromium", 74, Rarity.RARE, mage.cards.c.Chromium.class)); + cards.add(new SetCardInfo("City of Brass", 112, Rarity.RARE, mage.cards.c.CityOfBrass.class)); + cards.add(new SetCardInfo("Cocoon", 59, Rarity.UNCOMMON, mage.cards.c.Cocoon.class)); + cards.add(new SetCardInfo("Concordant Crossroads", 60, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); + cards.add(new SetCardInfo("Craw Giant", 61, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); + cards.add(new SetCardInfo("Cuombajj Witches", 31, Rarity.COMMON, mage.cards.c.CuombajjWitches.class)); + cards.add(new SetCardInfo("Cyclone", 62, Rarity.RARE, mage.cards.c.Cyclone.class)); + cards.add(new SetCardInfo("D'Avenant Archer", 5, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); + cards.add(new SetCardInfo("Dakkon Blackblade", 75, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); + cards.add(new SetCardInfo("Dance of Many", 17, Rarity.RARE, mage.cards.d.DanceOfMany.class)); + cards.add(new SetCardInfo("Dandan", 18, Rarity.COMMON, mage.cards.d.Dandan.class)); + cards.add(new SetCardInfo("Divine Offering", 6, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Emerald Dragonfly", 63, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); + cards.add(new SetCardInfo("Enchantment Alteration", 19, Rarity.UNCOMMON, mage.cards.e.EnchantmentAlteration.class)); + cards.add(new SetCardInfo("Erhnam Djinn", 64, Rarity.UNCOMMON, mage.cards.e.ErhnamDjinn.class)); + cards.add(new SetCardInfo("Fallen Angel", 32, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); + cards.add(new SetCardInfo("Feldon's Cane", 97, Rarity.COMMON, mage.cards.f.FeldonsCane.class)); + cards.add(new SetCardInfo("Fire Drake", 47, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); + cards.add(new SetCardInfo("Fishliver Oil", 20, Rarity.COMMON, mage.cards.f.FishliverOil.class)); + cards.add(new SetCardInfo("Flash Flood", 21, Rarity.COMMON, mage.cards.f.FlashFlood.class)); + cards.add(new SetCardInfo("Fountain of Youth", 98, Rarity.COMMON, mage.cards.f.FountainOfYouth.class)); + cards.add(new SetCardInfo("Gabriel Angelfire", 76, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); + cards.add(new SetCardInfo("Gauntlets of Chaos", 99, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); + cards.add(new SetCardInfo("Ghazban Ogre", 65, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); + cards.add(new SetCardInfo("Giant Slug", 33, Rarity.COMMON, mage.cards.g.GiantSlug.class)); + cards.add(new SetCardInfo("Goblin Artisans", 48, Rarity.UNCOMMON, mage.cards.g.GoblinArtisans.class)); + cards.add(new SetCardInfo("Goblin Digging Team", 49, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); + cards.add(new SetCardInfo("Goblin Shrine", 50, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); + cards.add(new SetCardInfo("Goblins of the Flarg", 51, Rarity.COMMON, mage.cards.g.GoblinsOfTheFlarg.class)); + cards.add(new SetCardInfo("Hasran Ogress", 34, Rarity.COMMON, mage.cards.h.HasranOgress.class)); + cards.add(new SetCardInfo("Hell's Caretaker", 35, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); + cards.add(new SetCardInfo("Horn of Deafening", 100, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); + cards.add(new SetCardInfo("Indestructible Aura", 7, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); + cards.add(new SetCardInfo("Ivory Guardians", 8, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); + cards.add(new SetCardInfo("Jalum Tome", 101, Rarity.RARE, mage.cards.j.JalumTome.class)); + cards.add(new SetCardInfo("Johan", 77, Rarity.RARE, mage.cards.j.Johan.class)); + cards.add(new SetCardInfo("Juxtapose", 22, Rarity.RARE, mage.cards.j.Juxtapose.class)); + cards.add(new SetCardInfo("Keepers of the Faith", 9, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); + cards.add(new SetCardInfo("Kei Takahashi", 78, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); + cards.add(new SetCardInfo("Land's Edge", 52, Rarity.RARE, mage.cards.l.LandsEdge.class)); + cards.add(new SetCardInfo("Living Armor", 103, Rarity.COMMON, mage.cards.l.LivingArmor.class)); + cards.add(new SetCardInfo("Marhault Elsdragon", 79, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); + cards.add(new SetCardInfo("Metamorphosis", 66, Rarity.COMMON, mage.cards.m.Metamorphosis.class)); + cards.add(new SetCardInfo("Mountain Yeti", 53, Rarity.COMMON, mage.cards.m.MountainYeti.class)); + cards.add(new SetCardInfo("Nebuchadnezzar", 80, Rarity.RARE, mage.cards.n.Nebuchadnezzar.class)); + cards.add(new SetCardInfo("Nicol Bolas", 81, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Obelisk of Undoing", 104, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); + cards.add(new SetCardInfo("Palladia-Mors", 82, Rarity.RARE, mage.cards.p.PalladiaMors.class)); + cards.add(new SetCardInfo("Petra Sphinx", 10, Rarity.RARE, mage.cards.p.PetraSphinx.class)); + cards.add(new SetCardInfo("Primordial Ooze", 54, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); + cards.add(new SetCardInfo("Puppet Master", 23, Rarity.UNCOMMON, mage.cards.p.PuppetMaster.class)); + cards.add(new SetCardInfo("Rabid Wombat", 67, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); + cards.add(new SetCardInfo("Rakalite", 105, Rarity.RARE, mage.cards.r.Rakalite.class)); + cards.add(new SetCardInfo("Recall", 24, Rarity.UNCOMMON, mage.cards.r.Recall.class)); + cards.add(new SetCardInfo("Remove Soul", 25, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Repentant Blacksmith", 11, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); + cards.add(new SetCardInfo("Revelation", 68, Rarity.RARE, mage.cards.r.Revelation.class)); + cards.add(new SetCardInfo("Rubinia Soulsinger", 83, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); + cards.add(new SetCardInfo("Runesword", 106, Rarity.COMMON, mage.cards.r.Runesword.class)); + cards.add(new SetCardInfo("Safe Haven", 113, Rarity.RARE, mage.cards.s.SafeHaven.class)); + cards.add(new SetCardInfo("Scavenger Folk", 69, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Sentinel", 107, Rarity.RARE, mage.cards.s.Sentinel.class)); + cards.add(new SetCardInfo("Serpent Generator", 108, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Shield Wall", 12, Rarity.UNCOMMON, mage.cards.s.ShieldWall.class)); + cards.add(new SetCardInfo("Shimian Night Stalker", 36, Rarity.UNCOMMON, mage.cards.s.ShimianNightStalker.class)); + cards.add(new SetCardInfo("Sivitri Scarzam", 84, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); + cards.add(new SetCardInfo("Sol'kanar the Swamp King", 85, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); + cards.add(new SetCardInfo("Stangg", 86, Rarity.RARE, mage.cards.s.Stangg.class)); + cards.add(new SetCardInfo("Storm Seeker", 70, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); + cards.add(new SetCardInfo("Teleport", 26, Rarity.RARE, mage.cards.t.Teleport.class)); + cards.add(new SetCardInfo("The Fallen", 38, Rarity.UNCOMMON, mage.cards.t.TheFallen.class)); + cards.add(new SetCardInfo("The Wretched", 39, Rarity.RARE, mage.cards.t.TheWretched.class)); + cards.add(new SetCardInfo("Tobias Andrion", 87, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); + cards.add(new SetCardInfo("Tor Wauki", 88, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); + cards.add(new SetCardInfo("Tormod's Crypt", 109, Rarity.COMMON, mage.cards.t.TormodsCrypt.class)); + cards.add(new SetCardInfo("Transmutation", 40, Rarity.COMMON, mage.cards.t.Transmutation.class)); + cards.add(new SetCardInfo("Triassic Egg", 110, Rarity.RARE, mage.cards.t.TriassicEgg.class)); + cards.add(new SetCardInfo("Urza's Mine", "114a", Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "114b", Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "114c", Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "114d", Rarity.UNCOMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "115a", Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "115b", Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "115c", Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "115d", Rarity.UNCOMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "116a", Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "116b", Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "116c", Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "116d", Rarity.UNCOMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Vaevictis Asmadi", 89, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); + cards.add(new SetCardInfo("Voodoo Doll", 111, Rarity.RARE, mage.cards.v.VoodooDoll.class)); + cards.add(new SetCardInfo("Wall of Heat", 55, Rarity.COMMON, mage.cards.w.WallOfHeat.class)); + cards.add(new SetCardInfo("Wall of Opposition", 56, Rarity.UNCOMMON, mage.cards.w.WallOfOpposition.class)); + cards.add(new SetCardInfo("Wall of Shadows", 41, Rarity.COMMON, mage.cards.w.WallOfShadows.class)); + cards.add(new SetCardInfo("Wall of Vapor", 27, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); + cards.add(new SetCardInfo("Wall of Wonder", 28, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); + cards.add(new SetCardInfo("War Elephant", 13, Rarity.COMMON, mage.cards.w.WarElephant.class)); + cards.add(new SetCardInfo("Witch Hunter", 14, Rarity.UNCOMMON, mage.cards.w.WitchHunter.class)); + cards.add(new SetCardInfo("Xira Arien", 90, Rarity.RARE, mage.cards.x.XiraArien.class)); + cards.add(new SetCardInfo("Yawgmoth Demon", 42, Rarity.RARE, mage.cards.y.YawgmothDemon.class)); + } + +} diff --git a/Mage.Sets/src/mage/sets/Conspiracy.java b/Mage.Sets/src/mage/sets/Conspiracy.java index 3e561263f1..bc992d2136 100644 --- a/Mage.Sets/src/mage/sets/Conspiracy.java +++ b/Mage.Sets/src/mage/sets/Conspiracy.java @@ -43,6 +43,7 @@ public final class Conspiracy extends ExpansionSet { cards.add(new SetCardInfo("Brainstorm", 91, Rarity.COMMON, mage.cards.b.Brainstorm.class)); cards.add(new SetCardInfo("Breakthrough", 92, Rarity.UNCOMMON, mage.cards.b.Breakthrough.class)); cards.add(new SetCardInfo("Brimstone Volley", 138, Rarity.COMMON, mage.cards.b.BrimstoneVolley.class)); + cards.add(new SetCardInfo("Canal Dredger", 55, Rarity.RARE, mage.cards.c.CanalDredger.class)); cards.add(new SetCardInfo("Charging Rhino", 159, Rarity.COMMON, mage.cards.c.ChargingRhino.class)); cards.add(new SetCardInfo("Chartooth Cougar", 139, Rarity.COMMON, mage.cards.c.ChartoothCougar.class)); cards.add(new SetCardInfo("Cinder Wall", 140, Rarity.COMMON, mage.cards.c.CinderWall.class)); @@ -57,6 +58,7 @@ public final class Conspiracy extends ExpansionSet { cards.add(new SetCardInfo("Custodi Squire", 18, Rarity.COMMON, mage.cards.c.CustodiSquire.class)); cards.add(new SetCardInfo("Dack Fayden", 42, Rarity.MYTHIC, mage.cards.d.DackFayden.class)); cards.add(new SetCardInfo("Dack's Duplicate", 43, Rarity.RARE, mage.cards.d.DacksDuplicate.class)); + cards.add(new SetCardInfo("Deal Broker", 61, Rarity.RARE, mage.cards.d.DealBroker.class)); cards.add(new SetCardInfo("Deathforge Shaman", 141, Rarity.UNCOMMON, mage.cards.d.DeathforgeShaman.class)); cards.add(new SetCardInfo("Deathreap Ritual", 44, Rarity.UNCOMMON, mage.cards.d.DeathreapRitual.class)); cards.add(new SetCardInfo("Deathrender", 197, Rarity.RARE, mage.cards.d.Deathrender.class)); diff --git a/Mage.Sets/src/mage/sets/DuelDecksAnthologyDivineVsDemonic.java b/Mage.Sets/src/mage/sets/DuelDecksAnthologyDivineVsDemonic.java index c7ac43ed64..a25fdfb6e4 100644 --- a/Mage.Sets/src/mage/sets/DuelDecksAnthologyDivineVsDemonic.java +++ b/Mage.Sets/src/mage/sets/DuelDecksAnthologyDivineVsDemonic.java @@ -16,8 +16,7 @@ public final class DuelDecksAnthologyDivineVsDemonic extends ExpansionSet { } private DuelDecksAnthologyDivineVsDemonic() { - super("Duel Decks: Anthology, Divine vs. Demonic", "DD3DVD", ExpansionSet.buildDate(2014, 12, 5), - SetType.SUPPLEMENTAL); + super("Duel Decks: Anthology, Divine vs. Demonic", "DD3DVD", ExpansionSet.buildDate(2014, 12, 5), SetType.SUPPLEMENTAL); this.blockName = "Duel Decks: Anthology"; this.hasBasicLands = true; diff --git a/Mage.Sets/src/mage/sets/Exodus.java b/Mage.Sets/src/mage/sets/Exodus.java index d1091318d4..a7d5dcb6b3 100644 --- a/Mage.Sets/src/mage/sets/Exodus.java +++ b/Mage.Sets/src/mage/sets/Exodus.java @@ -1,165 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Exodus extends ExpansionSet { - - private static final Exodus instance = new Exodus(); - - public static Exodus getInstance() { - return instance; - } - - private Exodus() { - super("Exodus", "EXO", ExpansionSet.buildDate(1998, 6, 15), SetType.EXPANSION); - this.blockName = "Tempest"; - this.parentSet = Tempest.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Allay", 1, Rarity.COMMON, mage.cards.a.Allay.class)); - cards.add(new SetCardInfo("Anarchist", 79, Rarity.COMMON, mage.cards.a.Anarchist.class)); - cards.add(new SetCardInfo("Angelic Blessing", 2, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); - cards.add(new SetCardInfo("Avenging Druid", 105, Rarity.COMMON, mage.cards.a.AvengingDruid.class)); - cards.add(new SetCardInfo("Bequeathal", 106, Rarity.COMMON, mage.cards.b.Bequeathal.class)); - cards.add(new SetCardInfo("Carnophage", 53, Rarity.COMMON, mage.cards.c.Carnophage.class)); - cards.add(new SetCardInfo("Cartographer", 107, Rarity.UNCOMMON, mage.cards.c.Cartographer.class)); - cards.add(new SetCardInfo("Cataclysm", 3, Rarity.RARE, mage.cards.c.Cataclysm.class)); - cards.add(new SetCardInfo("Cat Burglar", 54, Rarity.COMMON, mage.cards.c.CatBurglar.class)); - cards.add(new SetCardInfo("Charging Paladin", 4, Rarity.COMMON, mage.cards.c.ChargingPaladin.class)); - cards.add(new SetCardInfo("Cinder Crawler", 80, Rarity.COMMON, mage.cards.c.CinderCrawler.class)); - cards.add(new SetCardInfo("City of Traitors", 143, Rarity.RARE, mage.cards.c.CityOfTraitors.class)); - cards.add(new SetCardInfo("Coat of Arms", 131, Rarity.RARE, mage.cards.c.CoatOfArms.class)); - cards.add(new SetCardInfo("Convalescence", 5, Rarity.RARE, mage.cards.c.Convalescence.class)); - cards.add(new SetCardInfo("Crashing Boars", 108, Rarity.UNCOMMON, mage.cards.c.CrashingBoars.class)); - cards.add(new SetCardInfo("Culling the Weak", 55, Rarity.COMMON, mage.cards.c.CullingTheWeak.class)); - cards.add(new SetCardInfo("Curiosity", 29, Rarity.UNCOMMON, mage.cards.c.Curiosity.class)); - cards.add(new SetCardInfo("Cursed Flesh", 56, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); - cards.add(new SetCardInfo("Dauthi Cutthroat", 57, Rarity.UNCOMMON, mage.cards.d.DauthiCutthroat.class)); - cards.add(new SetCardInfo("Dauthi Jackal", 58, Rarity.COMMON, mage.cards.d.DauthiJackal.class)); - cards.add(new SetCardInfo("Dauthi Warlord", 59, Rarity.UNCOMMON, mage.cards.d.DauthiWarlord.class)); - cards.add(new SetCardInfo("Death's Duet", 60, Rarity.COMMON, mage.cards.d.DeathsDuet.class)); - cards.add(new SetCardInfo("Dominating Licid", 30, Rarity.RARE, mage.cards.d.DominatingLicid.class)); - cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); - cards.add(new SetCardInfo("Elvish Berserker", 110, Rarity.COMMON, mage.cards.e.ElvishBerserker.class)); - cards.add(new SetCardInfo("Entropic Specter", 61, Rarity.RARE, mage.cards.e.EntropicSpecter.class)); - cards.add(new SetCardInfo("Ephemeron", 31, Rarity.RARE, mage.cards.e.Ephemeron.class)); - cards.add(new SetCardInfo("Equilibrium", 32, Rarity.RARE, mage.cards.e.Equilibrium.class)); - cards.add(new SetCardInfo("Erratic Portal", 132, Rarity.RARE, mage.cards.e.ErraticPortal.class)); - cards.add(new SetCardInfo("Ertai, Wizard Adept", 33, Rarity.RARE, mage.cards.e.ErtaiWizardAdept.class)); - cards.add(new SetCardInfo("Exalted Dragon", 6, Rarity.RARE, mage.cards.e.ExaltedDragon.class)); - cards.add(new SetCardInfo("Fade Away", 34, Rarity.COMMON, mage.cards.f.FadeAway.class)); - cards.add(new SetCardInfo("Fighting Chance", 82, Rarity.RARE, mage.cards.f.FightingChance.class)); - cards.add(new SetCardInfo("Flowstone Flood", 83, Rarity.UNCOMMON, mage.cards.f.FlowstoneFlood.class)); - cards.add(new SetCardInfo("Forbid", 35, Rarity.UNCOMMON, mage.cards.f.Forbid.class)); - cards.add(new SetCardInfo("Fugue", 62, Rarity.UNCOMMON, mage.cards.f.Fugue.class)); - cards.add(new SetCardInfo("Furnace Brood", 84, Rarity.COMMON, mage.cards.f.FurnaceBrood.class)); - cards.add(new SetCardInfo("Hatred", 64, Rarity.RARE, mage.cards.h.Hatred.class)); - cards.add(new SetCardInfo("High Ground", 7, Rarity.UNCOMMON, mage.cards.h.HighGround.class)); - cards.add(new SetCardInfo("Jackalope Herd", 111, Rarity.COMMON, mage.cards.j.JackalopeHerd.class)); - cards.add(new SetCardInfo("Keeper of the Beasts", 112, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheBeasts.class)); - cards.add(new SetCardInfo("Keeper of the Dead", 65, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheDead.class)); - cards.add(new SetCardInfo("Keeper of the Light", 8, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheLight.class)); - cards.add(new SetCardInfo("Keeper of the Mind", 36, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheMind.class)); - cards.add(new SetCardInfo("Killer Whale", 37, Rarity.UNCOMMON, mage.cards.k.KillerWhale.class)); - cards.add(new SetCardInfo("Kor Chant", 9, Rarity.COMMON, mage.cards.k.KorChant.class)); - cards.add(new SetCardInfo("Mage il-Vec", 86, Rarity.COMMON, mage.cards.m.MageIlVec.class)); - cards.add(new SetCardInfo("Manabond", 113, Rarity.RARE, mage.cards.m.Manabond.class)); - cards.add(new SetCardInfo("Mana Breach", 38, Rarity.UNCOMMON, mage.cards.m.ManaBreach.class)); - cards.add(new SetCardInfo("Maniacal Rage", 87, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); - cards.add(new SetCardInfo("Medicine Bag", 133, Rarity.UNCOMMON, mage.cards.m.MedicineBag.class)); - cards.add(new SetCardInfo("Memory Crystal", 134, Rarity.RARE, mage.cards.m.MemoryCrystal.class)); - cards.add(new SetCardInfo("Merfolk Looter", 39, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); - cards.add(new SetCardInfo("Mindless Automaton", 135, Rarity.RARE, mage.cards.m.MindlessAutomaton.class)); - cards.add(new SetCardInfo("Mind Over Matter", 40, Rarity.RARE, mage.cards.m.MindOverMatter.class)); - cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); - cards.add(new SetCardInfo("Mirri, Cat Warrior", 114, Rarity.RARE, mage.cards.m.MirriCatWarrior.class)); - cards.add(new SetCardInfo("Mogg Assassin", 88, Rarity.UNCOMMON, mage.cards.m.MoggAssassin.class)); - cards.add(new SetCardInfo("Nausea", 67, Rarity.COMMON, mage.cards.n.Nausea.class)); - cards.add(new SetCardInfo("Necrologia", 68, Rarity.UNCOMMON, mage.cards.n.Necrologia.class)); - cards.add(new SetCardInfo("Null Brooch", 136, Rarity.RARE, mage.cards.n.NullBrooch.class)); - cards.add(new SetCardInfo("Oath of Druids", 115, Rarity.RARE, mage.cards.o.OathOfDruids.class)); - cards.add(new SetCardInfo("Oath of Ghouls", 69, Rarity.RARE, mage.cards.o.OathOfGhouls.class)); - cards.add(new SetCardInfo("Oath of Lieges", 11, Rarity.RARE, mage.cards.o.OathOfLieges.class)); - cards.add(new SetCardInfo("Oath of Mages", 90, Rarity.RARE, mage.cards.o.OathOfMages.class)); - cards.add(new SetCardInfo("Oath of Scholars", 42, Rarity.RARE, mage.cards.o.OathOfScholars.class)); - cards.add(new SetCardInfo("Ogre Shaman", 91, Rarity.RARE, mage.cards.o.OgreShaman.class)); - cards.add(new SetCardInfo("Onslaught", 92, Rarity.COMMON, mage.cards.o.Onslaught.class)); - cards.add(new SetCardInfo("Paladin en-Vec", 12, Rarity.RARE, mage.cards.p.PaladinEnVec.class)); - cards.add(new SetCardInfo("Pandemonium", 93, Rarity.RARE, mage.cards.p.Pandemonium.class)); - cards.add(new SetCardInfo("Peace of Mind", 13, Rarity.UNCOMMON, mage.cards.p.PeaceOfMind.class)); - cards.add(new SetCardInfo("Pegasus Stampede", 14, Rarity.UNCOMMON, mage.cards.p.PegasusStampede.class)); - cards.add(new SetCardInfo("Penance", 15, Rarity.UNCOMMON, mage.cards.p.Penance.class)); - cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); - cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); - cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); - cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); - cards.add(new SetCardInfo("Price of Progress", 95, Rarity.UNCOMMON, mage.cards.p.PriceOfProgress.class)); - cards.add(new SetCardInfo("Pygmy Troll", 118, Rarity.COMMON, mage.cards.p.PygmyTroll.class)); - cards.add(new SetCardInfo("Rabid Wolverines", 119, Rarity.COMMON, mage.cards.r.RabidWolverines.class)); - cards.add(new SetCardInfo("Raging Goblin", 96, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); - cards.add(new SetCardInfo("Ravenous Baboons", 97, Rarity.RARE, mage.cards.r.RavenousBaboons.class)); - cards.add(new SetCardInfo("Reaping the Rewards", 16, Rarity.COMMON, mage.cards.r.ReapingTheRewards.class)); - cards.add(new SetCardInfo("Reckless Ogre", 98, Rarity.COMMON, mage.cards.r.RecklessOgre.class)); - cards.add(new SetCardInfo("Reclaim", 120, Rarity.COMMON, mage.cards.r.Reclaim.class)); - cards.add(new SetCardInfo("Reconnaissance", 17, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class)); - cards.add(new SetCardInfo("Recurring Nightmare", 72, Rarity.RARE, mage.cards.r.RecurringNightmare.class)); - cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); - cards.add(new SetCardInfo("Robe of Mirrors", 43, Rarity.COMMON, mage.cards.r.RobeOfMirrors.class)); - cards.add(new SetCardInfo("Rootwater Alligator", 122, Rarity.COMMON, mage.cards.r.RootwaterAlligator.class)); - cards.add(new SetCardInfo("Rootwater Mystic", 44, Rarity.COMMON, mage.cards.r.RootwaterMystic.class)); - cards.add(new SetCardInfo("Sabertooth Wyvern", 99, Rarity.UNCOMMON, mage.cards.s.SabertoothWyvern.class)); - cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); - cards.add(new SetCardInfo("Scare Tactics", 73, Rarity.COMMON, mage.cards.s.ScareTactics.class)); - cards.add(new SetCardInfo("School of Piranha", 45, Rarity.COMMON, mage.cards.s.SchoolOfPiranha.class)); - cards.add(new SetCardInfo("Scrivener", 46, Rarity.UNCOMMON, mage.cards.s.Scrivener.class)); - cards.add(new SetCardInfo("Seismic Assault", 101, Rarity.RARE, mage.cards.s.SeismicAssault.class)); - cards.add(new SetCardInfo("Shackles", 18, Rarity.COMMON, mage.cards.s.Shackles.class)); - cards.add(new SetCardInfo("Shattering Pulse", 102, Rarity.COMMON, mage.cards.s.ShatteringPulse.class)); - cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); - cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class)); - cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class)); - cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class)); - cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class)); - cards.add(new SetCardInfo("Soltari Visionary", 20, Rarity.COMMON, mage.cards.s.SoltariVisionary.class)); - cards.add(new SetCardInfo("Song of Serenity", 125, Rarity.UNCOMMON, mage.cards.s.SongOfSerenity.class)); - cards.add(new SetCardInfo("Sonic Burst", 103, Rarity.COMMON, mage.cards.s.SonicBurst.class)); - cards.add(new SetCardInfo("Soul Warden", 21, Rarity.COMMON, mage.cards.s.SoulWarden.class)); - cards.add(new SetCardInfo("Spellbook", 138, Rarity.UNCOMMON, mage.cards.s.Spellbook.class)); - cards.add(new SetCardInfo("Spellshock", 104, Rarity.UNCOMMON, mage.cards.s.Spellshock.class)); - cards.add(new SetCardInfo("Sphere of Resistance", 139, Rarity.RARE, mage.cards.s.SphereOfResistance.class)); - cards.add(new SetCardInfo("Spike Cannibal", 75, Rarity.UNCOMMON, mage.cards.s.SpikeCannibal.class)); - cards.add(new SetCardInfo("Spike Hatcher", 126, Rarity.RARE, mage.cards.s.SpikeHatcher.class)); - cards.add(new SetCardInfo("Spike Rogue", 127, Rarity.UNCOMMON, mage.cards.s.SpikeRogue.class)); - cards.add(new SetCardInfo("Spike Weaver", 128, Rarity.RARE, mage.cards.s.SpikeWeaver.class)); - cards.add(new SetCardInfo("Standing Troops", 22, Rarity.COMMON, mage.cards.s.StandingTroops.class)); - cards.add(new SetCardInfo("Survival of the Fittest", 129, Rarity.RARE, mage.cards.s.SurvivalOfTheFittest.class)); - cards.add(new SetCardInfo("Thalakos Drifters", 47, Rarity.RARE, mage.cards.t.ThalakosDrifters.class)); - cards.add(new SetCardInfo("Thalakos Scout", 48, Rarity.COMMON, mage.cards.t.ThalakosScout.class)); - cards.add(new SetCardInfo("Theft of Dreams", 49, Rarity.COMMON, mage.cards.t.TheftOfDreams.class)); - cards.add(new SetCardInfo("Thopter Squadron", 140, Rarity.RARE, mage.cards.t.ThopterSquadron.class)); - cards.add(new SetCardInfo("Thrull Surgeon", 76, Rarity.COMMON, mage.cards.t.ThrullSurgeon.class)); - cards.add(new SetCardInfo("Transmogrifying Licid", 141, Rarity.UNCOMMON, mage.cards.t.TransmogrifyingLicid.class)); - cards.add(new SetCardInfo("Treasure Hunter", 23, Rarity.UNCOMMON, mage.cards.t.TreasureHunter.class)); - cards.add(new SetCardInfo("Treasure Trove", 50, Rarity.UNCOMMON, mage.cards.t.TreasureTrove.class)); - cards.add(new SetCardInfo("Vampire Hounds", 77, Rarity.COMMON, mage.cards.v.VampireHounds.class)); - cards.add(new SetCardInfo("Wall of Nets", 24, Rarity.RARE, mage.cards.w.WallOfNets.class)); - cards.add(new SetCardInfo("Wayward Soul", 51, Rarity.COMMON, mage.cards.w.WaywardSoul.class)); - cards.add(new SetCardInfo("Welkin Hawk", 25, Rarity.COMMON, mage.cards.w.WelkinHawk.class)); - cards.add(new SetCardInfo("Whiptongue Frog", 52, Rarity.COMMON, mage.cards.w.WhiptongueFrog.class)); - cards.add(new SetCardInfo("Wood Elves", 130, Rarity.COMMON, mage.cards.w.WoodElves.class)); - cards.add(new SetCardInfo("Workhorse", 142, Rarity.RARE, mage.cards.w.Workhorse.class)); - cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Exodus extends ExpansionSet { + + private static final Exodus instance = new Exodus(); + + public static Exodus getInstance() { + return instance; + } + + private Exodus() { + super("Exodus", "EXO", ExpansionSet.buildDate(1998, 6, 15), SetType.EXPANSION); + this.blockName = "Tempest"; + this.parentSet = Tempest.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Aether Tide", 27, Rarity.COMMON, mage.cards.a.AetherTide.class)); + cards.add(new SetCardInfo("Allay", 1, Rarity.COMMON, mage.cards.a.Allay.class)); + cards.add(new SetCardInfo("Anarchist", 79, Rarity.COMMON, mage.cards.a.Anarchist.class)); + cards.add(new SetCardInfo("Angelic Blessing", 2, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); + cards.add(new SetCardInfo("Avenging Druid", 105, Rarity.COMMON, mage.cards.a.AvengingDruid.class)); + cards.add(new SetCardInfo("Bequeathal", 106, Rarity.COMMON, mage.cards.b.Bequeathal.class)); + cards.add(new SetCardInfo("Carnophage", 53, Rarity.COMMON, mage.cards.c.Carnophage.class)); + cards.add(new SetCardInfo("Cartographer", 107, Rarity.UNCOMMON, mage.cards.c.Cartographer.class)); + cards.add(new SetCardInfo("Cataclysm", 3, Rarity.RARE, mage.cards.c.Cataclysm.class)); + cards.add(new SetCardInfo("Cat Burglar", 54, Rarity.COMMON, mage.cards.c.CatBurglar.class)); + cards.add(new SetCardInfo("Charging Paladin", 4, Rarity.COMMON, mage.cards.c.ChargingPaladin.class)); + cards.add(new SetCardInfo("Cinder Crawler", 80, Rarity.COMMON, mage.cards.c.CinderCrawler.class)); + cards.add(new SetCardInfo("City of Traitors", 143, Rarity.RARE, mage.cards.c.CityOfTraitors.class)); + cards.add(new SetCardInfo("Coat of Arms", 131, Rarity.RARE, mage.cards.c.CoatOfArms.class)); + cards.add(new SetCardInfo("Convalescence", 5, Rarity.RARE, mage.cards.c.Convalescence.class)); + cards.add(new SetCardInfo("Crashing Boars", 108, Rarity.UNCOMMON, mage.cards.c.CrashingBoars.class)); + cards.add(new SetCardInfo("Culling the Weak", 55, Rarity.COMMON, mage.cards.c.CullingTheWeak.class)); + cards.add(new SetCardInfo("Cunning", 28, Rarity.COMMON, mage.cards.c.Cunning.class)); + cards.add(new SetCardInfo("Curiosity", 29, Rarity.UNCOMMON, mage.cards.c.Curiosity.class)); + cards.add(new SetCardInfo("Cursed Flesh", 56, Rarity.COMMON, mage.cards.c.CursedFlesh.class)); + cards.add(new SetCardInfo("Dauthi Cutthroat", 57, Rarity.UNCOMMON, mage.cards.d.DauthiCutthroat.class)); + cards.add(new SetCardInfo("Dauthi Jackal", 58, Rarity.COMMON, mage.cards.d.DauthiJackal.class)); + cards.add(new SetCardInfo("Dauthi Warlord", 59, Rarity.UNCOMMON, mage.cards.d.DauthiWarlord.class)); + cards.add(new SetCardInfo("Death's Duet", 60, Rarity.COMMON, mage.cards.d.DeathsDuet.class)); + cards.add(new SetCardInfo("Dizzying Gaze", 81, Rarity.COMMON, mage.cards.d.DizzyingGaze.class)); + cards.add(new SetCardInfo("Dominating Licid", 30, Rarity.RARE, mage.cards.d.DominatingLicid.class)); + cards.add(new SetCardInfo("Elven Palisade", 109, Rarity.UNCOMMON, mage.cards.e.ElvenPalisade.class)); + cards.add(new SetCardInfo("Elvish Berserker", 110, Rarity.COMMON, mage.cards.e.ElvishBerserker.class)); + cards.add(new SetCardInfo("Entropic Specter", 61, Rarity.RARE, mage.cards.e.EntropicSpecter.class)); + cards.add(new SetCardInfo("Ephemeron", 31, Rarity.RARE, mage.cards.e.Ephemeron.class)); + cards.add(new SetCardInfo("Equilibrium", 32, Rarity.RARE, mage.cards.e.Equilibrium.class)); + cards.add(new SetCardInfo("Erratic Portal", 132, Rarity.RARE, mage.cards.e.ErraticPortal.class)); + cards.add(new SetCardInfo("Ertai, Wizard Adept", 33, Rarity.RARE, mage.cards.e.ErtaiWizardAdept.class)); + cards.add(new SetCardInfo("Exalted Dragon", 6, Rarity.RARE, mage.cards.e.ExaltedDragon.class)); + cards.add(new SetCardInfo("Fade Away", 34, Rarity.COMMON, mage.cards.f.FadeAway.class)); + cards.add(new SetCardInfo("Fighting Chance", 82, Rarity.RARE, mage.cards.f.FightingChance.class)); + cards.add(new SetCardInfo("Flowstone Flood", 83, Rarity.UNCOMMON, mage.cards.f.FlowstoneFlood.class)); + cards.add(new SetCardInfo("Forbid", 35, Rarity.UNCOMMON, mage.cards.f.Forbid.class)); + cards.add(new SetCardInfo("Fugue", 62, Rarity.UNCOMMON, mage.cards.f.Fugue.class)); + cards.add(new SetCardInfo("Furnace Brood", 84, Rarity.COMMON, mage.cards.f.FurnaceBrood.class)); + cards.add(new SetCardInfo("Grollub", 63, Rarity.COMMON, mage.cards.g.Grollub.class)); + cards.add(new SetCardInfo("Hatred", 64, Rarity.RARE, mage.cards.h.Hatred.class)); + cards.add(new SetCardInfo("High Ground", 7, Rarity.UNCOMMON, mage.cards.h.HighGround.class)); + cards.add(new SetCardInfo("Jackalope Herd", 111, Rarity.COMMON, mage.cards.j.JackalopeHerd.class)); + cards.add(new SetCardInfo("Keeper of the Beasts", 112, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheBeasts.class)); + cards.add(new SetCardInfo("Keeper of the Dead", 65, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheDead.class)); + cards.add(new SetCardInfo("Keeper of the Flame", 85, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheFlame.class)); + cards.add(new SetCardInfo("Keeper of the Light", 8, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheLight.class)); + cards.add(new SetCardInfo("Keeper of the Mind", 36, Rarity.UNCOMMON, mage.cards.k.KeeperOfTheMind.class)); + cards.add(new SetCardInfo("Killer Whale", 37, Rarity.UNCOMMON, mage.cards.k.KillerWhale.class)); + cards.add(new SetCardInfo("Kor Chant", 9, Rarity.COMMON, mage.cards.k.KorChant.class)); + cards.add(new SetCardInfo("Limited Resources", 10, Rarity.RARE, mage.cards.l.LimitedResources.class)); + cards.add(new SetCardInfo("Mage il-Vec", 86, Rarity.COMMON, mage.cards.m.MageIlVec.class)); + cards.add(new SetCardInfo("Manabond", 113, Rarity.RARE, mage.cards.m.Manabond.class)); + cards.add(new SetCardInfo("Mana Breach", 38, Rarity.UNCOMMON, mage.cards.m.ManaBreach.class)); + cards.add(new SetCardInfo("Maniacal Rage", 87, Rarity.COMMON, mage.cards.m.ManiacalRage.class)); + cards.add(new SetCardInfo("Medicine Bag", 133, Rarity.UNCOMMON, mage.cards.m.MedicineBag.class)); + cards.add(new SetCardInfo("Memory Crystal", 134, Rarity.RARE, mage.cards.m.MemoryCrystal.class)); + cards.add(new SetCardInfo("Merfolk Looter", 39, Rarity.COMMON, mage.cards.m.MerfolkLooter.class)); + cards.add(new SetCardInfo("Mind Maggots", 66, Rarity.UNCOMMON, mage.cards.m.MindMaggots.class)); + cards.add(new SetCardInfo("Mindless Automaton", 135, Rarity.RARE, mage.cards.m.MindlessAutomaton.class)); + cards.add(new SetCardInfo("Mind Over Matter", 40, Rarity.RARE, mage.cards.m.MindOverMatter.class)); + cards.add(new SetCardInfo("Mirozel", 41, Rarity.UNCOMMON, mage.cards.m.Mirozel.class)); + cards.add(new SetCardInfo("Mirri, Cat Warrior", 114, Rarity.RARE, mage.cards.m.MirriCatWarrior.class)); + cards.add(new SetCardInfo("Mogg Assassin", 88, Rarity.UNCOMMON, mage.cards.m.MoggAssassin.class)); + cards.add(new SetCardInfo("Monstrous Hound", 89, Rarity.RARE, mage.cards.m.MonstrousHound.class)); + cards.add(new SetCardInfo("Nausea", 67, Rarity.COMMON, mage.cards.n.Nausea.class)); + cards.add(new SetCardInfo("Necrologia", 68, Rarity.UNCOMMON, mage.cards.n.Necrologia.class)); + cards.add(new SetCardInfo("Null Brooch", 136, Rarity.RARE, mage.cards.n.NullBrooch.class)); + cards.add(new SetCardInfo("Oath of Druids", 115, Rarity.RARE, mage.cards.o.OathOfDruids.class)); + cards.add(new SetCardInfo("Oath of Ghouls", 69, Rarity.RARE, mage.cards.o.OathOfGhouls.class)); + cards.add(new SetCardInfo("Oath of Lieges", 11, Rarity.RARE, mage.cards.o.OathOfLieges.class)); + cards.add(new SetCardInfo("Oath of Mages", 90, Rarity.RARE, mage.cards.o.OathOfMages.class)); + cards.add(new SetCardInfo("Oath of Scholars", 42, Rarity.RARE, mage.cards.o.OathOfScholars.class)); + cards.add(new SetCardInfo("Ogre Shaman", 91, Rarity.RARE, mage.cards.o.OgreShaman.class)); + cards.add(new SetCardInfo("Onslaught", 92, Rarity.COMMON, mage.cards.o.Onslaught.class)); + cards.add(new SetCardInfo("Paladin en-Vec", 12, Rarity.RARE, mage.cards.p.PaladinEnVec.class)); + cards.add(new SetCardInfo("Pandemonium", 93, Rarity.RARE, mage.cards.p.Pandemonium.class)); + cards.add(new SetCardInfo("Paroxysm", 94, Rarity.UNCOMMON, mage.cards.p.Paroxysm.class)); + cards.add(new SetCardInfo("Peace of Mind", 13, Rarity.UNCOMMON, mage.cards.p.PeaceOfMind.class)); + cards.add(new SetCardInfo("Pegasus Stampede", 14, Rarity.UNCOMMON, mage.cards.p.PegasusStampede.class)); + cards.add(new SetCardInfo("Penance", 15, Rarity.UNCOMMON, mage.cards.p.Penance.class)); + cards.add(new SetCardInfo("Pit Spawn", 70, Rarity.RARE, mage.cards.p.PitSpawn.class)); + cards.add(new SetCardInfo("Plaguebearer", 71, Rarity.RARE, mage.cards.p.Plaguebearer.class)); + cards.add(new SetCardInfo("Plated Rootwalla", 116, Rarity.COMMON, mage.cards.p.PlatedRootwalla.class)); + cards.add(new SetCardInfo("Predatory Hunger", 117, Rarity.COMMON, mage.cards.p.PredatoryHunger.class)); + cards.add(new SetCardInfo("Price of Progress", 95, Rarity.UNCOMMON, mage.cards.p.PriceOfProgress.class)); + cards.add(new SetCardInfo("Pygmy Troll", 118, Rarity.COMMON, mage.cards.p.PygmyTroll.class)); + cards.add(new SetCardInfo("Rabid Wolverines", 119, Rarity.COMMON, mage.cards.r.RabidWolverines.class)); + cards.add(new SetCardInfo("Raging Goblin", 96, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); + cards.add(new SetCardInfo("Ravenous Baboons", 97, Rarity.RARE, mage.cards.r.RavenousBaboons.class)); + cards.add(new SetCardInfo("Reaping the Rewards", 16, Rarity.COMMON, mage.cards.r.ReapingTheRewards.class)); + cards.add(new SetCardInfo("Reckless Ogre", 98, Rarity.COMMON, mage.cards.r.RecklessOgre.class)); + cards.add(new SetCardInfo("Reclaim", 120, Rarity.COMMON, mage.cards.r.Reclaim.class)); + cards.add(new SetCardInfo("Reconnaissance", 17, Rarity.UNCOMMON, mage.cards.r.Reconnaissance.class)); + cards.add(new SetCardInfo("Recurring Nightmare", 72, Rarity.RARE, mage.cards.r.RecurringNightmare.class)); + cards.add(new SetCardInfo("Resuscitate", 121, Rarity.UNCOMMON, mage.cards.r.Resuscitate.class)); + cards.add(new SetCardInfo("Robe of Mirrors", 43, Rarity.COMMON, mage.cards.r.RobeOfMirrors.class)); + cards.add(new SetCardInfo("Rootwater Alligator", 122, Rarity.COMMON, mage.cards.r.RootwaterAlligator.class)); + cards.add(new SetCardInfo("Rootwater Mystic", 44, Rarity.COMMON, mage.cards.r.RootwaterMystic.class)); + cards.add(new SetCardInfo("Sabertooth Wyvern", 99, Rarity.UNCOMMON, mage.cards.s.SabertoothWyvern.class)); + cards.add(new SetCardInfo("Scalding Salamander", 100, Rarity.UNCOMMON, mage.cards.s.ScaldingSalamander.class)); + cards.add(new SetCardInfo("Scare Tactics", 73, Rarity.COMMON, mage.cards.s.ScareTactics.class)); + cards.add(new SetCardInfo("School of Piranha", 45, Rarity.COMMON, mage.cards.s.SchoolOfPiranha.class)); + cards.add(new SetCardInfo("Scrivener", 46, Rarity.UNCOMMON, mage.cards.s.Scrivener.class)); + cards.add(new SetCardInfo("Seismic Assault", 101, Rarity.RARE, mage.cards.s.SeismicAssault.class)); + cards.add(new SetCardInfo("Shackles", 18, Rarity.COMMON, mage.cards.s.Shackles.class)); + cards.add(new SetCardInfo("Shattering Pulse", 102, Rarity.COMMON, mage.cards.s.ShatteringPulse.class)); + cards.add(new SetCardInfo("Shield Mate", 19, Rarity.COMMON, mage.cards.s.ShieldMate.class)); + cards.add(new SetCardInfo("Skyshaper", 137, Rarity.UNCOMMON, mage.cards.s.Skyshaper.class)); + cards.add(new SetCardInfo("Skyshroud Elite", 123, Rarity.UNCOMMON, mage.cards.s.SkyshroudElite.class)); + cards.add(new SetCardInfo("Skyshroud War Beast", 124, Rarity.RARE, mage.cards.s.SkyshroudWarBeast.class)); + cards.add(new SetCardInfo("Slaughter", 74, Rarity.UNCOMMON, mage.cards.s.Slaughter.class)); + cards.add(new SetCardInfo("Soltari Visionary", 20, Rarity.COMMON, mage.cards.s.SoltariVisionary.class)); + cards.add(new SetCardInfo("Song of Serenity", 125, Rarity.UNCOMMON, mage.cards.s.SongOfSerenity.class)); + cards.add(new SetCardInfo("Sonic Burst", 103, Rarity.COMMON, mage.cards.s.SonicBurst.class)); + cards.add(new SetCardInfo("Soul Warden", 21, Rarity.COMMON, mage.cards.s.SoulWarden.class)); + cards.add(new SetCardInfo("Spellbook", 138, Rarity.UNCOMMON, mage.cards.s.Spellbook.class)); + cards.add(new SetCardInfo("Spellshock", 104, Rarity.UNCOMMON, mage.cards.s.Spellshock.class)); + cards.add(new SetCardInfo("Sphere of Resistance", 139, Rarity.RARE, mage.cards.s.SphereOfResistance.class)); + cards.add(new SetCardInfo("Spike Cannibal", 75, Rarity.UNCOMMON, mage.cards.s.SpikeCannibal.class)); + cards.add(new SetCardInfo("Spike Hatcher", 126, Rarity.RARE, mage.cards.s.SpikeHatcher.class)); + cards.add(new SetCardInfo("Spike Rogue", 127, Rarity.UNCOMMON, mage.cards.s.SpikeRogue.class)); + cards.add(new SetCardInfo("Spike Weaver", 128, Rarity.RARE, mage.cards.s.SpikeWeaver.class)); + cards.add(new SetCardInfo("Standing Troops", 22, Rarity.COMMON, mage.cards.s.StandingTroops.class)); + cards.add(new SetCardInfo("Survival of the Fittest", 129, Rarity.RARE, mage.cards.s.SurvivalOfTheFittest.class)); + cards.add(new SetCardInfo("Thalakos Drifters", 47, Rarity.RARE, mage.cards.t.ThalakosDrifters.class)); + cards.add(new SetCardInfo("Thalakos Scout", 48, Rarity.COMMON, mage.cards.t.ThalakosScout.class)); + cards.add(new SetCardInfo("Theft of Dreams", 49, Rarity.COMMON, mage.cards.t.TheftOfDreams.class)); + cards.add(new SetCardInfo("Thopter Squadron", 140, Rarity.RARE, mage.cards.t.ThopterSquadron.class)); + cards.add(new SetCardInfo("Thrull Surgeon", 76, Rarity.COMMON, mage.cards.t.ThrullSurgeon.class)); + cards.add(new SetCardInfo("Transmogrifying Licid", 141, Rarity.UNCOMMON, mage.cards.t.TransmogrifyingLicid.class)); + cards.add(new SetCardInfo("Treasure Hunter", 23, Rarity.UNCOMMON, mage.cards.t.TreasureHunter.class)); + cards.add(new SetCardInfo("Treasure Trove", 50, Rarity.UNCOMMON, mage.cards.t.TreasureTrove.class)); + cards.add(new SetCardInfo("Vampire Hounds", 77, Rarity.COMMON, mage.cards.v.VampireHounds.class)); + cards.add(new SetCardInfo("Volrath's Dungeon", 78, Rarity.RARE, mage.cards.v.VolrathsDungeon.class)); + cards.add(new SetCardInfo("Wall of Nets", 24, Rarity.RARE, mage.cards.w.WallOfNets.class)); + cards.add(new SetCardInfo("Wayward Soul", 51, Rarity.COMMON, mage.cards.w.WaywardSoul.class)); + cards.add(new SetCardInfo("Welkin Hawk", 25, Rarity.COMMON, mage.cards.w.WelkinHawk.class)); + cards.add(new SetCardInfo("Whiptongue Frog", 52, Rarity.COMMON, mage.cards.w.WhiptongueFrog.class)); + cards.add(new SetCardInfo("Wood Elves", 130, Rarity.COMMON, mage.cards.w.WoodElves.class)); + cards.add(new SetCardInfo("Workhorse", 142, Rarity.RARE, mage.cards.w.Workhorse.class)); + cards.add(new SetCardInfo("Zealots en-Dal", 26, Rarity.UNCOMMON, mage.cards.z.ZealotsEnDal.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/FifthEdition.java b/Mage.Sets/src/mage/sets/FifthEdition.java index fcef5f5123..5c5fb5f6df 100644 --- a/Mage.Sets/src/mage/sets/FifthEdition.java +++ b/Mage.Sets/src/mage/sets/FifthEdition.java @@ -1,465 +1,468 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -public final class FifthEdition extends ExpansionSet { - - private static final FifthEdition instance = new FifthEdition(); - - public static FifthEdition getInstance() { - return instance; - } - - private FifthEdition() { - super("Fifth Edition", "5ED", ExpansionSet.buildDate(1997, 3, 1), SetType.CORE); - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); - cards.add(new SetCardInfo("Abyssal Specter", 139, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); - cards.add(new SetCardInfo("Adarkar Wastes", 410, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); - cards.add(new SetCardInfo("Aether Storm", 70, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); - cards.add(new SetCardInfo("Air Elemental", 71, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Akron Legionnaire", 2, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); - cards.add(new SetCardInfo("Alabaster Potion", 3, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); - cards.add(new SetCardInfo("Aladdin's Ring", 346, Rarity.RARE, mage.cards.a.AladdinsRing.class)); - cards.add(new SetCardInfo("Ambush Party", 208, Rarity.COMMON, mage.cards.a.AmbushParty.class)); - cards.add(new SetCardInfo("Amulet of Kroog", 347, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); - cards.add(new SetCardInfo("An-Havva Constable", 277, Rarity.RARE, mage.cards.a.AnHavvaConstable.class)); - cards.add(new SetCardInfo("Angry Mob", 4, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); - cards.add(new SetCardInfo("Animate Dead", 140, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); - cards.add(new SetCardInfo("Animate Wall", 5, Rarity.RARE, mage.cards.a.AnimateWall.class)); - cards.add(new SetCardInfo("Ankh of Mishra", 348, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); - cards.add(new SetCardInfo("Anti-Magic Aura", 72, Rarity.UNCOMMON, mage.cards.a.AntiMagicAura.class)); - cards.add(new SetCardInfo("Arenson's Aura", 6, Rarity.UNCOMMON, mage.cards.a.ArensonsAura.class)); - cards.add(new SetCardInfo("Armageddon", 7, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Armor of Faith", 8, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Ashes to Ashes", 141, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); - cards.add(new SetCardInfo("Ashnod's Altar", 349, Rarity.UNCOMMON, mage.cards.a.AshnodsAltar.class)); - cards.add(new SetCardInfo("Ashnod's Transmogrant", 350, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); - cards.add(new SetCardInfo("Aspect of Wolf", 278, Rarity.RARE, mage.cards.a.AspectOfWolf.class)); - cards.add(new SetCardInfo("Atog", 209, Rarity.UNCOMMON, mage.cards.a.Atog.class)); - cards.add(new SetCardInfo("Aurochs", 279, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Aysen Bureaucrats", 9, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); - cards.add(new SetCardInfo("Azure Drake", 73, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); - cards.add(new SetCardInfo("Bad Moon", 142, Rarity.RARE, mage.cards.b.BadMoon.class)); - cards.add(new SetCardInfo("Ball Lightning", 210, Rarity.RARE, mage.cards.b.BallLightning.class)); - cards.add(new SetCardInfo("Barbed Sextant", 351, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Barl's Cage", 352, Rarity.RARE, mage.cards.b.BarlsCage.class)); - cards.add(new SetCardInfo("Battering Ram", 353, Rarity.COMMON, mage.cards.b.BatteringRam.class)); - cards.add(new SetCardInfo("Benalish Hero", 10, Rarity.COMMON, mage.cards.b.BenalishHero.class)); - cards.add(new SetCardInfo("Binding Grasp", 74, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Bird Maiden", 211, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); - cards.add(new SetCardInfo("Birds of Paradise", 280, Rarity.RARE, mage.cards.b.BirdsOfParadise.class)); - cards.add(new SetCardInfo("Black Knight", 143, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); - cards.add(new SetCardInfo("Blessed Wine", 11, Rarity.COMMON, mage.cards.b.BlessedWine.class)); - cards.add(new SetCardInfo("Blight", 144, Rarity.UNCOMMON, mage.cards.b.Blight.class)); - cards.add(new SetCardInfo("Blinking Spirit", 12, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); - cards.add(new SetCardInfo("Blood Lust", 212, Rarity.COMMON, mage.cards.b.BloodLust.class)); - cards.add(new SetCardInfo("Bog Imp", 145, Rarity.COMMON, mage.cards.b.BogImp.class)); - cards.add(new SetCardInfo("Bog Rats", 146, Rarity.COMMON, mage.cards.b.BogRats.class)); - cards.add(new SetCardInfo("Bog Wraith", 147, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); - cards.add(new SetCardInfo("Boomerang", 75, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Bottle of Suleiman", 354, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); - cards.add(new SetCardInfo("Bottomless Vault", 411, Rarity.RARE, mage.cards.b.BottomlessVault.class)); - cards.add(new SetCardInfo("Brainstorm", 76, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brainwash", 13, Rarity.COMMON, mage.cards.b.Brainwash.class)); - cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); - cards.add(new SetCardInfo("Breeding Pit", 148, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); - cards.add(new SetCardInfo("Broken Visage", 149, Rarity.RARE, mage.cards.b.BrokenVisage.class)); - cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); - cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class)); - cards.add(new SetCardInfo("Carapace", 281, Rarity.COMMON, mage.cards.c.Carapace.class)); - cards.add(new SetCardInfo("Caribou Range", 14, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Carrion Ants", 150, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); - cards.add(new SetCardInfo("Castle", 15, Rarity.UNCOMMON, mage.cards.c.Castle.class)); - cards.add(new SetCardInfo("Cat Warriors", 282, Rarity.COMMON, mage.cards.c.CatWarriors.class)); - cards.add(new SetCardInfo("Cave People", 215, Rarity.UNCOMMON, mage.cards.c.CavePeople.class)); - cards.add(new SetCardInfo("Chub Toad", 283, Rarity.COMMON, mage.cards.c.ChubToad.class)); - cards.add(new SetCardInfo("Circle of Protection: Artifacts", 16, Rarity.UNCOMMON, mage.cards.c.CircleOfProtectionArtifacts.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 17, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 18, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 19, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 20, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 21, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("City of Brass", 413, Rarity.RARE, mage.cards.c.CityOfBrass.class)); - cards.add(new SetCardInfo("Clay Statue", 355, Rarity.COMMON, mage.cards.c.ClayStatue.class)); - cards.add(new SetCardInfo("Clockwork Beast", 356, Rarity.RARE, mage.cards.c.ClockworkBeast.class)); - cards.add(new SetCardInfo("Clockwork Steed", 357, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); - cards.add(new SetCardInfo("Cockatrice", 284, Rarity.RARE, mage.cards.c.Cockatrice.class)); - cards.add(new SetCardInfo("Colossus of Sardia", 358, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); - cards.add(new SetCardInfo("Conquer", 216, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Coral Helm", 359, Rarity.RARE, mage.cards.c.CoralHelm.class)); - cards.add(new SetCardInfo("Counterspell", 77, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Craw Giant", 285, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); - cards.add(new SetCardInfo("Craw Wurm", 286, Rarity.COMMON, mage.cards.c.CrawWurm.class)); - cards.add(new SetCardInfo("Crimson Manticore", 217, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); - cards.add(new SetCardInfo("Crown of the Ages", 360, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); - cards.add(new SetCardInfo("Crumble", 287, Rarity.UNCOMMON, mage.cards.c.Crumble.class)); - cards.add(new SetCardInfo("Crusade", 22, Rarity.RARE, mage.cards.c.Crusade.class)); - cards.add(new SetCardInfo("Crystal Rod", 361, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); - cards.add(new SetCardInfo("Cursed Land", 152, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); - cards.add(new SetCardInfo("D'Avenant Archer", 23, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); - cards.add(new SetCardInfo("Dance of Many", 78, Rarity.RARE, mage.cards.d.DanceOfMany.class)); - cards.add(new SetCardInfo("Dancing Scimitar", 362, Rarity.RARE, mage.cards.d.DancingScimitar.class)); - cards.add(new SetCardInfo("Dandan", 79, Rarity.COMMON, mage.cards.d.Dandan.class)); - cards.add(new SetCardInfo("Dark Maze", 80, Rarity.COMMON, mage.cards.d.DarkMaze.class)); - cards.add(new SetCardInfo("Dark Ritual", 153, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Death Speakers", 24, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); - cards.add(new SetCardInfo("Death Ward", 25, Rarity.COMMON, mage.cards.d.DeathWard.class)); - cards.add(new SetCardInfo("Deathgrip", 154, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); - cards.add(new SetCardInfo("Deflection", 81, Rarity.RARE, mage.cards.d.Deflection.class)); - cards.add(new SetCardInfo("Derelor", 155, Rarity.RARE, mage.cards.d.Derelor.class)); - cards.add(new SetCardInfo("Desert Twister", 288, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); - cards.add(new SetCardInfo("Detonate", 218, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); - cards.add(new SetCardInfo("Diabolic Machine", 363, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); - cards.add(new SetCardInfo("Dingus Egg", 364, Rarity.RARE, mage.cards.d.DingusEgg.class)); - cards.add(new SetCardInfo("Disenchant", 26, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Disintegrate", 219, Rarity.COMMON, mage.cards.d.Disintegrate.class)); - cards.add(new SetCardInfo("Disrupting Scepter", 365, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); - cards.add(new SetCardInfo("Divine Offering", 27, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Divine Transformation", 28, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); - cards.add(new SetCardInfo("Dragon Engine", 366, Rarity.RARE, mage.cards.d.DragonEngine.class)); - cards.add(new SetCardInfo("Drain Life", 156, Rarity.COMMON, mage.cards.d.DrainLife.class)); - cards.add(new SetCardInfo("Drain Power", 82, Rarity.RARE, mage.cards.d.DrainPower.class)); - cards.add(new SetCardInfo("Drudge Skeletons", 157, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); - cards.add(new SetCardInfo("Durkwood Boars", 289, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); - cards.add(new SetCardInfo("Dust to Dust", 29, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); - cards.add(new SetCardInfo("Dwarven Catapult", 220, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); - cards.add(new SetCardInfo("Dwarven Hold", 414, Rarity.RARE, mage.cards.d.DwarvenHold.class)); - cards.add(new SetCardInfo("Dwarven Ruins", 415, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); - cards.add(new SetCardInfo("Dwarven Soldier", 221, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); - cards.add(new SetCardInfo("Dwarven Warriors", 222, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); - cards.add(new SetCardInfo("Earthquake", 223, Rarity.RARE, mage.cards.e.Earthquake.class)); - cards.add(new SetCardInfo("Ebon Stronghold", 416, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); - cards.add(new SetCardInfo("Elder Druid", 290, Rarity.RARE, mage.cards.e.ElderDruid.class)); - cards.add(new SetCardInfo("Elkin Bottle", 367, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Elven Riders", 291, Rarity.UNCOMMON, mage.cards.e.ElvenRiders.class)); - cards.add(new SetCardInfo("Elvish Archers", 292, Rarity.RARE, mage.cards.e.ElvishArchers.class)); - cards.add(new SetCardInfo("Energy Flux", 83, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); - cards.add(new SetCardInfo("Enervate", 84, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Erg Raiders", 158, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); - cards.add(new SetCardInfo("Errantry", 224, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Eternal Warrior", 225, Rarity.COMMON, mage.cards.e.EternalWarrior.class)); - cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 159, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); - cards.add(new SetCardInfo("Evil Presence", 160, Rarity.UNCOMMON, mage.cards.e.EvilPresence.class)); - cards.add(new SetCardInfo("Eye for an Eye", 30, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); - cards.add(new SetCardInfo("Fallen Angel", 161, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); - cards.add(new SetCardInfo("Fear", 162, Rarity.COMMON, mage.cards.f.Fear.class)); - cards.add(new SetCardInfo("Feedback", 85, Rarity.UNCOMMON, mage.cards.f.Feedback.class)); - cards.add(new SetCardInfo("Feldon's Cane", 368, Rarity.UNCOMMON, mage.cards.f.FeldonsCane.class)); - cards.add(new SetCardInfo("Fellwar Stone", 369, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); - cards.add(new SetCardInfo("Feroz's Ban", 370, Rarity.RARE, mage.cards.f.FerozsBan.class)); - cards.add(new SetCardInfo("Fire Drake", 226, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); - cards.add(new SetCardInfo("Fireball", 227, Rarity.COMMON, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Firebreathing", 228, Rarity.COMMON, mage.cards.f.Firebreathing.class)); - cards.add(new SetCardInfo("Flame Spirit", 229, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Flare", 230, Rarity.COMMON, mage.cards.f.Flare.class)); - cards.add(new SetCardInfo("Flashfires", 231, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); - cards.add(new SetCardInfo("Flight", 86, Rarity.COMMON, mage.cards.f.Flight.class)); - cards.add(new SetCardInfo("Flood", 87, Rarity.COMMON, mage.cards.f.Flood.class)); - cards.add(new SetCardInfo("Flying Carpet", 371, Rarity.RARE, mage.cards.f.FlyingCarpet.class)); - cards.add(new SetCardInfo("Fog", 293, Rarity.COMMON, mage.cards.f.Fog.class)); - cards.add(new SetCardInfo("Force Spike", 88, Rarity.COMMON, mage.cards.f.ForceSpike.class)); - cards.add(new SetCardInfo("Force of Nature", 294, Rarity.RARE, mage.cards.f.ForceOfNature.class)); - cards.add(new SetCardInfo("Forest", 446, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 447, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 448, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 449, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forget", 89, Rarity.RARE, mage.cards.f.Forget.class)); - cards.add(new SetCardInfo("Fountain of Youth", 372, Rarity.UNCOMMON, mage.cards.f.FountainOfYouth.class)); - cards.add(new SetCardInfo("Foxfire", 295, Rarity.COMMON, mage.cards.f.Foxfire.class)); - cards.add(new SetCardInfo("Frozen Shade", 163, Rarity.COMMON, mage.cards.f.FrozenShade.class)); - cards.add(new SetCardInfo("Funeral March", 164, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); - cards.add(new SetCardInfo("Fungusaur", 296, Rarity.RARE, mage.cards.f.Fungusaur.class)); - cards.add(new SetCardInfo("Fyndhorn Elder", 297, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); - cards.add(new SetCardInfo("Game of Chaos", 232, Rarity.RARE, mage.cards.g.GameOfChaos.class)); - cards.add(new SetCardInfo("Gaseous Form", 90, Rarity.COMMON, mage.cards.g.GaseousForm.class)); - cards.add(new SetCardInfo("Gauntlets of Chaos", 373, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); - cards.add(new SetCardInfo("Ghazban Ogre", 298, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); - cards.add(new SetCardInfo("Giant Growth", 299, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Spider", 300, Rarity.COMMON, mage.cards.g.GiantSpider.class)); - cards.add(new SetCardInfo("Giant Strength", 233, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Glacial Wall", 91, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); - cards.add(new SetCardInfo("Glasses of Urza", 374, Rarity.UNCOMMON, mage.cards.g.GlassesOfUrza.class)); - cards.add(new SetCardInfo("Gloom", 165, Rarity.UNCOMMON, mage.cards.g.Gloom.class)); - cards.add(new SetCardInfo("Goblin Digging Team", 234, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); - cards.add(new SetCardInfo("Goblin Hero", 235, Rarity.COMMON, mage.cards.g.GoblinHero.class)); - cards.add(new SetCardInfo("Goblin King", 236, Rarity.RARE, mage.cards.g.GoblinKing.class)); - cards.add(new SetCardInfo("Goblin War Drums", 237, Rarity.COMMON, mage.cards.g.GoblinWarDrums.class)); - cards.add(new SetCardInfo("Goblin Warrens", 238, Rarity.RARE, mage.cards.g.GoblinWarrens.class)); - cards.add(new SetCardInfo("Grapeshot Catapult", 375, Rarity.COMMON, mage.cards.g.GrapeshotCatapult.class)); - cards.add(new SetCardInfo("Greater Realm of Preservation", 31, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); - cards.add(new SetCardInfo("Greater Werewolf", 166, Rarity.UNCOMMON, mage.cards.g.GreaterWerewolf.class)); - cards.add(new SetCardInfo("Grizzly Bears", 301, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); - cards.add(new SetCardInfo("Havenwood Battleground", 417, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); - cards.add(new SetCardInfo("Heal", 32, Rarity.COMMON, mage.cards.h.Heal.class)); - cards.add(new SetCardInfo("Healing Salve", 33, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Hecatomb", 167, Rarity.RARE, mage.cards.h.Hecatomb.class)); - cards.add(new SetCardInfo("Helm of Chatzuk", 376, Rarity.RARE, mage.cards.h.HelmOfChatzuk.class)); - cards.add(new SetCardInfo("Hill Giant", 239, Rarity.COMMON, mage.cards.h.HillGiant.class)); - cards.add(new SetCardInfo("Hollow Trees", 418, Rarity.RARE, mage.cards.h.HollowTrees.class)); - cards.add(new SetCardInfo("Holy Strength", 35, Rarity.COMMON, mage.cards.h.HolyStrength.class)); - cards.add(new SetCardInfo("Homarid Warrior", 92, Rarity.COMMON, mage.cards.h.HomaridWarrior.class)); - cards.add(new SetCardInfo("Howl from Beyond", 168, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Howling Mine", 377, Rarity.RARE, mage.cards.h.HowlingMine.class)); - cards.add(new SetCardInfo("Hungry Mist", 302, Rarity.COMMON, mage.cards.h.HungryMist.class)); - cards.add(new SetCardInfo("Hurkyl's Recall", 93, Rarity.RARE, mage.cards.h.HurkylsRecall.class)); - cards.add(new SetCardInfo("Hurloon Minotaur", 240, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); - cards.add(new SetCardInfo("Hurricane", 303, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); - cards.add(new SetCardInfo("Hydroblast", 94, Rarity.UNCOMMON, mage.cards.h.Hydroblast.class)); - cards.add(new SetCardInfo("Icatian Phalanx", 36, Rarity.UNCOMMON, mage.cards.i.IcatianPhalanx.class)); - cards.add(new SetCardInfo("Icatian Scout", 37, Rarity.COMMON, mage.cards.i.IcatianScout.class)); - cards.add(new SetCardInfo("Icatian Store", 419, Rarity.RARE, mage.cards.i.IcatianStore.class)); - cards.add(new SetCardInfo("Icatian Town", 38, Rarity.RARE, mage.cards.i.IcatianTown.class)); - cards.add(new SetCardInfo("Ice Floe", 420, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Imposing Visage", 241, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); - cards.add(new SetCardInfo("Incinerate", 242, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Inferno", 243, Rarity.RARE, mage.cards.i.Inferno.class)); - cards.add(new SetCardInfo("Infinite Hourglass", 378, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); - cards.add(new SetCardInfo("Initiates of the Ebon Hand", 169, Rarity.COMMON, mage.cards.i.InitiatesOfTheEbonHand.class)); - cards.add(new SetCardInfo("Instill Energy", 304, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); - cards.add(new SetCardInfo("Iron Star", 379, Rarity.UNCOMMON, mage.cards.i.IronStar.class)); - cards.add(new SetCardInfo("Ironclaw Curse", 244, Rarity.RARE, mage.cards.i.IronclawCurse.class)); - cards.add(new SetCardInfo("Ironclaw Orcs", 245, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); - cards.add(new SetCardInfo("Ironroot Treefolk", 305, Rarity.COMMON, mage.cards.i.IronrootTreefolk.class)); - cards.add(new SetCardInfo("Island Sanctuary", 39, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); - cards.add(new SetCardInfo("Island", 434, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 435, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 436, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 437, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Cup", 380, Rarity.UNCOMMON, mage.cards.i.IvoryCup.class)); - cards.add(new SetCardInfo("Ivory Guardians", 40, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); - cards.add(new SetCardInfo("Jade Monolith", 381, Rarity.RARE, mage.cards.j.JadeMonolith.class)); - cards.add(new SetCardInfo("Jalum Tome", 382, Rarity.RARE, mage.cards.j.JalumTome.class)); - cards.add(new SetCardInfo("Jandor's Saddlebags", 383, Rarity.RARE, mage.cards.j.JandorsSaddlebags.class)); - cards.add(new SetCardInfo("Jayemdae Tome", 384, Rarity.RARE, mage.cards.j.JayemdaeTome.class)); - cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class)); - cards.add(new SetCardInfo("Johtull Wurm", 306, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class)); - cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); - cards.add(new SetCardInfo("Justice", 41, Rarity.UNCOMMON, mage.cards.j.Justice.class)); - cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class)); - cards.add(new SetCardInfo("Karma", 42, Rarity.UNCOMMON, mage.cards.k.Karma.class)); - cards.add(new SetCardInfo("Karplusan Forest", 421, Rarity.RARE, mage.cards.k.KarplusanForest.class)); - cards.add(new SetCardInfo("Keldon Warlord", 247, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); - cards.add(new SetCardInfo("Killer Bees", 307, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); - cards.add(new SetCardInfo("Kismet", 43, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 170, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Royal Guard", 44, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 45, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 171, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 172, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 96, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); - cards.add(new SetCardInfo("Leshrac's Rite", 173, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); - cards.add(new SetCardInfo("Leviathan", 98, Rarity.RARE, mage.cards.l.Leviathan.class)); - cards.add(new SetCardInfo("Ley Druid", 308, Rarity.COMMON, mage.cards.l.LeyDruid.class)); - cards.add(new SetCardInfo("Lhurgoyf", 309, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); - cards.add(new SetCardInfo("Library of Leng", 387, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); - cards.add(new SetCardInfo("Lifeforce", 310, Rarity.UNCOMMON, mage.cards.l.Lifeforce.class)); - cards.add(new SetCardInfo("Lifetap", 99, Rarity.UNCOMMON, mage.cards.l.Lifetap.class)); - cards.add(new SetCardInfo("Living Artifact", 311, Rarity.RARE, mage.cards.l.LivingArtifact.class)); - cards.add(new SetCardInfo("Living Lands", 312, Rarity.RARE, mage.cards.l.LivingLands.class)); - cards.add(new SetCardInfo("Llanowar Elves", 313, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); - cards.add(new SetCardInfo("Lord of Atlantis", 100, Rarity.RARE, mage.cards.l.LordOfAtlantis.class)); - cards.add(new SetCardInfo("Lord of the Pit", 174, Rarity.RARE, mage.cards.l.LordOfThePit.class)); - cards.add(new SetCardInfo("Lost Soul", 175, Rarity.COMMON, mage.cards.l.LostSoul.class)); - cards.add(new SetCardInfo("Lure", 314, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 102, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Mana Clash", 248, Rarity.RARE, mage.cards.m.ManaClash.class)); - cards.add(new SetCardInfo("Mana Flare", 249, Rarity.RARE, mage.cards.m.ManaFlare.class)); - cards.add(new SetCardInfo("Mana Vault", 388, Rarity.RARE, mage.cards.m.ManaVault.class)); - cards.add(new SetCardInfo("Manabarbs", 250, Rarity.RARE, mage.cards.m.Manabarbs.class)); - cards.add(new SetCardInfo("Marsh Viper", 315, Rarity.COMMON, mage.cards.m.MarshViper.class)); - cards.add(new SetCardInfo("Meekstone", 389, Rarity.RARE, mage.cards.m.Meekstone.class)); - cards.add(new SetCardInfo("Memory Lapse", 103, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); - cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 104, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); - cards.add(new SetCardInfo("Mesa Falcon", 46, Rarity.COMMON, mage.cards.m.MesaFalcon.class)); - cards.add(new SetCardInfo("Mesa Pegasus", 47, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); - cards.add(new SetCardInfo("Millstone", 390, Rarity.RARE, mage.cards.m.Millstone.class)); - cards.add(new SetCardInfo("Mind Bomb", 105, Rarity.UNCOMMON, mage.cards.m.MindBomb.class)); - cards.add(new SetCardInfo("Mind Ravel", 176, Rarity.COMMON, mage.cards.m.MindRavel.class)); - cards.add(new SetCardInfo("Mind Warp", 177, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); - cards.add(new SetCardInfo("Mindstab Thrull", 178, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); - cards.add(new SetCardInfo("Mole Worms", 179, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); - cards.add(new SetCardInfo("Mons's Goblin Raiders", 251, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); - cards.add(new SetCardInfo("Mountain Goat", 252, Rarity.COMMON, mage.cards.m.MountainGoat.class)); - cards.add(new SetCardInfo("Mountain", 442, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 443, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 444, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 445, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Murk Dwellers", 180, Rarity.COMMON, mage.cards.m.MurkDwellers.class)); - cards.add(new SetCardInfo("Nature's Lore", 316, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Necrite", 181, Rarity.COMMON, mage.cards.n.Necrite.class)); - cards.add(new SetCardInfo("Necropotence", 182, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Nether Shadow", 183, Rarity.RARE, mage.cards.n.NetherShadow.class)); - cards.add(new SetCardInfo("Nevinyrral's Disk", 391, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); - cards.add(new SetCardInfo("Nightmare", 184, Rarity.RARE, mage.cards.n.Nightmare.class)); - cards.add(new SetCardInfo("Obelisk of Undoing", 392, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); - cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class)); - cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); - cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class)); - cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 48, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 49, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Orgg", 259, Rarity.RARE, mage.cards.o.Orgg.class)); - cards.add(new SetCardInfo("Ornithopter", 393, Rarity.UNCOMMON, mage.cards.o.Ornithopter.class)); - cards.add(new SetCardInfo("Panic", 260, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Paralyze", 185, Rarity.COMMON, mage.cards.p.Paralyze.class)); - cards.add(new SetCardInfo("Pearled Unicorn", 50, Rarity.COMMON, mage.cards.p.PearledUnicorn.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 394, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Personal Incarnation", 51, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); - cards.add(new SetCardInfo("Pestilence", 186, Rarity.COMMON, mage.cards.p.Pestilence.class)); - cards.add(new SetCardInfo("Phantasmal Forces", 106, Rarity.UNCOMMON, mage.cards.p.PhantasmalForces.class)); - cards.add(new SetCardInfo("Phantasmal Terrain", 107, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); - cards.add(new SetCardInfo("Phantom Monster", 108, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class)); - cards.add(new SetCardInfo("Pikemen", 52, Rarity.COMMON, mage.cards.p.Pikemen.class)); - cards.add(new SetCardInfo("Pirate Ship", 109, Rarity.RARE, mage.cards.p.PirateShip.class)); - cards.add(new SetCardInfo("Pit Scorpion", 187, Rarity.COMMON, mage.cards.p.PitScorpion.class)); - cards.add(new SetCardInfo("Plague Rats", 188, Rarity.COMMON, mage.cards.p.PlagueRats.class)); - cards.add(new SetCardInfo("Plains", 430, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 431, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 432, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 433, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Portent", 110, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Power Sink", 111, Rarity.UNCOMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Pox", 189, Rarity.RARE, mage.cards.p.Pox.class)); - cards.add(new SetCardInfo("Pradesh Gypsies", 317, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); - cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); - cards.add(new SetCardInfo("Primal Order", 318, Rarity.RARE, mage.cards.p.PrimalOrder.class)); - cards.add(new SetCardInfo("Primordial Ooze", 261, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); - cards.add(new SetCardInfo("Prismatic Ward", 53, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); - cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); - cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); - cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); - cards.add(new SetCardInfo("Pyrotechnics", 263, Rarity.UNCOMMON, mage.cards.p.Pyrotechnics.class)); - cards.add(new SetCardInfo("Rabid Wombat", 319, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); - cards.add(new SetCardInfo("Radjan Spirit", 320, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); - cards.add(new SetCardInfo("Rag Man", 190, Rarity.RARE, mage.cards.r.RagMan.class)); - cards.add(new SetCardInfo("Raise Dead", 191, Rarity.COMMON, mage.cards.r.RaiseDead.class)); - cards.add(new SetCardInfo("Ray of Command", 114, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Recall", 115, Rarity.RARE, mage.cards.r.Recall.class)); - cards.add(new SetCardInfo("Reef Pirates", 116, Rarity.COMMON, mage.cards.r.ReefPirates.class)); - cards.add(new SetCardInfo("Regeneration", 321, Rarity.COMMON, mage.cards.r.Regeneration.class)); - cards.add(new SetCardInfo("Remove Soul", 117, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Repentant Blacksmith", 54, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); - cards.add(new SetCardInfo("Reverse Damage", 55, Rarity.RARE, mage.cards.r.ReverseDamage.class)); - cards.add(new SetCardInfo("Righteousness", 56, Rarity.RARE, mage.cards.r.Righteousness.class)); - cards.add(new SetCardInfo("Rod of Ruin", 396, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class)); - cards.add(new SetCardInfo("Ruins of Trokair", 422, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); - cards.add(new SetCardInfo("Sabretooth Tiger", 264, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); - cards.add(new SetCardInfo("Samite Healer", 58, Rarity.COMMON, mage.cards.s.SamiteHealer.class)); - cards.add(new SetCardInfo("Sand Silos", 423, Rarity.RARE, mage.cards.s.SandSilos.class)); - cards.add(new SetCardInfo("Scaled Wurm", 322, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); - cards.add(new SetCardInfo("Scathe Zombies", 192, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); - cards.add(new SetCardInfo("Scavenger Folk", 323, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); - cards.add(new SetCardInfo("Scryb Sprites", 324, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); - cards.add(new SetCardInfo("Sea Serpent", 118, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); - cards.add(new SetCardInfo("Sea Spirit", 119, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Sea Sprite", 120, Rarity.UNCOMMON, mage.cards.s.SeaSprite.class)); - cards.add(new SetCardInfo("Seasinger", 121, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); - cards.add(new SetCardInfo("Segovian Leviathan", 122, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); - cards.add(new SetCardInfo("Sengir Autocrat", 193, Rarity.RARE, mage.cards.s.SengirAutocrat.class)); - cards.add(new SetCardInfo("Serpent Generator", 397, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); - cards.add(new SetCardInfo("Serra Bestiary", 60, Rarity.UNCOMMON, mage.cards.s.SerraBestiary.class)); - cards.add(new SetCardInfo("Serra Paladin", 61, Rarity.UNCOMMON, mage.cards.s.SerraPaladin.class)); - cards.add(new SetCardInfo("Shanodin Dryads", 325, Rarity.COMMON, mage.cards.s.ShanodinDryads.class)); - cards.add(new SetCardInfo("Shapeshifter", 398, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); - cards.add(new SetCardInfo("Shatter", 265, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shatterstorm", 266, Rarity.UNCOMMON, mage.cards.s.Shatterstorm.class)); - cards.add(new SetCardInfo("Shield Bearer", 62, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shield Wall", 63, Rarity.COMMON, mage.cards.s.ShieldWall.class)); - cards.add(new SetCardInfo("Shivan Dragon", 267, Rarity.RARE, mage.cards.s.ShivanDragon.class)); - cards.add(new SetCardInfo("Shrink", 326, Rarity.COMMON, mage.cards.s.Shrink.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 123, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Skull Catapult", 399, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Smoke", 268, Rarity.RARE, mage.cards.s.Smoke.class)); - cards.add(new SetCardInfo("Sorceress Queen", 194, Rarity.RARE, mage.cards.s.SorceressQueen.class)); - cards.add(new SetCardInfo("Soul Barrier", 125, Rarity.COMMON, mage.cards.s.SoulBarrier.class)); - cards.add(new SetCardInfo("Soul Net", 400, Rarity.UNCOMMON, mage.cards.s.SoulNet.class)); - cards.add(new SetCardInfo("Spell Blast", 126, Rarity.COMMON, mage.cards.s.SpellBlast.class)); - cards.add(new SetCardInfo("Spirit Link", 64, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); - cards.add(new SetCardInfo("Stampede", 327, Rarity.RARE, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stasis", 127, Rarity.RARE, mage.cards.s.Stasis.class)); - cards.add(new SetCardInfo("Steal Artifact", 128, Rarity.UNCOMMON, mage.cards.s.StealArtifact.class)); - cards.add(new SetCardInfo("Stone Giant", 269, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); - cards.add(new SetCardInfo("Stone Rain", 270, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Stone Spirit", 271, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stream of Life", 328, Rarity.COMMON, mage.cards.s.StreamOfLife.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 195, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Sulfurous Springs", 424, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); - cards.add(new SetCardInfo("Svyelunite Temple", 425, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); - cards.add(new SetCardInfo("Swamp", 438, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 439, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 440, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 441, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sylvan Library", 329, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); - cards.add(new SetCardInfo("Tarpan", 330, Rarity.COMMON, mage.cards.t.Tarpan.class)); - cards.add(new SetCardInfo("Tawnos's Weaponry", 401, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); - cards.add(new SetCardInfo("Terror", 196, Rarity.COMMON, mage.cards.t.Terror.class)); - cards.add(new SetCardInfo("The Brute", 272, Rarity.COMMON, mage.cards.t.TheBrute.class)); - cards.add(new SetCardInfo("The Hive", 402, Rarity.RARE, mage.cards.t.TheHive.class)); - cards.add(new SetCardInfo("The Wretched", 197, Rarity.RARE, mage.cards.t.TheWretched.class)); - cards.add(new SetCardInfo("Thicket Basilisk", 331, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); - cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); - cards.add(new SetCardInfo("Thrull Retainer", 198, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); - cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class)); - cards.add(new SetCardInfo("Titania's Song", 332, Rarity.RARE, mage.cards.t.TitaniasSong.class)); - cards.add(new SetCardInfo("Torture", 199, Rarity.COMMON, mage.cards.t.Torture.class)); - cards.add(new SetCardInfo("Touch of Death", 200, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); - cards.add(new SetCardInfo("Tranquility", 333, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Truce", 65, Rarity.RARE, mage.cards.t.Truce.class)); - cards.add(new SetCardInfo("Tsunami", 334, Rarity.UNCOMMON, mage.cards.t.Tsunami.class)); - cards.add(new SetCardInfo("Tundra Wolves", 66, Rarity.COMMON, mage.cards.t.TundraWolves.class)); - cards.add(new SetCardInfo("Twiddle", 130, Rarity.COMMON, mage.cards.t.Twiddle.class)); - cards.add(new SetCardInfo("Underground River", 426, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); - cards.add(new SetCardInfo("Unholy Strength", 201, Rarity.COMMON, mage.cards.u.UnholyStrength.class)); - cards.add(new SetCardInfo("Unstable Mutation", 131, Rarity.COMMON, mage.cards.u.UnstableMutation.class)); - cards.add(new SetCardInfo("Unsummon", 132, Rarity.COMMON, mage.cards.u.Unsummon.class)); - cards.add(new SetCardInfo("Untamed Wilds", 335, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Updraft", 133, Rarity.COMMON, mage.cards.u.Updraft.class)); - cards.add(new SetCardInfo("Urza's Avenger", 405, Rarity.RARE, mage.cards.u.UrzasAvenger.class)); - cards.add(new SetCardInfo("Urza's Bauble", 406, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); - cards.add(new SetCardInfo("Urza's Mine", 427, Rarity.COMMON, mage.cards.u.UrzasMine.class)); - cards.add(new SetCardInfo("Urza's Power Plant", 428, Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class)); - cards.add(new SetCardInfo("Urza's Tower", 429, Rarity.COMMON, mage.cards.u.UrzasTower.class)); - cards.add(new SetCardInfo("Vampire Bats", 202, Rarity.COMMON, mage.cards.v.VampireBats.class)); - cards.add(new SetCardInfo("Venom", 336, Rarity.COMMON, mage.cards.v.Venom.class)); - cards.add(new SetCardInfo("Verduran Enchantress", 337, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); - cards.add(new SetCardInfo("Vodalian Soldiers", 134, Rarity.COMMON, mage.cards.v.VodalianSoldiers.class)); - cards.add(new SetCardInfo("Wall of Air", 135, Rarity.UNCOMMON, mage.cards.w.WallOfAir.class)); - cards.add(new SetCardInfo("Wall of Bone", 203, Rarity.UNCOMMON, mage.cards.w.WallOfBone.class)); - cards.add(new SetCardInfo("Wall of Brambles", 338, Rarity.UNCOMMON, mage.cards.w.WallOfBrambles.class)); - cards.add(new SetCardInfo("Wall of Fire", 273, Rarity.UNCOMMON, mage.cards.w.WallOfFire.class)); - cards.add(new SetCardInfo("Wall of Spears", 407, Rarity.COMMON, mage.cards.w.WallOfSpears.class)); - cards.add(new SetCardInfo("Wall of Stone", 274, Rarity.UNCOMMON, mage.cards.w.WallOfStone.class)); - cards.add(new SetCardInfo("Wall of Swords", 67, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); - cards.add(new SetCardInfo("Wanderlust", 339, Rarity.UNCOMMON, mage.cards.w.Wanderlust.class)); - cards.add(new SetCardInfo("War Mammoth", 340, Rarity.COMMON, mage.cards.w.WarMammoth.class)); - cards.add(new SetCardInfo("Warp Artifact", 204, Rarity.RARE, mage.cards.w.WarpArtifact.class)); - cards.add(new SetCardInfo("Weakness", 205, Rarity.COMMON, mage.cards.w.Weakness.class)); - cards.add(new SetCardInfo("Whirling Dervish", 341, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); - cards.add(new SetCardInfo("White Knight", 68, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); - cards.add(new SetCardInfo("Wild Growth", 342, Rarity.COMMON, mage.cards.w.WildGrowth.class)); - cards.add(new SetCardInfo("Wind Spirit", 136, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Winds of Change", 275, Rarity.RARE, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 343, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); - cards.add(new SetCardInfo("Winter Orb", 408, Rarity.RARE, mage.cards.w.WinterOrb.class)); - cards.add(new SetCardInfo("Wolverine Pack", 344, Rarity.UNCOMMON, mage.cards.w.WolverinePack.class)); - cards.add(new SetCardInfo("Wooden Sphere", 409, Rarity.UNCOMMON, mage.cards.w.WoodenSphere.class)); - cards.add(new SetCardInfo("Word of Blasting", 276, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); - cards.add(new SetCardInfo("Wrath of God", 69, Rarity.RARE, mage.cards.w.WrathOfGod.class)); - cards.add(new SetCardInfo("Wyluli Wolf", 345, Rarity.RARE, mage.cards.w.WyluliWolf.class)); - cards.add(new SetCardInfo("Xenic Poltergeist", 206, Rarity.RARE, mage.cards.x.XenicPoltergeist.class)); - cards.add(new SetCardInfo("Zephyr Falcon", 137, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); - cards.add(new SetCardInfo("Zombie Master", 207, Rarity.RARE, mage.cards.z.ZombieMaster.class)); - cards.add(new SetCardInfo("Zur's Weirding", 138, Rarity.RARE, mage.cards.z.ZursWeirding.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class FifthEdition extends ExpansionSet { + + private static final FifthEdition instance = new FifthEdition(); + + public static FifthEdition getInstance() { + return instance; + } + + private FifthEdition() { + super("Fifth Edition", "5ED", ExpansionSet.buildDate(1997, 3, 1), SetType.CORE); + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); + cards.add(new SetCardInfo("Abyssal Specter", 139, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); + cards.add(new SetCardInfo("Adarkar Wastes", 410, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); + cards.add(new SetCardInfo("Aether Storm", 70, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); + cards.add(new SetCardInfo("Air Elemental", 71, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Akron Legionnaire", 2, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); + cards.add(new SetCardInfo("Alabaster Potion", 3, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); + cards.add(new SetCardInfo("Aladdin's Ring", 346, Rarity.RARE, mage.cards.a.AladdinsRing.class)); + cards.add(new SetCardInfo("Ambush Party", 208, Rarity.COMMON, mage.cards.a.AmbushParty.class)); + cards.add(new SetCardInfo("Amulet of Kroog", 347, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); + cards.add(new SetCardInfo("An-Havva Constable", 277, Rarity.RARE, mage.cards.a.AnHavvaConstable.class)); + cards.add(new SetCardInfo("Angry Mob", 4, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); + cards.add(new SetCardInfo("Animate Dead", 140, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); + cards.add(new SetCardInfo("Animate Wall", 5, Rarity.RARE, mage.cards.a.AnimateWall.class)); + cards.add(new SetCardInfo("Ankh of Mishra", 348, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); + cards.add(new SetCardInfo("Anti-Magic Aura", 72, Rarity.UNCOMMON, mage.cards.a.AntiMagicAura.class)); + cards.add(new SetCardInfo("Arenson's Aura", 6, Rarity.UNCOMMON, mage.cards.a.ArensonsAura.class)); + cards.add(new SetCardInfo("Armageddon", 7, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Armor of Faith", 8, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Ashes to Ashes", 141, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); + cards.add(new SetCardInfo("Ashnod's Altar", 349, Rarity.UNCOMMON, mage.cards.a.AshnodsAltar.class)); + cards.add(new SetCardInfo("Ashnod's Transmogrant", 350, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); + cards.add(new SetCardInfo("Aspect of Wolf", 278, Rarity.RARE, mage.cards.a.AspectOfWolf.class)); + cards.add(new SetCardInfo("Atog", 209, Rarity.UNCOMMON, mage.cards.a.Atog.class)); + cards.add(new SetCardInfo("Aurochs", 279, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Aysen Bureaucrats", 9, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); + cards.add(new SetCardInfo("Azure Drake", 73, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); + cards.add(new SetCardInfo("Bad Moon", 142, Rarity.RARE, mage.cards.b.BadMoon.class)); + cards.add(new SetCardInfo("Ball Lightning", 210, Rarity.RARE, mage.cards.b.BallLightning.class)); + cards.add(new SetCardInfo("Barbed Sextant", 351, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Barl's Cage", 352, Rarity.RARE, mage.cards.b.BarlsCage.class)); + cards.add(new SetCardInfo("Battering Ram", 353, Rarity.COMMON, mage.cards.b.BatteringRam.class)); + cards.add(new SetCardInfo("Benalish Hero", 10, Rarity.COMMON, mage.cards.b.BenalishHero.class)); + cards.add(new SetCardInfo("Binding Grasp", 74, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Bird Maiden", 211, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); + cards.add(new SetCardInfo("Birds of Paradise", 280, Rarity.RARE, mage.cards.b.BirdsOfParadise.class)); + cards.add(new SetCardInfo("Black Knight", 143, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blessed Wine", 11, Rarity.COMMON, mage.cards.b.BlessedWine.class)); + cards.add(new SetCardInfo("Blight", 144, Rarity.UNCOMMON, mage.cards.b.Blight.class)); + cards.add(new SetCardInfo("Blinking Spirit", 12, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); + cards.add(new SetCardInfo("Blood Lust", 212, Rarity.COMMON, mage.cards.b.BloodLust.class)); + cards.add(new SetCardInfo("Bog Imp", 145, Rarity.COMMON, mage.cards.b.BogImp.class)); + cards.add(new SetCardInfo("Bog Rats", 146, Rarity.COMMON, mage.cards.b.BogRats.class)); + cards.add(new SetCardInfo("Bog Wraith", 147, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); + cards.add(new SetCardInfo("Boomerang", 75, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Bottle of Suleiman", 354, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); + cards.add(new SetCardInfo("Bottomless Vault", 411, Rarity.RARE, mage.cards.b.BottomlessVault.class)); + cards.add(new SetCardInfo("Brainstorm", 76, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brainwash", 13, Rarity.COMMON, mage.cards.b.Brainwash.class)); + cards.add(new SetCardInfo("Brassclaw Orcs", 213, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); + cards.add(new SetCardInfo("Breeding Pit", 148, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); + cards.add(new SetCardInfo("Broken Visage", 149, Rarity.RARE, mage.cards.b.BrokenVisage.class)); + cards.add(new SetCardInfo("Brothers of Fire", 214, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); + cards.add(new SetCardInfo("Brushland", 412, Rarity.RARE, mage.cards.b.Brushland.class)); + cards.add(new SetCardInfo("Carapace", 281, Rarity.COMMON, mage.cards.c.Carapace.class)); + cards.add(new SetCardInfo("Caribou Range", 14, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Carrion Ants", 150, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); + cards.add(new SetCardInfo("Castle", 15, Rarity.UNCOMMON, mage.cards.c.Castle.class)); + cards.add(new SetCardInfo("Cat Warriors", 282, Rarity.COMMON, mage.cards.c.CatWarriors.class)); + cards.add(new SetCardInfo("Cave People", 215, Rarity.UNCOMMON, mage.cards.c.CavePeople.class)); + cards.add(new SetCardInfo("Chub Toad", 283, Rarity.COMMON, mage.cards.c.ChubToad.class)); + cards.add(new SetCardInfo("Circle of Protection: Artifacts", 16, Rarity.UNCOMMON, mage.cards.c.CircleOfProtectionArtifacts.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 17, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 18, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 19, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 20, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 21, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("City of Brass", 413, Rarity.RARE, mage.cards.c.CityOfBrass.class)); + cards.add(new SetCardInfo("Clay Statue", 355, Rarity.COMMON, mage.cards.c.ClayStatue.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 151, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Clockwork Beast", 356, Rarity.RARE, mage.cards.c.ClockworkBeast.class)); + cards.add(new SetCardInfo("Clockwork Steed", 357, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); + cards.add(new SetCardInfo("Cockatrice", 284, Rarity.RARE, mage.cards.c.Cockatrice.class)); + cards.add(new SetCardInfo("Colossus of Sardia", 358, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); + cards.add(new SetCardInfo("Conquer", 216, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Coral Helm", 359, Rarity.RARE, mage.cards.c.CoralHelm.class)); + cards.add(new SetCardInfo("Counterspell", 77, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Craw Giant", 285, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); + cards.add(new SetCardInfo("Craw Wurm", 286, Rarity.COMMON, mage.cards.c.CrawWurm.class)); + cards.add(new SetCardInfo("Crimson Manticore", 217, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); + cards.add(new SetCardInfo("Crown of the Ages", 360, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); + cards.add(new SetCardInfo("Crumble", 287, Rarity.UNCOMMON, mage.cards.c.Crumble.class)); + cards.add(new SetCardInfo("Crusade", 22, Rarity.RARE, mage.cards.c.Crusade.class)); + cards.add(new SetCardInfo("Crystal Rod", 361, Rarity.UNCOMMON, mage.cards.c.CrystalRod.class)); + cards.add(new SetCardInfo("Cursed Land", 152, Rarity.UNCOMMON, mage.cards.c.CursedLand.class)); + cards.add(new SetCardInfo("D'Avenant Archer", 23, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); + cards.add(new SetCardInfo("Dance of Many", 78, Rarity.RARE, mage.cards.d.DanceOfMany.class)); + cards.add(new SetCardInfo("Dancing Scimitar", 362, Rarity.RARE, mage.cards.d.DancingScimitar.class)); + cards.add(new SetCardInfo("Dandan", 79, Rarity.COMMON, mage.cards.d.Dandan.class)); + cards.add(new SetCardInfo("Dark Maze", 80, Rarity.COMMON, mage.cards.d.DarkMaze.class)); + cards.add(new SetCardInfo("Dark Ritual", 153, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Death Speakers", 24, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); + cards.add(new SetCardInfo("Death Ward", 25, Rarity.COMMON, mage.cards.d.DeathWard.class)); + cards.add(new SetCardInfo("Deathgrip", 154, Rarity.UNCOMMON, mage.cards.d.Deathgrip.class)); + cards.add(new SetCardInfo("Deflection", 81, Rarity.RARE, mage.cards.d.Deflection.class)); + cards.add(new SetCardInfo("Derelor", 155, Rarity.RARE, mage.cards.d.Derelor.class)); + cards.add(new SetCardInfo("Desert Twister", 288, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); + cards.add(new SetCardInfo("Detonate", 218, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); + cards.add(new SetCardInfo("Diabolic Machine", 363, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); + cards.add(new SetCardInfo("Dingus Egg", 364, Rarity.RARE, mage.cards.d.DingusEgg.class)); + cards.add(new SetCardInfo("Disenchant", 26, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Disintegrate", 219, Rarity.COMMON, mage.cards.d.Disintegrate.class)); + cards.add(new SetCardInfo("Disrupting Scepter", 365, Rarity.RARE, mage.cards.d.DisruptingScepter.class)); + cards.add(new SetCardInfo("Divine Offering", 27, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Divine Transformation", 28, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); + cards.add(new SetCardInfo("Dragon Engine", 366, Rarity.RARE, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Drain Life", 156, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Drain Power", 82, Rarity.RARE, mage.cards.d.DrainPower.class)); + cards.add(new SetCardInfo("Drudge Skeletons", 157, Rarity.COMMON, mage.cards.d.DrudgeSkeletons.class)); + cards.add(new SetCardInfo("Durkwood Boars", 289, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); + cards.add(new SetCardInfo("Dust to Dust", 29, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); + cards.add(new SetCardInfo("Dwarven Catapult", 220, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); + cards.add(new SetCardInfo("Dwarven Hold", 414, Rarity.RARE, mage.cards.d.DwarvenHold.class)); + cards.add(new SetCardInfo("Dwarven Ruins", 415, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); + cards.add(new SetCardInfo("Dwarven Soldier", 221, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); + cards.add(new SetCardInfo("Dwarven Warriors", 222, Rarity.COMMON, mage.cards.d.DwarvenWarriors.class)); + cards.add(new SetCardInfo("Earthquake", 223, Rarity.RARE, mage.cards.e.Earthquake.class)); + cards.add(new SetCardInfo("Ebon Stronghold", 416, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); + cards.add(new SetCardInfo("Elder Druid", 290, Rarity.RARE, mage.cards.e.ElderDruid.class)); + cards.add(new SetCardInfo("Elkin Bottle", 367, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Elven Riders", 291, Rarity.UNCOMMON, mage.cards.e.ElvenRiders.class)); + cards.add(new SetCardInfo("Elvish Archers", 292, Rarity.RARE, mage.cards.e.ElvishArchers.class)); + cards.add(new SetCardInfo("Energy Flux", 83, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); + cards.add(new SetCardInfo("Enervate", 84, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Erg Raiders", 158, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); + cards.add(new SetCardInfo("Errantry", 224, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Eternal Warrior", 225, Rarity.COMMON, mage.cards.e.EternalWarrior.class)); + cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 159, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); + cards.add(new SetCardInfo("Evil Presence", 160, Rarity.UNCOMMON, mage.cards.e.EvilPresence.class)); + cards.add(new SetCardInfo("Eye for an Eye", 30, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); + cards.add(new SetCardInfo("Fallen Angel", 161, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); + cards.add(new SetCardInfo("Fear", 162, Rarity.COMMON, mage.cards.f.Fear.class)); + cards.add(new SetCardInfo("Feedback", 85, Rarity.UNCOMMON, mage.cards.f.Feedback.class)); + cards.add(new SetCardInfo("Feldon's Cane", 368, Rarity.UNCOMMON, mage.cards.f.FeldonsCane.class)); + cards.add(new SetCardInfo("Fellwar Stone", 369, Rarity.UNCOMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Feroz's Ban", 370, Rarity.RARE, mage.cards.f.FerozsBan.class)); + cards.add(new SetCardInfo("Fire Drake", 226, Rarity.UNCOMMON, mage.cards.f.FireDrake.class)); + cards.add(new SetCardInfo("Fireball", 227, Rarity.COMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Firebreathing", 228, Rarity.COMMON, mage.cards.f.Firebreathing.class)); + cards.add(new SetCardInfo("Flame Spirit", 229, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Flare", 230, Rarity.COMMON, mage.cards.f.Flare.class)); + cards.add(new SetCardInfo("Flashfires", 231, Rarity.UNCOMMON, mage.cards.f.Flashfires.class)); + cards.add(new SetCardInfo("Flight", 86, Rarity.COMMON, mage.cards.f.Flight.class)); + cards.add(new SetCardInfo("Flood", 87, Rarity.COMMON, mage.cards.f.Flood.class)); + cards.add(new SetCardInfo("Flying Carpet", 371, Rarity.RARE, mage.cards.f.FlyingCarpet.class)); + cards.add(new SetCardInfo("Fog", 293, Rarity.COMMON, mage.cards.f.Fog.class)); + cards.add(new SetCardInfo("Force of Nature", 294, Rarity.RARE, mage.cards.f.ForceOfNature.class)); + cards.add(new SetCardInfo("Force Spike", 88, Rarity.COMMON, mage.cards.f.ForceSpike.class)); + cards.add(new SetCardInfo("Forest", 446, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 447, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 448, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 449, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forget", 89, Rarity.RARE, mage.cards.f.Forget.class)); + cards.add(new SetCardInfo("Fountain of Youth", 372, Rarity.UNCOMMON, mage.cards.f.FountainOfYouth.class)); + cards.add(new SetCardInfo("Foxfire", 295, Rarity.COMMON, mage.cards.f.Foxfire.class)); + cards.add(new SetCardInfo("Frozen Shade", 163, Rarity.COMMON, mage.cards.f.FrozenShade.class)); + cards.add(new SetCardInfo("Funeral March", 164, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); + cards.add(new SetCardInfo("Fungusaur", 296, Rarity.RARE, mage.cards.f.Fungusaur.class)); + cards.add(new SetCardInfo("Fyndhorn Elder", 297, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); + cards.add(new SetCardInfo("Game of Chaos", 232, Rarity.RARE, mage.cards.g.GameOfChaos.class)); + cards.add(new SetCardInfo("Gaseous Form", 90, Rarity.COMMON, mage.cards.g.GaseousForm.class)); + cards.add(new SetCardInfo("Gauntlets of Chaos", 373, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); + cards.add(new SetCardInfo("Ghazban Ogre", 298, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); + cards.add(new SetCardInfo("Giant Growth", 299, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Spider", 300, Rarity.COMMON, mage.cards.g.GiantSpider.class)); + cards.add(new SetCardInfo("Giant Strength", 233, Rarity.COMMON, mage.cards.g.GiantStrength.class)); + cards.add(new SetCardInfo("Glacial Wall", 91, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); + cards.add(new SetCardInfo("Glasses of Urza", 374, Rarity.UNCOMMON, mage.cards.g.GlassesOfUrza.class)); + cards.add(new SetCardInfo("Gloom", 165, Rarity.UNCOMMON, mage.cards.g.Gloom.class)); + cards.add(new SetCardInfo("Goblin Digging Team", 234, Rarity.COMMON, mage.cards.g.GoblinDiggingTeam.class)); + cards.add(new SetCardInfo("Goblin Hero", 235, Rarity.COMMON, mage.cards.g.GoblinHero.class)); + cards.add(new SetCardInfo("Goblin King", 236, Rarity.RARE, mage.cards.g.GoblinKing.class)); + cards.add(new SetCardInfo("Goblin War Drums", 237, Rarity.COMMON, mage.cards.g.GoblinWarDrums.class)); + cards.add(new SetCardInfo("Goblin Warrens", 238, Rarity.RARE, mage.cards.g.GoblinWarrens.class)); + cards.add(new SetCardInfo("Grapeshot Catapult", 375, Rarity.COMMON, mage.cards.g.GrapeshotCatapult.class)); + cards.add(new SetCardInfo("Greater Realm of Preservation", 31, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); + cards.add(new SetCardInfo("Greater Werewolf", 166, Rarity.UNCOMMON, mage.cards.g.GreaterWerewolf.class)); + cards.add(new SetCardInfo("Grizzly Bears", 301, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); + cards.add(new SetCardInfo("Havenwood Battleground", 417, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); + cards.add(new SetCardInfo("Heal", 32, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Healing Salve", 33, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Hecatomb", 167, Rarity.RARE, mage.cards.h.Hecatomb.class)); + cards.add(new SetCardInfo("Helm of Chatzuk", 376, Rarity.RARE, mage.cards.h.HelmOfChatzuk.class)); + cards.add(new SetCardInfo("Hill Giant", 239, Rarity.COMMON, mage.cards.h.HillGiant.class)); + cards.add(new SetCardInfo("Hollow Trees", 418, Rarity.RARE, mage.cards.h.HollowTrees.class)); + cards.add(new SetCardInfo("Holy Strength", 35, Rarity.COMMON, mage.cards.h.HolyStrength.class)); + cards.add(new SetCardInfo("Homarid Warrior", 92, Rarity.COMMON, mage.cards.h.HomaridWarrior.class)); + cards.add(new SetCardInfo("Howl from Beyond", 168, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Howling Mine", 377, Rarity.RARE, mage.cards.h.HowlingMine.class)); + cards.add(new SetCardInfo("Hungry Mist", 302, Rarity.COMMON, mage.cards.h.HungryMist.class)); + cards.add(new SetCardInfo("Hurkyl's Recall", 93, Rarity.RARE, mage.cards.h.HurkylsRecall.class)); + cards.add(new SetCardInfo("Hurloon Minotaur", 240, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); + cards.add(new SetCardInfo("Hurricane", 303, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); + cards.add(new SetCardInfo("Hydroblast", 94, Rarity.UNCOMMON, mage.cards.h.Hydroblast.class)); + cards.add(new SetCardInfo("Icatian Phalanx", 36, Rarity.UNCOMMON, mage.cards.i.IcatianPhalanx.class)); + cards.add(new SetCardInfo("Icatian Scout", 37, Rarity.COMMON, mage.cards.i.IcatianScout.class)); + cards.add(new SetCardInfo("Icatian Store", 419, Rarity.RARE, mage.cards.i.IcatianStore.class)); + cards.add(new SetCardInfo("Icatian Town", 38, Rarity.RARE, mage.cards.i.IcatianTown.class)); + cards.add(new SetCardInfo("Ice Floe", 420, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Imposing Visage", 241, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); + cards.add(new SetCardInfo("Incinerate", 242, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Inferno", 243, Rarity.RARE, mage.cards.i.Inferno.class)); + cards.add(new SetCardInfo("Infinite Hourglass", 378, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); + cards.add(new SetCardInfo("Initiates of the Ebon Hand", 169, Rarity.COMMON, mage.cards.i.InitiatesOfTheEbonHand.class)); + cards.add(new SetCardInfo("Instill Energy", 304, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); + cards.add(new SetCardInfo("Iron Star", 379, Rarity.UNCOMMON, mage.cards.i.IronStar.class)); + cards.add(new SetCardInfo("Ironclaw Curse", 244, Rarity.RARE, mage.cards.i.IronclawCurse.class)); + cards.add(new SetCardInfo("Ironclaw Orcs", 245, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); + cards.add(new SetCardInfo("Ironroot Treefolk", 305, Rarity.COMMON, mage.cards.i.IronrootTreefolk.class)); + cards.add(new SetCardInfo("Island Sanctuary", 39, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); + cards.add(new SetCardInfo("Island", 434, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 435, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 436, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 437, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Cup", 380, Rarity.UNCOMMON, mage.cards.i.IvoryCup.class)); + cards.add(new SetCardInfo("Ivory Guardians", 40, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); + cards.add(new SetCardInfo("Jade Monolith", 381, Rarity.RARE, mage.cards.j.JadeMonolith.class)); + cards.add(new SetCardInfo("Jalum Tome", 382, Rarity.RARE, mage.cards.j.JalumTome.class)); + cards.add(new SetCardInfo("Jandor's Saddlebags", 383, Rarity.RARE, mage.cards.j.JandorsSaddlebags.class)); + cards.add(new SetCardInfo("Jayemdae Tome", 384, Rarity.RARE, mage.cards.j.JayemdaeTome.class)); + cards.add(new SetCardInfo("Jester's Cap", 385, Rarity.RARE, mage.cards.j.JestersCap.class)); + cards.add(new SetCardInfo("Johtull Wurm", 306, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Jokulhaups", 246, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Joven's Tools", 386, Rarity.UNCOMMON, mage.cards.j.JovensTools.class)); + cards.add(new SetCardInfo("Justice", 41, Rarity.UNCOMMON, mage.cards.j.Justice.class)); + cards.add(new SetCardInfo("Juxtapose", 95, Rarity.RARE, mage.cards.j.Juxtapose.class)); + cards.add(new SetCardInfo("Karma", 42, Rarity.UNCOMMON, mage.cards.k.Karma.class)); + cards.add(new SetCardInfo("Karplusan Forest", 421, Rarity.RARE, mage.cards.k.KarplusanForest.class)); + cards.add(new SetCardInfo("Keldon Warlord", 247, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); + cards.add(new SetCardInfo("Killer Bees", 307, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); + cards.add(new SetCardInfo("Kismet", 43, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 170, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Royal Guard", 44, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 45, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 171, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 172, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 96, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Labyrinth Minotaur", 97, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); + cards.add(new SetCardInfo("Leshrac's Rite", 173, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); + cards.add(new SetCardInfo("Leviathan", 98, Rarity.RARE, mage.cards.l.Leviathan.class)); + cards.add(new SetCardInfo("Ley Druid", 308, Rarity.COMMON, mage.cards.l.LeyDruid.class)); + cards.add(new SetCardInfo("Lhurgoyf", 309, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); + cards.add(new SetCardInfo("Library of Leng", 387, Rarity.UNCOMMON, mage.cards.l.LibraryOfLeng.class)); + cards.add(new SetCardInfo("Lifeforce", 310, Rarity.UNCOMMON, mage.cards.l.Lifeforce.class)); + cards.add(new SetCardInfo("Lifetap", 99, Rarity.UNCOMMON, mage.cards.l.Lifetap.class)); + cards.add(new SetCardInfo("Living Artifact", 311, Rarity.RARE, mage.cards.l.LivingArtifact.class)); + cards.add(new SetCardInfo("Living Lands", 312, Rarity.RARE, mage.cards.l.LivingLands.class)); + cards.add(new SetCardInfo("Llanowar Elves", 313, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); + cards.add(new SetCardInfo("Lord of Atlantis", 100, Rarity.RARE, mage.cards.l.LordOfAtlantis.class)); + cards.add(new SetCardInfo("Lord of the Pit", 174, Rarity.RARE, mage.cards.l.LordOfThePit.class)); + cards.add(new SetCardInfo("Lost Soul", 175, Rarity.COMMON, mage.cards.l.LostSoul.class)); + cards.add(new SetCardInfo("Lure", 314, Rarity.UNCOMMON, mage.cards.l.Lure.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 102, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Mana Clash", 248, Rarity.RARE, mage.cards.m.ManaClash.class)); + cards.add(new SetCardInfo("Mana Flare", 249, Rarity.RARE, mage.cards.m.ManaFlare.class)); + cards.add(new SetCardInfo("Mana Vault", 388, Rarity.RARE, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Manabarbs", 250, Rarity.RARE, mage.cards.m.Manabarbs.class)); + cards.add(new SetCardInfo("Marsh Viper", 315, Rarity.COMMON, mage.cards.m.MarshViper.class)); + cards.add(new SetCardInfo("Meekstone", 389, Rarity.RARE, mage.cards.m.Meekstone.class)); + cards.add(new SetCardInfo("Memory Lapse", 103, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); + cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 104, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); + cards.add(new SetCardInfo("Mesa Falcon", 46, Rarity.COMMON, mage.cards.m.MesaFalcon.class)); + cards.add(new SetCardInfo("Mesa Pegasus", 47, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); + cards.add(new SetCardInfo("Millstone", 390, Rarity.RARE, mage.cards.m.Millstone.class)); + cards.add(new SetCardInfo("Mind Bomb", 105, Rarity.UNCOMMON, mage.cards.m.MindBomb.class)); + cards.add(new SetCardInfo("Mind Ravel", 176, Rarity.COMMON, mage.cards.m.MindRavel.class)); + cards.add(new SetCardInfo("Mind Warp", 177, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); + cards.add(new SetCardInfo("Mindstab Thrull", 178, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); + cards.add(new SetCardInfo("Mole Worms", 179, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); + cards.add(new SetCardInfo("Mons's Goblin Raiders", 251, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); + cards.add(new SetCardInfo("Mountain Goat", 252, Rarity.COMMON, mage.cards.m.MountainGoat.class)); + cards.add(new SetCardInfo("Mountain", 442, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 443, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 444, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 445, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Murk Dwellers", 180, Rarity.COMMON, mage.cards.m.MurkDwellers.class)); + cards.add(new SetCardInfo("Nature's Lore", 316, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Necrite", 181, Rarity.COMMON, mage.cards.n.Necrite.class)); + cards.add(new SetCardInfo("Necropotence", 182, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Nether Shadow", 183, Rarity.RARE, mage.cards.n.NetherShadow.class)); + cards.add(new SetCardInfo("Nevinyrral's Disk", 391, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); + cards.add(new SetCardInfo("Nightmare", 184, Rarity.RARE, mage.cards.n.Nightmare.class)); + cards.add(new SetCardInfo("Obelisk of Undoing", 392, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); + cards.add(new SetCardInfo("Orcish Artillery", 253, Rarity.UNCOMMON, mage.cards.o.OrcishArtillery.class)); + cards.add(new SetCardInfo("Orcish Captain", 254, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); + cards.add(new SetCardInfo("Orcish Oriflamme", 257, Rarity.UNCOMMON, mage.cards.o.OrcishOriflamme.class)); + cards.add(new SetCardInfo("Orcish Squatters", 258, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 48, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 49, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Orgg", 259, Rarity.RARE, mage.cards.o.Orgg.class)); + cards.add(new SetCardInfo("Ornithopter", 393, Rarity.UNCOMMON, mage.cards.o.Ornithopter.class)); + cards.add(new SetCardInfo("Panic", 260, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Paralyze", 185, Rarity.COMMON, mage.cards.p.Paralyze.class)); + cards.add(new SetCardInfo("Pearled Unicorn", 50, Rarity.COMMON, mage.cards.p.PearledUnicorn.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 394, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Personal Incarnation", 51, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); + cards.add(new SetCardInfo("Pestilence", 186, Rarity.COMMON, mage.cards.p.Pestilence.class)); + cards.add(new SetCardInfo("Phantasmal Forces", 106, Rarity.UNCOMMON, mage.cards.p.PhantasmalForces.class)); + cards.add(new SetCardInfo("Phantasmal Terrain", 107, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); + cards.add(new SetCardInfo("Phantom Monster", 108, Rarity.UNCOMMON, mage.cards.p.PhantomMonster.class)); + cards.add(new SetCardInfo("Pikemen", 52, Rarity.COMMON, mage.cards.p.Pikemen.class)); + cards.add(new SetCardInfo("Pirate Ship", 109, Rarity.RARE, mage.cards.p.PirateShip.class)); + cards.add(new SetCardInfo("Pit Scorpion", 187, Rarity.COMMON, mage.cards.p.PitScorpion.class)); + cards.add(new SetCardInfo("Plague Rats", 188, Rarity.COMMON, mage.cards.p.PlagueRats.class)); + cards.add(new SetCardInfo("Plains", 430, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 431, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 432, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 433, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Portent", 110, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Power Sink", 111, Rarity.UNCOMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Pox", 189, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Pradesh Gypsies", 317, Rarity.COMMON, mage.cards.p.PradeshGypsies.class)); + cards.add(new SetCardInfo("Primal Clay", 395, Rarity.RARE, mage.cards.p.PrimalClay.class)); + cards.add(new SetCardInfo("Primal Order", 318, Rarity.RARE, mage.cards.p.PrimalOrder.class)); + cards.add(new SetCardInfo("Primordial Ooze", 261, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); + cards.add(new SetCardInfo("Prismatic Ward", 53, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); + cards.add(new SetCardInfo("Prodigal Sorcerer", 112, Rarity.COMMON, mage.cards.p.ProdigalSorcerer.class)); + cards.add(new SetCardInfo("Psychic Venom", 113, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); + cards.add(new SetCardInfo("Pyroblast", 262, Rarity.UNCOMMON, mage.cards.p.Pyroblast.class)); + cards.add(new SetCardInfo("Pyrotechnics", 263, Rarity.UNCOMMON, mage.cards.p.Pyrotechnics.class)); + cards.add(new SetCardInfo("Rabid Wombat", 319, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); + cards.add(new SetCardInfo("Radjan Spirit", 320, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); + cards.add(new SetCardInfo("Rag Man", 190, Rarity.RARE, mage.cards.r.RagMan.class)); + cards.add(new SetCardInfo("Raise Dead", 191, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Ray of Command", 114, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Recall", 115, Rarity.RARE, mage.cards.r.Recall.class)); + cards.add(new SetCardInfo("Reef Pirates", 116, Rarity.COMMON, mage.cards.r.ReefPirates.class)); + cards.add(new SetCardInfo("Regeneration", 321, Rarity.COMMON, mage.cards.r.Regeneration.class)); + cards.add(new SetCardInfo("Remove Soul", 117, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Repentant Blacksmith", 54, Rarity.COMMON, mage.cards.r.RepentantBlacksmith.class)); + cards.add(new SetCardInfo("Reverse Damage", 55, Rarity.RARE, mage.cards.r.ReverseDamage.class)); + cards.add(new SetCardInfo("Righteousness", 56, Rarity.RARE, mage.cards.r.Righteousness.class)); + cards.add(new SetCardInfo("Rod of Ruin", 396, Rarity.UNCOMMON, mage.cards.r.RodOfRuin.class)); + cards.add(new SetCardInfo("Ruins of Trokair", 422, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); + cards.add(new SetCardInfo("Sabretooth Tiger", 264, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); + cards.add(new SetCardInfo("Samite Healer", 58, Rarity.COMMON, mage.cards.s.SamiteHealer.class)); + cards.add(new SetCardInfo("Sand Silos", 423, Rarity.RARE, mage.cards.s.SandSilos.class)); + cards.add(new SetCardInfo("Scaled Wurm", 322, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); + cards.add(new SetCardInfo("Scathe Zombies", 192, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); + cards.add(new SetCardInfo("Scavenger Folk", 323, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Scryb Sprites", 324, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); + cards.add(new SetCardInfo("Sea Serpent", 118, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); + cards.add(new SetCardInfo("Sea Spirit", 119, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Sea Sprite", 120, Rarity.UNCOMMON, mage.cards.s.SeaSprite.class)); + cards.add(new SetCardInfo("Seasinger", 121, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); + cards.add(new SetCardInfo("Segovian Leviathan", 122, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); + cards.add(new SetCardInfo("Sengir Autocrat", 193, Rarity.RARE, mage.cards.s.SengirAutocrat.class)); + cards.add(new SetCardInfo("Seraph", 59, Rarity.RARE, mage.cards.s.Seraph.class)); + cards.add(new SetCardInfo("Serpent Generator", 397, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Serra Bestiary", 60, Rarity.UNCOMMON, mage.cards.s.SerraBestiary.class)); + cards.add(new SetCardInfo("Serra Paladin", 61, Rarity.UNCOMMON, mage.cards.s.SerraPaladin.class)); + cards.add(new SetCardInfo("Shanodin Dryads", 325, Rarity.COMMON, mage.cards.s.ShanodinDryads.class)); + cards.add(new SetCardInfo("Shapeshifter", 398, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); + cards.add(new SetCardInfo("Shatter", 265, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shatterstorm", 266, Rarity.UNCOMMON, mage.cards.s.Shatterstorm.class)); + cards.add(new SetCardInfo("Shield Bearer", 62, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shield Wall", 63, Rarity.COMMON, mage.cards.s.ShieldWall.class)); + cards.add(new SetCardInfo("Shivan Dragon", 267, Rarity.RARE, mage.cards.s.ShivanDragon.class)); + cards.add(new SetCardInfo("Shrink", 326, Rarity.COMMON, mage.cards.s.Shrink.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 123, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Skull Catapult", 399, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Smoke", 268, Rarity.RARE, mage.cards.s.Smoke.class)); + cards.add(new SetCardInfo("Sorceress Queen", 194, Rarity.RARE, mage.cards.s.SorceressQueen.class)); + cards.add(new SetCardInfo("Soul Barrier", 125, Rarity.COMMON, mage.cards.s.SoulBarrier.class)); + cards.add(new SetCardInfo("Soul Net", 400, Rarity.UNCOMMON, mage.cards.s.SoulNet.class)); + cards.add(new SetCardInfo("Spell Blast", 126, Rarity.COMMON, mage.cards.s.SpellBlast.class)); + cards.add(new SetCardInfo("Spirit Link", 64, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); + cards.add(new SetCardInfo("Stampede", 327, Rarity.RARE, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stasis", 127, Rarity.RARE, mage.cards.s.Stasis.class)); + cards.add(new SetCardInfo("Steal Artifact", 128, Rarity.UNCOMMON, mage.cards.s.StealArtifact.class)); + cards.add(new SetCardInfo("Stone Giant", 269, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); + cards.add(new SetCardInfo("Stone Rain", 270, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Stone Spirit", 271, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stream of Life", 328, Rarity.COMMON, mage.cards.s.StreamOfLife.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 195, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Sulfurous Springs", 424, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); + cards.add(new SetCardInfo("Svyelunite Temple", 425, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); + cards.add(new SetCardInfo("Swamp", 438, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 439, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 440, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 441, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Library", 329, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); + cards.add(new SetCardInfo("Tarpan", 330, Rarity.COMMON, mage.cards.t.Tarpan.class)); + cards.add(new SetCardInfo("Tawnos's Weaponry", 401, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); + cards.add(new SetCardInfo("Terror", 196, Rarity.COMMON, mage.cards.t.Terror.class)); + cards.add(new SetCardInfo("The Brute", 272, Rarity.COMMON, mage.cards.t.TheBrute.class)); + cards.add(new SetCardInfo("The Hive", 402, Rarity.RARE, mage.cards.t.TheHive.class)); + cards.add(new SetCardInfo("The Wretched", 197, Rarity.RARE, mage.cards.t.TheWretched.class)); + cards.add(new SetCardInfo("Thicket Basilisk", 331, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); + cards.add(new SetCardInfo("Throne of Bone", 403, Rarity.UNCOMMON, mage.cards.t.ThroneOfBone.class)); + cards.add(new SetCardInfo("Thrull Retainer", 198, Rarity.UNCOMMON, mage.cards.t.ThrullRetainer.class)); + cards.add(new SetCardInfo("Time Bomb", 404, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Time Elemental", 129, Rarity.RARE, mage.cards.t.TimeElemental.class)); + cards.add(new SetCardInfo("Titania's Song", 332, Rarity.RARE, mage.cards.t.TitaniasSong.class)); + cards.add(new SetCardInfo("Torture", 199, Rarity.COMMON, mage.cards.t.Torture.class)); + cards.add(new SetCardInfo("Touch of Death", 200, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); + cards.add(new SetCardInfo("Tranquility", 333, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Truce", 65, Rarity.RARE, mage.cards.t.Truce.class)); + cards.add(new SetCardInfo("Tsunami", 334, Rarity.UNCOMMON, mage.cards.t.Tsunami.class)); + cards.add(new SetCardInfo("Tundra Wolves", 66, Rarity.COMMON, mage.cards.t.TundraWolves.class)); + cards.add(new SetCardInfo("Twiddle", 130, Rarity.COMMON, mage.cards.t.Twiddle.class)); + cards.add(new SetCardInfo("Underground River", 426, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); + cards.add(new SetCardInfo("Unholy Strength", 201, Rarity.COMMON, mage.cards.u.UnholyStrength.class)); + cards.add(new SetCardInfo("Unstable Mutation", 131, Rarity.COMMON, mage.cards.u.UnstableMutation.class)); + cards.add(new SetCardInfo("Unsummon", 132, Rarity.COMMON, mage.cards.u.Unsummon.class)); + cards.add(new SetCardInfo("Untamed Wilds", 335, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Updraft", 133, Rarity.COMMON, mage.cards.u.Updraft.class)); + cards.add(new SetCardInfo("Urza's Avenger", 405, Rarity.RARE, mage.cards.u.UrzasAvenger.class)); + cards.add(new SetCardInfo("Urza's Bauble", 406, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); + cards.add(new SetCardInfo("Urza's Mine", 427, Rarity.COMMON, mage.cards.u.UrzasMine.class)); + cards.add(new SetCardInfo("Urza's Power Plant", 428, Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class)); + cards.add(new SetCardInfo("Urza's Tower", 429, Rarity.COMMON, mage.cards.u.UrzasTower.class)); + cards.add(new SetCardInfo("Vampire Bats", 202, Rarity.COMMON, mage.cards.v.VampireBats.class)); + cards.add(new SetCardInfo("Venom", 336, Rarity.COMMON, mage.cards.v.Venom.class)); + cards.add(new SetCardInfo("Verduran Enchantress", 337, Rarity.RARE, mage.cards.v.VerduranEnchantress.class)); + cards.add(new SetCardInfo("Vodalian Soldiers", 134, Rarity.COMMON, mage.cards.v.VodalianSoldiers.class)); + cards.add(new SetCardInfo("Wall of Air", 135, Rarity.UNCOMMON, mage.cards.w.WallOfAir.class)); + cards.add(new SetCardInfo("Wall of Bone", 203, Rarity.UNCOMMON, mage.cards.w.WallOfBone.class)); + cards.add(new SetCardInfo("Wall of Brambles", 338, Rarity.UNCOMMON, mage.cards.w.WallOfBrambles.class)); + cards.add(new SetCardInfo("Wall of Fire", 273, Rarity.UNCOMMON, mage.cards.w.WallOfFire.class)); + cards.add(new SetCardInfo("Wall of Spears", 407, Rarity.COMMON, mage.cards.w.WallOfSpears.class)); + cards.add(new SetCardInfo("Wall of Stone", 274, Rarity.UNCOMMON, mage.cards.w.WallOfStone.class)); + cards.add(new SetCardInfo("Wall of Swords", 67, Rarity.UNCOMMON, mage.cards.w.WallOfSwords.class)); + cards.add(new SetCardInfo("Wanderlust", 339, Rarity.UNCOMMON, mage.cards.w.Wanderlust.class)); + cards.add(new SetCardInfo("War Mammoth", 340, Rarity.COMMON, mage.cards.w.WarMammoth.class)); + cards.add(new SetCardInfo("Warp Artifact", 204, Rarity.RARE, mage.cards.w.WarpArtifact.class)); + cards.add(new SetCardInfo("Weakness", 205, Rarity.COMMON, mage.cards.w.Weakness.class)); + cards.add(new SetCardInfo("Whirling Dervish", 341, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); + cards.add(new SetCardInfo("White Knight", 68, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); + cards.add(new SetCardInfo("Wild Growth", 342, Rarity.COMMON, mage.cards.w.WildGrowth.class)); + cards.add(new SetCardInfo("Wind Spirit", 136, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Winds of Change", 275, Rarity.RARE, mage.cards.w.WindsOfChange.class)); + cards.add(new SetCardInfo("Winter Blast", 343, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Orb", 408, Rarity.RARE, mage.cards.w.WinterOrb.class)); + cards.add(new SetCardInfo("Wolverine Pack", 344, Rarity.UNCOMMON, mage.cards.w.WolverinePack.class)); + cards.add(new SetCardInfo("Wooden Sphere", 409, Rarity.UNCOMMON, mage.cards.w.WoodenSphere.class)); + cards.add(new SetCardInfo("Word of Blasting", 276, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); + cards.add(new SetCardInfo("Wrath of God", 69, Rarity.RARE, mage.cards.w.WrathOfGod.class)); + cards.add(new SetCardInfo("Wyluli Wolf", 345, Rarity.RARE, mage.cards.w.WyluliWolf.class)); + cards.add(new SetCardInfo("Xenic Poltergeist", 206, Rarity.RARE, mage.cards.x.XenicPoltergeist.class)); + cards.add(new SetCardInfo("Zephyr Falcon", 137, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); + cards.add(new SetCardInfo("Zombie Master", 207, Rarity.RARE, mage.cards.z.ZombieMaster.class)); + cards.add(new SetCardInfo("Zur's Weirding", 138, Rarity.RARE, mage.cards.z.ZursWeirding.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/GameNight.java b/Mage.Sets/src/mage/sets/GameNight.java new file mode 100644 index 0000000000..84631bf8ac --- /dev/null +++ b/Mage.Sets/src/mage/sets/GameNight.java @@ -0,0 +1,91 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class GameNight extends ExpansionSet { + + private static final GameNight instance = new GameNight(); + + public static GameNight getInstance() { + return instance; + } + + private GameNight() { + super("Game Night", "GNT", ExpansionSet.buildDate(2018, 11, 16), SetType.SUPPLEMENTAL); + this.hasBasicLands = true; + + cards.add(new SetCardInfo("Advanced Stitchwing", 18, Rarity.UNCOMMON, mage.cards.a.AdvancedStitchwing.class)); + cards.add(new SetCardInfo("Aerial Responder", 6, Rarity.UNCOMMON, mage.cards.a.AerialResponder.class)); + cards.add(new SetCardInfo("Air Elemental", 19, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Always Watching", 7, Rarity.RARE, mage.cards.a.AlwaysWatching.class)); + cards.add(new SetCardInfo("Avatar of Growth", 5, Rarity.MYTHIC, mage.cards.a.AvatarOfGrowth.class)); + cards.add(new SetCardInfo("Benalish Marshal", 8, Rarity.RARE, mage.cards.b.BenalishMarshal.class)); + cards.add(new SetCardInfo("Bombard", 37, Rarity.COMMON, mage.cards.b.Bombard.class)); + cards.add(new SetCardInfo("Bone Splinters", 27, Rarity.COMMON, mage.cards.b.BoneSplinters.class)); + cards.add(new SetCardInfo("Bright Reprisal", 9, Rarity.UNCOMMON, mage.cards.b.BrightReprisal.class)); + cards.add(new SetCardInfo("Call the Cavalry", 10, Rarity.COMMON, mage.cards.c.CallTheCavalry.class)); + cards.add(new SetCardInfo("Captivating Crew", 38, Rarity.RARE, mage.cards.c.CaptivatingCrew.class)); + cards.add(new SetCardInfo("Claustrophobia", 20, Rarity.COMMON, mage.cards.c.Claustrophobia.class)); + cards.add(new SetCardInfo("Cruel Revival", 28, Rarity.UNCOMMON, mage.cards.c.CruelRevival.class)); + cards.add(new SetCardInfo("Dragon Fodder", 39, Rarity.COMMON, mage.cards.d.DragonFodder.class)); + cards.add(new SetCardInfo("Eager Construct", 51, Rarity.COMMON, mage.cards.e.EagerConstruct.class)); + cards.add(new SetCardInfo("Everdawn Champion", 11, Rarity.UNCOMMON, mage.cards.e.EverdawnChampion.class)); + cards.add(new SetCardInfo("Fan Bearer", 12, Rarity.COMMON, mage.cards.f.FanBearer.class)); + cards.add(new SetCardInfo("Favorable Winds", 21, Rarity.UNCOMMON, mage.cards.f.FavorableWinds.class)); + cards.add(new SetCardInfo("Filigree Familiar", 52, Rarity.UNCOMMON, mage.cards.f.FiligreeFamiliar.class)); + cards.add(new SetCardInfo("Fleshbag Marauder", 29, Rarity.UNCOMMON, mage.cards.f.FleshbagMarauder.class)); + cards.add(new SetCardInfo("Forest", 67, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 68, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ghalta, Primal Hunger", 44, Rarity.RARE, mage.cards.g.GhaltaPrimalHunger.class)); + cards.add(new SetCardInfo("Goblin Goliath", 4, Rarity.MYTHIC, mage.cards.g.GoblinGoliath.class)); + cards.add(new SetCardInfo("Gruesome Fate", 30, Rarity.COMMON, mage.cards.g.GruesomeFate.class)); + cards.add(new SetCardInfo("Howling Golem", 53, Rarity.UNCOMMON, mage.cards.h.HowlingGolem.class)); + cards.add(new SetCardInfo("Hydrolash", 22, Rarity.UNCOMMON, mage.cards.h.Hydrolash.class)); + cards.add(new SetCardInfo("Inspired Charge", 13, Rarity.COMMON, mage.cards.i.InspiredCharge.class)); + cards.add(new SetCardInfo("Inspired Sphinx", 2, Rarity.MYTHIC, mage.cards.i.InspiredSphinx.class)); + cards.add(new SetCardInfo("Inspiring Captain", 14, Rarity.COMMON, mage.cards.i.InspiringCaptain.class)); + cards.add(new SetCardInfo("Island", 61, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 62, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jungle Delver", 45, Rarity.COMMON, mage.cards.j.JungleDelver.class)); + cards.add(new SetCardInfo("Languish", 31, Rarity.RARE, mage.cards.l.Languish.class)); + cards.add(new SetCardInfo("Liliana's Mastery", 32, Rarity.RARE, mage.cards.l.LilianasMastery.class)); + cards.add(new SetCardInfo("Llanowar Elves", 46, Rarity.COMMON, mage.cards.l.LlanowarElves.class)); + cards.add(new SetCardInfo("Lord of the Accursed", 33, Rarity.UNCOMMON, mage.cards.l.LordOfTheAccursed.class)); + cards.add(new SetCardInfo("Manalith", 54, Rarity.COMMON, mage.cards.m.Manalith.class)); + cards.add(new SetCardInfo("Mesa Unicorn", 15, Rarity.COMMON, mage.cards.m.MesaUnicorn.class)); + cards.add(new SetCardInfo("Militant Angel", 1, Rarity.MYTHIC, mage.cards.m.MilitantAngel.class)); + cards.add(new SetCardInfo("Mountain", 65, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 66, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nissa's Revelation", 47, Rarity.RARE, mage.cards.n.NissasRevelation.class)); + cards.add(new SetCardInfo("Overcome", 48, Rarity.UNCOMMON, mage.cards.o.Overcome.class)); + cards.add(new SetCardInfo("Pilgrim's Eye", 55, Rarity.UNCOMMON, mage.cards.p.PilgrimsEye.class)); + cards.add(new SetCardInfo("Plains", 59, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 60, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Reckless Scholar", 23, Rarity.UNCOMMON, mage.cards.r.RecklessScholar.class)); + cards.add(new SetCardInfo("Rhonas's Monument", 56, Rarity.UNCOMMON, mage.cards.r.RhonassMonument.class)); + cards.add(new SetCardInfo("Rolling Thunder", 40, Rarity.UNCOMMON, mage.cards.r.RollingThunder.class)); + cards.add(new SetCardInfo("Rot Hulk", 3, Rarity.MYTHIC, mage.cards.r.RotHulk.class)); + cards.add(new SetCardInfo("Seek the Wilds", 49, Rarity.COMMON, mage.cards.s.SeekTheWilds.class)); + cards.add(new SetCardInfo("Seismic Elemental", 41, Rarity.UNCOMMON, mage.cards.s.SeismicElemental.class)); + cards.add(new SetCardInfo("Serra Angel", 16, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); + cards.add(new SetCardInfo("Siege-Gang Commander", 42, Rarity.RARE, mage.cards.s.SiegeGangCommander.class)); + cards.add(new SetCardInfo("Snare Thopter", 57, Rarity.UNCOMMON, mage.cards.s.SnareThopter.class)); + cards.add(new SetCardInfo("Soulblade Djinn", 24, Rarity.RARE, mage.cards.s.SoulbladeDjinn.class)); + cards.add(new SetCardInfo("Subjugator Angel", 17, Rarity.UNCOMMON, mage.cards.s.SubjugatorAngel.class)); + cards.add(new SetCardInfo("Swamp", 63, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 64, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tattered Mummy", 34, Rarity.COMMON, mage.cards.t.TatteredMummy.class)); + cards.add(new SetCardInfo("Thallid Soothsayer", 35, Rarity.UNCOMMON, mage.cards.t.ThallidSoothsayer.class)); + cards.add(new SetCardInfo("Thrashing Brontodon", 50, Rarity.UNCOMMON, mage.cards.t.ThrashingBrontodon.class)); + cards.add(new SetCardInfo("Tormenting Voice", 43, Rarity.COMMON, mage.cards.t.TormentingVoice.class)); + cards.add(new SetCardInfo("Welder Automaton", 58, Rarity.COMMON, mage.cards.w.WelderAutomaton.class)); + cards.add(new SetCardInfo("Whirler Rogue", 25, Rarity.UNCOMMON, mage.cards.w.WhirlerRogue.class)); + cards.add(new SetCardInfo("Zahid, Djinn of the Lamp", 26, Rarity.RARE, mage.cards.z.ZahidDjinnOfTheLamp.class)); + cards.add(new SetCardInfo("Zulaport Cutthroat", 36, Rarity.UNCOMMON, mage.cards.z.ZulaportCutthroat.class)); + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/GlobalSeriesJiangYangguAndMuYanling.java b/Mage.Sets/src/mage/sets/GlobalSeriesJiangYangguAndMuYanling.java index c63ec1e93f..1fe5de31fb 100644 --- a/Mage.Sets/src/mage/sets/GlobalSeriesJiangYangguAndMuYanling.java +++ b/Mage.Sets/src/mage/sets/GlobalSeriesJiangYangguAndMuYanling.java @@ -16,7 +16,7 @@ public final class GlobalSeriesJiangYangguAndMuYanling extends ExpansionSet { } private GlobalSeriesJiangYangguAndMuYanling() { - super("Global Series: Jiang Yanggu & Mu Yanling", "GS1", ExpansionSet.buildDate(2018, 6, 22), SetType.SUPPLEMENTAL_STANDARD_LEGAL); + super("Global Series: Jiang Yanggu & Mu Yanling", "GS1", ExpansionSet.buildDate(2018, 6, 22), SetType.SUPPLEMENTAL); this.blockName = "Global Series"; this.hasBasicLands = true; diff --git a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java index 0c9ee0fd14..2dcf4088b8 100644 --- a/Mage.Sets/src/mage/sets/GuildsOfRavnica.java +++ b/Mage.Sets/src/mage/sets/GuildsOfRavnica.java @@ -86,7 +86,7 @@ public final class GuildsOfRavnica extends ExpansionSet { cards.add(new SetCardInfo("Deadly Visit", 68, Rarity.COMMON, mage.cards.d.DeadlyVisit.class)); cards.add(new SetCardInfo("Deafening Clarion", 165, Rarity.RARE, mage.cards.d.DeafeningClarion.class)); cards.add(new SetCardInfo("Demotion", 9, Rarity.UNCOMMON, mage.cards.d.Demotion.class)); - cards.add(new SetCardInfo("Devious Cover-up", 35, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); + cards.add(new SetCardInfo("Devious Cover-Up", 35, Rarity.COMMON, mage.cards.d.DeviousCoverUp.class)); cards.add(new SetCardInfo("Devkarin Dissident", 127, Rarity.COMMON, mage.cards.d.DevkarinDissident.class)); cards.add(new SetCardInfo("Dimir Guildgate", 245, Rarity.COMMON, mage.cards.d.DimirGuildgate.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Dimir Guildgate", 246, Rarity.COMMON, mage.cards.d.DimirGuildgate.class, NON_FULL_USE_VARIOUS)); @@ -343,4 +343,4 @@ public final class GuildsOfRavnica extends ExpansionSet { } return specialCards; } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/HeroesOfTheRealm.java b/Mage.Sets/src/mage/sets/HeroesOfTheRealm.java new file mode 100644 index 0000000000..4ccfd7f447 --- /dev/null +++ b/Mage.Sets/src/mage/sets/HeroesOfTheRealm.java @@ -0,0 +1,24 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class HeroesOfTheRealm extends ExpansionSet { + + private static final HeroesOfTheRealm instance = new HeroesOfTheRealm(); + + public static HeroesOfTheRealm getInstance() { + return instance; + } + + private HeroesOfTheRealm() { + super("Heroes of the Realm", "HTR", ExpansionSet.buildDate(2017, 9, 20), SetType.JOKESET); + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Chandra, Gremlin Wrangler", 1, Rarity.MYTHIC, mage.cards.c.ChandraGremlinWrangler.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Homelands.java b/Mage.Sets/src/mage/sets/Homelands.java index cc54407c64..6705fa8c66 100644 --- a/Mage.Sets/src/mage/sets/Homelands.java +++ b/Mage.Sets/src/mage/sets/Homelands.java @@ -136,7 +136,8 @@ public final class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Roots", 95, Rarity.UNCOMMON, mage.cards.r.Roots.class)); cards.add(new SetCardInfo("Roterothopter", 109, Rarity.COMMON, mage.cards.r.Roterothopter.class)); cards.add(new SetCardInfo("Rysorian Badger", 96, Rarity.RARE, mage.cards.r.RysorianBadger.class)); - cards.add(new SetCardInfo("Samite Alchemist", 117, Rarity.COMMON, mage.cards.s.SamiteAlchemist.class)); + cards.add(new SetCardInfo("Samite Alchemist", "13a", Rarity.COMMON, mage.cards.s.SamiteAlchemist.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Samite Alchemist", "13b", Rarity.COMMON, mage.cards.s.SamiteAlchemist.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Sea Sprite", 38, Rarity.UNCOMMON, mage.cards.s.SeaSprite.class)); cards.add(new SetCardInfo("Sea Troll", 39, Rarity.UNCOMMON, mage.cards.s.SeaTroll.class)); cards.add(new SetCardInfo("Sengir Autocrat", 56, Rarity.UNCOMMON, mage.cards.s.SengirAutocrat.class)); @@ -164,4 +165,4 @@ public final class Homelands extends ExpansionSet { cards.add(new SetCardInfo("Winter Sky", 80, Rarity.RARE, mage.cards.w.WinterSky.class)); cards.add(new SetCardInfo("Wizards' School", 115, Rarity.UNCOMMON, mage.cards.w.WizardsSchool.class)); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/sets/IceAge.java b/Mage.Sets/src/mage/sets/IceAge.java index fc2e781f9c..863417b6be 100644 --- a/Mage.Sets/src/mage/sets/IceAge.java +++ b/Mage.Sets/src/mage/sets/IceAge.java @@ -1,356 +1,379 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class IceAge extends ExpansionSet { - - private static final IceAge instance = new IceAge(); - - public static IceAge getInstance() { - return instance; - } - - private IceAge() { - super("Ice Age", "ICE", ExpansionSet.buildDate(1995, 5, 1), SetType.EXPANSION); - this.blockName = "Ice Age"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abyssal Specter", 113, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); - cards.add(new SetCardInfo("Adarkar Sentinel", 306, Rarity.UNCOMMON, mage.cards.a.AdarkarSentinel.class)); - cards.add(new SetCardInfo("Adarkar Wastes", 351, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); - cards.add(new SetCardInfo("Aegis of the Meek", 307, Rarity.RARE, mage.cards.a.AegisOfTheMeek.class)); - cards.add(new SetCardInfo("Altar of Bone", 281, Rarity.RARE, mage.cards.a.AltarOfBone.class)); - cards.add(new SetCardInfo("Anarchy", 170, Rarity.UNCOMMON, mage.cards.a.Anarchy.class)); - cards.add(new SetCardInfo("Arenson's Aura", 3, Rarity.COMMON, mage.cards.a.ArensonsAura.class)); - cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Arnjlot's Ascent", 57, Rarity.COMMON, mage.cards.a.ArnjlotsAscent.class)); - cards.add(new SetCardInfo("Ashen Ghoul", 114, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); - cards.add(new SetCardInfo("Aurochs", 225, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Avalanche", 171, Rarity.UNCOMMON, mage.cards.a.Avalanche.class)); - cards.add(new SetCardInfo("Balduvian Barbarians", 172, Rarity.COMMON, mage.cards.b.BalduvianBarbarians.class)); - cards.add(new SetCardInfo("Balduvian Bears", 226, Rarity.COMMON, mage.cards.b.BalduvianBears.class)); - cards.add(new SetCardInfo("Balduvian Conjurer", 58, Rarity.UNCOMMON, mage.cards.b.BalduvianConjurer.class)); - cards.add(new SetCardInfo("Balduvian Hydra", 173, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); - cards.add(new SetCardInfo("Barbed Sextant", 312, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Baton of Morale", 313, Rarity.UNCOMMON, mage.cards.b.BatonOfMorale.class)); - cards.add(new SetCardInfo("Battle Cry", 5, Rarity.UNCOMMON, mage.cards.b.BattleCry.class)); - cards.add(new SetCardInfo("Battle Frenzy", 175, Rarity.COMMON, mage.cards.b.BattleFrenzy.class)); - cards.add(new SetCardInfo("Binding Grasp", 60, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Black Scarab", 6, Rarity.UNCOMMON, mage.cards.b.BlackScarab.class)); - cards.add(new SetCardInfo("Blessed Wine", 7, Rarity.COMMON, mage.cards.b.BlessedWine.class)); - cards.add(new SetCardInfo("Blinking Spirit", 8, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); - cards.add(new SetCardInfo("Blizzard", 227, Rarity.RARE, mage.cards.b.Blizzard.class)); - cards.add(new SetCardInfo("Blue Scarab", 9, Rarity.UNCOMMON, mage.cards.b.BlueScarab.class)); - cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brand of Ill Omen", 177, Rarity.RARE, mage.cards.b.BrandOfIllOmen.class)); - cards.add(new SetCardInfo("Breath of Dreams", 62, Rarity.UNCOMMON, mage.cards.b.BreathOfDreams.class)); - cards.add(new SetCardInfo("Brine Shaman", 115, Rarity.COMMON, mage.cards.b.BrineShaman.class)); - cards.add(new SetCardInfo("Brown Ouphe", 228, Rarity.COMMON, mage.cards.b.BrownOuphe.class)); - cards.add(new SetCardInfo("Brushland", 352, Rarity.RARE, mage.cards.b.Brushland.class)); - cards.add(new SetCardInfo("Burnt Offering", 116, Rarity.COMMON, mage.cards.b.BurntOffering.class)); - cards.add(new SetCardInfo("Call to Arms", 10, Rarity.RARE, mage.cards.c.CallToArms.class)); - cards.add(new SetCardInfo("Caribou Range", 11, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Celestial Sword", 314, Rarity.RARE, mage.cards.c.CelestialSword.class)); - cards.add(new SetCardInfo("Centaur Archer", 282, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); - cards.add(new SetCardInfo("Chaos Moon", 179, Rarity.RARE, mage.cards.c.ChaosMoon.class)); - cards.add(new SetCardInfo("Chub Toad", 229, Rarity.COMMON, mage.cards.c.ChubToad.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 14, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 15, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 16, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("Clairvoyance", 63, Rarity.COMMON, mage.cards.c.Clairvoyance.class)); - cards.add(new SetCardInfo("Cold Snap", 17, Rarity.UNCOMMON, mage.cards.c.ColdSnap.class)); - cards.add(new SetCardInfo("Conquer", 180, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Cooperation", 18, Rarity.COMMON, mage.cards.c.Cooperation.class)); - cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crown of the Ages", 315, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); - cards.add(new SetCardInfo("Curse of Marit Lage", 181, Rarity.RARE, mage.cards.c.CurseOfMaritLage.class)); - cards.add(new SetCardInfo("Dance of the Dead", 118, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); - cards.add(new SetCardInfo("Dark Banishing", 119, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Dark Ritual", 120, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Death Ward", 19, Rarity.COMMON, mage.cards.d.DeathWard.class)); - cards.add(new SetCardInfo("Deflection", 65, Rarity.RARE, mage.cards.d.Deflection.class)); - cards.add(new SetCardInfo("Demonic Consultation", 121, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); - cards.add(new SetCardInfo("Despotic Scepter", 316, Rarity.RARE, mage.cards.d.DespoticScepter.class)); - cards.add(new SetCardInfo("Diabolic Vision", 284, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); - cards.add(new SetCardInfo("Dire Wolves", 230, Rarity.COMMON, mage.cards.d.DireWolves.class)); - cards.add(new SetCardInfo("Disenchant", 20, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dreams of the Dead", 66, Rarity.UNCOMMON, mage.cards.d.DreamsOfTheDead.class)); - cards.add(new SetCardInfo("Drift of the Dead", 123, Rarity.UNCOMMON, mage.cards.d.DriftOfTheDead.class)); - cards.add(new SetCardInfo("Drought", 21, Rarity.UNCOMMON, mage.cards.d.Drought.class)); - cards.add(new SetCardInfo("Dwarven Armory", 182, Rarity.RARE, mage.cards.d.DwarvenArmory.class)); - cards.add(new SetCardInfo("Earthlink", 285, Rarity.RARE, mage.cards.e.Earthlink.class)); - cards.add(new SetCardInfo("Earthlore", 231, Rarity.COMMON, mage.cards.e.Earthlore.class)); - cards.add(new SetCardInfo("Elder Druid", 232, Rarity.RARE, mage.cards.e.ElderDruid.class)); - cards.add(new SetCardInfo("Elemental Augury", 286, Rarity.RARE, mage.cards.e.ElementalAugury.class)); - cards.add(new SetCardInfo("Elkin Bottle", 317, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Enduring Renewal", 23, Rarity.RARE, mage.cards.e.EnduringRenewal.class)); - cards.add(new SetCardInfo("Energy Storm", 24, Rarity.RARE, mage.cards.e.EnergyStorm.class)); - cards.add(new SetCardInfo("Enervate", 67, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Errantry", 183, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Essence Filter", 233, Rarity.COMMON, mage.cards.e.EssenceFilter.class)); - cards.add(new SetCardInfo("Essence Flare", 69, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); - cards.add(new SetCardInfo("Fanatical Fever", 234, Rarity.UNCOMMON, mage.cards.f.FanaticalFever.class)); - cards.add(new SetCardInfo("Fear", 124, Rarity.COMMON, mage.cards.f.Fear.class)); - cards.add(new SetCardInfo("Fiery Justice", 288, Rarity.RARE, mage.cards.f.FieryJustice.class)); - cards.add(new SetCardInfo("Fire Covenant", 289, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); - cards.add(new SetCardInfo("Flame Spirit", 184, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Flare", 185, Rarity.COMMON, mage.cards.f.Flare.class)); - cards.add(new SetCardInfo("Flooded Woodlands", 290, Rarity.RARE, mage.cards.f.FloodedWoodlands.class)); - cards.add(new SetCardInfo("Flow of Maggots", 125, Rarity.RARE, mage.cards.f.FlowOfMaggots.class)); - cards.add(new SetCardInfo("Folk of the Pines", 235, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); - cards.add(new SetCardInfo("Forbidden Lore", 236, Rarity.RARE, mage.cards.f.ForbiddenLore.class)); - cards.add(new SetCardInfo("Force Void", 70, Rarity.UNCOMMON, mage.cards.f.ForceVoid.class)); - cards.add(new SetCardInfo("Forest", 380, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 381, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 382, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forgotten Lore", 237, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); - cards.add(new SetCardInfo("Formation", 25, Rarity.RARE, mage.cards.f.Formation.class)); - cards.add(new SetCardInfo("Foul Familiar", 126, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); - cards.add(new SetCardInfo("Foxfire", 238, Rarity.COMMON, mage.cards.f.Foxfire.class)); - cards.add(new SetCardInfo("Freyalise's Charm", 240, Rarity.UNCOMMON, mage.cards.f.FreyalisesCharm.class)); - cards.add(new SetCardInfo("Fumarole", 291, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); - cards.add(new SetCardInfo("Fyndhorn Bow", 318, Rarity.UNCOMMON, mage.cards.f.FyndhornBow.class)); - cards.add(new SetCardInfo("Fyndhorn Brownie", 242, Rarity.COMMON, mage.cards.f.FyndhornBrownie.class)); - cards.add(new SetCardInfo("Fyndhorn Elder", 243, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); - cards.add(new SetCardInfo("Fyndhorn Elves", 244, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); - cards.add(new SetCardInfo("Fyndhorn Pollen", 245, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); - cards.add(new SetCardInfo("Game of Chaos", 186, Rarity.RARE, mage.cards.g.GameOfChaos.class)); - cards.add(new SetCardInfo("Gangrenous Zombies", 127, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); - cards.add(new SetCardInfo("General Jarkeld", 27, Rarity.RARE, mage.cards.g.GeneralJarkeld.class)); - cards.add(new SetCardInfo("Giant Growth", 246, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Trap Door Spider", 293, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); - cards.add(new SetCardInfo("Glacial Chasm", 353, Rarity.UNCOMMON, mage.cards.g.GlacialChasm.class)); - cards.add(new SetCardInfo("Glacial Crevasses", 187, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); - cards.add(new SetCardInfo("Glacial Wall", 71, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); - cards.add(new SetCardInfo("Goblin Lyre", 319, Rarity.RARE, mage.cards.g.GoblinLyre.class)); - cards.add(new SetCardInfo("Goblin Mutant", 188, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); - cards.add(new SetCardInfo("Goblin Snowman", 191, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); - cards.add(new SetCardInfo("Gorilla Pack", 247, Rarity.COMMON, mage.cards.g.GorillaPack.class)); - cards.add(new SetCardInfo("Gravebind", 129, Rarity.RARE, mage.cards.g.Gravebind.class)); - cards.add(new SetCardInfo("Green Scarab", 28, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class)); - cards.add(new SetCardInfo("Hallowed Ground", 29, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); - cards.add(new SetCardInfo("Halls of Mist", 354, Rarity.RARE, mage.cards.h.HallsOfMist.class)); - cards.add(new SetCardInfo("Heal", 30, Rarity.COMMON, mage.cards.h.Heal.class)); - cards.add(new SetCardInfo("Hecatomb", 130, Rarity.RARE, mage.cards.h.Hecatomb.class)); - cards.add(new SetCardInfo("Hematite Talisman", 320, Rarity.UNCOMMON, mage.cards.h.HematiteTalisman.class)); - cards.add(new SetCardInfo("Hoar Shade", 131, Rarity.COMMON, mage.cards.h.HoarShade.class)); - cards.add(new SetCardInfo("Hot Springs", 248, Rarity.RARE, mage.cards.h.HotSprings.class)); - cards.add(new SetCardInfo("Howl from Beyond", 132, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Hurricane", 249, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); - cards.add(new SetCardInfo("Hyalopterous Lemure", 133, Rarity.UNCOMMON, mage.cards.h.HyalopterousLemure.class)); - cards.add(new SetCardInfo("Hydroblast", 72, Rarity.COMMON, mage.cards.h.Hydroblast.class)); - cards.add(new SetCardInfo("Hymn of Rebirth", 295, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); - cards.add(new SetCardInfo("Ice Cauldron", 321, Rarity.RARE, mage.cards.i.IceCauldron.class)); - cards.add(new SetCardInfo("Ice Floe", 355, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Iceberg", 73, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); - cards.add(new SetCardInfo("Icequake", 134, Rarity.UNCOMMON, mage.cards.i.Icequake.class)); - cards.add(new SetCardInfo("Icy Manipulator", 322, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); - cards.add(new SetCardInfo("Icy Prison", 74, Rarity.RARE, mage.cards.i.IcyPrison.class)); - cards.add(new SetCardInfo("Illusionary Forces", 75, Rarity.COMMON, mage.cards.i.IllusionaryForces.class)); - cards.add(new SetCardInfo("Illusionary Wall", 78, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); - cards.add(new SetCardInfo("Illusions of Grandeur", 79, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); - cards.add(new SetCardInfo("Imposing Visage", 193, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); - cards.add(new SetCardInfo("Incinerate", 194, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infernal Darkness", 135, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); - cards.add(new SetCardInfo("Infernal Denizen", 136, Rarity.RARE, mage.cards.i.InfernalDenizen.class)); - cards.add(new SetCardInfo("Infinite Hourglass", 323, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); - cards.add(new SetCardInfo("Infuse", 80, Rarity.COMMON, mage.cards.i.Infuse.class)); - cards.add(new SetCardInfo("Island", 368, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 369, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 370, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jester's Cap", 324, Rarity.RARE, mage.cards.j.JestersCap.class)); - cards.add(new SetCardInfo("Jester's Mask", 325, Rarity.RARE, mage.cards.j.JestersMask.class)); - cards.add(new SetCardInfo("Jeweled Amulet", 326, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); - cards.add(new SetCardInfo("Johtull Wurm", 250, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Jokulhaups", 195, Rarity.RARE, mage.cards.j.Jokulhaups.class)); - cards.add(new SetCardInfo("Juniper Order Druid", 251, Rarity.COMMON, mage.cards.j.JuniperOrderDruid.class)); - cards.add(new SetCardInfo("Justice", 32, Rarity.UNCOMMON, mage.cards.j.Justice.class)); - cards.add(new SetCardInfo("Karplusan Forest", 356, Rarity.RARE, mage.cards.k.KarplusanForest.class)); - cards.add(new SetCardInfo("Karplusan Giant", 196, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); - cards.add(new SetCardInfo("Karplusan Yeti", 197, Rarity.RARE, mage.cards.k.KarplusanYeti.class)); - cards.add(new SetCardInfo("Kelsinko Ranger", 33, Rarity.COMMON, mage.cards.k.KelsinkoRanger.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 137, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Frostbeast", 296, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); - cards.add(new SetCardInfo("Kjeldoran Knight", 36, Rarity.RARE, mage.cards.k.KjeldoranKnight.class)); - cards.add(new SetCardInfo("Kjeldoran Phalanx", 37, Rarity.RARE, mage.cards.k.KjeldoranPhalanx.class)); - cards.add(new SetCardInfo("Kjeldoran Royal Guard", 38, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 39, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Kjeldoran Skyknight", 40, Rarity.COMMON, mage.cards.k.KjeldoranSkyknight.class)); - cards.add(new SetCardInfo("Kjeldoran Warrior", 41, Rarity.COMMON, mage.cards.k.KjeldoranWarrior.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 138, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Elementalist", 139, Rarity.UNCOMMON, mage.cards.k.KrovikanElementalist.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 140, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 81, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Land Cap", 357, Rarity.RARE, mage.cards.l.LandCap.class)); - cards.add(new SetCardInfo("Lapis Lazuli Talisman", 327, Rarity.UNCOMMON, mage.cards.l.LapisLazuliTalisman.class)); - cards.add(new SetCardInfo("Lava Tubes", 358, Rarity.RARE, mage.cards.l.LavaTubes.class)); - cards.add(new SetCardInfo("Legions of Lim-Dul", 142, Rarity.COMMON, mage.cards.l.LegionsOfLimDul.class)); - cards.add(new SetCardInfo("Leshrac's Rite", 143, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); - cards.add(new SetCardInfo("Leshrac's Sigil", 144, Rarity.UNCOMMON, mage.cards.l.LeshracsSigil.class)); - cards.add(new SetCardInfo("Lhurgoyf", 252, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); - cards.add(new SetCardInfo("Lightning Blow", 42, Rarity.RARE, mage.cards.l.LightningBlow.class)); - cards.add(new SetCardInfo("Lim-Dul's Hex", 146, Rarity.UNCOMMON, mage.cards.l.LimDulsHex.class)); - cards.add(new SetCardInfo("Lure", 253, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Malachite Talisman", 328, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); - cards.add(new SetCardInfo("Marton Stromgald", 204, Rarity.RARE, mage.cards.m.MartonStromgald.class)); - cards.add(new SetCardInfo("Melee", 199, Rarity.UNCOMMON, mage.cards.m.Melee.class)); - cards.add(new SetCardInfo("Melting", 200, Rarity.UNCOMMON, mage.cards.m.Melting.class)); - cards.add(new SetCardInfo("Merieke Ri Berit", 297, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); - cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); - cards.add(new SetCardInfo("Meteor Shower", 201, Rarity.COMMON, mage.cards.m.MeteorShower.class)); - cards.add(new SetCardInfo("Mind Ravel", 147, Rarity.COMMON, mage.cards.m.MindRavel.class)); - cards.add(new SetCardInfo("Mind Warp", 148, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); - cards.add(new SetCardInfo("Minion of Leshrac", 150, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); - cards.add(new SetCardInfo("Minion of Tevesh Szat", 151, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); - cards.add(new SetCardInfo("Mole Worms", 152, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); - cards.add(new SetCardInfo("Monsoon", 298, Rarity.RARE, mage.cards.m.Monsoon.class)); - cards.add(new SetCardInfo("Moor Fiend", 153, Rarity.COMMON, mage.cards.m.MoorFiend.class)); - cards.add(new SetCardInfo("Mountain Goat", 202, Rarity.COMMON, mage.cards.m.MountainGoat.class)); - cards.add(new SetCardInfo("Mountain Titan", 299, Rarity.RARE, mage.cards.m.MountainTitan.class)); - cards.add(new SetCardInfo("Mountain", 376, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 377, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 378, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mudslide", 203, Rarity.RARE, mage.cards.m.Mudslide.class)); - cards.add(new SetCardInfo("Mystic Might", 86, Rarity.RARE, mage.cards.m.MysticMight.class)); - cards.add(new SetCardInfo("Mystic Remora", 87, Rarity.COMMON, mage.cards.m.MysticRemora.class)); - cards.add(new SetCardInfo("Nacre Talisman", 329, Rarity.UNCOMMON, mage.cards.n.NacreTalisman.class)); - cards.add(new SetCardInfo("Naked Singularity", 330, Rarity.RARE, mage.cards.n.NakedSingularity.class)); - cards.add(new SetCardInfo("Nature's Lore", 255, Rarity.UNCOMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Necropotence", 154, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Norritt", 155, Rarity.COMMON, mage.cards.n.Norritt.class)); - cards.add(new SetCardInfo("Onyx Talisman", 331, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class)); - cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); - cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class)); - cards.add(new SetCardInfo("Orcish Librarian", 209, Rarity.RARE, mage.cards.o.OrcishLibrarian.class)); - cards.add(new SetCardInfo("Orcish Lumberjack", 210, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); - cards.add(new SetCardInfo("Orcish Squatters", 211, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 45, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 46, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Pale Bears", 256, Rarity.RARE, mage.cards.p.PaleBears.class)); - cards.add(new SetCardInfo("Panic", 212, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 332, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Pestilence Rats", 157, Rarity.COMMON, mage.cards.p.PestilenceRats.class)); - cards.add(new SetCardInfo("Pit Trap", 333, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); - cards.add(new SetCardInfo("Plains", 364, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 365, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 366, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polar Kraken", 89, Rarity.RARE, mage.cards.p.PolarKraken.class)); - cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Pox", 158, Rarity.RARE, mage.cards.p.Pox.class)); - cards.add(new SetCardInfo("Prismatic Ward", 47, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); - cards.add(new SetCardInfo("Pygmy Allosaurus", 257, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); - cards.add(new SetCardInfo("Pyknite", 258, Rarity.COMMON, mage.cards.p.Pyknite.class)); - cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); - cards.add(new SetCardInfo("Pyroclasm", 214, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class)); - cards.add(new SetCardInfo("Rally", 48, Rarity.COMMON, mage.cards.r.Rally.class)); - cards.add(new SetCardInfo("Ray of Command", 92, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Ray of Erasure", 93, Rarity.COMMON, mage.cards.r.RayOfErasure.class)); - cards.add(new SetCardInfo("Reality Twist", 94, Rarity.RARE, mage.cards.r.RealityTwist.class)); - cards.add(new SetCardInfo("Reclamation", 300, Rarity.RARE, mage.cards.r.Reclamation.class)); - cards.add(new SetCardInfo("Red Scarab", 49, Rarity.UNCOMMON, mage.cards.r.RedScarab.class)); - cards.add(new SetCardInfo("Regeneration", 259, Rarity.COMMON, mage.cards.r.Regeneration.class)); - cards.add(new SetCardInfo("Rime Dryad", 260, Rarity.COMMON, mage.cards.r.RimeDryad.class)); - cards.add(new SetCardInfo("Ritual of Subdual", 261, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); - cards.add(new SetCardInfo("River Delta", 359, Rarity.RARE, mage.cards.r.RiverDelta.class)); - cards.add(new SetCardInfo("Runed Arch", 334, Rarity.RARE, mage.cards.r.RunedArch.class)); - cards.add(new SetCardInfo("Sabretooth Tiger", 215, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); - cards.add(new SetCardInfo("Scaled Wurm", 262, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); - cards.add(new SetCardInfo("Sea Spirit", 95, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Seizures", 159, Rarity.COMMON, mage.cards.s.Seizures.class)); - cards.add(new SetCardInfo("Shambling Strider", 263, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); - cards.add(new SetCardInfo("Shatter", 216, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shield Bearer", 52, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shield of the Ages", 335, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); - cards.add(new SetCardInfo("Shyft", 96, Rarity.RARE, mage.cards.s.Shyft.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 97, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Silver Erne", 98, Rarity.UNCOMMON, mage.cards.s.SilverErne.class)); - cards.add(new SetCardInfo("Skeleton Ship", 301, Rarity.RARE, mage.cards.s.SkeletonShip.class)); - cards.add(new SetCardInfo("Skull Catapult", 336, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Snow Fortress", 337, Rarity.RARE, mage.cards.s.SnowFortress.class)); - cards.add(new SetCardInfo("Snow Hound", 53, Rarity.UNCOMMON, mage.cards.s.SnowHound.class)); - cards.add(new SetCardInfo("Snow-Covered Forest", 383, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); - cards.add(new SetCardInfo("Snow-Covered Island", 371, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); - cards.add(new SetCardInfo("Snow-Covered Mountain", 379, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); - cards.add(new SetCardInfo("Snow-Covered Plains", 367, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); - cards.add(new SetCardInfo("Snow-Covered Swamp", 372, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); - cards.add(new SetCardInfo("Soldevi Golem", 338, Rarity.RARE, mage.cards.s.SoldeviGolem.class)); - cards.add(new SetCardInfo("Soldevi Machinist", 102, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); - cards.add(new SetCardInfo("Soldevi Simulacrum", 339, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); - cards.add(new SetCardInfo("Songs of the Damned", 160, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); - cards.add(new SetCardInfo("Soul Barrier", 103, Rarity.UNCOMMON, mage.cards.s.SoulBarrier.class)); - cards.add(new SetCardInfo("Soul Burn", 161, Rarity.COMMON, mage.cards.s.SoulBurn.class)); - cards.add(new SetCardInfo("Soul Kiss", 162, Rarity.COMMON, mage.cards.s.SoulKiss.class)); - cards.add(new SetCardInfo("Spoils of Evil", 163, Rarity.RARE, mage.cards.s.SpoilsOfEvil.class)); - cards.add(new SetCardInfo("Staff of the Ages", 340, Rarity.RARE, mage.cards.s.StaffOfTheAges.class)); - cards.add(new SetCardInfo("Stampede", 265, Rarity.RARE, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stone Rain", 217, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Stone Spirit", 218, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stonehands", 219, Rarity.COMMON, mage.cards.s.Stonehands.class)); - cards.add(new SetCardInfo("Storm Spirit", 303, Rarity.RARE, mage.cards.s.StormSpirit.class)); - cards.add(new SetCardInfo("Stormbind", 304, Rarity.RARE, mage.cards.s.Stormbind.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 166, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Stunted Growth", 266, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); - cards.add(new SetCardInfo("Sulfurous Springs", 360, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); - cards.add(new SetCardInfo("Sunstone", 341, Rarity.UNCOMMON, mage.cards.s.Sunstone.class)); - cards.add(new SetCardInfo("Swamp", 373, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 374, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 375, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swords to Plowshares", 54, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Tarpan", 267, Rarity.COMMON, mage.cards.t.Tarpan.class)); - cards.add(new SetCardInfo("Thermokarst", 268, Rarity.UNCOMMON, mage.cards.t.Thermokarst.class)); - cards.add(new SetCardInfo("Thoughtleech", 269, Rarity.UNCOMMON, mage.cards.t.Thoughtleech.class)); - cards.add(new SetCardInfo("Thunder Wall", 104, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); - cards.add(new SetCardInfo("Timberline Ridge", 361, Rarity.RARE, mage.cards.t.TimberlineRidge.class)); - cards.add(new SetCardInfo("Time Bomb", 342, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Tinder Wall", 270, Rarity.COMMON, mage.cards.t.TinderWall.class)); - cards.add(new SetCardInfo("Tor Giant", 220, Rarity.COMMON, mage.cards.t.TorGiant.class)); - cards.add(new SetCardInfo("Total War", 221, Rarity.RARE, mage.cards.t.TotalWar.class)); - cards.add(new SetCardInfo("Touch of Death", 167, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); - cards.add(new SetCardInfo("Trailblazer", 272, Rarity.RARE, mage.cards.t.Trailblazer.class)); - cards.add(new SetCardInfo("Underground River", 362, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); - cards.add(new SetCardInfo("Updraft", 105, Rarity.UNCOMMON, mage.cards.u.Updraft.class)); - cards.add(new SetCardInfo("Urza's Bauble", 343, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); - cards.add(new SetCardInfo("Veldt", 363, Rarity.RARE, mage.cards.v.Veldt.class)); - cards.add(new SetCardInfo("Venomous Breath", 273, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); - cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); - cards.add(new SetCardInfo("Vexing Arcanix", 344, Rarity.RARE, mage.cards.v.VexingArcanix.class)); - cards.add(new SetCardInfo("Vibrating Sphere", 345, Rarity.RARE, mage.cards.v.VibratingSphere.class)); - cards.add(new SetCardInfo("Walking Wall", 346, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); - cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); - cards.add(new SetCardInfo("Wall of Pine Needles", 274, Rarity.UNCOMMON, mage.cards.w.WallOfPineNeedles.class)); - cards.add(new SetCardInfo("Wall of Shields", 347, Rarity.UNCOMMON, mage.cards.w.WallOfShields.class)); - cards.add(new SetCardInfo("War Chariot", 348, Rarity.UNCOMMON, mage.cards.w.WarChariot.class)); - cards.add(new SetCardInfo("Warning", 55, Rarity.COMMON, mage.cards.w.Warning.class)); - cards.add(new SetCardInfo("Whalebone Glider", 349, Rarity.UNCOMMON, mage.cards.w.WhaleboneGlider.class)); - cards.add(new SetCardInfo("White Scarab", 56, Rarity.UNCOMMON, mage.cards.w.WhiteScarab.class)); - cards.add(new SetCardInfo("Whiteout", 275, Rarity.UNCOMMON, mage.cards.w.Whiteout.class)); - cards.add(new SetCardInfo("Wild Growth", 277, Rarity.COMMON, mage.cards.w.WildGrowth.class)); - cards.add(new SetCardInfo("Wind Spirit", 106, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Wings of Aesthir", 305, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); - cards.add(new SetCardInfo("Withering Wisps", 168, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); - cards.add(new SetCardInfo("Woolly Mammoths", 278, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); - cards.add(new SetCardInfo("Woolly Spider", 279, Rarity.COMMON, mage.cards.w.WoollySpider.class)); - cards.add(new SetCardInfo("Word of Blasting", 224, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); - cards.add(new SetCardInfo("Word of Undoing", 108, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); - cards.add(new SetCardInfo("Wrath of Marit Lage", 109, Rarity.RARE, mage.cards.w.WrathOfMaritLage.class)); - cards.add(new SetCardInfo("Yavimaya Gnats", 280, Rarity.UNCOMMON, mage.cards.y.YavimayaGnats.class)); - cards.add(new SetCardInfo("Zur's Weirding", 110, Rarity.RARE, mage.cards.z.ZursWeirding.class)); - cards.add(new SetCardInfo("Zuran Enchanter", 111, Rarity.COMMON, mage.cards.z.ZuranEnchanter.class)); - cards.add(new SetCardInfo("Zuran Orb", 350, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); - cards.add(new SetCardInfo("Zuran Spellcaster", 112, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class IceAge extends ExpansionSet { + + private static final IceAge instance = new IceAge(); + + public static IceAge getInstance() { + return instance; + } + + private IceAge() { + super("Ice Age", "ICE", ExpansionSet.buildDate(1995, 5, 1), SetType.EXPANSION); + this.blockName = "Ice Age"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abyssal Specter", 113, Rarity.UNCOMMON, mage.cards.a.AbyssalSpecter.class)); + cards.add(new SetCardInfo("Adarkar Sentinel", 306, Rarity.UNCOMMON, mage.cards.a.AdarkarSentinel.class)); + cards.add(new SetCardInfo("Adarkar Wastes", 351, Rarity.RARE, mage.cards.a.AdarkarWastes.class)); + cards.add(new SetCardInfo("Aegis of the Meek", 307, Rarity.RARE, mage.cards.a.AegisOfTheMeek.class)); + cards.add(new SetCardInfo("Aggression", 169, Rarity.UNCOMMON, mage.cards.a.Aggression.class)); + cards.add(new SetCardInfo("Altar of Bone", 281, Rarity.RARE, mage.cards.a.AltarOfBone.class)); + cards.add(new SetCardInfo("Anarchy", 170, Rarity.UNCOMMON, mage.cards.a.Anarchy.class)); + cards.add(new SetCardInfo("Arenson's Aura", 3, Rarity.COMMON, mage.cards.a.ArensonsAura.class)); + cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Arnjlot's Ascent", 57, Rarity.COMMON, mage.cards.a.ArnjlotsAscent.class)); + cards.add(new SetCardInfo("Ashen Ghoul", 114, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); + cards.add(new SetCardInfo("Aurochs", 225, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Avalanche", 171, Rarity.UNCOMMON, mage.cards.a.Avalanche.class)); + cards.add(new SetCardInfo("Balduvian Barbarians", 172, Rarity.COMMON, mage.cards.b.BalduvianBarbarians.class)); + cards.add(new SetCardInfo("Balduvian Bears", 226, Rarity.COMMON, mage.cards.b.BalduvianBears.class)); + cards.add(new SetCardInfo("Balduvian Conjurer", 58, Rarity.UNCOMMON, mage.cards.b.BalduvianConjurer.class)); + cards.add(new SetCardInfo("Balduvian Hydra", 173, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); + cards.add(new SetCardInfo("Barbed Sextant", 312, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Baton of Morale", 313, Rarity.UNCOMMON, mage.cards.b.BatonOfMorale.class)); + cards.add(new SetCardInfo("Battle Cry", 5, Rarity.UNCOMMON, mage.cards.b.BattleCry.class)); + cards.add(new SetCardInfo("Battle Frenzy", 175, Rarity.COMMON, mage.cards.b.BattleFrenzy.class)); + cards.add(new SetCardInfo("Binding Grasp", 60, Rarity.UNCOMMON, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Black Scarab", 6, Rarity.UNCOMMON, mage.cards.b.BlackScarab.class)); + cards.add(new SetCardInfo("Blessed Wine", 7, Rarity.COMMON, mage.cards.b.BlessedWine.class)); + cards.add(new SetCardInfo("Blinking Spirit", 8, Rarity.RARE, mage.cards.b.BlinkingSpirit.class)); + cards.add(new SetCardInfo("Blizzard", 227, Rarity.RARE, mage.cards.b.Blizzard.class)); + cards.add(new SetCardInfo("Blue Scarab", 9, Rarity.UNCOMMON, mage.cards.b.BlueScarab.class)); + cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brand of Ill Omen", 177, Rarity.RARE, mage.cards.b.BrandOfIllOmen.class)); + cards.add(new SetCardInfo("Breath of Dreams", 62, Rarity.UNCOMMON, mage.cards.b.BreathOfDreams.class)); + cards.add(new SetCardInfo("Brine Shaman", 115, Rarity.COMMON, mage.cards.b.BrineShaman.class)); + cards.add(new SetCardInfo("Brown Ouphe", 228, Rarity.COMMON, mage.cards.b.BrownOuphe.class)); + cards.add(new SetCardInfo("Brushland", 352, Rarity.RARE, mage.cards.b.Brushland.class)); + cards.add(new SetCardInfo("Burnt Offering", 116, Rarity.COMMON, mage.cards.b.BurntOffering.class)); + cards.add(new SetCardInfo("Call to Arms", 10, Rarity.RARE, mage.cards.c.CallToArms.class)); + cards.add(new SetCardInfo("Caribou Range", 11, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Celestial Sword", 314, Rarity.RARE, mage.cards.c.CelestialSword.class)); + cards.add(new SetCardInfo("Centaur Archer", 282, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); + cards.add(new SetCardInfo("Chaos Lord", 178, Rarity.RARE, mage.cards.c.ChaosLord.class)); + cards.add(new SetCardInfo("Chaos Moon", 179, Rarity.RARE, mage.cards.c.ChaosMoon.class)); + cards.add(new SetCardInfo("Chub Toad", 229, Rarity.COMMON, mage.cards.c.ChubToad.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 14, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 15, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 16, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("Clairvoyance", 63, Rarity.COMMON, mage.cards.c.Clairvoyance.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 117, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Cold Snap", 17, Rarity.UNCOMMON, mage.cards.c.ColdSnap.class)); + cards.add(new SetCardInfo("Conquer", 180, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Cooperation", 18, Rarity.COMMON, mage.cards.c.Cooperation.class)); + cards.add(new SetCardInfo("Counterspell", 64, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crown of the Ages", 315, Rarity.RARE, mage.cards.c.CrownOfTheAges.class)); + cards.add(new SetCardInfo("Curse of Marit Lage", 181, Rarity.RARE, mage.cards.c.CurseOfMaritLage.class)); + cards.add(new SetCardInfo("Dance of the Dead", 118, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); + cards.add(new SetCardInfo("Dark Banishing", 119, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Dark Ritual", 120, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Death Ward", 19, Rarity.COMMON, mage.cards.d.DeathWard.class)); + cards.add(new SetCardInfo("Deflection", 65, Rarity.RARE, mage.cards.d.Deflection.class)); + cards.add(new SetCardInfo("Demonic Consultation", 121, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); + cards.add(new SetCardInfo("Despotic Scepter", 316, Rarity.RARE, mage.cards.d.DespoticScepter.class)); + cards.add(new SetCardInfo("Diabolic Vision", 284, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); + cards.add(new SetCardInfo("Dire Wolves", 230, Rarity.COMMON, mage.cards.d.DireWolves.class)); + cards.add(new SetCardInfo("Disenchant", 20, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dread Wight", 122, Rarity.RARE, mage.cards.d.DreadWight.class)); + cards.add(new SetCardInfo("Dreams of the Dead", 66, Rarity.UNCOMMON, mage.cards.d.DreamsOfTheDead.class)); + cards.add(new SetCardInfo("Drift of the Dead", 123, Rarity.UNCOMMON, mage.cards.d.DriftOfTheDead.class)); + cards.add(new SetCardInfo("Drought", 21, Rarity.UNCOMMON, mage.cards.d.Drought.class)); + cards.add(new SetCardInfo("Dwarven Armory", 182, Rarity.RARE, mage.cards.d.DwarvenArmory.class)); + cards.add(new SetCardInfo("Earthlink", 285, Rarity.RARE, mage.cards.e.Earthlink.class)); + cards.add(new SetCardInfo("Earthlore", 231, Rarity.COMMON, mage.cards.e.Earthlore.class)); + cards.add(new SetCardInfo("Elder Druid", 232, Rarity.RARE, mage.cards.e.ElderDruid.class)); + cards.add(new SetCardInfo("Elemental Augury", 286, Rarity.RARE, mage.cards.e.ElementalAugury.class)); + cards.add(new SetCardInfo("Elkin Bottle", 317, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Enduring Renewal", 23, Rarity.RARE, mage.cards.e.EnduringRenewal.class)); + cards.add(new SetCardInfo("Energy Storm", 24, Rarity.RARE, mage.cards.e.EnergyStorm.class)); + cards.add(new SetCardInfo("Enervate", 67, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Errant Minion", 68, Rarity.COMMON, mage.cards.e.ErrantMinion.class)); + cards.add(new SetCardInfo("Errantry", 183, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Essence Filter", 233, Rarity.COMMON, mage.cards.e.EssenceFilter.class)); + cards.add(new SetCardInfo("Essence Flare", 69, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); + cards.add(new SetCardInfo("Fanatical Fever", 234, Rarity.UNCOMMON, mage.cards.f.FanaticalFever.class)); + cards.add(new SetCardInfo("Fear", 124, Rarity.COMMON, mage.cards.f.Fear.class)); + cards.add(new SetCardInfo("Fiery Justice", 288, Rarity.RARE, mage.cards.f.FieryJustice.class)); + cards.add(new SetCardInfo("Fire Covenant", 289, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); + cards.add(new SetCardInfo("Flame Spirit", 184, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Flare", 185, Rarity.COMMON, mage.cards.f.Flare.class)); + cards.add(new SetCardInfo("Flooded Woodlands", 290, Rarity.RARE, mage.cards.f.FloodedWoodlands.class)); + cards.add(new SetCardInfo("Flow of Maggots", 125, Rarity.RARE, mage.cards.f.FlowOfMaggots.class)); + cards.add(new SetCardInfo("Folk of the Pines", 235, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); + cards.add(new SetCardInfo("Forbidden Lore", 236, Rarity.RARE, mage.cards.f.ForbiddenLore.class)); + cards.add(new SetCardInfo("Force Void", 70, Rarity.UNCOMMON, mage.cards.f.ForceVoid.class)); + cards.add(new SetCardInfo("Forest", 380, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 381, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 382, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forgotten Lore", 237, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); + cards.add(new SetCardInfo("Formation", 25, Rarity.RARE, mage.cards.f.Formation.class)); + cards.add(new SetCardInfo("Foul Familiar", 126, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); + cards.add(new SetCardInfo("Foxfire", 238, Rarity.COMMON, mage.cards.f.Foxfire.class)); + cards.add(new SetCardInfo("Freyalise Supplicant", 239, Rarity.UNCOMMON, mage.cards.f.FreyaliseSupplicant.class)); + cards.add(new SetCardInfo("Freyalise's Charm", 240, Rarity.UNCOMMON, mage.cards.f.FreyalisesCharm.class)); + cards.add(new SetCardInfo("Freyalise's Winds", 241, Rarity.RARE, mage.cards.f.FreyalisesWinds.class)); + cards.add(new SetCardInfo("Fumarole", 291, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); + cards.add(new SetCardInfo("Fyndhorn Bow", 318, Rarity.UNCOMMON, mage.cards.f.FyndhornBow.class)); + cards.add(new SetCardInfo("Fyndhorn Brownie", 242, Rarity.COMMON, mage.cards.f.FyndhornBrownie.class)); + cards.add(new SetCardInfo("Fyndhorn Elder", 243, Rarity.UNCOMMON, mage.cards.f.FyndhornElder.class)); + cards.add(new SetCardInfo("Fyndhorn Elves", 244, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); + cards.add(new SetCardInfo("Fyndhorn Pollen", 245, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); + cards.add(new SetCardInfo("Game of Chaos", 186, Rarity.RARE, mage.cards.g.GameOfChaos.class)); + cards.add(new SetCardInfo("Gangrenous Zombies", 127, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); + cards.add(new SetCardInfo("Gaze of Pain", 128, Rarity.COMMON, mage.cards.g.GazeOfPain.class)); + cards.add(new SetCardInfo("General Jarkeld", 27, Rarity.RARE, mage.cards.g.GeneralJarkeld.class)); + cards.add(new SetCardInfo("Giant Growth", 246, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Trap Door Spider", 293, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); + cards.add(new SetCardInfo("Glacial Chasm", 353, Rarity.UNCOMMON, mage.cards.g.GlacialChasm.class)); + cards.add(new SetCardInfo("Glacial Crevasses", 187, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); + cards.add(new SetCardInfo("Glacial Wall", 71, Rarity.UNCOMMON, mage.cards.g.GlacialWall.class)); + cards.add(new SetCardInfo("Glaciers", 294, Rarity.RARE, mage.cards.g.Glaciers.class)); + cards.add(new SetCardInfo("Goblin Lyre", 319, Rarity.RARE, mage.cards.g.GoblinLyre.class)); + cards.add(new SetCardInfo("Goblin Mutant", 188, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); + cards.add(new SetCardInfo("Goblin Snowman", 191, Rarity.UNCOMMON, mage.cards.g.GoblinSnowman.class)); + cards.add(new SetCardInfo("Gorilla Pack", 247, Rarity.COMMON, mage.cards.g.GorillaPack.class)); + cards.add(new SetCardInfo("Gravebind", 129, Rarity.RARE, mage.cards.g.Gravebind.class)); + cards.add(new SetCardInfo("Green Scarab", 28, Rarity.UNCOMMON, mage.cards.g.GreenScarab.class)); + cards.add(new SetCardInfo("Hallowed Ground", 29, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); + cards.add(new SetCardInfo("Halls of Mist", 354, Rarity.RARE, mage.cards.h.HallsOfMist.class)); + cards.add(new SetCardInfo("Heal", 30, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Hecatomb", 130, Rarity.RARE, mage.cards.h.Hecatomb.class)); + cards.add(new SetCardInfo("Hematite Talisman", 320, Rarity.UNCOMMON, mage.cards.h.HematiteTalisman.class)); + cards.add(new SetCardInfo("Hoar Shade", 131, Rarity.COMMON, mage.cards.h.HoarShade.class)); + cards.add(new SetCardInfo("Hot Springs", 248, Rarity.RARE, mage.cards.h.HotSprings.class)); + cards.add(new SetCardInfo("Howl from Beyond", 132, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Hurricane", 249, Rarity.UNCOMMON, mage.cards.h.Hurricane.class)); + cards.add(new SetCardInfo("Hyalopterous Lemure", 133, Rarity.UNCOMMON, mage.cards.h.HyalopterousLemure.class)); + cards.add(new SetCardInfo("Hydroblast", 72, Rarity.COMMON, mage.cards.h.Hydroblast.class)); + cards.add(new SetCardInfo("Hymn of Rebirth", 295, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); + cards.add(new SetCardInfo("Ice Cauldron", 321, Rarity.RARE, mage.cards.i.IceCauldron.class)); + cards.add(new SetCardInfo("Ice Floe", 355, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Iceberg", 73, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); + cards.add(new SetCardInfo("Icequake", 134, Rarity.UNCOMMON, mage.cards.i.Icequake.class)); + cards.add(new SetCardInfo("Icy Manipulator", 322, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); + cards.add(new SetCardInfo("Icy Prison", 74, Rarity.RARE, mage.cards.i.IcyPrison.class)); + cards.add(new SetCardInfo("Illusionary Forces", 75, Rarity.COMMON, mage.cards.i.IllusionaryForces.class)); + cards.add(new SetCardInfo("Illusionary Presence", 76, Rarity.RARE, mage.cards.i.IllusionaryPresence.class)); + cards.add(new SetCardInfo("Illusionary Terrain", 77, Rarity.UNCOMMON, mage.cards.i.IllusionaryTerrain.class)); + cards.add(new SetCardInfo("Illusionary Wall", 78, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); + cards.add(new SetCardInfo("Illusions of Grandeur", 79, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); + cards.add(new SetCardInfo("Imposing Visage", 193, Rarity.COMMON, mage.cards.i.ImposingVisage.class)); + cards.add(new SetCardInfo("Incinerate", 194, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Infernal Darkness", 135, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); + cards.add(new SetCardInfo("Infernal Denizen", 136, Rarity.RARE, mage.cards.i.InfernalDenizen.class)); + cards.add(new SetCardInfo("Infinite Hourglass", 323, Rarity.RARE, mage.cards.i.InfiniteHourglass.class)); + cards.add(new SetCardInfo("Infuse", 80, Rarity.COMMON, mage.cards.i.Infuse.class)); + cards.add(new SetCardInfo("Island", 368, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 369, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 370, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jester's Cap", 324, Rarity.RARE, mage.cards.j.JestersCap.class)); + cards.add(new SetCardInfo("Jester's Mask", 325, Rarity.RARE, mage.cards.j.JestersMask.class)); + cards.add(new SetCardInfo("Jeweled Amulet", 326, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); + cards.add(new SetCardInfo("Johtull Wurm", 250, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Jokulhaups", 195, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Juniper Order Druid", 251, Rarity.COMMON, mage.cards.j.JuniperOrderDruid.class)); + cards.add(new SetCardInfo("Justice", 32, Rarity.UNCOMMON, mage.cards.j.Justice.class)); + cards.add(new SetCardInfo("Karplusan Forest", 356, Rarity.RARE, mage.cards.k.KarplusanForest.class)); + cards.add(new SetCardInfo("Karplusan Giant", 196, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); + cards.add(new SetCardInfo("Karplusan Yeti", 197, Rarity.RARE, mage.cards.k.KarplusanYeti.class)); + cards.add(new SetCardInfo("Kelsinko Ranger", 33, Rarity.COMMON, mage.cards.k.KelsinkoRanger.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 137, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Frostbeast", 296, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); + cards.add(new SetCardInfo("Kjeldoran Knight", 36, Rarity.RARE, mage.cards.k.KjeldoranKnight.class)); + cards.add(new SetCardInfo("Kjeldoran Phalanx", 37, Rarity.RARE, mage.cards.k.KjeldoranPhalanx.class)); + cards.add(new SetCardInfo("Kjeldoran Royal Guard", 38, Rarity.RARE, mage.cards.k.KjeldoranRoyalGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 39, Rarity.UNCOMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Kjeldoran Skyknight", 40, Rarity.COMMON, mage.cards.k.KjeldoranSkyknight.class)); + cards.add(new SetCardInfo("Kjeldoran Warrior", 41, Rarity.COMMON, mage.cards.k.KjeldoranWarrior.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 138, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Elementalist", 139, Rarity.UNCOMMON, mage.cards.k.KrovikanElementalist.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 140, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 81, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Krovikan Vampire", 141, Rarity.UNCOMMON, mage.cards.k.KrovikanVampire.class)); + cards.add(new SetCardInfo("Land Cap", 357, Rarity.RARE, mage.cards.l.LandCap.class)); + cards.add(new SetCardInfo("Lapis Lazuli Talisman", 327, Rarity.UNCOMMON, mage.cards.l.LapisLazuliTalisman.class)); + cards.add(new SetCardInfo("Lava Tubes", 358, Rarity.RARE, mage.cards.l.LavaTubes.class)); + cards.add(new SetCardInfo("Legions of Lim-Dul", 142, Rarity.COMMON, mage.cards.l.LegionsOfLimDul.class)); + cards.add(new SetCardInfo("Leshrac's Rite", 143, Rarity.UNCOMMON, mage.cards.l.LeshracsRite.class)); + cards.add(new SetCardInfo("Leshrac's Sigil", 144, Rarity.UNCOMMON, mage.cards.l.LeshracsSigil.class)); + cards.add(new SetCardInfo("Lhurgoyf", 252, Rarity.RARE, mage.cards.l.Lhurgoyf.class)); + cards.add(new SetCardInfo("Lightning Blow", 42, Rarity.RARE, mage.cards.l.LightningBlow.class)); + cards.add(new SetCardInfo("Lim-Dul's Cohort", 145, Rarity.COMMON, mage.cards.l.LimDulsCohort.class)); + cards.add(new SetCardInfo("Lim-Dul's Hex", 146, Rarity.UNCOMMON, mage.cards.l.LimDulsHex.class)); + cards.add(new SetCardInfo("Lost Order of Jarkeld", 43, Rarity.RARE, mage.cards.l.LostOrderOfJarkeld.class)); + cards.add(new SetCardInfo("Lure", 253, Rarity.UNCOMMON, mage.cards.l.Lure.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 82, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Malachite Talisman", 328, Rarity.UNCOMMON, mage.cards.m.MalachiteTalisman.class)); + cards.add(new SetCardInfo("Marton Stromgald", 199, Rarity.RARE, mage.cards.m.MartonStromgald.class)); + cards.add(new SetCardInfo("Melee", 200, Rarity.UNCOMMON, mage.cards.m.Melee.class)); + cards.add(new SetCardInfo("Melting", 201, Rarity.UNCOMMON, mage.cards.m.Melting.class)); + cards.add(new SetCardInfo("Merieke Ri Berit", 297, Rarity.RARE, mage.cards.m.MeriekeRiBerit.class)); + cards.add(new SetCardInfo("Mesmeric Trance", 83, Rarity.RARE, mage.cards.m.MesmericTrance.class)); + cards.add(new SetCardInfo("Meteor Shower", 202, Rarity.COMMON, mage.cards.m.MeteorShower.class)); + cards.add(new SetCardInfo("Mind Ravel", 147, Rarity.COMMON, mage.cards.m.MindRavel.class)); + cards.add(new SetCardInfo("Mind Warp", 148, Rarity.UNCOMMON, mage.cards.m.MindWarp.class)); + cards.add(new SetCardInfo("Mind Whip", 149, Rarity.RARE, mage.cards.m.MindWhip.class)); + cards.add(new SetCardInfo("Minion of Leshrac", 150, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); + cards.add(new SetCardInfo("Minion of Tevesh Szat", 151, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); + cards.add(new SetCardInfo("Mistfolk", 84, Rarity.COMMON, mage.cards.m.Mistfolk.class)); + cards.add(new SetCardInfo("Mole Worms", 152, Rarity.UNCOMMON, mage.cards.m.MoleWorms.class)); + cards.add(new SetCardInfo("Monsoon", 298, Rarity.RARE, mage.cards.m.Monsoon.class)); + cards.add(new SetCardInfo("Moor Fiend", 153, Rarity.COMMON, mage.cards.m.MoorFiend.class)); + cards.add(new SetCardInfo("Mountain Goat", 203, Rarity.COMMON, mage.cards.m.MountainGoat.class)); + cards.add(new SetCardInfo("Mountain Titan", 299, Rarity.RARE, mage.cards.m.MountainTitan.class)); + cards.add(new SetCardInfo("Mountain", 376, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 377, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 378, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mudslide", 204, Rarity.RARE, mage.cards.m.Mudslide.class)); + cards.add(new SetCardInfo("Musician", 85, Rarity.RARE, mage.cards.m.Musician.class)); + cards.add(new SetCardInfo("Mystic Might", 86, Rarity.RARE, mage.cards.m.MysticMight.class)); + cards.add(new SetCardInfo("Mystic Remora", 87, Rarity.COMMON, mage.cards.m.MysticRemora.class)); + cards.add(new SetCardInfo("Nacre Talisman", 329, Rarity.UNCOMMON, mage.cards.n.NacreTalisman.class)); + cards.add(new SetCardInfo("Naked Singularity", 330, Rarity.RARE, mage.cards.n.NakedSingularity.class)); + cards.add(new SetCardInfo("Nature's Lore", 255, Rarity.UNCOMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Necropotence", 154, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Norritt", 155, Rarity.COMMON, mage.cards.n.Norritt.class)); + cards.add(new SetCardInfo("Oath of Lim-Dul", 156, Rarity.RARE, mage.cards.o.OathOfLimDul.class)); + cards.add(new SetCardInfo("Onyx Talisman", 331, Rarity.UNCOMMON, mage.cards.o.OnyxTalisman.class)); + cards.add(new SetCardInfo("Orcish Cannoneers", 205, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); + cards.add(new SetCardInfo("Orcish Healer", 208, Rarity.UNCOMMON, mage.cards.o.OrcishHealer.class)); + cards.add(new SetCardInfo("Orcish Librarian", 209, Rarity.RARE, mage.cards.o.OrcishLibrarian.class)); + cards.add(new SetCardInfo("Orcish Lumberjack", 210, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); + cards.add(new SetCardInfo("Orcish Squatters", 211, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 45, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 46, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Pale Bears", 256, Rarity.RARE, mage.cards.p.PaleBears.class)); + cards.add(new SetCardInfo("Panic", 212, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 332, Rarity.RARE, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Pestilence Rats", 157, Rarity.COMMON, mage.cards.p.PestilenceRats.class)); + cards.add(new SetCardInfo("Phantasmal Mount", 88, Rarity.UNCOMMON, mage.cards.p.PhantasmalMount.class)); + cards.add(new SetCardInfo("Pit Trap", 333, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); + cards.add(new SetCardInfo("Plains", 364, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 365, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 366, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Polar Kraken", 89, Rarity.RARE, mage.cards.p.PolarKraken.class)); + cards.add(new SetCardInfo("Portent", 90, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Power Sink", 91, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Pox", 158, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Prismatic Ward", 47, Rarity.COMMON, mage.cards.p.PrismaticWard.class)); + cards.add(new SetCardInfo("Pygmy Allosaurus", 257, Rarity.RARE, mage.cards.p.PygmyAllosaurus.class)); + cards.add(new SetCardInfo("Pyknite", 258, Rarity.COMMON, mage.cards.p.Pyknite.class)); + cards.add(new SetCardInfo("Pyroblast", 213, Rarity.COMMON, mage.cards.p.Pyroblast.class)); + cards.add(new SetCardInfo("Pyroclasm", 214, Rarity.UNCOMMON, mage.cards.p.Pyroclasm.class)); + cards.add(new SetCardInfo("Rally", 48, Rarity.COMMON, mage.cards.r.Rally.class)); + cards.add(new SetCardInfo("Ray of Command", 92, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Ray of Erasure", 93, Rarity.COMMON, mage.cards.r.RayOfErasure.class)); + cards.add(new SetCardInfo("Reality Twist", 94, Rarity.RARE, mage.cards.r.RealityTwist.class)); + cards.add(new SetCardInfo("Reclamation", 300, Rarity.RARE, mage.cards.r.Reclamation.class)); + cards.add(new SetCardInfo("Red Scarab", 49, Rarity.UNCOMMON, mage.cards.r.RedScarab.class)); + cards.add(new SetCardInfo("Regeneration", 259, Rarity.COMMON, mage.cards.r.Regeneration.class)); + cards.add(new SetCardInfo("Rime Dryad", 260, Rarity.COMMON, mage.cards.r.RimeDryad.class)); + cards.add(new SetCardInfo("Ritual of Subdual", 261, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); + cards.add(new SetCardInfo("River Delta", 359, Rarity.RARE, mage.cards.r.RiverDelta.class)); + cards.add(new SetCardInfo("Runed Arch", 334, Rarity.RARE, mage.cards.r.RunedArch.class)); + cards.add(new SetCardInfo("Sabretooth Tiger", 215, Rarity.COMMON, mage.cards.s.SabretoothTiger.class)); + cards.add(new SetCardInfo("Scaled Wurm", 262, Rarity.COMMON, mage.cards.s.ScaledWurm.class)); + cards.add(new SetCardInfo("Sea Spirit", 95, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Seizures", 159, Rarity.COMMON, mage.cards.s.Seizures.class)); + cards.add(new SetCardInfo("Seraph", 51, Rarity.RARE, mage.cards.s.Seraph.class)); + cards.add(new SetCardInfo("Shambling Strider", 263, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); + cards.add(new SetCardInfo("Shatter", 216, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shield Bearer", 52, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shield of the Ages", 335, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); + cards.add(new SetCardInfo("Shyft", 96, Rarity.RARE, mage.cards.s.Shyft.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 97, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Silver Erne", 98, Rarity.UNCOMMON, mage.cards.s.SilverErne.class)); + cards.add(new SetCardInfo("Skeleton Ship", 301, Rarity.RARE, mage.cards.s.SkeletonShip.class)); + cards.add(new SetCardInfo("Skull Catapult", 336, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Snow Devil", 100, Rarity.COMMON, mage.cards.s.SnowDevil.class)); + cards.add(new SetCardInfo("Snow Fortress", 337, Rarity.RARE, mage.cards.s.SnowFortress.class)); + cards.add(new SetCardInfo("Snow Hound", 53, Rarity.UNCOMMON, mage.cards.s.SnowHound.class)); + cards.add(new SetCardInfo("Snow-Covered Forest", 383, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); + cards.add(new SetCardInfo("Snow-Covered Island", 371, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); + cards.add(new SetCardInfo("Snow-Covered Mountain", 379, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); + cards.add(new SetCardInfo("Snow-Covered Plains", 367, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); + cards.add(new SetCardInfo("Snow-Covered Swamp", 372, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); + cards.add(new SetCardInfo("Soldevi Golem", 338, Rarity.RARE, mage.cards.s.SoldeviGolem.class)); + cards.add(new SetCardInfo("Soldevi Machinist", 102, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); + cards.add(new SetCardInfo("Soldevi Simulacrum", 339, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); + cards.add(new SetCardInfo("Songs of the Damned", 160, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); + cards.add(new SetCardInfo("Soul Barrier", 103, Rarity.UNCOMMON, mage.cards.s.SoulBarrier.class)); + cards.add(new SetCardInfo("Soul Burn", 161, Rarity.COMMON, mage.cards.s.SoulBurn.class)); + cards.add(new SetCardInfo("Soul Kiss", 162, Rarity.COMMON, mage.cards.s.SoulKiss.class)); + cards.add(new SetCardInfo("Spoils of Evil", 163, Rarity.RARE, mage.cards.s.SpoilsOfEvil.class)); + cards.add(new SetCardInfo("Staff of the Ages", 340, Rarity.RARE, mage.cards.s.StaffOfTheAges.class)); + cards.add(new SetCardInfo("Stampede", 265, Rarity.RARE, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stench of Evil", 165, Rarity.UNCOMMON, mage.cards.s.StenchOfEvil.class)); + cards.add(new SetCardInfo("Stone Rain", 217, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Stone Spirit", 218, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stonehands", 219, Rarity.COMMON, mage.cards.s.Stonehands.class)); + cards.add(new SetCardInfo("Storm Spirit", 303, Rarity.RARE, mage.cards.s.StormSpirit.class)); + cards.add(new SetCardInfo("Stormbind", 304, Rarity.RARE, mage.cards.s.Stormbind.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 166, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Stunted Growth", 266, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); + cards.add(new SetCardInfo("Sulfurous Springs", 360, Rarity.RARE, mage.cards.s.SulfurousSprings.class)); + cards.add(new SetCardInfo("Sunstone", 341, Rarity.UNCOMMON, mage.cards.s.Sunstone.class)); + cards.add(new SetCardInfo("Swamp", 373, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 374, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 375, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swords to Plowshares", 54, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Tarpan", 267, Rarity.COMMON, mage.cards.t.Tarpan.class)); + cards.add(new SetCardInfo("Thermokarst", 268, Rarity.UNCOMMON, mage.cards.t.Thermokarst.class)); + cards.add(new SetCardInfo("Thoughtleech", 269, Rarity.UNCOMMON, mage.cards.t.Thoughtleech.class)); + cards.add(new SetCardInfo("Thunder Wall", 104, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); + cards.add(new SetCardInfo("Timberline Ridge", 361, Rarity.RARE, mage.cards.t.TimberlineRidge.class)); + cards.add(new SetCardInfo("Time Bomb", 342, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Tinder Wall", 270, Rarity.COMMON, mage.cards.t.TinderWall.class)); + cards.add(new SetCardInfo("Tor Giant", 220, Rarity.COMMON, mage.cards.t.TorGiant.class)); + cards.add(new SetCardInfo("Total War", 221, Rarity.RARE, mage.cards.t.TotalWar.class)); + cards.add(new SetCardInfo("Touch of Death", 167, Rarity.COMMON, mage.cards.t.TouchOfDeath.class)); + cards.add(new SetCardInfo("Trailblazer", 272, Rarity.RARE, mage.cards.t.Trailblazer.class)); + cards.add(new SetCardInfo("Underground River", 362, Rarity.RARE, mage.cards.u.UndergroundRiver.class)); + cards.add(new SetCardInfo("Updraft", 105, Rarity.UNCOMMON, mage.cards.u.Updraft.class)); + cards.add(new SetCardInfo("Urza's Bauble", 343, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); + cards.add(new SetCardInfo("Veldt", 363, Rarity.RARE, mage.cards.v.Veldt.class)); + cards.add(new SetCardInfo("Venomous Breath", 273, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); + cards.add(new SetCardInfo("Vertigo", 222, Rarity.UNCOMMON, mage.cards.v.Vertigo.class)); + cards.add(new SetCardInfo("Vexing Arcanix", 344, Rarity.RARE, mage.cards.v.VexingArcanix.class)); + cards.add(new SetCardInfo("Vibrating Sphere", 345, Rarity.RARE, mage.cards.v.VibratingSphere.class)); + cards.add(new SetCardInfo("Walking Wall", 346, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); + cards.add(new SetCardInfo("Wall of Lava", 223, Rarity.UNCOMMON, mage.cards.w.WallOfLava.class)); + cards.add(new SetCardInfo("Wall of Pine Needles", 274, Rarity.UNCOMMON, mage.cards.w.WallOfPineNeedles.class)); + cards.add(new SetCardInfo("Wall of Shields", 347, Rarity.UNCOMMON, mage.cards.w.WallOfShields.class)); + cards.add(new SetCardInfo("War Chariot", 348, Rarity.UNCOMMON, mage.cards.w.WarChariot.class)); + cards.add(new SetCardInfo("Warning", 55, Rarity.COMMON, mage.cards.w.Warning.class)); + cards.add(new SetCardInfo("Whalebone Glider", 349, Rarity.UNCOMMON, mage.cards.w.WhaleboneGlider.class)); + cards.add(new SetCardInfo("White Scarab", 56, Rarity.UNCOMMON, mage.cards.w.WhiteScarab.class)); + cards.add(new SetCardInfo("Whiteout", 275, Rarity.UNCOMMON, mage.cards.w.Whiteout.class)); + cards.add(new SetCardInfo("Wiitigo", 276, Rarity.RARE, mage.cards.w.Wiitigo.class)); + cards.add(new SetCardInfo("Wild Growth", 277, Rarity.COMMON, mage.cards.w.WildGrowth.class)); + cards.add(new SetCardInfo("Wind Spirit", 106, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Wings of Aesthir", 305, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); + cards.add(new SetCardInfo("Withering Wisps", 168, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); + cards.add(new SetCardInfo("Woolly Mammoths", 278, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); + cards.add(new SetCardInfo("Woolly Spider", 279, Rarity.COMMON, mage.cards.w.WoollySpider.class)); + cards.add(new SetCardInfo("Word of Blasting", 224, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); + cards.add(new SetCardInfo("Word of Undoing", 108, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); + cards.add(new SetCardInfo("Wrath of Marit Lage", 109, Rarity.RARE, mage.cards.w.WrathOfMaritLage.class)); + cards.add(new SetCardInfo("Yavimaya Gnats", 280, Rarity.UNCOMMON, mage.cards.y.YavimayaGnats.class)); + cards.add(new SetCardInfo("Zur's Weirding", 110, Rarity.RARE, mage.cards.z.ZursWeirding.class)); + cards.add(new SetCardInfo("Zuran Enchanter", 111, Rarity.COMMON, mage.cards.z.ZuranEnchanter.class)); + cards.add(new SetCardInfo("Zuran Orb", 350, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); + cards.add(new SetCardInfo("Zuran Spellcaster", 112, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Invasion.java b/Mage.Sets/src/mage/sets/Invasion.java index 7aef568c5a..beb5c28697 100644 --- a/Mage.Sets/src/mage/sets/Invasion.java +++ b/Mage.Sets/src/mage/sets/Invasion.java @@ -55,6 +55,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Benalish Heralds", 6, Rarity.UNCOMMON, mage.cards.b.BenalishHeralds.class)); cards.add(new SetCardInfo("Benalish Lancer", 7, Rarity.COMMON, mage.cards.b.BenalishLancer.class)); cards.add(new SetCardInfo("Benalish Trapper", 8, Rarity.COMMON, mage.cards.b.BenalishTrapper.class)); + cards.add(new SetCardInfo("Bend or Break", 137, Rarity.RARE, mage.cards.b.BendOrBreak.class)); cards.add(new SetCardInfo("Bind", 182, Rarity.RARE, mage.cards.b.Bind.class)); cards.add(new SetCardInfo("Blazing Specter", 236, Rarity.RARE, mage.cards.b.BlazingSpecter.class)); cards.add(new SetCardInfo("Blinding Light", 9, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); @@ -88,6 +89,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Darigaaz's Attendant", 301, Rarity.UNCOMMON, mage.cards.d.DarigaazsAttendant.class)); cards.add(new SetCardInfo("Darigaaz, the Igniter", 243, Rarity.RARE, mage.cards.d.DarigaazTheIgniter.class)); cards.add(new SetCardInfo("Defiling Tears", 99, Rarity.UNCOMMON, mage.cards.d.DefilingTears.class)); + cards.add(new SetCardInfo("Death or Glory", 13, Rarity.RARE, mage.cards.d.DeathOrGlory.class)); cards.add(new SetCardInfo("Desperate Research", 100, Rarity.RARE, mage.cards.d.DesperateResearch.class)); cards.add(new SetCardInfo("Devouring Strossus", 101, Rarity.RARE, mage.cards.d.DevouringStrossus.class)); cards.add(new SetCardInfo("Dismantling Blow", 14, Rarity.COMMON, mage.cards.d.DismantlingBlow.class)); @@ -113,6 +115,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Fact or Fiction", 57, Rarity.UNCOMMON, mage.cards.f.FactOrFiction.class)); cards.add(new SetCardInfo("Faerie Squadron", 58, Rarity.COMMON, mage.cards.f.FaerieSquadron.class)); cards.add(new SetCardInfo("Fertile Ground", 188, Rarity.COMMON, mage.cards.f.FertileGround.class)); + cards.add(new SetCardInfo("Fight or Flight", 16, Rarity.RARE, mage.cards.f.FightOrFlight.class)); cards.add(new SetCardInfo("Firebrand Ranger", 143, Rarity.UNCOMMON, mage.cards.f.FirebrandRanger.class)); cards.add(new SetCardInfo("Firescreamer", 106, Rarity.COMMON, mage.cards.f.Firescreamer.class)); cards.add(new SetCardInfo("Fires of Yavimaya", 246, Rarity.UNCOMMON, mage.cards.f.FiresOfYavimaya.class)); @@ -217,6 +220,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Prohibit", 67, Rarity.COMMON, mage.cards.p.Prohibit.class)); cards.add(new SetCardInfo("Protective Sphere", 26, Rarity.COMMON, mage.cards.p.ProtectiveSphere.class)); cards.add(new SetCardInfo("Psychic Battle", 68, Rarity.RARE, mage.cards.p.PsychicBattle.class)); + cards.add(new SetCardInfo("Pulse of Llanowar", 202, Rarity.UNCOMMON, mage.cards.p.PulseOfLlanowar.class)); cards.add(new SetCardInfo("Pure Reflection", 27, Rarity.RARE, mage.cards.p.PureReflection.class)); cards.add(new SetCardInfo("Pyre Zombie", 261, Rarity.RARE, mage.cards.p.PyreZombie.class)); cards.add(new SetCardInfo("Quirion Elves", 203, Rarity.COMMON, mage.cards.q.QuirionElves.class)); @@ -250,6 +254,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Sabertooth Nishoba", 268, Rarity.RARE, mage.cards.s.SabertoothNishoba.class)); cards.add(new SetCardInfo("Salt Marsh", 326, Rarity.UNCOMMON, mage.cards.s.SaltMarsh.class)); cards.add(new SetCardInfo("Samite Archer", 269, Rarity.UNCOMMON, mage.cards.s.SamiteArcher.class)); + cards.add(new SetCardInfo("Samite Ministration", 36, Rarity.UNCOMMON, mage.cards.s.SamiteMinistration.class)); cards.add(new SetCardInfo("Sapphire Leech", 71, Rarity.RARE, mage.cards.s.SapphireLeech.class)); cards.add(new SetCardInfo("Saproling Infestation", 208, Rarity.RARE, mage.cards.s.SaprolingInfestation.class)); cards.add(new SetCardInfo("Saproling Symbiosis", 209, Rarity.RARE, mage.cards.s.SaprolingSymbiosis.class)); @@ -286,6 +291,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Spreading Plague", 125, Rarity.RARE, mage.cards.s.SpreadingPlague.class)); cards.add(new SetCardInfo("Stalking Assassin", 277, Rarity.RARE, mage.cards.s.StalkingAssassin.class)); cards.add(new SetCardInfo("Stand // Deliver", 292, Rarity.UNCOMMON, mage.cards.s.StandDeliver.class)); + cards.add(new SetCardInfo("Stand or Fall", 171, Rarity.RARE, mage.cards.s.StandOrFall.class)); cards.add(new SetCardInfo("Sterling Grove", 278, Rarity.UNCOMMON, mage.cards.s.SterlingGrove.class)); cards.add(new SetCardInfo("Stormscape Apprentice", 75, Rarity.COMMON, mage.cards.s.StormscapeApprentice.class)); cards.add(new SetCardInfo("Stormscape Master", 76, Rarity.RARE, mage.cards.s.StormscapeMaster.class)); @@ -346,6 +352,7 @@ public final class Invasion extends ExpansionSet { cards.add(new SetCardInfo("Verduran Emissary", 221, Rarity.UNCOMMON, mage.cards.v.VerduranEmissary.class)); cards.add(new SetCardInfo("Viashino Grappler", 179, Rarity.COMMON, mage.cards.v.ViashinoGrappler.class)); cards.add(new SetCardInfo("Vicious Kavu", 284, Rarity.UNCOMMON, mage.cards.v.ViciousKavu.class)); + cards.add(new SetCardInfo("Vigorous Charge", 222, Rarity.COMMON, mage.cards.v.VigorousCharge.class)); cards.add(new SetCardInfo("Vile Consumption", 285, Rarity.RARE, mage.cards.v.VileConsumption.class)); cards.add(new SetCardInfo("Vodalian Hypnotist", 84, Rarity.UNCOMMON, mage.cards.v.VodalianHypnotist.class)); cards.add(new SetCardInfo("Vodalian Merchant", 85, Rarity.COMMON, mage.cards.v.VodalianMerchant.class)); diff --git a/Mage.Sets/src/mage/sets/Judgment.java b/Mage.Sets/src/mage/sets/Judgment.java index 2acb1d73d7..9643a838be 100644 --- a/Mage.Sets/src/mage/sets/Judgment.java +++ b/Mage.Sets/src/mage/sets/Judgment.java @@ -121,6 +121,7 @@ public final class Judgment extends ExpansionSet { cards.add(new SetCardInfo("Prismatic Strands", 18, Rarity.COMMON, mage.cards.p.PrismaticStrands.class)); cards.add(new SetCardInfo("Pulsemage Advocate", 19, Rarity.RARE, mage.cards.p.PulsemageAdvocate.class)); cards.add(new SetCardInfo("Quiet Speculation", 49, Rarity.UNCOMMON, mage.cards.q.QuietSpeculation.class)); + cards.add(new SetCardInfo("Rats' Feast", 71, Rarity.COMMON, mage.cards.r.RatsFeast.class)); cards.add(new SetCardInfo("Ray of Revelation", 20, Rarity.COMMON, mage.cards.r.RayOfRevelation.class)); cards.add(new SetCardInfo("Riftstone Portal", 143, Rarity.UNCOMMON, mage.cards.r.RiftstonePortal.class)); cards.add(new SetCardInfo("Scalpelexis", 50, Rarity.RARE, mage.cards.s.Scalpelexis.class)); diff --git a/Mage.Sets/src/mage/sets/Legends.java b/Mage.Sets/src/mage/sets/Legends.java index 987bc827dd..c62c211ba4 100644 --- a/Mage.Sets/src/mage/sets/Legends.java +++ b/Mage.Sets/src/mage/sets/Legends.java @@ -1,295 +1,329 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Legends extends ExpansionSet { - - private static final Legends instance = new Legends(); - - public static Legends getInstance() { - return instance; - } - - private Legends() { - super("Legends", "LEG", ExpansionSet.buildDate(1994, 6, 1), SetType.EXPANSION); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abomination", 87, Rarity.UNCOMMON, mage.cards.a.Abomination.class)); - cards.add(new SetCardInfo("Acid Rain", 44, Rarity.RARE, mage.cards.a.AcidRain.class)); - cards.add(new SetCardInfo("Active Volcano", 130, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); - cards.add(new SetCardInfo("Adun Oakenshield", 216, Rarity.RARE, mage.cards.a.AdunOakenshield.class)); - cards.add(new SetCardInfo("Aerathi Berserker", 131, Rarity.UNCOMMON, mage.cards.a.AerathiBerserker.class)); - cards.add(new SetCardInfo("Aisling Leprechaun", 173, Rarity.COMMON, mage.cards.a.AislingLeprechaun.class)); - cards.add(new SetCardInfo("Akron Legionnaire", 1, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); - cards.add(new SetCardInfo("Al-abara's Carpet", 271, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); - cards.add(new SetCardInfo("Alabaster Potion", 2, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); - cards.add(new SetCardInfo("Alchor's Tomb", 272, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); - cards.add(new SetCardInfo("All Hallow's Eve", 88, Rarity.RARE, mage.cards.a.AllHallowsEve.class)); - cards.add(new SetCardInfo("Amrou Kithkin", 3, Rarity.COMMON, mage.cards.a.AmrouKithkin.class)); - cards.add(new SetCardInfo("Angelic Voices", 4, Rarity.RARE, mage.cards.a.AngelicVoices.class)); - cards.add(new SetCardInfo("Angus Mackenzie", 217, Rarity.RARE, mage.cards.a.AngusMackenzie.class)); - cards.add(new SetCardInfo("Anti-Magic Aura", 45, Rarity.COMMON, mage.cards.a.AntiMagicAura.class)); - cards.add(new SetCardInfo("Arboria", 174, Rarity.UNCOMMON, mage.cards.a.Arboria.class)); - cards.add(new SetCardInfo("Arcades Sabboth", 218, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); - cards.add(new SetCardInfo("Arena of the Ancients", 273, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); - cards.add(new SetCardInfo("Avoid Fate", 175, Rarity.COMMON, mage.cards.a.AvoidFate.class)); - cards.add(new SetCardInfo("Axelrod Gunnarson", 219, Rarity.RARE, mage.cards.a.AxelrodGunnarson.class)); - cards.add(new SetCardInfo("Ayesha Tanaka", 220, Rarity.RARE, mage.cards.a.AyeshaTanaka.class)); - cards.add(new SetCardInfo("Azure Drake", 46, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); - cards.add(new SetCardInfo("Backfire", 47, Rarity.UNCOMMON, mage.cards.b.Backfire.class)); - cards.add(new SetCardInfo("Barbary Apes", 176, Rarity.COMMON, mage.cards.b.BarbaryApes.class)); - cards.add(new SetCardInfo("Barktooth Warbeard", 221, Rarity.UNCOMMON, mage.cards.b.BarktoothWarbeard.class)); - cards.add(new SetCardInfo("Bartel Runeaxe", 222, Rarity.RARE, mage.cards.b.BartelRuneaxe.class)); - cards.add(new SetCardInfo("Beasts of Bogardan", 133, Rarity.UNCOMMON, mage.cards.b.BeastsOfBogardan.class)); - cards.add(new SetCardInfo("Black Mana Battery", 274, Rarity.UNCOMMON, mage.cards.b.BlackManaBattery.class)); - cards.add(new SetCardInfo("Blight", 89, Rarity.UNCOMMON, mage.cards.b.Blight.class)); - cards.add(new SetCardInfo("Blood Lust", 135, Rarity.UNCOMMON, mage.cards.b.BloodLust.class)); - cards.add(new SetCardInfo("Blue Mana Battery", 275, Rarity.UNCOMMON, mage.cards.b.BlueManaBattery.class)); - cards.add(new SetCardInfo("Boomerang", 48, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Boris Devilboon", 223, Rarity.RARE, mage.cards.b.BorisDevilboon.class)); - cards.add(new SetCardInfo("Carrion Ants", 90, Rarity.RARE, mage.cards.c.CarrionAnts.class)); - cards.add(new SetCardInfo("Cat Warriors", 177, Rarity.COMMON, mage.cards.c.CatWarriors.class)); - cards.add(new SetCardInfo("Caverns of Despair", 136, Rarity.RARE, mage.cards.c.CavernsOfDespair.class)); - cards.add(new SetCardInfo("Chain Lightning", 137, Rarity.COMMON, mage.cards.c.ChainLightning.class)); - cards.add(new SetCardInfo("Chains of Mephistopheles", 91, Rarity.RARE, mage.cards.c.ChainsOfMephistopheles.class)); - cards.add(new SetCardInfo("Chromium", 224, Rarity.RARE, mage.cards.c.Chromium.class)); - cards.add(new SetCardInfo("Cleanse", 5, Rarity.RARE, mage.cards.c.Cleanse.class)); - cards.add(new SetCardInfo("Clergy of the Holy Nimbus", 6, Rarity.COMMON, mage.cards.c.ClergyOfTheHolyNimbus.class)); - cards.add(new SetCardInfo("Concordant Crossroads", 179, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); - cards.add(new SetCardInfo("Cosmic Horror", 92, Rarity.RARE, mage.cards.c.CosmicHorror.class)); - cards.add(new SetCardInfo("Craw Giant", 180, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); - cards.add(new SetCardInfo("Crevasse", 138, Rarity.UNCOMMON, mage.cards.c.Crevasse.class)); - cards.add(new SetCardInfo("Crimson Kobolds", 139, Rarity.COMMON, mage.cards.c.CrimsonKobolds.class)); - cards.add(new SetCardInfo("Crimson Manticore", 140, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); - cards.add(new SetCardInfo("Crookshank Kobolds", 141, Rarity.COMMON, mage.cards.c.CrookshankKobolds.class)); - cards.add(new SetCardInfo("Cyclopean Mummy", 93, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); - cards.add(new SetCardInfo("D'Avenant Archer", 7, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); - cards.add(new SetCardInfo("Dakkon Blackblade", 225, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); - cards.add(new SetCardInfo("Darkness", 94, Rarity.COMMON, mage.cards.d.Darkness.class)); - cards.add(new SetCardInfo("Deadfall", 181, Rarity.UNCOMMON, mage.cards.d.Deadfall.class)); - cards.add(new SetCardInfo("Demonic Torment", 95, Rarity.UNCOMMON, mage.cards.d.DemonicTorment.class)); - cards.add(new SetCardInfo("Devouring Deep", 50, Rarity.COMMON, mage.cards.d.DevouringDeep.class)); - cards.add(new SetCardInfo("Disharmony", 142, Rarity.RARE, mage.cards.d.Disharmony.class)); - cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); - cards.add(new SetCardInfo("Divine Offering", 9, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Divine Transformation", 10, Rarity.RARE, mage.cards.d.DivineTransformation.class)); - cards.add(new SetCardInfo("Dream Coat", 51, Rarity.UNCOMMON, mage.cards.d.DreamCoat.class)); - cards.add(new SetCardInfo("Durkwood Boars", 182, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); - cards.add(new SetCardInfo("Dwarven Song", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class)); - cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); - cards.add(new SetCardInfo("Elven Riders", 183, Rarity.RARE, mage.cards.e.ElvenRiders.class)); - cards.add(new SetCardInfo("Emerald Dragonfly", 184, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); - cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class)); - cards.add(new SetCardInfo("Eternal Warrior", 144, Rarity.UNCOMMON, mage.cards.e.EternalWarrior.class)); - cards.add(new SetCardInfo("Eureka", 185, Rarity.RARE, mage.cards.e.Eureka.class)); - cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 96, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); - cards.add(new SetCardInfo("Fallen Angel", 97, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); - cards.add(new SetCardInfo("Field of Dreams", 55, Rarity.RARE, mage.cards.f.FieldOfDreams.class)); - cards.add(new SetCardInfo("Fire Sprites", 186, Rarity.COMMON, mage.cards.f.FireSprites.class)); - cards.add(new SetCardInfo("Flash Counter", 56, Rarity.COMMON, mage.cards.f.FlashCounter.class)); - cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class)); - cards.add(new SetCardInfo("Floral Spuzzem", 187, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); - cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class)); - cards.add(new SetCardInfo("Fortified Area", 14, Rarity.UNCOMMON, mage.cards.f.FortifiedArea.class)); - cards.add(new SetCardInfo("Frost Giant", 148, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); - cards.add(new SetCardInfo("Gabriel Angelfire", 226, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); - cards.add(new SetCardInfo("Gaseous Form", 59, Rarity.COMMON, mage.cards.g.GaseousForm.class)); - cards.add(new SetCardInfo("Gauntlets of Chaos", 278, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); - cards.add(new SetCardInfo("Ghosts of the Damned", 98, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); - cards.add(new SetCardInfo("Giant Strength", 149, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Giant Turtle", 188, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); - cards.add(new SetCardInfo("Glyph of Destruction", 150, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class)); - cards.add(new SetCardInfo("Glyph of Doom", 100, Rarity.COMMON, mage.cards.g.GlyphOfDoom.class)); - cards.add(new SetCardInfo("Glyph of Life", 15, Rarity.COMMON, mage.cards.g.GlyphOfLife.class)); - cards.add(new SetCardInfo("Gosta Dirk", 227, Rarity.RARE, mage.cards.g.GostaDirk.class)); - cards.add(new SetCardInfo("Gravity Sphere", 151, Rarity.RARE, mage.cards.g.GravitySphere.class)); - cards.add(new SetCardInfo("Great Defender", 16, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class)); - cards.add(new SetCardInfo("Great Wall", 17, Rarity.UNCOMMON, mage.cards.g.GreatWall.class)); - cards.add(new SetCardInfo("Greater Realm of Preservation", 18, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); - cards.add(new SetCardInfo("Greed", 101, Rarity.RARE, mage.cards.g.Greed.class)); - cards.add(new SetCardInfo("Green Mana Battery", 279, Rarity.UNCOMMON, mage.cards.g.GreenManaBattery.class)); - cards.add(new SetCardInfo("Gwendlyn Di Corci", 228, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); - cards.add(new SetCardInfo("Halfdane", 229, Rarity.RARE, mage.cards.h.Halfdane.class)); - cards.add(new SetCardInfo("Hammerheim", 302, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); - cards.add(new SetCardInfo("Hazezon Tamar", 230, Rarity.RARE, mage.cards.h.HazezonTamar.class)); - cards.add(new SetCardInfo("Headless Horseman", 102, Rarity.COMMON, mage.cards.h.HeadlessHorseman.class)); - cards.add(new SetCardInfo("Heaven's Gate", 19, Rarity.UNCOMMON, mage.cards.h.HeavensGate.class)); - cards.add(new SetCardInfo("Hell Swarm", 103, Rarity.COMMON, mage.cards.h.HellSwarm.class)); - cards.add(new SetCardInfo("Hell's Caretaker", 104, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); - cards.add(new SetCardInfo("Hellfire", 105, Rarity.RARE, mage.cards.h.Hellfire.class)); - cards.add(new SetCardInfo("Holy Day", 20, Rarity.COMMON, mage.cards.h.HolyDay.class)); - cards.add(new SetCardInfo("Horn of Deafening", 280, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); - cards.add(new SetCardInfo("Hornet Cobra", 190, Rarity.COMMON, mage.cards.h.HornetCobra.class)); - cards.add(new SetCardInfo("Horror of Horrors", 106, Rarity.UNCOMMON, mage.cards.h.HorrorOfHorrors.class)); - cards.add(new SetCardInfo("Hunding Gjornersen", 231, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); - cards.add(new SetCardInfo("Hyperion Blacksmith", 152, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class)); - cards.add(new SetCardInfo("Immolation", 153, Rarity.COMMON, mage.cards.i.Immolation.class)); - cards.add(new SetCardInfo("Imprison", 107, Rarity.RARE, mage.cards.i.Imprison.class)); - cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); - cards.add(new SetCardInfo("Indestructible Aura", 21, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); - cards.add(new SetCardInfo("Infernal Medusa", 108, Rarity.UNCOMMON, mage.cards.i.InfernalMedusa.class)); - cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class)); - cards.add(new SetCardInfo("Ivory Guardians", 23, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); - cards.add(new SetCardInfo("Jacques le Vert", 232, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); - cards.add(new SetCardInfo("Jasmine Boreal", 233, Rarity.UNCOMMON, mage.cards.j.JasmineBoreal.class)); - cards.add(new SetCardInfo("Jedit Ojanen", 234, Rarity.UNCOMMON, mage.cards.j.JeditOjanen.class)); - cards.add(new SetCardInfo("Jerrard of the Closed Fist", 235, Rarity.UNCOMMON, mage.cards.j.JerrardOfTheClosedFist.class)); - cards.add(new SetCardInfo("Johan", 236, Rarity.RARE, mage.cards.j.Johan.class)); - cards.add(new SetCardInfo("Jovial Evil", 109, Rarity.RARE, mage.cards.j.JovialEvil.class)); - cards.add(new SetCardInfo("Juxtapose", 63, Rarity.RARE, mage.cards.j.Juxtapose.class)); - cards.add(new SetCardInfo("Karakas", 303, Rarity.UNCOMMON, mage.cards.k.Karakas.class)); - cards.add(new SetCardInfo("Kasimir the Lone Wolf", 237, Rarity.UNCOMMON, mage.cards.k.KasimirTheLoneWolf.class)); - cards.add(new SetCardInfo("Keepers of the Faith", 24, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); - cards.add(new SetCardInfo("Kei Takahashi", 238, Rarity.RARE, mage.cards.k.KeiTakahashi.class)); - cards.add(new SetCardInfo("Killer Bees", 192, Rarity.RARE, mage.cards.k.KillerBees.class)); - cards.add(new SetCardInfo("Kismet", 25, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); - cards.add(new SetCardInfo("Kobold Drill Sergeant", 154, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class)); - cards.add(new SetCardInfo("Kobold Overlord", 155, Rarity.RARE, mage.cards.k.KoboldOverlord.class)); - cards.add(new SetCardInfo("Kobold Taskmaster", 156, Rarity.UNCOMMON, mage.cards.k.KoboldTaskmaster.class)); - cards.add(new SetCardInfo("Kobolds of Kher Keep", 157, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); - cards.add(new SetCardInfo("Lady Caleria", 239, Rarity.RARE, mage.cards.l.LadyCaleria.class)); - cards.add(new SetCardInfo("Lady Evangela", 240, Rarity.RARE, mage.cards.l.LadyEvangela.class)); - cards.add(new SetCardInfo("Lady Orca", 241, Rarity.UNCOMMON, mage.cards.l.LadyOrca.class)); - cards.add(new SetCardInfo("Land Equilibrium", 64, Rarity.RARE, mage.cards.l.LandEquilibrium.class)); - cards.add(new SetCardInfo("Land Tax", 26, Rarity.UNCOMMON, mage.cards.l.LandTax.class)); - cards.add(new SetCardInfo("Land's Edge", 158, Rarity.RARE, mage.cards.l.LandsEdge.class)); - cards.add(new SetCardInfo("Life Chisel", 283, Rarity.UNCOMMON, mage.cards.l.LifeChisel.class)); - cards.add(new SetCardInfo("Lifeblood", 27, Rarity.RARE, mage.cards.l.Lifeblood.class)); - cards.add(new SetCardInfo("Living Plane", 193, Rarity.RARE, mage.cards.l.LivingPlane.class)); - cards.add(new SetCardInfo("Livonya Silone", 242, Rarity.RARE, mage.cards.l.LivonyaSilone.class)); - cards.add(new SetCardInfo("Lord Magnus", 243, Rarity.UNCOMMON, mage.cards.l.LordMagnus.class)); - cards.add(new SetCardInfo("Lost Soul", 111, Rarity.COMMON, mage.cards.l.LostSoul.class)); - cards.add(new SetCardInfo("Mana Drain", 65, Rarity.UNCOMMON, mage.cards.m.ManaDrain.class)); - cards.add(new SetCardInfo("Mana Matrix", 285, Rarity.RARE, mage.cards.m.ManaMatrix.class)); - cards.add(new SetCardInfo("Marble Priest", 286, Rarity.UNCOMMON, mage.cards.m.MarblePriest.class)); - cards.add(new SetCardInfo("Marhault Elsdragon", 244, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); - cards.add(new SetCardInfo("Mirror Universe", 287, Rarity.RARE, mage.cards.m.MirrorUniverse.class)); - cards.add(new SetCardInfo("Moat", 28, Rarity.RARE, mage.cards.m.Moat.class)); - cards.add(new SetCardInfo("Mold Demon", 112, Rarity.RARE, mage.cards.m.MoldDemon.class)); - cards.add(new SetCardInfo("Moss Monster", 195, Rarity.COMMON, mage.cards.m.MossMonster.class)); - cards.add(new SetCardInfo("Mountain Yeti", 159, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class)); - cards.add(new SetCardInfo("Nebuchadnezzar", 245, Rarity.RARE, mage.cards.n.Nebuchadnezzar.class)); - cards.add(new SetCardInfo("Nether Void", 113, Rarity.RARE, mage.cards.n.NetherVoid.class)); - cards.add(new SetCardInfo("Nicol Bolas", 246, Rarity.RARE, mage.cards.n.NicolBolas.class)); - cards.add(new SetCardInfo("Nova Pentacle", 289, Rarity.RARE, mage.cards.n.NovaPentacle.class)); - cards.add(new SetCardInfo("Osai Vultures", 29, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); - cards.add(new SetCardInfo("Palladia-Mors", 247, Rarity.RARE, mage.cards.p.PalladiaMors.class)); - cards.add(new SetCardInfo("Part Water", 66, Rarity.UNCOMMON, mage.cards.p.PartWater.class)); - cards.add(new SetCardInfo("Pavel Maliki", 248, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); - cards.add(new SetCardInfo("Pendelhaven", 305, Rarity.UNCOMMON, mage.cards.p.Pendelhaven.class)); - cards.add(new SetCardInfo("Petra Sphinx", 30, Rarity.RARE, mage.cards.p.PetraSphinx.class)); - cards.add(new SetCardInfo("Pit Scorpion", 114, Rarity.COMMON, mage.cards.p.PitScorpion.class)); - cards.add(new SetCardInfo("Pixie Queen", 196, Rarity.RARE, mage.cards.p.PixieQueen.class)); - cards.add(new SetCardInfo("Planar Gate", 290, Rarity.RARE, mage.cards.p.PlanarGate.class)); - cards.add(new SetCardInfo("Pradesh Gypsies", 197, Rarity.UNCOMMON, mage.cards.p.PradeshGypsies.class)); - cards.add(new SetCardInfo("Presence of the Master", 31, Rarity.UNCOMMON, mage.cards.p.PresenceOfTheMaster.class)); - cards.add(new SetCardInfo("Primordial Ooze", 160, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); - cards.add(new SetCardInfo("Princess Lucrezia", 249, Rarity.UNCOMMON, mage.cards.p.PrincessLucrezia.class)); - cards.add(new SetCardInfo("Psionic Entity", 67, Rarity.RARE, mage.cards.p.PsionicEntity.class)); - cards.add(new SetCardInfo("Psychic Purge", 68, Rarity.COMMON, mage.cards.p.PsychicPurge.class)); - cards.add(new SetCardInfo("Pyrotechnics", 161, Rarity.COMMON, mage.cards.p.Pyrotechnics.class)); - cards.add(new SetCardInfo("Quagmire", 115, Rarity.UNCOMMON, mage.cards.q.Quagmire.class)); - cards.add(new SetCardInfo("Rabid Wombat", 198, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); - cards.add(new SetCardInfo("Radjan Spirit", 199, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); - cards.add(new SetCardInfo("Raging Bull", 163, Rarity.COMMON, mage.cards.r.RagingBull.class)); - cards.add(new SetCardInfo("Ragnar", 250, Rarity.RARE, mage.cards.r.Ragnar.class)); - cards.add(new SetCardInfo("Ramirez DePietro", 251, Rarity.UNCOMMON, mage.cards.r.RamirezDePietro.class)); - cards.add(new SetCardInfo("Ramses Overdark", 252, Rarity.RARE, mage.cards.r.RamsesOverdark.class)); - cards.add(new SetCardInfo("Rasputin Dreamweaver", 253, Rarity.RARE, mage.cards.r.RasputinDreamweaver.class)); - cards.add(new SetCardInfo("Recall", 70, Rarity.RARE, mage.cards.r.Recall.class)); - cards.add(new SetCardInfo("Red Mana Battery", 291, Rarity.UNCOMMON, mage.cards.r.RedManaBattery.class)); - cards.add(new SetCardInfo("Reincarnation", 201, Rarity.UNCOMMON, mage.cards.r.Reincarnation.class)); - cards.add(new SetCardInfo("Relic Barrier", 292, Rarity.UNCOMMON, mage.cards.r.RelicBarrier.class)); - cards.add(new SetCardInfo("Relic Bind", 71, Rarity.UNCOMMON, mage.cards.r.RelicBind.class)); - cards.add(new SetCardInfo("Remove Enchantments", 33, Rarity.COMMON, mage.cards.r.RemoveEnchantments.class)); - cards.add(new SetCardInfo("Remove Soul", 72, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Reset", 73, Rarity.UNCOMMON, mage.cards.r.Reset.class)); - cards.add(new SetCardInfo("Revelation", 202, Rarity.RARE, mage.cards.r.Revelation.class)); - cards.add(new SetCardInfo("Righteous Avengers", 34, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class)); - cards.add(new SetCardInfo("Ring of Immortals", 293, Rarity.RARE, mage.cards.r.RingOfImmortals.class)); - cards.add(new SetCardInfo("Riven Turnbull", 254, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); - cards.add(new SetCardInfo("Rohgahh of Kher Keep", 255, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); - cards.add(new SetCardInfo("Rubinia Soulsinger", 256, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); - cards.add(new SetCardInfo("Rust", 203, Rarity.COMMON, mage.cards.r.Rust.class)); - cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class)); - cards.add(new SetCardInfo("Seeker", 35, Rarity.UNCOMMON, mage.cards.s.Seeker.class)); - cards.add(new SetCardInfo("Segovian Leviathan", 76, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); - cards.add(new SetCardInfo("Sentinel", 294, Rarity.RARE, mage.cards.s.Sentinel.class)); - cards.add(new SetCardInfo("Serpent Generator", 295, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); - cards.add(new SetCardInfo("Shield Wall", 36, Rarity.UNCOMMON, mage.cards.s.ShieldWall.class)); - cards.add(new SetCardInfo("Shimian Night Stalker", 116, Rarity.UNCOMMON, mage.cards.s.ShimianNightStalker.class)); - cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 257, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class)); - cards.add(new SetCardInfo("Sivitri Scarzam", 258, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); - cards.add(new SetCardInfo("Sol'kanar the Swamp King", 259, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); - cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class)); - cards.add(new SetCardInfo("Spinal Villain", 164, Rarity.RARE, mage.cards.s.SpinalVillain.class)); - cards.add(new SetCardInfo("Spirit Link", 37, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); - cards.add(new SetCardInfo("Spirit Shackle", 117, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); - cards.add(new SetCardInfo("Spiritual Sanctuary", 38, Rarity.RARE, mage.cards.s.SpiritualSanctuary.class)); - cards.add(new SetCardInfo("Stangg", 260, Rarity.RARE, mage.cards.s.Stangg.class)); - cards.add(new SetCardInfo("Storm Seeker", 205, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); - cards.add(new SetCardInfo("Storm World", 165, Rarity.RARE, mage.cards.s.StormWorld.class)); - cards.add(new SetCardInfo("Sunastian Falconer", 261, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); - cards.add(new SetCardInfo("Sword of the Ages", 296, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); - cards.add(new SetCardInfo("Sylvan Library", 207, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); - cards.add(new SetCardInfo("Sylvan Paradise", 208, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class)); - cards.add(new SetCardInfo("Syphon Soul", 118, Rarity.COMMON, mage.cards.s.SyphonSoul.class)); - cards.add(new SetCardInfo("Telekinesis", 79, Rarity.RARE, mage.cards.t.Telekinesis.class)); - cards.add(new SetCardInfo("Teleport", 80, Rarity.RARE, mage.cards.t.Teleport.class)); - cards.add(new SetCardInfo("Tetsuo Umezawa", 262, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); - cards.add(new SetCardInfo("The Abyss", 120, Rarity.RARE, mage.cards.t.TheAbyss.class)); - cards.add(new SetCardInfo("The Brute", 167, Rarity.COMMON, mage.cards.t.TheBrute.class)); - cards.add(new SetCardInfo("The Lady of the Mountain", 263, Rarity.UNCOMMON, mage.cards.t.TheLadyOfTheMountain.class)); - cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 307, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); - cards.add(new SetCardInfo("The Wretched", 121, Rarity.RARE, mage.cards.t.TheWretched.class)); - cards.add(new SetCardInfo("Thunder Spirit", 39, Rarity.RARE, mage.cards.t.ThunderSpirit.class)); - cards.add(new SetCardInfo("Time Elemental", 81, Rarity.RARE, mage.cards.t.TimeElemental.class)); - cards.add(new SetCardInfo("Tobias Andrion", 264, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); - cards.add(new SetCardInfo("Tor Wauki", 265, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); - cards.add(new SetCardInfo("Torsten Von Ursus", 266, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class)); - cards.add(new SetCardInfo("Touch of Darkness", 122, Rarity.UNCOMMON, mage.cards.t.TouchOfDarkness.class)); - cards.add(new SetCardInfo("Transmutation", 123, Rarity.COMMON, mage.cards.t.Transmutation.class)); - cards.add(new SetCardInfo("Triassic Egg", 297, Rarity.RARE, mage.cards.t.TriassicEgg.class)); - cards.add(new SetCardInfo("Tuknir Deathlock", 267, Rarity.RARE, mage.cards.t.TuknirDeathlock.class)); - cards.add(new SetCardInfo("Tundra Wolves", 40, Rarity.COMMON, mage.cards.t.TundraWolves.class)); - cards.add(new SetCardInfo("Typhoon", 209, Rarity.RARE, mage.cards.t.Typhoon.class)); - cards.add(new SetCardInfo("Undertow", 82, Rarity.UNCOMMON, mage.cards.u.Undertow.class)); - cards.add(new SetCardInfo("Underworld Dreams", 124, Rarity.UNCOMMON, mage.cards.u.UnderworldDreams.class)); - cards.add(new SetCardInfo("Untamed Wilds", 210, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Ur-Drago", 268, Rarity.RARE, mage.cards.u.UrDrago.class)); - cards.add(new SetCardInfo("Urborg", 310, Rarity.UNCOMMON, mage.cards.u.Urborg.class)); - cards.add(new SetCardInfo("Vaevictis Asmadi", 269, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); - cards.add(new SetCardInfo("Vampire Bats", 125, Rarity.COMMON, mage.cards.v.VampireBats.class)); - cards.add(new SetCardInfo("Visions", 41, Rarity.UNCOMMON, mage.cards.v.Visions.class)); - cards.add(new SetCardInfo("Walking Dead", 126, Rarity.COMMON, mage.cards.w.WalkingDead.class)); - cards.add(new SetCardInfo("Wall of Caltrops", 42, Rarity.COMMON, mage.cards.w.WallOfCaltrops.class)); - cards.add(new SetCardInfo("Wall of Dust", 168, Rarity.UNCOMMON, mage.cards.w.WallOfDust.class)); - cards.add(new SetCardInfo("Wall of Earth", 169, Rarity.COMMON, mage.cards.w.WallOfEarth.class)); - cards.add(new SetCardInfo("Wall of Heat", 170, Rarity.COMMON, mage.cards.w.WallOfHeat.class)); - cards.add(new SetCardInfo("Wall of Light", 43, Rarity.UNCOMMON, mage.cards.w.WallOfLight.class)); - cards.add(new SetCardInfo("Wall of Opposition", 171, Rarity.RARE, mage.cards.w.WallOfOpposition.class)); - cards.add(new SetCardInfo("Wall of Putrid Flesh", 127, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); - cards.add(new SetCardInfo("Wall of Vapor", 84, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); - cards.add(new SetCardInfo("Wall of Wonder", 85, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); - cards.add(new SetCardInfo("Whirling Dervish", 211, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); - cards.add(new SetCardInfo("White Mana Battery", 299, Rarity.UNCOMMON, mage.cards.w.WhiteManaBattery.class)); - cards.add(new SetCardInfo("Willow Satyr", 212, Rarity.RARE, mage.cards.w.WillowSatyr.class)); - cards.add(new SetCardInfo("Winds of Change", 172, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 213, Rarity.RARE, mage.cards.w.WinterBlast.class)); - cards.add(new SetCardInfo("Wolverine Pack", 214, Rarity.COMMON, mage.cards.w.WolverinePack.class)); - cards.add(new SetCardInfo("Wood Elemental", 215, Rarity.RARE, mage.cards.w.WoodElemental.class)); - cards.add(new SetCardInfo("Xira Arien", 270, Rarity.RARE, mage.cards.x.XiraArien.class)); - cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Legends extends ExpansionSet { + + private static final Legends instance = new Legends(); + + public static Legends getInstance() { + return instance; + } + + private Legends() { + super("Legends", "LEG", ExpansionSet.buildDate(1994, 6, 1), SetType.EXPANSION); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abomination", 87, Rarity.UNCOMMON, mage.cards.a.Abomination.class)); + cards.add(new SetCardInfo("Acid Rain", 44, Rarity.RARE, mage.cards.a.AcidRain.class)); + cards.add(new SetCardInfo("Active Volcano", 130, Rarity.COMMON, mage.cards.a.ActiveVolcano.class)); + cards.add(new SetCardInfo("Adun Oakenshield", 216, Rarity.RARE, mage.cards.a.AdunOakenshield.class)); + cards.add(new SetCardInfo("Adventurers' Guildhouse", 300, Rarity.UNCOMMON, mage.cards.a.AdventurersGuildhouse.class)); + cards.add(new SetCardInfo("Aerathi Berserker", 131, Rarity.UNCOMMON, mage.cards.a.AerathiBerserker.class)); + cards.add(new SetCardInfo("Aisling Leprechaun", 173, Rarity.COMMON, mage.cards.a.AislingLeprechaun.class)); + cards.add(new SetCardInfo("Akron Legionnaire", 1, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); + cards.add(new SetCardInfo("Al-abara's Carpet", 271, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); + cards.add(new SetCardInfo("Alabaster Potion", 2, Rarity.COMMON, mage.cards.a.AlabasterPotion.class)); + cards.add(new SetCardInfo("Alchor's Tomb", 272, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); + cards.add(new SetCardInfo("All Hallow's Eve", 88, Rarity.RARE, mage.cards.a.AllHallowsEve.class)); + cards.add(new SetCardInfo("Amrou Kithkin", 3, Rarity.COMMON, mage.cards.a.AmrouKithkin.class)); + cards.add(new SetCardInfo("Angelic Voices", 4, Rarity.RARE, mage.cards.a.AngelicVoices.class)); + cards.add(new SetCardInfo("Angus Mackenzie", 217, Rarity.RARE, mage.cards.a.AngusMackenzie.class)); + cards.add(new SetCardInfo("Anti-Magic Aura", 45, Rarity.COMMON, mage.cards.a.AntiMagicAura.class)); + cards.add(new SetCardInfo("Arboria", 174, Rarity.UNCOMMON, mage.cards.a.Arboria.class)); + cards.add(new SetCardInfo("Arcades Sabboth", 218, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); + cards.add(new SetCardInfo("Arena of the Ancients", 273, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); + cards.add(new SetCardInfo("Avoid Fate", 175, Rarity.COMMON, mage.cards.a.AvoidFate.class)); + cards.add(new SetCardInfo("Axelrod Gunnarson", 219, Rarity.RARE, mage.cards.a.AxelrodGunnarson.class)); + cards.add(new SetCardInfo("Ayesha Tanaka", 220, Rarity.RARE, mage.cards.a.AyeshaTanaka.class)); + cards.add(new SetCardInfo("Azure Drake", 46, Rarity.UNCOMMON, mage.cards.a.AzureDrake.class)); + cards.add(new SetCardInfo("Backfire", 47, Rarity.UNCOMMON, mage.cards.b.Backfire.class)); + cards.add(new SetCardInfo("Barbary Apes", 176, Rarity.COMMON, mage.cards.b.BarbaryApes.class)); + cards.add(new SetCardInfo("Barktooth Warbeard", 221, Rarity.UNCOMMON, mage.cards.b.BarktoothWarbeard.class)); + cards.add(new SetCardInfo("Bartel Runeaxe", 222, Rarity.RARE, mage.cards.b.BartelRuneaxe.class)); + cards.add(new SetCardInfo("Beasts of Bogardan", 133, Rarity.UNCOMMON, mage.cards.b.BeastsOfBogardan.class)); + cards.add(new SetCardInfo("Black Mana Battery", 274, Rarity.UNCOMMON, mage.cards.b.BlackManaBattery.class)); + cards.add(new SetCardInfo("Blazing Effigy", 134, Rarity.COMMON, mage.cards.b.BlazingEffigy.class)); + cards.add(new SetCardInfo("Blight", 89, Rarity.UNCOMMON, mage.cards.b.Blight.class)); + cards.add(new SetCardInfo("Blood Lust", 135, Rarity.UNCOMMON, mage.cards.b.BloodLust.class)); + cards.add(new SetCardInfo("Blue Mana Battery", 275, Rarity.UNCOMMON, mage.cards.b.BlueManaBattery.class)); + cards.add(new SetCardInfo("Boomerang", 48, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Boris Devilboon", 223, Rarity.RARE, mage.cards.b.BorisDevilboon.class)); + cards.add(new SetCardInfo("Brine Hag", 49, Rarity.UNCOMMON, mage.cards.b.BrineHag.class)); + cards.add(new SetCardInfo("Bronze Horse", 276, Rarity.RARE, mage.cards.b.BronzeHorse.class)); + cards.add(new SetCardInfo("Carrion Ants", 90, Rarity.RARE, mage.cards.c.CarrionAnts.class)); + cards.add(new SetCardInfo("Cat Warriors", 177, Rarity.COMMON, mage.cards.c.CatWarriors.class)); + cards.add(new SetCardInfo("Cathedral of Serra", 301, Rarity.UNCOMMON, mage.cards.c.CathedralOfSerra.class)); + cards.add(new SetCardInfo("Caverns of Despair", 136, Rarity.RARE, mage.cards.c.CavernsOfDespair.class)); + cards.add(new SetCardInfo("Chain Lightning", 137, Rarity.COMMON, mage.cards.c.ChainLightning.class)); + cards.add(new SetCardInfo("Chains of Mephistopheles", 91, Rarity.RARE, mage.cards.c.ChainsOfMephistopheles.class)); + cards.add(new SetCardInfo("Chromium", 224, Rarity.RARE, mage.cards.c.Chromium.class)); + cards.add(new SetCardInfo("Cleanse", 5, Rarity.RARE, mage.cards.c.Cleanse.class)); + cards.add(new SetCardInfo("Clergy of the Holy Nimbus", 6, Rarity.COMMON, mage.cards.c.ClergyOfTheHolyNimbus.class)); + cards.add(new SetCardInfo("Concordant Crossroads", 179, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); + cards.add(new SetCardInfo("Cocoon", 178, Rarity.UNCOMMON, mage.cards.c.Cocoon.class)); + cards.add(new SetCardInfo("Cosmic Horror", 92, Rarity.RARE, mage.cards.c.CosmicHorror.class)); + cards.add(new SetCardInfo("Craw Giant", 180, Rarity.UNCOMMON, mage.cards.c.CrawGiant.class)); + cards.add(new SetCardInfo("Crevasse", 138, Rarity.UNCOMMON, mage.cards.c.Crevasse.class)); + cards.add(new SetCardInfo("Crimson Kobolds", 139, Rarity.COMMON, mage.cards.c.CrimsonKobolds.class)); + cards.add(new SetCardInfo("Crimson Manticore", 140, Rarity.RARE, mage.cards.c.CrimsonManticore.class)); + cards.add(new SetCardInfo("Crookshank Kobolds", 141, Rarity.COMMON, mage.cards.c.CrookshankKobolds.class)); + cards.add(new SetCardInfo("Cyclopean Mummy", 93, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); + cards.add(new SetCardInfo("D'Avenant Archer", 7, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); + cards.add(new SetCardInfo("Dakkon Blackblade", 225, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); + cards.add(new SetCardInfo("Darkness", 94, Rarity.COMMON, mage.cards.d.Darkness.class)); + cards.add(new SetCardInfo("Deadfall", 181, Rarity.UNCOMMON, mage.cards.d.Deadfall.class)); + cards.add(new SetCardInfo("Demonic Torment", 95, Rarity.UNCOMMON, mage.cards.d.DemonicTorment.class)); + cards.add(new SetCardInfo("Devouring Deep", 50, Rarity.COMMON, mage.cards.d.DevouringDeep.class)); + cards.add(new SetCardInfo("Disharmony", 142, Rarity.RARE, mage.cards.d.Disharmony.class)); + cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); + cards.add(new SetCardInfo("Divine Offering", 9, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Divine Transformation", 10, Rarity.RARE, mage.cards.d.DivineTransformation.class)); + cards.add(new SetCardInfo("Dream Coat", 51, Rarity.UNCOMMON, mage.cards.d.DreamCoat.class)); + cards.add(new SetCardInfo("Durkwood Boars", 182, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); + cards.add(new SetCardInfo("Dwarven Song", 143, Rarity.UNCOMMON, mage.cards.d.DwarvenSong.class)); + cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.RARE, mage.cards.e.ElderLandWurm.class)); + cards.add(new SetCardInfo("Elder Spawn", 52, Rarity.RARE, mage.cards.e.ElderSpawn.class)); + cards.add(new SetCardInfo("Elven Riders", 183, Rarity.RARE, mage.cards.e.ElvenRiders.class)); + cards.add(new SetCardInfo("Emerald Dragonfly", 184, Rarity.COMMON, mage.cards.e.EmeraldDragonfly.class)); + cards.add(new SetCardInfo("Enchanted Being", 12, Rarity.COMMON, mage.cards.e.EnchantedBeing.class)); + cards.add(new SetCardInfo("Enchantment Alteration", 53, Rarity.COMMON, mage.cards.e.EnchantmentAlteration.class)); + cards.add(new SetCardInfo("Energy Tap", 54, Rarity.COMMON, mage.cards.e.EnergyTap.class)); + cards.add(new SetCardInfo("Eternal Warrior", 144, Rarity.UNCOMMON, mage.cards.e.EternalWarrior.class)); + cards.add(new SetCardInfo("Eureka", 185, Rarity.RARE, mage.cards.e.Eureka.class)); + cards.add(new SetCardInfo("Evil Eye of Orms-by-Gore", 96, Rarity.UNCOMMON, mage.cards.e.EvilEyeOfOrmsByGore.class)); + cards.add(new SetCardInfo("Fallen Angel", 97, Rarity.UNCOMMON, mage.cards.f.FallenAngel.class)); + cards.add(new SetCardInfo("Feint", 146, Rarity.COMMON, mage.cards.f.Feint.class)); + cards.add(new SetCardInfo("Field of Dreams", 55, Rarity.RARE, mage.cards.f.FieldOfDreams.class)); + cards.add(new SetCardInfo("Fire Sprites", 186, Rarity.COMMON, mage.cards.f.FireSprites.class)); + cards.add(new SetCardInfo("Flash Counter", 56, Rarity.COMMON, mage.cards.f.FlashCounter.class)); + cards.add(new SetCardInfo("Flash Flood", 57, Rarity.COMMON, mage.cards.f.FlashFlood.class)); + cards.add(new SetCardInfo("Floral Spuzzem", 187, Rarity.UNCOMMON, mage.cards.f.FloralSpuzzem.class)); + cards.add(new SetCardInfo("Force Spike", 58, Rarity.COMMON, mage.cards.f.ForceSpike.class)); + cards.add(new SetCardInfo("Forethought Amulet", 277, Rarity.RARE, mage.cards.f.ForethoughtAmulet.class)); + cards.add(new SetCardInfo("Fortified Area", 14, Rarity.UNCOMMON, mage.cards.f.FortifiedArea.class)); + cards.add(new SetCardInfo("Frost Giant", 148, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); + cards.add(new SetCardInfo("Gabriel Angelfire", 226, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); + cards.add(new SetCardInfo("Gaseous Form", 59, Rarity.COMMON, mage.cards.g.GaseousForm.class)); + cards.add(new SetCardInfo("Gauntlets of Chaos", 278, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); + cards.add(new SetCardInfo("Ghosts of the Damned", 98, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); + cards.add(new SetCardInfo("Giant Slug", 99, Rarity.COMMON, mage.cards.g.GiantSlug.class)); + cards.add(new SetCardInfo("Giant Strength", 149, Rarity.COMMON, mage.cards.g.GiantStrength.class)); + cards.add(new SetCardInfo("Giant Turtle", 188, Rarity.COMMON, mage.cards.g.GiantTurtle.class)); + cards.add(new SetCardInfo("Glyph of Delusion", 60, Rarity.COMMON, mage.cards.g.GlyphOfDelusion.class)); + cards.add(new SetCardInfo("Glyph of Destruction", 150, Rarity.COMMON, mage.cards.g.GlyphOfDestruction.class)); + cards.add(new SetCardInfo("Glyph of Doom", 100, Rarity.COMMON, mage.cards.g.GlyphOfDoom.class)); + cards.add(new SetCardInfo("Glyph of Life", 15, Rarity.COMMON, mage.cards.g.GlyphOfLife.class)); + cards.add(new SetCardInfo("Glyph of Reincarnation", 189, Rarity.COMMON, mage.cards.g.GlyphOfReincarnation.class)); + cards.add(new SetCardInfo("Gosta Dirk", 227, Rarity.RARE, mage.cards.g.GostaDirk.class)); + cards.add(new SetCardInfo("Gravity Sphere", 151, Rarity.RARE, mage.cards.g.GravitySphere.class)); + cards.add(new SetCardInfo("Great Defender", 16, Rarity.UNCOMMON, mage.cards.g.GreatDefender.class)); + cards.add(new SetCardInfo("Great Wall", 17, Rarity.UNCOMMON, mage.cards.g.GreatWall.class)); + cards.add(new SetCardInfo("Greater Realm of Preservation", 18, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); + cards.add(new SetCardInfo("Greed", 101, Rarity.RARE, mage.cards.g.Greed.class)); + cards.add(new SetCardInfo("Green Mana Battery", 279, Rarity.UNCOMMON, mage.cards.g.GreenManaBattery.class)); + cards.add(new SetCardInfo("Gwendlyn Di Corci", 228, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); + cards.add(new SetCardInfo("Halfdane", 229, Rarity.RARE, mage.cards.h.Halfdane.class)); + cards.add(new SetCardInfo("Hammerheim", 302, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); + cards.add(new SetCardInfo("Hazezon Tamar", 230, Rarity.RARE, mage.cards.h.HazezonTamar.class)); + cards.add(new SetCardInfo("Headless Horseman", 102, Rarity.COMMON, mage.cards.h.HeadlessHorseman.class)); + cards.add(new SetCardInfo("Heaven's Gate", 19, Rarity.UNCOMMON, mage.cards.h.HeavensGate.class)); + cards.add(new SetCardInfo("Hell Swarm", 103, Rarity.COMMON, mage.cards.h.HellSwarm.class)); + cards.add(new SetCardInfo("Hell's Caretaker", 104, Rarity.RARE, mage.cards.h.HellsCaretaker.class)); + cards.add(new SetCardInfo("Hellfire", 105, Rarity.RARE, mage.cards.h.Hellfire.class)); + cards.add(new SetCardInfo("Holy Day", 20, Rarity.COMMON, mage.cards.h.HolyDay.class)); + cards.add(new SetCardInfo("Horn of Deafening", 280, Rarity.RARE, mage.cards.h.HornOfDeafening.class)); + cards.add(new SetCardInfo("Hornet Cobra", 190, Rarity.COMMON, mage.cards.h.HornetCobra.class)); + cards.add(new SetCardInfo("Horror of Horrors", 106, Rarity.UNCOMMON, mage.cards.h.HorrorOfHorrors.class)); + cards.add(new SetCardInfo("Hunding Gjornersen", 231, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); + cards.add(new SetCardInfo("Hyperion Blacksmith", 152, Rarity.UNCOMMON, mage.cards.h.HyperionBlacksmith.class)); + cards.add(new SetCardInfo("Ichneumon Druid", 191, Rarity.UNCOMMON, mage.cards.i.IchneumonDruid.class)); + cards.add(new SetCardInfo("Immolation", 153, Rarity.COMMON, mage.cards.i.Immolation.class)); + cards.add(new SetCardInfo("Imprison", 107, Rarity.RARE, mage.cards.i.Imprison.class)); + cards.add(new SetCardInfo("In the Eye of Chaos", 61, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); + cards.add(new SetCardInfo("Indestructible Aura", 21, Rarity.COMMON, mage.cards.i.IndestructibleAura.class)); + cards.add(new SetCardInfo("Infernal Medusa", 108, Rarity.UNCOMMON, mage.cards.i.InfernalMedusa.class)); + cards.add(new SetCardInfo("Infinite Authority", 22, Rarity.RARE, mage.cards.i.InfiniteAuthority.class)); + cards.add(new SetCardInfo("Invoke Prejudice", 62, Rarity.RARE, mage.cards.i.InvokePrejudice.class)); + cards.add(new SetCardInfo("Ivory Guardians", 23, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); + cards.add(new SetCardInfo("Jacques le Vert", 232, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); + cards.add(new SetCardInfo("Jasmine Boreal", 233, Rarity.UNCOMMON, mage.cards.j.JasmineBoreal.class)); + cards.add(new SetCardInfo("Jedit Ojanen", 234, Rarity.UNCOMMON, mage.cards.j.JeditOjanen.class)); + cards.add(new SetCardInfo("Jerrard of the Closed Fist", 235, Rarity.UNCOMMON, mage.cards.j.JerrardOfTheClosedFist.class)); + cards.add(new SetCardInfo("Johan", 236, Rarity.RARE, mage.cards.j.Johan.class)); + cards.add(new SetCardInfo("Jovial Evil", 109, Rarity.RARE, mage.cards.j.JovialEvil.class)); + cards.add(new SetCardInfo("Juxtapose", 63, Rarity.RARE, mage.cards.j.Juxtapose.class)); + cards.add(new SetCardInfo("Karakas", 303, Rarity.UNCOMMON, mage.cards.k.Karakas.class)); + cards.add(new SetCardInfo("Kasimir the Lone Wolf", 237, Rarity.UNCOMMON, mage.cards.k.KasimirTheLoneWolf.class)); + cards.add(new SetCardInfo("Keepers of the Faith", 24, Rarity.COMMON, mage.cards.k.KeepersOfTheFaith.class)); + cards.add(new SetCardInfo("Kei Takahashi", 238, Rarity.RARE, mage.cards.k.KeiTakahashi.class)); + cards.add(new SetCardInfo("Killer Bees", 192, Rarity.RARE, mage.cards.k.KillerBees.class)); + cards.add(new SetCardInfo("Kismet", 25, Rarity.UNCOMMON, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Knowledge Vault", 281, Rarity.RARE, mage.cards.k.KnowledgeVault.class)); + cards.add(new SetCardInfo("Kobold Drill Sergeant", 154, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class)); + cards.add(new SetCardInfo("Kobold Overlord", 155, Rarity.RARE, mage.cards.k.KoboldOverlord.class)); + cards.add(new SetCardInfo("Kobold Taskmaster", 156, Rarity.UNCOMMON, mage.cards.k.KoboldTaskmaster.class)); + cards.add(new SetCardInfo("Kobolds of Kher Keep", 157, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); + cards.add(new SetCardInfo("Kry Shield", 282, Rarity.UNCOMMON, mage.cards.k.KryShield.class)); + cards.add(new SetCardInfo("Lady Caleria", 239, Rarity.RARE, mage.cards.l.LadyCaleria.class)); + cards.add(new SetCardInfo("Lady Evangela", 240, Rarity.RARE, mage.cards.l.LadyEvangela.class)); + cards.add(new SetCardInfo("Lady Orca", 241, Rarity.UNCOMMON, mage.cards.l.LadyOrca.class)); + cards.add(new SetCardInfo("Land Equilibrium", 64, Rarity.RARE, mage.cards.l.LandEquilibrium.class)); + cards.add(new SetCardInfo("Land Tax", 26, Rarity.UNCOMMON, mage.cards.l.LandTax.class)); + cards.add(new SetCardInfo("Land's Edge", 158, Rarity.RARE, mage.cards.l.LandsEdge.class)); + cards.add(new SetCardInfo("Lesser Werewolf", 110, Rarity.UNCOMMON, mage.cards.l.LesserWerewolf.class)); + cards.add(new SetCardInfo("Life Chisel", 283, Rarity.UNCOMMON, mage.cards.l.LifeChisel.class)); + cards.add(new SetCardInfo("Life Matrix", 284, Rarity.RARE, mage.cards.l.LifeMatrix.class)); + cards.add(new SetCardInfo("Lifeblood", 27, Rarity.RARE, mage.cards.l.Lifeblood.class)); + cards.add(new SetCardInfo("Living Plane", 193, Rarity.RARE, mage.cards.l.LivingPlane.class)); + cards.add(new SetCardInfo("Livonya Silone", 242, Rarity.RARE, mage.cards.l.LivonyaSilone.class)); + cards.add(new SetCardInfo("Lord Magnus", 243, Rarity.UNCOMMON, mage.cards.l.LordMagnus.class)); + cards.add(new SetCardInfo("Lost Soul", 111, Rarity.COMMON, mage.cards.l.LostSoul.class)); + cards.add(new SetCardInfo("Mana Drain", 65, Rarity.UNCOMMON, mage.cards.m.ManaDrain.class)); + cards.add(new SetCardInfo("Mana Matrix", 285, Rarity.RARE, mage.cards.m.ManaMatrix.class)); + cards.add(new SetCardInfo("Marble Priest", 286, Rarity.UNCOMMON, mage.cards.m.MarblePriest.class)); + cards.add(new SetCardInfo("Marhault Elsdragon", 244, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); + cards.add(new SetCardInfo("Master of the Hunt", 194, Rarity.RARE, mage.cards.m.MasterOfTheHunt.class)); + cards.add(new SetCardInfo("Mirror Universe", 287, Rarity.RARE, mage.cards.m.MirrorUniverse.class)); + cards.add(new SetCardInfo("Moat", 28, Rarity.RARE, mage.cards.m.Moat.class)); + cards.add(new SetCardInfo("Mold Demon", 112, Rarity.RARE, mage.cards.m.MoldDemon.class)); + cards.add(new SetCardInfo("Moss Monster", 195, Rarity.COMMON, mage.cards.m.MossMonster.class)); + cards.add(new SetCardInfo("Mountain Stronghold", 304, Rarity.UNCOMMON, mage.cards.m.MountainStronghold.class)); + cards.add(new SetCardInfo("Mountain Yeti", 159, Rarity.UNCOMMON, mage.cards.m.MountainYeti.class)); + cards.add(new SetCardInfo("Nebuchadnezzar", 245, Rarity.RARE, mage.cards.n.Nebuchadnezzar.class)); + cards.add(new SetCardInfo("Nether Void", 113, Rarity.RARE, mage.cards.n.NetherVoid.class)); + cards.add(new SetCardInfo("Nicol Bolas", 246, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Nova Pentacle", 289, Rarity.RARE, mage.cards.n.NovaPentacle.class)); + cards.add(new SetCardInfo("Osai Vultures", 29, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); + cards.add(new SetCardInfo("Palladia-Mors", 247, Rarity.RARE, mage.cards.p.PalladiaMors.class)); + cards.add(new SetCardInfo("Part Water", 66, Rarity.UNCOMMON, mage.cards.p.PartWater.class)); + cards.add(new SetCardInfo("Pavel Maliki", 248, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); + cards.add(new SetCardInfo("Pendelhaven", 305, Rarity.UNCOMMON, mage.cards.p.Pendelhaven.class)); + cards.add(new SetCardInfo("Petra Sphinx", 30, Rarity.RARE, mage.cards.p.PetraSphinx.class)); + cards.add(new SetCardInfo("Pit Scorpion", 114, Rarity.COMMON, mage.cards.p.PitScorpion.class)); + cards.add(new SetCardInfo("Pixie Queen", 196, Rarity.RARE, mage.cards.p.PixieQueen.class)); + cards.add(new SetCardInfo("Planar Gate", 290, Rarity.RARE, mage.cards.p.PlanarGate.class)); + cards.add(new SetCardInfo("Pradesh Gypsies", 197, Rarity.UNCOMMON, mage.cards.p.PradeshGypsies.class)); + cards.add(new SetCardInfo("Presence of the Master", 31, Rarity.UNCOMMON, mage.cards.p.PresenceOfTheMaster.class)); + cards.add(new SetCardInfo("Primordial Ooze", 160, Rarity.UNCOMMON, mage.cards.p.PrimordialOoze.class)); + cards.add(new SetCardInfo("Princess Lucrezia", 249, Rarity.UNCOMMON, mage.cards.p.PrincessLucrezia.class)); + cards.add(new SetCardInfo("Psionic Entity", 67, Rarity.RARE, mage.cards.p.PsionicEntity.class)); + cards.add(new SetCardInfo("Psychic Purge", 68, Rarity.COMMON, mage.cards.p.PsychicPurge.class)); + cards.add(new SetCardInfo("Puppet Master", 69, Rarity.UNCOMMON, mage.cards.p.PuppetMaster.class)); + cards.add(new SetCardInfo("Pyrotechnics", 161, Rarity.COMMON, mage.cards.p.Pyrotechnics.class)); + cards.add(new SetCardInfo("Quagmire", 115, Rarity.UNCOMMON, mage.cards.q.Quagmire.class)); + cards.add(new SetCardInfo("Rabid Wombat", 198, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); + cards.add(new SetCardInfo("Radjan Spirit", 199, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); + cards.add(new SetCardInfo("Raging Bull", 163, Rarity.COMMON, mage.cards.r.RagingBull.class)); + cards.add(new SetCardInfo("Ragnar", 250, Rarity.RARE, mage.cards.r.Ragnar.class)); + cards.add(new SetCardInfo("Ramirez DePietro", 251, Rarity.UNCOMMON, mage.cards.r.RamirezDePietro.class)); + cards.add(new SetCardInfo("Ramses Overdark", 252, Rarity.RARE, mage.cards.r.RamsesOverdark.class)); + cards.add(new SetCardInfo("Rapid Fire", 32, Rarity.RARE, mage.cards.r.RapidFire.class)); + cards.add(new SetCardInfo("Rasputin Dreamweaver", 253, Rarity.RARE, mage.cards.r.RasputinDreamweaver.class)); + cards.add(new SetCardInfo("Recall", 70, Rarity.RARE, mage.cards.r.Recall.class)); + cards.add(new SetCardInfo("Red Mana Battery", 291, Rarity.UNCOMMON, mage.cards.r.RedManaBattery.class)); + cards.add(new SetCardInfo("Reincarnation", 201, Rarity.UNCOMMON, mage.cards.r.Reincarnation.class)); + cards.add(new SetCardInfo("Relic Barrier", 292, Rarity.UNCOMMON, mage.cards.r.RelicBarrier.class)); + cards.add(new SetCardInfo("Relic Bind", 71, Rarity.UNCOMMON, mage.cards.r.RelicBind.class)); + cards.add(new SetCardInfo("Remove Enchantments", 33, Rarity.COMMON, mage.cards.r.RemoveEnchantments.class)); + cards.add(new SetCardInfo("Remove Soul", 72, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Reset", 73, Rarity.UNCOMMON, mage.cards.r.Reset.class)); + cards.add(new SetCardInfo("Revelation", 202, Rarity.RARE, mage.cards.r.Revelation.class)); + cards.add(new SetCardInfo("Reverberation", 74, Rarity.RARE, mage.cards.r.Reverberation.class)); + cards.add(new SetCardInfo("Righteous Avengers", 34, Rarity.UNCOMMON, mage.cards.r.RighteousAvengers.class)); + cards.add(new SetCardInfo("Ring of Immortals", 293, Rarity.RARE, mage.cards.r.RingOfImmortals.class)); + cards.add(new SetCardInfo("Riven Turnbull", 254, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); + cards.add(new SetCardInfo("Rohgahh of Kher Keep", 255, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); + cards.add(new SetCardInfo("Rubinia Soulsinger", 256, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); + cards.add(new SetCardInfo("Rust", 203, Rarity.COMMON, mage.cards.r.Rust.class)); + cards.add(new SetCardInfo("Sea Kings' Blessing", 75, Rarity.UNCOMMON, mage.cards.s.SeaKingsBlessing.class)); + cards.add(new SetCardInfo("Seafarer's Quay", 306, Rarity.UNCOMMON, mage.cards.s.SeafarersQuay.class)); + cards.add(new SetCardInfo("Seeker", 35, Rarity.UNCOMMON, mage.cards.s.Seeker.class)); + cards.add(new SetCardInfo("Segovian Leviathan", 76, Rarity.UNCOMMON, mage.cards.s.SegovianLeviathan.class)); + cards.add(new SetCardInfo("Sentinel", 294, Rarity.RARE, mage.cards.s.Sentinel.class)); + cards.add(new SetCardInfo("Serpent Generator", 295, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Shelkin Brownie", 204, Rarity.COMMON, mage.cards.s.ShelkinBrownie.class)); + cards.add(new SetCardInfo("Shield Wall", 36, Rarity.UNCOMMON, mage.cards.s.ShieldWall.class)); + cards.add(new SetCardInfo("Shimian Night Stalker", 116, Rarity.UNCOMMON, mage.cards.s.ShimianNightStalker.class)); + cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 257, Rarity.UNCOMMON, mage.cards.s.SirShandlarOfEberyn.class)); + cards.add(new SetCardInfo("Sivitri Scarzam", 258, Rarity.UNCOMMON, mage.cards.s.SivitriScarzam.class)); + cards.add(new SetCardInfo("Sol'kanar the Swamp King", 259, Rarity.RARE, mage.cards.s.SolkanarTheSwampKing.class)); + cards.add(new SetCardInfo("Spectral Cloak", 78, Rarity.UNCOMMON, mage.cards.s.SpectralCloak.class)); + cards.add(new SetCardInfo("Spinal Villain", 164, Rarity.RARE, mage.cards.s.SpinalVillain.class)); + cards.add(new SetCardInfo("Spirit Link", 37, Rarity.UNCOMMON, mage.cards.s.SpiritLink.class)); + cards.add(new SetCardInfo("Spirit Shackle", 117, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); + cards.add(new SetCardInfo("Spiritual Sanctuary", 38, Rarity.RARE, mage.cards.s.SpiritualSanctuary.class)); + cards.add(new SetCardInfo("Stangg", 260, Rarity.RARE, mage.cards.s.Stangg.class)); + cards.add(new SetCardInfo("Storm Seeker", 205, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); + cards.add(new SetCardInfo("Storm World", 165, Rarity.RARE, mage.cards.s.StormWorld.class)); + cards.add(new SetCardInfo("Subdue", 206, Rarity.COMMON, mage.cards.s.Subdue.class)); + cards.add(new SetCardInfo("Sunastian Falconer", 261, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); + cards.add(new SetCardInfo("Sword of the Ages", 296, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); + cards.add(new SetCardInfo("Sylvan Library", 207, Rarity.UNCOMMON, mage.cards.s.SylvanLibrary.class)); + cards.add(new SetCardInfo("Sylvan Paradise", 208, Rarity.UNCOMMON, mage.cards.s.SylvanParadise.class)); + cards.add(new SetCardInfo("Syphon Soul", 118, Rarity.COMMON, mage.cards.s.SyphonSoul.class)); + cards.add(new SetCardInfo("Telekinesis", 79, Rarity.RARE, mage.cards.t.Telekinesis.class)); + cards.add(new SetCardInfo("Teleport", 80, Rarity.RARE, mage.cards.t.Teleport.class)); + cards.add(new SetCardInfo("Tetsuo Umezawa", 262, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); + cards.add(new SetCardInfo("The Abyss", 120, Rarity.RARE, mage.cards.t.TheAbyss.class)); + cards.add(new SetCardInfo("The Brute", 167, Rarity.COMMON, mage.cards.t.TheBrute.class)); + cards.add(new SetCardInfo("The Lady of the Mountain", 263, Rarity.UNCOMMON, mage.cards.t.TheLadyOfTheMountain.class)); + cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 307, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); + cards.add(new SetCardInfo("The Wretched", 121, Rarity.RARE, mage.cards.t.TheWretched.class)); + cards.add(new SetCardInfo("Thunder Spirit", 39, Rarity.RARE, mage.cards.t.ThunderSpirit.class)); + cards.add(new SetCardInfo("Time Elemental", 81, Rarity.RARE, mage.cards.t.TimeElemental.class)); + cards.add(new SetCardInfo("Tobias Andrion", 264, Rarity.UNCOMMON, mage.cards.t.TobiasAndrion.class)); + cards.add(new SetCardInfo("Tolaria", 308, Rarity.UNCOMMON, mage.cards.t.Tolaria.class)); + cards.add(new SetCardInfo("Tor Wauki", 265, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); + cards.add(new SetCardInfo("Torsten Von Ursus", 266, Rarity.UNCOMMON, mage.cards.t.TorstenVonUrsus.class)); + cards.add(new SetCardInfo("Touch of Darkness", 122, Rarity.UNCOMMON, mage.cards.t.TouchOfDarkness.class)); + cards.add(new SetCardInfo("Transmutation", 123, Rarity.COMMON, mage.cards.t.Transmutation.class)); + cards.add(new SetCardInfo("Triassic Egg", 297, Rarity.RARE, mage.cards.t.TriassicEgg.class)); + cards.add(new SetCardInfo("Tuknir Deathlock", 267, Rarity.RARE, mage.cards.t.TuknirDeathlock.class)); + cards.add(new SetCardInfo("Tundra Wolves", 40, Rarity.COMMON, mage.cards.t.TundraWolves.class)); + cards.add(new SetCardInfo("Typhoon", 209, Rarity.RARE, mage.cards.t.Typhoon.class)); + cards.add(new SetCardInfo("Undertow", 82, Rarity.UNCOMMON, mage.cards.u.Undertow.class)); + cards.add(new SetCardInfo("Unholy Citadel", 309, Rarity.UNCOMMON, mage.cards.u.UnholyCitadel.class)); + cards.add(new SetCardInfo("Underworld Dreams", 124, Rarity.UNCOMMON, mage.cards.u.UnderworldDreams.class)); + cards.add(new SetCardInfo("Untamed Wilds", 210, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Ur-Drago", 268, Rarity.RARE, mage.cards.u.UrDrago.class)); + cards.add(new SetCardInfo("Urborg", 310, Rarity.UNCOMMON, mage.cards.u.Urborg.class)); + cards.add(new SetCardInfo("Vaevictis Asmadi", 269, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); + cards.add(new SetCardInfo("Vampire Bats", 125, Rarity.COMMON, mage.cards.v.VampireBats.class)); + cards.add(new SetCardInfo("Venarian Gold", 83, Rarity.COMMON, mage.cards.v.VenarianGold.class)); + cards.add(new SetCardInfo("Visions", 41, Rarity.UNCOMMON, mage.cards.v.Visions.class)); + cards.add(new SetCardInfo("Voodoo Doll", 298, Rarity.RARE, mage.cards.v.VoodooDoll.class)); + cards.add(new SetCardInfo("Walking Dead", 126, Rarity.COMMON, mage.cards.w.WalkingDead.class)); + cards.add(new SetCardInfo("Wall of Caltrops", 42, Rarity.COMMON, mage.cards.w.WallOfCaltrops.class)); + cards.add(new SetCardInfo("Wall of Dust", 168, Rarity.UNCOMMON, mage.cards.w.WallOfDust.class)); + cards.add(new SetCardInfo("Wall of Earth", 169, Rarity.COMMON, mage.cards.w.WallOfEarth.class)); + cards.add(new SetCardInfo("Wall of Heat", 170, Rarity.COMMON, mage.cards.w.WallOfHeat.class)); + cards.add(new SetCardInfo("Wall of Light", 43, Rarity.UNCOMMON, mage.cards.w.WallOfLight.class)); + cards.add(new SetCardInfo("Wall of Opposition", 171, Rarity.RARE, mage.cards.w.WallOfOpposition.class)); + cards.add(new SetCardInfo("Wall of Putrid Flesh", 127, Rarity.UNCOMMON, mage.cards.w.WallOfPutridFlesh.class)); + cards.add(new SetCardInfo("Wall of Shadows", 128, Rarity.COMMON, mage.cards.w.WallOfShadows.class)); + cards.add(new SetCardInfo("Wall of Tombstones", 129, Rarity.UNCOMMON, mage.cards.w.WallOfTombstones.class)); + cards.add(new SetCardInfo("Wall of Vapor", 84, Rarity.COMMON, mage.cards.w.WallOfVapor.class)); + cards.add(new SetCardInfo("Wall of Wonder", 85, Rarity.UNCOMMON, mage.cards.w.WallOfWonder.class)); + cards.add(new SetCardInfo("Whirling Dervish", 211, Rarity.UNCOMMON, mage.cards.w.WhirlingDervish.class)); + cards.add(new SetCardInfo("White Mana Battery", 299, Rarity.UNCOMMON, mage.cards.w.WhiteManaBattery.class)); + cards.add(new SetCardInfo("Willow Satyr", 212, Rarity.RARE, mage.cards.w.WillowSatyr.class)); + cards.add(new SetCardInfo("Winds of Change", 172, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); + cards.add(new SetCardInfo("Winter Blast", 213, Rarity.RARE, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Wolverine Pack", 214, Rarity.COMMON, mage.cards.w.WolverinePack.class)); + cards.add(new SetCardInfo("Wood Elemental", 215, Rarity.RARE, mage.cards.w.WoodElemental.class)); + cards.add(new SetCardInfo("Xira Arien", 270, Rarity.RARE, mage.cards.x.XiraArien.class)); + cards.add(new SetCardInfo("Zephyr Falcon", 86, Rarity.COMMON, mage.cards.z.ZephyrFalcon.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MastersEdition.java b/Mage.Sets/src/mage/sets/MastersEdition.java index 99486fa757..17317b3cd8 100644 --- a/Mage.Sets/src/mage/sets/MastersEdition.java +++ b/Mage.Sets/src/mage/sets/MastersEdition.java @@ -1,222 +1,223 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author LevelX2 - */ -public final class MastersEdition extends ExpansionSet { - - private static final MastersEdition instance = new MastersEdition(); - - public static MastersEdition getInstance() { - return instance; - } - - private MastersEdition() { - super("Masters Edition", "MED", ExpansionSet.buildDate(2007, 9, 10), SetType.MAGIC_ONLINE); - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Adun Oakenshield", 141, Rarity.RARE, mage.cards.a.AdunOakenshield.class)); - cards.add(new SetCardInfo("Amnesia", 29, Rarity.RARE, mage.cards.a.Amnesia.class)); - cards.add(new SetCardInfo("Angry Mob", 1, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); - cards.add(new SetCardInfo("Animate Dead", 57, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); - cards.add(new SetCardInfo("Animate Wall", 2, Rarity.UNCOMMON, mage.cards.a.AnimateWall.class)); - cards.add(new SetCardInfo("Ankh of Mishra", 151, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); - cards.add(new SetCardInfo("Apprentice Wizard", 30, Rarity.COMMON, mage.cards.a.ApprenticeWizard.class)); - cards.add(new SetCardInfo("Arcane Denial", 31, Rarity.COMMON, mage.cards.a.ArcaneDenial.class)); - cards.add(new SetCardInfo("Argivian Archaeologist", 3, Rarity.RARE, mage.cards.a.ArgivianArchaeologist.class)); - cards.add(new SetCardInfo("Armageddon", 4, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Artifact Blast", 85, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); - cards.add(new SetCardInfo("Ashnod's Transmogrant", 152, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); - cards.add(new SetCardInfo("Autumn Willow", 113, Rarity.RARE, mage.cards.a.AutumnWillow.class)); - cards.add(new SetCardInfo("Balduvian Horde", 86, Rarity.RARE, mage.cards.b.BalduvianHorde.class)); - cards.add(new SetCardInfo("Ball Lightning", 87, Rarity.RARE, mage.cards.b.BallLightning.class)); - cards.add(new SetCardInfo("Baron Sengir", 58, Rarity.RARE, mage.cards.b.BaronSengir.class)); - cards.add(new SetCardInfo("Basal Thrull", 59, Rarity.COMMON, mage.cards.b.BasalThrull.class)); - cards.add(new SetCardInfo("Benalish Hero", 5, Rarity.COMMON, mage.cards.b.BenalishHero.class)); - cards.add(new SetCardInfo("Berserk", 114, Rarity.RARE, mage.cards.b.Berserk.class)); - cards.add(new SetCardInfo("Bestial Fury", 88, Rarity.COMMON, mage.cards.b.BestialFury.class)); - cards.add(new SetCardInfo("Black Knight", 60, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); - cards.add(new SetCardInfo("Blight", 61, Rarity.UNCOMMON, mage.cards.b.Blight.class)); - cards.add(new SetCardInfo("Breeding Pit", 62, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); - cards.add(new SetCardInfo("Brothers of Fire", 89, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); - cards.add(new SetCardInfo("Carnivorous Plant", 115, Rarity.UNCOMMON, mage.cards.c.CarnivorousPlant.class)); - cards.add(new SetCardInfo("Centaur Archer", 142, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); - cards.add(new SetCardInfo("Chains of Mephistopheles", 63, Rarity.RARE, mage.cards.c.ChainsOfMephistopheles.class)); - cards.add(new SetCardInfo("Chub Toad", 116, Rarity.COMMON, mage.cards.c.ChubToad.class)); - cards.add(new SetCardInfo("Clockwork Beast", 153, Rarity.UNCOMMON, mage.cards.c.ClockworkBeast.class)); - cards.add(new SetCardInfo("Contagion", 64, Rarity.RARE, mage.cards.c.Contagion.class)); - cards.add(new SetCardInfo("Copper Tablet", 154, Rarity.UNCOMMON, mage.cards.c.CopperTablet.class)); - cards.add(new SetCardInfo("Crookshank Kobolds", 90, Rarity.COMMON, mage.cards.c.CrookshankKobolds.class)); - cards.add(new SetCardInfo("Crusade", 6, Rarity.RARE, mage.cards.c.Crusade.class)); - cards.add(new SetCardInfo("Cuombajj Witches", 65, Rarity.COMMON, mage.cards.c.CuombajjWitches.class)); - cards.add(new SetCardInfo("Cursed Rack", 155, Rarity.UNCOMMON, mage.cards.c.CursedRack.class)); - cards.add(new SetCardInfo("Dakkon Blackblade", 143, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); - cards.add(new SetCardInfo("Death Speakers", 7, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); - cards.add(new SetCardInfo("Death Ward", 8, Rarity.COMMON, mage.cards.d.DeathWard.class)); - cards.add(new SetCardInfo("Derelor", 66, Rarity.UNCOMMON, mage.cards.d.Derelor.class)); - cards.add(new SetCardInfo("Diamond Valley", 175, Rarity.RARE, mage.cards.d.DiamondValley.class)); - cards.add(new SetCardInfo("Diminishing Returns", 32, Rarity.RARE, mage.cards.d.DiminishingReturns.class)); - cards.add(new SetCardInfo("Divine Transformation", 9, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); - cards.add(new SetCardInfo("Dragon Engine", 156, Rarity.COMMON, mage.cards.d.DragonEngine.class)); - cards.add(new SetCardInfo("Dust to Dust", 10, Rarity.COMMON, mage.cards.d.DustToDust.class)); - cards.add(new SetCardInfo("Dwarven Catapult", 91, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); - cards.add(new SetCardInfo("Dwarven Soldier", 92, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); - cards.add(new SetCardInfo("Eater of the Dead", 67, Rarity.UNCOMMON, mage.cards.e.EaterOfTheDead.class)); - cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class)); - cards.add(new SetCardInfo("Erg Raiders", 68, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); - cards.add(new SetCardInfo("Eureka", 117, Rarity.RARE, mage.cards.e.Eureka.class)); - cards.add(new SetCardInfo("Exile", 12, Rarity.COMMON, mage.cards.e.Exile.class)); - cards.add(new SetCardInfo("The Fallen", 69, Rarity.UNCOMMON, mage.cards.t.TheFallen.class)); - cards.add(new SetCardInfo("Feast or Famine", 70, Rarity.COMMON, mage.cards.f.FeastOrFamine.class)); - cards.add(new SetCardInfo("Fire Covenant", 145, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); - cards.add(new SetCardInfo("Fissure", 93, Rarity.COMMON, mage.cards.f.Fissure.class)); - cards.add(new SetCardInfo("Forcefield", 157, Rarity.RARE, mage.cards.f.Forcefield.class)); - cards.add(new SetCardInfo("Force of Will", 33, Rarity.RARE, mage.cards.f.ForceOfWill.class)); - cards.add(new SetCardInfo("Forest", 193, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 194, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 195, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fyndhorn Elves", 118, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); - cards.add(new SetCardInfo("Ghazban Ogre", 120, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); - cards.add(new SetCardInfo("Giant Tortoise", 34, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); - cards.add(new SetCardInfo("Goblin Chirurgeon", 94, Rarity.COMMON, mage.cards.g.GoblinChirurgeon.class)); - cards.add(new SetCardInfo("Goblin Grenade", 95, Rarity.UNCOMMON, mage.cards.g.GoblinGrenade.class)); - cards.add(new SetCardInfo("Goblin Mutant", 96, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); - cards.add(new SetCardInfo("Goblins of the Flarg", 98, Rarity.COMMON, mage.cards.g.GoblinsOfTheFlarg.class)); - cards.add(new SetCardInfo("Goblin Wizard", 97, Rarity.RARE, mage.cards.g.GoblinWizard.class)); - cards.add(new SetCardInfo("Granite Gargoyle", 99, Rarity.UNCOMMON, mage.cards.g.GraniteGargoyle.class)); - cards.add(new SetCardInfo("Greater Realm of Preservation", 13, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); - cards.add(new SetCardInfo("Hallowed Ground", 14, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); - cards.add(new SetCardInfo("Hand of Justice", 15, Rarity.RARE, mage.cards.h.HandOfJustice.class)); - cards.add(new SetCardInfo("Hecatomb", 71, Rarity.RARE, mage.cards.h.Hecatomb.class)); - cards.add(new SetCardInfo("High Tide", 35, Rarity.UNCOMMON, mage.cards.h.HighTide.class)); - cards.add(new SetCardInfo("Holy Light", 16, Rarity.COMMON, mage.cards.h.HolyLight.class)); - cards.add(new SetCardInfo("Homarid Spawning Bed", 36, Rarity.UNCOMMON, mage.cards.h.HomaridSpawningBed.class)); - cards.add(new SetCardInfo("Hungry Mist", 121, Rarity.COMMON, mage.cards.h.HungryMist.class)); - cards.add(new SetCardInfo("Hyalopterous Lemure", 72, Rarity.COMMON, mage.cards.h.HyalopterousLemure.class)); - cards.add(new SetCardInfo("Hydroblast", 37, Rarity.COMMON, mage.cards.h.Hydroblast.class)); - cards.add(new SetCardInfo("Hymn of Rebirth", 146, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); - cards.add(new SetCardInfo("Hymn to Tourach", 73, Rarity.UNCOMMON, mage.cards.h.HymnToTourach.class)); - cards.add(new SetCardInfo("Icatian Lieutenant", 17, Rarity.COMMON, mage.cards.i.IcatianLieutenant.class)); - cards.add(new SetCardInfo("Icatian Town", 18, Rarity.UNCOMMON, mage.cards.i.IcatianTown.class)); - cards.add(new SetCardInfo("Ice Storm", 122, Rarity.UNCOMMON, mage.cards.i.IceStorm.class)); - cards.add(new SetCardInfo("Ifh-Biff Efreet", 123, Rarity.RARE, mage.cards.i.IfhBiffEfreet.class)); - cards.add(new SetCardInfo("Illusionary Forces", 38, Rarity.UNCOMMON, mage.cards.i.IllusionaryForces.class)); - cards.add(new SetCardInfo("Illusionary Wall", 39, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); - cards.add(new SetCardInfo("Illusions of Grandeur", 40, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); - cards.add(new SetCardInfo("Island", 184, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 185, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 186, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island of Wak-Wak", 176, Rarity.RARE, mage.cards.i.IslandOfWakWak.class)); - cards.add(new SetCardInfo("Ivory Tower", 158, Rarity.RARE, mage.cards.i.IvoryTower.class)); - cards.add(new SetCardInfo("Jacques le Vert", 147, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); - cards.add(new SetCardInfo("Jokulhaups", 100, Rarity.RARE, mage.cards.j.Jokulhaups.class)); - cards.add(new SetCardInfo("Juxtapose", 41, Rarity.UNCOMMON, mage.cards.j.Juxtapose.class)); - cards.add(new SetCardInfo("Juzam Djinn", 74, Rarity.RARE, mage.cards.j.JuzamDjinn.class)); - cards.add(new SetCardInfo("Keldon Warlord", 101, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); - cards.add(new SetCardInfo("Khabal Ghoul", 75, Rarity.RARE, mage.cards.k.KhabalGhoul.class)); - cards.add(new SetCardInfo("Knights of Thorn", 19, Rarity.COMMON, mage.cards.k.KnightsOfThorn.class)); - cards.add(new SetCardInfo("Lake of the Dead", 177, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); - cards.add(new SetCardInfo("Lightning Bolt", 102, Rarity.COMMON, mage.cards.l.LightningBolt.class)); - cards.add(new SetCardInfo("Lim-Dul's Vault", 148, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); - cards.add(new SetCardInfo("Lord of Tresserhorn", 149, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); - cards.add(new SetCardInfo("Mana Flare", 103, Rarity.RARE, mage.cards.m.ManaFlare.class)); - cards.add(new SetCardInfo("Marton Stromgald", 104, Rarity.RARE, mage.cards.m.MartonStromgald.class)); - cards.add(new SetCardInfo("Mesa Pegasus", 20, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); - cards.add(new SetCardInfo("Mindstab Thrull", 76, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); - cards.add(new SetCardInfo("Mirror Universe", 159, Rarity.RARE, mage.cards.m.MirrorUniverse.class)); - cards.add(new SetCardInfo("Mishra's Factory", 178, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); - cards.add(new SetCardInfo("Moat", 21, Rarity.RARE, mage.cards.m.Moat.class)); - cards.add(new SetCardInfo("Mountain", 190, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 191, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 192, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain Yeti", 105, Rarity.COMMON, mage.cards.m.MountainYeti.class)); - cards.add(new SetCardInfo("Mystic Remora", 42, Rarity.UNCOMMON, mage.cards.m.MysticRemora.class)); - cards.add(new SetCardInfo("Nature's Lore", 124, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Nether Shadow", 77, Rarity.UNCOMMON, mage.cards.n.NetherShadow.class)); - cards.add(new SetCardInfo("Nevinyrral's Disk", 160, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); - cards.add(new SetCardInfo("Onulet", 161, Rarity.COMMON, mage.cards.o.Onulet.class)); - cards.add(new SetCardInfo("Orcish Mechanics", 106, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); - cards.add(new SetCardInfo("Order of Leitbur", 22, Rarity.COMMON, mage.cards.o.OrderOfLeitbur.class)); - cards.add(new SetCardInfo("Order of the Ebon Hand", 78, Rarity.COMMON, mage.cards.o.OrderOfTheEbonHand.class)); - cards.add(new SetCardInfo("Oubliette", 79, Rarity.COMMON, mage.cards.o.Oubliette.class)); - cards.add(new SetCardInfo("Paralyze", 80, Rarity.COMMON, mage.cards.p.Paralyze.class)); - cards.add(new SetCardInfo("Petra Sphinx", 23, Rarity.RARE, mage.cards.p.PetraSphinx.class)); - cards.add(new SetCardInfo("Phantom Monster", 43, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); - cards.add(new SetCardInfo("Phelddagrif", 150, Rarity.RARE, mage.cards.p.Phelddagrif.class)); - cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class)); - cards.add(new SetCardInfo("Phyrexian War Beast", 162, Rarity.UNCOMMON, mage.cards.p.PhyrexianWarBeast.class)); - cards.add(new SetCardInfo("Plains", 181, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 182, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 183, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Polar Kraken", 44, Rarity.RARE, mage.cards.p.PolarKraken.class)); - cards.add(new SetCardInfo("Pox", 82, Rarity.RARE, mage.cards.p.Pox.class)); - cards.add(new SetCardInfo("Preacher", 24, Rarity.RARE, mage.cards.p.Preacher.class)); - cards.add(new SetCardInfo("Primal Order", 125, Rarity.RARE, mage.cards.p.PrimalOrder.class)); - cards.add(new SetCardInfo("Psychic Purge", 45, Rarity.UNCOMMON, mage.cards.p.PsychicPurge.class)); - cards.add(new SetCardInfo("Psychic Venom", 46, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); - cards.add(new SetCardInfo("Pyroblast", 107, Rarity.COMMON, mage.cards.p.Pyroblast.class)); - cards.add(new SetCardInfo("Rabid Wombat", 126, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); - cards.add(new SetCardInfo("Rainbow Vale", 179, Rarity.RARE, mage.cards.r.RainbowVale.class)); - cards.add(new SetCardInfo("Righteous Avengers", 25, Rarity.COMMON, mage.cards.r.RighteousAvengers.class)); - cards.add(new SetCardInfo("Ring of Ma'ruf", 163, Rarity.RARE, mage.cards.r.RingOfMaruf.class)); - cards.add(new SetCardInfo("River Merfolk", 47, Rarity.COMMON, mage.cards.r.RiverMerfolk.class)); - cards.add(new SetCardInfo("Roots", 127, Rarity.COMMON, mage.cards.r.Roots.class)); - cards.add(new SetCardInfo("Scryb Sprites", 128, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); - cards.add(new SetCardInfo("Seasinger", 49, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); - cards.add(new SetCardInfo("Sea Sprite", 48, Rarity.COMMON, mage.cards.s.SeaSprite.class)); - cards.add(new SetCardInfo("Serendib Efreet", 50, Rarity.RARE, mage.cards.s.SerendibEfreet.class)); - cards.add(new SetCardInfo("Serpent Generator", 164, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); - cards.add(new SetCardInfo("Shambling Strider", 129, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); - cards.add(new SetCardInfo("Shield of the Ages", 165, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); - cards.add(new SetCardInfo("Shield Sphere", 166, Rarity.COMMON, mage.cards.s.ShieldSphere.class)); - cards.add(new SetCardInfo("Singing Tree", 130, Rarity.UNCOMMON, mage.cards.s.SingingTree.class)); - cards.add(new SetCardInfo("Spectral Bears", 131, Rarity.UNCOMMON, mage.cards.s.SpectralBears.class)); - cards.add(new SetCardInfo("Spinal Villain", 108, Rarity.UNCOMMON, mage.cards.s.SpinalVillain.class)); - cards.add(new SetCardInfo("Stone Calendar", 167, Rarity.UNCOMMON, mage.cards.s.StoneCalendar.class)); - cards.add(new SetCardInfo("Stone Giant", 109, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); - cards.add(new SetCardInfo("Storm Seeker", 132, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); - cards.add(new SetCardInfo("Su-Chi", 168, Rarity.RARE, mage.cards.s.SuChi.class)); - cards.add(new SetCardInfo("Sunken City", 51, Rarity.UNCOMMON, mage.cards.s.SunkenCity.class)); - cards.add(new SetCardInfo("Swamp", 187, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 188, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 189, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sylvan Library", 133, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); - cards.add(new SetCardInfo("Tawnos's Coffin", 169, Rarity.RARE, mage.cards.t.TawnossCoffin.class)); - cards.add(new SetCardInfo("Telekinesis", 52, Rarity.COMMON, mage.cards.t.Telekinesis.class)); - cards.add(new SetCardInfo("Thawing Glaciers", 180, Rarity.RARE, mage.cards.t.ThawingGlaciers.class)); - cards.add(new SetCardInfo("Thicket Basilisk", 134, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); - cards.add(new SetCardInfo("Thorn Thallid", 135, Rarity.COMMON, mage.cards.t.ThornThallid.class)); - cards.add(new SetCardInfo("Thrull Champion", 83, Rarity.RARE, mage.cards.t.ThrullChampion.class)); - cards.add(new SetCardInfo("Thrull Retainer", 84, Rarity.COMMON, mage.cards.t.ThrullRetainer.class)); - cards.add(new SetCardInfo("Thunder Spirit", 27, Rarity.UNCOMMON, mage.cards.t.ThunderSpirit.class)); - cards.add(new SetCardInfo("Time Elemental", 53, Rarity.RARE, mage.cards.t.TimeElemental.class)); - cards.add(new SetCardInfo("Tivadar's Crusade", 28, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class)); - cards.add(new SetCardInfo("Tornado", 136, Rarity.RARE, mage.cards.t.Tornado.class)); - cards.add(new SetCardInfo("Urza's Bauble", 170, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); - cards.add(new SetCardInfo("Urza's Chalice", 171, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); - cards.add(new SetCardInfo("Varchild's War-Riders", 110, Rarity.RARE, mage.cards.v.VarchildsWarRiders.class)); - cards.add(new SetCardInfo("Vesuvan Doppelganger", 54, Rarity.RARE, mage.cards.v.VesuvanDoppelganger.class)); - cards.add(new SetCardInfo("Vodalian Knights", 55, Rarity.UNCOMMON, mage.cards.v.VodalianKnights.class)); - cards.add(new SetCardInfo("Walking Wall", 172, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); - cards.add(new SetCardInfo("Wanderlust", 137, Rarity.COMMON, mage.cards.w.Wanderlust.class)); - cards.add(new SetCardInfo("Winds of Change", 111, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); - cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); - cards.add(new SetCardInfo("Winter Orb", 173, Rarity.RARE, mage.cards.w.WinterOrb.class)); - cards.add(new SetCardInfo("Word of Undoing", 56, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); - cards.add(new SetCardInfo("Wyluli Wolf", 139, Rarity.COMMON, mage.cards.w.WyluliWolf.class)); - cards.add(new SetCardInfo("Yavimaya Ants", 140, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); - cards.add(new SetCardInfo("Ydwen Efreet", 112, Rarity.RARE, mage.cards.y.YdwenEfreet.class)); - cards.add(new SetCardInfo("Zuran Orb", 174, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); - } + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author LevelX2 + */ +public final class MastersEdition extends ExpansionSet { + + private static final MastersEdition instance = new MastersEdition(); + + public static MastersEdition getInstance() { + return instance; + } + + private MastersEdition() { + super("Masters Edition", "MED", ExpansionSet.buildDate(2007, 9, 10), SetType.MAGIC_ONLINE); + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Adun Oakenshield", 141, Rarity.RARE, mage.cards.a.AdunOakenshield.class)); + cards.add(new SetCardInfo("Amnesia", 29, Rarity.RARE, mage.cards.a.Amnesia.class)); + cards.add(new SetCardInfo("Angry Mob", 1, Rarity.UNCOMMON, mage.cards.a.AngryMob.class)); + cards.add(new SetCardInfo("Animate Dead", 57, Rarity.UNCOMMON, mage.cards.a.AnimateDead.class)); + cards.add(new SetCardInfo("Animate Wall", 2, Rarity.UNCOMMON, mage.cards.a.AnimateWall.class)); + cards.add(new SetCardInfo("Ankh of Mishra", 151, Rarity.RARE, mage.cards.a.AnkhOfMishra.class)); + cards.add(new SetCardInfo("Apprentice Wizard", 30, Rarity.COMMON, mage.cards.a.ApprenticeWizard.class)); + cards.add(new SetCardInfo("Arcane Denial", 31, Rarity.COMMON, mage.cards.a.ArcaneDenial.class)); + cards.add(new SetCardInfo("Argivian Archaeologist", 3, Rarity.RARE, mage.cards.a.ArgivianArchaeologist.class)); + cards.add(new SetCardInfo("Armageddon", 4, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Artifact Blast", 85, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); + cards.add(new SetCardInfo("Ashnod's Transmogrant", 152, Rarity.COMMON, mage.cards.a.AshnodsTransmogrant.class)); + cards.add(new SetCardInfo("Autumn Willow", 113, Rarity.RARE, mage.cards.a.AutumnWillow.class)); + cards.add(new SetCardInfo("Balduvian Horde", 86, Rarity.RARE, mage.cards.b.BalduvianHorde.class)); + cards.add(new SetCardInfo("Ball Lightning", 87, Rarity.RARE, mage.cards.b.BallLightning.class)); + cards.add(new SetCardInfo("Baron Sengir", 58, Rarity.RARE, mage.cards.b.BaronSengir.class)); + cards.add(new SetCardInfo("Basal Thrull", 59, Rarity.COMMON, mage.cards.b.BasalThrull.class)); + cards.add(new SetCardInfo("Benalish Hero", 5, Rarity.COMMON, mage.cards.b.BenalishHero.class)); + cards.add(new SetCardInfo("Berserk", 114, Rarity.RARE, mage.cards.b.Berserk.class)); + cards.add(new SetCardInfo("Bestial Fury", 88, Rarity.COMMON, mage.cards.b.BestialFury.class)); + cards.add(new SetCardInfo("Black Knight", 60, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blight", 61, Rarity.UNCOMMON, mage.cards.b.Blight.class)); + cards.add(new SetCardInfo("Breeding Pit", 62, Rarity.UNCOMMON, mage.cards.b.BreedingPit.class)); + cards.add(new SetCardInfo("Brothers of Fire", 89, Rarity.COMMON, mage.cards.b.BrothersOfFire.class)); + cards.add(new SetCardInfo("Carnivorous Plant", 115, Rarity.UNCOMMON, mage.cards.c.CarnivorousPlant.class)); + cards.add(new SetCardInfo("Centaur Archer", 142, Rarity.UNCOMMON, mage.cards.c.CentaurArcher.class)); + cards.add(new SetCardInfo("Chains of Mephistopheles", 63, Rarity.RARE, mage.cards.c.ChainsOfMephistopheles.class)); + cards.add(new SetCardInfo("Chub Toad", 116, Rarity.COMMON, mage.cards.c.ChubToad.class)); + cards.add(new SetCardInfo("Clockwork Beast", 153, Rarity.UNCOMMON, mage.cards.c.ClockworkBeast.class)); + cards.add(new SetCardInfo("Contagion", 64, Rarity.RARE, mage.cards.c.Contagion.class)); + cards.add(new SetCardInfo("Copper Tablet", 154, Rarity.UNCOMMON, mage.cards.c.CopperTablet.class)); + cards.add(new SetCardInfo("Crookshank Kobolds", 90, Rarity.COMMON, mage.cards.c.CrookshankKobolds.class)); + cards.add(new SetCardInfo("Crusade", 6, Rarity.RARE, mage.cards.c.Crusade.class)); + cards.add(new SetCardInfo("Cuombajj Witches", 65, Rarity.COMMON, mage.cards.c.CuombajjWitches.class)); + cards.add(new SetCardInfo("Cursed Rack", 155, Rarity.UNCOMMON, mage.cards.c.CursedRack.class)); + cards.add(new SetCardInfo("Dakkon Blackblade", 143, Rarity.RARE, mage.cards.d.DakkonBlackblade.class)); + cards.add(new SetCardInfo("Death Speakers", 7, Rarity.COMMON, mage.cards.d.DeathSpeakers.class)); + cards.add(new SetCardInfo("Death Ward", 8, Rarity.COMMON, mage.cards.d.DeathWard.class)); + cards.add(new SetCardInfo("Derelor", 66, Rarity.UNCOMMON, mage.cards.d.Derelor.class)); + cards.add(new SetCardInfo("Diamond Valley", 175, Rarity.RARE, mage.cards.d.DiamondValley.class)); + cards.add(new SetCardInfo("Diminishing Returns", 32, Rarity.RARE, mage.cards.d.DiminishingReturns.class)); + cards.add(new SetCardInfo("Divine Transformation", 9, Rarity.UNCOMMON, mage.cards.d.DivineTransformation.class)); + cards.add(new SetCardInfo("Dragon Engine", 156, Rarity.COMMON, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Dust to Dust", 10, Rarity.COMMON, mage.cards.d.DustToDust.class)); + cards.add(new SetCardInfo("Dwarven Catapult", 91, Rarity.UNCOMMON, mage.cards.d.DwarvenCatapult.class)); + cards.add(new SetCardInfo("Dwarven Soldier", 92, Rarity.COMMON, mage.cards.d.DwarvenSoldier.class)); + cards.add(new SetCardInfo("Eater of the Dead", 67, Rarity.UNCOMMON, mage.cards.e.EaterOfTheDead.class)); + cards.add(new SetCardInfo("Elder Land Wurm", 11, Rarity.UNCOMMON, mage.cards.e.ElderLandWurm.class)); + cards.add(new SetCardInfo("Erg Raiders", 68, Rarity.COMMON, mage.cards.e.ErgRaiders.class)); + cards.add(new SetCardInfo("Eureka", 117, Rarity.RARE, mage.cards.e.Eureka.class)); + cards.add(new SetCardInfo("Exile", 12, Rarity.COMMON, mage.cards.e.Exile.class)); + cards.add(new SetCardInfo("The Fallen", 69, Rarity.UNCOMMON, mage.cards.t.TheFallen.class)); + cards.add(new SetCardInfo("Feast or Famine", 70, Rarity.COMMON, mage.cards.f.FeastOrFamine.class)); + cards.add(new SetCardInfo("Fire Covenant", 145, Rarity.UNCOMMON, mage.cards.f.FireCovenant.class)); + cards.add(new SetCardInfo("Fissure", 93, Rarity.COMMON, mage.cards.f.Fissure.class)); + cards.add(new SetCardInfo("Forcefield", 157, Rarity.RARE, mage.cards.f.Forcefield.class)); + cards.add(new SetCardInfo("Force of Will", 33, Rarity.RARE, mage.cards.f.ForceOfWill.class)); + cards.add(new SetCardInfo("Forest", 193, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 194, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 195, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fyndhorn Elves", 118, Rarity.COMMON, mage.cards.f.FyndhornElves.class)); + cards.add(new SetCardInfo("Ghazban Ogre", 120, Rarity.COMMON, mage.cards.g.GhazbanOgre.class)); + cards.add(new SetCardInfo("Giant Tortoise", 34, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); + cards.add(new SetCardInfo("Goblin Chirurgeon", 94, Rarity.COMMON, mage.cards.g.GoblinChirurgeon.class)); + cards.add(new SetCardInfo("Goblin Grenade", 95, Rarity.UNCOMMON, mage.cards.g.GoblinGrenade.class)); + cards.add(new SetCardInfo("Goblin Mutant", 96, Rarity.UNCOMMON, mage.cards.g.GoblinMutant.class)); + cards.add(new SetCardInfo("Goblins of the Flarg", 98, Rarity.COMMON, mage.cards.g.GoblinsOfTheFlarg.class)); + cards.add(new SetCardInfo("Goblin Wizard", 97, Rarity.RARE, mage.cards.g.GoblinWizard.class)); + cards.add(new SetCardInfo("Granite Gargoyle", 99, Rarity.UNCOMMON, mage.cards.g.GraniteGargoyle.class)); + cards.add(new SetCardInfo("Greater Realm of Preservation", 13, Rarity.UNCOMMON, mage.cards.g.GreaterRealmOfPreservation.class)); + cards.add(new SetCardInfo("Hallowed Ground", 14, Rarity.UNCOMMON, mage.cards.h.HallowedGround.class)); + cards.add(new SetCardInfo("Hand of Justice", 15, Rarity.RARE, mage.cards.h.HandOfJustice.class)); + cards.add(new SetCardInfo("Hecatomb", 71, Rarity.RARE, mage.cards.h.Hecatomb.class)); + cards.add(new SetCardInfo("High Tide", 35, Rarity.UNCOMMON, mage.cards.h.HighTide.class)); + cards.add(new SetCardInfo("Holy Light", 16, Rarity.COMMON, mage.cards.h.HolyLight.class)); + cards.add(new SetCardInfo("Homarid Spawning Bed", 36, Rarity.UNCOMMON, mage.cards.h.HomaridSpawningBed.class)); + cards.add(new SetCardInfo("Hungry Mist", 121, Rarity.COMMON, mage.cards.h.HungryMist.class)); + cards.add(new SetCardInfo("Hyalopterous Lemure", 72, Rarity.COMMON, mage.cards.h.HyalopterousLemure.class)); + cards.add(new SetCardInfo("Hydroblast", 37, Rarity.COMMON, mage.cards.h.Hydroblast.class)); + cards.add(new SetCardInfo("Hymn of Rebirth", 146, Rarity.UNCOMMON, mage.cards.h.HymnOfRebirth.class)); + cards.add(new SetCardInfo("Hymn to Tourach", 73, Rarity.UNCOMMON, mage.cards.h.HymnToTourach.class)); + cards.add(new SetCardInfo("Icatian Lieutenant", 17, Rarity.COMMON, mage.cards.i.IcatianLieutenant.class)); + cards.add(new SetCardInfo("Icatian Town", 18, Rarity.UNCOMMON, mage.cards.i.IcatianTown.class)); + cards.add(new SetCardInfo("Ice Storm", 122, Rarity.UNCOMMON, mage.cards.i.IceStorm.class)); + cards.add(new SetCardInfo("Ifh-Biff Efreet", 123, Rarity.RARE, mage.cards.i.IfhBiffEfreet.class)); + cards.add(new SetCardInfo("Illusionary Forces", 38, Rarity.UNCOMMON, mage.cards.i.IllusionaryForces.class)); + cards.add(new SetCardInfo("Illusionary Wall", 39, Rarity.COMMON, mage.cards.i.IllusionaryWall.class)); + cards.add(new SetCardInfo("Illusions of Grandeur", 40, Rarity.RARE, mage.cards.i.IllusionsOfGrandeur.class)); + cards.add(new SetCardInfo("Island", 184, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 185, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 186, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island of Wak-Wak", 176, Rarity.RARE, mage.cards.i.IslandOfWakWak.class)); + cards.add(new SetCardInfo("Ivory Tower", 158, Rarity.RARE, mage.cards.i.IvoryTower.class)); + cards.add(new SetCardInfo("Jacques le Vert", 147, Rarity.RARE, mage.cards.j.JacquesLeVert.class)); + cards.add(new SetCardInfo("Jokulhaups", 100, Rarity.RARE, mage.cards.j.Jokulhaups.class)); + cards.add(new SetCardInfo("Juxtapose", 41, Rarity.UNCOMMON, mage.cards.j.Juxtapose.class)); + cards.add(new SetCardInfo("Juzam Djinn", 74, Rarity.RARE, mage.cards.j.JuzamDjinn.class)); + cards.add(new SetCardInfo("Keldon Warlord", 101, Rarity.UNCOMMON, mage.cards.k.KeldonWarlord.class)); + cards.add(new SetCardInfo("Khabal Ghoul", 75, Rarity.RARE, mage.cards.k.KhabalGhoul.class)); + cards.add(new SetCardInfo("Knights of Thorn", 19, Rarity.COMMON, mage.cards.k.KnightsOfThorn.class)); + cards.add(new SetCardInfo("Lake of the Dead", 177, Rarity.RARE, mage.cards.l.LakeOfTheDead.class)); + cards.add(new SetCardInfo("Lightning Bolt", 102, Rarity.COMMON, mage.cards.l.LightningBolt.class)); + cards.add(new SetCardInfo("Lim-Dul's Vault", 148, Rarity.UNCOMMON, mage.cards.l.LimDulsVault.class)); + cards.add(new SetCardInfo("Lord of Tresserhorn", 149, Rarity.RARE, mage.cards.l.LordOfTresserhorn.class)); + cards.add(new SetCardInfo("Mana Flare", 103, Rarity.RARE, mage.cards.m.ManaFlare.class)); + cards.add(new SetCardInfo("Marton Stromgald", 104, Rarity.RARE, mage.cards.m.MartonStromgald.class)); + cards.add(new SetCardInfo("Mesa Pegasus", 20, Rarity.COMMON, mage.cards.m.MesaPegasus.class)); + cards.add(new SetCardInfo("Mindstab Thrull", 76, Rarity.COMMON, mage.cards.m.MindstabThrull.class)); + cards.add(new SetCardInfo("Mirror Universe", 159, Rarity.RARE, mage.cards.m.MirrorUniverse.class)); + cards.add(new SetCardInfo("Mishra's Factory", 178, Rarity.UNCOMMON, mage.cards.m.MishrasFactory.class)); + cards.add(new SetCardInfo("Moat", 21, Rarity.RARE, mage.cards.m.Moat.class)); + cards.add(new SetCardInfo("Mountain", 190, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 191, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 192, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain Yeti", 105, Rarity.COMMON, mage.cards.m.MountainYeti.class)); + cards.add(new SetCardInfo("Mystic Remora", 42, Rarity.UNCOMMON, mage.cards.m.MysticRemora.class)); + cards.add(new SetCardInfo("Nature's Lore", 124, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Nether Shadow", 77, Rarity.UNCOMMON, mage.cards.n.NetherShadow.class)); + cards.add(new SetCardInfo("Nevinyrral's Disk", 160, Rarity.RARE, mage.cards.n.NevinyrralsDisk.class)); + cards.add(new SetCardInfo("Onulet", 161, Rarity.COMMON, mage.cards.o.Onulet.class)); + cards.add(new SetCardInfo("Orcish Mechanics", 106, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); + cards.add(new SetCardInfo("Order of Leitbur", 22, Rarity.COMMON, mage.cards.o.OrderOfLeitbur.class)); + cards.add(new SetCardInfo("Order of the Ebon Hand", 78, Rarity.COMMON, mage.cards.o.OrderOfTheEbonHand.class)); + cards.add(new SetCardInfo("Oubliette", 79, Rarity.COMMON, mage.cards.o.Oubliette.class)); + cards.add(new SetCardInfo("Paralyze", 80, Rarity.COMMON, mage.cards.p.Paralyze.class)); + cards.add(new SetCardInfo("Petra Sphinx", 23, Rarity.RARE, mage.cards.p.PetraSphinx.class)); + cards.add(new SetCardInfo("Phantom Monster", 43, Rarity.COMMON, mage.cards.p.PhantomMonster.class)); + cards.add(new SetCardInfo("Phelddagrif", 150, Rarity.RARE, mage.cards.p.Phelddagrif.class)); + cards.add(new SetCardInfo("Phyrexian Boon", 81, Rarity.COMMON, mage.cards.p.PhyrexianBoon.class)); + cards.add(new SetCardInfo("Phyrexian War Beast", 162, Rarity.UNCOMMON, mage.cards.p.PhyrexianWarBeast.class)); + cards.add(new SetCardInfo("Plains", 181, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 182, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 183, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Polar Kraken", 44, Rarity.RARE, mage.cards.p.PolarKraken.class)); + cards.add(new SetCardInfo("Pox", 82, Rarity.RARE, mage.cards.p.Pox.class)); + cards.add(new SetCardInfo("Preacher", 24, Rarity.RARE, mage.cards.p.Preacher.class)); + cards.add(new SetCardInfo("Primal Order", 125, Rarity.RARE, mage.cards.p.PrimalOrder.class)); + cards.add(new SetCardInfo("Psychic Purge", 45, Rarity.UNCOMMON, mage.cards.p.PsychicPurge.class)); + cards.add(new SetCardInfo("Psychic Venom", 46, Rarity.COMMON, mage.cards.p.PsychicVenom.class)); + cards.add(new SetCardInfo("Pyroblast", 107, Rarity.COMMON, mage.cards.p.Pyroblast.class)); + cards.add(new SetCardInfo("Rabid Wombat", 126, Rarity.UNCOMMON, mage.cards.r.RabidWombat.class)); + cards.add(new SetCardInfo("Rainbow Vale", 179, Rarity.RARE, mage.cards.r.RainbowVale.class)); + cards.add(new SetCardInfo("Righteous Avengers", 25, Rarity.COMMON, mage.cards.r.RighteousAvengers.class)); + cards.add(new SetCardInfo("Ring of Ma'ruf", 163, Rarity.RARE, mage.cards.r.RingOfMaruf.class)); + cards.add(new SetCardInfo("River Merfolk", 47, Rarity.COMMON, mage.cards.r.RiverMerfolk.class)); + cards.add(new SetCardInfo("Roots", 127, Rarity.COMMON, mage.cards.r.Roots.class)); + cards.add(new SetCardInfo("Scryb Sprites", 128, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); + cards.add(new SetCardInfo("Seasinger", 49, Rarity.UNCOMMON, mage.cards.s.Seasinger.class)); + cards.add(new SetCardInfo("Sea Sprite", 48, Rarity.COMMON, mage.cards.s.SeaSprite.class)); + cards.add(new SetCardInfo("Seraph", 26, Rarity.RARE, mage.cards.s.Seraph.class)); + cards.add(new SetCardInfo("Serendib Efreet", 50, Rarity.RARE, mage.cards.s.SerendibEfreet.class)); + cards.add(new SetCardInfo("Serpent Generator", 164, Rarity.RARE, mage.cards.s.SerpentGenerator.class)); + cards.add(new SetCardInfo("Shambling Strider", 129, Rarity.COMMON, mage.cards.s.ShamblingStrider.class)); + cards.add(new SetCardInfo("Shield of the Ages", 165, Rarity.UNCOMMON, mage.cards.s.ShieldOfTheAges.class)); + cards.add(new SetCardInfo("Shield Sphere", 166, Rarity.COMMON, mage.cards.s.ShieldSphere.class)); + cards.add(new SetCardInfo("Singing Tree", 130, Rarity.UNCOMMON, mage.cards.s.SingingTree.class)); + cards.add(new SetCardInfo("Spectral Bears", 131, Rarity.UNCOMMON, mage.cards.s.SpectralBears.class)); + cards.add(new SetCardInfo("Spinal Villain", 108, Rarity.UNCOMMON, mage.cards.s.SpinalVillain.class)); + cards.add(new SetCardInfo("Stone Calendar", 167, Rarity.UNCOMMON, mage.cards.s.StoneCalendar.class)); + cards.add(new SetCardInfo("Stone Giant", 109, Rarity.UNCOMMON, mage.cards.s.StoneGiant.class)); + cards.add(new SetCardInfo("Storm Seeker", 132, Rarity.UNCOMMON, mage.cards.s.StormSeeker.class)); + cards.add(new SetCardInfo("Su-Chi", 168, Rarity.RARE, mage.cards.s.SuChi.class)); + cards.add(new SetCardInfo("Sunken City", 51, Rarity.UNCOMMON, mage.cards.s.SunkenCity.class)); + cards.add(new SetCardInfo("Swamp", 187, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 188, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 189, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Library", 133, Rarity.RARE, mage.cards.s.SylvanLibrary.class)); + cards.add(new SetCardInfo("Tawnos's Coffin", 169, Rarity.RARE, mage.cards.t.TawnossCoffin.class)); + cards.add(new SetCardInfo("Telekinesis", 52, Rarity.COMMON, mage.cards.t.Telekinesis.class)); + cards.add(new SetCardInfo("Thawing Glaciers", 180, Rarity.RARE, mage.cards.t.ThawingGlaciers.class)); + cards.add(new SetCardInfo("Thicket Basilisk", 134, Rarity.UNCOMMON, mage.cards.t.ThicketBasilisk.class)); + cards.add(new SetCardInfo("Thorn Thallid", 135, Rarity.COMMON, mage.cards.t.ThornThallid.class)); + cards.add(new SetCardInfo("Thrull Champion", 83, Rarity.RARE, mage.cards.t.ThrullChampion.class)); + cards.add(new SetCardInfo("Thrull Retainer", 84, Rarity.COMMON, mage.cards.t.ThrullRetainer.class)); + cards.add(new SetCardInfo("Thunder Spirit", 27, Rarity.UNCOMMON, mage.cards.t.ThunderSpirit.class)); + cards.add(new SetCardInfo("Time Elemental", 53, Rarity.RARE, mage.cards.t.TimeElemental.class)); + cards.add(new SetCardInfo("Tivadar's Crusade", 28, Rarity.UNCOMMON, mage.cards.t.TivadarsCrusade.class)); + cards.add(new SetCardInfo("Tornado", 136, Rarity.RARE, mage.cards.t.Tornado.class)); + cards.add(new SetCardInfo("Urza's Bauble", 170, Rarity.UNCOMMON, mage.cards.u.UrzasBauble.class)); + cards.add(new SetCardInfo("Urza's Chalice", 171, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); + cards.add(new SetCardInfo("Varchild's War-Riders", 110, Rarity.RARE, mage.cards.v.VarchildsWarRiders.class)); + cards.add(new SetCardInfo("Vesuvan Doppelganger", 54, Rarity.RARE, mage.cards.v.VesuvanDoppelganger.class)); + cards.add(new SetCardInfo("Vodalian Knights", 55, Rarity.UNCOMMON, mage.cards.v.VodalianKnights.class)); + cards.add(new SetCardInfo("Walking Wall", 172, Rarity.UNCOMMON, mage.cards.w.WalkingWall.class)); + cards.add(new SetCardInfo("Wanderlust", 137, Rarity.COMMON, mage.cards.w.Wanderlust.class)); + cards.add(new SetCardInfo("Winds of Change", 111, Rarity.UNCOMMON, mage.cards.w.WindsOfChange.class)); + cards.add(new SetCardInfo("Winter Blast", 138, Rarity.UNCOMMON, mage.cards.w.WinterBlast.class)); + cards.add(new SetCardInfo("Winter Orb", 173, Rarity.RARE, mage.cards.w.WinterOrb.class)); + cards.add(new SetCardInfo("Word of Undoing", 56, Rarity.COMMON, mage.cards.w.WordOfUndoing.class)); + cards.add(new SetCardInfo("Wyluli Wolf", 139, Rarity.COMMON, mage.cards.w.WyluliWolf.class)); + cards.add(new SetCardInfo("Yavimaya Ants", 140, Rarity.UNCOMMON, mage.cards.y.YavimayaAnts.class)); + cards.add(new SetCardInfo("Ydwen Efreet", 112, Rarity.RARE, mage.cards.y.YdwenEfreet.class)); + cards.add(new SetCardInfo("Zuran Orb", 174, Rarity.UNCOMMON, mage.cards.z.ZuranOrb.class)); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/MastersEditionII.java b/Mage.Sets/src/mage/sets/MastersEditionII.java index 7002dff323..573f0482df 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionII.java @@ -1,258 +1,265 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author LevelX2 - */ -public final class MastersEditionII extends ExpansionSet { - - private static final MastersEditionII instance = new MastersEditionII(); - - public static MastersEditionII getInstance() { - return instance; - } - - private MastersEditionII() { - super("Masters Edition II", "ME2", ExpansionSet.buildDate(2008, 9, 22), SetType.MAGIC_ONLINE); - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); - cards.add(new SetCardInfo("Adarkar Sentinel", 201, Rarity.COMMON, mage.cards.a.AdarkarSentinel.class)); - cards.add(new SetCardInfo("Aeolipile", 202, Rarity.COMMON, mage.cards.a.Aeolipile.class)); - cards.add(new SetCardInfo("Aether Storm", 39, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); - cards.add(new SetCardInfo("Ambush Party", 115, Rarity.COMMON, mage.cards.a.AmbushParty.class)); - cards.add(new SetCardInfo("An-Zerrin Ruins", 117, Rarity.RARE, mage.cards.a.AnZerrinRuins.class)); - cards.add(new SetCardInfo("Anarchy", 116, Rarity.RARE, mage.cards.a.Anarchy.class)); - cards.add(new SetCardInfo("Angel of Fury", 2, Rarity.RARE, mage.cards.a.AngelOfFury.class)); - cards.add(new SetCardInfo("Angel of Light", 3, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); - cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); - cards.add(new SetCardInfo("Armor Thrull", 77, Rarity.COMMON, mage.cards.a.ArmorThrull.class)); - cards.add(new SetCardInfo("Armored Griffin", 5, Rarity.COMMON, mage.cards.a.ArmoredGriffin.class)); - cards.add(new SetCardInfo("Ashen Ghoul", 78, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); - cards.add(new SetCardInfo("Ashnod's Cylix", 203, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); - cards.add(new SetCardInfo("Aurochs", 153, Rarity.COMMON, mage.cards.a.Aurochs.class)); - cards.add(new SetCardInfo("Aysen Bureaucrats", 6, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); - cards.add(new SetCardInfo("Aysen Crusader", 7, Rarity.UNCOMMON, mage.cards.a.AysenCrusader.class)); - cards.add(new SetCardInfo("Badlands", 225, Rarity.RARE, mage.cards.b.Badlands.class)); - cards.add(new SetCardInfo("Balduvian Conjurer", 40, Rarity.COMMON, mage.cards.b.BalduvianConjurer.class)); - cards.add(new SetCardInfo("Balduvian Dead", 79, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); - cards.add(new SetCardInfo("Balduvian Hydra", 118, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); - cards.add(new SetCardInfo("Balduvian Trading Post", 226, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); - cards.add(new SetCardInfo("Barbed Sextant", 204, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); - cards.add(new SetCardInfo("Binding Grasp", 41, Rarity.RARE, mage.cards.b.BindingGrasp.class)); - cards.add(new SetCardInfo("Bounty of the Hunt", 154, Rarity.RARE, mage.cards.b.BountyOfTheHunt.class)); - cards.add(new SetCardInfo("Brainstorm", 42, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); - cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class)); - cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class)); - cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class)); - cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class)); - cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); - cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class)); - cards.add(new SetCardInfo("Caribou Range", 8, Rarity.RARE, mage.cards.c.CaribouRange.class)); - cards.add(new SetCardInfo("Clockwork Steed", 205, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); - cards.add(new SetCardInfo("Combat Medic", 9, Rarity.COMMON, mage.cards.c.CombatMedic.class)); - cards.add(new SetCardInfo("Conquer", 122, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); - cards.add(new SetCardInfo("Counterspell", 44, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Dance of the Dead", 83, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); - cards.add(new SetCardInfo("Dark Banishing", 84, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Death Spark", 123, Rarity.COMMON, mage.cards.d.DeathSpark.class)); - cards.add(new SetCardInfo("Deep Spawn", 45, Rarity.RARE, mage.cards.d.DeepSpawn.class)); - cards.add(new SetCardInfo("Demonic Consultation", 85, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); - cards.add(new SetCardInfo("Despotic Scepter", 206, Rarity.RARE, mage.cards.d.DespoticScepter.class)); - cards.add(new SetCardInfo("Diabolic Vision", 191, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); - cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dreams of the Dead", 46, Rarity.RARE, mage.cards.d.DreamsOfTheDead.class)); - cards.add(new SetCardInfo("Drift of the Dead", 86, Rarity.COMMON, mage.cards.d.DriftOfTheDead.class)); - cards.add(new SetCardInfo("Dry Spell", 87, Rarity.COMMON, mage.cards.d.DrySpell.class)); - cards.add(new SetCardInfo("Dwarven Ruins", 227, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); - cards.add(new SetCardInfo("Dystopia", 88, Rarity.RARE, mage.cards.d.Dystopia.class)); - cards.add(new SetCardInfo("Earthlink", 192, Rarity.RARE, mage.cards.e.Earthlink.class)); - cards.add(new SetCardInfo("Ebon Praetor", 89, Rarity.RARE, mage.cards.e.EbonPraetor.class)); - cards.add(new SetCardInfo("Ebon Stronghold", 228, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); - cards.add(new SetCardInfo("Elemental Augury", 193, Rarity.RARE, mage.cards.e.ElementalAugury.class)); - cards.add(new SetCardInfo("Elkin Bottle", 207, Rarity.RARE, mage.cards.e.ElkinBottle.class)); - cards.add(new SetCardInfo("Elven Lyre", 208, Rarity.COMMON, mage.cards.e.ElvenLyre.class)); - cards.add(new SetCardInfo("Elvish Farmer", 156, Rarity.RARE, mage.cards.e.ElvishFarmer.class)); - cards.add(new SetCardInfo("Elvish Hunter", 157, Rarity.COMMON, mage.cards.e.ElvishHunter.class)); - cards.add(new SetCardInfo("Elvish Ranger", 158, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); - cards.add(new SetCardInfo("Elvish Spirit Guide", 159, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); - cards.add(new SetCardInfo("Energy Storm", 11, Rarity.RARE, mage.cards.e.EnergyStorm.class)); - cards.add(new SetCardInfo("Enervate", 47, Rarity.COMMON, mage.cards.e.Enervate.class)); - cards.add(new SetCardInfo("Errand of Duty", 12, Rarity.UNCOMMON, mage.cards.e.ErrandOfDuty.class)); - cards.add(new SetCardInfo("Errantry", 124, Rarity.COMMON, mage.cards.e.Errantry.class)); - cards.add(new SetCardInfo("Essence Filter", 160, Rarity.UNCOMMON, mage.cards.e.EssenceFilter.class)); - cards.add(new SetCardInfo("Essence Flare", 48, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); - cards.add(new SetCardInfo("Farrel's Mantle", 13, Rarity.UNCOMMON, mage.cards.f.FarrelsMantle.class)); - cards.add(new SetCardInfo("Farrel's Zealot", 14, Rarity.UNCOMMON, mage.cards.f.FarrelsZealot.class)); - cards.add(new SetCardInfo("Feral Thallid", 161, Rarity.COMMON, mage.cards.f.FeralThallid.class)); - cards.add(new SetCardInfo("Fire Dragon", 125, Rarity.RARE, mage.cards.f.FireDragon.class)); - cards.add(new SetCardInfo("Flame Spirit", 126, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); - cards.add(new SetCardInfo("Folk of the Pines", 162, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); - cards.add(new SetCardInfo("Forbidden Lore", 163, Rarity.UNCOMMON, mage.cards.f.ForbiddenLore.class)); - cards.add(new SetCardInfo("Forgotten Lore", 164, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); - cards.add(new SetCardInfo("Foul Familiar", 90, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); - cards.add(new SetCardInfo("Fumarole", 194, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); - cards.add(new SetCardInfo("Funeral March", 91, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); - cards.add(new SetCardInfo("Fungal Bloom", 165, Rarity.RARE, mage.cards.f.FungalBloom.class)); - cards.add(new SetCardInfo("Fyndhorn Pollen", 166, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); - cards.add(new SetCardInfo("Gangrenous Zombies", 92, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); - cards.add(new SetCardInfo("Giant Growth", 167, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Trap Door Spider", 195, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); - cards.add(new SetCardInfo("Glacial Chasm", 229, Rarity.RARE, mage.cards.g.GlacialChasm.class)); - cards.add(new SetCardInfo("Glacial Crevasses", 127, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); - cards.add(new SetCardInfo("Gorilla Shaman", 129, Rarity.UNCOMMON, mage.cards.g.GorillaShaman.class)); - cards.add(new SetCardInfo("Grandmother Sengir", 93, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); - cards.add(new SetCardInfo("Havenwood Battleground", 230, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); - cards.add(new SetCardInfo("Heart of Yavimaya", 231, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); - cards.add(new SetCardInfo("Helm of Obedience", 210, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); - cards.add(new SetCardInfo("Icatian Javelineers", 15, Rarity.COMMON, mage.cards.i.IcatianJavelineers.class)); - cards.add(new SetCardInfo("Icatian Phalanx", 16, Rarity.COMMON, mage.cards.i.IcatianPhalanx.class)); - cards.add(new SetCardInfo("Icatian Scout", 17, Rarity.COMMON, mage.cards.i.IcatianScout.class)); - cards.add(new SetCardInfo("Ice Floe", 232, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); - cards.add(new SetCardInfo("Iceberg", 49, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); - cards.add(new SetCardInfo("Icequake", 94, Rarity.COMMON, mage.cards.i.Icequake.class)); - cards.add(new SetCardInfo("Icy Prison", 50, Rarity.COMMON, mage.cards.i.IcyPrison.class)); - cards.add(new SetCardInfo("Ihsan's Shade", 95, Rarity.RARE, mage.cards.i.IhsansShade.class)); - cards.add(new SetCardInfo("Imperial Recruiter", 130, Rarity.RARE, mage.cards.i.ImperialRecruiter.class)); - cards.add(new SetCardInfo("Imperial Seal", 96, Rarity.RARE, mage.cards.i.ImperialSeal.class)); - cards.add(new SetCardInfo("Incinerate", 131, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infernal Darkness", 97, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); - cards.add(new SetCardInfo("Inheritance", 18, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); - cards.add(new SetCardInfo("Ironclaw Orcs", 132, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); - cards.add(new SetCardInfo("Ivory Gargoyle", 19, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); - cards.add(new SetCardInfo("Jester's Mask", 211, Rarity.RARE, mage.cards.j.JestersMask.class)); - cards.add(new SetCardInfo("Jeweled Amulet", 212, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); - cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); - cards.add(new SetCardInfo("Joven's Ferrets", 169, Rarity.UNCOMMON, mage.cards.j.JovensFerrets.class)); - cards.add(new SetCardInfo("Juniper Order Advocate", 20, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); - cards.add(new SetCardInfo("Karplusan Giant", 133, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); - cards.add(new SetCardInfo("Kaysa", 170, Rarity.RARE, mage.cards.k.Kaysa.class)); - cards.add(new SetCardInfo("Kjeldoran Dead", 98, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); - cards.add(new SetCardInfo("Kjeldoran Home Guard", 22, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); - cards.add(new SetCardInfo("Kjeldoran Outpost", 233, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); - cards.add(new SetCardInfo("Kjeldoran Skycaptain", 23, Rarity.COMMON, mage.cards.k.KjeldoranSkycaptain.class)); - cards.add(new SetCardInfo("Knight of Stromgald", 99, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); - cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); - cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); - cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); - cards.add(new SetCardInfo("Lat-Nam's Legacy", 52, Rarity.COMMON, mage.cards.l.LatNamsLegacy.class)); - cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); - cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, mage.cards.l.LimDulsHighGuard.class)); - cards.add(new SetCardInfo("Lodestone Bauble", 213, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); - cards.add(new SetCardInfo("Magus of the Unseen", 53, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); - cards.add(new SetCardInfo("Mana Crypt", 214, Rarity.RARE, mage.cards.m.ManaCrypt.class)); - cards.add(new SetCardInfo("Marjhan", 54, Rarity.RARE, mage.cards.m.Marjhan.class)); - cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); - cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); - cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); - cards.add(new SetCardInfo("Mishra's Groundbreaker", 215, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); - cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); - cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); - cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); - cards.add(new SetCardInfo("Nature's Blessing", 196, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); - cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); - cards.add(new SetCardInfo("Necrite", 106, Rarity.COMMON, mage.cards.n.Necrite.class)); - cards.add(new SetCardInfo("Necropotence", 107, Rarity.RARE, mage.cards.n.Necropotence.class)); - cards.add(new SetCardInfo("Night Soil", 173, Rarity.UNCOMMON, mage.cards.n.NightSoil.class)); - cards.add(new SetCardInfo("Orc General", 137, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class)); - cards.add(new SetCardInfo("Orcish Cannoneers", 138, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); - cards.add(new SetCardInfo("Orcish Captain", 139, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); - cards.add(new SetCardInfo("Orcish Lumberjack", 142, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); - cards.add(new SetCardInfo("Orcish Squatters", 143, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); - cards.add(new SetCardInfo("Orcish Veteran", 144, Rarity.COMMON, mage.cards.o.OrcishVeteran.class)); - cards.add(new SetCardInfo("Order of the Sacred Torch", 25, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); - cards.add(new SetCardInfo("Order of the White Shield", 26, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); - cards.add(new SetCardInfo("Panic", 145, Rarity.COMMON, mage.cards.p.Panic.class)); - cards.add(new SetCardInfo("Personal Tutor", 58, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); - cards.add(new SetCardInfo("Phantasmal Fiend", 108, Rarity.COMMON, mage.cards.p.PhantasmalFiend.class)); - cards.add(new SetCardInfo("Phyrexian Devourer", 216, Rarity.UNCOMMON, mage.cards.p.PhyrexianDevourer.class)); - cards.add(new SetCardInfo("Pillage", 146, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); - cards.add(new SetCardInfo("Portent", 60, Rarity.COMMON, mage.cards.p.Portent.class)); - cards.add(new SetCardInfo("Pyrokinesis", 147, Rarity.RARE, mage.cards.p.Pyrokinesis.class)); - cards.add(new SetCardInfo("Ravages of War", 27, Rarity.RARE, mage.cards.r.RavagesOfWar.class)); - cards.add(new SetCardInfo("Ray of Command", 61, Rarity.UNCOMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Red Cliffs Armada", 62, Rarity.COMMON, mage.cards.r.RedCliffsArmada.class)); - cards.add(new SetCardInfo("Reinforcements", 28, Rarity.COMMON, mage.cards.r.Reinforcements.class)); - cards.add(new SetCardInfo("Reprisal", 29, Rarity.COMMON, mage.cards.r.Reprisal.class)); - cards.add(new SetCardInfo("Retribution", 148, Rarity.UNCOMMON, mage.cards.r.Retribution.class)); - cards.add(new SetCardInfo("Righteous Fury", 30, Rarity.RARE, mage.cards.r.RighteousFury.class)); - cards.add(new SetCardInfo("Ritual of Subdual", 174, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); - cards.add(new SetCardInfo("Ritual of the Machine", 109, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); - cards.add(new SetCardInfo("Roterothopter", 218, Rarity.COMMON, mage.cards.r.Roterothopter.class)); - cards.add(new SetCardInfo("Royal Decree", 31, Rarity.RARE, mage.cards.r.RoyalDecree.class)); - cards.add(new SetCardInfo("Royal Trooper", 32, Rarity.COMMON, mage.cards.r.RoyalTrooper.class)); - cards.add(new SetCardInfo("Ruins of Trokair", 234, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); - cards.add(new SetCardInfo("Savannah", 235, Rarity.RARE, mage.cards.s.Savannah.class)); - cards.add(new SetCardInfo("Screeching Drake", 63, Rarity.COMMON, mage.cards.s.ScreechingDrake.class)); - cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class)); - cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); - cards.add(new SetCardInfo("Shield Bearer", 35, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); - cards.add(new SetCardInfo("Shrink", 175, Rarity.COMMON, mage.cards.s.Shrink.class)); - cards.add(new SetCardInfo("Shyft", 66, Rarity.COMMON, mage.cards.s.Shyft.class)); - cards.add(new SetCardInfo("Sibilant Spirit", 67, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); - cards.add(new SetCardInfo("Skeleton Ship", 197, Rarity.RARE, mage.cards.s.SkeletonShip.class)); - cards.add(new SetCardInfo("Skull Catapult", 219, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); - cards.add(new SetCardInfo("Snow Fortress", 220, Rarity.UNCOMMON, mage.cards.s.SnowFortress.class)); - cards.add(new SetCardInfo("Snow-Covered Forest", 245, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); - cards.add(new SetCardInfo("Snow-Covered Island", 242, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); - cards.add(new SetCardInfo("Snow-Covered Mountain", 244, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); - cards.add(new SetCardInfo("Snow-Covered Plains", 241, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); - cards.add(new SetCardInfo("Snow-Covered Swamp", 243, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); - cards.add(new SetCardInfo("Soldevi Digger", 221, Rarity.UNCOMMON, mage.cards.s.SoldeviDigger.class)); - cards.add(new SetCardInfo("Soldevi Excavations", 236, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); - cards.add(new SetCardInfo("Soldevi Simulacrum", 222, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); - cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); - cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); - cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); - cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class)); - cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); - cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); - cards.add(new SetCardInfo("Stone Spirit", 150, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); - cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); - cards.add(new SetCardInfo("Storm Spirit", 198, Rarity.RARE, mage.cards.s.StormSpirit.class)); - cards.add(new SetCardInfo("Stromgald Cabal", 113, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); - cards.add(new SetCardInfo("Stunted Growth", 179, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); - cards.add(new SetCardInfo("Sustaining Spirit", 36, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); - cards.add(new SetCardInfo("Svyelunite Temple", 237, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); - cards.add(new SetCardInfo("Swords to Plowshares", 37, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Taiga", 238, Rarity.RARE, mage.cards.t.Taiga.class)); - cards.add(new SetCardInfo("Temporal Manipulation", 69, Rarity.RARE, mage.cards.t.TemporalManipulation.class)); - cards.add(new SetCardInfo("Thallid Devourer", 181, Rarity.COMMON, mage.cards.t.ThallidDevourer.class)); - cards.add(new SetCardInfo("Thallid", 180, Rarity.COMMON, mage.cards.t.Thallid.class)); - cards.add(new SetCardInfo("Thelonite Druid", 182, Rarity.RARE, mage.cards.t.TheloniteDruid.class)); - cards.add(new SetCardInfo("Thermokarst", 183, Rarity.COMMON, mage.cards.t.Thermokarst.class)); - cards.add(new SetCardInfo("Thought Lash", 70, Rarity.RARE, mage.cards.t.ThoughtLash.class)); - cards.add(new SetCardInfo("Thunder Wall", 71, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); - cards.add(new SetCardInfo("Time Bomb", 223, Rarity.RARE, mage.cards.t.TimeBomb.class)); - cards.add(new SetCardInfo("Tinder Wall", 184, Rarity.COMMON, mage.cards.t.TinderWall.class)); - cards.add(new SetCardInfo("Tundra", 239, Rarity.RARE, mage.cards.t.Tundra.class)); - cards.add(new SetCardInfo("Underground Sea", 240, Rarity.RARE, mage.cards.u.UndergroundSea.class)); - cards.add(new SetCardInfo("Varchild's Crusader", 152, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class)); - cards.add(new SetCardInfo("Viscerid Armor", 72, Rarity.COMMON, mage.cards.v.VisceridArmor.class)); - cards.add(new SetCardInfo("Viscerid Drone", 73, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); - cards.add(new SetCardInfo("Wall of Kelp", 74, Rarity.COMMON, mage.cards.w.WallOfKelp.class)); - cards.add(new SetCardInfo("Warning", 38, Rarity.COMMON, mage.cards.w.Warning.class)); - cards.add(new SetCardInfo("Whirling Catapult", 224, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); - cards.add(new SetCardInfo("Whiteout", 185, Rarity.COMMON, mage.cards.w.Whiteout.class)); - cards.add(new SetCardInfo("Wind Spirit", 75, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); - cards.add(new SetCardInfo("Wings of Aesthir", 199, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); - cards.add(new SetCardInfo("Winter's Night", 200, Rarity.RARE, mage.cards.w.WintersNight.class)); - cards.add(new SetCardInfo("Withering Wisps", 114, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); - cards.add(new SetCardInfo("Wolf Pack", 187, Rarity.RARE, mage.cards.w.WolfPack.class)); - cards.add(new SetCardInfo("Woolly Mammoths", 188, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); - cards.add(new SetCardInfo("Woolly Spider", 189, Rarity.UNCOMMON, mage.cards.w.WoollySpider.class)); - cards.add(new SetCardInfo("Yavimaya Ancients", 190, Rarity.UNCOMMON, mage.cards.y.YavimayaAncients.class)); - cards.add(new SetCardInfo("Zuran Spellcaster", 76, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author LevelX2 + */ +public final class MastersEditionII extends ExpansionSet { + + private static final MastersEditionII instance = new MastersEditionII(); + + public static MastersEditionII getInstance() { + return instance; + } + + private MastersEditionII() { + super("Masters Edition II", "ME2", ExpansionSet.buildDate(2008, 9, 22), SetType.MAGIC_ONLINE); + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abbey Gargoyles", 1, Rarity.UNCOMMON, mage.cards.a.AbbeyGargoyles.class)); + cards.add(new SetCardInfo("Adarkar Sentinel", 201, Rarity.COMMON, mage.cards.a.AdarkarSentinel.class)); + cards.add(new SetCardInfo("Aeolipile", 202, Rarity.COMMON, mage.cards.a.Aeolipile.class)); + cards.add(new SetCardInfo("Aether Storm", 39, Rarity.UNCOMMON, mage.cards.a.AetherStorm.class)); + cards.add(new SetCardInfo("Ambush Party", 115, Rarity.COMMON, mage.cards.a.AmbushParty.class)); + cards.add(new SetCardInfo("An-Zerrin Ruins", 117, Rarity.RARE, mage.cards.a.AnZerrinRuins.class)); + cards.add(new SetCardInfo("Anarchy", 116, Rarity.RARE, mage.cards.a.Anarchy.class)); + cards.add(new SetCardInfo("Angel of Fury", 2, Rarity.RARE, mage.cards.a.AngelOfFury.class)); + cards.add(new SetCardInfo("Angel of Light", 3, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); + cards.add(new SetCardInfo("Armor of Faith", 4, Rarity.COMMON, mage.cards.a.ArmorOfFaith.class)); + cards.add(new SetCardInfo("Armor Thrull", 77, Rarity.COMMON, mage.cards.a.ArmorThrull.class)); + cards.add(new SetCardInfo("Armored Griffin", 5, Rarity.COMMON, mage.cards.a.ArmoredGriffin.class)); + cards.add(new SetCardInfo("Ashen Ghoul", 78, Rarity.UNCOMMON, mage.cards.a.AshenGhoul.class)); + cards.add(new SetCardInfo("Ashnod's Cylix", 203, Rarity.RARE, mage.cards.a.AshnodsCylix.class)); + cards.add(new SetCardInfo("Aurochs", 153, Rarity.COMMON, mage.cards.a.Aurochs.class)); + cards.add(new SetCardInfo("Aysen Bureaucrats", 6, Rarity.COMMON, mage.cards.a.AysenBureaucrats.class)); + cards.add(new SetCardInfo("Aysen Crusader", 7, Rarity.UNCOMMON, mage.cards.a.AysenCrusader.class)); + cards.add(new SetCardInfo("Badlands", 225, Rarity.RARE, mage.cards.b.Badlands.class)); + cards.add(new SetCardInfo("Balduvian Conjurer", 40, Rarity.COMMON, mage.cards.b.BalduvianConjurer.class)); + cards.add(new SetCardInfo("Balduvian Dead", 79, Rarity.UNCOMMON, mage.cards.b.BalduvianDead.class)); + cards.add(new SetCardInfo("Balduvian Hydra", 118, Rarity.RARE, mage.cards.b.BalduvianHydra.class)); + cards.add(new SetCardInfo("Balduvian Trading Post", 226, Rarity.RARE, mage.cards.b.BalduvianTradingPost.class)); + cards.add(new SetCardInfo("Barbed Sextant", 204, Rarity.COMMON, mage.cards.b.BarbedSextant.class)); + cards.add(new SetCardInfo("Binding Grasp", 41, Rarity.RARE, mage.cards.b.BindingGrasp.class)); + cards.add(new SetCardInfo("Bounty of the Hunt", 154, Rarity.RARE, mage.cards.b.BountyOfTheHunt.class)); + cards.add(new SetCardInfo("Brainstorm", 42, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brassclaw Orcs", 119, Rarity.COMMON, mage.cards.b.BrassclawOrcs.class)); + cards.add(new SetCardInfo("Brimstone Dragon", 120, Rarity.RARE, mage.cards.b.BrimstoneDragon.class)); + cards.add(new SetCardInfo("Brine Shaman", 80, Rarity.COMMON, mage.cards.b.BrineShaman.class)); + cards.add(new SetCardInfo("Broken Visage", 81, Rarity.UNCOMMON, mage.cards.b.BrokenVisage.class)); + cards.add(new SetCardInfo("Browse", 43, Rarity.UNCOMMON, mage.cards.b.Browse.class)); + cards.add(new SetCardInfo("Burnout", 121, Rarity.UNCOMMON, mage.cards.b.Burnout.class)); + cards.add(new SetCardInfo("Carapace", 155, Rarity.COMMON, mage.cards.c.Carapace.class)); + cards.add(new SetCardInfo("Caribou Range", 8, Rarity.RARE, mage.cards.c.CaribouRange.class)); + cards.add(new SetCardInfo("Cloak of Confusion", 82, Rarity.COMMON, mage.cards.c.CloakOfConfusion.class)); + cards.add(new SetCardInfo("Clockwork Steed", 205, Rarity.UNCOMMON, mage.cards.c.ClockworkSteed.class)); + cards.add(new SetCardInfo("Combat Medic", 9, Rarity.COMMON, mage.cards.c.CombatMedic.class)); + cards.add(new SetCardInfo("Conquer", 122, Rarity.UNCOMMON, mage.cards.c.Conquer.class)); + cards.add(new SetCardInfo("Counterspell", 44, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Dance of the Dead", 83, Rarity.UNCOMMON, mage.cards.d.DanceOfTheDead.class)); + cards.add(new SetCardInfo("Dark Banishing", 84, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Death Spark", 123, Rarity.COMMON, mage.cards.d.DeathSpark.class)); + cards.add(new SetCardInfo("Deep Spawn", 45, Rarity.RARE, mage.cards.d.DeepSpawn.class)); + cards.add(new SetCardInfo("Demonic Consultation", 85, Rarity.UNCOMMON, mage.cards.d.DemonicConsultation.class)); + cards.add(new SetCardInfo("Despotic Scepter", 206, Rarity.RARE, mage.cards.d.DespoticScepter.class)); + cards.add(new SetCardInfo("Diabolic Vision", 191, Rarity.UNCOMMON, mage.cards.d.DiabolicVision.class)); + cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dreams of the Dead", 46, Rarity.RARE, mage.cards.d.DreamsOfTheDead.class)); + cards.add(new SetCardInfo("Drift of the Dead", 86, Rarity.COMMON, mage.cards.d.DriftOfTheDead.class)); + cards.add(new SetCardInfo("Dry Spell", 87, Rarity.COMMON, mage.cards.d.DrySpell.class)); + cards.add(new SetCardInfo("Dwarven Ruins", 227, Rarity.UNCOMMON, mage.cards.d.DwarvenRuins.class)); + cards.add(new SetCardInfo("Dystopia", 88, Rarity.RARE, mage.cards.d.Dystopia.class)); + cards.add(new SetCardInfo("Earthlink", 192, Rarity.RARE, mage.cards.e.Earthlink.class)); + cards.add(new SetCardInfo("Ebon Praetor", 89, Rarity.RARE, mage.cards.e.EbonPraetor.class)); + cards.add(new SetCardInfo("Ebon Stronghold", 228, Rarity.UNCOMMON, mage.cards.e.EbonStronghold.class)); + cards.add(new SetCardInfo("Elemental Augury", 193, Rarity.RARE, mage.cards.e.ElementalAugury.class)); + cards.add(new SetCardInfo("Elkin Bottle", 207, Rarity.RARE, mage.cards.e.ElkinBottle.class)); + cards.add(new SetCardInfo("Elven Lyre", 208, Rarity.COMMON, mage.cards.e.ElvenLyre.class)); + cards.add(new SetCardInfo("Elvish Farmer", 156, Rarity.RARE, mage.cards.e.ElvishFarmer.class)); + cards.add(new SetCardInfo("Elvish Hunter", 157, Rarity.COMMON, mage.cards.e.ElvishHunter.class)); + cards.add(new SetCardInfo("Elvish Ranger", 158, Rarity.COMMON, mage.cards.e.ElvishRanger.class)); + cards.add(new SetCardInfo("Elvish Spirit Guide", 159, Rarity.UNCOMMON, mage.cards.e.ElvishSpiritGuide.class)); + cards.add(new SetCardInfo("Energy Storm", 11, Rarity.RARE, mage.cards.e.EnergyStorm.class)); + cards.add(new SetCardInfo("Enervate", 47, Rarity.COMMON, mage.cards.e.Enervate.class)); + cards.add(new SetCardInfo("Errand of Duty", 12, Rarity.UNCOMMON, mage.cards.e.ErrandOfDuty.class)); + cards.add(new SetCardInfo("Errantry", 124, Rarity.COMMON, mage.cards.e.Errantry.class)); + cards.add(new SetCardInfo("Essence Filter", 160, Rarity.UNCOMMON, mage.cards.e.EssenceFilter.class)); + cards.add(new SetCardInfo("Essence Flare", 48, Rarity.COMMON, mage.cards.e.EssenceFlare.class)); + cards.add(new SetCardInfo("Farrel's Mantle", 13, Rarity.UNCOMMON, mage.cards.f.FarrelsMantle.class)); + cards.add(new SetCardInfo("Farrel's Zealot", 14, Rarity.UNCOMMON, mage.cards.f.FarrelsZealot.class)); + cards.add(new SetCardInfo("Feral Thallid", 161, Rarity.COMMON, mage.cards.f.FeralThallid.class)); + cards.add(new SetCardInfo("Fire Dragon", 125, Rarity.RARE, mage.cards.f.FireDragon.class)); + cards.add(new SetCardInfo("Flame Spirit", 126, Rarity.UNCOMMON, mage.cards.f.FlameSpirit.class)); + cards.add(new SetCardInfo("Folk of the Pines", 162, Rarity.COMMON, mage.cards.f.FolkOfThePines.class)); + cards.add(new SetCardInfo("Forbidden Lore", 163, Rarity.UNCOMMON, mage.cards.f.ForbiddenLore.class)); + cards.add(new SetCardInfo("Forgotten Lore", 164, Rarity.UNCOMMON, mage.cards.f.ForgottenLore.class)); + cards.add(new SetCardInfo("Foul Familiar", 90, Rarity.COMMON, mage.cards.f.FoulFamiliar.class)); + cards.add(new SetCardInfo("Fumarole", 194, Rarity.UNCOMMON, mage.cards.f.Fumarole.class)); + cards.add(new SetCardInfo("Funeral March", 91, Rarity.COMMON, mage.cards.f.FuneralMarch.class)); + cards.add(new SetCardInfo("Fungal Bloom", 165, Rarity.RARE, mage.cards.f.FungalBloom.class)); + cards.add(new SetCardInfo("Fyndhorn Pollen", 166, Rarity.RARE, mage.cards.f.FyndhornPollen.class)); + cards.add(new SetCardInfo("Gangrenous Zombies", 92, Rarity.COMMON, mage.cards.g.GangrenousZombies.class)); + cards.add(new SetCardInfo("Giant Growth", 167, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Trap Door Spider", 195, Rarity.UNCOMMON, mage.cards.g.GiantTrapDoorSpider.class)); + cards.add(new SetCardInfo("Glacial Chasm", 229, Rarity.RARE, mage.cards.g.GlacialChasm.class)); + cards.add(new SetCardInfo("Glacial Crevasses", 127, Rarity.RARE, mage.cards.g.GlacialCrevasses.class)); + cards.add(new SetCardInfo("Gorilla Shaman", 129, Rarity.UNCOMMON, mage.cards.g.GorillaShaman.class)); + cards.add(new SetCardInfo("Grandmother Sengir", 93, Rarity.RARE, mage.cards.g.GrandmotherSengir.class)); + cards.add(new SetCardInfo("Havenwood Battleground", 230, Rarity.UNCOMMON, mage.cards.h.HavenwoodBattleground.class)); + cards.add(new SetCardInfo("Heart of Yavimaya", 231, Rarity.RARE, mage.cards.h.HeartOfYavimaya.class)); + cards.add(new SetCardInfo("Helm of Obedience", 210, Rarity.RARE, mage.cards.h.HelmOfObedience.class)); + cards.add(new SetCardInfo("Icatian Javelineers", 15, Rarity.COMMON, mage.cards.i.IcatianJavelineers.class)); + cards.add(new SetCardInfo("Icatian Phalanx", 16, Rarity.COMMON, mage.cards.i.IcatianPhalanx.class)); + cards.add(new SetCardInfo("Icatian Scout", 17, Rarity.COMMON, mage.cards.i.IcatianScout.class)); + cards.add(new SetCardInfo("Ice Floe", 232, Rarity.UNCOMMON, mage.cards.i.IceFloe.class)); + cards.add(new SetCardInfo("Iceberg", 49, Rarity.UNCOMMON, mage.cards.i.Iceberg.class)); + cards.add(new SetCardInfo("Icequake", 94, Rarity.COMMON, mage.cards.i.Icequake.class)); + cards.add(new SetCardInfo("Icy Prison", 50, Rarity.COMMON, mage.cards.i.IcyPrison.class)); + cards.add(new SetCardInfo("Ihsan's Shade", 95, Rarity.RARE, mage.cards.i.IhsansShade.class)); + cards.add(new SetCardInfo("Imperial Recruiter", 130, Rarity.RARE, mage.cards.i.ImperialRecruiter.class)); + cards.add(new SetCardInfo("Imperial Seal", 96, Rarity.RARE, mage.cards.i.ImperialSeal.class)); + cards.add(new SetCardInfo("Incinerate", 131, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Infernal Darkness", 97, Rarity.RARE, mage.cards.i.InfernalDarkness.class)); + cards.add(new SetCardInfo("Inheritance", 18, Rarity.UNCOMMON, mage.cards.i.Inheritance.class)); + cards.add(new SetCardInfo("Ironclaw Orcs", 132, Rarity.COMMON, mage.cards.i.IronclawOrcs.class)); + cards.add(new SetCardInfo("Ivory Gargoyle", 19, Rarity.RARE, mage.cards.i.IvoryGargoyle.class)); + cards.add(new SetCardInfo("Jester's Mask", 211, Rarity.RARE, mage.cards.j.JestersMask.class)); + cards.add(new SetCardInfo("Jeweled Amulet", 212, Rarity.UNCOMMON, mage.cards.j.JeweledAmulet.class)); + cards.add(new SetCardInfo("Johtull Wurm", 168, Rarity.UNCOMMON, mage.cards.j.JohtullWurm.class)); + cards.add(new SetCardInfo("Joven's Ferrets", 169, Rarity.UNCOMMON, mage.cards.j.JovensFerrets.class)); + cards.add(new SetCardInfo("Juniper Order Advocate", 20, Rarity.UNCOMMON, mage.cards.j.JuniperOrderAdvocate.class)); + cards.add(new SetCardInfo("Karplusan Giant", 133, Rarity.UNCOMMON, mage.cards.k.KarplusanGiant.class)); + cards.add(new SetCardInfo("Kaysa", 170, Rarity.RARE, mage.cards.k.Kaysa.class)); + cards.add(new SetCardInfo("Kjeldoran Dead", 98, Rarity.COMMON, mage.cards.k.KjeldoranDead.class)); + cards.add(new SetCardInfo("Kjeldoran Home Guard", 22, Rarity.UNCOMMON, mage.cards.k.KjeldoranHomeGuard.class)); + cards.add(new SetCardInfo("Kjeldoran Outpost", 233, Rarity.RARE, mage.cards.k.KjeldoranOutpost.class)); + cards.add(new SetCardInfo("Kjeldoran Skycaptain", 23, Rarity.COMMON, mage.cards.k.KjeldoranSkycaptain.class)); + cards.add(new SetCardInfo("Knight of Stromgald", 99, Rarity.UNCOMMON, mage.cards.k.KnightOfStromgald.class)); + cards.add(new SetCardInfo("Krovikan Fetish", 100, Rarity.COMMON, mage.cards.k.KrovikanFetish.class)); + cards.add(new SetCardInfo("Krovikan Horror", 101, Rarity.RARE, mage.cards.k.KrovikanHorror.class)); + cards.add(new SetCardInfo("Krovikan Sorcerer", 51, Rarity.COMMON, mage.cards.k.KrovikanSorcerer.class)); + cards.add(new SetCardInfo("Krovikan Vampire", 102, Rarity.UNCOMMON, mage.cards.k.KrovikanVampire.class)); + cards.add(new SetCardInfo("Lat-Nam's Legacy", 52, Rarity.COMMON, mage.cards.l.LatNamsLegacy.class)); + cards.add(new SetCardInfo("Leaping Lizard", 171, Rarity.COMMON, mage.cards.l.LeapingLizard.class)); + cards.add(new SetCardInfo("Lim-Dul's High Guard", 103, Rarity.UNCOMMON, mage.cards.l.LimDulsHighGuard.class)); + cards.add(new SetCardInfo("Lodestone Bauble", 213, Rarity.RARE, mage.cards.l.LodestoneBauble.class)); + cards.add(new SetCardInfo("Lost Order of Jarkeld", 24, Rarity.RARE, mage.cards.l.LostOrderOfJarkeld.class)); + cards.add(new SetCardInfo("Magus of the Unseen", 53, Rarity.RARE, mage.cards.m.MagusOfTheUnseen.class)); + cards.add(new SetCardInfo("Mana Crypt", 214, Rarity.RARE, mage.cards.m.ManaCrypt.class)); + cards.add(new SetCardInfo("Marjhan", 54, Rarity.RARE, mage.cards.m.Marjhan.class)); + cards.add(new SetCardInfo("Mesmeric Trance", 55, Rarity.RARE, mage.cards.m.MesmericTrance.class)); + cards.add(new SetCardInfo("Meteor Shower", 135, Rarity.COMMON, mage.cards.m.MeteorShower.class)); + cards.add(new SetCardInfo("Minion of Leshrac", 104, Rarity.RARE, mage.cards.m.MinionOfLeshrac.class)); + cards.add(new SetCardInfo("Mishra's Groundbreaker", 215, Rarity.UNCOMMON, mage.cards.m.MishrasGroundbreaker.class)); + cards.add(new SetCardInfo("Misinformation", 105, Rarity.UNCOMMON, mage.cards.m.Misinformation.class)); + cards.add(new SetCardInfo("Mudslide", 136, Rarity.RARE, mage.cards.m.Mudslide.class)); + cards.add(new SetCardInfo("Musician", 56, Rarity.RARE, mage.cards.m.Musician.class)); + cards.add(new SetCardInfo("Narwhal", 57, Rarity.UNCOMMON, mage.cards.n.Narwhal.class)); + cards.add(new SetCardInfo("Nature's Blessing", 196, Rarity.UNCOMMON, mage.cards.n.NaturesBlessing.class)); + cards.add(new SetCardInfo("Nature's Wrath", 172, Rarity.RARE, mage.cards.n.NaturesWrath.class)); + cards.add(new SetCardInfo("Necrite", 106, Rarity.COMMON, mage.cards.n.Necrite.class)); + cards.add(new SetCardInfo("Necropotence", 107, Rarity.RARE, mage.cards.n.Necropotence.class)); + cards.add(new SetCardInfo("Night Soil", 173, Rarity.UNCOMMON, mage.cards.n.NightSoil.class)); + cards.add(new SetCardInfo("Orc General", 137, Rarity.UNCOMMON, mage.cards.o.OrcGeneral.class)); + cards.add(new SetCardInfo("Orcish Cannoneers", 138, Rarity.UNCOMMON, mage.cards.o.OrcishCannoneers.class)); + cards.add(new SetCardInfo("Orcish Captain", 139, Rarity.UNCOMMON, mage.cards.o.OrcishCaptain.class)); + cards.add(new SetCardInfo("Orcish Lumberjack", 142, Rarity.COMMON, mage.cards.o.OrcishLumberjack.class)); + cards.add(new SetCardInfo("Orcish Squatters", 143, Rarity.RARE, mage.cards.o.OrcishSquatters.class)); + cards.add(new SetCardInfo("Orcish Veteran", 144, Rarity.COMMON, mage.cards.o.OrcishVeteran.class)); + cards.add(new SetCardInfo("Order of the Sacred Torch", 25, Rarity.RARE, mage.cards.o.OrderOfTheSacredTorch.class)); + cards.add(new SetCardInfo("Order of the White Shield", 26, Rarity.UNCOMMON, mage.cards.o.OrderOfTheWhiteShield.class)); + cards.add(new SetCardInfo("Panic", 145, Rarity.COMMON, mage.cards.p.Panic.class)); + cards.add(new SetCardInfo("Personal Tutor", 58, Rarity.UNCOMMON, mage.cards.p.PersonalTutor.class)); + cards.add(new SetCardInfo("Phantasmal Fiend", 108, Rarity.COMMON, mage.cards.p.PhantasmalFiend.class)); + cards.add(new SetCardInfo("Phantasmal Mount", 59, Rarity.COMMON, mage.cards.p.PhantasmalMount.class)); + cards.add(new SetCardInfo("Phyrexian Devourer", 216, Rarity.UNCOMMON, mage.cards.p.PhyrexianDevourer.class)); + cards.add(new SetCardInfo("Pillage", 146, Rarity.UNCOMMON, mage.cards.p.Pillage.class)); + cards.add(new SetCardInfo("Portent", 60, Rarity.COMMON, mage.cards.p.Portent.class)); + cards.add(new SetCardInfo("Pyrokinesis", 147, Rarity.RARE, mage.cards.p.Pyrokinesis.class)); + cards.add(new SetCardInfo("Ravages of War", 27, Rarity.RARE, mage.cards.r.RavagesOfWar.class)); + cards.add(new SetCardInfo("Ray of Command", 61, Rarity.UNCOMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Red Cliffs Armada", 62, Rarity.COMMON, mage.cards.r.RedCliffsArmada.class)); + cards.add(new SetCardInfo("Reinforcements", 28, Rarity.COMMON, mage.cards.r.Reinforcements.class)); + cards.add(new SetCardInfo("Reprisal", 29, Rarity.COMMON, mage.cards.r.Reprisal.class)); + cards.add(new SetCardInfo("Retribution", 148, Rarity.UNCOMMON, mage.cards.r.Retribution.class)); + cards.add(new SetCardInfo("Righteous Fury", 30, Rarity.RARE, mage.cards.r.RighteousFury.class)); + cards.add(new SetCardInfo("Ritual of Subdual", 174, Rarity.RARE, mage.cards.r.RitualOfSubdual.class)); + cards.add(new SetCardInfo("Ritual of the Machine", 109, Rarity.RARE, mage.cards.r.RitualOfTheMachine.class)); + cards.add(new SetCardInfo("Roterothopter", 218, Rarity.COMMON, mage.cards.r.Roterothopter.class)); + cards.add(new SetCardInfo("Rogue Skycaptain", 149, Rarity.RARE, mage.cards.r.RogueSkycaptain.class)); + cards.add(new SetCardInfo("Royal Decree", 31, Rarity.RARE, mage.cards.r.RoyalDecree.class)); + cards.add(new SetCardInfo("Royal Trooper", 32, Rarity.COMMON, mage.cards.r.RoyalTrooper.class)); + cards.add(new SetCardInfo("Ruins of Trokair", 234, Rarity.UNCOMMON, mage.cards.r.RuinsOfTrokair.class)); + cards.add(new SetCardInfo("Savannah", 235, Rarity.RARE, mage.cards.s.Savannah.class)); + cards.add(new SetCardInfo("Screeching Drake", 63, Rarity.COMMON, mage.cards.s.ScreechingDrake.class)); + cards.add(new SetCardInfo("Sea Drake", 64, Rarity.RARE, mage.cards.s.SeaDrake.class)); + cards.add(new SetCardInfo("Sea Spirit", 65, Rarity.UNCOMMON, mage.cards.s.SeaSpirit.class)); + cards.add(new SetCardInfo("Shield Bearer", 35, Rarity.COMMON, mage.cards.s.ShieldBearer.class)); + cards.add(new SetCardInfo("Shrink", 175, Rarity.COMMON, mage.cards.s.Shrink.class)); + cards.add(new SetCardInfo("Shyft", 66, Rarity.COMMON, mage.cards.s.Shyft.class)); + cards.add(new SetCardInfo("Sibilant Spirit", 67, Rarity.RARE, mage.cards.s.SibilantSpirit.class)); + cards.add(new SetCardInfo("Skeleton Ship", 197, Rarity.RARE, mage.cards.s.SkeletonShip.class)); + cards.add(new SetCardInfo("Skull Catapult", 219, Rarity.UNCOMMON, mage.cards.s.SkullCatapult.class)); + cards.add(new SetCardInfo("Snow Fortress", 220, Rarity.UNCOMMON, mage.cards.s.SnowFortress.class)); + cards.add(new SetCardInfo("Snow-Covered Forest", 245, Rarity.LAND, mage.cards.s.SnowCoveredForest.class)); + cards.add(new SetCardInfo("Snow-Covered Island", 242, Rarity.LAND, mage.cards.s.SnowCoveredIsland.class)); + cards.add(new SetCardInfo("Snow-Covered Mountain", 244, Rarity.LAND, mage.cards.s.SnowCoveredMountain.class)); + cards.add(new SetCardInfo("Snow-Covered Plains", 241, Rarity.LAND, mage.cards.s.SnowCoveredPlains.class)); + cards.add(new SetCardInfo("Snow-Covered Swamp", 243, Rarity.LAND, mage.cards.s.SnowCoveredSwamp.class)); + cards.add(new SetCardInfo("Soldevi Digger", 221, Rarity.UNCOMMON, mage.cards.s.SoldeviDigger.class)); + cards.add(new SetCardInfo("Soldevi Excavations", 236, Rarity.RARE, mage.cards.s.SoldeviExcavations.class)); + cards.add(new SetCardInfo("Soldevi Simulacrum", 222, Rarity.UNCOMMON, mage.cards.s.SoldeviSimulacrum.class)); + cards.add(new SetCardInfo("Songs of the Damned", 110, Rarity.COMMON, mage.cards.s.SongsOfTheDamned.class)); + cards.add(new SetCardInfo("Soul Exchange", 111, Rarity.UNCOMMON, mage.cards.s.SoulExchange.class)); + cards.add(new SetCardInfo("Soul Kiss", 112, Rarity.UNCOMMON, mage.cards.s.SoulKiss.class)); + cards.add(new SetCardInfo("Spore Cloud", 176, Rarity.UNCOMMON, mage.cards.s.SporeCloud.class)); + cards.add(new SetCardInfo("Spore Flower", 177, Rarity.UNCOMMON, mage.cards.s.SporeFlower.class)); + cards.add(new SetCardInfo("Stampede", 178, Rarity.UNCOMMON, mage.cards.s.Stampede.class)); + cards.add(new SetCardInfo("Stone Spirit", 150, Rarity.UNCOMMON, mage.cards.s.StoneSpirit.class)); + cards.add(new SetCardInfo("Stonehands", 151, Rarity.COMMON, mage.cards.s.Stonehands.class)); + cards.add(new SetCardInfo("Storm Spirit", 198, Rarity.RARE, mage.cards.s.StormSpirit.class)); + cards.add(new SetCardInfo("Stromgald Cabal", 113, Rarity.RARE, mage.cards.s.StromgaldCabal.class)); + cards.add(new SetCardInfo("Stunted Growth", 179, Rarity.RARE, mage.cards.s.StuntedGrowth.class)); + cards.add(new SetCardInfo("Sustaining Spirit", 36, Rarity.RARE, mage.cards.s.SustainingSpirit.class)); + cards.add(new SetCardInfo("Svyelunite Temple", 237, Rarity.UNCOMMON, mage.cards.s.SvyeluniteTemple.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 37, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Taiga", 238, Rarity.RARE, mage.cards.t.Taiga.class)); + cards.add(new SetCardInfo("Temporal Manipulation", 69, Rarity.RARE, mage.cards.t.TemporalManipulation.class)); + cards.add(new SetCardInfo("Thallid Devourer", 181, Rarity.COMMON, mage.cards.t.ThallidDevourer.class)); + cards.add(new SetCardInfo("Thallid", 180, Rarity.COMMON, mage.cards.t.Thallid.class)); + cards.add(new SetCardInfo("Thelonite Druid", 182, Rarity.RARE, mage.cards.t.TheloniteDruid.class)); + cards.add(new SetCardInfo("Thermokarst", 183, Rarity.COMMON, mage.cards.t.Thermokarst.class)); + cards.add(new SetCardInfo("Thought Lash", 70, Rarity.RARE, mage.cards.t.ThoughtLash.class)); + cards.add(new SetCardInfo("Thunder Wall", 71, Rarity.UNCOMMON, mage.cards.t.ThunderWall.class)); + cards.add(new SetCardInfo("Time Bomb", 223, Rarity.RARE, mage.cards.t.TimeBomb.class)); + cards.add(new SetCardInfo("Tinder Wall", 184, Rarity.COMMON, mage.cards.t.TinderWall.class)); + cards.add(new SetCardInfo("Tundra", 239, Rarity.RARE, mage.cards.t.Tundra.class)); + cards.add(new SetCardInfo("Underground Sea", 240, Rarity.RARE, mage.cards.u.UndergroundSea.class)); + cards.add(new SetCardInfo("Varchild's Crusader", 152, Rarity.COMMON, mage.cards.v.VarchildsCrusader.class)); + cards.add(new SetCardInfo("Viscerid Armor", 72, Rarity.COMMON, mage.cards.v.VisceridArmor.class)); + cards.add(new SetCardInfo("Viscerid Drone", 73, Rarity.UNCOMMON, mage.cards.v.VisceridDrone.class)); + cards.add(new SetCardInfo("Wall of Kelp", 74, Rarity.COMMON, mage.cards.w.WallOfKelp.class)); + cards.add(new SetCardInfo("Warning", 38, Rarity.COMMON, mage.cards.w.Warning.class)); + cards.add(new SetCardInfo("Whirling Catapult", 224, Rarity.UNCOMMON, mage.cards.w.WhirlingCatapult.class)); + cards.add(new SetCardInfo("Whiteout", 185, Rarity.COMMON, mage.cards.w.Whiteout.class)); + cards.add(new SetCardInfo("Wiitigo", 186, Rarity.RARE, mage.cards.w.Wiitigo.class)); + cards.add(new SetCardInfo("Wind Spirit", 75, Rarity.UNCOMMON, mage.cards.w.WindSpirit.class)); + cards.add(new SetCardInfo("Wings of Aesthir", 199, Rarity.UNCOMMON, mage.cards.w.WingsOfAesthir.class)); + cards.add(new SetCardInfo("Winter's Night", 200, Rarity.RARE, mage.cards.w.WintersNight.class)); + cards.add(new SetCardInfo("Withering Wisps", 114, Rarity.UNCOMMON, mage.cards.w.WitheringWisps.class)); + cards.add(new SetCardInfo("Wolf Pack", 187, Rarity.RARE, mage.cards.w.WolfPack.class)); + cards.add(new SetCardInfo("Woolly Mammoths", 188, Rarity.COMMON, mage.cards.w.WoollyMammoths.class)); + cards.add(new SetCardInfo("Woolly Spider", 189, Rarity.UNCOMMON, mage.cards.w.WoollySpider.class)); + cards.add(new SetCardInfo("Yavimaya Ancients", 190, Rarity.UNCOMMON, mage.cards.y.YavimayaAncients.class)); + cards.add(new SetCardInfo("Zuran Spellcaster", 76, Rarity.COMMON, mage.cards.z.ZuranSpellcaster.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/MastersEditionIII.java b/Mage.Sets/src/mage/sets/MastersEditionIII.java index 779517679c..20f24d901e 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIII.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIII.java @@ -1,249 +1,250 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author LevelX2 - */ -public final class MastersEditionIII extends ExpansionSet { - - private static final MastersEditionIII instance = new MastersEditionIII(); - - public static MastersEditionIII getInstance() { - return instance; - } - - private MastersEditionIII() { - super("Masters Edition III", "ME3", ExpansionSet.buildDate(2009, 9, 7), SetType.MAGIC_ONLINE); - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Active Volcano", 85, Rarity.UNCOMMON, mage.cards.a.ActiveVolcano.class)); - cards.add(new SetCardInfo("Akron Legionnaire", 1, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); - cards.add(new SetCardInfo("Alabaster Potion", 2, Rarity.UNCOMMON, mage.cards.a.AlabasterPotion.class)); - cards.add(new SetCardInfo("All Hallow's Eve", 57, Rarity.RARE, mage.cards.a.AllHallowsEve.class)); - cards.add(new SetCardInfo("Amrou Kithkin", 3, Rarity.COMMON, mage.cards.a.AmrouKithkin.class)); - cards.add(new SetCardInfo("Anaba Ancestor", 86, Rarity.COMMON, mage.cards.a.AnabaAncestor.class)); - cards.add(new SetCardInfo("Anaba Spirit Crafter", 87, Rarity.COMMON, mage.cards.a.AnabaSpiritCrafter.class)); - cards.add(new SetCardInfo("Angus Mackenzie", 141, Rarity.RARE, mage.cards.a.AngusMackenzie.class)); - cards.add(new SetCardInfo("Arboria", 113, Rarity.RARE, mage.cards.a.Arboria.class)); - cards.add(new SetCardInfo("Arcades Sabboth", 142, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); - cards.add(new SetCardInfo("Arena of the Ancients", 188, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); - cards.add(new SetCardInfo("Ashes to Ashes", 58, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); - cards.add(new SetCardInfo("Astrolabe", 189, Rarity.COMMON, mage.cards.a.Astrolabe.class)); - cards.add(new SetCardInfo("Axelrod Gunnarson", 143, Rarity.UNCOMMON, mage.cards.a.AxelrodGunnarson.class)); - cards.add(new SetCardInfo("Banshee", 59, Rarity.UNCOMMON, mage.cards.b.Banshee.class)); - cards.add(new SetCardInfo("Barktooth Warbeard", 144, Rarity.COMMON, mage.cards.b.BarktoothWarbeard.class)); - cards.add(new SetCardInfo("Barl's Cage", 190, Rarity.RARE, mage.cards.b.BarlsCage.class)); - cards.add(new SetCardInfo("Bartel Runeaxe", 145, Rarity.UNCOMMON, mage.cards.b.BartelRuneaxe.class)); - cards.add(new SetCardInfo("Bayou", 204, Rarity.RARE, mage.cards.b.Bayou.class)); - cards.add(new SetCardInfo("Bazaar of Baghdad", 205, Rarity.RARE, mage.cards.b.BazaarOfBaghdad.class)); - cards.add(new SetCardInfo("Black Vise", 191, Rarity.RARE, mage.cards.b.BlackVise.class)); - cards.add(new SetCardInfo("Blood Lust", 88, Rarity.COMMON, mage.cards.b.BloodLust.class)); - cards.add(new SetCardInfo("Bone Flute", 192, Rarity.COMMON, mage.cards.b.BoneFlute.class)); - cards.add(new SetCardInfo("Boomerang", 30, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Boris Devilboon", 146, Rarity.UNCOMMON, mage.cards.b.BorisDevilboon.class)); - cards.add(new SetCardInfo("Borrowing 100,000 Arrows", 31, Rarity.UNCOMMON, mage.cards.b.Borrowing100000Arrows.class)); - cards.add(new SetCardInfo("Brilliant Plan", 32, Rarity.COMMON, mage.cards.b.BrilliantPlan.class)); - cards.add(new SetCardInfo("Burning of Xinye", 89, Rarity.RARE, mage.cards.b.BurningOfXinye.class)); - cards.add(new SetCardInfo("Call to Arms", 4, Rarity.UNCOMMON, mage.cards.c.CallToArms.class)); - cards.add(new SetCardInfo("Capture of Jingzhou", 33, Rarity.RARE, mage.cards.c.CaptureOfJingzhou.class)); - cards.add(new SetCardInfo("Carrion Ants", 60, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); - cards.add(new SetCardInfo("Chain Lightning", 90, Rarity.COMMON, mage.cards.c.ChainLightning.class)); - cards.add(new SetCardInfo("Chromium", 147, Rarity.RARE, mage.cards.c.Chromium.class)); - cards.add(new SetCardInfo("Cinder Storm", 91, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); - cards.add(new SetCardInfo("City of Shadows", 206, Rarity.RARE, mage.cards.c.CityOfShadows.class)); - cards.add(new SetCardInfo("Cleanse", 5, Rarity.RARE, mage.cards.c.Cleanse.class)); - cards.add(new SetCardInfo("Coal Golem", 193, Rarity.COMMON, mage.cards.c.CoalGolem.class)); - cards.add(new SetCardInfo("Concordant Crossroads", 114, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); - cards.add(new SetCardInfo("Corrupt Eunuchs", 92, Rarity.UNCOMMON, mage.cards.c.CorruptEunuchs.class)); - cards.add(new SetCardInfo("Cosmic Horror", 61, Rarity.RARE, mage.cards.c.CosmicHorror.class)); - cards.add(new SetCardInfo("Crimson Kobolds", 93, Rarity.COMMON, mage.cards.c.CrimsonKobolds.class)); - cards.add(new SetCardInfo("Crimson Manticore", 94, Rarity.UNCOMMON, mage.cards.c.CrimsonManticore.class)); - cards.add(new SetCardInfo("Dance of Many", 34, Rarity.UNCOMMON, mage.cards.d.DanceOfMany.class)); - cards.add(new SetCardInfo("D'Avenant Archer", 6, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); - cards.add(new SetCardInfo("Demonic Torment", 62, Rarity.COMMON, mage.cards.d.DemonicTorment.class)); - cards.add(new SetCardInfo("Desert Twister", 115, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); - cards.add(new SetCardInfo("Desperate Charge", 63, Rarity.COMMON, mage.cards.d.DesperateCharge.class)); - cards.add(new SetCardInfo("Didgeridoo", 194, Rarity.UNCOMMON, mage.cards.d.Didgeridoo.class)); - cards.add(new SetCardInfo("Disenchant", 7, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class)); - cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); - cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 96, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); - cards.add(new SetCardInfo("Eightfold Maze", 9, Rarity.UNCOMMON, mage.cards.e.EightfoldMaze.class)); - cards.add(new SetCardInfo("Elves of Deep Shadow", 116, Rarity.COMMON, mage.cards.e.ElvesOfDeepShadow.class)); - cards.add(new SetCardInfo("Evil Presence", 64, Rarity.COMMON, mage.cards.e.EvilPresence.class)); - cards.add(new SetCardInfo("Exorcist", 10, Rarity.UNCOMMON, mage.cards.e.Exorcist.class)); - cards.add(new SetCardInfo("Faerie Noble", 117, Rarity.UNCOMMON, mage.cards.f.FaerieNoble.class)); - cards.add(new SetCardInfo("False Defeat", 11, Rarity.UNCOMMON, mage.cards.f.FalseDefeat.class)); - cards.add(new SetCardInfo("Famine", 65, Rarity.UNCOMMON, mage.cards.f.Famine.class)); - cards.add(new SetCardInfo("Fellwar Stone", 195, Rarity.COMMON, mage.cards.f.FellwarStone.class)); - cards.add(new SetCardInfo("Fevered Strength", 66, Rarity.COMMON, mage.cards.f.FeveredStrength.class)); - cards.add(new SetCardInfo("Fire Ambush", 97, Rarity.COMMON, mage.cards.f.FireAmbush.class)); - cards.add(new SetCardInfo("Fire Drake", 98, Rarity.COMMON, mage.cards.f.FireDrake.class)); - cards.add(new SetCardInfo("Fire Sprites", 118, Rarity.COMMON, mage.cards.f.FireSprites.class)); - cards.add(new SetCardInfo("Flash Flood", 35, Rarity.UNCOMMON, mage.cards.f.FlashFlood.class)); - cards.add(new SetCardInfo("Forced Retreat", 37, Rarity.COMMON, mage.cards.f.ForcedRetreat.class)); - cards.add(new SetCardInfo("Force Spike", 36, Rarity.COMMON, mage.cards.f.ForceSpike.class)); - cards.add(new SetCardInfo("Forest", 228, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 229, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 230, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Frost Giant", 101, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); - cards.add(new SetCardInfo("Gabriel Angelfire", 148, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); - cards.add(new SetCardInfo("Gaea's Touch", 120, Rarity.UNCOMMON, mage.cards.g.GaeasTouch.class)); - cards.add(new SetCardInfo("Gauntlets of Chaos", 196, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); - cards.add(new SetCardInfo("Ghostly Visit", 67, Rarity.COMMON, mage.cards.g.GhostlyVisit.class)); - cards.add(new SetCardInfo("Ghosts of the Damned", 68, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); - cards.add(new SetCardInfo("Giant Growth", 121, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Grim Tutor", 69, Rarity.RARE, mage.cards.g.GrimTutor.class)); - cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 13, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class)); - cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 12, Rarity.UNCOMMON, mage.cards.g.GuanYuSaintedWarrior.class)); - cards.add(new SetCardInfo("Gwendlyn Di Corci", 149, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); - cards.add(new SetCardInfo("Halfdane", 150, Rarity.RARE, mage.cards.h.Halfdane.class)); - cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); - cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class)); - cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class)); - cards.add(new SetCardInfo("Heavy Fog", 122, Rarity.COMMON, mage.cards.h.HeavyFog.class)); - cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class)); - cards.add(new SetCardInfo("Hua Tuo, Honored Physician", 123, Rarity.RARE, mage.cards.h.HuaTuoHonoredPhysician.class)); - cards.add(new SetCardInfo("Hunding Gjornersen", 152, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); - cards.add(new SetCardInfo("Hunting Cheetah", 124, Rarity.COMMON, mage.cards.h.HuntingCheetah.class)); - cards.add(new SetCardInfo("Hurloon Minotaur", 102, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); - cards.add(new SetCardInfo("Immolation", 103, Rarity.COMMON, mage.cards.i.Immolation.class)); - cards.add(new SetCardInfo("Infuse", 38, Rarity.COMMON, mage.cards.i.Infuse.class)); - cards.add(new SetCardInfo("Island", 219, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 220, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 221, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Guardians", 15, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); - cards.add(new SetCardInfo("Jedit Ojanen", 153, Rarity.COMMON, mage.cards.j.JeditOjanen.class)); - cards.add(new SetCardInfo("Jerrard of the Closed Fist", 154, Rarity.COMMON, mage.cards.j.JerrardOfTheClosedFist.class)); - cards.add(new SetCardInfo("Jungle Lion", 125, Rarity.COMMON, mage.cards.j.JungleLion.class)); - cards.add(new SetCardInfo("Karakas", 208, Rarity.RARE, mage.cards.k.Karakas.class)); - cards.add(new SetCardInfo("Kei Takahashi", 155, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); - cards.add(new SetCardInfo("Killer Bees", 126, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); - cards.add(new SetCardInfo("Kjeldoran Frostbeast", 156, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); - cards.add(new SetCardInfo("Kobold Drill Sergeant", 104, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class)); - cards.add(new SetCardInfo("Kobold Overlord", 105, Rarity.UNCOMMON, mage.cards.k.KoboldOverlord.class)); - cards.add(new SetCardInfo("Kobolds of Kher Keep", 107, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); - cards.add(new SetCardInfo("Kobold Taskmaster", 106, Rarity.COMMON, mage.cards.k.KoboldTaskmaster.class)); - cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 16, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class)); - cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); - cards.add(new SetCardInfo("Lady Caleria", 157, Rarity.UNCOMMON, mage.cards.l.LadyCaleria.class)); - cards.add(new SetCardInfo("Lady Evangela", 158, Rarity.UNCOMMON, mage.cards.l.LadyEvangela.class)); - cards.add(new SetCardInfo("Lady Orca", 159, Rarity.COMMON, mage.cards.l.LadyOrca.class)); - cards.add(new SetCardInfo("Land Equilibrium", 40, Rarity.RARE, mage.cards.l.LandEquilibrium.class)); - cards.add(new SetCardInfo("Land Tax", 17, Rarity.RARE, mage.cards.l.LandTax.class)); - cards.add(new SetCardInfo("Life Chisel", 199, Rarity.RARE, mage.cards.l.LifeChisel.class)); - cards.add(new SetCardInfo("Lightning Blow", 18, Rarity.COMMON, mage.cards.l.LightningBlow.class)); - cards.add(new SetCardInfo("Liu Bei, Lord of Shu", 19, Rarity.RARE, mage.cards.l.LiuBeiLordOfShu.class)); - cards.add(new SetCardInfo("Living Plane", 127, Rarity.RARE, mage.cards.l.LivingPlane.class)); - cards.add(new SetCardInfo("Livonya Silone", 160, Rarity.UNCOMMON, mage.cards.l.LivonyaSilone.class)); - cards.add(new SetCardInfo("Loyal Retainers", 20, Rarity.UNCOMMON, mage.cards.l.LoyalRetainers.class)); - cards.add(new SetCardInfo("Lu Bu, Master-at-Arms", 108, Rarity.RARE, mage.cards.l.LuBuMasterAtArms.class)); - cards.add(new SetCardInfo("Lu Meng, Wu General", 41, Rarity.UNCOMMON, mage.cards.l.LuMengWuGeneral.class)); - cards.add(new SetCardInfo("Lu Xun, Scholar General", 42, Rarity.UNCOMMON, mage.cards.l.LuXunScholarGeneral.class)); - cards.add(new SetCardInfo("Mana Drain", 43, Rarity.RARE, mage.cards.m.ManaDrain.class)); - cards.add(new SetCardInfo("Mana Vortex", 44, Rarity.RARE, mage.cards.m.ManaVortex.class)); - cards.add(new SetCardInfo("Marhault Elsdragon", 161, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); - cards.add(new SetCardInfo("Meng Huo, Barbarian King", 128, Rarity.RARE, mage.cards.m.MengHuoBarbarianKing.class)); - cards.add(new SetCardInfo("Meng Huo's Horde", 129, Rarity.COMMON, mage.cards.m.MengHuosHorde.class)); - cards.add(new SetCardInfo("Mind Twist", 72, Rarity.RARE, mage.cards.m.MindTwist.class)); - cards.add(new SetCardInfo("Misfortune's Gain", 21, Rarity.COMMON, mage.cards.m.MisfortunesGain.class)); - cards.add(new SetCardInfo("Mountain", 225, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 226, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 227, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Nebuchadnezzar", 162, Rarity.UNCOMMON, mage.cards.n.Nebuchadnezzar.class)); - cards.add(new SetCardInfo("Nether Void", 73, Rarity.RARE, mage.cards.n.NetherVoid.class)); - cards.add(new SetCardInfo("Nicol Bolas", 163, Rarity.RARE, mage.cards.n.NicolBolas.class)); - cards.add(new SetCardInfo("Nova Pentacle", 200, Rarity.RARE, mage.cards.n.NovaPentacle.class)); - cards.add(new SetCardInfo("Old Man of the Sea", 45, Rarity.RARE, mage.cards.o.OldManOfTheSea.class)); - cards.add(new SetCardInfo("Palladia-Mors", 164, Rarity.RARE, mage.cards.p.PalladiaMors.class)); - cards.add(new SetCardInfo("Pavel Maliki", 165, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); - cards.add(new SetCardInfo("Peach Garden Oath", 22, Rarity.COMMON, mage.cards.p.PeachGardenOath.class)); - cards.add(new SetCardInfo("Plains", 216, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 217, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 218, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plateau", 209, Rarity.RARE, mage.cards.p.Plateau.class)); - cards.add(new SetCardInfo("Princess Lucrezia", 166, Rarity.UNCOMMON, mage.cards.p.PrincessLucrezia.class)); - cards.add(new SetCardInfo("Raging Minotaur", 109, Rarity.COMMON, mage.cards.r.RagingMinotaur.class)); - cards.add(new SetCardInfo("Ragnar", 167, Rarity.UNCOMMON, mage.cards.r.Ragnar.class)); - cards.add(new SetCardInfo("Ramirez DePietro", 168, Rarity.COMMON, mage.cards.r.RamirezDePietro.class)); - cards.add(new SetCardInfo("Ramses Overdark", 169, Rarity.UNCOMMON, mage.cards.r.RamsesOverdark.class)); - cards.add(new SetCardInfo("Rasputin Dreamweaver", 170, Rarity.RARE, mage.cards.r.RasputinDreamweaver.class)); - cards.add(new SetCardInfo("Recall", 46, Rarity.UNCOMMON, mage.cards.r.Recall.class)); - cards.add(new SetCardInfo("Reincarnation", 130, Rarity.UNCOMMON, mage.cards.r.Reincarnation.class)); - cards.add(new SetCardInfo("Remove Soul", 47, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Reset", 48, Rarity.RARE, mage.cards.r.Reset.class)); - cards.add(new SetCardInfo("Reveka, Wizard Savant", 49, Rarity.UNCOMMON, mage.cards.r.RevekaWizardSavant.class)); - cards.add(new SetCardInfo("Riding the Dilu Horse", 131, Rarity.UNCOMMON, mage.cards.r.RidingTheDiluHorse.class)); - cards.add(new SetCardInfo("Riven Turnbull", 171, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); - cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); - cards.add(new SetCardInfo("Rolling Earthquake", 110, Rarity.RARE, mage.cards.r.RollingEarthquake.class)); - cards.add(new SetCardInfo("Rubinia Soulsinger", 173, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); - cards.add(new SetCardInfo("Scrubland", 210, Rarity.RARE, mage.cards.s.Scrubland.class)); - cards.add(new SetCardInfo("Scryb Sprites", 132, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); - cards.add(new SetCardInfo("Shu Cavalry", 23, Rarity.COMMON, mage.cards.s.ShuCavalry.class)); - cards.add(new SetCardInfo("Shu Elite Companions", 24, Rarity.COMMON, mage.cards.s.ShuEliteCompanions.class)); - cards.add(new SetCardInfo("Shu General", 25, Rarity.COMMON, mage.cards.s.ShuGeneral.class)); - cards.add(new SetCardInfo("Shu Soldier-Farmers", 26, Rarity.COMMON, mage.cards.s.ShuSoldierFarmers.class)); - cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 174, Rarity.COMMON, mage.cards.s.SirShandlarOfEberyn.class)); - cards.add(new SetCardInfo("Sivitri Scarzam", 175, Rarity.COMMON, mage.cards.s.SivitriScarzam.class)); - cards.add(new SetCardInfo("Slashing Tiger", 133, Rarity.COMMON, mage.cards.s.SlashingTiger.class)); - cards.add(new SetCardInfo("Sol Grail", 201, Rarity.COMMON, mage.cards.s.SolGrail.class)); - cards.add(new SetCardInfo("Sorrow's Path", 211, Rarity.RARE, mage.cards.s.SorrowsPath.class)); - cards.add(new SetCardInfo("Spirit Shackle", 74, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); - cards.add(new SetCardInfo("Spoils of Victory", 134, Rarity.COMMON, mage.cards.s.SpoilsOfVictory.class)); - cards.add(new SetCardInfo("Stangg", 177, Rarity.UNCOMMON, mage.cards.s.Stangg.class)); - cards.add(new SetCardInfo("Stolen Grain", 75, Rarity.UNCOMMON, mage.cards.s.StolenGrain.class)); - cards.add(new SetCardInfo("Storm World", 111, Rarity.RARE, mage.cards.s.StormWorld.class)); - cards.add(new SetCardInfo("Strategic Planning", 51, Rarity.COMMON, mage.cards.s.StrategicPlanning.class)); - cards.add(new SetCardInfo("Sunastian Falconer", 178, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); - cards.add(new SetCardInfo("Sun Ce, Young Conquerer", 52, Rarity.UNCOMMON, mage.cards.s.SunCeYoungConquerer.class)); - cards.add(new SetCardInfo("Sun Quan, Lord of Wu", 53, Rarity.RARE, mage.cards.s.SunQuanLordOfWu.class)); - cards.add(new SetCardInfo("Swamp", 222, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 223, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 224, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sword of the Ages", 202, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); - cards.add(new SetCardInfo("Tetsuo Umezawa", 179, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); - cards.add(new SetCardInfo("The Abyss", 77, Rarity.RARE, mage.cards.t.TheAbyss.class)); - cards.add(new SetCardInfo("The Lady of the Mountain", 180, Rarity.COMMON, mage.cards.t.TheLadyOfTheMountain.class)); - cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 212, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); - cards.add(new SetCardInfo("The Wretched", 78, Rarity.UNCOMMON, mage.cards.t.TheWretched.class)); - cards.add(new SetCardInfo("Three Visits", 135, Rarity.COMMON, mage.cards.t.ThreeVisits.class)); - cards.add(new SetCardInfo("Tobias Andrion", 181, Rarity.COMMON, mage.cards.t.TobiasAndrion.class)); - cards.add(new SetCardInfo("Torsten Von Ursus", 183, Rarity.COMMON, mage.cards.t.TorstenVonUrsus.class)); - cards.add(new SetCardInfo("Tor Wauki", 182, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); - cards.add(new SetCardInfo("Tracker", 136, Rarity.UNCOMMON, mage.cards.t.Tracker.class)); - cards.add(new SetCardInfo("Trip Wire", 137, Rarity.COMMON, mage.cards.t.TripWire.class)); - cards.add(new SetCardInfo("Tropical Island", 213, Rarity.RARE, mage.cards.t.TropicalIsland.class)); - cards.add(new SetCardInfo("Tuknir Deathlock", 184, Rarity.UNCOMMON, mage.cards.t.TuknirDeathlock.class)); - cards.add(new SetCardInfo("Urborg", 214, Rarity.UNCOMMON, mage.cards.u.Urborg.class)); - cards.add(new SetCardInfo("Vaevictis Asmadi", 185, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); - cards.add(new SetCardInfo("Volcanic Island", 215, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); - cards.add(new SetCardInfo("Wall of Light", 27, Rarity.COMMON, mage.cards.w.WallOfLight.class)); - cards.add(new SetCardInfo("Wandering Mage", 186, Rarity.RARE, mage.cards.w.WanderingMage.class)); - cards.add(new SetCardInfo("Wei Elite Companions", 79, Rarity.COMMON, mage.cards.w.WeiEliteCompanions.class)); - cards.add(new SetCardInfo("Wei Infantry", 80, Rarity.COMMON, mage.cards.w.WeiInfantry.class)); - cards.add(new SetCardInfo("Wei Night Raiders", 81, Rarity.UNCOMMON, mage.cards.w.WeiNightRaiders.class)); - cards.add(new SetCardInfo("Wei Strike Force", 82, Rarity.COMMON, mage.cards.w.WeiStrikeForce.class)); - cards.add(new SetCardInfo("Willow Priestess", 138, Rarity.UNCOMMON, mage.cards.w.WillowPriestess.class)); - cards.add(new SetCardInfo("Willow Satyr", 139, Rarity.RARE, mage.cards.w.WillowSatyr.class)); - cards.add(new SetCardInfo("Wormwood Treefolk", 140, Rarity.UNCOMMON, mage.cards.w.WormwoodTreefolk.class)); - cards.add(new SetCardInfo("Wu Elite Cavalry", 54, Rarity.COMMON, mage.cards.w.WuEliteCavalry.class)); - cards.add(new SetCardInfo("Wu Longbowman", 55, Rarity.COMMON, mage.cards.w.WuLongbowman.class)); - cards.add(new SetCardInfo("Wu Warship", 56, Rarity.COMMON, mage.cards.w.WuWarship.class)); - cards.add(new SetCardInfo("Xiahou Dun, the One-Eyed", 83, Rarity.UNCOMMON, mage.cards.x.XiahouDunTheOneEyed.class)); - cards.add(new SetCardInfo("Xira Arien", 187, Rarity.RARE, mage.cards.x.XiraArien.class)); - cards.add(new SetCardInfo("Young Wei Recruits", 84, Rarity.COMMON, mage.cards.y.YoungWeiRecruits.class)); - cards.add(new SetCardInfo("Zhang Fei, Fierce Warrior", 28, Rarity.UNCOMMON, mage.cards.z.ZhangFeiFierceWarrior.class)); - cards.add(new SetCardInfo("Zodiac Dragon", 112, Rarity.RARE, mage.cards.z.ZodiacDragon.class)); - } + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author LevelX2 + */ +public final class MastersEditionIII extends ExpansionSet { + + private static final MastersEditionIII instance = new MastersEditionIII(); + + public static MastersEditionIII getInstance() { + return instance; + } + + private MastersEditionIII() { + super("Masters Edition III", "ME3", ExpansionSet.buildDate(2009, 9, 7), SetType.MAGIC_ONLINE); + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Active Volcano", 85, Rarity.UNCOMMON, mage.cards.a.ActiveVolcano.class)); + cards.add(new SetCardInfo("Akron Legionnaire", 1, Rarity.RARE, mage.cards.a.AkronLegionnaire.class)); + cards.add(new SetCardInfo("Alabaster Potion", 2, Rarity.UNCOMMON, mage.cards.a.AlabasterPotion.class)); + cards.add(new SetCardInfo("All Hallow's Eve", 57, Rarity.RARE, mage.cards.a.AllHallowsEve.class)); + cards.add(new SetCardInfo("Amrou Kithkin", 3, Rarity.COMMON, mage.cards.a.AmrouKithkin.class)); + cards.add(new SetCardInfo("Anaba Ancestor", 86, Rarity.COMMON, mage.cards.a.AnabaAncestor.class)); + cards.add(new SetCardInfo("Anaba Spirit Crafter", 87, Rarity.COMMON, mage.cards.a.AnabaSpiritCrafter.class)); + cards.add(new SetCardInfo("Angus Mackenzie", 141, Rarity.RARE, mage.cards.a.AngusMackenzie.class)); + cards.add(new SetCardInfo("Arboria", 113, Rarity.RARE, mage.cards.a.Arboria.class)); + cards.add(new SetCardInfo("Arcades Sabboth", 142, Rarity.RARE, mage.cards.a.ArcadesSabboth.class)); + cards.add(new SetCardInfo("Arena of the Ancients", 188, Rarity.RARE, mage.cards.a.ArenaOfTheAncients.class)); + cards.add(new SetCardInfo("Ashes to Ashes", 58, Rarity.UNCOMMON, mage.cards.a.AshesToAshes.class)); + cards.add(new SetCardInfo("Astrolabe", 189, Rarity.COMMON, mage.cards.a.Astrolabe.class)); + cards.add(new SetCardInfo("Axelrod Gunnarson", 143, Rarity.UNCOMMON, mage.cards.a.AxelrodGunnarson.class)); + cards.add(new SetCardInfo("Banshee", 59, Rarity.UNCOMMON, mage.cards.b.Banshee.class)); + cards.add(new SetCardInfo("Barktooth Warbeard", 144, Rarity.COMMON, mage.cards.b.BarktoothWarbeard.class)); + cards.add(new SetCardInfo("Barl's Cage", 190, Rarity.RARE, mage.cards.b.BarlsCage.class)); + cards.add(new SetCardInfo("Bartel Runeaxe", 145, Rarity.UNCOMMON, mage.cards.b.BartelRuneaxe.class)); + cards.add(new SetCardInfo("Bayou", 204, Rarity.RARE, mage.cards.b.Bayou.class)); + cards.add(new SetCardInfo("Bazaar of Baghdad", 205, Rarity.RARE, mage.cards.b.BazaarOfBaghdad.class)); + cards.add(new SetCardInfo("Black Vise", 191, Rarity.RARE, mage.cards.b.BlackVise.class)); + cards.add(new SetCardInfo("Blood Lust", 88, Rarity.COMMON, mage.cards.b.BloodLust.class)); + cards.add(new SetCardInfo("Bone Flute", 192, Rarity.COMMON, mage.cards.b.BoneFlute.class)); + cards.add(new SetCardInfo("Boomerang", 30, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Boris Devilboon", 146, Rarity.UNCOMMON, mage.cards.b.BorisDevilboon.class)); + cards.add(new SetCardInfo("Borrowing 100,000 Arrows", 31, Rarity.UNCOMMON, mage.cards.b.Borrowing100000Arrows.class)); + cards.add(new SetCardInfo("Brilliant Plan", 32, Rarity.COMMON, mage.cards.b.BrilliantPlan.class)); + cards.add(new SetCardInfo("Burning of Xinye", 89, Rarity.RARE, mage.cards.b.BurningOfXinye.class)); + cards.add(new SetCardInfo("Call to Arms", 4, Rarity.UNCOMMON, mage.cards.c.CallToArms.class)); + cards.add(new SetCardInfo("Capture of Jingzhou", 33, Rarity.RARE, mage.cards.c.CaptureOfJingzhou.class)); + cards.add(new SetCardInfo("Carrion Ants", 60, Rarity.UNCOMMON, mage.cards.c.CarrionAnts.class)); + cards.add(new SetCardInfo("Chain Lightning", 90, Rarity.COMMON, mage.cards.c.ChainLightning.class)); + cards.add(new SetCardInfo("Chromium", 147, Rarity.RARE, mage.cards.c.Chromium.class)); + cards.add(new SetCardInfo("Cinder Storm", 91, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); + cards.add(new SetCardInfo("City of Shadows", 206, Rarity.RARE, mage.cards.c.CityOfShadows.class)); + cards.add(new SetCardInfo("Cleanse", 5, Rarity.RARE, mage.cards.c.Cleanse.class)); + cards.add(new SetCardInfo("Coal Golem", 193, Rarity.COMMON, mage.cards.c.CoalGolem.class)); + cards.add(new SetCardInfo("Concordant Crossroads", 114, Rarity.RARE, mage.cards.c.ConcordantCrossroads.class)); + cards.add(new SetCardInfo("Corrupt Eunuchs", 92, Rarity.UNCOMMON, mage.cards.c.CorruptEunuchs.class)); + cards.add(new SetCardInfo("Cosmic Horror", 61, Rarity.RARE, mage.cards.c.CosmicHorror.class)); + cards.add(new SetCardInfo("Crimson Kobolds", 93, Rarity.COMMON, mage.cards.c.CrimsonKobolds.class)); + cards.add(new SetCardInfo("Crimson Manticore", 94, Rarity.UNCOMMON, mage.cards.c.CrimsonManticore.class)); + cards.add(new SetCardInfo("Dance of Many", 34, Rarity.UNCOMMON, mage.cards.d.DanceOfMany.class)); + cards.add(new SetCardInfo("D'Avenant Archer", 6, Rarity.COMMON, mage.cards.d.DAvenantArcher.class)); + cards.add(new SetCardInfo("Demonic Torment", 62, Rarity.COMMON, mage.cards.d.DemonicTorment.class)); + cards.add(new SetCardInfo("Desert Twister", 115, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); + cards.add(new SetCardInfo("Desperate Charge", 63, Rarity.COMMON, mage.cards.d.DesperateCharge.class)); + cards.add(new SetCardInfo("Didgeridoo", 194, Rarity.UNCOMMON, mage.cards.d.Didgeridoo.class)); + cards.add(new SetCardInfo("Disenchant", 7, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Disharmony", 95, Rarity.UNCOMMON, mage.cards.d.Disharmony.class)); + cards.add(new SetCardInfo("Divine Intervention", 8, Rarity.RARE, mage.cards.d.DivineIntervention.class)); + cards.add(new SetCardInfo("Dong Zhou, the Tyrant", 96, Rarity.RARE, mage.cards.d.DongZhouTheTyrant.class)); + cards.add(new SetCardInfo("Eightfold Maze", 9, Rarity.UNCOMMON, mage.cards.e.EightfoldMaze.class)); + cards.add(new SetCardInfo("Elves of Deep Shadow", 116, Rarity.COMMON, mage.cards.e.ElvesOfDeepShadow.class)); + cards.add(new SetCardInfo("Evil Presence", 64, Rarity.COMMON, mage.cards.e.EvilPresence.class)); + cards.add(new SetCardInfo("Exorcist", 10, Rarity.UNCOMMON, mage.cards.e.Exorcist.class)); + cards.add(new SetCardInfo("Faerie Noble", 117, Rarity.UNCOMMON, mage.cards.f.FaerieNoble.class)); + cards.add(new SetCardInfo("False Defeat", 11, Rarity.UNCOMMON, mage.cards.f.FalseDefeat.class)); + cards.add(new SetCardInfo("Famine", 65, Rarity.UNCOMMON, mage.cards.f.Famine.class)); + cards.add(new SetCardInfo("Fellwar Stone", 195, Rarity.COMMON, mage.cards.f.FellwarStone.class)); + cards.add(new SetCardInfo("Fevered Strength", 66, Rarity.COMMON, mage.cards.f.FeveredStrength.class)); + cards.add(new SetCardInfo("Fire Ambush", 97, Rarity.COMMON, mage.cards.f.FireAmbush.class)); + cards.add(new SetCardInfo("Fire Drake", 98, Rarity.COMMON, mage.cards.f.FireDrake.class)); + cards.add(new SetCardInfo("Fire Sprites", 118, Rarity.COMMON, mage.cards.f.FireSprites.class)); + cards.add(new SetCardInfo("Flash Flood", 35, Rarity.UNCOMMON, mage.cards.f.FlashFlood.class)); + cards.add(new SetCardInfo("Forced Retreat", 37, Rarity.COMMON, mage.cards.f.ForcedRetreat.class)); + cards.add(new SetCardInfo("Force Spike", 36, Rarity.COMMON, mage.cards.f.ForceSpike.class)); + cards.add(new SetCardInfo("Forest", 228, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 229, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 230, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Freyalise's Winds", 119, Rarity.RARE, mage.cards.f.FreyalisesWinds.class)); + cards.add(new SetCardInfo("Frost Giant", 101, Rarity.UNCOMMON, mage.cards.f.FrostGiant.class)); + cards.add(new SetCardInfo("Gabriel Angelfire", 148, Rarity.RARE, mage.cards.g.GabrielAngelfire.class)); + cards.add(new SetCardInfo("Gaea's Touch", 120, Rarity.UNCOMMON, mage.cards.g.GaeasTouch.class)); + cards.add(new SetCardInfo("Gauntlets of Chaos", 196, Rarity.RARE, mage.cards.g.GauntletsOfChaos.class)); + cards.add(new SetCardInfo("Ghostly Visit", 67, Rarity.COMMON, mage.cards.g.GhostlyVisit.class)); + cards.add(new SetCardInfo("Ghosts of the Damned", 68, Rarity.COMMON, mage.cards.g.GhostsOfTheDamned.class)); + cards.add(new SetCardInfo("Giant Growth", 121, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Grim Tutor", 69, Rarity.RARE, mage.cards.g.GrimTutor.class)); + cards.add(new SetCardInfo("Guan Yu's 1,000-Li March", 13, Rarity.RARE, mage.cards.g.GuanYus1000LiMarch.class)); + cards.add(new SetCardInfo("Guan Yu, Sainted Warrior", 12, Rarity.UNCOMMON, mage.cards.g.GuanYuSaintedWarrior.class)); + cards.add(new SetCardInfo("Gwendlyn Di Corci", 149, Rarity.RARE, mage.cards.g.GwendlynDiCorci.class)); + cards.add(new SetCardInfo("Halfdane", 150, Rarity.RARE, mage.cards.h.Halfdane.class)); + cards.add(new SetCardInfo("Hammerheim", 207, Rarity.UNCOMMON, mage.cards.h.Hammerheim.class)); + cards.add(new SetCardInfo("Hazezon Tamar", 151, Rarity.RARE, mage.cards.h.HazezonTamar.class)); + cards.add(new SetCardInfo("Heal", 14, Rarity.COMMON, mage.cards.h.Heal.class)); + cards.add(new SetCardInfo("Heavy Fog", 122, Rarity.COMMON, mage.cards.h.HeavyFog.class)); + cards.add(new SetCardInfo("Hellfire", 70, Rarity.RARE, mage.cards.h.Hellfire.class)); + cards.add(new SetCardInfo("Hua Tuo, Honored Physician", 123, Rarity.RARE, mage.cards.h.HuaTuoHonoredPhysician.class)); + cards.add(new SetCardInfo("Hunding Gjornersen", 152, Rarity.UNCOMMON, mage.cards.h.HundingGjornersen.class)); + cards.add(new SetCardInfo("Hunting Cheetah", 124, Rarity.COMMON, mage.cards.h.HuntingCheetah.class)); + cards.add(new SetCardInfo("Hurloon Minotaur", 102, Rarity.COMMON, mage.cards.h.HurloonMinotaur.class)); + cards.add(new SetCardInfo("Immolation", 103, Rarity.COMMON, mage.cards.i.Immolation.class)); + cards.add(new SetCardInfo("Infuse", 38, Rarity.COMMON, mage.cards.i.Infuse.class)); + cards.add(new SetCardInfo("Island", 219, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 220, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 221, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Guardians", 15, Rarity.UNCOMMON, mage.cards.i.IvoryGuardians.class)); + cards.add(new SetCardInfo("Jedit Ojanen", 153, Rarity.COMMON, mage.cards.j.JeditOjanen.class)); + cards.add(new SetCardInfo("Jerrard of the Closed Fist", 154, Rarity.COMMON, mage.cards.j.JerrardOfTheClosedFist.class)); + cards.add(new SetCardInfo("Jungle Lion", 125, Rarity.COMMON, mage.cards.j.JungleLion.class)); + cards.add(new SetCardInfo("Karakas", 208, Rarity.RARE, mage.cards.k.Karakas.class)); + cards.add(new SetCardInfo("Kei Takahashi", 155, Rarity.UNCOMMON, mage.cards.k.KeiTakahashi.class)); + cards.add(new SetCardInfo("Killer Bees", 126, Rarity.UNCOMMON, mage.cards.k.KillerBees.class)); + cards.add(new SetCardInfo("Kjeldoran Frostbeast", 156, Rarity.UNCOMMON, mage.cards.k.KjeldoranFrostbeast.class)); + cards.add(new SetCardInfo("Kobold Drill Sergeant", 104, Rarity.UNCOMMON, mage.cards.k.KoboldDrillSergeant.class)); + cards.add(new SetCardInfo("Kobold Overlord", 105, Rarity.UNCOMMON, mage.cards.k.KoboldOverlord.class)); + cards.add(new SetCardInfo("Kobolds of Kher Keep", 107, Rarity.COMMON, mage.cards.k.KoboldsOfKherKeep.class)); + cards.add(new SetCardInfo("Kobold Taskmaster", 106, Rarity.COMMON, mage.cards.k.KoboldTaskmaster.class)); + cards.add(new SetCardInfo("Kongming, 'Sleeping Dragon'", 16, Rarity.RARE, mage.cards.k.KongmingSleepingDragon.class)); + cards.add(new SetCardInfo("Labyrinth Minotaur", 39, Rarity.COMMON, mage.cards.l.LabyrinthMinotaur.class)); + cards.add(new SetCardInfo("Lady Caleria", 157, Rarity.UNCOMMON, mage.cards.l.LadyCaleria.class)); + cards.add(new SetCardInfo("Lady Evangela", 158, Rarity.UNCOMMON, mage.cards.l.LadyEvangela.class)); + cards.add(new SetCardInfo("Lady Orca", 159, Rarity.COMMON, mage.cards.l.LadyOrca.class)); + cards.add(new SetCardInfo("Land Equilibrium", 40, Rarity.RARE, mage.cards.l.LandEquilibrium.class)); + cards.add(new SetCardInfo("Land Tax", 17, Rarity.RARE, mage.cards.l.LandTax.class)); + cards.add(new SetCardInfo("Life Chisel", 199, Rarity.RARE, mage.cards.l.LifeChisel.class)); + cards.add(new SetCardInfo("Lightning Blow", 18, Rarity.COMMON, mage.cards.l.LightningBlow.class)); + cards.add(new SetCardInfo("Liu Bei, Lord of Shu", 19, Rarity.RARE, mage.cards.l.LiuBeiLordOfShu.class)); + cards.add(new SetCardInfo("Living Plane", 127, Rarity.RARE, mage.cards.l.LivingPlane.class)); + cards.add(new SetCardInfo("Livonya Silone", 160, Rarity.UNCOMMON, mage.cards.l.LivonyaSilone.class)); + cards.add(new SetCardInfo("Loyal Retainers", 20, Rarity.UNCOMMON, mage.cards.l.LoyalRetainers.class)); + cards.add(new SetCardInfo("Lu Bu, Master-at-Arms", 108, Rarity.RARE, mage.cards.l.LuBuMasterAtArms.class)); + cards.add(new SetCardInfo("Lu Meng, Wu General", 41, Rarity.UNCOMMON, mage.cards.l.LuMengWuGeneral.class)); + cards.add(new SetCardInfo("Lu Xun, Scholar General", 42, Rarity.UNCOMMON, mage.cards.l.LuXunScholarGeneral.class)); + cards.add(new SetCardInfo("Mana Drain", 43, Rarity.RARE, mage.cards.m.ManaDrain.class)); + cards.add(new SetCardInfo("Mana Vortex", 44, Rarity.RARE, mage.cards.m.ManaVortex.class)); + cards.add(new SetCardInfo("Marhault Elsdragon", 161, Rarity.UNCOMMON, mage.cards.m.MarhaultElsdragon.class)); + cards.add(new SetCardInfo("Meng Huo, Barbarian King", 128, Rarity.RARE, mage.cards.m.MengHuoBarbarianKing.class)); + cards.add(new SetCardInfo("Meng Huo's Horde", 129, Rarity.COMMON, mage.cards.m.MengHuosHorde.class)); + cards.add(new SetCardInfo("Mind Twist", 72, Rarity.RARE, mage.cards.m.MindTwist.class)); + cards.add(new SetCardInfo("Misfortune's Gain", 21, Rarity.COMMON, mage.cards.m.MisfortunesGain.class)); + cards.add(new SetCardInfo("Mountain", 225, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 226, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 227, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nebuchadnezzar", 162, Rarity.UNCOMMON, mage.cards.n.Nebuchadnezzar.class)); + cards.add(new SetCardInfo("Nether Void", 73, Rarity.RARE, mage.cards.n.NetherVoid.class)); + cards.add(new SetCardInfo("Nicol Bolas", 163, Rarity.RARE, mage.cards.n.NicolBolas.class)); + cards.add(new SetCardInfo("Nova Pentacle", 200, Rarity.RARE, mage.cards.n.NovaPentacle.class)); + cards.add(new SetCardInfo("Old Man of the Sea", 45, Rarity.RARE, mage.cards.o.OldManOfTheSea.class)); + cards.add(new SetCardInfo("Palladia-Mors", 164, Rarity.RARE, mage.cards.p.PalladiaMors.class)); + cards.add(new SetCardInfo("Pavel Maliki", 165, Rarity.UNCOMMON, mage.cards.p.PavelMaliki.class)); + cards.add(new SetCardInfo("Peach Garden Oath", 22, Rarity.COMMON, mage.cards.p.PeachGardenOath.class)); + cards.add(new SetCardInfo("Plains", 216, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 217, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 218, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plateau", 209, Rarity.RARE, mage.cards.p.Plateau.class)); + cards.add(new SetCardInfo("Princess Lucrezia", 166, Rarity.UNCOMMON, mage.cards.p.PrincessLucrezia.class)); + cards.add(new SetCardInfo("Raging Minotaur", 109, Rarity.COMMON, mage.cards.r.RagingMinotaur.class)); + cards.add(new SetCardInfo("Ragnar", 167, Rarity.UNCOMMON, mage.cards.r.Ragnar.class)); + cards.add(new SetCardInfo("Ramirez DePietro", 168, Rarity.COMMON, mage.cards.r.RamirezDePietro.class)); + cards.add(new SetCardInfo("Ramses Overdark", 169, Rarity.UNCOMMON, mage.cards.r.RamsesOverdark.class)); + cards.add(new SetCardInfo("Rasputin Dreamweaver", 170, Rarity.RARE, mage.cards.r.RasputinDreamweaver.class)); + cards.add(new SetCardInfo("Recall", 46, Rarity.UNCOMMON, mage.cards.r.Recall.class)); + cards.add(new SetCardInfo("Reincarnation", 130, Rarity.UNCOMMON, mage.cards.r.Reincarnation.class)); + cards.add(new SetCardInfo("Remove Soul", 47, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Reset", 48, Rarity.RARE, mage.cards.r.Reset.class)); + cards.add(new SetCardInfo("Reveka, Wizard Savant", 49, Rarity.UNCOMMON, mage.cards.r.RevekaWizardSavant.class)); + cards.add(new SetCardInfo("Riding the Dilu Horse", 131, Rarity.UNCOMMON, mage.cards.r.RidingTheDiluHorse.class)); + cards.add(new SetCardInfo("Riven Turnbull", 171, Rarity.UNCOMMON, mage.cards.r.RivenTurnbull.class)); + cards.add(new SetCardInfo("Rohgahh of Kher Keep", 172, Rarity.RARE, mage.cards.r.RohgahhOfKherKeep.class)); + cards.add(new SetCardInfo("Rolling Earthquake", 110, Rarity.RARE, mage.cards.r.RollingEarthquake.class)); + cards.add(new SetCardInfo("Rubinia Soulsinger", 173, Rarity.RARE, mage.cards.r.RubiniaSoulsinger.class)); + cards.add(new SetCardInfo("Scrubland", 210, Rarity.RARE, mage.cards.s.Scrubland.class)); + cards.add(new SetCardInfo("Scryb Sprites", 132, Rarity.COMMON, mage.cards.s.ScrybSprites.class)); + cards.add(new SetCardInfo("Shu Cavalry", 23, Rarity.COMMON, mage.cards.s.ShuCavalry.class)); + cards.add(new SetCardInfo("Shu Elite Companions", 24, Rarity.COMMON, mage.cards.s.ShuEliteCompanions.class)); + cards.add(new SetCardInfo("Shu General", 25, Rarity.COMMON, mage.cards.s.ShuGeneral.class)); + cards.add(new SetCardInfo("Shu Soldier-Farmers", 26, Rarity.COMMON, mage.cards.s.ShuSoldierFarmers.class)); + cards.add(new SetCardInfo("Sir Shandlar of Eberyn", 174, Rarity.COMMON, mage.cards.s.SirShandlarOfEberyn.class)); + cards.add(new SetCardInfo("Sivitri Scarzam", 175, Rarity.COMMON, mage.cards.s.SivitriScarzam.class)); + cards.add(new SetCardInfo("Slashing Tiger", 133, Rarity.COMMON, mage.cards.s.SlashingTiger.class)); + cards.add(new SetCardInfo("Sol Grail", 201, Rarity.COMMON, mage.cards.s.SolGrail.class)); + cards.add(new SetCardInfo("Sorrow's Path", 211, Rarity.RARE, mage.cards.s.SorrowsPath.class)); + cards.add(new SetCardInfo("Spirit Shackle", 74, Rarity.COMMON, mage.cards.s.SpiritShackle.class)); + cards.add(new SetCardInfo("Spoils of Victory", 134, Rarity.COMMON, mage.cards.s.SpoilsOfVictory.class)); + cards.add(new SetCardInfo("Stangg", 177, Rarity.UNCOMMON, mage.cards.s.Stangg.class)); + cards.add(new SetCardInfo("Stolen Grain", 75, Rarity.UNCOMMON, mage.cards.s.StolenGrain.class)); + cards.add(new SetCardInfo("Storm World", 111, Rarity.RARE, mage.cards.s.StormWorld.class)); + cards.add(new SetCardInfo("Strategic Planning", 51, Rarity.COMMON, mage.cards.s.StrategicPlanning.class)); + cards.add(new SetCardInfo("Sunastian Falconer", 178, Rarity.UNCOMMON, mage.cards.s.SunastianFalconer.class)); + cards.add(new SetCardInfo("Sun Ce, Young Conquerer", 52, Rarity.UNCOMMON, mage.cards.s.SunCeYoungConquerer.class)); + cards.add(new SetCardInfo("Sun Quan, Lord of Wu", 53, Rarity.RARE, mage.cards.s.SunQuanLordOfWu.class)); + cards.add(new SetCardInfo("Swamp", 222, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 223, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 224, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sword of the Ages", 202, Rarity.RARE, mage.cards.s.SwordOfTheAges.class)); + cards.add(new SetCardInfo("Tetsuo Umezawa", 179, Rarity.RARE, mage.cards.t.TetsuoUmezawa.class)); + cards.add(new SetCardInfo("The Abyss", 77, Rarity.RARE, mage.cards.t.TheAbyss.class)); + cards.add(new SetCardInfo("The Lady of the Mountain", 180, Rarity.COMMON, mage.cards.t.TheLadyOfTheMountain.class)); + cards.add(new SetCardInfo("The Tabernacle at Pendrell Vale", 212, Rarity.RARE, mage.cards.t.TheTabernacleAtPendrellVale.class)); + cards.add(new SetCardInfo("The Wretched", 78, Rarity.UNCOMMON, mage.cards.t.TheWretched.class)); + cards.add(new SetCardInfo("Three Visits", 135, Rarity.COMMON, mage.cards.t.ThreeVisits.class)); + cards.add(new SetCardInfo("Tobias Andrion", 181, Rarity.COMMON, mage.cards.t.TobiasAndrion.class)); + cards.add(new SetCardInfo("Torsten Von Ursus", 183, Rarity.COMMON, mage.cards.t.TorstenVonUrsus.class)); + cards.add(new SetCardInfo("Tor Wauki", 182, Rarity.UNCOMMON, mage.cards.t.TorWauki.class)); + cards.add(new SetCardInfo("Tracker", 136, Rarity.UNCOMMON, mage.cards.t.Tracker.class)); + cards.add(new SetCardInfo("Trip Wire", 137, Rarity.COMMON, mage.cards.t.TripWire.class)); + cards.add(new SetCardInfo("Tropical Island", 213, Rarity.RARE, mage.cards.t.TropicalIsland.class)); + cards.add(new SetCardInfo("Tuknir Deathlock", 184, Rarity.UNCOMMON, mage.cards.t.TuknirDeathlock.class)); + cards.add(new SetCardInfo("Urborg", 214, Rarity.UNCOMMON, mage.cards.u.Urborg.class)); + cards.add(new SetCardInfo("Vaevictis Asmadi", 185, Rarity.RARE, mage.cards.v.VaevictisAsmadi.class)); + cards.add(new SetCardInfo("Volcanic Island", 215, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); + cards.add(new SetCardInfo("Wall of Light", 27, Rarity.COMMON, mage.cards.w.WallOfLight.class)); + cards.add(new SetCardInfo("Wandering Mage", 186, Rarity.RARE, mage.cards.w.WanderingMage.class)); + cards.add(new SetCardInfo("Wei Elite Companions", 79, Rarity.COMMON, mage.cards.w.WeiEliteCompanions.class)); + cards.add(new SetCardInfo("Wei Infantry", 80, Rarity.COMMON, mage.cards.w.WeiInfantry.class)); + cards.add(new SetCardInfo("Wei Night Raiders", 81, Rarity.UNCOMMON, mage.cards.w.WeiNightRaiders.class)); + cards.add(new SetCardInfo("Wei Strike Force", 82, Rarity.COMMON, mage.cards.w.WeiStrikeForce.class)); + cards.add(new SetCardInfo("Willow Priestess", 138, Rarity.UNCOMMON, mage.cards.w.WillowPriestess.class)); + cards.add(new SetCardInfo("Willow Satyr", 139, Rarity.RARE, mage.cards.w.WillowSatyr.class)); + cards.add(new SetCardInfo("Wormwood Treefolk", 140, Rarity.UNCOMMON, mage.cards.w.WormwoodTreefolk.class)); + cards.add(new SetCardInfo("Wu Elite Cavalry", 54, Rarity.COMMON, mage.cards.w.WuEliteCavalry.class)); + cards.add(new SetCardInfo("Wu Longbowman", 55, Rarity.COMMON, mage.cards.w.WuLongbowman.class)); + cards.add(new SetCardInfo("Wu Warship", 56, Rarity.COMMON, mage.cards.w.WuWarship.class)); + cards.add(new SetCardInfo("Xiahou Dun, the One-Eyed", 83, Rarity.UNCOMMON, mage.cards.x.XiahouDunTheOneEyed.class)); + cards.add(new SetCardInfo("Xira Arien", 187, Rarity.RARE, mage.cards.x.XiraArien.class)); + cards.add(new SetCardInfo("Young Wei Recruits", 84, Rarity.COMMON, mage.cards.y.YoungWeiRecruits.class)); + cards.add(new SetCardInfo("Zhang Fei, Fierce Warrior", 28, Rarity.UNCOMMON, mage.cards.z.ZhangFeiFierceWarrior.class)); + cards.add(new SetCardInfo("Zodiac Dragon", 112, Rarity.RARE, mage.cards.z.ZodiacDragon.class)); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/MastersEditionIV.java b/Mage.Sets/src/mage/sets/MastersEditionIV.java index ba6d2eb7e9..6a680a577b 100644 --- a/Mage.Sets/src/mage/sets/MastersEditionIV.java +++ b/Mage.Sets/src/mage/sets/MastersEditionIV.java @@ -1,318 +1,320 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.cards.repository.CardCriteria; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; -import mage.constants.Rarity; -import mage.constants.SetType; - -import java.util.ArrayList; -import java.util.List; - -/** - * @author LevelX2 - */ -public final class MastersEditionIV extends ExpansionSet { - - private static final MastersEditionIV instance = new MastersEditionIV(); - - public static MastersEditionIV getInstance() { - return instance; - } - - protected final List savedSpecialLand = new ArrayList<>(); - - private MastersEditionIV() { - super("Masters Edition IV", "ME4", ExpansionSet.buildDate(2011, 1, 10), SetType.MAGIC_ONLINE); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 1; - this.numBoosterCommon = 10; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - this.ratioBoosterSpecialLand = 1; // replace all basic lands - - cards.add(new SetCardInfo("Acid Rain", 36, Rarity.RARE, mage.cards.a.AcidRain.class)); - cards.add(new SetCardInfo("Aesthir Glider", 176, Rarity.COMMON, mage.cards.a.AesthirGlider.class)); - cards.add(new SetCardInfo("Air Elemental", 37, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Al-abara's Carpet", 177, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); - cards.add(new SetCardInfo("Alaborn Musketeer", 1, Rarity.COMMON, mage.cards.a.AlabornMusketeer.class)); - cards.add(new SetCardInfo("Alaborn Trooper", 2, Rarity.COMMON, mage.cards.a.AlabornTrooper.class)); - cards.add(new SetCardInfo("Aladdin", 106, Rarity.RARE, mage.cards.a.Aladdin.class)); - cards.add(new SetCardInfo("Alchor's Tomb", 178, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); - cards.add(new SetCardInfo("Ali from Cairo", 107, Rarity.RARE, mage.cards.a.AliFromCairo.class)); - cards.add(new SetCardInfo("Alluring Scent", 141, Rarity.COMMON, mage.cards.a.AlluringScent.class)); - cards.add(new SetCardInfo("Amulet of Kroog", 179, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); - cards.add(new SetCardInfo("Angelic Voices", 3, Rarity.UNCOMMON, mage.cards.a.AngelicVoices.class)); - cards.add(new SetCardInfo("Animate Artifact", 38, Rarity.UNCOMMON, mage.cards.a.AnimateArtifact.class)); - cards.add(new SetCardInfo("Argivian Blacksmith", 4, Rarity.UNCOMMON, mage.cards.a.ArgivianBlacksmith.class)); - cards.add(new SetCardInfo("Argothian Pixies", 142, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); - cards.add(new SetCardInfo("Argothian Treefolk", 143, Rarity.UNCOMMON, mage.cards.a.ArgothianTreefolk.class)); - cards.add(new SetCardInfo("Armageddon Clock", 180, Rarity.RARE, mage.cards.a.ArmageddonClock.class)); - cards.add(new SetCardInfo("Armageddon", 5, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Artifact Blast", 108, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); - cards.add(new SetCardInfo("Ashnod's Altar", 181, Rarity.RARE, mage.cards.a.AshnodsAltar.class)); - cards.add(new SetCardInfo("Atog", 109, Rarity.COMMON, mage.cards.a.Atog.class)); - cards.add(new SetCardInfo("Badlands", 241, Rarity.RARE, mage.cards.b.Badlands.class)); - cards.add(new SetCardInfo("Balance", 6, Rarity.RARE, mage.cards.b.Balance.class)); - cards.add(new SetCardInfo("Basalt Monolith", 182, Rarity.UNCOMMON, mage.cards.b.BasaltMonolith.class)); - cards.add(new SetCardInfo("Bayou", 242, Rarity.RARE, mage.cards.b.Bayou.class)); - cards.add(new SetCardInfo("Bee Sting", 144, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); - cards.add(new SetCardInfo("Bird Maiden", 110, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); - cards.add(new SetCardInfo("Black Knight", 71, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); - cards.add(new SetCardInfo("Blaze of Glory", 7, Rarity.UNCOMMON, mage.cards.b.BlazeOfGlory.class)); - cards.add(new SetCardInfo("Blue Elemental Blast", 39, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); - cards.add(new SetCardInfo("Book of Rass", 183, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); - cards.add(new SetCardInfo("Bottle of Suleiman", 184, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); - cards.add(new SetCardInfo("Braingeyser", 40, Rarity.RARE, mage.cards.b.Braingeyser.class)); - cards.add(new SetCardInfo("Brass Man", 185, Rarity.COMMON, mage.cards.b.BrassMan.class)); - cards.add(new SetCardInfo("Candelabra of Tawnos", 187, Rarity.RARE, mage.cards.c.CandelabraOfTawnos.class)); - cards.add(new SetCardInfo("Celestial Sword", 188, Rarity.UNCOMMON, mage.cards.c.CelestialSword.class)); - cards.add(new SetCardInfo("Champion Lancer", 8, Rarity.RARE, mage.cards.c.ChampionLancer.class)); - cards.add(new SetCardInfo("Channel", 145, Rarity.RARE, mage.cards.c.Channel.class)); - cards.add(new SetCardInfo("Citanul Druid", 146, Rarity.COMMON, mage.cards.c.CitanulDruid.class)); - cards.add(new SetCardInfo("City of Brass", 243, Rarity.RARE, mage.cards.c.CityOfBrass.class)); - cards.add(new SetCardInfo("Clay Statue", 189, Rarity.UNCOMMON, mage.cards.c.ClayStatue.class)); - cards.add(new SetCardInfo("Clockwork Avian", 190, Rarity.UNCOMMON, mage.cards.c.ClockworkAvian.class)); - cards.add(new SetCardInfo("Clockwork Gnomes", 191, Rarity.UNCOMMON, mage.cards.c.ClockworkGnomes.class)); - cards.add(new SetCardInfo("Clockwork Swarm", 192, Rarity.COMMON, mage.cards.c.ClockworkSwarm.class)); - cards.add(new SetCardInfo("Cloud Dragon", 41, Rarity.RARE, mage.cards.c.CloudDragon.class)); - cards.add(new SetCardInfo("Cloud Spirit", 42, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Colossus of Sardia", 193, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); - cards.add(new SetCardInfo("Control Magic", 43, Rarity.RARE, mage.cards.c.ControlMagic.class)); - cards.add(new SetCardInfo("Conversion", 9, Rarity.RARE, mage.cards.c.Conversion.class)); - cards.add(new SetCardInfo("Copy Artifact", 44, Rarity.RARE, mage.cards.c.CopyArtifact.class)); - cards.add(new SetCardInfo("Coral Helm", 194, Rarity.UNCOMMON, mage.cards.c.CoralHelm.class)); - cards.add(new SetCardInfo("Counterspell", 45, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crumble", 147, Rarity.COMMON, mage.cards.c.Crumble.class)); - cards.add(new SetCardInfo("Cyclone", 148, Rarity.RARE, mage.cards.c.Cyclone.class)); - cards.add(new SetCardInfo("Cyclopean Mummy", 72, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); - cards.add(new SetCardInfo("Cyclopean Tomb", 195, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); - cards.add(new SetCardInfo("Dakmor Plague", 73, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); - cards.add(new SetCardInfo("Dark Ritual", 74, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Deathcoil Wurm", 149, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); - cards.add(new SetCardInfo("Deathgrip", 75, Rarity.RARE, mage.cards.d.Deathgrip.class)); - cards.add(new SetCardInfo("Demonic Hordes", 76, Rarity.RARE, mage.cards.d.DemonicHordes.class)); - cards.add(new SetCardInfo("Demonic Tutor", 77, Rarity.RARE, mage.cards.d.DemonicTutor.class)); - cards.add(new SetCardInfo("Detonate", 111, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); - cards.add(new SetCardInfo("Devastation", 112, Rarity.RARE, mage.cards.d.Devastation.class)); - cards.add(new SetCardInfo("Diabolic Machine", 196, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); - cards.add(new SetCardInfo("Divine Offering", 10, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Dragon Engine", 197, Rarity.COMMON, mage.cards.d.DragonEngine.class)); - cards.add(new SetCardInfo("Drain Power", 46, Rarity.RARE, mage.cards.d.DrainPower.class)); - cards.add(new SetCardInfo("Dread Reaper", 78, Rarity.RARE, mage.cards.d.DreadReaper.class)); - cards.add(new SetCardInfo("Drop of Honey", 150, Rarity.RARE, mage.cards.d.DropOfHoney.class)); - cards.add(new SetCardInfo("Drowned", 47, Rarity.COMMON, mage.cards.d.Drowned.class)); - cards.add(new SetCardInfo("Dust to Dust", 11, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); - cards.add(new SetCardInfo("Ebon Dragon", 80, Rarity.RARE, mage.cards.e.EbonDragon.class)); - cards.add(new SetCardInfo("Ebony Horse", 198, Rarity.COMMON, mage.cards.e.EbonyHorse.class)); - cards.add(new SetCardInfo("Ebony Rhino", 199, Rarity.COMMON, mage.cards.e.EbonyRhino.class)); - cards.add(new SetCardInfo("Elephant Graveyard", 244, Rarity.UNCOMMON, mage.cards.e.ElephantGraveyard.class)); - cards.add(new SetCardInfo("Elite Cat Warrior", 151, Rarity.COMMON, mage.cards.e.EliteCatWarrior.class)); - cards.add(new SetCardInfo("Energy Flux", 48, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); - cards.add(new SetCardInfo("Eye for an Eye", 12, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); - cards.add(new SetCardInfo("False Summoning", 49, Rarity.COMMON, mage.cards.f.FalseSummoning.class)); - cards.add(new SetCardInfo("Fastbond", 152, Rarity.RARE, mage.cards.f.Fastbond.class)); - cards.add(new SetCardInfo("Fire Imp", 113, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); - cards.add(new SetCardInfo("Fire Tempest", 114, Rarity.RARE, mage.cards.f.FireTempest.class)); - cards.add(new SetCardInfo("Fireball", 115, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); - cards.add(new SetCardInfo("Floodwater Dam", 200, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); - cards.add(new SetCardInfo("Flying Carpet", 201, Rarity.COMMON, mage.cards.f.FlyingCarpet.class)); - cards.add(new SetCardInfo("Fog", 153, Rarity.COMMON, mage.cards.f.Fog.class)); - cards.add(new SetCardInfo("Force of Nature", 154, Rarity.RARE, mage.cards.f.ForceOfNature.class)); - cards.add(new SetCardInfo("Fork", 116, Rarity.RARE, mage.cards.f.Fork.class)); - cards.add(new SetCardInfo("Foul Spirit", 81, Rarity.COMMON, mage.cards.f.FoulSpirit.class)); - cards.add(new SetCardInfo("Gaea's Avenger", 155, Rarity.UNCOMMON, mage.cards.g.GaeasAvenger.class)); - cards.add(new SetCardInfo("Gate to Phyrexia", 82, Rarity.UNCOMMON, mage.cards.g.GateToPhyrexia.class)); - cards.add(new SetCardInfo("Gauntlet of Might", 202, Rarity.RARE, mage.cards.g.GauntletOfMight.class)); - cards.add(new SetCardInfo("Giant Growth", 156, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); - cards.add(new SetCardInfo("Giant Tortoise", 50, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); - cards.add(new SetCardInfo("Glasses of Urza", 203, Rarity.COMMON, mage.cards.g.GlassesOfUrza.class)); - cards.add(new SetCardInfo("Gloom", 83, Rarity.RARE, mage.cards.g.Gloom.class)); - cards.add(new SetCardInfo("Goblin Bully", 117, Rarity.COMMON, mage.cards.g.GoblinBully.class)); - cards.add(new SetCardInfo("Goblin Cavaliers", 118, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); - cards.add(new SetCardInfo("Goblin Caves", 119, Rarity.COMMON, mage.cards.g.GoblinCaves.class)); - cards.add(new SetCardInfo("Goblin Firestarter", 120, Rarity.COMMON, mage.cards.g.GoblinFirestarter.class)); - cards.add(new SetCardInfo("Goblin General", 121, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); - cards.add(new SetCardInfo("Goblin Shrine", 122, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); - cards.add(new SetCardInfo("Goblin Warrens", 123, Rarity.UNCOMMON, mage.cards.g.GoblinWarrens.class)); - cards.add(new SetCardInfo("Gorilla War Cry", 124, Rarity.COMMON, mage.cards.g.GorillaWarCry.class)); - cards.add(new SetCardInfo("Grapeshot Catapult", 204, Rarity.UNCOMMON, mage.cards.g.GrapeshotCatapult.class)); - cards.add(new SetCardInfo("Gravebind", 84, Rarity.COMMON, mage.cards.g.Gravebind.class)); - cards.add(new SetCardInfo("Guardian Beast", 85, Rarity.RARE, mage.cards.g.GuardianBeast.class)); - cards.add(new SetCardInfo("Harsh Justice", 13, Rarity.RARE, mage.cards.h.HarshJustice.class)); - cards.add(new SetCardInfo("Hasran Ogress", 86, Rarity.COMMON, mage.cards.h.HasranOgress.class)); - cards.add(new SetCardInfo("Healing Salve", 14, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Horn of Deafening", 205, Rarity.UNCOMMON, mage.cards.h.HornOfDeafening.class)); - cards.add(new SetCardInfo("Howl from Beyond", 87, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); - cards.add(new SetCardInfo("Ice Cauldron", 206, Rarity.RARE, mage.cards.i.IceCauldron.class)); - cards.add(new SetCardInfo("Icy Manipulator", 207, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); - cards.add(new SetCardInfo("In the Eye of Chaos", 51, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); - cards.add(new SetCardInfo("Instill Energy", 157, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); - cards.add(new SetCardInfo("Ironhoof Ox", 158, Rarity.COMMON, mage.cards.i.IronhoofOx.class)); - cards.add(new SetCardInfo("Island Sanctuary", 15, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); - cards.add(new SetCardInfo("Jade Monolith", 208, Rarity.RARE, mage.cards.j.JadeMonolith.class)); - cards.add(new SetCardInfo("Juggernaut", 209, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); - cards.add(new SetCardInfo("Junun Efreet", 88, Rarity.UNCOMMON, mage.cards.j.JununEfreet.class)); - cards.add(new SetCardInfo("Just Fate", 16, Rarity.COMMON, mage.cards.j.JustFate.class)); - cards.add(new SetCardInfo("Kismet", 17, Rarity.RARE, mage.cards.k.Kismet.class)); - cards.add(new SetCardInfo("Kormus Bell", 210, Rarity.RARE, mage.cards.k.KormusBell.class)); - cards.add(new SetCardInfo("Kudzu", 159, Rarity.UNCOMMON, mage.cards.k.Kudzu.class)); - cards.add(new SetCardInfo("Last Chance", 125, Rarity.RARE, mage.cards.l.LastChance.class)); - cards.add(new SetCardInfo("Lava Flow", 126, Rarity.COMMON, mage.cards.l.LavaFlow.class)); - cards.add(new SetCardInfo("Leeches", 18, Rarity.RARE, mage.cards.l.Leeches.class)); - cards.add(new SetCardInfo("Library of Alexandria", 245, Rarity.RARE, mage.cards.l.LibraryOfAlexandria.class)); - cards.add(new SetCardInfo("Library of Leng", 211, Rarity.COMMON, mage.cards.l.LibraryOfLeng.class)); - cards.add(new SetCardInfo("Lich", 89, Rarity.RARE, mage.cards.l.Lich.class)); - cards.add(new SetCardInfo("Lifeforce", 160, Rarity.RARE, mage.cards.l.Lifeforce.class)); - cards.add(new SetCardInfo("Living Lands", 161, Rarity.RARE, mage.cards.l.LivingLands.class)); - cards.add(new SetCardInfo("Living Wall", 212, Rarity.UNCOMMON, mage.cards.l.LivingWall.class)); - cards.add(new SetCardInfo("Mahamoti Djinn", 52, Rarity.RARE, mage.cards.m.MahamotiDjinn.class)); - cards.add(new SetCardInfo("Mana Matrix", 213, Rarity.RARE, mage.cards.m.ManaMatrix.class)); - cards.add(new SetCardInfo("Mana Vault", 214, Rarity.RARE, mage.cards.m.ManaVault.class)); - cards.add(new SetCardInfo("Martyr's Cry", 19, Rarity.RARE, mage.cards.m.MartyrsCry.class)); - cards.add(new SetCardInfo("Martyrs of Korlis", 20, Rarity.UNCOMMON, mage.cards.m.MartyrsOfKorlis.class)); - cards.add(new SetCardInfo("Maze of Ith", 246, Rarity.RARE, mage.cards.m.MazeOfIth.class)); - cards.add(new SetCardInfo("Mightstone", 215, Rarity.COMMON, mage.cards.m.Mightstone.class)); - cards.add(new SetCardInfo("Mijae Djinn", 127, Rarity.RARE, mage.cards.m.MijaeDjinn.class)); - cards.add(new SetCardInfo("Minion of Tevesh Szat", 91, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); - cards.add(new SetCardInfo("Mishra's Workshop", 247, Rarity.RARE, mage.cards.m.MishrasWorkshop.class)); - cards.add(new SetCardInfo("Mystic Decree", 53, Rarity.UNCOMMON, mage.cards.m.MysticDecree.class)); - cards.add(new SetCardInfo("Naked Singularity", 216, Rarity.RARE, mage.cards.n.NakedSingularity.class)); - cards.add(new SetCardInfo("Oasis", 248, Rarity.COMMON, mage.cards.o.Oasis.class)); - cards.add(new SetCardInfo("Obelisk of Undoing", 217, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); - cards.add(new SetCardInfo("Obsianus Golem", 218, Rarity.COMMON, mage.cards.o.ObsianusGolem.class)); - cards.add(new SetCardInfo("Ogre Taskmaster", 128, Rarity.COMMON, mage.cards.o.OgreTaskmaster.class)); - cards.add(new SetCardInfo("Onulet", 219, Rarity.COMMON, mage.cards.o.Onulet.class)); - cards.add(new SetCardInfo("Orcish Mechanics", 129, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); - cards.add(new SetCardInfo("Osai Vultures", 21, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); - cards.add(new SetCardInfo("Overwhelming Forces", 92, Rarity.RARE, mage.cards.o.OverwhelmingForces.class)); - cards.add(new SetCardInfo("Owl Familiar", 54, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); - cards.add(new SetCardInfo("Pentagram of the Ages", 220, Rarity.UNCOMMON, mage.cards.p.PentagramOfTheAges.class)); - cards.add(new SetCardInfo("Personal Incarnation", 22, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); - cards.add(new SetCardInfo("Phantasmal Forces", 55, Rarity.COMMON, mage.cards.p.PhantasmalForces.class)); - cards.add(new SetCardInfo("Phantasmal Terrain", 56, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); - cards.add(new SetCardInfo("Planar Gate", 221, Rarity.UNCOMMON, mage.cards.p.PlanarGate.class)); - cards.add(new SetCardInfo("Plateau", 249, Rarity.RARE, mage.cards.p.Plateau.class)); - cards.add(new SetCardInfo("Power Artifact", 57, Rarity.RARE, mage.cards.p.PowerArtifact.class)); - cards.add(new SetCardInfo("Primal Clay", 222, Rarity.COMMON, mage.cards.p.PrimalClay.class)); - cards.add(new SetCardInfo("Prodigal Sorcerer", 58, Rarity.UNCOMMON, mage.cards.p.ProdigalSorcerer.class)); - cards.add(new SetCardInfo("Prowling Nightstalker", 93, Rarity.COMMON, mage.cards.p.ProwlingNightstalker.class)); - cards.add(new SetCardInfo("Radjan Spirit", 162, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); - cards.add(new SetCardInfo("Rain of Daggers", 94, Rarity.RARE, mage.cards.r.RainOfDaggers.class)); - cards.add(new SetCardInfo("Rakalite", 223, Rarity.RARE, mage.cards.r.Rakalite.class)); - cards.add(new SetCardInfo("Reconstruction", 59, Rarity.COMMON, mage.cards.r.Reconstruction.class)); - cards.add(new SetCardInfo("Red Elemental Blast", 131, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); - cards.add(new SetCardInfo("Regrowth", 163, Rarity.RARE, mage.cards.r.Regrowth.class)); - cards.add(new SetCardInfo("Righteous Charge", 23, Rarity.COMMON, mage.cards.r.RighteousCharge.class)); - cards.add(new SetCardInfo("Ring of Renewal", 224, Rarity.RARE, mage.cards.r.RingOfRenewal.class)); - cards.add(new SetCardInfo("Roc of Kher Ridges", 132, Rarity.UNCOMMON, mage.cards.r.RocOfKherRidges.class)); - cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class)); - cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class)); - cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class)); - cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class)); - cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class)); - cards.add(new SetCardInfo("Scarecrow", 225, Rarity.UNCOMMON, mage.cards.s.Scarecrow.class)); - cards.add(new SetCardInfo("Scarwood Bandits", 165, Rarity.RARE, mage.cards.s.ScarwoodBandits.class)); - cards.add(new SetCardInfo("Scavenger Folk", 166, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); - cards.add(new SetCardInfo("Scavenging Ghoul", 95, Rarity.UNCOMMON, mage.cards.s.ScavengingGhoul.class)); - cards.add(new SetCardInfo("Scrubland", 251, Rarity.RARE, mage.cards.s.Scrubland.class)); - cards.add(new SetCardInfo("Sea Serpent", 60, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); - cards.add(new SetCardInfo("Sedge Troll", 135, Rarity.RARE, mage.cards.s.SedgeTroll.class)); - cards.add(new SetCardInfo("Sengir Vampire", 96, Rarity.UNCOMMON, mage.cards.s.SengirVampire.class)); - cards.add(new SetCardInfo("Serendib Djinn", 61, Rarity.RARE, mage.cards.s.SerendibDjinn.class)); - cards.add(new SetCardInfo("Serra Angel", 25, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); - cards.add(new SetCardInfo("Serra Aviary", 26, Rarity.UNCOMMON, mage.cards.s.SerraAviary.class)); - cards.add(new SetCardInfo("Serra Bestiary", 27, Rarity.COMMON, mage.cards.s.SerraBestiary.class)); - cards.add(new SetCardInfo("Shapeshifter", 226, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); - cards.add(new SetCardInfo("Shivan Dragon", 136, Rarity.RARE, mage.cards.s.ShivanDragon.class)); - cards.add(new SetCardInfo("Sinkhole", 97, Rarity.RARE, mage.cards.s.Sinkhole.class)); - cards.add(new SetCardInfo("Sleight of Hand", 62, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); - cards.add(new SetCardInfo("Smoke", 137, Rarity.RARE, mage.cards.s.Smoke.class)); - cards.add(new SetCardInfo("Sol Ring", 227, Rarity.RARE, mage.cards.s.SolRing.class)); - cards.add(new SetCardInfo("Soldevi Golem", 228, Rarity.UNCOMMON, mage.cards.s.SoldeviGolem.class)); - cards.add(new SetCardInfo("Soldevi Machinist", 63, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); - cards.add(new SetCardInfo("Soul Shred", 98, Rarity.COMMON, mage.cards.s.SoulShred.class)); - cards.add(new SetCardInfo("Southern Elephant", 167, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); - cards.add(new SetCardInfo("Spotted Griffin", 28, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); - cards.add(new SetCardInfo("Squall", 168, Rarity.UNCOMMON, mage.cards.s.Squall.class)); - cards.add(new SetCardInfo("Staff of Zegon", 229, Rarity.COMMON, mage.cards.s.StaffOfZegon.class)); - cards.add(new SetCardInfo("Stasis", 64, Rarity.RARE, mage.cards.s.Stasis.class)); - cards.add(new SetCardInfo("Steam Catapult", 29, Rarity.RARE, mage.cards.s.SteamCatapult.class)); - cards.add(new SetCardInfo("Strip Mine", 252, Rarity.RARE, mage.cards.s.StripMine.class)); - cards.add(new SetCardInfo("Swords to Plowshares", 30, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); - cards.add(new SetCardInfo("Sylvan Tutor", 169, Rarity.UNCOMMON, mage.cards.s.SylvanTutor.class)); - cards.add(new SetCardInfo("Symbol of Unsummoning", 65, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); - cards.add(new SetCardInfo("Tablet of Epityr", 230, Rarity.COMMON, mage.cards.t.TabletOfEpityr.class)); - cards.add(new SetCardInfo("Taiga", 253, Rarity.RARE, mage.cards.t.Taiga.class)); - cards.add(new SetCardInfo("Talas Researcher", 66, Rarity.UNCOMMON, mage.cards.t.TalasResearcher.class)); - cards.add(new SetCardInfo("Tawnos's Wand", 231, Rarity.COMMON, mage.cards.t.TawnossWand.class)); - cards.add(new SetCardInfo("Tawnos's Weaponry", 232, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); - cards.add(new SetCardInfo("Temple Acolyte", 31, Rarity.COMMON, mage.cards.t.TempleAcolyte.class)); - cards.add(new SetCardInfo("Terror", 99, Rarity.COMMON, mage.cards.t.Terror.class)); - cards.add(new SetCardInfo("Tetravus", 233, Rarity.RARE, mage.cards.t.Tetravus.class)); - cards.add(new SetCardInfo("Theft of Dreams", 67, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); - cards.add(new SetCardInfo("Thing from the Deep", 68, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); - cards.add(new SetCardInfo("Thunder Dragon", 138, Rarity.RARE, mage.cards.t.ThunderDragon.class)); - cards.add(new SetCardInfo("Time Vault", 234, Rarity.RARE, mage.cards.t.TimeVault.class)); - cards.add(new SetCardInfo("Titania's Song", 170, Rarity.RARE, mage.cards.t.TitaniasSong.class)); - cards.add(new SetCardInfo("Transmute Artifact", 69, Rarity.RARE, mage.cards.t.TransmuteArtifact.class)); - cards.add(new SetCardInfo("Triassic Egg", 235, Rarity.RARE, mage.cards.t.TriassicEgg.class)); - cards.add(new SetCardInfo("Tropical Island", 254, Rarity.RARE, mage.cards.t.TropicalIsland.class)); - cards.add(new SetCardInfo("Tsunami", 171, Rarity.RARE, mage.cards.t.Tsunami.class)); - cards.add(new SetCardInfo("Tundra", 255, Rarity.RARE, mage.cards.t.Tundra.class)); - cards.add(new SetCardInfo("Two-Headed Giant of Foriys", 139, Rarity.UNCOMMON, mage.cards.t.TwoHeadedGiantOfForiys.class)); - cards.add(new SetCardInfo("Underground Sea", 256, Rarity.RARE, mage.cards.u.UndergroundSea.class)); - cards.add(new SetCardInfo("Urza's Chalice", 236, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); - cards.add(new SetCardInfo("Urza's Mine", "257a", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257b", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257c", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Mine", "257d", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Miter", 237, Rarity.RARE, mage.cards.u.UrzasMiter.class)); - cards.add(new SetCardInfo("Urza's Power Plant", "258a", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258b", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258c", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Power Plant", "258d", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259a", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259b", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259c", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Urza's Tower", "259d", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Veteran Bodyguard", 32, Rarity.RARE, mage.cards.v.VeteranBodyguard.class)); - cards.add(new SetCardInfo("Vibrating Sphere", 238, Rarity.RARE, mage.cards.v.VibratingSphere.class)); - cards.add(new SetCardInfo("Volcanic Island", 260, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); - cards.add(new SetCardInfo("War Mammoth", 172, Rarity.COMMON, mage.cards.w.WarMammoth.class)); - cards.add(new SetCardInfo("Warp Artifact", 100, Rarity.COMMON, mage.cards.w.WarpArtifact.class)); - cards.add(new SetCardInfo("Water Elemental", 70, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); - cards.add(new SetCardInfo("Weakness", 101, Rarity.COMMON, mage.cards.w.Weakness.class)); - cards.add(new SetCardInfo("Weakstone", 239, Rarity.UNCOMMON, mage.cards.w.Weakstone.class)); - cards.add(new SetCardInfo("Wheel of Fortune", 140, Rarity.RARE, mage.cards.w.WheelOfFortune.class)); - cards.add(new SetCardInfo("Whiptail Wurm", 173, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); - cards.add(new SetCardInfo("White Knight", 33, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); - cards.add(new SetCardInfo("Wicked Pact", 102, Rarity.UNCOMMON, mage.cards.w.WickedPact.class)); - cards.add(new SetCardInfo("Wild Aesthir", 34, Rarity.COMMON, mage.cards.w.WildAesthir.class)); - cards.add(new SetCardInfo("Wild Griffin", 35, Rarity.COMMON, mage.cards.w.WildGriffin.class)); - cards.add(new SetCardInfo("Wild Ox", 174, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); - cards.add(new SetCardInfo("Wood Elemental", 175, Rarity.RARE, mage.cards.w.WoodElemental.class)); - cards.add(new SetCardInfo("Word of Command", 103, Rarity.RARE, mage.cards.w.WordOfCommand.class)); - cards.add(new SetCardInfo("Xenic Poltergeist", 104, Rarity.UNCOMMON, mage.cards.x.XenicPoltergeist.class)); - cards.add(new SetCardInfo("Yotian Soldier", 240, Rarity.COMMON, mage.cards.y.YotianSoldier.class)); - cards.add(new SetCardInfo("Zombie Master", 105, Rarity.UNCOMMON, mage.cards.z.ZombieMaster.class)); - } - - @Override - public List getSpecialLand() { - // ME4 replace all basic lands with special (1 per booster) - // https://mtg.gamepedia.com/Masters_Edition_IV - - if (savedSpecialLand.isEmpty()) { - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Mine"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Power Plant"))); - savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Tower"))); - } - - return new ArrayList<>(savedSpecialLand); - } + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author LevelX2 + */ +public final class MastersEditionIV extends ExpansionSet { + + private static final MastersEditionIV instance = new MastersEditionIV(); + + public static MastersEditionIV getInstance() { + return instance; + } + + protected final List savedSpecialLand = new ArrayList<>(); + + private MastersEditionIV() { + super("Masters Edition IV", "ME4", ExpansionSet.buildDate(2011, 1, 10), SetType.MAGIC_ONLINE); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + this.ratioBoosterSpecialLand = 1; // replace all basic lands + + cards.add(new SetCardInfo("Acid Rain", 36, Rarity.RARE, mage.cards.a.AcidRain.class)); + cards.add(new SetCardInfo("Aesthir Glider", 176, Rarity.COMMON, mage.cards.a.AesthirGlider.class)); + cards.add(new SetCardInfo("Air Elemental", 37, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Al-abara's Carpet", 177, Rarity.RARE, mage.cards.a.AlAbarasCarpet.class)); + cards.add(new SetCardInfo("Alaborn Musketeer", 1, Rarity.COMMON, mage.cards.a.AlabornMusketeer.class)); + cards.add(new SetCardInfo("Alaborn Trooper", 2, Rarity.COMMON, mage.cards.a.AlabornTrooper.class)); + cards.add(new SetCardInfo("Aladdin", 106, Rarity.RARE, mage.cards.a.Aladdin.class)); + cards.add(new SetCardInfo("Alchor's Tomb", 178, Rarity.RARE, mage.cards.a.AlchorsTomb.class)); + cards.add(new SetCardInfo("Ali from Cairo", 107, Rarity.RARE, mage.cards.a.AliFromCairo.class)); + cards.add(new SetCardInfo("Alluring Scent", 141, Rarity.COMMON, mage.cards.a.AlluringScent.class)); + cards.add(new SetCardInfo("Amulet of Kroog", 179, Rarity.COMMON, mage.cards.a.AmuletOfKroog.class)); + cards.add(new SetCardInfo("Angelic Voices", 3, Rarity.UNCOMMON, mage.cards.a.AngelicVoices.class)); + cards.add(new SetCardInfo("Animate Artifact", 38, Rarity.UNCOMMON, mage.cards.a.AnimateArtifact.class)); + cards.add(new SetCardInfo("Argivian Blacksmith", 4, Rarity.UNCOMMON, mage.cards.a.ArgivianBlacksmith.class)); + cards.add(new SetCardInfo("Argothian Pixies", 142, Rarity.COMMON, mage.cards.a.ArgothianPixies.class)); + cards.add(new SetCardInfo("Argothian Treefolk", 143, Rarity.UNCOMMON, mage.cards.a.ArgothianTreefolk.class)); + cards.add(new SetCardInfo("Armageddon Clock", 180, Rarity.RARE, mage.cards.a.ArmageddonClock.class)); + cards.add(new SetCardInfo("Armageddon", 5, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Artifact Blast", 108, Rarity.COMMON, mage.cards.a.ArtifactBlast.class)); + cards.add(new SetCardInfo("Ashnod's Altar", 181, Rarity.RARE, mage.cards.a.AshnodsAltar.class)); + cards.add(new SetCardInfo("Atog", 109, Rarity.COMMON, mage.cards.a.Atog.class)); + cards.add(new SetCardInfo("Badlands", 241, Rarity.RARE, mage.cards.b.Badlands.class)); + cards.add(new SetCardInfo("Balance", 6, Rarity.RARE, mage.cards.b.Balance.class)); + cards.add(new SetCardInfo("Basalt Monolith", 182, Rarity.UNCOMMON, mage.cards.b.BasaltMonolith.class)); + cards.add(new SetCardInfo("Bayou", 242, Rarity.RARE, mage.cards.b.Bayou.class)); + cards.add(new SetCardInfo("Bee Sting", 144, Rarity.UNCOMMON, mage.cards.b.BeeSting.class)); + cards.add(new SetCardInfo("Bird Maiden", 110, Rarity.COMMON, mage.cards.b.BirdMaiden.class)); + cards.add(new SetCardInfo("Black Knight", 71, Rarity.UNCOMMON, mage.cards.b.BlackKnight.class)); + cards.add(new SetCardInfo("Blaze of Glory", 7, Rarity.UNCOMMON, mage.cards.b.BlazeOfGlory.class)); + cards.add(new SetCardInfo("Blue Elemental Blast", 39, Rarity.UNCOMMON, mage.cards.b.BlueElementalBlast.class)); + cards.add(new SetCardInfo("Book of Rass", 183, Rarity.UNCOMMON, mage.cards.b.BookOfRass.class)); + cards.add(new SetCardInfo("Bottle of Suleiman", 184, Rarity.RARE, mage.cards.b.BottleOfSuleiman.class)); + cards.add(new SetCardInfo("Braingeyser", 40, Rarity.RARE, mage.cards.b.Braingeyser.class)); + cards.add(new SetCardInfo("Brass Man", 185, Rarity.COMMON, mage.cards.b.BrassMan.class)); + cards.add(new SetCardInfo("Candelabra of Tawnos", 187, Rarity.RARE, mage.cards.c.CandelabraOfTawnos.class)); + cards.add(new SetCardInfo("Celestial Sword", 188, Rarity.UNCOMMON, mage.cards.c.CelestialSword.class)); + cards.add(new SetCardInfo("Champion Lancer", 8, Rarity.RARE, mage.cards.c.ChampionLancer.class)); + cards.add(new SetCardInfo("Channel", 145, Rarity.RARE, mage.cards.c.Channel.class)); + cards.add(new SetCardInfo("Citanul Druid", 146, Rarity.COMMON, mage.cards.c.CitanulDruid.class)); + cards.add(new SetCardInfo("City of Brass", 243, Rarity.RARE, mage.cards.c.CityOfBrass.class)); + cards.add(new SetCardInfo("Clay Statue", 189, Rarity.UNCOMMON, mage.cards.c.ClayStatue.class)); + cards.add(new SetCardInfo("Clockwork Avian", 190, Rarity.UNCOMMON, mage.cards.c.ClockworkAvian.class)); + cards.add(new SetCardInfo("Clockwork Gnomes", 191, Rarity.UNCOMMON, mage.cards.c.ClockworkGnomes.class)); + cards.add(new SetCardInfo("Clockwork Swarm", 192, Rarity.COMMON, mage.cards.c.ClockworkSwarm.class)); + cards.add(new SetCardInfo("Cloud Dragon", 41, Rarity.RARE, mage.cards.c.CloudDragon.class)); + cards.add(new SetCardInfo("Cloud Spirit", 42, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Colossus of Sardia", 193, Rarity.RARE, mage.cards.c.ColossusOfSardia.class)); + cards.add(new SetCardInfo("Control Magic", 43, Rarity.RARE, mage.cards.c.ControlMagic.class)); + cards.add(new SetCardInfo("Conversion", 9, Rarity.RARE, mage.cards.c.Conversion.class)); + cards.add(new SetCardInfo("Copy Artifact", 44, Rarity.RARE, mage.cards.c.CopyArtifact.class)); + cards.add(new SetCardInfo("Coral Helm", 194, Rarity.UNCOMMON, mage.cards.c.CoralHelm.class)); + cards.add(new SetCardInfo("Counterspell", 45, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crumble", 147, Rarity.COMMON, mage.cards.c.Crumble.class)); + cards.add(new SetCardInfo("Cyclone", 148, Rarity.RARE, mage.cards.c.Cyclone.class)); + cards.add(new SetCardInfo("Cyclopean Mummy", 72, Rarity.COMMON, mage.cards.c.CyclopeanMummy.class)); + cards.add(new SetCardInfo("Cyclopean Tomb", 195, Rarity.RARE, mage.cards.c.CyclopeanTomb.class)); + cards.add(new SetCardInfo("Dakmor Plague", 73, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); + cards.add(new SetCardInfo("Dark Ritual", 74, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Deathcoil Wurm", 149, Rarity.RARE, mage.cards.d.DeathcoilWurm.class)); + cards.add(new SetCardInfo("Deathgrip", 75, Rarity.RARE, mage.cards.d.Deathgrip.class)); + cards.add(new SetCardInfo("Demonic Hordes", 76, Rarity.RARE, mage.cards.d.DemonicHordes.class)); + cards.add(new SetCardInfo("Demonic Tutor", 77, Rarity.RARE, mage.cards.d.DemonicTutor.class)); + cards.add(new SetCardInfo("Detonate", 111, Rarity.UNCOMMON, mage.cards.d.Detonate.class)); + cards.add(new SetCardInfo("Devastation", 112, Rarity.RARE, mage.cards.d.Devastation.class)); + cards.add(new SetCardInfo("Diabolic Machine", 196, Rarity.UNCOMMON, mage.cards.d.DiabolicMachine.class)); + cards.add(new SetCardInfo("Divine Offering", 10, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Dragon Engine", 197, Rarity.COMMON, mage.cards.d.DragonEngine.class)); + cards.add(new SetCardInfo("Drain Power", 46, Rarity.RARE, mage.cards.d.DrainPower.class)); + cards.add(new SetCardInfo("Dread Reaper", 78, Rarity.RARE, mage.cards.d.DreadReaper.class)); + cards.add(new SetCardInfo("Dread Wight", 79, Rarity.UNCOMMON, mage.cards.d.DreadWight.class)); + cards.add(new SetCardInfo("Drop of Honey", 150, Rarity.RARE, mage.cards.d.DropOfHoney.class)); + cards.add(new SetCardInfo("Drowned", 47, Rarity.COMMON, mage.cards.d.Drowned.class)); + cards.add(new SetCardInfo("Dust to Dust", 11, Rarity.UNCOMMON, mage.cards.d.DustToDust.class)); + cards.add(new SetCardInfo("Ebon Dragon", 80, Rarity.RARE, mage.cards.e.EbonDragon.class)); + cards.add(new SetCardInfo("Ebony Horse", 198, Rarity.COMMON, mage.cards.e.EbonyHorse.class)); + cards.add(new SetCardInfo("Ebony Rhino", 199, Rarity.COMMON, mage.cards.e.EbonyRhino.class)); + cards.add(new SetCardInfo("Elephant Graveyard", 244, Rarity.UNCOMMON, mage.cards.e.ElephantGraveyard.class)); + cards.add(new SetCardInfo("Elite Cat Warrior", 151, Rarity.COMMON, mage.cards.e.EliteCatWarrior.class)); + cards.add(new SetCardInfo("Energy Flux", 48, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); + cards.add(new SetCardInfo("Eye for an Eye", 12, Rarity.RARE, mage.cards.e.EyeForAnEye.class)); + cards.add(new SetCardInfo("False Summoning", 49, Rarity.COMMON, mage.cards.f.FalseSummoning.class)); + cards.add(new SetCardInfo("Fastbond", 152, Rarity.RARE, mage.cards.f.Fastbond.class)); + cards.add(new SetCardInfo("Fire Imp", 113, Rarity.UNCOMMON, mage.cards.f.FireImp.class)); + cards.add(new SetCardInfo("Fire Tempest", 114, Rarity.RARE, mage.cards.f.FireTempest.class)); + cards.add(new SetCardInfo("Fireball", 115, Rarity.UNCOMMON, mage.cards.f.Fireball.class)); + cards.add(new SetCardInfo("Floodwater Dam", 200, Rarity.RARE, mage.cards.f.FloodwaterDam.class)); + cards.add(new SetCardInfo("Flying Carpet", 201, Rarity.COMMON, mage.cards.f.FlyingCarpet.class)); + cards.add(new SetCardInfo("Fog", 153, Rarity.COMMON, mage.cards.f.Fog.class)); + cards.add(new SetCardInfo("Force of Nature", 154, Rarity.RARE, mage.cards.f.ForceOfNature.class)); + cards.add(new SetCardInfo("Fork", 116, Rarity.RARE, mage.cards.f.Fork.class)); + cards.add(new SetCardInfo("Foul Spirit", 81, Rarity.COMMON, mage.cards.f.FoulSpirit.class)); + cards.add(new SetCardInfo("Gaea's Avenger", 155, Rarity.UNCOMMON, mage.cards.g.GaeasAvenger.class)); + cards.add(new SetCardInfo("Gate to Phyrexia", 82, Rarity.UNCOMMON, mage.cards.g.GateToPhyrexia.class)); + cards.add(new SetCardInfo("Gauntlet of Might", 202, Rarity.RARE, mage.cards.g.GauntletOfMight.class)); + cards.add(new SetCardInfo("Giant Growth", 156, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Giant Tortoise", 50, Rarity.COMMON, mage.cards.g.GiantTortoise.class)); + cards.add(new SetCardInfo("Glasses of Urza", 203, Rarity.COMMON, mage.cards.g.GlassesOfUrza.class)); + cards.add(new SetCardInfo("Gloom", 83, Rarity.RARE, mage.cards.g.Gloom.class)); + cards.add(new SetCardInfo("Goblin Bully", 117, Rarity.COMMON, mage.cards.g.GoblinBully.class)); + cards.add(new SetCardInfo("Goblin Cavaliers", 118, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); + cards.add(new SetCardInfo("Goblin Caves", 119, Rarity.COMMON, mage.cards.g.GoblinCaves.class)); + cards.add(new SetCardInfo("Goblin Firestarter", 120, Rarity.COMMON, mage.cards.g.GoblinFirestarter.class)); + cards.add(new SetCardInfo("Goblin General", 121, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); + cards.add(new SetCardInfo("Goblin Shrine", 122, Rarity.COMMON, mage.cards.g.GoblinShrine.class)); + cards.add(new SetCardInfo("Goblin Warrens", 123, Rarity.UNCOMMON, mage.cards.g.GoblinWarrens.class)); + cards.add(new SetCardInfo("Gorilla War Cry", 124, Rarity.COMMON, mage.cards.g.GorillaWarCry.class)); + cards.add(new SetCardInfo("Grapeshot Catapult", 204, Rarity.UNCOMMON, mage.cards.g.GrapeshotCatapult.class)); + cards.add(new SetCardInfo("Gravebind", 84, Rarity.COMMON, mage.cards.g.Gravebind.class)); + cards.add(new SetCardInfo("Guardian Beast", 85, Rarity.RARE, mage.cards.g.GuardianBeast.class)); + cards.add(new SetCardInfo("Harsh Justice", 13, Rarity.RARE, mage.cards.h.HarshJustice.class)); + cards.add(new SetCardInfo("Hasran Ogress", 86, Rarity.COMMON, mage.cards.h.HasranOgress.class)); + cards.add(new SetCardInfo("Healing Salve", 14, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Horn of Deafening", 205, Rarity.UNCOMMON, mage.cards.h.HornOfDeafening.class)); + cards.add(new SetCardInfo("Howl from Beyond", 87, Rarity.COMMON, mage.cards.h.HowlFromBeyond.class)); + cards.add(new SetCardInfo("Ice Cauldron", 206, Rarity.RARE, mage.cards.i.IceCauldron.class)); + cards.add(new SetCardInfo("Icy Manipulator", 207, Rarity.UNCOMMON, mage.cards.i.IcyManipulator.class)); + cards.add(new SetCardInfo("In the Eye of Chaos", 51, Rarity.RARE, mage.cards.i.InTheEyeOfChaos.class)); + cards.add(new SetCardInfo("Instill Energy", 157, Rarity.UNCOMMON, mage.cards.i.InstillEnergy.class)); + cards.add(new SetCardInfo("Ironhoof Ox", 158, Rarity.COMMON, mage.cards.i.IronhoofOx.class)); + cards.add(new SetCardInfo("Island Sanctuary", 15, Rarity.RARE, mage.cards.i.IslandSanctuary.class)); + cards.add(new SetCardInfo("Jade Monolith", 208, Rarity.RARE, mage.cards.j.JadeMonolith.class)); + cards.add(new SetCardInfo("Juggernaut", 209, Rarity.UNCOMMON, mage.cards.j.Juggernaut.class)); + cards.add(new SetCardInfo("Junun Efreet", 88, Rarity.UNCOMMON, mage.cards.j.JununEfreet.class)); + cards.add(new SetCardInfo("Just Fate", 16, Rarity.COMMON, mage.cards.j.JustFate.class)); + cards.add(new SetCardInfo("Kismet", 17, Rarity.RARE, mage.cards.k.Kismet.class)); + cards.add(new SetCardInfo("Kormus Bell", 210, Rarity.RARE, mage.cards.k.KormusBell.class)); + cards.add(new SetCardInfo("Kudzu", 159, Rarity.UNCOMMON, mage.cards.k.Kudzu.class)); + cards.add(new SetCardInfo("Last Chance", 125, Rarity.RARE, mage.cards.l.LastChance.class)); + cards.add(new SetCardInfo("Lava Flow", 126, Rarity.COMMON, mage.cards.l.LavaFlow.class)); + cards.add(new SetCardInfo("Leeches", 18, Rarity.RARE, mage.cards.l.Leeches.class)); + cards.add(new SetCardInfo("Library of Alexandria", 245, Rarity.RARE, mage.cards.l.LibraryOfAlexandria.class)); + cards.add(new SetCardInfo("Library of Leng", 211, Rarity.COMMON, mage.cards.l.LibraryOfLeng.class)); + cards.add(new SetCardInfo("Lich", 89, Rarity.RARE, mage.cards.l.Lich.class)); + cards.add(new SetCardInfo("Lifeforce", 160, Rarity.RARE, mage.cards.l.Lifeforce.class)); + cards.add(new SetCardInfo("Lim-Dul's Cohort", 90, Rarity.COMMON, mage.cards.l.LimDulsCohort.class)); + cards.add(new SetCardInfo("Living Lands", 161, Rarity.RARE, mage.cards.l.LivingLands.class)); + cards.add(new SetCardInfo("Living Wall", 212, Rarity.UNCOMMON, mage.cards.l.LivingWall.class)); + cards.add(new SetCardInfo("Mahamoti Djinn", 52, Rarity.RARE, mage.cards.m.MahamotiDjinn.class)); + cards.add(new SetCardInfo("Mana Matrix", 213, Rarity.RARE, mage.cards.m.ManaMatrix.class)); + cards.add(new SetCardInfo("Mana Vault", 214, Rarity.RARE, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Martyr's Cry", 19, Rarity.RARE, mage.cards.m.MartyrsCry.class)); + cards.add(new SetCardInfo("Martyrs of Korlis", 20, Rarity.UNCOMMON, mage.cards.m.MartyrsOfKorlis.class)); + cards.add(new SetCardInfo("Maze of Ith", 246, Rarity.RARE, mage.cards.m.MazeOfIth.class)); + cards.add(new SetCardInfo("Mightstone", 215, Rarity.COMMON, mage.cards.m.Mightstone.class)); + cards.add(new SetCardInfo("Mijae Djinn", 127, Rarity.RARE, mage.cards.m.MijaeDjinn.class)); + cards.add(new SetCardInfo("Minion of Tevesh Szat", 91, Rarity.RARE, mage.cards.m.MinionOfTeveshSzat.class)); + cards.add(new SetCardInfo("Mishra's Workshop", 247, Rarity.RARE, mage.cards.m.MishrasWorkshop.class)); + cards.add(new SetCardInfo("Mystic Decree", 53, Rarity.UNCOMMON, mage.cards.m.MysticDecree.class)); + cards.add(new SetCardInfo("Naked Singularity", 216, Rarity.RARE, mage.cards.n.NakedSingularity.class)); + cards.add(new SetCardInfo("Oasis", 248, Rarity.COMMON, mage.cards.o.Oasis.class)); + cards.add(new SetCardInfo("Obelisk of Undoing", 217, Rarity.RARE, mage.cards.o.ObeliskOfUndoing.class)); + cards.add(new SetCardInfo("Obsianus Golem", 218, Rarity.COMMON, mage.cards.o.ObsianusGolem.class)); + cards.add(new SetCardInfo("Ogre Taskmaster", 128, Rarity.COMMON, mage.cards.o.OgreTaskmaster.class)); + cards.add(new SetCardInfo("Onulet", 219, Rarity.COMMON, mage.cards.o.Onulet.class)); + cards.add(new SetCardInfo("Orcish Mechanics", 129, Rarity.UNCOMMON, mage.cards.o.OrcishMechanics.class)); + cards.add(new SetCardInfo("Osai Vultures", 21, Rarity.COMMON, mage.cards.o.OsaiVultures.class)); + cards.add(new SetCardInfo("Overwhelming Forces", 92, Rarity.RARE, mage.cards.o.OverwhelmingForces.class)); + cards.add(new SetCardInfo("Owl Familiar", 54, Rarity.COMMON, mage.cards.o.OwlFamiliar.class)); + cards.add(new SetCardInfo("Pentagram of the Ages", 220, Rarity.UNCOMMON, mage.cards.p.PentagramOfTheAges.class)); + cards.add(new SetCardInfo("Personal Incarnation", 22, Rarity.RARE, mage.cards.p.PersonalIncarnation.class)); + cards.add(new SetCardInfo("Phantasmal Forces", 55, Rarity.COMMON, mage.cards.p.PhantasmalForces.class)); + cards.add(new SetCardInfo("Phantasmal Terrain", 56, Rarity.COMMON, mage.cards.p.PhantasmalTerrain.class)); + cards.add(new SetCardInfo("Planar Gate", 221, Rarity.UNCOMMON, mage.cards.p.PlanarGate.class)); + cards.add(new SetCardInfo("Plateau", 249, Rarity.RARE, mage.cards.p.Plateau.class)); + cards.add(new SetCardInfo("Power Artifact", 57, Rarity.RARE, mage.cards.p.PowerArtifact.class)); + cards.add(new SetCardInfo("Primal Clay", 222, Rarity.COMMON, mage.cards.p.PrimalClay.class)); + cards.add(new SetCardInfo("Prodigal Sorcerer", 58, Rarity.UNCOMMON, mage.cards.p.ProdigalSorcerer.class)); + cards.add(new SetCardInfo("Prowling Nightstalker", 93, Rarity.COMMON, mage.cards.p.ProwlingNightstalker.class)); + cards.add(new SetCardInfo("Radjan Spirit", 162, Rarity.UNCOMMON, mage.cards.r.RadjanSpirit.class)); + cards.add(new SetCardInfo("Rain of Daggers", 94, Rarity.RARE, mage.cards.r.RainOfDaggers.class)); + cards.add(new SetCardInfo("Rakalite", 223, Rarity.RARE, mage.cards.r.Rakalite.class)); + cards.add(new SetCardInfo("Reconstruction", 59, Rarity.COMMON, mage.cards.r.Reconstruction.class)); + cards.add(new SetCardInfo("Red Elemental Blast", 131, Rarity.UNCOMMON, mage.cards.r.RedElementalBlast.class)); + cards.add(new SetCardInfo("Regrowth", 163, Rarity.RARE, mage.cards.r.Regrowth.class)); + cards.add(new SetCardInfo("Righteous Charge", 23, Rarity.COMMON, mage.cards.r.RighteousCharge.class)); + cards.add(new SetCardInfo("Ring of Renewal", 224, Rarity.RARE, mage.cards.r.RingOfRenewal.class)); + cards.add(new SetCardInfo("Roc of Kher Ridges", 132, Rarity.UNCOMMON, mage.cards.r.RocOfKherRidges.class)); + cards.add(new SetCardInfo("Rock Hydra", 133, Rarity.RARE, mage.cards.r.RockHydra.class)); + cards.add(new SetCardInfo("Rockslide Ambush", 134, Rarity.COMMON, mage.cards.r.RockslideAmbush.class)); + cards.add(new SetCardInfo("Sandstorm", 164, Rarity.COMMON, mage.cards.s.Sandstorm.class)); + cards.add(new SetCardInfo("Savannah Lions", 24, Rarity.UNCOMMON, mage.cards.s.SavannahLions.class)); + cards.add(new SetCardInfo("Savannah", 250, Rarity.RARE, mage.cards.s.Savannah.class)); + cards.add(new SetCardInfo("Scarecrow", 225, Rarity.UNCOMMON, mage.cards.s.Scarecrow.class)); + cards.add(new SetCardInfo("Scarwood Bandits", 165, Rarity.RARE, mage.cards.s.ScarwoodBandits.class)); + cards.add(new SetCardInfo("Scavenger Folk", 166, Rarity.COMMON, mage.cards.s.ScavengerFolk.class)); + cards.add(new SetCardInfo("Scavenging Ghoul", 95, Rarity.UNCOMMON, mage.cards.s.ScavengingGhoul.class)); + cards.add(new SetCardInfo("Scrubland", 251, Rarity.RARE, mage.cards.s.Scrubland.class)); + cards.add(new SetCardInfo("Sea Serpent", 60, Rarity.COMMON, mage.cards.s.SeaSerpent.class)); + cards.add(new SetCardInfo("Sedge Troll", 135, Rarity.RARE, mage.cards.s.SedgeTroll.class)); + cards.add(new SetCardInfo("Sengir Vampire", 96, Rarity.UNCOMMON, mage.cards.s.SengirVampire.class)); + cards.add(new SetCardInfo("Serendib Djinn", 61, Rarity.RARE, mage.cards.s.SerendibDjinn.class)); + cards.add(new SetCardInfo("Serra Angel", 25, Rarity.UNCOMMON, mage.cards.s.SerraAngel.class)); + cards.add(new SetCardInfo("Serra Aviary", 26, Rarity.UNCOMMON, mage.cards.s.SerraAviary.class)); + cards.add(new SetCardInfo("Serra Bestiary", 27, Rarity.COMMON, mage.cards.s.SerraBestiary.class)); + cards.add(new SetCardInfo("Shapeshifter", 226, Rarity.UNCOMMON, mage.cards.s.Shapeshifter.class)); + cards.add(new SetCardInfo("Shivan Dragon", 136, Rarity.RARE, mage.cards.s.ShivanDragon.class)); + cards.add(new SetCardInfo("Sinkhole", 97, Rarity.RARE, mage.cards.s.Sinkhole.class)); + cards.add(new SetCardInfo("Sleight of Hand", 62, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); + cards.add(new SetCardInfo("Smoke", 137, Rarity.RARE, mage.cards.s.Smoke.class)); + cards.add(new SetCardInfo("Sol Ring", 227, Rarity.RARE, mage.cards.s.SolRing.class)); + cards.add(new SetCardInfo("Soldevi Golem", 228, Rarity.UNCOMMON, mage.cards.s.SoldeviGolem.class)); + cards.add(new SetCardInfo("Soldevi Machinist", 63, Rarity.UNCOMMON, mage.cards.s.SoldeviMachinist.class)); + cards.add(new SetCardInfo("Soul Shred", 98, Rarity.COMMON, mage.cards.s.SoulShred.class)); + cards.add(new SetCardInfo("Southern Elephant", 167, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); + cards.add(new SetCardInfo("Spotted Griffin", 28, Rarity.COMMON, mage.cards.s.SpottedGriffin.class)); + cards.add(new SetCardInfo("Squall", 168, Rarity.UNCOMMON, mage.cards.s.Squall.class)); + cards.add(new SetCardInfo("Staff of Zegon", 229, Rarity.COMMON, mage.cards.s.StaffOfZegon.class)); + cards.add(new SetCardInfo("Stasis", 64, Rarity.RARE, mage.cards.s.Stasis.class)); + cards.add(new SetCardInfo("Steam Catapult", 29, Rarity.RARE, mage.cards.s.SteamCatapult.class)); + cards.add(new SetCardInfo("Strip Mine", 252, Rarity.RARE, mage.cards.s.StripMine.class)); + cards.add(new SetCardInfo("Swords to Plowshares", 30, Rarity.UNCOMMON, mage.cards.s.SwordsToPlowshares.class)); + cards.add(new SetCardInfo("Sylvan Tutor", 169, Rarity.UNCOMMON, mage.cards.s.SylvanTutor.class)); + cards.add(new SetCardInfo("Symbol of Unsummoning", 65, Rarity.COMMON, mage.cards.s.SymbolOfUnsummoning.class)); + cards.add(new SetCardInfo("Tablet of Epityr", 230, Rarity.COMMON, mage.cards.t.TabletOfEpityr.class)); + cards.add(new SetCardInfo("Taiga", 253, Rarity.RARE, mage.cards.t.Taiga.class)); + cards.add(new SetCardInfo("Talas Researcher", 66, Rarity.UNCOMMON, mage.cards.t.TalasResearcher.class)); + cards.add(new SetCardInfo("Tawnos's Wand", 231, Rarity.COMMON, mage.cards.t.TawnossWand.class)); + cards.add(new SetCardInfo("Tawnos's Weaponry", 232, Rarity.UNCOMMON, mage.cards.t.TawnossWeaponry.class)); + cards.add(new SetCardInfo("Temple Acolyte", 31, Rarity.COMMON, mage.cards.t.TempleAcolyte.class)); + cards.add(new SetCardInfo("Terror", 99, Rarity.COMMON, mage.cards.t.Terror.class)); + cards.add(new SetCardInfo("Tetravus", 233, Rarity.RARE, mage.cards.t.Tetravus.class)); + cards.add(new SetCardInfo("Theft of Dreams", 67, Rarity.UNCOMMON, mage.cards.t.TheftOfDreams.class)); + cards.add(new SetCardInfo("Thing from the Deep", 68, Rarity.RARE, mage.cards.t.ThingFromTheDeep.class)); + cards.add(new SetCardInfo("Thunder Dragon", 138, Rarity.RARE, mage.cards.t.ThunderDragon.class)); + cards.add(new SetCardInfo("Time Vault", 234, Rarity.RARE, mage.cards.t.TimeVault.class)); + cards.add(new SetCardInfo("Titania's Song", 170, Rarity.RARE, mage.cards.t.TitaniasSong.class)); + cards.add(new SetCardInfo("Transmute Artifact", 69, Rarity.RARE, mage.cards.t.TransmuteArtifact.class)); + cards.add(new SetCardInfo("Triassic Egg", 235, Rarity.RARE, mage.cards.t.TriassicEgg.class)); + cards.add(new SetCardInfo("Tropical Island", 254, Rarity.RARE, mage.cards.t.TropicalIsland.class)); + cards.add(new SetCardInfo("Tsunami", 171, Rarity.RARE, mage.cards.t.Tsunami.class)); + cards.add(new SetCardInfo("Tundra", 255, Rarity.RARE, mage.cards.t.Tundra.class)); + cards.add(new SetCardInfo("Two-Headed Giant of Foriys", 139, Rarity.UNCOMMON, mage.cards.t.TwoHeadedGiantOfForiys.class)); + cards.add(new SetCardInfo("Underground Sea", 256, Rarity.RARE, mage.cards.u.UndergroundSea.class)); + cards.add(new SetCardInfo("Urza's Chalice", 236, Rarity.COMMON, mage.cards.u.UrzasChalice.class)); + cards.add(new SetCardInfo("Urza's Mine", "257a", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257b", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257c", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Mine", "257d", Rarity.COMMON, mage.cards.u.UrzasMine.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Miter", 237, Rarity.RARE, mage.cards.u.UrzasMiter.class)); + cards.add(new SetCardInfo("Urza's Power Plant", "258a", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258b", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258c", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Power Plant", "258d", Rarity.COMMON, mage.cards.u.UrzasPowerPlant.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259a", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259b", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259c", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Urza's Tower", "259d", Rarity.COMMON, mage.cards.u.UrzasTower.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Veteran Bodyguard", 32, Rarity.RARE, mage.cards.v.VeteranBodyguard.class)); + cards.add(new SetCardInfo("Vibrating Sphere", 238, Rarity.RARE, mage.cards.v.VibratingSphere.class)); + cards.add(new SetCardInfo("Volcanic Island", 260, Rarity.RARE, mage.cards.v.VolcanicIsland.class)); + cards.add(new SetCardInfo("War Mammoth", 172, Rarity.COMMON, mage.cards.w.WarMammoth.class)); + cards.add(new SetCardInfo("Warp Artifact", 100, Rarity.COMMON, mage.cards.w.WarpArtifact.class)); + cards.add(new SetCardInfo("Water Elemental", 70, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); + cards.add(new SetCardInfo("Weakness", 101, Rarity.COMMON, mage.cards.w.Weakness.class)); + cards.add(new SetCardInfo("Weakstone", 239, Rarity.UNCOMMON, mage.cards.w.Weakstone.class)); + cards.add(new SetCardInfo("Wheel of Fortune", 140, Rarity.RARE, mage.cards.w.WheelOfFortune.class)); + cards.add(new SetCardInfo("Whiptail Wurm", 173, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); + cards.add(new SetCardInfo("White Knight", 33, Rarity.UNCOMMON, mage.cards.w.WhiteKnight.class)); + cards.add(new SetCardInfo("Wicked Pact", 102, Rarity.UNCOMMON, mage.cards.w.WickedPact.class)); + cards.add(new SetCardInfo("Wild Aesthir", 34, Rarity.COMMON, mage.cards.w.WildAesthir.class)); + cards.add(new SetCardInfo("Wild Griffin", 35, Rarity.COMMON, mage.cards.w.WildGriffin.class)); + cards.add(new SetCardInfo("Wild Ox", 174, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); + cards.add(new SetCardInfo("Wood Elemental", 175, Rarity.RARE, mage.cards.w.WoodElemental.class)); + cards.add(new SetCardInfo("Word of Command", 103, Rarity.RARE, mage.cards.w.WordOfCommand.class)); + cards.add(new SetCardInfo("Xenic Poltergeist", 104, Rarity.UNCOMMON, mage.cards.x.XenicPoltergeist.class)); + cards.add(new SetCardInfo("Yotian Soldier", 240, Rarity.COMMON, mage.cards.y.YotianSoldier.class)); + cards.add(new SetCardInfo("Zombie Master", 105, Rarity.UNCOMMON, mage.cards.z.ZombieMaster.class)); + } + + @Override + public List getSpecialLand() { + // ME4 replace all basic lands with special (1 per booster) + // https://mtg.gamepedia.com/Masters_Edition_IV + + if (savedSpecialLand.isEmpty()) { + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Mine"))); + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Power Plant"))); + savedSpecialLand.addAll(CardRepository.instance.findCards(new CardCriteria().setCodes(this.code).name("Urza's Tower"))); + } + + return new ArrayList<>(savedSpecialLand); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/MercadianMasques.java b/Mage.Sets/src/mage/sets/MercadianMasques.java index a1110e968c..d1ed0a59ca 100644 --- a/Mage.Sets/src/mage/sets/MercadianMasques.java +++ b/Mage.Sets/src/mage/sets/MercadianMasques.java @@ -1,361 +1,364 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author North - */ -public final class MercadianMasques extends ExpansionSet { - - private static final MercadianMasques instance = new MercadianMasques(); - - public static MercadianMasques getInstance() { - return instance; - } - - private MercadianMasques() { - super("Mercadian Masques", "MMQ", ExpansionSet.buildDate(1999, 8, 25), SetType.EXPANSION); - this.blockName = "Masques"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Aerial Caravan", 58, Rarity.RARE, mage.cards.a.AerialCaravan.class)); - cards.add(new SetCardInfo("Afterlife", 1, Rarity.UNCOMMON, mage.cards.a.Afterlife.class)); - cards.add(new SetCardInfo("Alabaster Wall", 2, Rarity.COMMON, mage.cards.a.AlabasterWall.class)); - cards.add(new SetCardInfo("Alley Grifters", 115, Rarity.COMMON, mage.cards.a.AlleyGrifters.class)); - cards.add(new SetCardInfo("Ancestral Mask", 229, Rarity.COMMON, mage.cards.a.AncestralMask.class)); - cards.add(new SetCardInfo("Armistice", 3, Rarity.RARE, mage.cards.a.Armistice.class)); - cards.add(new SetCardInfo("Arms Dealer", 172, Rarity.UNCOMMON, mage.cards.a.ArmsDealer.class)); - cards.add(new SetCardInfo("Arrest", 4, Rarity.UNCOMMON, mage.cards.a.Arrest.class)); - cards.add(new SetCardInfo("Assembly Hall", 286, Rarity.RARE, mage.cards.a.AssemblyHall.class)); - cards.add(new SetCardInfo("Ballista Squad", 5, Rarity.UNCOMMON, mage.cards.b.BallistaSquad.class)); - cards.add(new SetCardInfo("Balloon Peddler", 59, Rarity.COMMON, mage.cards.b.BalloonPeddler.class)); - cards.add(new SetCardInfo("Battle Rampart", 173, Rarity.COMMON, mage.cards.b.BattleRampart.class)); - cards.add(new SetCardInfo("Battle Squadron", 174, Rarity.RARE, mage.cards.b.BattleSquadron.class)); - cards.add(new SetCardInfo("Bifurcate", 230, Rarity.RARE, mage.cards.b.Bifurcate.class)); - cards.add(new SetCardInfo("Black Market", 116, Rarity.RARE, mage.cards.b.BlackMarket.class)); - cards.add(new SetCardInfo("Blaster Mage", 175, Rarity.COMMON, mage.cards.b.BlasterMage.class)); - cards.add(new SetCardInfo("Blockade Runner", 60, Rarity.COMMON, mage.cards.b.BlockadeRunner.class)); - cards.add(new SetCardInfo("Blood Hound", 176, Rarity.RARE, mage.cards.b.BloodHound.class)); - cards.add(new SetCardInfo("Blood Oath", 177, Rarity.RARE, mage.cards.b.BloodOath.class)); - cards.add(new SetCardInfo("Boa Constrictor", 231, Rarity.UNCOMMON, mage.cards.b.BoaConstrictor.class)); - cards.add(new SetCardInfo("Bog Smugglers", 117, Rarity.COMMON, mage.cards.b.BogSmugglers.class)); - cards.add(new SetCardInfo("Bog Witch", 118, Rarity.COMMON, mage.cards.b.BogWitch.class)); - cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); - cards.add(new SetCardInfo("Brawl", 178, Rarity.RARE, mage.cards.b.Brawl.class)); - cards.add(new SetCardInfo("Briar Patch", 232, Rarity.UNCOMMON, mage.cards.b.BriarPatch.class)); - cards.add(new SetCardInfo("Bribery", 62, Rarity.RARE, mage.cards.b.Bribery.class)); - cards.add(new SetCardInfo("Buoyancy", 63, Rarity.COMMON, mage.cards.b.Buoyancy.class)); - cards.add(new SetCardInfo("Cackling Witch", 119, Rarity.UNCOMMON, mage.cards.c.CacklingWitch.class)); - cards.add(new SetCardInfo("Caller of the Hunt", 233, Rarity.RARE, mage.cards.c.CallerOfTheHunt.class)); - cards.add(new SetCardInfo("Cateran Brute", 120, Rarity.COMMON, mage.cards.c.CateranBrute.class)); - cards.add(new SetCardInfo("Cateran Enforcer", 121, Rarity.UNCOMMON, mage.cards.c.CateranEnforcer.class)); - cards.add(new SetCardInfo("Cateran Kidnappers", 122, Rarity.UNCOMMON, mage.cards.c.CateranKidnappers.class)); - cards.add(new SetCardInfo("Cateran Overlord", 123, Rarity.RARE, mage.cards.c.CateranOverlord.class)); - cards.add(new SetCardInfo("Cateran Persuader", 124, Rarity.COMMON, mage.cards.c.CateranPersuader.class)); - cards.add(new SetCardInfo("Cateran Slaver", 125, Rarity.RARE, mage.cards.c.CateranSlaver.class)); - cards.add(new SetCardInfo("Cateran Summons", 126, Rarity.UNCOMMON, mage.cards.c.CateranSummons.class)); - cards.add(new SetCardInfo("Caustic Wasps", 234, Rarity.UNCOMMON, mage.cards.c.CausticWasps.class)); - cards.add(new SetCardInfo("Cave-In", 180, Rarity.RARE, mage.cards.c.CaveIn.class)); - cards.add(new SetCardInfo("Cavern Crawler", 181, Rarity.COMMON, mage.cards.c.CavernCrawler.class)); - cards.add(new SetCardInfo("Cave Sense", 179, Rarity.COMMON, mage.cards.c.CaveSense.class)); - cards.add(new SetCardInfo("Ceremonial Guard", 182, Rarity.COMMON, mage.cards.c.CeremonialGuard.class)); - cards.add(new SetCardInfo("Chambered Nautilus", 64, Rarity.UNCOMMON, mage.cards.c.ChamberedNautilus.class)); - cards.add(new SetCardInfo("Charisma", 66, Rarity.RARE, mage.cards.c.Charisma.class)); - cards.add(new SetCardInfo("Charm Peddler", 6, Rarity.COMMON, mage.cards.c.CharmPeddler.class)); - cards.add(new SetCardInfo("Charmed Griffin", 7, Rarity.UNCOMMON, mage.cards.c.CharmedGriffin.class)); - cards.add(new SetCardInfo("Cho-Arrim Alchemist", 8, Rarity.RARE, mage.cards.c.ChoArrimAlchemist.class)); - cards.add(new SetCardInfo("Cho-Arrim Bruiser", 9, Rarity.RARE, mage.cards.c.ChoArrimBruiser.class)); - cards.add(new SetCardInfo("Cho-Arrim Legate", 10, Rarity.UNCOMMON, mage.cards.c.ChoArrimLegate.class)); - cards.add(new SetCardInfo("Cho-Manno, Revolutionary", 11, Rarity.RARE, mage.cards.c.ChoMannoRevolutionary.class)); - cards.add(new SetCardInfo("Cho-Manno's Blessing", 12, Rarity.COMMON, mage.cards.c.ChoMannosBlessing.class)); - cards.add(new SetCardInfo("Cinder Elemental", 183, Rarity.UNCOMMON, mage.cards.c.CinderElemental.class)); - cards.add(new SetCardInfo("Close Quarters", 184, Rarity.UNCOMMON, mage.cards.c.CloseQuarters.class)); - cards.add(new SetCardInfo("Cloud Sprite", 67, Rarity.COMMON, mage.cards.c.CloudSprite.class)); - cards.add(new SetCardInfo("Coastal Piracy", 68, Rarity.UNCOMMON, mage.cards.c.CoastalPiracy.class)); - cards.add(new SetCardInfo("Collective Unconscious", 236, Rarity.RARE, mage.cards.c.CollectiveUnconscious.class)); - cards.add(new SetCardInfo("Common Cause", 13, Rarity.RARE, mage.cards.c.CommonCause.class)); - cards.add(new SetCardInfo("Conspiracy", 127, Rarity.RARE, mage.cards.c.Conspiracy.class)); - cards.add(new SetCardInfo("Corrupt Official", 128, Rarity.RARE, mage.cards.c.CorruptOfficial.class)); - cards.add(new SetCardInfo("Counterspell", 69, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Cowardice", 70, Rarity.RARE, mage.cards.c.Cowardice.class)); - cards.add(new SetCardInfo("Crackdown", 15, Rarity.RARE, mage.cards.c.Crackdown.class)); - cards.add(new SetCardInfo("Crag Saurian", 185, Rarity.RARE, mage.cards.c.CragSaurian.class)); - cards.add(new SetCardInfo("Crash", 186, Rarity.COMMON, mage.cards.c.Crash.class)); - cards.add(new SetCardInfo("Credit Voucher", 289, Rarity.UNCOMMON, mage.cards.c.CreditVoucher.class)); - cards.add(new SetCardInfo("Crenellated Wall", 290, Rarity.UNCOMMON, mage.cards.c.CrenellatedWall.class)); - cards.add(new SetCardInfo("Crooked Scales", 291, Rarity.RARE, mage.cards.c.CrookedScales.class)); - cards.add(new SetCardInfo("Crossbow Infantry", 16, Rarity.COMMON, mage.cards.c.CrossbowInfantry.class)); - cards.add(new SetCardInfo("Crumbling Sanctuary", 292, Rarity.RARE, mage.cards.c.CrumblingSanctuary.class)); - cards.add(new SetCardInfo("Customs Depot", 71, Rarity.UNCOMMON, mage.cards.c.CustomsDepot.class)); - cards.add(new SetCardInfo("Dark Ritual", 129, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Darting Merfolk", 72, Rarity.COMMON, mage.cards.d.DartingMerfolk.class)); - cards.add(new SetCardInfo("Dawnstrider", 237, Rarity.RARE, mage.cards.d.Dawnstrider.class)); - cards.add(new SetCardInfo("Deadly Insect", 238, Rarity.COMMON, mage.cards.d.DeadlyInsect.class)); - cards.add(new SetCardInfo("Deathgazer", 130, Rarity.UNCOMMON, mage.cards.d.Deathgazer.class)); - cards.add(new SetCardInfo("Deepwood Drummer", 239, Rarity.COMMON, mage.cards.d.DeepwoodDrummer.class)); - cards.add(new SetCardInfo("Deepwood Elder", 240, Rarity.RARE, mage.cards.d.DeepwoodElder.class)); - cards.add(new SetCardInfo("Deepwood Ghoul", 131, Rarity.COMMON, mage.cards.d.DeepwoodGhoul.class)); - cards.add(new SetCardInfo("Deepwood Legate", 132, Rarity.UNCOMMON, mage.cards.d.DeepwoodLegate.class)); - cards.add(new SetCardInfo("Deepwood Tantiv", 241, Rarity.UNCOMMON, mage.cards.d.DeepwoodTantiv.class)); - cards.add(new SetCardInfo("Deepwood Wolverine", 242, Rarity.COMMON, mage.cards.d.DeepwoodWolverine.class)); - cards.add(new SetCardInfo("Dehydration", 73, Rarity.COMMON, mage.cards.d.Dehydration.class)); - cards.add(new SetCardInfo("Delraich", 133, Rarity.RARE, mage.cards.d.Delraich.class)); - cards.add(new SetCardInfo("Desert Twister", 243, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); - cards.add(new SetCardInfo("Devout Witness", 17, Rarity.COMMON, mage.cards.d.DevoutWitness.class)); - cards.add(new SetCardInfo("Diplomatic Escort", 74, Rarity.UNCOMMON, mage.cards.d.DiplomaticEscort.class)); - cards.add(new SetCardInfo("Diplomatic Immunity", 75, Rarity.COMMON, mage.cards.d.DiplomaticImmunity.class)); - cards.add(new SetCardInfo("Disenchant", 18, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Distorting Lens", 293, Rarity.RARE, mage.cards.d.DistortingLens.class)); - cards.add(new SetCardInfo("Drake Hatchling", 76, Rarity.COMMON, mage.cards.d.DrakeHatchling.class)); - cards.add(new SetCardInfo("Dust Bowl", 316, Rarity.RARE, mage.cards.d.DustBowl.class)); - cards.add(new SetCardInfo("Embargo", 77, Rarity.RARE, mage.cards.e.Embargo.class)); - cards.add(new SetCardInfo("Energy Flux", 78, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); - cards.add(new SetCardInfo("Enslaved Horror", 134, Rarity.UNCOMMON, mage.cards.e.EnslavedHorror.class)); - cards.add(new SetCardInfo("Extortion", 135, Rarity.RARE, mage.cards.e.Extortion.class)); - cards.add(new SetCardInfo("Extravagant Spirit", 79, Rarity.RARE, mage.cards.e.ExtravagantSpirit.class)); - cards.add(new SetCardInfo("Eye of Ramos", 294, Rarity.RARE, mage.cards.e.EyeOfRamos.class)); - cards.add(new SetCardInfo("False Demise", 80, Rarity.UNCOMMON, mage.cards.f.FalseDemise.class)); - cards.add(new SetCardInfo("Ferocity", 245, Rarity.COMMON, mage.cards.f.Ferocity.class)); - cards.add(new SetCardInfo("Flailing Manticore", 187, Rarity.RARE, mage.cards.f.FlailingManticore.class)); - cards.add(new SetCardInfo("Flailing Ogre", 188, Rarity.UNCOMMON, mage.cards.f.FlailingOgre.class)); - cards.add(new SetCardInfo("Flailing Soldier", 189, Rarity.COMMON, mage.cards.f.FlailingSoldier.class)); - cards.add(new SetCardInfo("Flaming Sword", 190, Rarity.COMMON, mage.cards.f.FlamingSword.class)); - cards.add(new SetCardInfo("Food Chain", 246, Rarity.RARE, mage.cards.f.FoodChain.class)); - cards.add(new SetCardInfo("Forced March", 136, Rarity.RARE, mage.cards.f.ForcedMarch.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Foster", 247, Rarity.RARE, mage.cards.f.Foster.class)); - cards.add(new SetCardInfo("Fountain of Cho", 317, Rarity.UNCOMMON, mage.cards.f.FountainOfCho.class)); - cards.add(new SetCardInfo("Fountain Watch", 19, Rarity.RARE, mage.cards.f.FountainWatch.class)); - cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class)); - cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class)); - cards.add(new SetCardInfo("Game Preserve", 248, Rarity.RARE, mage.cards.g.GamePreserve.class)); - cards.add(new SetCardInfo("General's Regalia", 295, Rarity.RARE, mage.cards.g.GeneralsRegalia.class)); - cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class)); - cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class)); - cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); - cards.add(new SetCardInfo("Glowing Anemone", 81, Rarity.UNCOMMON, mage.cards.g.GlowingAnemone.class)); - cards.add(new SetCardInfo("Groundskeeper", 250, Rarity.UNCOMMON, mage.cards.g.Groundskeeper.class)); - cards.add(new SetCardInfo("Gush", 82, Rarity.COMMON, mage.cards.g.Gush.class)); - cards.add(new SetCardInfo("Hammer Mage", 193, Rarity.UNCOMMON, mage.cards.h.HammerMage.class)); - cards.add(new SetCardInfo("Haunted Crossroads", 138, Rarity.UNCOMMON, mage.cards.h.HauntedCrossroads.class)); - cards.add(new SetCardInfo("Heart of Ramos", 296, Rarity.RARE, mage.cards.h.HeartOfRamos.class)); - cards.add(new SetCardInfo("Henge Guardian", 297, Rarity.UNCOMMON, mage.cards.h.HengeGuardian.class)); - cards.add(new SetCardInfo("Henge of Ramos", 318, Rarity.UNCOMMON, mage.cards.h.HengeOfRamos.class)); - cards.add(new SetCardInfo("Hickory Woodlot", 319, Rarity.COMMON, mage.cards.h.HickoryWoodlot.class)); - cards.add(new SetCardInfo("High Market", 320, Rarity.RARE, mage.cards.h.HighMarket.class)); - cards.add(new SetCardInfo("High Seas", 83, Rarity.UNCOMMON, mage.cards.h.HighSeas.class)); - cards.add(new SetCardInfo("Highway Robber", 139, Rarity.COMMON, mage.cards.h.HighwayRobber.class)); - cards.add(new SetCardInfo("Hired Giant", 194, Rarity.UNCOMMON, mage.cards.h.HiredGiant.class)); - cards.add(new SetCardInfo("Honor the Fallen", 21, Rarity.RARE, mage.cards.h.HonorTheFallen.class)); - cards.add(new SetCardInfo("Hoodwink", 84, Rarity.COMMON, mage.cards.h.Hoodwink.class)); - cards.add(new SetCardInfo("Horned Troll", 251, Rarity.COMMON, mage.cards.h.HornedTroll.class)); - cards.add(new SetCardInfo("Horn of Plenty", 298, Rarity.RARE, mage.cards.h.HornOfPlenty.class)); - cards.add(new SetCardInfo("Horn of Ramos", 299, Rarity.RARE, mage.cards.h.HornOfRamos.class)); - cards.add(new SetCardInfo("Howling Wolf", 252, Rarity.COMMON, mage.cards.h.HowlingWolf.class)); - cards.add(new SetCardInfo("Hunted Wumpus", 253, Rarity.UNCOMMON, mage.cards.h.HuntedWumpus.class)); - cards.add(new SetCardInfo("Ignoble Soldier", 22, Rarity.UNCOMMON, mage.cards.i.IgnobleSoldier.class)); - cards.add(new SetCardInfo("Indentured Djinn", 85, Rarity.UNCOMMON, mage.cards.i.IndenturedDjinn.class)); - cards.add(new SetCardInfo("Instigator", 140, Rarity.RARE, mage.cards.i.Instigator.class)); - cards.add(new SetCardInfo("Intimidation", 142, Rarity.UNCOMMON, mage.cards.i.Intimidation.class)); - cards.add(new SetCardInfo("Invigorate", 254, Rarity.COMMON, mage.cards.i.Invigorate.class)); - cards.add(new SetCardInfo("Inviolability", 23, Rarity.COMMON, mage.cards.i.Inviolability.class)); - cards.add(new SetCardInfo("Iron Lance", 300, Rarity.UNCOMMON, mage.cards.i.IronLance.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Mask", 24, Rarity.RARE, mage.cards.i.IvoryMask.class)); - cards.add(new SetCardInfo("Jhovall Queen", 25, Rarity.RARE, mage.cards.j.JhovallQueen.class)); - cards.add(new SetCardInfo("Jhovall Rider", 26, Rarity.UNCOMMON, mage.cards.j.JhovallRider.class)); - cards.add(new SetCardInfo("Karn's Touch", 86, Rarity.RARE, mage.cards.k.KarnsTouch.class)); - cards.add(new SetCardInfo("Kris Mage", 195, Rarity.COMMON, mage.cards.k.KrisMage.class)); - cards.add(new SetCardInfo("Kyren Archive", 302, Rarity.RARE, mage.cards.k.KyrenArchive.class)); - cards.add(new SetCardInfo("Kyren Glider", 196, Rarity.COMMON, mage.cards.k.KyrenGlider.class)); - cards.add(new SetCardInfo("Kyren Legate", 197, Rarity.UNCOMMON, mage.cards.k.KyrenLegate.class)); - cards.add(new SetCardInfo("Kyren Negotiations", 198, Rarity.UNCOMMON, mage.cards.k.KyrenNegotiations.class)); - cards.add(new SetCardInfo("Kyren Sniper", 199, Rarity.COMMON, mage.cards.k.KyrenSniper.class)); - cards.add(new SetCardInfo("Kyren Toy", 303, Rarity.RARE, mage.cards.k.KyrenToy.class)); - cards.add(new SetCardInfo("Land Grant", 255, Rarity.COMMON, mage.cards.l.LandGrant.class)); - cards.add(new SetCardInfo("Larceny", 143, Rarity.UNCOMMON, mage.cards.l.Larceny.class)); - cards.add(new SetCardInfo("Last Breath", 27, Rarity.UNCOMMON, mage.cards.l.LastBreath.class)); - cards.add(new SetCardInfo("Lava Runner", 200, Rarity.RARE, mage.cards.l.LavaRunner.class)); - cards.add(new SetCardInfo("Liability", 144, Rarity.RARE, mage.cards.l.Liability.class)); - cards.add(new SetCardInfo("Lightning Hounds", 201, Rarity.COMMON, mage.cards.l.LightningHounds.class)); - cards.add(new SetCardInfo("Lithophage", 202, Rarity.RARE, mage.cards.l.Lithophage.class)); - cards.add(new SetCardInfo("Lumbering Satyr", 257, Rarity.UNCOMMON, mage.cards.l.LumberingSatyr.class)); - cards.add(new SetCardInfo("Lunge", 203, Rarity.COMMON, mage.cards.l.Lunge.class)); - cards.add(new SetCardInfo("Lure", 258, Rarity.UNCOMMON, mage.cards.l.Lure.class)); - cards.add(new SetCardInfo("Maggot Therapy", 145, Rarity.COMMON, mage.cards.m.MaggotTherapy.class)); - cards.add(new SetCardInfo("Magistrate's Scepter", 304, Rarity.RARE, mage.cards.m.MagistratesScepter.class)); - cards.add(new SetCardInfo("Magistrate's Veto", 204, Rarity.UNCOMMON, mage.cards.m.MagistratesVeto.class)); - cards.add(new SetCardInfo("Megatherium", 259, Rarity.RARE, mage.cards.m.Megatherium.class)); - cards.add(new SetCardInfo("Mercadia's Downfall", 205, Rarity.UNCOMMON, mage.cards.m.MercadiasDownfall.class)); - cards.add(new SetCardInfo("Mercadian Atlas", 305, Rarity.RARE, mage.cards.m.MercadianAtlas.class)); - cards.add(new SetCardInfo("Mercadian Bazaar", 321, Rarity.UNCOMMON, mage.cards.m.MercadianBazaar.class)); - cards.add(new SetCardInfo("Midnight Ritual", 146, Rarity.RARE, mage.cards.m.MidnightRitual.class)); - cards.add(new SetCardInfo("Misdirection", 87, Rarity.RARE, mage.cards.m.Misdirection.class)); - cards.add(new SetCardInfo("Misshapen Fiend", 147, Rarity.COMMON, mage.cards.m.MisshapenFiend.class)); - cards.add(new SetCardInfo("Misstep", 88, Rarity.COMMON, mage.cards.m.Misstep.class)); - cards.add(new SetCardInfo("Molting Harpy", 148, Rarity.UNCOMMON, mage.cards.m.MoltingHarpy.class)); - cards.add(new SetCardInfo("Moment of Silence", 28, Rarity.COMMON, mage.cards.m.MomentOfSilence.class)); - cards.add(new SetCardInfo("Monkey Cage", 307, Rarity.RARE, mage.cards.m.MonkeyCage.class)); - cards.add(new SetCardInfo("Moonlit Wake", 29, Rarity.UNCOMMON, mage.cards.m.MoonlitWake.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Muzzle", 30, Rarity.COMMON, mage.cards.m.Muzzle.class)); - cards.add(new SetCardInfo("Natural Affinity", 260, Rarity.RARE, mage.cards.n.NaturalAffinity.class)); - cards.add(new SetCardInfo("Nether Spirit", 149, Rarity.RARE, mage.cards.n.NetherSpirit.class)); - cards.add(new SetCardInfo("Nightwind Glider", 31, Rarity.COMMON, mage.cards.n.NightwindGlider.class)); - cards.add(new SetCardInfo("Noble Purpose", 32, Rarity.UNCOMMON, mage.cards.n.NoblePurpose.class)); - cards.add(new SetCardInfo("Notorious Assassin", 150, Rarity.RARE, mage.cards.n.NotoriousAssassin.class)); - cards.add(new SetCardInfo("Ogre Taskmaster", 206, Rarity.UNCOMMON, mage.cards.o.OgreTaskmaster.class)); - cards.add(new SetCardInfo("Orim's Cure", 33, Rarity.COMMON, mage.cards.o.OrimsCure.class)); - cards.add(new SetCardInfo("Overtaker", 89, Rarity.RARE, mage.cards.o.Overtaker.class)); - cards.add(new SetCardInfo("Panacea", 308, Rarity.UNCOMMON, mage.cards.p.Panacea.class)); - cards.add(new SetCardInfo("Pangosaur", 261, Rarity.RARE, mage.cards.p.Pangosaur.class)); - cards.add(new SetCardInfo("Peat Bog", 322, Rarity.COMMON, mage.cards.p.PeatBog.class)); - cards.add(new SetCardInfo("Pious Warrior", 34, Rarity.COMMON, mage.cards.p.PiousWarrior.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Power Matrix", 309, Rarity.RARE, mage.cards.p.PowerMatrix.class)); - cards.add(new SetCardInfo("Primeval Shambler", 152, Rarity.UNCOMMON, mage.cards.p.PrimevalShambler.class)); - cards.add(new SetCardInfo("Pulverize", 207, Rarity.RARE, mage.cards.p.Pulverize.class)); - cards.add(new SetCardInfo("Putrefaction", 153, Rarity.UNCOMMON, mage.cards.p.Putrefaction.class)); - cards.add(new SetCardInfo("Puppet's Verdict", 208, Rarity.RARE, mage.cards.p.PuppetsVerdict.class)); - cards.add(new SetCardInfo("Quagmire Lamprey", 154, Rarity.UNCOMMON, mage.cards.q.QuagmireLamprey.class)); - cards.add(new SetCardInfo("Rain of Tears", 155, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); - cards.add(new SetCardInfo("Ramosian Captain", 35, Rarity.UNCOMMON, mage.cards.r.RamosianCaptain.class)); - cards.add(new SetCardInfo("Ramosian Commander", 36, Rarity.UNCOMMON, mage.cards.r.RamosianCommander.class)); - cards.add(new SetCardInfo("Ramosian Lieutenant", 37, Rarity.COMMON, mage.cards.r.RamosianLieutenant.class)); - cards.add(new SetCardInfo("Ramosian Rally", 38, Rarity.COMMON, mage.cards.r.RamosianRally.class)); - cards.add(new SetCardInfo("Ramosian Sergeant", 39, Rarity.COMMON, mage.cards.r.RamosianSergeant.class)); - cards.add(new SetCardInfo("Ramosian Sky Marshal", 40, Rarity.RARE, mage.cards.r.RamosianSkyMarshal.class)); - cards.add(new SetCardInfo("Rampart Crawler", 156, Rarity.COMMON, mage.cards.r.RampartCrawler.class)); - cards.add(new SetCardInfo("Rappelling Scouts", 41, Rarity.RARE, mage.cards.r.RappellingScouts.class)); - cards.add(new SetCardInfo("Remote Farm", 323, Rarity.COMMON, mage.cards.r.RemoteFarm.class)); - cards.add(new SetCardInfo("Renounce", 42, Rarity.UNCOMMON, mage.cards.r.Renounce.class)); - cards.add(new SetCardInfo("Revered Elder", 43, Rarity.COMMON, mage.cards.r.ReveredElder.class)); - cards.add(new SetCardInfo("Reverent Mantra", 44, Rarity.RARE, mage.cards.r.ReverentMantra.class)); - cards.add(new SetCardInfo("Revive", 262, Rarity.UNCOMMON, mage.cards.r.Revive.class)); - cards.add(new SetCardInfo("Righteous Aura", 45, Rarity.UNCOMMON, mage.cards.r.RighteousAura.class)); - cards.add(new SetCardInfo("Rishadan Airship", 91, Rarity.COMMON, mage.cards.r.RishadanAirship.class)); - cards.add(new SetCardInfo("Rishadan Brigand", 92, Rarity.RARE, mage.cards.r.RishadanBrigand.class)); - cards.add(new SetCardInfo("Rishadan Cutpurse", 93, Rarity.COMMON, mage.cards.r.RishadanCutpurse.class)); - cards.add(new SetCardInfo("Rishadan Footpad", 94, Rarity.UNCOMMON, mage.cards.r.RishadanFootpad.class)); - cards.add(new SetCardInfo("Rishadan Pawnshop", 311, Rarity.RARE, mage.cards.r.RishadanPawnshop.class)); - cards.add(new SetCardInfo("Rishadan Port", 324, Rarity.RARE, mage.cards.r.RishadanPort.class)); - cards.add(new SetCardInfo("Rock Badger", 210, Rarity.UNCOMMON, mage.cards.r.RockBadger.class)); - cards.add(new SetCardInfo("Rouse", 157, Rarity.COMMON, mage.cards.r.Rouse.class)); - cards.add(new SetCardInfo("Rushwood Dryad", 263, Rarity.COMMON, mage.cards.r.RushwoodDryad.class)); - cards.add(new SetCardInfo("Rushwood Elemental", 264, Rarity.RARE, mage.cards.r.RushwoodElemental.class)); - cards.add(new SetCardInfo("Rushwood Grove", 325, Rarity.UNCOMMON, mage.cards.r.RushwoodGrove.class)); - cards.add(new SetCardInfo("Rushwood Herbalist", 265, Rarity.COMMON, mage.cards.r.RushwoodHerbalist.class)); - cards.add(new SetCardInfo("Rushwood Legate", 266, Rarity.UNCOMMON, mage.cards.r.RushwoodLegate.class)); - cards.add(new SetCardInfo("Saber Ants", 267, Rarity.UNCOMMON, mage.cards.s.SaberAnts.class)); - cards.add(new SetCardInfo("Sacred Prey", 268, Rarity.COMMON, mage.cards.s.SacredPrey.class)); - cards.add(new SetCardInfo("Sailmonger", 95, Rarity.UNCOMMON, mage.cards.s.Sailmonger.class)); - cards.add(new SetCardInfo("Sand Squid", 96, Rarity.RARE, mage.cards.s.SandSquid.class)); - cards.add(new SetCardInfo("Sandstone Needle", 326, Rarity.COMMON, mage.cards.s.SandstoneNeedle.class)); - cards.add(new SetCardInfo("Saprazzan Bailiff", 97, Rarity.RARE, mage.cards.s.SaprazzanBailiff.class)); - cards.add(new SetCardInfo("Saprazzan Breaker", 98, Rarity.UNCOMMON, mage.cards.s.SaprazzanBreaker.class)); - cards.add(new SetCardInfo("Saprazzan Cove", 327, Rarity.UNCOMMON, mage.cards.s.SaprazzanCove.class)); - cards.add(new SetCardInfo("Saprazzan Heir", 99, Rarity.RARE, mage.cards.s.SaprazzanHeir.class)); - cards.add(new SetCardInfo("Saprazzan Legate", 100, Rarity.UNCOMMON, mage.cards.s.SaprazzanLegate.class)); - cards.add(new SetCardInfo("Saprazzan Outrigger", 101, Rarity.COMMON, mage.cards.s.SaprazzanOutrigger.class)); - cards.add(new SetCardInfo("Saprazzan Raider", 102, Rarity.COMMON, mage.cards.s.SaprazzanRaider.class)); - cards.add(new SetCardInfo("Saprazzan Skerry", 328, Rarity.COMMON, mage.cards.s.SaprazzanSkerry.class)); - cards.add(new SetCardInfo("Scandalmonger", 158, Rarity.UNCOMMON, mage.cards.s.Scandalmonger.class)); - cards.add(new SetCardInfo("Security Detail", 47, Rarity.RARE, mage.cards.s.SecurityDetail.class)); - cards.add(new SetCardInfo("Seismic Mage", 211, Rarity.RARE, mage.cards.s.SeismicMage.class)); - cards.add(new SetCardInfo("Sever Soul", 159, Rarity.COMMON, mage.cards.s.SeverSoul.class)); - cards.add(new SetCardInfo("Shock Troops", 212, Rarity.COMMON, mage.cards.s.ShockTroops.class)); - cards.add(new SetCardInfo("Shoving Match", 103, Rarity.UNCOMMON, mage.cards.s.ShovingMatch.class)); - cards.add(new SetCardInfo("Silverglade Elemental", 269, Rarity.COMMON, mage.cards.s.SilvergladeElemental.class)); - cards.add(new SetCardInfo("Silverglade Pathfinder", 270, Rarity.UNCOMMON, mage.cards.s.SilvergladePathfinder.class)); - cards.add(new SetCardInfo("Sizzle", 213, Rarity.COMMON, mage.cards.s.Sizzle.class)); - cards.add(new SetCardInfo("Skulking Fugitive", 161, Rarity.COMMON, mage.cards.s.SkulkingFugitive.class)); - cards.add(new SetCardInfo("Skull of Ramos", 312, Rarity.RARE, mage.cards.s.SkullOfRamos.class)); - cards.add(new SetCardInfo("Snake Pit", 271, Rarity.UNCOMMON, mage.cards.s.SnakePit.class)); - cards.add(new SetCardInfo("Snorting Gahr", 272, Rarity.COMMON, mage.cards.s.SnortingGahr.class)); - cards.add(new SetCardInfo("Snuff Out", 162, Rarity.COMMON, mage.cards.s.SnuffOut.class)); - cards.add(new SetCardInfo("Soothing Balm", 48, Rarity.COMMON, mage.cards.s.SoothingBalm.class)); - cards.add(new SetCardInfo("Soothsaying", 104, Rarity.UNCOMMON, mage.cards.s.Soothsaying.class)); - cards.add(new SetCardInfo("Soul Channeling", 163, Rarity.COMMON, mage.cards.s.SoulChanneling.class)); - cards.add(new SetCardInfo("Specter's Wail", 164, Rarity.COMMON, mage.cards.s.SpectersWail.class)); - cards.add(new SetCardInfo("Spidersilk Armor", 273, Rarity.COMMON, mage.cards.s.SpidersilkArmor.class)); - cards.add(new SetCardInfo("Spiritual Focus", 49, Rarity.RARE, mage.cards.s.SpiritualFocus.class)); - cards.add(new SetCardInfo("Spontaneous Generation", 274, Rarity.RARE, mage.cards.s.SpontaneousGeneration.class)); - cards.add(new SetCardInfo("Squall", 275, Rarity.COMMON, mage.cards.s.Squall.class)); - cards.add(new SetCardInfo("Squallmonger", 276, Rarity.UNCOMMON, mage.cards.s.Squallmonger.class)); - cards.add(new SetCardInfo("Squee, Goblin Nabob", 214, Rarity.RARE, mage.cards.s.SqueeGoblinNabob.class)); - cards.add(new SetCardInfo("Squeeze", 105, Rarity.RARE, mage.cards.s.Squeeze.class)); - cards.add(new SetCardInfo("Stamina", 277, Rarity.UNCOMMON, mage.cards.s.Stamina.class)); - cards.add(new SetCardInfo("Statecraft", 106, Rarity.RARE, mage.cards.s.Statecraft.class)); - cards.add(new SetCardInfo("Steadfast Guard", 50, Rarity.COMMON, mage.cards.s.SteadfastGuard.class)); - cards.add(new SetCardInfo("Stinging Barrier", 107, Rarity.COMMON, mage.cards.s.StingingBarrier.class)); - cards.add(new SetCardInfo("Stone Rain", 215, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Story Circle", 51, Rarity.UNCOMMON, mage.cards.s.StoryCircle.class)); - cards.add(new SetCardInfo("Strongarm Thug", 165, Rarity.UNCOMMON, mage.cards.s.StrongarmThug.class)); - cards.add(new SetCardInfo("Subterranean Hangar", 329, Rarity.UNCOMMON, mage.cards.s.SubterraneanHangar.class)); - cards.add(new SetCardInfo("Sustenance", 278, Rarity.UNCOMMON, mage.cards.s.Sustenance.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Task Force", 52, Rarity.COMMON, mage.cards.t.TaskForce.class)); - cards.add(new SetCardInfo("Tectonic Break", 216, Rarity.RARE, mage.cards.t.TectonicBreak.class)); - cards.add(new SetCardInfo("Territorial Dispute", 217, Rarity.RARE, mage.cards.t.TerritorialDispute.class)); - cards.add(new SetCardInfo("Thermal Glider", 53, Rarity.COMMON, mage.cards.t.ThermalGlider.class)); - cards.add(new SetCardInfo("Thieves' Auction", 218, Rarity.RARE, mage.cards.t.ThievesAuction.class)); - cards.add(new SetCardInfo("Thrashing Wumpus", 166, Rarity.RARE, mage.cards.t.ThrashingWumpus.class)); - cards.add(new SetCardInfo("Thunderclap", 219, Rarity.COMMON, mage.cards.t.Thunderclap.class)); - cards.add(new SetCardInfo("Thwart", 108, Rarity.UNCOMMON, mage.cards.t.Thwart.class)); - cards.add(new SetCardInfo("Tidal Bore", 109, Rarity.COMMON, mage.cards.t.TidalBore.class)); - cards.add(new SetCardInfo("Tidal Kraken", 110, Rarity.RARE, mage.cards.t.TidalKraken.class)); - cards.add(new SetCardInfo("Tiger Claws", 279, Rarity.COMMON, mage.cards.t.TigerClaws.class)); - cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); - cards.add(new SetCardInfo("Tonic Peddler", 54, Rarity.UNCOMMON, mage.cards.t.TonicPeddler.class)); - cards.add(new SetCardInfo("Tooth of Ramos", 313, Rarity.RARE, mage.cards.t.ToothOfRamos.class)); - cards.add(new SetCardInfo("Tower of the Magistrate", 330, Rarity.RARE, mage.cards.t.TowerOfTheMagistrate.class)); - cards.add(new SetCardInfo("Toymaker", 314, Rarity.UNCOMMON, mage.cards.t.Toymaker.class)); - cards.add(new SetCardInfo("Trade Routes", 112, Rarity.RARE, mage.cards.t.TradeRoutes.class)); - cards.add(new SetCardInfo("Tranquility", 280, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Trap Runner", 55, Rarity.UNCOMMON, mage.cards.t.TrapRunner.class)); - cards.add(new SetCardInfo("Tremor", 220, Rarity.COMMON, mage.cards.t.Tremor.class)); - cards.add(new SetCardInfo("Two-Headed Dragon", 221, Rarity.RARE, mage.cards.t.TwoHeadedDragon.class)); - cards.add(new SetCardInfo("Undertaker", 167, Rarity.COMMON, mage.cards.u.Undertaker.class)); - cards.add(new SetCardInfo("Unmask", 168, Rarity.RARE, mage.cards.u.Unmask.class)); - cards.add(new SetCardInfo("Uphill Battle", 222, Rarity.UNCOMMON, mage.cards.u.UphillBattle.class)); - cards.add(new SetCardInfo("Vendetta", 170, Rarity.COMMON, mage.cards.v.Vendetta.class)); - cards.add(new SetCardInfo("Venomous Breath", 281, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); - cards.add(new SetCardInfo("Venomous Dragonfly", 282, Rarity.COMMON, mage.cards.v.VenomousDragonfly.class)); - cards.add(new SetCardInfo("Vernal Equinox", 283, Rarity.RARE, mage.cards.v.VernalEquinox.class)); - cards.add(new SetCardInfo("Vine Dryad", 284, Rarity.RARE, mage.cards.v.VineDryad.class)); - cards.add(new SetCardInfo("Vine Trellis", 285, Rarity.COMMON, mage.cards.v.VineTrellis.class)); - cards.add(new SetCardInfo("Volcanic Wind", 223, Rarity.UNCOMMON, mage.cards.v.VolcanicWind.class)); - cards.add(new SetCardInfo("Wall of Distortion", 171, Rarity.COMMON, mage.cards.w.WallOfDistortion.class)); - cards.add(new SetCardInfo("War Cadence", 224, Rarity.UNCOMMON, mage.cards.w.WarCadence.class)); - cards.add(new SetCardInfo("War Tax", 113, Rarity.UNCOMMON, mage.cards.w.WarTax.class)); - cards.add(new SetCardInfo("Warmonger", 225, Rarity.UNCOMMON, mage.cards.w.Warmonger.class)); - cards.add(new SetCardInfo("Warpath", 226, Rarity.UNCOMMON, mage.cards.w.Warpath.class)); - cards.add(new SetCardInfo("Waterfront Bouncer", 114, Rarity.COMMON, mage.cards.w.WaterfrontBouncer.class)); - cards.add(new SetCardInfo("Wave of Reckoning", 56, Rarity.RARE, mage.cards.w.WaveOfReckoning.class)); - cards.add(new SetCardInfo("Wild Jhovall", 227, Rarity.COMMON, mage.cards.w.WildJhovall.class)); - cards.add(new SetCardInfo("Wishmonger", 57, Rarity.UNCOMMON, mage.cards.w.Wishmonger.class)); - cards.add(new SetCardInfo("Word of Blasting", 228, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); - cards.add(new SetCardInfo("Worry Beads", 315, Rarity.RARE, mage.cards.w.WorryBeads.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class MercadianMasques extends ExpansionSet { + + private static final MercadianMasques instance = new MercadianMasques(); + + public static MercadianMasques getInstance() { + return instance; + } + + private MercadianMasques() { + super("Mercadian Masques", "MMQ", ExpansionSet.buildDate(1999, 8, 25), SetType.EXPANSION); + this.blockName = "Masques"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Aerial Caravan", 58, Rarity.RARE, mage.cards.a.AerialCaravan.class)); + cards.add(new SetCardInfo("Afterlife", 1, Rarity.UNCOMMON, mage.cards.a.Afterlife.class)); + cards.add(new SetCardInfo("Alabaster Wall", 2, Rarity.COMMON, mage.cards.a.AlabasterWall.class)); + cards.add(new SetCardInfo("Alley Grifters", 115, Rarity.COMMON, mage.cards.a.AlleyGrifters.class)); + cards.add(new SetCardInfo("Ancestral Mask", 229, Rarity.COMMON, mage.cards.a.AncestralMask.class)); + cards.add(new SetCardInfo("Armistice", 3, Rarity.RARE, mage.cards.a.Armistice.class)); + cards.add(new SetCardInfo("Arms Dealer", 172, Rarity.UNCOMMON, mage.cards.a.ArmsDealer.class)); + cards.add(new SetCardInfo("Arrest", 4, Rarity.UNCOMMON, mage.cards.a.Arrest.class)); + cards.add(new SetCardInfo("Assembly Hall", 286, Rarity.RARE, mage.cards.a.AssemblyHall.class)); + cards.add(new SetCardInfo("Ballista Squad", 5, Rarity.UNCOMMON, mage.cards.b.BallistaSquad.class)); + cards.add(new SetCardInfo("Balloon Peddler", 59, Rarity.COMMON, mage.cards.b.BalloonPeddler.class)); + cards.add(new SetCardInfo("Battle Rampart", 173, Rarity.COMMON, mage.cards.b.BattleRampart.class)); + cards.add(new SetCardInfo("Battle Squadron", 174, Rarity.RARE, mage.cards.b.BattleSquadron.class)); + cards.add(new SetCardInfo("Bifurcate", 230, Rarity.RARE, mage.cards.b.Bifurcate.class)); + cards.add(new SetCardInfo("Black Market", 116, Rarity.RARE, mage.cards.b.BlackMarket.class)); + cards.add(new SetCardInfo("Blaster Mage", 175, Rarity.COMMON, mage.cards.b.BlasterMage.class)); + cards.add(new SetCardInfo("Blockade Runner", 60, Rarity.COMMON, mage.cards.b.BlockadeRunner.class)); + cards.add(new SetCardInfo("Blood Hound", 176, Rarity.RARE, mage.cards.b.BloodHound.class)); + cards.add(new SetCardInfo("Blood Oath", 177, Rarity.RARE, mage.cards.b.BloodOath.class)); + cards.add(new SetCardInfo("Boa Constrictor", 231, Rarity.UNCOMMON, mage.cards.b.BoaConstrictor.class)); + cards.add(new SetCardInfo("Bog Smugglers", 117, Rarity.COMMON, mage.cards.b.BogSmugglers.class)); + cards.add(new SetCardInfo("Bog Witch", 118, Rarity.COMMON, mage.cards.b.BogWitch.class)); + cards.add(new SetCardInfo("Brainstorm", 61, Rarity.COMMON, mage.cards.b.Brainstorm.class)); + cards.add(new SetCardInfo("Brawl", 178, Rarity.RARE, mage.cards.b.Brawl.class)); + cards.add(new SetCardInfo("Briar Patch", 232, Rarity.UNCOMMON, mage.cards.b.BriarPatch.class)); + cards.add(new SetCardInfo("Bribery", 62, Rarity.RARE, mage.cards.b.Bribery.class)); + cards.add(new SetCardInfo("Buoyancy", 63, Rarity.COMMON, mage.cards.b.Buoyancy.class)); + cards.add(new SetCardInfo("Cackling Witch", 119, Rarity.UNCOMMON, mage.cards.c.CacklingWitch.class)); + cards.add(new SetCardInfo("Caller of the Hunt", 233, Rarity.RARE, mage.cards.c.CallerOfTheHunt.class)); + cards.add(new SetCardInfo("Cateran Brute", 120, Rarity.COMMON, mage.cards.c.CateranBrute.class)); + cards.add(new SetCardInfo("Cateran Enforcer", 121, Rarity.UNCOMMON, mage.cards.c.CateranEnforcer.class)); + cards.add(new SetCardInfo("Cateran Kidnappers", 122, Rarity.UNCOMMON, mage.cards.c.CateranKidnappers.class)); + cards.add(new SetCardInfo("Cateran Overlord", 123, Rarity.RARE, mage.cards.c.CateranOverlord.class)); + cards.add(new SetCardInfo("Cateran Persuader", 124, Rarity.COMMON, mage.cards.c.CateranPersuader.class)); + cards.add(new SetCardInfo("Cateran Slaver", 125, Rarity.RARE, mage.cards.c.CateranSlaver.class)); + cards.add(new SetCardInfo("Cateran Summons", 126, Rarity.UNCOMMON, mage.cards.c.CateranSummons.class)); + cards.add(new SetCardInfo("Caustic Wasps", 234, Rarity.UNCOMMON, mage.cards.c.CausticWasps.class)); + cards.add(new SetCardInfo("Cave-In", 180, Rarity.RARE, mage.cards.c.CaveIn.class)); + cards.add(new SetCardInfo("Cavern Crawler", 181, Rarity.COMMON, mage.cards.c.CavernCrawler.class)); + cards.add(new SetCardInfo("Cave Sense", 179, Rarity.COMMON, mage.cards.c.CaveSense.class)); + cards.add(new SetCardInfo("Ceremonial Guard", 182, Rarity.COMMON, mage.cards.c.CeremonialGuard.class)); + cards.add(new SetCardInfo("Chambered Nautilus", 64, Rarity.UNCOMMON, mage.cards.c.ChamberedNautilus.class)); + cards.add(new SetCardInfo("Charisma", 66, Rarity.RARE, mage.cards.c.Charisma.class)); + cards.add(new SetCardInfo("Charm Peddler", 6, Rarity.COMMON, mage.cards.c.CharmPeddler.class)); + cards.add(new SetCardInfo("Charmed Griffin", 7, Rarity.UNCOMMON, mage.cards.c.CharmedGriffin.class)); + cards.add(new SetCardInfo("Cho-Arrim Alchemist", 8, Rarity.RARE, mage.cards.c.ChoArrimAlchemist.class)); + cards.add(new SetCardInfo("Cho-Arrim Bruiser", 9, Rarity.RARE, mage.cards.c.ChoArrimBruiser.class)); + cards.add(new SetCardInfo("Cho-Arrim Legate", 10, Rarity.UNCOMMON, mage.cards.c.ChoArrimLegate.class)); + cards.add(new SetCardInfo("Cho-Manno, Revolutionary", 11, Rarity.RARE, mage.cards.c.ChoMannoRevolutionary.class)); + cards.add(new SetCardInfo("Cho-Manno's Blessing", 12, Rarity.COMMON, mage.cards.c.ChoMannosBlessing.class)); + cards.add(new SetCardInfo("Cinder Elemental", 183, Rarity.UNCOMMON, mage.cards.c.CinderElemental.class)); + cards.add(new SetCardInfo("Clear the Land", 235, Rarity.RARE, mage.cards.c.ClearTheLand.class)); + cards.add(new SetCardInfo("Close Quarters", 184, Rarity.UNCOMMON, mage.cards.c.CloseQuarters.class)); + cards.add(new SetCardInfo("Cloud Sprite", 67, Rarity.COMMON, mage.cards.c.CloudSprite.class)); + cards.add(new SetCardInfo("Coastal Piracy", 68, Rarity.UNCOMMON, mage.cards.c.CoastalPiracy.class)); + cards.add(new SetCardInfo("Collective Unconscious", 236, Rarity.RARE, mage.cards.c.CollectiveUnconscious.class)); + cards.add(new SetCardInfo("Common Cause", 13, Rarity.RARE, mage.cards.c.CommonCause.class)); + cards.add(new SetCardInfo("Conspiracy", 127, Rarity.RARE, mage.cards.c.Conspiracy.class)); + cards.add(new SetCardInfo("Corrupt Official", 128, Rarity.RARE, mage.cards.c.CorruptOfficial.class)); + cards.add(new SetCardInfo("Counterspell", 69, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Cowardice", 70, Rarity.RARE, mage.cards.c.Cowardice.class)); + cards.add(new SetCardInfo("Crackdown", 15, Rarity.RARE, mage.cards.c.Crackdown.class)); + cards.add(new SetCardInfo("Crag Saurian", 185, Rarity.RARE, mage.cards.c.CragSaurian.class)); + cards.add(new SetCardInfo("Crash", 186, Rarity.COMMON, mage.cards.c.Crash.class)); + cards.add(new SetCardInfo("Credit Voucher", 289, Rarity.UNCOMMON, mage.cards.c.CreditVoucher.class)); + cards.add(new SetCardInfo("Crenellated Wall", 290, Rarity.UNCOMMON, mage.cards.c.CrenellatedWall.class)); + cards.add(new SetCardInfo("Crooked Scales", 291, Rarity.RARE, mage.cards.c.CrookedScales.class)); + cards.add(new SetCardInfo("Crossbow Infantry", 16, Rarity.COMMON, mage.cards.c.CrossbowInfantry.class)); + cards.add(new SetCardInfo("Crumbling Sanctuary", 292, Rarity.RARE, mage.cards.c.CrumblingSanctuary.class)); + cards.add(new SetCardInfo("Customs Depot", 71, Rarity.UNCOMMON, mage.cards.c.CustomsDepot.class)); + cards.add(new SetCardInfo("Dark Ritual", 129, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Darting Merfolk", 72, Rarity.COMMON, mage.cards.d.DartingMerfolk.class)); + cards.add(new SetCardInfo("Dawnstrider", 237, Rarity.RARE, mage.cards.d.Dawnstrider.class)); + cards.add(new SetCardInfo("Deadly Insect", 238, Rarity.COMMON, mage.cards.d.DeadlyInsect.class)); + cards.add(new SetCardInfo("Deathgazer", 130, Rarity.UNCOMMON, mage.cards.d.Deathgazer.class)); + cards.add(new SetCardInfo("Deepwood Drummer", 239, Rarity.COMMON, mage.cards.d.DeepwoodDrummer.class)); + cards.add(new SetCardInfo("Deepwood Elder", 240, Rarity.RARE, mage.cards.d.DeepwoodElder.class)); + cards.add(new SetCardInfo("Deepwood Ghoul", 131, Rarity.COMMON, mage.cards.d.DeepwoodGhoul.class)); + cards.add(new SetCardInfo("Deepwood Legate", 132, Rarity.UNCOMMON, mage.cards.d.DeepwoodLegate.class)); + cards.add(new SetCardInfo("Deepwood Tantiv", 241, Rarity.UNCOMMON, mage.cards.d.DeepwoodTantiv.class)); + cards.add(new SetCardInfo("Deepwood Wolverine", 242, Rarity.COMMON, mage.cards.d.DeepwoodWolverine.class)); + cards.add(new SetCardInfo("Dehydration", 73, Rarity.COMMON, mage.cards.d.Dehydration.class)); + cards.add(new SetCardInfo("Delraich", 133, Rarity.RARE, mage.cards.d.Delraich.class)); + cards.add(new SetCardInfo("Desert Twister", 243, Rarity.UNCOMMON, mage.cards.d.DesertTwister.class)); + cards.add(new SetCardInfo("Devout Witness", 17, Rarity.COMMON, mage.cards.d.DevoutWitness.class)); + cards.add(new SetCardInfo("Diplomatic Escort", 74, Rarity.UNCOMMON, mage.cards.d.DiplomaticEscort.class)); + cards.add(new SetCardInfo("Diplomatic Immunity", 75, Rarity.COMMON, mage.cards.d.DiplomaticImmunity.class)); + cards.add(new SetCardInfo("Disenchant", 18, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Distorting Lens", 293, Rarity.RARE, mage.cards.d.DistortingLens.class)); + cards.add(new SetCardInfo("Drake Hatchling", 76, Rarity.COMMON, mage.cards.d.DrakeHatchling.class)); + cards.add(new SetCardInfo("Dust Bowl", 316, Rarity.RARE, mage.cards.d.DustBowl.class)); + cards.add(new SetCardInfo("Embargo", 77, Rarity.RARE, mage.cards.e.Embargo.class)); + cards.add(new SetCardInfo("Energy Flux", 78, Rarity.UNCOMMON, mage.cards.e.EnergyFlux.class)); + cards.add(new SetCardInfo("Enslaved Horror", 134, Rarity.UNCOMMON, mage.cards.e.EnslavedHorror.class)); + cards.add(new SetCardInfo("Extortion", 135, Rarity.RARE, mage.cards.e.Extortion.class)); + cards.add(new SetCardInfo("Extravagant Spirit", 79, Rarity.RARE, mage.cards.e.ExtravagantSpirit.class)); + cards.add(new SetCardInfo("Eye of Ramos", 294, Rarity.RARE, mage.cards.e.EyeOfRamos.class)); + cards.add(new SetCardInfo("False Demise", 80, Rarity.UNCOMMON, mage.cards.f.FalseDemise.class)); + cards.add(new SetCardInfo("Ferocity", 245, Rarity.COMMON, mage.cards.f.Ferocity.class)); + cards.add(new SetCardInfo("Flailing Manticore", 187, Rarity.RARE, mage.cards.f.FlailingManticore.class)); + cards.add(new SetCardInfo("Flailing Ogre", 188, Rarity.UNCOMMON, mage.cards.f.FlailingOgre.class)); + cards.add(new SetCardInfo("Flailing Soldier", 189, Rarity.COMMON, mage.cards.f.FlailingSoldier.class)); + cards.add(new SetCardInfo("Flaming Sword", 190, Rarity.COMMON, mage.cards.f.FlamingSword.class)); + cards.add(new SetCardInfo("Food Chain", 246, Rarity.RARE, mage.cards.f.FoodChain.class)); + cards.add(new SetCardInfo("Forced March", 136, Rarity.RARE, mage.cards.f.ForcedMarch.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Foster", 247, Rarity.RARE, mage.cards.f.Foster.class)); + cards.add(new SetCardInfo("Fountain of Cho", 317, Rarity.UNCOMMON, mage.cards.f.FountainOfCho.class)); + cards.add(new SetCardInfo("Fountain Watch", 19, Rarity.RARE, mage.cards.f.FountainWatch.class)); + cards.add(new SetCardInfo("Fresh Volunteers", 20, Rarity.COMMON, mage.cards.f.FreshVolunteers.class)); + cards.add(new SetCardInfo("Furious Assault", 191, Rarity.COMMON, mage.cards.f.FuriousAssault.class)); + cards.add(new SetCardInfo("Game Preserve", 248, Rarity.RARE, mage.cards.g.GamePreserve.class)); + cards.add(new SetCardInfo("General's Regalia", 295, Rarity.RARE, mage.cards.g.GeneralsRegalia.class)); + cards.add(new SetCardInfo("Gerrard's Irregulars", 192, Rarity.COMMON, mage.cards.g.GerrardsIrregulars.class)); + cards.add(new SetCardInfo("Ghoul's Feast", 137, Rarity.UNCOMMON, mage.cards.g.GhoulsFeast.class)); + cards.add(new SetCardInfo("Giant Caterpillar", 249, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); + cards.add(new SetCardInfo("Glowing Anemone", 81, Rarity.UNCOMMON, mage.cards.g.GlowingAnemone.class)); + cards.add(new SetCardInfo("Groundskeeper", 250, Rarity.UNCOMMON, mage.cards.g.Groundskeeper.class)); + cards.add(new SetCardInfo("Gush", 82, Rarity.COMMON, mage.cards.g.Gush.class)); + cards.add(new SetCardInfo("Hammer Mage", 193, Rarity.UNCOMMON, mage.cards.h.HammerMage.class)); + cards.add(new SetCardInfo("Haunted Crossroads", 138, Rarity.UNCOMMON, mage.cards.h.HauntedCrossroads.class)); + cards.add(new SetCardInfo("Heart of Ramos", 296, Rarity.RARE, mage.cards.h.HeartOfRamos.class)); + cards.add(new SetCardInfo("Henge Guardian", 297, Rarity.UNCOMMON, mage.cards.h.HengeGuardian.class)); + cards.add(new SetCardInfo("Henge of Ramos", 318, Rarity.UNCOMMON, mage.cards.h.HengeOfRamos.class)); + cards.add(new SetCardInfo("Hickory Woodlot", 319, Rarity.COMMON, mage.cards.h.HickoryWoodlot.class)); + cards.add(new SetCardInfo("High Market", 320, Rarity.RARE, mage.cards.h.HighMarket.class)); + cards.add(new SetCardInfo("High Seas", 83, Rarity.UNCOMMON, mage.cards.h.HighSeas.class)); + cards.add(new SetCardInfo("Highway Robber", 139, Rarity.COMMON, mage.cards.h.HighwayRobber.class)); + cards.add(new SetCardInfo("Hired Giant", 194, Rarity.UNCOMMON, mage.cards.h.HiredGiant.class)); + cards.add(new SetCardInfo("Honor the Fallen", 21, Rarity.RARE, mage.cards.h.HonorTheFallen.class)); + cards.add(new SetCardInfo("Hoodwink", 84, Rarity.COMMON, mage.cards.h.Hoodwink.class)); + cards.add(new SetCardInfo("Horned Troll", 251, Rarity.COMMON, mage.cards.h.HornedTroll.class)); + cards.add(new SetCardInfo("Horn of Plenty", 298, Rarity.RARE, mage.cards.h.HornOfPlenty.class)); + cards.add(new SetCardInfo("Horn of Ramos", 299, Rarity.RARE, mage.cards.h.HornOfRamos.class)); + cards.add(new SetCardInfo("Howling Wolf", 252, Rarity.COMMON, mage.cards.h.HowlingWolf.class)); + cards.add(new SetCardInfo("Hunted Wumpus", 253, Rarity.UNCOMMON, mage.cards.h.HuntedWumpus.class)); + cards.add(new SetCardInfo("Ignoble Soldier", 22, Rarity.UNCOMMON, mage.cards.i.IgnobleSoldier.class)); + cards.add(new SetCardInfo("Indentured Djinn", 85, Rarity.UNCOMMON, mage.cards.i.IndenturedDjinn.class)); + cards.add(new SetCardInfo("Instigator", 140, Rarity.RARE, mage.cards.i.Instigator.class)); + cards.add(new SetCardInfo("Intimidation", 142, Rarity.UNCOMMON, mage.cards.i.Intimidation.class)); + cards.add(new SetCardInfo("Invigorate", 254, Rarity.COMMON, mage.cards.i.Invigorate.class)); + cards.add(new SetCardInfo("Inviolability", 23, Rarity.COMMON, mage.cards.i.Inviolability.class)); + cards.add(new SetCardInfo("Iron Lance", 300, Rarity.UNCOMMON, mage.cards.i.IronLance.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Mask", 24, Rarity.RARE, mage.cards.i.IvoryMask.class)); + cards.add(new SetCardInfo("Jeweled Torque", 301, Rarity.UNCOMMON, mage.cards.j.JeweledTorque.class)); + cards.add(new SetCardInfo("Jhovall Queen", 25, Rarity.RARE, mage.cards.j.JhovallQueen.class)); + cards.add(new SetCardInfo("Jhovall Rider", 26, Rarity.UNCOMMON, mage.cards.j.JhovallRider.class)); + cards.add(new SetCardInfo("Karn's Touch", 86, Rarity.RARE, mage.cards.k.KarnsTouch.class)); + cards.add(new SetCardInfo("Kris Mage", 195, Rarity.COMMON, mage.cards.k.KrisMage.class)); + cards.add(new SetCardInfo("Kyren Archive", 302, Rarity.RARE, mage.cards.k.KyrenArchive.class)); + cards.add(new SetCardInfo("Kyren Glider", 196, Rarity.COMMON, mage.cards.k.KyrenGlider.class)); + cards.add(new SetCardInfo("Kyren Legate", 197, Rarity.UNCOMMON, mage.cards.k.KyrenLegate.class)); + cards.add(new SetCardInfo("Kyren Negotiations", 198, Rarity.UNCOMMON, mage.cards.k.KyrenNegotiations.class)); + cards.add(new SetCardInfo("Kyren Sniper", 199, Rarity.COMMON, mage.cards.k.KyrenSniper.class)); + cards.add(new SetCardInfo("Kyren Toy", 303, Rarity.RARE, mage.cards.k.KyrenToy.class)); + cards.add(new SetCardInfo("Land Grant", 255, Rarity.COMMON, mage.cards.l.LandGrant.class)); + cards.add(new SetCardInfo("Larceny", 143, Rarity.UNCOMMON, mage.cards.l.Larceny.class)); + cards.add(new SetCardInfo("Last Breath", 27, Rarity.UNCOMMON, mage.cards.l.LastBreath.class)); + cards.add(new SetCardInfo("Lava Runner", 200, Rarity.RARE, mage.cards.l.LavaRunner.class)); + cards.add(new SetCardInfo("Liability", 144, Rarity.RARE, mage.cards.l.Liability.class)); + cards.add(new SetCardInfo("Lightning Hounds", 201, Rarity.COMMON, mage.cards.l.LightningHounds.class)); + cards.add(new SetCardInfo("Lithophage", 202, Rarity.RARE, mage.cards.l.Lithophage.class)); + cards.add(new SetCardInfo("Lumbering Satyr", 257, Rarity.UNCOMMON, mage.cards.l.LumberingSatyr.class)); + cards.add(new SetCardInfo("Lunge", 203, Rarity.COMMON, mage.cards.l.Lunge.class)); + cards.add(new SetCardInfo("Lure", 258, Rarity.UNCOMMON, mage.cards.l.Lure.class)); + cards.add(new SetCardInfo("Maggot Therapy", 145, Rarity.COMMON, mage.cards.m.MaggotTherapy.class)); + cards.add(new SetCardInfo("Magistrate's Scepter", 304, Rarity.RARE, mage.cards.m.MagistratesScepter.class)); + cards.add(new SetCardInfo("Magistrate's Veto", 204, Rarity.UNCOMMON, mage.cards.m.MagistratesVeto.class)); + cards.add(new SetCardInfo("Megatherium", 259, Rarity.RARE, mage.cards.m.Megatherium.class)); + cards.add(new SetCardInfo("Mercadia's Downfall", 205, Rarity.UNCOMMON, mage.cards.m.MercadiasDownfall.class)); + cards.add(new SetCardInfo("Mercadian Atlas", 305, Rarity.RARE, mage.cards.m.MercadianAtlas.class)); + cards.add(new SetCardInfo("Mercadian Bazaar", 321, Rarity.UNCOMMON, mage.cards.m.MercadianBazaar.class)); + cards.add(new SetCardInfo("Mercadian Lift", 306, Rarity.RARE, mage.cards.m.MercadianLift.class)); + cards.add(new SetCardInfo("Midnight Ritual", 146, Rarity.RARE, mage.cards.m.MidnightRitual.class)); + cards.add(new SetCardInfo("Misdirection", 87, Rarity.RARE, mage.cards.m.Misdirection.class)); + cards.add(new SetCardInfo("Misshapen Fiend", 147, Rarity.COMMON, mage.cards.m.MisshapenFiend.class)); + cards.add(new SetCardInfo("Misstep", 88, Rarity.COMMON, mage.cards.m.Misstep.class)); + cards.add(new SetCardInfo("Molting Harpy", 148, Rarity.UNCOMMON, mage.cards.m.MoltingHarpy.class)); + cards.add(new SetCardInfo("Moment of Silence", 28, Rarity.COMMON, mage.cards.m.MomentOfSilence.class)); + cards.add(new SetCardInfo("Monkey Cage", 307, Rarity.RARE, mage.cards.m.MonkeyCage.class)); + cards.add(new SetCardInfo("Moonlit Wake", 29, Rarity.UNCOMMON, mage.cards.m.MoonlitWake.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Muzzle", 30, Rarity.COMMON, mage.cards.m.Muzzle.class)); + cards.add(new SetCardInfo("Natural Affinity", 260, Rarity.RARE, mage.cards.n.NaturalAffinity.class)); + cards.add(new SetCardInfo("Nether Spirit", 149, Rarity.RARE, mage.cards.n.NetherSpirit.class)); + cards.add(new SetCardInfo("Nightwind Glider", 31, Rarity.COMMON, mage.cards.n.NightwindGlider.class)); + cards.add(new SetCardInfo("Noble Purpose", 32, Rarity.UNCOMMON, mage.cards.n.NoblePurpose.class)); + cards.add(new SetCardInfo("Notorious Assassin", 150, Rarity.RARE, mage.cards.n.NotoriousAssassin.class)); + cards.add(new SetCardInfo("Ogre Taskmaster", 206, Rarity.UNCOMMON, mage.cards.o.OgreTaskmaster.class)); + cards.add(new SetCardInfo("Orim's Cure", 33, Rarity.COMMON, mage.cards.o.OrimsCure.class)); + cards.add(new SetCardInfo("Overtaker", 89, Rarity.RARE, mage.cards.o.Overtaker.class)); + cards.add(new SetCardInfo("Panacea", 308, Rarity.UNCOMMON, mage.cards.p.Panacea.class)); + cards.add(new SetCardInfo("Pangosaur", 261, Rarity.RARE, mage.cards.p.Pangosaur.class)); + cards.add(new SetCardInfo("Peat Bog", 322, Rarity.COMMON, mage.cards.p.PeatBog.class)); + cards.add(new SetCardInfo("Pious Warrior", 34, Rarity.COMMON, mage.cards.p.PiousWarrior.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Power Matrix", 309, Rarity.RARE, mage.cards.p.PowerMatrix.class)); + cards.add(new SetCardInfo("Primeval Shambler", 152, Rarity.UNCOMMON, mage.cards.p.PrimevalShambler.class)); + cards.add(new SetCardInfo("Pulverize", 207, Rarity.RARE, mage.cards.p.Pulverize.class)); + cards.add(new SetCardInfo("Putrefaction", 153, Rarity.UNCOMMON, mage.cards.p.Putrefaction.class)); + cards.add(new SetCardInfo("Puppet's Verdict", 208, Rarity.RARE, mage.cards.p.PuppetsVerdict.class)); + cards.add(new SetCardInfo("Quagmire Lamprey", 154, Rarity.UNCOMMON, mage.cards.q.QuagmireLamprey.class)); + cards.add(new SetCardInfo("Rain of Tears", 155, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); + cards.add(new SetCardInfo("Ramosian Captain", 35, Rarity.UNCOMMON, mage.cards.r.RamosianCaptain.class)); + cards.add(new SetCardInfo("Ramosian Commander", 36, Rarity.UNCOMMON, mage.cards.r.RamosianCommander.class)); + cards.add(new SetCardInfo("Ramosian Lieutenant", 37, Rarity.COMMON, mage.cards.r.RamosianLieutenant.class)); + cards.add(new SetCardInfo("Ramosian Rally", 38, Rarity.COMMON, mage.cards.r.RamosianRally.class)); + cards.add(new SetCardInfo("Ramosian Sergeant", 39, Rarity.COMMON, mage.cards.r.RamosianSergeant.class)); + cards.add(new SetCardInfo("Ramosian Sky Marshal", 40, Rarity.RARE, mage.cards.r.RamosianSkyMarshal.class)); + cards.add(new SetCardInfo("Rampart Crawler", 156, Rarity.COMMON, mage.cards.r.RampartCrawler.class)); + cards.add(new SetCardInfo("Rappelling Scouts", 41, Rarity.RARE, mage.cards.r.RappellingScouts.class)); + cards.add(new SetCardInfo("Remote Farm", 323, Rarity.COMMON, mage.cards.r.RemoteFarm.class)); + cards.add(new SetCardInfo("Renounce", 42, Rarity.UNCOMMON, mage.cards.r.Renounce.class)); + cards.add(new SetCardInfo("Revered Elder", 43, Rarity.COMMON, mage.cards.r.ReveredElder.class)); + cards.add(new SetCardInfo("Reverent Mantra", 44, Rarity.RARE, mage.cards.r.ReverentMantra.class)); + cards.add(new SetCardInfo("Revive", 262, Rarity.UNCOMMON, mage.cards.r.Revive.class)); + cards.add(new SetCardInfo("Righteous Aura", 45, Rarity.UNCOMMON, mage.cards.r.RighteousAura.class)); + cards.add(new SetCardInfo("Rishadan Airship", 91, Rarity.COMMON, mage.cards.r.RishadanAirship.class)); + cards.add(new SetCardInfo("Rishadan Brigand", 92, Rarity.RARE, mage.cards.r.RishadanBrigand.class)); + cards.add(new SetCardInfo("Rishadan Cutpurse", 93, Rarity.COMMON, mage.cards.r.RishadanCutpurse.class)); + cards.add(new SetCardInfo("Rishadan Footpad", 94, Rarity.UNCOMMON, mage.cards.r.RishadanFootpad.class)); + cards.add(new SetCardInfo("Rishadan Pawnshop", 311, Rarity.RARE, mage.cards.r.RishadanPawnshop.class)); + cards.add(new SetCardInfo("Rishadan Port", 324, Rarity.RARE, mage.cards.r.RishadanPort.class)); + cards.add(new SetCardInfo("Rock Badger", 210, Rarity.UNCOMMON, mage.cards.r.RockBadger.class)); + cards.add(new SetCardInfo("Rouse", 157, Rarity.COMMON, mage.cards.r.Rouse.class)); + cards.add(new SetCardInfo("Rushwood Dryad", 263, Rarity.COMMON, mage.cards.r.RushwoodDryad.class)); + cards.add(new SetCardInfo("Rushwood Elemental", 264, Rarity.RARE, mage.cards.r.RushwoodElemental.class)); + cards.add(new SetCardInfo("Rushwood Grove", 325, Rarity.UNCOMMON, mage.cards.r.RushwoodGrove.class)); + cards.add(new SetCardInfo("Rushwood Herbalist", 265, Rarity.COMMON, mage.cards.r.RushwoodHerbalist.class)); + cards.add(new SetCardInfo("Rushwood Legate", 266, Rarity.UNCOMMON, mage.cards.r.RushwoodLegate.class)); + cards.add(new SetCardInfo("Saber Ants", 267, Rarity.UNCOMMON, mage.cards.s.SaberAnts.class)); + cards.add(new SetCardInfo("Sacred Prey", 268, Rarity.COMMON, mage.cards.s.SacredPrey.class)); + cards.add(new SetCardInfo("Sailmonger", 95, Rarity.UNCOMMON, mage.cards.s.Sailmonger.class)); + cards.add(new SetCardInfo("Sand Squid", 96, Rarity.RARE, mage.cards.s.SandSquid.class)); + cards.add(new SetCardInfo("Sandstone Needle", 326, Rarity.COMMON, mage.cards.s.SandstoneNeedle.class)); + cards.add(new SetCardInfo("Saprazzan Bailiff", 97, Rarity.RARE, mage.cards.s.SaprazzanBailiff.class)); + cards.add(new SetCardInfo("Saprazzan Breaker", 98, Rarity.UNCOMMON, mage.cards.s.SaprazzanBreaker.class)); + cards.add(new SetCardInfo("Saprazzan Cove", 327, Rarity.UNCOMMON, mage.cards.s.SaprazzanCove.class)); + cards.add(new SetCardInfo("Saprazzan Heir", 99, Rarity.RARE, mage.cards.s.SaprazzanHeir.class)); + cards.add(new SetCardInfo("Saprazzan Legate", 100, Rarity.UNCOMMON, mage.cards.s.SaprazzanLegate.class)); + cards.add(new SetCardInfo("Saprazzan Outrigger", 101, Rarity.COMMON, mage.cards.s.SaprazzanOutrigger.class)); + cards.add(new SetCardInfo("Saprazzan Raider", 102, Rarity.COMMON, mage.cards.s.SaprazzanRaider.class)); + cards.add(new SetCardInfo("Saprazzan Skerry", 328, Rarity.COMMON, mage.cards.s.SaprazzanSkerry.class)); + cards.add(new SetCardInfo("Scandalmonger", 158, Rarity.UNCOMMON, mage.cards.s.Scandalmonger.class)); + cards.add(new SetCardInfo("Security Detail", 47, Rarity.RARE, mage.cards.s.SecurityDetail.class)); + cards.add(new SetCardInfo("Seismic Mage", 211, Rarity.RARE, mage.cards.s.SeismicMage.class)); + cards.add(new SetCardInfo("Sever Soul", 159, Rarity.COMMON, mage.cards.s.SeverSoul.class)); + cards.add(new SetCardInfo("Shock Troops", 212, Rarity.COMMON, mage.cards.s.ShockTroops.class)); + cards.add(new SetCardInfo("Shoving Match", 103, Rarity.UNCOMMON, mage.cards.s.ShovingMatch.class)); + cards.add(new SetCardInfo("Silverglade Elemental", 269, Rarity.COMMON, mage.cards.s.SilvergladeElemental.class)); + cards.add(new SetCardInfo("Silverglade Pathfinder", 270, Rarity.UNCOMMON, mage.cards.s.SilvergladePathfinder.class)); + cards.add(new SetCardInfo("Sizzle", 213, Rarity.COMMON, mage.cards.s.Sizzle.class)); + cards.add(new SetCardInfo("Skulking Fugitive", 161, Rarity.COMMON, mage.cards.s.SkulkingFugitive.class)); + cards.add(new SetCardInfo("Skull of Ramos", 312, Rarity.RARE, mage.cards.s.SkullOfRamos.class)); + cards.add(new SetCardInfo("Snake Pit", 271, Rarity.UNCOMMON, mage.cards.s.SnakePit.class)); + cards.add(new SetCardInfo("Snorting Gahr", 272, Rarity.COMMON, mage.cards.s.SnortingGahr.class)); + cards.add(new SetCardInfo("Snuff Out", 162, Rarity.COMMON, mage.cards.s.SnuffOut.class)); + cards.add(new SetCardInfo("Soothing Balm", 48, Rarity.COMMON, mage.cards.s.SoothingBalm.class)); + cards.add(new SetCardInfo("Soothsaying", 104, Rarity.UNCOMMON, mage.cards.s.Soothsaying.class)); + cards.add(new SetCardInfo("Soul Channeling", 163, Rarity.COMMON, mage.cards.s.SoulChanneling.class)); + cards.add(new SetCardInfo("Specter's Wail", 164, Rarity.COMMON, mage.cards.s.SpectersWail.class)); + cards.add(new SetCardInfo("Spidersilk Armor", 273, Rarity.COMMON, mage.cards.s.SpidersilkArmor.class)); + cards.add(new SetCardInfo("Spiritual Focus", 49, Rarity.RARE, mage.cards.s.SpiritualFocus.class)); + cards.add(new SetCardInfo("Spontaneous Generation", 274, Rarity.RARE, mage.cards.s.SpontaneousGeneration.class)); + cards.add(new SetCardInfo("Squall", 275, Rarity.COMMON, mage.cards.s.Squall.class)); + cards.add(new SetCardInfo("Squallmonger", 276, Rarity.UNCOMMON, mage.cards.s.Squallmonger.class)); + cards.add(new SetCardInfo("Squee, Goblin Nabob", 214, Rarity.RARE, mage.cards.s.SqueeGoblinNabob.class)); + cards.add(new SetCardInfo("Squeeze", 105, Rarity.RARE, mage.cards.s.Squeeze.class)); + cards.add(new SetCardInfo("Stamina", 277, Rarity.UNCOMMON, mage.cards.s.Stamina.class)); + cards.add(new SetCardInfo("Statecraft", 106, Rarity.RARE, mage.cards.s.Statecraft.class)); + cards.add(new SetCardInfo("Steadfast Guard", 50, Rarity.COMMON, mage.cards.s.SteadfastGuard.class)); + cards.add(new SetCardInfo("Stinging Barrier", 107, Rarity.COMMON, mage.cards.s.StingingBarrier.class)); + cards.add(new SetCardInfo("Stone Rain", 215, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Story Circle", 51, Rarity.UNCOMMON, mage.cards.s.StoryCircle.class)); + cards.add(new SetCardInfo("Strongarm Thug", 165, Rarity.UNCOMMON, mage.cards.s.StrongarmThug.class)); + cards.add(new SetCardInfo("Subterranean Hangar", 329, Rarity.UNCOMMON, mage.cards.s.SubterraneanHangar.class)); + cards.add(new SetCardInfo("Sustenance", 278, Rarity.UNCOMMON, mage.cards.s.Sustenance.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Task Force", 52, Rarity.COMMON, mage.cards.t.TaskForce.class)); + cards.add(new SetCardInfo("Tectonic Break", 216, Rarity.RARE, mage.cards.t.TectonicBreak.class)); + cards.add(new SetCardInfo("Territorial Dispute", 217, Rarity.RARE, mage.cards.t.TerritorialDispute.class)); + cards.add(new SetCardInfo("Thermal Glider", 53, Rarity.COMMON, mage.cards.t.ThermalGlider.class)); + cards.add(new SetCardInfo("Thieves' Auction", 218, Rarity.RARE, mage.cards.t.ThievesAuction.class)); + cards.add(new SetCardInfo("Thrashing Wumpus", 166, Rarity.RARE, mage.cards.t.ThrashingWumpus.class)); + cards.add(new SetCardInfo("Thunderclap", 219, Rarity.COMMON, mage.cards.t.Thunderclap.class)); + cards.add(new SetCardInfo("Thwart", 108, Rarity.UNCOMMON, mage.cards.t.Thwart.class)); + cards.add(new SetCardInfo("Tidal Bore", 109, Rarity.COMMON, mage.cards.t.TidalBore.class)); + cards.add(new SetCardInfo("Tidal Kraken", 110, Rarity.RARE, mage.cards.t.TidalKraken.class)); + cards.add(new SetCardInfo("Tiger Claws", 279, Rarity.COMMON, mage.cards.t.TigerClaws.class)); + cards.add(new SetCardInfo("Timid Drake", 111, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); + cards.add(new SetCardInfo("Tonic Peddler", 54, Rarity.UNCOMMON, mage.cards.t.TonicPeddler.class)); + cards.add(new SetCardInfo("Tooth of Ramos", 313, Rarity.RARE, mage.cards.t.ToothOfRamos.class)); + cards.add(new SetCardInfo("Tower of the Magistrate", 330, Rarity.RARE, mage.cards.t.TowerOfTheMagistrate.class)); + cards.add(new SetCardInfo("Toymaker", 314, Rarity.UNCOMMON, mage.cards.t.Toymaker.class)); + cards.add(new SetCardInfo("Trade Routes", 112, Rarity.RARE, mage.cards.t.TradeRoutes.class)); + cards.add(new SetCardInfo("Tranquility", 280, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Trap Runner", 55, Rarity.UNCOMMON, mage.cards.t.TrapRunner.class)); + cards.add(new SetCardInfo("Tremor", 220, Rarity.COMMON, mage.cards.t.Tremor.class)); + cards.add(new SetCardInfo("Two-Headed Dragon", 221, Rarity.RARE, mage.cards.t.TwoHeadedDragon.class)); + cards.add(new SetCardInfo("Undertaker", 167, Rarity.COMMON, mage.cards.u.Undertaker.class)); + cards.add(new SetCardInfo("Unmask", 168, Rarity.RARE, mage.cards.u.Unmask.class)); + cards.add(new SetCardInfo("Uphill Battle", 222, Rarity.UNCOMMON, mage.cards.u.UphillBattle.class)); + cards.add(new SetCardInfo("Vendetta", 170, Rarity.COMMON, mage.cards.v.Vendetta.class)); + cards.add(new SetCardInfo("Venomous Breath", 281, Rarity.UNCOMMON, mage.cards.v.VenomousBreath.class)); + cards.add(new SetCardInfo("Venomous Dragonfly", 282, Rarity.COMMON, mage.cards.v.VenomousDragonfly.class)); + cards.add(new SetCardInfo("Vernal Equinox", 283, Rarity.RARE, mage.cards.v.VernalEquinox.class)); + cards.add(new SetCardInfo("Vine Dryad", 284, Rarity.RARE, mage.cards.v.VineDryad.class)); + cards.add(new SetCardInfo("Vine Trellis", 285, Rarity.COMMON, mage.cards.v.VineTrellis.class)); + cards.add(new SetCardInfo("Volcanic Wind", 223, Rarity.UNCOMMON, mage.cards.v.VolcanicWind.class)); + cards.add(new SetCardInfo("Wall of Distortion", 171, Rarity.COMMON, mage.cards.w.WallOfDistortion.class)); + cards.add(new SetCardInfo("War Cadence", 224, Rarity.UNCOMMON, mage.cards.w.WarCadence.class)); + cards.add(new SetCardInfo("War Tax", 113, Rarity.UNCOMMON, mage.cards.w.WarTax.class)); + cards.add(new SetCardInfo("Warmonger", 225, Rarity.UNCOMMON, mage.cards.w.Warmonger.class)); + cards.add(new SetCardInfo("Warpath", 226, Rarity.UNCOMMON, mage.cards.w.Warpath.class)); + cards.add(new SetCardInfo("Waterfront Bouncer", 114, Rarity.COMMON, mage.cards.w.WaterfrontBouncer.class)); + cards.add(new SetCardInfo("Wave of Reckoning", 56, Rarity.RARE, mage.cards.w.WaveOfReckoning.class)); + cards.add(new SetCardInfo("Wild Jhovall", 227, Rarity.COMMON, mage.cards.w.WildJhovall.class)); + cards.add(new SetCardInfo("Wishmonger", 57, Rarity.UNCOMMON, mage.cards.w.Wishmonger.class)); + cards.add(new SetCardInfo("Word of Blasting", 228, Rarity.UNCOMMON, mage.cards.w.WordOfBlasting.class)); + cards.add(new SetCardInfo("Worry Beads", 315, Rarity.RARE, mage.cards.w.WorryBeads.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Mirage.java b/Mage.Sets/src/mage/sets/Mirage.java index 4a45154f42..6e87d40a7c 100644 --- a/Mage.Sets/src/mage/sets/Mirage.java +++ b/Mage.Sets/src/mage/sets/Mirage.java @@ -1,332 +1,344 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author North - */ -public final class Mirage extends ExpansionSet { - - private static final Mirage instance = new Mirage(); - - public static Mirage getInstance() { - return instance; - } - - private Mirage() { - super("Mirage", "MIR", ExpansionSet.buildDate(1996, 8, 21), SetType.EXPANSION); - this.blockName = "Mirage"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - - cards.add(new SetCardInfo("Abyssal Hunter", 103, Rarity.RARE, mage.cards.a.AbyssalHunter.class)); - cards.add(new SetCardInfo("Afiya Grove", 205, Rarity.RARE, mage.cards.a.AfiyaGrove.class)); - cards.add(new SetCardInfo("Afterlife", 1, Rarity.UNCOMMON, mage.cards.a.Afterlife.class)); - cards.add(new SetCardInfo("Agility", 154, Rarity.COMMON, mage.cards.a.Agility.class)); - cards.add(new SetCardInfo("Alarum", 2, Rarity.COMMON, mage.cards.a.Alarum.class)); - cards.add(new SetCardInfo("Aleatory", 155, Rarity.UNCOMMON, mage.cards.a.Aleatory.class)); - cards.add(new SetCardInfo("Amber Prison", 292, Rarity.RARE, mage.cards.a.AmberPrison.class)); - cards.add(new SetCardInfo("Amulet of Unmaking", 293, Rarity.RARE, mage.cards.a.AmuletOfUnmaking.class)); - cards.add(new SetCardInfo("Ancestral Memories", 52, Rarity.RARE, mage.cards.a.AncestralMemories.class)); - cards.add(new SetCardInfo("Armor of Thorns", 206, Rarity.COMMON, mage.cards.a.ArmorOfThorns.class)); - cards.add(new SetCardInfo("Armorer Guildmage", 156, Rarity.COMMON, mage.cards.a.ArmorerGuildmage.class)); - cards.add(new SetCardInfo("Ashen Powder", 104, Rarity.RARE, mage.cards.a.AshenPowder.class)); - cards.add(new SetCardInfo("Asmira, Holy Avenger", 256, Rarity.RARE, mage.cards.a.AsmiraHolyAvenger.class)); - cards.add(new SetCardInfo("Auspicious Ancestor", 3, Rarity.RARE, mage.cards.a.AuspiciousAncestor.class)); - cards.add(new SetCardInfo("Azimaet Drake", 53, Rarity.COMMON, mage.cards.a.AzimaetDrake.class)); - cards.add(new SetCardInfo("Bad River", 324, Rarity.UNCOMMON, mage.cards.b.BadRiver.class)); - cards.add(new SetCardInfo("Barbed Foliage", 207, Rarity.UNCOMMON, mage.cards.b.BarbedFoliage.class)); - cards.add(new SetCardInfo("Barbed-Back Wurm", 105, Rarity.UNCOMMON, mage.cards.b.BarbedBackWurm.class)); - cards.add(new SetCardInfo("Bay Falcon", 54, Rarity.COMMON, mage.cards.b.BayFalcon.class)); - cards.add(new SetCardInfo("Bazaar of Wonders", 55, Rarity.RARE, mage.cards.b.BazaarOfWonders.class)); - cards.add(new SetCardInfo("Benthic Djinn", 257, Rarity.RARE, mage.cards.b.BenthicDjinn.class)); - cards.add(new SetCardInfo("Binding Agony", 106, Rarity.COMMON, mage.cards.b.BindingAgony.class)); - cards.add(new SetCardInfo("Blighted Shaman", 107, Rarity.UNCOMMON, mage.cards.b.BlightedShaman.class)); - cards.add(new SetCardInfo("Blinding Light", 5, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); - cards.add(new SetCardInfo("Blistering Barrier", 159, Rarity.COMMON, mage.cards.b.BlisteringBarrier.class)); - cards.add(new SetCardInfo("Bone Harvest", 108, Rarity.COMMON, mage.cards.b.BoneHarvest.class)); - cards.add(new SetCardInfo("Boomerang", 56, Rarity.COMMON, mage.cards.b.Boomerang.class)); - cards.add(new SetCardInfo("Breathstealer", 109, Rarity.COMMON, mage.cards.b.Breathstealer.class)); - cards.add(new SetCardInfo("Brushwagg", 208, Rarity.RARE, mage.cards.b.Brushwagg.class)); - cards.add(new SetCardInfo("Builder's Bane", 160, Rarity.COMMON, mage.cards.b.BuildersBane.class)); - cards.add(new SetCardInfo("Burning Palm Efreet", 161, Rarity.UNCOMMON, mage.cards.b.BurningPalmEfreet.class)); - cards.add(new SetCardInfo("Burning Shield Askari", 162, Rarity.COMMON, mage.cards.b.BurningShieldAskari.class)); - cards.add(new SetCardInfo("Cadaverous Bloom", 258, Rarity.RARE, mage.cards.c.CadaverousBloom.class)); - cards.add(new SetCardInfo("Cadaverous Knight", 110, Rarity.COMMON, mage.cards.c.CadaverousKnight.class)); - cards.add(new SetCardInfo("Canopy Dragon", 209, Rarity.RARE, mage.cards.c.CanopyDragon.class)); - cards.add(new SetCardInfo("Carrion", 111, Rarity.RARE, mage.cards.c.Carrion.class)); - cards.add(new SetCardInfo("Celestial Dawn", 6, Rarity.RARE, mage.cards.c.CelestialDawn.class)); - cards.add(new SetCardInfo("Cerulean Wyvern", 57, Rarity.UNCOMMON, mage.cards.c.CeruleanWyvern.class)); - cards.add(new SetCardInfo("Chaos Charm", 163, Rarity.COMMON, mage.cards.c.ChaosCharm.class)); - cards.add(new SetCardInfo("Chaosphere", 164, Rarity.RARE, mage.cards.c.Chaosphere.class)); - cards.add(new SetCardInfo("Charcoal Diamond", 296, Rarity.UNCOMMON, mage.cards.c.CharcoalDiamond.class)); - cards.add(new SetCardInfo("Chariot of the Sun", 262, Rarity.UNCOMMON, mage.cards.c.ChariotOfTheSun.class)); - cards.add(new SetCardInfo("Choking Sands", 113, Rarity.COMMON, mage.cards.c.ChokingSands.class)); - cards.add(new SetCardInfo("Cinder Cloud", 165, Rarity.UNCOMMON, mage.cards.c.CinderCloud.class)); - cards.add(new SetCardInfo("Civic Guildmage", 7, Rarity.COMMON, mage.cards.c.CivicGuildmage.class)); - cards.add(new SetCardInfo("Cloak of Invisibility", 58, Rarity.COMMON, mage.cards.c.CloakOfInvisibility.class)); - cards.add(new SetCardInfo("Consuming Ferocity", 166, Rarity.UNCOMMON, mage.cards.c.ConsumingFerocity.class)); - cards.add(new SetCardInfo("Coral Fighters", 59, Rarity.UNCOMMON, mage.cards.c.CoralFighters.class)); - cards.add(new SetCardInfo("Crash of Rhinos", 210, Rarity.COMMON, mage.cards.c.CrashOfRhinos.class)); - cards.add(new SetCardInfo("Crimson Hellkite", 167, Rarity.RARE, mage.cards.c.CrimsonHellkite.class)); - cards.add(new SetCardInfo("Crypt Cobra", 114, Rarity.UNCOMMON, mage.cards.c.CryptCobra.class)); - cards.add(new SetCardInfo("Crystal Golem", 298, Rarity.UNCOMMON, mage.cards.c.CrystalGolem.class)); - cards.add(new SetCardInfo("Crystal Vein", 325, Rarity.UNCOMMON, mage.cards.c.CrystalVein.class)); - cards.add(new SetCardInfo("Cursed Totem", 299, Rarity.RARE, mage.cards.c.CursedTotem.class)); - cards.add(new SetCardInfo("Daring Apprentice", 60, Rarity.RARE, mage.cards.d.DaringApprentice.class)); - cards.add(new SetCardInfo("Dark Banishing", 115, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Dark Ritual", 116, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Dazzling Beauty", 8, Rarity.COMMON, mage.cards.d.DazzlingBeauty.class)); - cards.add(new SetCardInfo("Delirium", 260, Rarity.UNCOMMON, mage.cards.d.Delirium.class)); - cards.add(new SetCardInfo("Dirtwater Wraith", 117, Rarity.COMMON, mage.cards.d.DirtwaterWraith.class)); - cards.add(new SetCardInfo("Disempower", 9, Rarity.COMMON, mage.cards.d.Disempower.class)); - cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dissipate", 61, Rarity.UNCOMMON, mage.cards.d.Dissipate.class)); - cards.add(new SetCardInfo("Divine Offering", 11, Rarity.COMMON, mage.cards.d.DivineOffering.class)); - cards.add(new SetCardInfo("Divine Retribution", 12, Rarity.RARE, mage.cards.d.DivineRetribution.class)); - cards.add(new SetCardInfo("Drain Life", 118, Rarity.COMMON, mage.cards.d.DrainLife.class)); - cards.add(new SetCardInfo("Dread Specter", 119, Rarity.UNCOMMON, mage.cards.d.DreadSpecter.class)); - cards.add(new SetCardInfo("Dream Cache", 62, Rarity.COMMON, mage.cards.d.DreamCache.class)); - cards.add(new SetCardInfo("Dwarven Miner", 169, Rarity.UNCOMMON, mage.cards.d.DwarvenMiner.class)); - cards.add(new SetCardInfo("Dwarven Nomad", 170, Rarity.COMMON, mage.cards.d.DwarvenNomad.class)); - cards.add(new SetCardInfo("Early Harvest", 213, Rarity.RARE, mage.cards.e.EarlyHarvest.class)); - cards.add(new SetCardInfo("Ebony Charm", 120, Rarity.COMMON, mage.cards.e.EbonyCharm.class)); - cards.add(new SetCardInfo("Ekundu Griffin", 13, Rarity.COMMON, mage.cards.e.EkunduGriffin.class)); - cards.add(new SetCardInfo("Elixir of Vitality", 300, Rarity.UNCOMMON, mage.cards.e.ElixirOfVitality.class)); - cards.add(new SetCardInfo("Emberwilde Caliph", 322, Rarity.RARE, mage.cards.e.EmberwildeCaliph.class)); - cards.add(new SetCardInfo("Emberwilde Djinn", 172, Rarity.RARE, mage.cards.e.EmberwildeDjinn.class)); - cards.add(new SetCardInfo("Energy Bolt", 263, Rarity.RARE, mage.cards.e.EnergyBolt.class)); - cards.add(new SetCardInfo("Enfeeblement", 121, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); - cards.add(new SetCardInfo("Enlightened Tutor", 14, Rarity.UNCOMMON, mage.cards.e.EnlightenedTutor.class)); - cards.add(new SetCardInfo("Ersatz Gnomes", 301, Rarity.UNCOMMON, mage.cards.e.ErsatzGnomes.class)); - cards.add(new SetCardInfo("Ethereal Champion", 15, Rarity.RARE, mage.cards.e.EtherealChampion.class)); - cards.add(new SetCardInfo("Fallow Earth", 214, Rarity.UNCOMMON, mage.cards.f.FallowEarth.class)); - cards.add(new SetCardInfo("Favorable Destiny", 16, Rarity.UNCOMMON, mage.cards.f.FavorableDestiny.class)); - cards.add(new SetCardInfo("Femeref Archers", 215, Rarity.UNCOMMON, mage.cards.f.FemerefArchers.class)); - cards.add(new SetCardInfo("Femeref Healer", 17, Rarity.COMMON, mage.cards.f.FemerefHealer.class)); - cards.add(new SetCardInfo("Femeref Knight", 18, Rarity.COMMON, mage.cards.f.FemerefKnight.class)); - cards.add(new SetCardInfo("Femeref Scouts", 19, Rarity.COMMON, mage.cards.f.FemerefScouts.class)); - cards.add(new SetCardInfo("Feral Shadow", 122, Rarity.COMMON, mage.cards.f.FeralShadow.class)); - cards.add(new SetCardInfo("Fetid Horror", 123, Rarity.COMMON, mage.cards.f.FetidHorror.class)); - cards.add(new SetCardInfo("Final Fortune", 173, Rarity.RARE, mage.cards.f.FinalFortune.class)); - cards.add(new SetCardInfo("Fire Diamond", 302, Rarity.UNCOMMON, mage.cards.f.FireDiamond.class)); - cards.add(new SetCardInfo("Firebreathing", 174, Rarity.COMMON, mage.cards.f.Firebreathing.class)); - cards.add(new SetCardInfo("Flame Elemental", 175, Rarity.UNCOMMON, mage.cards.f.FlameElemental.class)); - cards.add(new SetCardInfo("Flare", 176, Rarity.COMMON, mage.cards.f.Flare.class)); - cards.add(new SetCardInfo("Flash", 66, Rarity.RARE, mage.cards.f.Flash.class)); - cards.add(new SetCardInfo("Flood Plain", 326, Rarity.UNCOMMON, mage.cards.f.FloodPlain.class)); - cards.add(new SetCardInfo("Floodgate", 67, Rarity.UNCOMMON, mage.cards.f.Floodgate.class)); - cards.add(new SetCardInfo("Fog", 216, Rarity.COMMON, mage.cards.f.Fog.class)); - cards.add(new SetCardInfo("Foratog", 217, Rarity.UNCOMMON, mage.cards.f.Foratog.class)); - cards.add(new SetCardInfo("Forbidden Crypt", 124, Rarity.RARE, mage.cards.f.ForbiddenCrypt.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forsaken Wastes", 125, Rarity.RARE, mage.cards.f.ForsakenWastes.class)); - cards.add(new SetCardInfo("Frenetic Efreet", 264, Rarity.RARE, mage.cards.f.FreneticEfreet.class)); - cards.add(new SetCardInfo("Giant Mantis", 218, Rarity.COMMON, mage.cards.g.GiantMantis.class)); - cards.add(new SetCardInfo("Gibbering Hyenas", 219, Rarity.COMMON, mage.cards.g.GibberingHyenas.class)); - cards.add(new SetCardInfo("Goblin Elite Infantry", 177, Rarity.COMMON, mage.cards.g.GoblinEliteInfantry.class)); - cards.add(new SetCardInfo("Goblin Scouts", 178, Rarity.UNCOMMON, mage.cards.g.GoblinScouts.class)); - cards.add(new SetCardInfo("Goblin Soothsayer", 179, Rarity.UNCOMMON, mage.cards.g.GoblinSoothsayer.class)); - cards.add(new SetCardInfo("Goblin Tinkerer", 180, Rarity.COMMON, mage.cards.g.GoblinTinkerer.class)); - cards.add(new SetCardInfo("Granger Guildmage", 220, Rarity.COMMON, mage.cards.g.GrangerGuildmage.class)); - cards.add(new SetCardInfo("Grasslands", 327, Rarity.UNCOMMON, mage.cards.g.Grasslands.class)); - cards.add(new SetCardInfo("Grave Servitude", 126, Rarity.COMMON, mage.cards.g.GraveServitude.class)); - cards.add(new SetCardInfo("Gravebane Zombie", 127, Rarity.COMMON, mage.cards.g.GravebaneZombie.class)); - cards.add(new SetCardInfo("Grim Feast", 265, Rarity.RARE, mage.cards.g.GrimFeast.class)); - cards.add(new SetCardInfo("Grinning Totem", 303, Rarity.RARE, mage.cards.g.GrinningTotem.class)); - cards.add(new SetCardInfo("Hakim, Loreweaver", 68, Rarity.RARE, mage.cards.h.HakimLoreweaver.class)); - cards.add(new SetCardInfo("Hall of Gemstone", 221, Rarity.RARE, mage.cards.h.HallOfGemstone.class)); - cards.add(new SetCardInfo("Hammer of Bogardan", 181, Rarity.RARE, mage.cards.h.HammerOfBogardan.class)); - cards.add(new SetCardInfo("Harbinger of Night", 128, Rarity.RARE, mage.cards.h.HarbingerOfNight.class)); - cards.add(new SetCardInfo("Harbor Guardian", 266, Rarity.UNCOMMON, mage.cards.h.HarborGuardian.class)); - cards.add(new SetCardInfo("Harmattan Efreet", 69, Rarity.UNCOMMON, mage.cards.h.HarmattanEfreet.class)); - cards.add(new SetCardInfo("Hazerider Drake", 268, Rarity.UNCOMMON, mage.cards.h.HazeriderDrake.class)); - cards.add(new SetCardInfo("Healing Salve", 20, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Hivis of the Scale", 182, Rarity.RARE, mage.cards.h.HivisOfTheScale.class)); - cards.add(new SetCardInfo("Horrible Hordes", 304, Rarity.UNCOMMON, mage.cards.h.HorribleHordes.class)); - cards.add(new SetCardInfo("Igneous Golem", 305, Rarity.UNCOMMON, mage.cards.i.IgneousGolem.class)); - cards.add(new SetCardInfo("Illicit Auction", 183, Rarity.RARE, mage.cards.i.IllicitAuction.class)); - cards.add(new SetCardInfo("Illumination", 21, Rarity.UNCOMMON, mage.cards.i.Illumination.class)); - cards.add(new SetCardInfo("Incinerate", 184, Rarity.COMMON, mage.cards.i.Incinerate.class)); - cards.add(new SetCardInfo("Infernal Contract", 129, Rarity.RARE, mage.cards.i.InfernalContract.class)); - cards.add(new SetCardInfo("Iron Tusk Elephant", 22, Rarity.UNCOMMON, mage.cards.i.IronTuskElephant.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Ivory Charm", 23, Rarity.COMMON, mage.cards.i.IvoryCharm.class)); - cards.add(new SetCardInfo("Jolrael's Centaur", 222, Rarity.COMMON, mage.cards.j.JolraelsCentaur.class)); - cards.add(new SetCardInfo("Jolt", 70, Rarity.COMMON, mage.cards.j.Jolt.class)); - cards.add(new SetCardInfo("Jungle Patrol", 223, Rarity.RARE, mage.cards.j.JunglePatrol.class)); - cards.add(new SetCardInfo("Jungle Troll", 269, Rarity.UNCOMMON, mage.cards.j.JungleTroll.class)); - cards.add(new SetCardInfo("Jungle Wurm", 224, Rarity.COMMON, mage.cards.j.JungleWurm.class)); - cards.add(new SetCardInfo("Kaervek's Hex", 130, Rarity.UNCOMMON, mage.cards.k.KaerveksHex.class)); - cards.add(new SetCardInfo("Kaervek's Purge", 270, Rarity.UNCOMMON, mage.cards.k.KaerveksPurge.class)); - cards.add(new SetCardInfo("Kaervek's Torch", 185, Rarity.COMMON, mage.cards.k.KaerveksTorch.class)); - cards.add(new SetCardInfo("Karoo Meerkat", 225, Rarity.UNCOMMON, mage.cards.k.KarooMeerkat.class)); - cards.add(new SetCardInfo("Kukemssa Pirates", 71, Rarity.RARE, mage.cards.k.KukemssaPirates.class)); - cards.add(new SetCardInfo("Kukemssa Serpent", 72, Rarity.COMMON, mage.cards.k.KukemssaSerpent.class)); - cards.add(new SetCardInfo("Lead Golem", 306, Rarity.UNCOMMON, mage.cards.l.LeadGolem.class)); - cards.add(new SetCardInfo("Leering Gargoyle", 271, Rarity.RARE, mage.cards.l.LeeringGargoyle.class)); - cards.add(new SetCardInfo("Lightning Reflexes", 186, Rarity.COMMON, mage.cards.l.LightningReflexes.class)); - cards.add(new SetCardInfo("Lion's Eye Diamond", 307, Rarity.RARE, mage.cards.l.LionsEyeDiamond.class)); - cards.add(new SetCardInfo("Locust Swarm", 226, Rarity.UNCOMMON, mage.cards.l.LocustSwarm.class)); - cards.add(new SetCardInfo("Lure of Prey", 227, Rarity.RARE, mage.cards.l.LureOfPrey.class)); - cards.add(new SetCardInfo("Mana Prism", 308, Rarity.UNCOMMON, mage.cards.m.ManaPrism.class)); - cards.add(new SetCardInfo("Mangara's Tome", 309, Rarity.RARE, mage.cards.m.MangarasTome.class)); - cards.add(new SetCardInfo("Marble Diamond", 310, Rarity.UNCOMMON, mage.cards.m.MarbleDiamond.class)); - cards.add(new SetCardInfo("Maro", 228, Rarity.RARE, mage.cards.m.Maro.class)); - cards.add(new SetCardInfo("Melesse Spirit", 27, Rarity.UNCOMMON, mage.cards.m.MelesseSpirit.class)); - cards.add(new SetCardInfo("Memory Lapse", 74, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); - cards.add(new SetCardInfo("Merfolk Raiders", 75, Rarity.COMMON, mage.cards.m.MerfolkRaiders.class)); - cards.add(new SetCardInfo("Merfolk Seer", 76, Rarity.COMMON, mage.cards.m.MerfolkSeer.class)); - cards.add(new SetCardInfo("Mind Harness", 78, Rarity.UNCOMMON, mage.cards.m.MindHarness.class)); - cards.add(new SetCardInfo("Mire Shade", 131, Rarity.UNCOMMON, mage.cards.m.MireShade.class)); - cards.add(new SetCardInfo("Misers' Cage", 311, Rarity.RARE, mage.cards.m.MisersCage.class)); - cards.add(new SetCardInfo("Mist Dragon", 79, Rarity.RARE, mage.cards.m.MistDragon.class)); - cards.add(new SetCardInfo("Moss Diamond", 312, Rarity.UNCOMMON, mage.cards.m.MossDiamond.class)); - cards.add(new SetCardInfo("Mountain Valley", 328, Rarity.UNCOMMON, mage.cards.m.MountainValley.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mtenda Griffin", 28, Rarity.UNCOMMON, mage.cards.m.MtendaGriffin.class)); - cards.add(new SetCardInfo("Mtenda Herder", 29, Rarity.COMMON, mage.cards.m.MtendaHerder.class)); - cards.add(new SetCardInfo("Mystical Tutor", 80, Rarity.UNCOMMON, mage.cards.m.MysticalTutor.class)); - cards.add(new SetCardInfo("Natural Balance", 231, Rarity.RARE, mage.cards.n.NaturalBalance.class)); - cards.add(new SetCardInfo("Nettletooth Djinn", 232, Rarity.UNCOMMON, mage.cards.n.NettletoothDjinn.class)); - cards.add(new SetCardInfo("Noble Elephant", 30, Rarity.COMMON, mage.cards.n.NobleElephant.class)); - cards.add(new SetCardInfo("Nocturnal Raid", 132, Rarity.UNCOMMON, mage.cards.n.NocturnalRaid.class)); - cards.add(new SetCardInfo("Pacifism", 32, Rarity.COMMON, mage.cards.p.Pacifism.class)); - cards.add(new SetCardInfo("Painful Memories", 133, Rarity.UNCOMMON, mage.cards.p.PainfulMemories.class)); - cards.add(new SetCardInfo("Patagia Golem", 313, Rarity.UNCOMMON, mage.cards.p.PatagiaGolem.class)); - cards.add(new SetCardInfo("Paupers' Cage", 314, Rarity.RARE, mage.cards.p.PaupersCage.class)); - cards.add(new SetCardInfo("Pearl Dragon", 33, Rarity.RARE, mage.cards.p.PearlDragon.class)); - cards.add(new SetCardInfo("Phyrexian Dreadnought", 315, Rarity.RARE, mage.cards.p.PhyrexianDreadnought.class)); - cards.add(new SetCardInfo("Phyrexian Purge", 273, Rarity.RARE, mage.cards.p.PhyrexianPurge.class)); - cards.add(new SetCardInfo("Phyrexian Tribute", 134, Rarity.RARE, mage.cards.p.PhyrexianTribute.class)); - cards.add(new SetCardInfo("Phyrexian Vault", 316, Rarity.UNCOMMON, mage.cards.p.PhyrexianVault.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Political Trickery", 81, Rarity.RARE, mage.cards.p.PoliticalTrickery.class)); - cards.add(new SetCardInfo("Polymorph", 82, Rarity.RARE, mage.cards.p.Polymorph.class)); - cards.add(new SetCardInfo("Power Sink", 83, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Prismatic Circle", 34, Rarity.COMMON, mage.cards.p.PrismaticCircle.class)); - cards.add(new SetCardInfo("Prismatic Lace", 84, Rarity.RARE, mage.cards.p.PrismaticLace.class)); - cards.add(new SetCardInfo("Psychic Transfer", 85, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); - cards.add(new SetCardInfo("Purgatory", 275, Rarity.RARE, mage.cards.p.Purgatory.class)); - cards.add(new SetCardInfo("Purraj of Urborg", 135, Rarity.RARE, mage.cards.p.PurrajOfUrborg.class)); - cards.add(new SetCardInfo("Pyric Salamander", 187, Rarity.COMMON, mage.cards.p.PyricSalamander.class)); - cards.add(new SetCardInfo("Quirion Elves", 234, Rarity.COMMON, mage.cards.q.QuirionElves.class)); - cards.add(new SetCardInfo("Radiant Essence", 276, Rarity.UNCOMMON, mage.cards.r.RadiantEssence.class)); - cards.add(new SetCardInfo("Raging Spirit", 188, Rarity.COMMON, mage.cards.r.RagingSpirit.class)); - cards.add(new SetCardInfo("Rampant Growth", 235, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); - cards.add(new SetCardInfo("Rashida Scalebane", 35, Rarity.RARE, mage.cards.r.RashidaScalebane.class)); - cards.add(new SetCardInfo("Ravenous Vampire", 136, Rarity.UNCOMMON, mage.cards.r.RavenousVampire.class)); - cards.add(new SetCardInfo("Ray of Command", 86, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); - cards.add(new SetCardInfo("Reality Ripple", 87, Rarity.COMMON, mage.cards.r.RealityRipple.class)); - cards.add(new SetCardInfo("Reckless Embermage", 189, Rarity.RARE, mage.cards.r.RecklessEmbermage.class)); - cards.add(new SetCardInfo("Regeneration", 236, Rarity.COMMON, mage.cards.r.Regeneration.class)); - cards.add(new SetCardInfo("Reign of Chaos", 190, Rarity.UNCOMMON, mage.cards.r.ReignOfChaos.class)); - cards.add(new SetCardInfo("Reparations", 278, Rarity.RARE, mage.cards.r.Reparations.class)); - cards.add(new SetCardInfo("Restless Dead", 138, Rarity.COMMON, mage.cards.r.RestlessDead.class)); - cards.add(new SetCardInfo("Ritual of Steel", 36, Rarity.COMMON, mage.cards.r.RitualOfSteel.class)); - cards.add(new SetCardInfo("Rock Basilisk", 279, Rarity.RARE, mage.cards.r.RockBasilisk.class)); - cards.add(new SetCardInfo("Rocky Tar Pit", 329, Rarity.UNCOMMON, mage.cards.r.RockyTarPit.class)); - cards.add(new SetCardInfo("Roots of Life", 237, Rarity.UNCOMMON, mage.cards.r.RootsOfLife.class)); - cards.add(new SetCardInfo("Sabertooth Cobra", 238, Rarity.COMMON, mage.cards.s.SabertoothCobra.class)); - cards.add(new SetCardInfo("Sacred Mesa", 37, Rarity.RARE, mage.cards.s.SacredMesa.class)); - cards.add(new SetCardInfo("Sandbar Crocodile", 88, Rarity.COMMON, mage.cards.s.SandbarCrocodile.class)); - cards.add(new SetCardInfo("Sandstorm", 239, Rarity.COMMON, mage.cards.s.Sandstorm.class)); - cards.add(new SetCardInfo("Sapphire Charm", 89, Rarity.COMMON, mage.cards.s.SapphireCharm.class)); - cards.add(new SetCardInfo("Savage Twister", 280, Rarity.UNCOMMON, mage.cards.s.SavageTwister.class)); - cards.add(new SetCardInfo("Sawback Manticore", 281, Rarity.RARE, mage.cards.s.SawbackManticore.class)); - cards.add(new SetCardInfo("Sea Scryer", 90, Rarity.COMMON, mage.cards.s.SeaScryer.class)); - cards.add(new SetCardInfo("Searing Spear Askari", 191, Rarity.COMMON, mage.cards.s.SearingSpearAskari.class)); - cards.add(new SetCardInfo("Seedling Charm", 240, Rarity.COMMON, mage.cards.s.SeedlingCharm.class)); - cards.add(new SetCardInfo("Seeds of Innocence", 241, Rarity.RARE, mage.cards.s.SeedsOfInnocence.class)); - cards.add(new SetCardInfo("Serene Heart", 242, Rarity.COMMON, mage.cards.s.SereneHeart.class)); - cards.add(new SetCardInfo("Sewer Rats", 139, Rarity.COMMON, mage.cards.s.SewerRats.class)); - cards.add(new SetCardInfo("Shadow Guildmage", 140, Rarity.COMMON, mage.cards.s.ShadowGuildmage.class)); - cards.add(new SetCardInfo("Shallow Grave", 141, Rarity.RARE, mage.cards.s.ShallowGrave.class)); - cards.add(new SetCardInfo("Shaper Guildmage", 91, Rarity.COMMON, mage.cards.s.ShaperGuildmage.class)); - cards.add(new SetCardInfo("Shauku's Minion", 283, Rarity.UNCOMMON, mage.cards.s.ShaukusMinion.class)); - cards.add(new SetCardInfo("Shauku, Endbringer", 142, Rarity.RARE, mage.cards.s.ShaukuEndbringer.class)); - cards.add(new SetCardInfo("Shimmer", 92, Rarity.RARE, mage.cards.s.Shimmer.class)); - cards.add(new SetCardInfo("Sidar Jabari", 39, Rarity.RARE, mage.cards.s.SidarJabari.class)); - cards.add(new SetCardInfo("Skulking Ghost", 143, Rarity.COMMON, mage.cards.s.SkulkingGhost.class)); - cards.add(new SetCardInfo("Sky Diamond", 319, Rarity.UNCOMMON, mage.cards.s.SkyDiamond.class)); - cards.add(new SetCardInfo("Soar", 93, Rarity.COMMON, mage.cards.s.Soar.class)); - cards.add(new SetCardInfo("Soul Echo", 40, Rarity.RARE, mage.cards.s.SoulEcho.class)); - cards.add(new SetCardInfo("Soul Rend", 144, Rarity.UNCOMMON, mage.cards.s.SoulRend.class)); - cards.add(new SetCardInfo("Spectral Guardian", 41, Rarity.RARE, mage.cards.s.SpectralGuardian.class)); - cards.add(new SetCardInfo("Spirit of the Night", 146, Rarity.RARE, mage.cards.s.SpiritOfTheNight.class)); - cards.add(new SetCardInfo("Spitting Earth", 193, Rarity.COMMON, mage.cards.s.SpittingEarth.class)); - cards.add(new SetCardInfo("Stalking Tiger", 243, Rarity.COMMON, mage.cards.s.StalkingTiger.class)); - cards.add(new SetCardInfo("Stone Rain", 194, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Stupor", 147, Rarity.UNCOMMON, mage.cards.s.Stupor.class)); - cards.add(new SetCardInfo("Subterranean Spirit", 195, Rarity.RARE, mage.cards.s.SubterraneanSpirit.class)); - cards.add(new SetCardInfo("Sunweb", 42, Rarity.RARE, mage.cards.s.Sunweb.class)); - cards.add(new SetCardInfo("Suq'Ata Firewalker", 94, Rarity.UNCOMMON, mage.cards.s.SuqAtaFirewalker.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Talruum Minotaur", 196, Rarity.COMMON, mage.cards.t.TalruumMinotaur.class)); - cards.add(new SetCardInfo("Taniwha", 95, Rarity.RARE, mage.cards.t.Taniwha.class)); - cards.add(new SetCardInfo("Teeka's Dragon", 320, Rarity.RARE, mage.cards.t.TeekasDragon.class)); - cards.add(new SetCardInfo("Teferi's Curse", 96, Rarity.COMMON, mage.cards.t.TeferisCurse.class)); - cards.add(new SetCardInfo("Teferi's Drake", 97, Rarity.COMMON, mage.cards.t.TeferisDrake.class)); - cards.add(new SetCardInfo("Teferi's Isle", 330, Rarity.RARE, mage.cards.t.TeferisIsle.class)); - cards.add(new SetCardInfo("Telim'Tor", 197, Rarity.RARE, mage.cards.t.TelimTor.class)); - cards.add(new SetCardInfo("Telim'Tor's Darts", 321, Rarity.UNCOMMON, mage.cards.t.TelimTorsDarts.class)); - cards.add(new SetCardInfo("Telim'Tor's Edict", 198, Rarity.RARE, mage.cards.t.TelimTorsEdict.class)); - cards.add(new SetCardInfo("Teremko Griffin", 43, Rarity.COMMON, mage.cards.t.TeremkoGriffin.class)); - cards.add(new SetCardInfo("Thirst", 99, Rarity.COMMON, mage.cards.t.Thirst.class)); - cards.add(new SetCardInfo("Tidal Wave", 100, Rarity.UNCOMMON, mage.cards.t.TidalWave.class)); - cards.add(new SetCardInfo("Tombstone Stairwell", 149, Rarity.RARE, mage.cards.t.TombstoneStairwell.class)); - cards.add(new SetCardInfo("Tranquil Domain", 245, Rarity.COMMON, mage.cards.t.TranquilDomain.class)); - cards.add(new SetCardInfo("Tropical Storm", 246, Rarity.UNCOMMON, mage.cards.t.TropicalStorm.class)); - cards.add(new SetCardInfo("Uktabi Faerie", 247, Rarity.COMMON, mage.cards.u.UktabiFaerie.class)); - cards.add(new SetCardInfo("Uktabi Wildcats", 248, Rarity.RARE, mage.cards.u.UktabiWildcats.class)); - cards.add(new SetCardInfo("Unfulfilled Desires", 285, Rarity.RARE, mage.cards.u.UnfulfilledDesires.class)); - cards.add(new SetCardInfo("Unseen Walker", 249, Rarity.UNCOMMON, mage.cards.u.UnseenWalker.class)); - cards.add(new SetCardInfo("Unyaro Bee Sting", 250, Rarity.UNCOMMON, mage.cards.u.UnyaroBeeSting.class)); - cards.add(new SetCardInfo("Unyaro Griffin", 44, Rarity.UNCOMMON, mage.cards.u.UnyaroGriffin.class)); - cards.add(new SetCardInfo("Vaporous Djinn", 101, Rarity.UNCOMMON, mage.cards.v.VaporousDjinn.class)); - cards.add(new SetCardInfo("Ventifact Bottle", 323, Rarity.RARE, mage.cards.v.VentifactBottle.class)); - cards.add(new SetCardInfo("Viashino Warrior", 200, Rarity.COMMON, mage.cards.v.ViashinoWarrior.class)); - cards.add(new SetCardInfo("Vigilant Martyr", 45, Rarity.UNCOMMON, mage.cards.v.VigilantMartyr.class)); - cards.add(new SetCardInfo("Village Elder", 251, Rarity.COMMON, mage.cards.v.VillageElder.class)); - cards.add(new SetCardInfo("Vitalizing Cascade", 286, Rarity.UNCOMMON, mage.cards.v.VitalizingCascade.class)); - cards.add(new SetCardInfo("Volcanic Dragon", 201, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); - cards.add(new SetCardInfo("Volcanic Geyser", 202, Rarity.UNCOMMON, mage.cards.v.VolcanicGeyser.class)); - cards.add(new SetCardInfo("Waiting in the Weeds", 252, Rarity.RARE, mage.cards.w.WaitingInTheWeeds.class)); - cards.add(new SetCardInfo("Wall of Roots", 253, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); - cards.add(new SetCardInfo("Ward of Lights", 47, Rarity.COMMON, mage.cards.w.WardOfLights.class)); - cards.add(new SetCardInfo("Warping Wurm", 287, Rarity.RARE, mage.cards.w.WarpingWurm.class)); - cards.add(new SetCardInfo("Wave Elemental", 102, Rarity.UNCOMMON, mage.cards.w.WaveElemental.class)); - cards.add(new SetCardInfo("Wild Elephant", 254, Rarity.COMMON, mage.cards.w.WildElephant.class)); - cards.add(new SetCardInfo("Wildfire Emissary", 203, Rarity.UNCOMMON, mage.cards.w.WildfireEmissary.class)); - cards.add(new SetCardInfo("Windreaper Falcon", 289, Rarity.UNCOMMON, mage.cards.w.WindreaperFalcon.class)); - cards.add(new SetCardInfo("Withering Boon", 152, Rarity.UNCOMMON, mage.cards.w.WitheringBoon.class)); - cards.add(new SetCardInfo("Worldly Tutor", 255, Rarity.UNCOMMON, mage.cards.w.WorldlyTutor.class)); - cards.add(new SetCardInfo("Zebra Unicorn", 290, Rarity.UNCOMMON, mage.cards.z.ZebraUnicorn.class)); - cards.add(new SetCardInfo("Zhalfirin Commander", 49, Rarity.UNCOMMON, mage.cards.z.ZhalfirinCommander.class)); - cards.add(new SetCardInfo("Zhalfirin Knight", 50, Rarity.COMMON, mage.cards.z.ZhalfirinKnight.class)); - cards.add(new SetCardInfo("Zirilan of the Claw", 204, Rarity.RARE, mage.cards.z.ZirilanOfTheClaw.class)); - cards.add(new SetCardInfo("Zombie Mob", 153, Rarity.UNCOMMON, mage.cards.z.ZombieMob.class)); - cards.add(new SetCardInfo("Zuberi, Golden Feather", 51, Rarity.RARE, mage.cards.z.ZuberiGoldenFeather.class)); - } +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class Mirage extends ExpansionSet { + + private static final Mirage instance = new Mirage(); + + public static Mirage getInstance() { + return instance; + } + + private Mirage() { + super("Mirage", "MIR", ExpansionSet.buildDate(1996, 8, 21), SetType.EXPANSION); + this.blockName = "Mirage"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Abyssal Hunter", 103, Rarity.RARE, mage.cards.a.AbyssalHunter.class)); + cards.add(new SetCardInfo("Afiya Grove", 205, Rarity.RARE, mage.cards.a.AfiyaGrove.class)); + cards.add(new SetCardInfo("Afterlife", 1, Rarity.UNCOMMON, mage.cards.a.Afterlife.class)); + cards.add(new SetCardInfo("Agility", 154, Rarity.COMMON, mage.cards.a.Agility.class)); + cards.add(new SetCardInfo("Alarum", 2, Rarity.COMMON, mage.cards.a.Alarum.class)); + cards.add(new SetCardInfo("Aleatory", 155, Rarity.UNCOMMON, mage.cards.a.Aleatory.class)); + cards.add(new SetCardInfo("Amber Prison", 292, Rarity.RARE, mage.cards.a.AmberPrison.class)); + cards.add(new SetCardInfo("Amulet of Unmaking", 293, Rarity.RARE, mage.cards.a.AmuletOfUnmaking.class)); + cards.add(new SetCardInfo("Ancestral Memories", 52, Rarity.RARE, mage.cards.a.AncestralMemories.class)); + cards.add(new SetCardInfo("Armor of Thorns", 206, Rarity.COMMON, mage.cards.a.ArmorOfThorns.class)); + cards.add(new SetCardInfo("Armorer Guildmage", 156, Rarity.COMMON, mage.cards.a.ArmorerGuildmage.class)); + cards.add(new SetCardInfo("Ashen Powder", 104, Rarity.RARE, mage.cards.a.AshenPowder.class)); + cards.add(new SetCardInfo("Asmira, Holy Avenger", 256, Rarity.RARE, mage.cards.a.AsmiraHolyAvenger.class)); + cards.add(new SetCardInfo("Auspicious Ancestor", 3, Rarity.RARE, mage.cards.a.AuspiciousAncestor.class)); + cards.add(new SetCardInfo("Azimaet Drake", 53, Rarity.COMMON, mage.cards.a.AzimaetDrake.class)); + cards.add(new SetCardInfo("Bad River", 324, Rarity.UNCOMMON, mage.cards.b.BadRiver.class)); + cards.add(new SetCardInfo("Barbed Foliage", 207, Rarity.UNCOMMON, mage.cards.b.BarbedFoliage.class)); + cards.add(new SetCardInfo("Barbed-Back Wurm", 105, Rarity.UNCOMMON, mage.cards.b.BarbedBackWurm.class)); + cards.add(new SetCardInfo("Bay Falcon", 54, Rarity.COMMON, mage.cards.b.BayFalcon.class)); + cards.add(new SetCardInfo("Bazaar of Wonders", 55, Rarity.RARE, mage.cards.b.BazaarOfWonders.class)); + cards.add(new SetCardInfo("Benevolent Unicorn", 4, Rarity.COMMON, mage.cards.b.BenevolentUnicorn.class)); + cards.add(new SetCardInfo("Benthic Djinn", 257, Rarity.RARE, mage.cards.b.BenthicDjinn.class)); + cards.add(new SetCardInfo("Binding Agony", 106, Rarity.COMMON, mage.cards.b.BindingAgony.class)); + cards.add(new SetCardInfo("Blighted Shaman", 107, Rarity.UNCOMMON, mage.cards.b.BlightedShaman.class)); + cards.add(new SetCardInfo("Blinding Light", 5, Rarity.UNCOMMON, mage.cards.b.BlindingLight.class)); + cards.add(new SetCardInfo("Blistering Barrier", 159, Rarity.COMMON, mage.cards.b.BlisteringBarrier.class)); + cards.add(new SetCardInfo("Bone Harvest", 108, Rarity.COMMON, mage.cards.b.BoneHarvest.class)); + cards.add(new SetCardInfo("Bone Mask", 295, Rarity.RARE, mage.cards.b.BoneMask.class)); + cards.add(new SetCardInfo("Boomerang", 56, Rarity.COMMON, mage.cards.b.Boomerang.class)); + cards.add(new SetCardInfo("Breathstealer", 109, Rarity.COMMON, mage.cards.b.Breathstealer.class)); + cards.add(new SetCardInfo("Brushwagg", 208, Rarity.RARE, mage.cards.b.Brushwagg.class)); + cards.add(new SetCardInfo("Builder's Bane", 160, Rarity.COMMON, mage.cards.b.BuildersBane.class)); + cards.add(new SetCardInfo("Burning Palm Efreet", 161, Rarity.UNCOMMON, mage.cards.b.BurningPalmEfreet.class)); + cards.add(new SetCardInfo("Burning Shield Askari", 162, Rarity.COMMON, mage.cards.b.BurningShieldAskari.class)); + cards.add(new SetCardInfo("Cadaverous Bloom", 258, Rarity.RARE, mage.cards.c.CadaverousBloom.class)); + cards.add(new SetCardInfo("Cadaverous Knight", 110, Rarity.COMMON, mage.cards.c.CadaverousKnight.class)); + cards.add(new SetCardInfo("Canopy Dragon", 209, Rarity.RARE, mage.cards.c.CanopyDragon.class)); + cards.add(new SetCardInfo("Carrion", 111, Rarity.RARE, mage.cards.c.Carrion.class)); + cards.add(new SetCardInfo("Catacomb Dragon", 112, Rarity.RARE, mage.cards.c.CatacombDragon.class)); + cards.add(new SetCardInfo("Celestial Dawn", 6, Rarity.RARE, mage.cards.c.CelestialDawn.class)); + cards.add(new SetCardInfo("Cerulean Wyvern", 57, Rarity.UNCOMMON, mage.cards.c.CeruleanWyvern.class)); + cards.add(new SetCardInfo("Chaos Charm", 163, Rarity.COMMON, mage.cards.c.ChaosCharm.class)); + cards.add(new SetCardInfo("Chaosphere", 164, Rarity.RARE, mage.cards.c.Chaosphere.class)); + cards.add(new SetCardInfo("Charcoal Diamond", 296, Rarity.UNCOMMON, mage.cards.c.CharcoalDiamond.class)); + cards.add(new SetCardInfo("Chariot of the Sun", 262, Rarity.UNCOMMON, mage.cards.c.ChariotOfTheSun.class)); + cards.add(new SetCardInfo("Choking Sands", 113, Rarity.COMMON, mage.cards.c.ChokingSands.class)); + cards.add(new SetCardInfo("Cinder Cloud", 165, Rarity.UNCOMMON, mage.cards.c.CinderCloud.class)); + cards.add(new SetCardInfo("Civic Guildmage", 7, Rarity.COMMON, mage.cards.c.CivicGuildmage.class)); + cards.add(new SetCardInfo("Cloak of Invisibility", 58, Rarity.COMMON, mage.cards.c.CloakOfInvisibility.class)); + cards.add(new SetCardInfo("Consuming Ferocity", 166, Rarity.UNCOMMON, mage.cards.c.ConsumingFerocity.class)); + cards.add(new SetCardInfo("Coral Fighters", 59, Rarity.UNCOMMON, mage.cards.c.CoralFighters.class)); + cards.add(new SetCardInfo("Crash of Rhinos", 210, Rarity.COMMON, mage.cards.c.CrashOfRhinos.class)); + cards.add(new SetCardInfo("Crimson Hellkite", 167, Rarity.RARE, mage.cards.c.CrimsonHellkite.class)); + cards.add(new SetCardInfo("Crypt Cobra", 114, Rarity.UNCOMMON, mage.cards.c.CryptCobra.class)); + cards.add(new SetCardInfo("Crystal Golem", 298, Rarity.UNCOMMON, mage.cards.c.CrystalGolem.class)); + cards.add(new SetCardInfo("Crystal Vein", 325, Rarity.UNCOMMON, mage.cards.c.CrystalVein.class)); + cards.add(new SetCardInfo("Cursed Totem", 299, Rarity.RARE, mage.cards.c.CursedTotem.class)); + cards.add(new SetCardInfo("Daring Apprentice", 60, Rarity.RARE, mage.cards.d.DaringApprentice.class)); + cards.add(new SetCardInfo("Dark Banishing", 115, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Dark Ritual", 116, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Dazzling Beauty", 8, Rarity.COMMON, mage.cards.d.DazzlingBeauty.class)); + cards.add(new SetCardInfo("Delirium", 260, Rarity.UNCOMMON, mage.cards.d.Delirium.class)); + cards.add(new SetCardInfo("Dirtwater Wraith", 117, Rarity.COMMON, mage.cards.d.DirtwaterWraith.class)); + cards.add(new SetCardInfo("Disempower", 9, Rarity.COMMON, mage.cards.d.Disempower.class)); + cards.add(new SetCardInfo("Disenchant", 10, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dissipate", 61, Rarity.UNCOMMON, mage.cards.d.Dissipate.class)); + cards.add(new SetCardInfo("Divine Offering", 11, Rarity.COMMON, mage.cards.d.DivineOffering.class)); + cards.add(new SetCardInfo("Divine Retribution", 12, Rarity.RARE, mage.cards.d.DivineRetribution.class)); + cards.add(new SetCardInfo("Drain Life", 118, Rarity.COMMON, mage.cards.d.DrainLife.class)); + cards.add(new SetCardInfo("Dread Specter", 119, Rarity.UNCOMMON, mage.cards.d.DreadSpecter.class)); + cards.add(new SetCardInfo("Dream Cache", 62, Rarity.COMMON, mage.cards.d.DreamCache.class)); + cards.add(new SetCardInfo("Dwarven Miner", 169, Rarity.UNCOMMON, mage.cards.d.DwarvenMiner.class)); + cards.add(new SetCardInfo("Dwarven Nomad", 170, Rarity.COMMON, mage.cards.d.DwarvenNomad.class)); + cards.add(new SetCardInfo("Early Harvest", 213, Rarity.RARE, mage.cards.e.EarlyHarvest.class)); + cards.add(new SetCardInfo("Ebony Charm", 120, Rarity.COMMON, mage.cards.e.EbonyCharm.class)); + cards.add(new SetCardInfo("Ekundu Griffin", 13, Rarity.COMMON, mage.cards.e.EkunduGriffin.class)); + cards.add(new SetCardInfo("Elixir of Vitality", 300, Rarity.UNCOMMON, mage.cards.e.ElixirOfVitality.class)); + cards.add(new SetCardInfo("Emberwilde Caliph", 322, Rarity.RARE, mage.cards.e.EmberwildeCaliph.class)); + cards.add(new SetCardInfo("Emberwilde Djinn", 172, Rarity.RARE, mage.cards.e.EmberwildeDjinn.class)); + cards.add(new SetCardInfo("Energy Bolt", 263, Rarity.RARE, mage.cards.e.EnergyBolt.class)); + cards.add(new SetCardInfo("Energy Vortex", 64, Rarity.RARE, mage.cards.e.EnergyVortex.class)); + cards.add(new SetCardInfo("Enfeeblement", 121, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); + cards.add(new SetCardInfo("Enlightened Tutor", 14, Rarity.UNCOMMON, mage.cards.e.EnlightenedTutor.class)); + cards.add(new SetCardInfo("Ersatz Gnomes", 301, Rarity.UNCOMMON, mage.cards.e.ErsatzGnomes.class)); + cards.add(new SetCardInfo("Ether Well", 65, Rarity.UNCOMMON, mage.cards.e.EtherWell.class)); + cards.add(new SetCardInfo("Ethereal Champion", 15, Rarity.RARE, mage.cards.e.EtherealChampion.class)); + cards.add(new SetCardInfo("Fallow Earth", 214, Rarity.UNCOMMON, mage.cards.f.FallowEarth.class)); + cards.add(new SetCardInfo("Favorable Destiny", 16, Rarity.UNCOMMON, mage.cards.f.FavorableDestiny.class)); + cards.add(new SetCardInfo("Femeref Archers", 215, Rarity.UNCOMMON, mage.cards.f.FemerefArchers.class)); + cards.add(new SetCardInfo("Femeref Healer", 17, Rarity.COMMON, mage.cards.f.FemerefHealer.class)); + cards.add(new SetCardInfo("Femeref Knight", 18, Rarity.COMMON, mage.cards.f.FemerefKnight.class)); + cards.add(new SetCardInfo("Femeref Scouts", 19, Rarity.COMMON, mage.cards.f.FemerefScouts.class)); + cards.add(new SetCardInfo("Feral Shadow", 122, Rarity.COMMON, mage.cards.f.FeralShadow.class)); + cards.add(new SetCardInfo("Fetid Horror", 123, Rarity.COMMON, mage.cards.f.FetidHorror.class)); + cards.add(new SetCardInfo("Final Fortune", 173, Rarity.RARE, mage.cards.f.FinalFortune.class)); + cards.add(new SetCardInfo("Fire Diamond", 302, Rarity.UNCOMMON, mage.cards.f.FireDiamond.class)); + cards.add(new SetCardInfo("Firebreathing", 174, Rarity.COMMON, mage.cards.f.Firebreathing.class)); + cards.add(new SetCardInfo("Flame Elemental", 175, Rarity.UNCOMMON, mage.cards.f.FlameElemental.class)); + cards.add(new SetCardInfo("Flare", 176, Rarity.COMMON, mage.cards.f.Flare.class)); + cards.add(new SetCardInfo("Flash", 66, Rarity.RARE, mage.cards.f.Flash.class)); + cards.add(new SetCardInfo("Flood Plain", 326, Rarity.UNCOMMON, mage.cards.f.FloodPlain.class)); + cards.add(new SetCardInfo("Floodgate", 67, Rarity.UNCOMMON, mage.cards.f.Floodgate.class)); + cards.add(new SetCardInfo("Fog", 216, Rarity.COMMON, mage.cards.f.Fog.class)); + cards.add(new SetCardInfo("Foratog", 217, Rarity.UNCOMMON, mage.cards.f.Foratog.class)); + cards.add(new SetCardInfo("Forbidden Crypt", 124, Rarity.RARE, mage.cards.f.ForbiddenCrypt.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forsaken Wastes", 125, Rarity.RARE, mage.cards.f.ForsakenWastes.class)); + cards.add(new SetCardInfo("Frenetic Efreet", 264, Rarity.RARE, mage.cards.f.FreneticEfreet.class)); + cards.add(new SetCardInfo("Giant Mantis", 218, Rarity.COMMON, mage.cards.g.GiantMantis.class)); + cards.add(new SetCardInfo("Gibbering Hyenas", 219, Rarity.COMMON, mage.cards.g.GibberingHyenas.class)); + cards.add(new SetCardInfo("Goblin Elite Infantry", 177, Rarity.COMMON, mage.cards.g.GoblinEliteInfantry.class)); + cards.add(new SetCardInfo("Goblin Scouts", 178, Rarity.UNCOMMON, mage.cards.g.GoblinScouts.class)); + cards.add(new SetCardInfo("Goblin Soothsayer", 179, Rarity.UNCOMMON, mage.cards.g.GoblinSoothsayer.class)); + cards.add(new SetCardInfo("Goblin Tinkerer", 180, Rarity.COMMON, mage.cards.g.GoblinTinkerer.class)); + cards.add(new SetCardInfo("Granger Guildmage", 220, Rarity.COMMON, mage.cards.g.GrangerGuildmage.class)); + cards.add(new SetCardInfo("Grasslands", 327, Rarity.UNCOMMON, mage.cards.g.Grasslands.class)); + cards.add(new SetCardInfo("Grave Servitude", 126, Rarity.COMMON, mage.cards.g.GraveServitude.class)); + cards.add(new SetCardInfo("Gravebane Zombie", 127, Rarity.COMMON, mage.cards.g.GravebaneZombie.class)); + cards.add(new SetCardInfo("Grim Feast", 265, Rarity.RARE, mage.cards.g.GrimFeast.class)); + cards.add(new SetCardInfo("Grinning Totem", 303, Rarity.RARE, mage.cards.g.GrinningTotem.class)); + cards.add(new SetCardInfo("Hakim, Loreweaver", 68, Rarity.RARE, mage.cards.h.HakimLoreweaver.class)); + cards.add(new SetCardInfo("Hall of Gemstone", 221, Rarity.RARE, mage.cards.h.HallOfGemstone.class)); + cards.add(new SetCardInfo("Hammer of Bogardan", 181, Rarity.RARE, mage.cards.h.HammerOfBogardan.class)); + cards.add(new SetCardInfo("Harbinger of Night", 128, Rarity.RARE, mage.cards.h.HarbingerOfNight.class)); + cards.add(new SetCardInfo("Harbor Guardian", 266, Rarity.UNCOMMON, mage.cards.h.HarborGuardian.class)); + cards.add(new SetCardInfo("Harmattan Efreet", 69, Rarity.UNCOMMON, mage.cards.h.HarmattanEfreet.class)); + cards.add(new SetCardInfo("Hazerider Drake", 268, Rarity.UNCOMMON, mage.cards.h.HazeriderDrake.class)); + cards.add(new SetCardInfo("Healing Salve", 20, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Hivis of the Scale", 182, Rarity.RARE, mage.cards.h.HivisOfTheScale.class)); + cards.add(new SetCardInfo("Horrible Hordes", 304, Rarity.UNCOMMON, mage.cards.h.HorribleHordes.class)); + cards.add(new SetCardInfo("Igneous Golem", 305, Rarity.UNCOMMON, mage.cards.i.IgneousGolem.class)); + cards.add(new SetCardInfo("Illicit Auction", 183, Rarity.RARE, mage.cards.i.IllicitAuction.class)); + cards.add(new SetCardInfo("Illumination", 21, Rarity.UNCOMMON, mage.cards.i.Illumination.class)); + cards.add(new SetCardInfo("Incinerate", 184, Rarity.COMMON, mage.cards.i.Incinerate.class)); + cards.add(new SetCardInfo("Infernal Contract", 129, Rarity.RARE, mage.cards.i.InfernalContract.class)); + cards.add(new SetCardInfo("Iron Tusk Elephant", 22, Rarity.UNCOMMON, mage.cards.i.IronTuskElephant.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ivory Charm", 23, Rarity.COMMON, mage.cards.i.IvoryCharm.class)); + cards.add(new SetCardInfo("Jolrael's Centaur", 222, Rarity.COMMON, mage.cards.j.JolraelsCentaur.class)); + cards.add(new SetCardInfo("Jolt", 70, Rarity.COMMON, mage.cards.j.Jolt.class)); + cards.add(new SetCardInfo("Jungle Patrol", 223, Rarity.RARE, mage.cards.j.JunglePatrol.class)); + cards.add(new SetCardInfo("Jungle Troll", 269, Rarity.UNCOMMON, mage.cards.j.JungleTroll.class)); + cards.add(new SetCardInfo("Jungle Wurm", 224, Rarity.COMMON, mage.cards.j.JungleWurm.class)); + cards.add(new SetCardInfo("Kaervek's Hex", 130, Rarity.UNCOMMON, mage.cards.k.KaerveksHex.class)); + cards.add(new SetCardInfo("Kaervek's Purge", 270, Rarity.UNCOMMON, mage.cards.k.KaerveksPurge.class)); + cards.add(new SetCardInfo("Kaervek's Torch", 185, Rarity.COMMON, mage.cards.k.KaerveksTorch.class)); + cards.add(new SetCardInfo("Karoo Meerkat", 225, Rarity.UNCOMMON, mage.cards.k.KarooMeerkat.class)); + cards.add(new SetCardInfo("Kukemssa Pirates", 71, Rarity.RARE, mage.cards.k.KukemssaPirates.class)); + cards.add(new SetCardInfo("Kukemssa Serpent", 72, Rarity.COMMON, mage.cards.k.KukemssaSerpent.class)); + cards.add(new SetCardInfo("Lead Golem", 306, Rarity.UNCOMMON, mage.cards.l.LeadGolem.class)); + cards.add(new SetCardInfo("Leering Gargoyle", 271, Rarity.RARE, mage.cards.l.LeeringGargoyle.class)); + cards.add(new SetCardInfo("Lightning Reflexes", 186, Rarity.COMMON, mage.cards.l.LightningReflexes.class)); + cards.add(new SetCardInfo("Lion's Eye Diamond", 307, Rarity.RARE, mage.cards.l.LionsEyeDiamond.class)); + cards.add(new SetCardInfo("Locust Swarm", 226, Rarity.UNCOMMON, mage.cards.l.LocustSwarm.class)); + cards.add(new SetCardInfo("Lure of Prey", 227, Rarity.RARE, mage.cards.l.LureOfPrey.class)); + cards.add(new SetCardInfo("Malignant Growth", 272, Rarity.RARE, mage.cards.m.MalignantGrowth.class)); + cards.add(new SetCardInfo("Mana Prism", 308, Rarity.UNCOMMON, mage.cards.m.ManaPrism.class)); + cards.add(new SetCardInfo("Mangara's Tome", 309, Rarity.RARE, mage.cards.m.MangarasTome.class)); + cards.add(new SetCardInfo("Marble Diamond", 310, Rarity.UNCOMMON, mage.cards.m.MarbleDiamond.class)); + cards.add(new SetCardInfo("Maro", 228, Rarity.RARE, mage.cards.m.Maro.class)); + cards.add(new SetCardInfo("Melesse Spirit", 27, Rarity.UNCOMMON, mage.cards.m.MelesseSpirit.class)); + cards.add(new SetCardInfo("Memory Lapse", 74, Rarity.COMMON, mage.cards.m.MemoryLapse.class)); + cards.add(new SetCardInfo("Merfolk Raiders", 75, Rarity.COMMON, mage.cards.m.MerfolkRaiders.class)); + cards.add(new SetCardInfo("Merfolk Seer", 76, Rarity.COMMON, mage.cards.m.MerfolkSeer.class)); + cards.add(new SetCardInfo("Mind Harness", 78, Rarity.UNCOMMON, mage.cards.m.MindHarness.class)); + cards.add(new SetCardInfo("Mire Shade", 131, Rarity.UNCOMMON, mage.cards.m.MireShade.class)); + cards.add(new SetCardInfo("Misers' Cage", 311, Rarity.RARE, mage.cards.m.MisersCage.class)); + cards.add(new SetCardInfo("Mist Dragon", 79, Rarity.RARE, mage.cards.m.MistDragon.class)); + cards.add(new SetCardInfo("Moss Diamond", 312, Rarity.UNCOMMON, mage.cards.m.MossDiamond.class)); + cards.add(new SetCardInfo("Mountain Valley", 328, Rarity.UNCOMMON, mage.cards.m.MountainValley.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mtenda Griffin", 28, Rarity.UNCOMMON, mage.cards.m.MtendaGriffin.class)); + cards.add(new SetCardInfo("Mtenda Herder", 29, Rarity.COMMON, mage.cards.m.MtendaHerder.class)); + cards.add(new SetCardInfo("Mystical Tutor", 80, Rarity.UNCOMMON, mage.cards.m.MysticalTutor.class)); + cards.add(new SetCardInfo("Natural Balance", 231, Rarity.RARE, mage.cards.n.NaturalBalance.class)); + cards.add(new SetCardInfo("Nettletooth Djinn", 232, Rarity.UNCOMMON, mage.cards.n.NettletoothDjinn.class)); + cards.add(new SetCardInfo("Noble Elephant", 30, Rarity.COMMON, mage.cards.n.NobleElephant.class)); + cards.add(new SetCardInfo("Nocturnal Raid", 132, Rarity.UNCOMMON, mage.cards.n.NocturnalRaid.class)); + cards.add(new SetCardInfo("Null Chamber", 31, Rarity.RARE, mage.cards.n.NullChamber.class)); + cards.add(new SetCardInfo("Pacifism", 32, Rarity.COMMON, mage.cards.p.Pacifism.class)); + cards.add(new SetCardInfo("Painful Memories", 133, Rarity.UNCOMMON, mage.cards.p.PainfulMemories.class)); + cards.add(new SetCardInfo("Patagia Golem", 313, Rarity.UNCOMMON, mage.cards.p.PatagiaGolem.class)); + cards.add(new SetCardInfo("Paupers' Cage", 314, Rarity.RARE, mage.cards.p.PaupersCage.class)); + cards.add(new SetCardInfo("Pearl Dragon", 33, Rarity.RARE, mage.cards.p.PearlDragon.class)); + cards.add(new SetCardInfo("Phyrexian Dreadnought", 315, Rarity.RARE, mage.cards.p.PhyrexianDreadnought.class)); + cards.add(new SetCardInfo("Phyrexian Purge", 273, Rarity.RARE, mage.cards.p.PhyrexianPurge.class)); + cards.add(new SetCardInfo("Phyrexian Tribute", 134, Rarity.RARE, mage.cards.p.PhyrexianTribute.class)); + cards.add(new SetCardInfo("Phyrexian Vault", 316, Rarity.UNCOMMON, mage.cards.p.PhyrexianVault.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Political Trickery", 81, Rarity.RARE, mage.cards.p.PoliticalTrickery.class)); + cards.add(new SetCardInfo("Polymorph", 82, Rarity.RARE, mage.cards.p.Polymorph.class)); + cards.add(new SetCardInfo("Power Sink", 83, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Prismatic Boon", 274, Rarity.UNCOMMON, mage.cards.p.PrismaticBoon.class)); + cards.add(new SetCardInfo("Prismatic Circle", 34, Rarity.COMMON, mage.cards.p.PrismaticCircle.class)); + cards.add(new SetCardInfo("Prismatic Lace", 84, Rarity.RARE, mage.cards.p.PrismaticLace.class)); + cards.add(new SetCardInfo("Psychic Transfer", 85, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); + cards.add(new SetCardInfo("Purgatory", 275, Rarity.RARE, mage.cards.p.Purgatory.class)); + cards.add(new SetCardInfo("Purraj of Urborg", 135, Rarity.RARE, mage.cards.p.PurrajOfUrborg.class)); + cards.add(new SetCardInfo("Pyric Salamander", 187, Rarity.COMMON, mage.cards.p.PyricSalamander.class)); + cards.add(new SetCardInfo("Quirion Elves", 234, Rarity.COMMON, mage.cards.q.QuirionElves.class)); + cards.add(new SetCardInfo("Radiant Essence", 276, Rarity.UNCOMMON, mage.cards.r.RadiantEssence.class)); + cards.add(new SetCardInfo("Raging Spirit", 188, Rarity.COMMON, mage.cards.r.RagingSpirit.class)); + cards.add(new SetCardInfo("Rampant Growth", 235, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); + cards.add(new SetCardInfo("Rashida Scalebane", 35, Rarity.RARE, mage.cards.r.RashidaScalebane.class)); + cards.add(new SetCardInfo("Ravenous Vampire", 136, Rarity.UNCOMMON, mage.cards.r.RavenousVampire.class)); + cards.add(new SetCardInfo("Ray of Command", 86, Rarity.COMMON, mage.cards.r.RayOfCommand.class)); + cards.add(new SetCardInfo("Razor Pendulum", 317, Rarity.RARE, mage.cards.r.RazorPendulum.class)); + cards.add(new SetCardInfo("Reality Ripple", 87, Rarity.COMMON, mage.cards.r.RealityRipple.class)); + cards.add(new SetCardInfo("Reckless Embermage", 189, Rarity.RARE, mage.cards.r.RecklessEmbermage.class)); + cards.add(new SetCardInfo("Regeneration", 236, Rarity.COMMON, mage.cards.r.Regeneration.class)); + cards.add(new SetCardInfo("Reign of Chaos", 190, Rarity.UNCOMMON, mage.cards.r.ReignOfChaos.class)); + cards.add(new SetCardInfo("Reparations", 278, Rarity.RARE, mage.cards.r.Reparations.class)); + cards.add(new SetCardInfo("Restless Dead", 138, Rarity.COMMON, mage.cards.r.RestlessDead.class)); + cards.add(new SetCardInfo("Ritual of Steel", 36, Rarity.COMMON, mage.cards.r.RitualOfSteel.class)); + cards.add(new SetCardInfo("Rock Basilisk", 279, Rarity.RARE, mage.cards.r.RockBasilisk.class)); + cards.add(new SetCardInfo("Rocky Tar Pit", 329, Rarity.UNCOMMON, mage.cards.r.RockyTarPit.class)); + cards.add(new SetCardInfo("Roots of Life", 237, Rarity.UNCOMMON, mage.cards.r.RootsOfLife.class)); + cards.add(new SetCardInfo("Sabertooth Cobra", 238, Rarity.COMMON, mage.cards.s.SabertoothCobra.class)); + cards.add(new SetCardInfo("Sacred Mesa", 37, Rarity.RARE, mage.cards.s.SacredMesa.class)); + cards.add(new SetCardInfo("Sandbar Crocodile", 88, Rarity.COMMON, mage.cards.s.SandbarCrocodile.class)); + cards.add(new SetCardInfo("Sandstorm", 239, Rarity.COMMON, mage.cards.s.Sandstorm.class)); + cards.add(new SetCardInfo("Sapphire Charm", 89, Rarity.COMMON, mage.cards.s.SapphireCharm.class)); + cards.add(new SetCardInfo("Savage Twister", 280, Rarity.UNCOMMON, mage.cards.s.SavageTwister.class)); + cards.add(new SetCardInfo("Sawback Manticore", 281, Rarity.RARE, mage.cards.s.SawbackManticore.class)); + cards.add(new SetCardInfo("Sea Scryer", 90, Rarity.COMMON, mage.cards.s.SeaScryer.class)); + cards.add(new SetCardInfo("Searing Spear Askari", 191, Rarity.COMMON, mage.cards.s.SearingSpearAskari.class)); + cards.add(new SetCardInfo("Seedling Charm", 240, Rarity.COMMON, mage.cards.s.SeedlingCharm.class)); + cards.add(new SetCardInfo("Seeds of Innocence", 241, Rarity.RARE, mage.cards.s.SeedsOfInnocence.class)); + cards.add(new SetCardInfo("Serene Heart", 242, Rarity.COMMON, mage.cards.s.SereneHeart.class)); + cards.add(new SetCardInfo("Sewer Rats", 139, Rarity.COMMON, mage.cards.s.SewerRats.class)); + cards.add(new SetCardInfo("Shadow Guildmage", 140, Rarity.COMMON, mage.cards.s.ShadowGuildmage.class)); + cards.add(new SetCardInfo("Shallow Grave", 141, Rarity.RARE, mage.cards.s.ShallowGrave.class)); + cards.add(new SetCardInfo("Shaper Guildmage", 91, Rarity.COMMON, mage.cards.s.ShaperGuildmage.class)); + cards.add(new SetCardInfo("Shauku's Minion", 283, Rarity.UNCOMMON, mage.cards.s.ShaukusMinion.class)); + cards.add(new SetCardInfo("Shauku, Endbringer", 142, Rarity.RARE, mage.cards.s.ShaukuEndbringer.class)); + cards.add(new SetCardInfo("Shimmer", 92, Rarity.RARE, mage.cards.s.Shimmer.class)); + cards.add(new SetCardInfo("Sidar Jabari", 39, Rarity.RARE, mage.cards.s.SidarJabari.class)); + cards.add(new SetCardInfo("Skulking Ghost", 143, Rarity.COMMON, mage.cards.s.SkulkingGhost.class)); + cards.add(new SetCardInfo("Sky Diamond", 319, Rarity.UNCOMMON, mage.cards.s.SkyDiamond.class)); + cards.add(new SetCardInfo("Soar", 93, Rarity.COMMON, mage.cards.s.Soar.class)); + cards.add(new SetCardInfo("Soul Echo", 40, Rarity.RARE, mage.cards.s.SoulEcho.class)); + cards.add(new SetCardInfo("Soul Rend", 144, Rarity.UNCOMMON, mage.cards.s.SoulRend.class)); + cards.add(new SetCardInfo("Soulshriek", 145, Rarity.COMMON, mage.cards.s.Soulshriek.class)); + cards.add(new SetCardInfo("Spectral Guardian", 41, Rarity.RARE, mage.cards.s.SpectralGuardian.class)); + cards.add(new SetCardInfo("Spirit of the Night", 146, Rarity.RARE, mage.cards.s.SpiritOfTheNight.class)); + cards.add(new SetCardInfo("Spitting Earth", 193, Rarity.COMMON, mage.cards.s.SpittingEarth.class)); + cards.add(new SetCardInfo("Stalking Tiger", 243, Rarity.COMMON, mage.cards.s.StalkingTiger.class)); + cards.add(new SetCardInfo("Stone Rain", 194, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Stupor", 147, Rarity.UNCOMMON, mage.cards.s.Stupor.class)); + cards.add(new SetCardInfo("Subterranean Spirit", 195, Rarity.RARE, mage.cards.s.SubterraneanSpirit.class)); + cards.add(new SetCardInfo("Sunweb", 42, Rarity.RARE, mage.cards.s.Sunweb.class)); + cards.add(new SetCardInfo("Superior Numbers", 244, Rarity.UNCOMMON, mage.cards.s.SuperiorNumbers.class)); + cards.add(new SetCardInfo("Suq'Ata Firewalker", 94, Rarity.UNCOMMON, mage.cards.s.SuqAtaFirewalker.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Talruum Minotaur", 196, Rarity.COMMON, mage.cards.t.TalruumMinotaur.class)); + cards.add(new SetCardInfo("Taniwha", 95, Rarity.RARE, mage.cards.t.Taniwha.class)); + cards.add(new SetCardInfo("Teeka's Dragon", 320, Rarity.RARE, mage.cards.t.TeekasDragon.class)); + cards.add(new SetCardInfo("Teferi's Curse", 96, Rarity.COMMON, mage.cards.t.TeferisCurse.class)); + cards.add(new SetCardInfo("Teferi's Drake", 97, Rarity.COMMON, mage.cards.t.TeferisDrake.class)); + cards.add(new SetCardInfo("Teferi's Isle", 330, Rarity.RARE, mage.cards.t.TeferisIsle.class)); + cards.add(new SetCardInfo("Telim'Tor", 197, Rarity.RARE, mage.cards.t.TelimTor.class)); + cards.add(new SetCardInfo("Telim'Tor's Darts", 321, Rarity.UNCOMMON, mage.cards.t.TelimTorsDarts.class)); + cards.add(new SetCardInfo("Telim'Tor's Edict", 198, Rarity.RARE, mage.cards.t.TelimTorsEdict.class)); + cards.add(new SetCardInfo("Teremko Griffin", 43, Rarity.COMMON, mage.cards.t.TeremkoGriffin.class)); + cards.add(new SetCardInfo("Thirst", 99, Rarity.COMMON, mage.cards.t.Thirst.class)); + cards.add(new SetCardInfo("Tidal Wave", 100, Rarity.UNCOMMON, mage.cards.t.TidalWave.class)); + cards.add(new SetCardInfo("Tombstone Stairwell", 149, Rarity.RARE, mage.cards.t.TombstoneStairwell.class)); + cards.add(new SetCardInfo("Tranquil Domain", 245, Rarity.COMMON, mage.cards.t.TranquilDomain.class)); + cards.add(new SetCardInfo("Tropical Storm", 246, Rarity.UNCOMMON, mage.cards.t.TropicalStorm.class)); + cards.add(new SetCardInfo("Uktabi Faerie", 247, Rarity.COMMON, mage.cards.u.UktabiFaerie.class)); + cards.add(new SetCardInfo("Uktabi Wildcats", 248, Rarity.RARE, mage.cards.u.UktabiWildcats.class)); + cards.add(new SetCardInfo("Unfulfilled Desires", 285, Rarity.RARE, mage.cards.u.UnfulfilledDesires.class)); + cards.add(new SetCardInfo("Unseen Walker", 249, Rarity.UNCOMMON, mage.cards.u.UnseenWalker.class)); + cards.add(new SetCardInfo("Unyaro Bee Sting", 250, Rarity.UNCOMMON, mage.cards.u.UnyaroBeeSting.class)); + cards.add(new SetCardInfo("Unyaro Griffin", 44, Rarity.UNCOMMON, mage.cards.u.UnyaroGriffin.class)); + cards.add(new SetCardInfo("Urborg Panther", 150, Rarity.COMMON, mage.cards.u.UrborgPanther.class)); + cards.add(new SetCardInfo("Vaporous Djinn", 101, Rarity.UNCOMMON, mage.cards.v.VaporousDjinn.class)); + cards.add(new SetCardInfo("Ventifact Bottle", 323, Rarity.RARE, mage.cards.v.VentifactBottle.class)); + cards.add(new SetCardInfo("Viashino Warrior", 200, Rarity.COMMON, mage.cards.v.ViashinoWarrior.class)); + cards.add(new SetCardInfo("Vigilant Martyr", 45, Rarity.UNCOMMON, mage.cards.v.VigilantMartyr.class)); + cards.add(new SetCardInfo("Village Elder", 251, Rarity.COMMON, mage.cards.v.VillageElder.class)); + cards.add(new SetCardInfo("Vitalizing Cascade", 286, Rarity.UNCOMMON, mage.cards.v.VitalizingCascade.class)); + cards.add(new SetCardInfo("Volcanic Dragon", 201, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); + cards.add(new SetCardInfo("Volcanic Geyser", 202, Rarity.UNCOMMON, mage.cards.v.VolcanicGeyser.class)); + cards.add(new SetCardInfo("Waiting in the Weeds", 252, Rarity.RARE, mage.cards.w.WaitingInTheWeeds.class)); + cards.add(new SetCardInfo("Wall of Roots", 253, Rarity.COMMON, mage.cards.w.WallOfRoots.class)); + cards.add(new SetCardInfo("Ward of Lights", 47, Rarity.COMMON, mage.cards.w.WardOfLights.class)); + cards.add(new SetCardInfo("Warping Wurm", 287, Rarity.RARE, mage.cards.w.WarpingWurm.class)); + cards.add(new SetCardInfo("Wave Elemental", 102, Rarity.UNCOMMON, mage.cards.w.WaveElemental.class)); + cards.add(new SetCardInfo("Wild Elephant", 254, Rarity.COMMON, mage.cards.w.WildElephant.class)); + cards.add(new SetCardInfo("Wildfire Emissary", 203, Rarity.UNCOMMON, mage.cards.w.WildfireEmissary.class)); + cards.add(new SetCardInfo("Windreaper Falcon", 289, Rarity.UNCOMMON, mage.cards.w.WindreaperFalcon.class)); + cards.add(new SetCardInfo("Withering Boon", 152, Rarity.UNCOMMON, mage.cards.w.WitheringBoon.class)); + cards.add(new SetCardInfo("Worldly Tutor", 255, Rarity.UNCOMMON, mage.cards.w.WorldlyTutor.class)); + cards.add(new SetCardInfo("Zebra Unicorn", 290, Rarity.UNCOMMON, mage.cards.z.ZebraUnicorn.class)); + cards.add(new SetCardInfo("Zhalfirin Commander", 49, Rarity.UNCOMMON, mage.cards.z.ZhalfirinCommander.class)); + cards.add(new SetCardInfo("Zhalfirin Knight", 50, Rarity.COMMON, mage.cards.z.ZhalfirinKnight.class)); + cards.add(new SetCardInfo("Zirilan of the Claw", 204, Rarity.RARE, mage.cards.z.ZirilanOfTheClaw.class)); + cards.add(new SetCardInfo("Zombie Mob", 153, Rarity.UNCOMMON, mage.cards.z.ZombieMob.class)); + cards.add(new SetCardInfo("Zuberi, Golden Feather", 51, Rarity.RARE, mage.cards.z.ZuberiGoldenFeather.class)); + } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/ModernHorizons.java b/Mage.Sets/src/mage/sets/ModernHorizons.java new file mode 100644 index 0000000000..ed129a78a7 --- /dev/null +++ b/Mage.Sets/src/mage/sets/ModernHorizons.java @@ -0,0 +1,33 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author TheElk801 + */ +public final class ModernHorizons extends ExpansionSet { + + private static final ModernHorizons instance = new ModernHorizons(); + + public static ModernHorizons getInstance() { + return instance; + } + + private ModernHorizons() { + // TODO: update the set type closer to release (no point right now, the cards won't be legal for a while) + super("Modern Horizons", "MH1", ExpansionSet.buildDate(2019, 6, 14), SetType.SUPPLEMENTAL_MODERN_LEGAL); + this.blockName = "Modern Horizons"; + this.hasBasicLands = false; + this.hasBoosters = false; // TODO: enable after more cards will be available + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Cabal Therapist", 80, Rarity.RARE, mage.cards.c.CabalTherapist.class)); + cards.add(new SetCardInfo("Serra the Benevolent", 26, Rarity.MYTHIC, mage.cards.s.SerraTheBenevolent.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernMasters.java b/Mage.Sets/src/mage/sets/ModernMasters.java index 638fc63faa..9b87034f21 100644 --- a/Mage.Sets/src/mage/sets/ModernMasters.java +++ b/Mage.Sets/src/mage/sets/ModernMasters.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -6,7 +5,6 @@ import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author LevelX2 */ public final class ModernMasters extends ExpansionSet { @@ -18,7 +16,7 @@ public final class ModernMasters extends ExpansionSet { } private ModernMasters() { - super("Modern Masters", "MMA", ExpansionSet.buildDate(2013, 6, 7), SetType.SUPPLEMENTAL); + super("Modern Masters", "MMA", ExpansionSet.buildDate(2013, 6, 7), SetType.SUPPLEMENTAL_MODERN_LEGAL); this.blockName = "Reprint"; this.hasBasicLands = false; this.hasBoosters = true; diff --git a/Mage.Sets/src/mage/sets/ModernMasters2015.java b/Mage.Sets/src/mage/sets/ModernMasters2015.java index 3230298231..c577a99628 100644 --- a/Mage.Sets/src/mage/sets/ModernMasters2015.java +++ b/Mage.Sets/src/mage/sets/ModernMasters2015.java @@ -5,7 +5,6 @@ import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author fireshoes */ public final class ModernMasters2015 extends ExpansionSet { @@ -17,7 +16,7 @@ public final class ModernMasters2015 extends ExpansionSet { } private ModernMasters2015() { - super("Modern Masters 2015", "MM2", ExpansionSet.buildDate(2015, 5, 22), SetType.SUPPLEMENTAL); + super("Modern Masters 2015", "MM2", ExpansionSet.buildDate(2015, 5, 22), SetType.SUPPLEMENTAL_MODERN_LEGAL); this.blockName = "Reprint"; this.hasBasicLands = false; this.hasBoosters = true; diff --git a/Mage.Sets/src/mage/sets/ModernMasters2017.java b/Mage.Sets/src/mage/sets/ModernMasters2017.java index 6686b06134..8137d6771d 100644 --- a/Mage.Sets/src/mage/sets/ModernMasters2017.java +++ b/Mage.Sets/src/mage/sets/ModernMasters2017.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -6,7 +5,6 @@ import mage.constants.Rarity; import mage.constants.SetType; /** - * * @author fireshoes */ public final class ModernMasters2017 extends ExpansionSet { @@ -18,7 +16,7 @@ public final class ModernMasters2017 extends ExpansionSet { } private ModernMasters2017() { - super("Modern Masters 2017", "MM3", ExpansionSet.buildDate(2017, 3, 17), SetType.SUPPLEMENTAL); + super("Modern Masters 2017", "MM3", ExpansionSet.buildDate(2017, 3, 17), SetType.SUPPLEMENTAL_MODERN_LEGAL); this.blockName = "Reprint"; this.hasBasicLands = false; this.hasBoosters = true; diff --git a/Mage.Sets/src/mage/sets/MythicEdition.java b/Mage.Sets/src/mage/sets/MythicEdition.java new file mode 100644 index 0000000000..5774079750 --- /dev/null +++ b/Mage.Sets/src/mage/sets/MythicEdition.java @@ -0,0 +1,39 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class MythicEdition extends ExpansionSet { + + private static final MythicEdition instance = new MythicEdition(); + + public static MythicEdition getInstance() { + return instance; + } + + private MythicEdition() { + super("Mythic Edition", "MEDM", ExpansionSet.buildDate(2018, 10, 5), SetType.SUPPLEMENTAL); // MEDM cause MED uses for master edition + this.hasBasicLands = false; + + cards.add(new SetCardInfo("Ajani, Mentor of Heroes", "RA5", Rarity.MYTHIC, mage.cards.a.AjaniMentorOfHeroes.class)); + cards.add(new SetCardInfo("Dack Fayden", "RA6", Rarity.MYTHIC, mage.cards.d.DackFayden.class)); + cards.add(new SetCardInfo("Daretti, Ingenious Iconoclast", "GR3", Rarity.MYTHIC, mage.cards.d.DarettiIngeniousIconoclast.class)); + cards.add(new SetCardInfo("Domri, Chaos Bringer", "RA7", Rarity.MYTHIC, mage.cards.d.DomriChaosBringer.class)); + cards.add(new SetCardInfo("Elspeth, Knight-Errant", "GR1", Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class)); + cards.add(new SetCardInfo("Jaya Ballard", "RA4", Rarity.MYTHIC, mage.cards.j.JayaBallard.class)); + cards.add(new SetCardInfo("Karn, Scion of Urza", "RA1", Rarity.MYTHIC, mage.cards.k.KarnScionOfUrza.class)); + cards.add(new SetCardInfo("Kaya, Orzhov Usurper", "RA8", Rarity.MYTHIC, mage.cards.k.KayaOrzhovUsurper.class)); + cards.add(new SetCardInfo("Liliana, the Last Hope", "GR2", Rarity.MYTHIC, mage.cards.l.LilianaTheLastHope.class)); + cards.add(new SetCardInfo("Nicol Bolas, Planeswalker", "GR4", Rarity.MYTHIC, mage.cards.n.NicolBolasPlaneswalker.class)); + cards.add(new SetCardInfo("Ral, Izzet Viceroy", "GR5", Rarity.MYTHIC, mage.cards.r.RalIzzetViceroy.class)); + cards.add(new SetCardInfo("Sorin Markov", "RA3", Rarity.MYTHIC, mage.cards.s.SorinMarkov.class)); + cards.add(new SetCardInfo("Tamiyo, the Moon Sage", "RA2", Rarity.MYTHIC, mage.cards.t.TamiyoTheMoonSage.class)); + cards.add(new SetCardInfo("Teferi, Hero of Dominaria", "GR6", Rarity.MYTHIC, mage.cards.t.TeferiHeroOfDominaria.class)); + cards.add(new SetCardInfo("Tezzeret, Agent of Bolas", "GR7", Rarity.MYTHIC, mage.cards.t.TezzeretAgentOfBolas.class)); + cards.add(new SetCardInfo("Vraska, Golgari Queen", "GR8", Rarity.MYTHIC, mage.cards.v.VraskaGolgariQueen.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Planeshift.java b/Mage.Sets/src/mage/sets/Planeshift.java index 57a70190de..206dd194b3 100644 --- a/Mage.Sets/src/mage/sets/Planeshift.java +++ b/Mage.Sets/src/mage/sets/Planeshift.java @@ -30,6 +30,7 @@ public final class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Allied Strategies", 20, Rarity.UNCOMMON, mage.cards.a.AlliedStrategies.class)); cards.add(new SetCardInfo("Alpha Kavu", 77, Rarity.UNCOMMON, mage.cards.a.AlphaKavu.class)); + cards.add(new SetCardInfo("Amphibious Kavu", 78, Rarity.COMMON, mage.cards.a.AmphibiousKavu.class)); cards.add(new SetCardInfo("Ancient Spider", 96, Rarity.RARE, mage.cards.a.AncientSpider.class)); cards.add(new SetCardInfo("Arctic Merfolk", 21, Rarity.COMMON, mage.cards.a.ArcticMerfolk.class)); cards.add(new SetCardInfo("Aura Blast", 1, Rarity.COMMON, mage.cards.a.AuraBlast.class)); @@ -50,6 +51,7 @@ public final class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Destructive Flow", 102, Rarity.RARE, mage.cards.d.DestructiveFlow.class)); cards.add(new SetCardInfo("Diabolic Intent", 42, Rarity.RARE, mage.cards.d.DiabolicIntent.class)); cards.add(new SetCardInfo("Disciple of Kangee", 3, Rarity.COMMON, mage.cards.d.DiscipleOfKangee.class)); + cards.add(new SetCardInfo("Dominaria's Judgment", 4, Rarity.RARE, mage.cards.d.DominariasJudgment.class)); cards.add(new SetCardInfo("Doomsday Specter", 103, Rarity.RARE, mage.cards.d.DoomsdaySpecter.class)); cards.add(new SetCardInfo("Draco", 131, Rarity.RARE, mage.cards.d.Draco.class)); cards.add(new SetCardInfo("Dralnu's Crusade", 104, Rarity.RARE, mage.cards.d.DralnusCrusade.class)); @@ -71,6 +73,7 @@ public final class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Gainsay", 26, Rarity.UNCOMMON, mage.cards.g.Gainsay.class)); cards.add(new SetCardInfo("Gerrard's Command", 109, Rarity.COMMON, mage.cards.g.GerrardsCommand.class)); cards.add(new SetCardInfo("Goblin Game", 61, Rarity.RARE, mage.cards.g.GoblinGame.class)); + cards.add(new SetCardInfo("Guard Dogs", 5, Rarity.UNCOMMON, mage.cards.g.GuardDogs.class)); cards.add(new SetCardInfo("Heroic Defiance", 6, Rarity.COMMON, mage.cards.h.HeroicDefiance.class)); cards.add(new SetCardInfo("Hobble", 7, Rarity.COMMON, mage.cards.h.Hobble.class)); cards.add(new SetCardInfo("Honorable Scout", 8, Rarity.COMMON, mage.cards.h.HonorableScout.class)); @@ -95,6 +98,7 @@ public final class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Meddling Mage", 116, Rarity.RARE, mage.cards.m.MeddlingMage.class)); cards.add(new SetCardInfo("Meteor Crater", 140, Rarity.RARE, mage.cards.m.MeteorCrater.class)); cards.add(new SetCardInfo("Mire Kavu", 67, Rarity.COMMON, mage.cards.m.MireKavu.class)); + cards.add(new SetCardInfo("Mirrorwood Treefolk", 83, Rarity.UNCOMMON, mage.cards.m.MirrorwoodTreefolk.class)); cards.add(new SetCardInfo("Mogg Jailer", 68, Rarity.UNCOMMON, mage.cards.m.MoggJailer.class)); cards.add(new SetCardInfo("Mogg Sentry", 69, Rarity.RARE, mage.cards.m.MoggSentry.class)); cards.add(new SetCardInfo("Morgue Toad", 46, Rarity.COMMON, mage.cards.m.MorgueToad.class)); @@ -103,6 +107,7 @@ public final class Planeshift extends ExpansionSet { cards.add(new SetCardInfo("Nemata, Grove Guardian", 85, Rarity.RARE, mage.cards.n.NemataGroveGuardian.class)); cards.add(new SetCardInfo("Nightscape Battlemage", 47, Rarity.UNCOMMON, mage.cards.n.NightscapeBattlemage.class)); cards.add(new SetCardInfo("Nightscape Familiar", 48, Rarity.COMMON, mage.cards.n.NightscapeFamiliar.class)); + cards.add(new SetCardInfo("Noxious Vapors", 49, Rarity.UNCOMMON, mage.cards.n.NoxiousVapors.class)); cards.add(new SetCardInfo("Orim's Chant", 11, Rarity.RARE, mage.cards.o.OrimsChant.class)); cards.add(new SetCardInfo("Phyrexian Bloodstock", 50, Rarity.COMMON, mage.cards.p.PhyrexianBloodstock.class)); cards.add(new SetCardInfo("Phyrexian Scuta", 51, Rarity.RARE, mage.cards.p.PhyrexianScuta.class)); diff --git a/Mage.Sets/src/mage/sets/PremiumDeckSeriesFireAndLightning.java b/Mage.Sets/src/mage/sets/PremiumDeckSeriesFireAndLightning.java index ec04e84bdd..69f7688c0e 100644 --- a/Mage.Sets/src/mage/sets/PremiumDeckSeriesFireAndLightning.java +++ b/Mage.Sets/src/mage/sets/PremiumDeckSeriesFireAndLightning.java @@ -1,4 +1,3 @@ - package mage.sets; import mage.cards.ExpansionSet; @@ -17,8 +16,7 @@ public final class PremiumDeckSeriesFireAndLightning extends ExpansionSet { } private PremiumDeckSeriesFireAndLightning() { - super("Premium Deck Series: Fire and Lightning", "PD2", ExpansionSet.buildDate(2010, 11, 1), - SetType.SUPPLEMENTAL); + super("Premium Deck Series: Fire and Lightning", "PD2", ExpansionSet.buildDate(2010, 11, 1), SetType.SUPPLEMENTAL); this.hasBasicLands = true; cards.add(new SetCardInfo("Ball Lightning", 12, Rarity.RARE, mage.cards.b.BallLightning.class)); diff --git a/Mage.Sets/src/mage/sets/Prophecy.java b/Mage.Sets/src/mage/sets/Prophecy.java index 428e91c876..9ff9dde2a7 100644 --- a/Mage.Sets/src/mage/sets/Prophecy.java +++ b/Mage.Sets/src/mage/sets/Prophecy.java @@ -1,172 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Prophecy extends ExpansionSet { - - private static final Prophecy instance = new Prophecy(); - - public static Prophecy getInstance() { - return instance; - } - - private Prophecy() { - super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); - this.blockName = "Masques"; - this.parentSet = MercadianMasques.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); - cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); - cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); - cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); - cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); - cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); - cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); - cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); - cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); - cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); - cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); - cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); - cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); - cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); - cards.add(new SetCardInfo("Branded Brawlers", 84, Rarity.COMMON, mage.cards.b.BrandedBrawlers.class)); - cards.add(new SetCardInfo("Brutal Suppression", 85, Rarity.UNCOMMON, mage.cards.b.BrutalSuppression.class)); - cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); - cards.add(new SetCardInfo("Celestial Convergence", 5, Rarity.RARE, mage.cards.c.CelestialConvergence.class)); - cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); - cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); - cards.add(new SetCardInfo("Citadel of Pain", 86, Rarity.UNCOMMON, mage.cards.c.CitadelOfPain.class)); - cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); - cards.add(new SetCardInfo("Coffin Puppets", 60, Rarity.RARE, mage.cards.c.CoffinPuppets.class)); - cards.add(new SetCardInfo("Copper-Leaf Angel", 137, Rarity.RARE, mage.cards.c.CopperLeafAngel.class)); - cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); - cards.add(new SetCardInfo("Death Charmer", 61, Rarity.COMMON, mage.cards.d.DeathCharmer.class)); - cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); - cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); - cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); - cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); - cards.add(new SetCardInfo("Dual Nature", 112, Rarity.RARE, mage.cards.d.DualNature.class)); - cards.add(new SetCardInfo("Elephant Resurgence", 113, Rarity.RARE, mage.cards.e.ElephantResurgence.class)); - cards.add(new SetCardInfo("Endbringer's Revel", 63, Rarity.UNCOMMON, mage.cards.e.EndbringersRevel.class)); - cards.add(new SetCardInfo("Entangler", 7, Rarity.UNCOMMON, mage.cards.e.Entangler.class)); - cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); - cards.add(new SetCardInfo("Excise", 8, Rarity.COMMON, mage.cards.e.Excise.class)); - cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); - cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); - cards.add(new SetCardInfo("Fickle Efreet", 89, Rarity.RARE, mage.cards.f.FickleEfreet.class)); - cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); - cards.add(new SetCardInfo("Flay", 65, Rarity.COMMON, mage.cards.f.Flay.class)); - cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); - cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); - cards.add(new SetCardInfo("Forgotten Harvest", 114, Rarity.RARE, mage.cards.f.ForgottenHarvest.class)); - cards.add(new SetCardInfo("Glittering Lion", 10, Rarity.UNCOMMON, mage.cards.g.GlitteringLion.class)); - cards.add(new SetCardInfo("Glittering Lynx", 11, Rarity.COMMON, mage.cards.g.GlitteringLynx.class)); - cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); - cards.add(new SetCardInfo("Greel, Mind Raker", 66, Rarity.RARE, mage.cards.g.GreelMindRaker.class)); - cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); - cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); - cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); - cards.add(new SetCardInfo("Hollow Warrior", 138, Rarity.UNCOMMON, mage.cards.h.HollowWarrior.class)); - cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); - cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); - cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); - cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); - cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); - cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); - cards.add(new SetCardInfo("Keldon Battlewagon", 139, Rarity.RARE, mage.cards.k.KeldonBattlewagon.class)); - cards.add(new SetCardInfo("Keldon Berserker", 93, Rarity.COMMON, mage.cards.k.KeldonBerserker.class)); - cards.add(new SetCardInfo("Keldon Firebombers", 94, Rarity.RARE, mage.cards.k.KeldonFirebombers.class)); - cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); - cards.add(new SetCardInfo("Latulla's Orders", 96, Rarity.COMMON, mage.cards.l.LatullasOrders.class)); - cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); - cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); - cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); - cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); - cards.add(new SetCardInfo("Mana Vapors", 38, Rarity.UNCOMMON, mage.cards.m.ManaVapors.class)); - cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); - cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); - cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); - cards.add(new SetCardInfo("Mirror Strike", 17, Rarity.UNCOMMON, mage.cards.m.MirrorStrike.class)); - cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); - cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); - cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); - cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); - cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); - cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); - cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); - cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); - cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); - cards.add(new SetCardInfo("Psychic Theft", 40, Rarity.RARE, mage.cards.p.PsychicTheft.class)); - cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); - cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); - cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); - cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); - cards.add(new SetCardInfo("Reveille Squad", 18, Rarity.UNCOMMON, mage.cards.r.ReveilleSquad.class)); - cards.add(new SetCardInfo("Rhystic Cave", 142, Rarity.UNCOMMON, mage.cards.r.RhysticCave.class)); - cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); - cards.add(new SetCardInfo("Rhystic Deluge", 43, Rarity.COMMON, mage.cards.r.RhysticDeluge.class)); - cards.add(new SetCardInfo("Rhystic Lightning", 99, Rarity.COMMON, mage.cards.r.RhysticLightning.class)); - cards.add(new SetCardInfo("Rhystic Scrying", 44, Rarity.UNCOMMON, mage.cards.r.RhysticScrying.class)); - cards.add(new SetCardInfo("Rhystic Shield", 20, Rarity.COMMON, mage.cards.r.RhysticShield.class)); - cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); - cards.add(new SetCardInfo("Rhystic Syphon", 76, Rarity.UNCOMMON, mage.cards.r.RhysticSyphon.class)); - cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); - cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); - cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); - cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); - cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); - cards.add(new SetCardInfo("Samite Sanctuary", 21, Rarity.RARE, mage.cards.s.SamiteSanctuary.class)); - cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); - cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); - cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); - cards.add(new SetCardInfo("Shrouded Serpent", 47, Rarity.RARE, mage.cards.s.ShroudedSerpent.class)); - cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); - cards.add(new SetCardInfo("Snag", 124, Rarity.UNCOMMON, mage.cards.s.Snag.class)); - cards.add(new SetCardInfo("Soul Charmer", 24, Rarity.COMMON, mage.cards.s.SoulCharmer.class)); - cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); - cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); - cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); - cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); - cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); - cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); - cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); - cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); - cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); - cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); - cards.add(new SetCardInfo("Task Mage Assembly", 105, Rarity.RARE, mage.cards.t.TaskMageAssembly.class)); - cards.add(new SetCardInfo("Thresher Beast", 128, Rarity.COMMON, mage.cards.t.ThresherBeast.class)); - cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); - cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); - cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); - cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); - cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); - cards.add(new SetCardInfo("Veteran Brawlers", 106, Rarity.RARE, mage.cards.v.VeteranBrawlers.class)); - cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); - cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); - cards.add(new SetCardInfo("Vitalizing Wind", 133, Rarity.RARE, mage.cards.v.VitalizingWind.class)); - cards.add(new SetCardInfo("Wall of Vipers", 80, Rarity.UNCOMMON, mage.cards.w.WallOfVipers.class)); - cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); - cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); - cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); - cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); - cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); - cards.add(new SetCardInfo("Windscouter", 53, Rarity.UNCOMMON, mage.cards.w.Windscouter.class)); - cards.add(new SetCardInfo("Wing Storm", 135, Rarity.UNCOMMON, mage.cards.w.WingStorm.class)); - cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); - cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); - cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Prophecy extends ExpansionSet { + + private static final Prophecy instance = new Prophecy(); + + public static Prophecy getInstance() { + return instance; + } + + private Prophecy() { + super("Prophecy", "PCY", ExpansionSet.buildDate(2000, 4, 27), SetType.EXPANSION); + this.blockName = "Masques"; + this.parentSet = MercadianMasques.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abolish", 1, Rarity.UNCOMMON, mage.cards.a.Abolish.class)); + cards.add(new SetCardInfo("Agent of Shauku", 55, Rarity.COMMON, mage.cards.a.AgentOfShauku.class)); + cards.add(new SetCardInfo("Alexi's Cloak", 29, Rarity.COMMON, mage.cards.a.AlexisCloak.class)); + cards.add(new SetCardInfo("Alexi, Zephyr Mage", 28, Rarity.RARE, mage.cards.a.AlexiZephyrMage.class)); + cards.add(new SetCardInfo("Aura Fracture", 2, Rarity.COMMON, mage.cards.a.AuraFracture.class)); + cards.add(new SetCardInfo("Avatar of Fury", 82, Rarity.RARE, mage.cards.a.AvatarOfFury.class)); + cards.add(new SetCardInfo("Avatar of Hope", 3, Rarity.RARE, mage.cards.a.AvatarOfHope.class)); + cards.add(new SetCardInfo("Avatar of Might", 109, Rarity.RARE, mage.cards.a.AvatarOfMight.class)); + cards.add(new SetCardInfo("Avatar of Will", 30, Rarity.RARE, mage.cards.a.AvatarOfWill.class)); + cards.add(new SetCardInfo("Avatar of Woe", 56, Rarity.RARE, mage.cards.a.AvatarOfWoe.class)); + cards.add(new SetCardInfo("Barbed Field", 83, Rarity.UNCOMMON, mage.cards.b.BarbedField.class)); + cards.add(new SetCardInfo("Blessed Wind", 4, Rarity.RARE, mage.cards.b.BlessedWind.class)); + cards.add(new SetCardInfo("Bog Elemental", 57, Rarity.RARE, mage.cards.b.BogElemental.class)); + cards.add(new SetCardInfo("Bog Glider", 58, Rarity.COMMON, mage.cards.b.BogGlider.class)); + cards.add(new SetCardInfo("Branded Brawlers", 84, Rarity.COMMON, mage.cards.b.BrandedBrawlers.class)); + cards.add(new SetCardInfo("Brutal Suppression", 85, Rarity.UNCOMMON, mage.cards.b.BrutalSuppression.class)); + cards.add(new SetCardInfo("Calming Verse", 110, Rarity.COMMON, mage.cards.c.CalmingVerse.class)); + cards.add(new SetCardInfo("Celestial Convergence", 5, Rarity.RARE, mage.cards.c.CelestialConvergence.class)); + cards.add(new SetCardInfo("Chilling Apparition", 59, Rarity.UNCOMMON, mage.cards.c.ChillingApparition.class)); + cards.add(new SetCardInfo("Chimeric Idol", 136, Rarity.UNCOMMON, mage.cards.c.ChimericIdol.class)); + cards.add(new SetCardInfo("Citadel of Pain", 86, Rarity.UNCOMMON, mage.cards.c.CitadelOfPain.class)); + cards.add(new SetCardInfo("Coastal Hornclaw", 31, Rarity.COMMON, mage.cards.c.CoastalHornclaw.class)); + cards.add(new SetCardInfo("Coffin Puppets", 60, Rarity.RARE, mage.cards.c.CoffinPuppets.class)); + cards.add(new SetCardInfo("Copper-Leaf Angel", 137, Rarity.RARE, mage.cards.c.CopperLeafAngel.class)); + cards.add(new SetCardInfo("Darba", 111, Rarity.UNCOMMON, mage.cards.d.Darba.class)); + cards.add(new SetCardInfo("Death Charmer", 61, Rarity.COMMON, mage.cards.d.DeathCharmer.class)); + cards.add(new SetCardInfo("Denying Wind", 32, Rarity.RARE, mage.cards.d.DenyingWind.class)); + cards.add(new SetCardInfo("Despoil", 62, Rarity.COMMON, mage.cards.d.Despoil.class)); + cards.add(new SetCardInfo("Devastate", 87, Rarity.COMMON, mage.cards.d.Devastate.class)); + cards.add(new SetCardInfo("Diving Griffin", 6, Rarity.COMMON, mage.cards.d.DivingGriffin.class)); + cards.add(new SetCardInfo("Dual Nature", 112, Rarity.RARE, mage.cards.d.DualNature.class)); + cards.add(new SetCardInfo("Elephant Resurgence", 113, Rarity.RARE, mage.cards.e.ElephantResurgence.class)); + cards.add(new SetCardInfo("Endbringer's Revel", 63, Rarity.UNCOMMON, mage.cards.e.EndbringersRevel.class)); + cards.add(new SetCardInfo("Entangler", 7, Rarity.UNCOMMON, mage.cards.e.Entangler.class)); + cards.add(new SetCardInfo("Excavation", 33, Rarity.UNCOMMON, mage.cards.e.Excavation.class)); + cards.add(new SetCardInfo("Excise", 8, Rarity.COMMON, mage.cards.e.Excise.class)); + cards.add(new SetCardInfo("Fault Riders", 88, Rarity.COMMON, mage.cards.f.FaultRiders.class)); + cards.add(new SetCardInfo("Fen Stalker", 64, Rarity.COMMON, mage.cards.f.FenStalker.class)); + cards.add(new SetCardInfo("Fickle Efreet", 89, Rarity.RARE, mage.cards.f.FickleEfreet.class)); + cards.add(new SetCardInfo("Flameshot", 90, Rarity.UNCOMMON, mage.cards.f.Flameshot.class)); + cards.add(new SetCardInfo("Flay", 65, Rarity.COMMON, mage.cards.f.Flay.class)); + cards.add(new SetCardInfo("Flowering Field", 9, Rarity.UNCOMMON, mage.cards.f.FloweringField.class)); + cards.add(new SetCardInfo("Foil", 34, Rarity.UNCOMMON, mage.cards.f.Foil.class)); + cards.add(new SetCardInfo("Forgotten Harvest", 114, Rarity.RARE, mage.cards.f.ForgottenHarvest.class)); + cards.add(new SetCardInfo("Glittering Lion", 10, Rarity.UNCOMMON, mage.cards.g.GlitteringLion.class)); + cards.add(new SetCardInfo("Glittering Lynx", 11, Rarity.COMMON, mage.cards.g.GlitteringLynx.class)); + cards.add(new SetCardInfo("Greel's Caress", 67, Rarity.COMMON, mage.cards.g.GreelsCaress.class)); + cards.add(new SetCardInfo("Greel, Mind Raker", 66, Rarity.RARE, mage.cards.g.GreelMindRaker.class)); + cards.add(new SetCardInfo("Gulf Squid", 35, Rarity.COMMON, mage.cards.g.GulfSquid.class)); + cards.add(new SetCardInfo("Hazy Homunculus", 36, Rarity.COMMON, mage.cards.h.HazyHomunculus.class)); + cards.add(new SetCardInfo("Heightened Awareness", 37, Rarity.RARE, mage.cards.h.HeightenedAwareness.class)); + cards.add(new SetCardInfo("Hollow Warrior", 138, Rarity.UNCOMMON, mage.cards.h.HollowWarrior.class)); + cards.add(new SetCardInfo("Infernal Genesis", 68, Rarity.RARE, mage.cards.i.InfernalGenesis.class)); + cards.add(new SetCardInfo("Inflame", 91, Rarity.COMMON, mage.cards.i.Inflame.class)); + cards.add(new SetCardInfo("Jeweled Spirit", 12, Rarity.RARE, mage.cards.j.JeweledSpirit.class)); + cards.add(new SetCardInfo("Jolrael, Empress of Beasts", 115, Rarity.RARE, mage.cards.j.JolraelEmpressOfBeasts.class)); + cards.add(new SetCardInfo("Jolrael's Favor", 116, Rarity.COMMON, mage.cards.j.JolraelsFavor.class)); + cards.add(new SetCardInfo("Keldon Arsonist", 92, Rarity.UNCOMMON, mage.cards.k.KeldonArsonist.class)); + cards.add(new SetCardInfo("Keldon Battlewagon", 139, Rarity.RARE, mage.cards.k.KeldonBattlewagon.class)); + cards.add(new SetCardInfo("Keldon Berserker", 93, Rarity.COMMON, mage.cards.k.KeldonBerserker.class)); + cards.add(new SetCardInfo("Keldon Firebombers", 94, Rarity.RARE, mage.cards.k.KeldonFirebombers.class)); + cards.add(new SetCardInfo("Latulla, Keldon Overseer", 95, Rarity.RARE, mage.cards.l.LatullaKeldonOverseer.class)); + cards.add(new SetCardInfo("Latulla's Orders", 96, Rarity.COMMON, mage.cards.l.LatullasOrders.class)); + cards.add(new SetCardInfo("Lesser Gargadon", 97, Rarity.UNCOMMON, mage.cards.l.LesserGargadon.class)); + cards.add(new SetCardInfo("Living Terrain", 117, Rarity.UNCOMMON, mage.cards.l.LivingTerrain.class)); + cards.add(new SetCardInfo("Mageta's Boon", 14, Rarity.COMMON, mage.cards.m.MagetasBoon.class)); + cards.add(new SetCardInfo("Mageta the Lion", 13, Rarity.RARE, mage.cards.m.MagetaTheLion.class)); + cards.add(new SetCardInfo("Mana Vapors", 38, Rarity.UNCOMMON, mage.cards.m.ManaVapors.class)); + cards.add(new SetCardInfo("Marsh Boa", 118, Rarity.COMMON, mage.cards.m.MarshBoa.class)); + cards.add(new SetCardInfo("Mercenary Informer", 15, Rarity.RARE, mage.cards.m.MercenaryInformer.class)); + cards.add(new SetCardInfo("Mine Bearer", 16, Rarity.COMMON, mage.cards.m.MineBearer.class)); + cards.add(new SetCardInfo("Mirror Strike", 17, Rarity.UNCOMMON, mage.cards.m.MirrorStrike.class)); + cards.add(new SetCardInfo("Mungha Wurm", 119, Rarity.RARE, mage.cards.m.MunghaWurm.class)); + cards.add(new SetCardInfo("Nakaya Shade", 69, Rarity.UNCOMMON, mage.cards.n.NakayaShade.class)); + cards.add(new SetCardInfo("Noxious Field", 70, Rarity.UNCOMMON, mage.cards.n.NoxiousField.class)); + cards.add(new SetCardInfo("Outbreak", 71, Rarity.UNCOMMON, mage.cards.o.Outbreak.class)); + cards.add(new SetCardInfo("Overburden", 39, Rarity.RARE, mage.cards.o.Overburden.class)); + cards.add(new SetCardInfo("Panic Attack", 98, Rarity.COMMON, mage.cards.p.PanicAttack.class)); + cards.add(new SetCardInfo("Pit Raptor", 72, Rarity.UNCOMMON, mage.cards.p.PitRaptor.class)); + cards.add(new SetCardInfo("Plague Fiend", 73, Rarity.COMMON, mage.cards.p.PlagueFiend.class)); + cards.add(new SetCardInfo("Plague Wind", 74, Rarity.RARE, mage.cards.p.PlagueWind.class)); + cards.add(new SetCardInfo("Psychic Theft", 40, Rarity.RARE, mage.cards.p.PsychicTheft.class)); + cards.add(new SetCardInfo("Pygmy Razorback", 120, Rarity.COMMON, mage.cards.p.PygmyRazorback.class)); + cards.add(new SetCardInfo("Quicksilver Wall", 41, Rarity.UNCOMMON, mage.cards.q.QuicksilverWall.class)); + cards.add(new SetCardInfo("Rebel Informer", 75, Rarity.RARE, mage.cards.r.RebelInformer.class)); + cards.add(new SetCardInfo("Rethink", 42, Rarity.COMMON, mage.cards.r.Rethink.class)); + cards.add(new SetCardInfo("Reveille Squad", 18, Rarity.UNCOMMON, mage.cards.r.ReveilleSquad.class)); + cards.add(new SetCardInfo("Rhystic Cave", 142, Rarity.UNCOMMON, mage.cards.r.RhysticCave.class)); + cards.add(new SetCardInfo("Rhystic Circle", 19, Rarity.COMMON, mage.cards.r.RhysticCircle.class)); + cards.add(new SetCardInfo("Rhystic Deluge", 43, Rarity.COMMON, mage.cards.r.RhysticDeluge.class)); + cards.add(new SetCardInfo("Rhystic Lightning", 99, Rarity.COMMON, mage.cards.r.RhysticLightning.class)); + cards.add(new SetCardInfo("Rhystic Scrying", 44, Rarity.UNCOMMON, mage.cards.r.RhysticScrying.class)); + cards.add(new SetCardInfo("Rhystic Shield", 20, Rarity.COMMON, mage.cards.r.RhysticShield.class)); + cards.add(new SetCardInfo("Rhystic Study", 45, Rarity.COMMON, mage.cards.r.RhysticStudy.class)); + cards.add(new SetCardInfo("Rhystic Syphon", 76, Rarity.UNCOMMON, mage.cards.r.RhysticSyphon.class)); + cards.add(new SetCardInfo("Rhystic Tutor", 77, Rarity.RARE, mage.cards.r.RhysticTutor.class)); + cards.add(new SetCardInfo("Ribbon Snake", 46, Rarity.COMMON, mage.cards.r.RibbonSnake.class)); + cards.add(new SetCardInfo("Rib Cage Spider", 121, Rarity.COMMON, mage.cards.r.RibCageSpider.class)); + cards.add(new SetCardInfo("Ridgeline Rager", 100, Rarity.COMMON, mage.cards.r.RidgelineRager.class)); + cards.add(new SetCardInfo("Root Cage", 122, Rarity.UNCOMMON, mage.cards.r.RootCage.class)); + cards.add(new SetCardInfo("Samite Sanctuary", 21, Rarity.RARE, mage.cards.s.SamiteSanctuary.class)); + cards.add(new SetCardInfo("Scoria Cat", 101, Rarity.UNCOMMON, mage.cards.s.ScoriaCat.class)); + cards.add(new SetCardInfo("Search for Survivors", 102, Rarity.RARE, mage.cards.s.SearchForSurvivors.class)); + cards.add(new SetCardInfo("Searing Wind", 103, Rarity.RARE, mage.cards.s.SearingWind.class)); + cards.add(new SetCardInfo("Sheltering Prayers", 22, Rarity.RARE, mage.cards.s.ShelteringPrayers.class)); + cards.add(new SetCardInfo("Shield Dancer", 23, Rarity.UNCOMMON, mage.cards.s.ShieldDancer.class)); + cards.add(new SetCardInfo("Shrouded Serpent", 47, Rarity.RARE, mage.cards.s.ShroudedSerpent.class)); + cards.add(new SetCardInfo("Silt Crawler", 123, Rarity.COMMON, mage.cards.s.SiltCrawler.class)); + cards.add(new SetCardInfo("Snag", 124, Rarity.UNCOMMON, mage.cards.s.Snag.class)); + cards.add(new SetCardInfo("Soul Charmer", 24, Rarity.COMMON, mage.cards.s.SoulCharmer.class)); + cards.add(new SetCardInfo("Soul Strings", 78, Rarity.COMMON, mage.cards.s.SoulStrings.class)); + cards.add(new SetCardInfo("Spiketail Drake", 48, Rarity.UNCOMMON, mage.cards.s.SpiketailDrake.class)); + cards.add(new SetCardInfo("Spiketail Hatchling", 49, Rarity.COMMON, mage.cards.s.SpiketailHatchling.class)); + cards.add(new SetCardInfo("Spitting Spider", 125, Rarity.UNCOMMON, mage.cards.s.SpittingSpider.class)); + cards.add(new SetCardInfo("Spore Frog", 126, Rarity.COMMON, mage.cards.s.SporeFrog.class)); + cards.add(new SetCardInfo("Spur Grappler", 104, Rarity.COMMON, mage.cards.s.SpurGrappler.class)); + cards.add(new SetCardInfo("Squirrel Wrangler", 127, Rarity.RARE, mage.cards.s.SquirrelWrangler.class)); + cards.add(new SetCardInfo("Steal Strength", 79, Rarity.COMMON, mage.cards.s.StealStrength.class)); + cards.add(new SetCardInfo("Stormwatch Eagle", 50, Rarity.COMMON, mage.cards.s.StormwatchEagle.class)); + cards.add(new SetCardInfo("Sunken Field", 51, Rarity.UNCOMMON, mage.cards.s.SunkenField.class)); + cards.add(new SetCardInfo("Sword Dancer", 25, Rarity.UNCOMMON, mage.cards.s.SwordDancer.class)); + cards.add(new SetCardInfo("Task Mage Assembly", 105, Rarity.RARE, mage.cards.t.TaskMageAssembly.class)); + cards.add(new SetCardInfo("Thresher Beast", 128, Rarity.COMMON, mage.cards.t.ThresherBeast.class)); + cards.add(new SetCardInfo("Thrive", 129, Rarity.COMMON, mage.cards.t.Thrive.class)); + cards.add(new SetCardInfo("Trenching Steed", 26, Rarity.COMMON, mage.cards.t.TrenchingSteed.class)); + cards.add(new SetCardInfo("Troubled Healer", 27, Rarity.COMMON, mage.cards.t.TroubledHealer.class)); + cards.add(new SetCardInfo("Troublesome Spirit", 52, Rarity.RARE, mage.cards.t.TroublesomeSpirit.class)); + cards.add(new SetCardInfo("Verdant Field", 130, Rarity.UNCOMMON, mage.cards.v.VerdantField.class)); + cards.add(new SetCardInfo("Veteran Brawlers", 106, Rarity.RARE, mage.cards.v.VeteranBrawlers.class)); + cards.add(new SetCardInfo("Vintara Elephant", 131, Rarity.COMMON, mage.cards.v.VintaraElephant.class)); + cards.add(new SetCardInfo("Vintara Snapper", 132, Rarity.UNCOMMON, mage.cards.v.VintaraSnapper.class)); + cards.add(new SetCardInfo("Vitalizing Wind", 133, Rarity.RARE, mage.cards.v.VitalizingWind.class)); + cards.add(new SetCardInfo("Wall of Vipers", 80, Rarity.UNCOMMON, mage.cards.w.WallOfVipers.class)); + cards.add(new SetCardInfo("Well of Discovery", 140, Rarity.RARE, mage.cards.w.WellOfDiscovery.class)); + cards.add(new SetCardInfo("Well of Life", 141, Rarity.UNCOMMON, mage.cards.w.WellOfLife.class)); + cards.add(new SetCardInfo("Whip Sergeant", 107, Rarity.UNCOMMON, mage.cards.w.WhipSergeant.class)); + cards.add(new SetCardInfo("Whipstitched Zombie", 81, Rarity.COMMON, mage.cards.w.WhipstitchedZombie.class)); + cards.add(new SetCardInfo("Wild Might", 134, Rarity.COMMON, mage.cards.w.WildMight.class)); + cards.add(new SetCardInfo("Windscouter", 53, Rarity.UNCOMMON, mage.cards.w.Windscouter.class)); + cards.add(new SetCardInfo("Wing Storm", 135, Rarity.UNCOMMON, mage.cards.w.WingStorm.class)); + cards.add(new SetCardInfo("Wintermoon Mesa", 143, Rarity.RARE, mage.cards.w.WintermoonMesa.class)); + cards.add(new SetCardInfo("Withdraw", 54, Rarity.COMMON, mage.cards.w.Withdraw.class)); + cards.add(new SetCardInfo("Zerapa Minotaur", 108, Rarity.COMMON, mage.cards.z.ZerapaMinotaur.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegiance.java b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java new file mode 100644 index 0000000000..735ad45eb1 --- /dev/null +++ b/Mage.Sets/src/mage/sets/RavnicaAllegiance.java @@ -0,0 +1,346 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.CardType; +import mage.constants.Rarity; +import mage.constants.SetType; + +import java.util.ArrayList; +import java.util.List; + +public final class RavnicaAllegiance extends ExpansionSet { + + private static final RavnicaAllegiance instance = new RavnicaAllegiance(); + + public static RavnicaAllegiance getInstance() { + return instance; + } + + private RavnicaAllegiance() { + super("Ravnica Allegiance", "RNA", ExpansionSet.buildDate(2019, 1, 25), SetType.EXPANSION); + this.blockName = "Guilds of Ravnica"; + this.hasBoosters = true; + this.numBoosterSpecial = 1; + this.numBoosterLands = 0; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.maxCardNumberInBooster = 259; + + cards.add(new SetCardInfo("Absorb", 151, Rarity.RARE, mage.cards.a.Absorb.class)); + cards.add(new SetCardInfo("Act of Treason", 91, Rarity.COMMON, mage.cards.a.ActOfTreason.class)); + cards.add(new SetCardInfo("Aeromunculus", 152, Rarity.COMMON, mage.cards.a.Aeromunculus.class)); + cards.add(new SetCardInfo("Amplifire", 92, Rarity.RARE, mage.cards.a.Amplifire.class)); + cards.add(new SetCardInfo("Angel of Grace", 1, Rarity.MYTHIC, mage.cards.a.AngelOfGrace.class)); + cards.add(new SetCardInfo("Angelic Exaltation", 2, Rarity.UNCOMMON, mage.cards.a.AngelicExaltation.class)); + cards.add(new SetCardInfo("Applied Biomancy", 153, Rarity.COMMON, mage.cards.a.AppliedBiomancy.class)); + cards.add(new SetCardInfo("Archway Angel", 3, Rarity.UNCOMMON, mage.cards.a.ArchwayAngel.class)); + cards.add(new SetCardInfo("Arrester's Admonition", 31, Rarity.COMMON, mage.cards.a.ArrestersAdmonition.class)); + cards.add(new SetCardInfo("Arrester's Zeal", 4, Rarity.COMMON, mage.cards.a.ArrestersZeal.class)); + cards.add(new SetCardInfo("Awaken the Erstwhile", 61, Rarity.RARE, mage.cards.a.AwakenTheErstwhile.class)); + cards.add(new SetCardInfo("Axebane Beast", 121, Rarity.COMMON, mage.cards.a.AxebaneBeast.class)); + cards.add(new SetCardInfo("Azorius Guildgate", 243, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azorius Guildgate", 244, Rarity.COMMON, mage.cards.a.AzoriusGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Azorius Knight-Arbiter", 154, Rarity.COMMON, mage.cards.a.AzoriusKnightArbiter.class)); + cards.add(new SetCardInfo("Azorius Locket", 231, Rarity.COMMON, mage.cards.a.AzoriusLocket.class)); + cards.add(new SetCardInfo("Azorius Skyguard", 155, Rarity.UNCOMMON, mage.cards.a.AzoriusSkyguard.class)); + cards.add(new SetCardInfo("Bankrupt in Blood", 62, Rarity.UNCOMMON, mage.cards.b.BankruptInBlood.class)); + cards.add(new SetCardInfo("Basilica Bell-Haunt", 156, Rarity.UNCOMMON, mage.cards.b.BasilicaBellHaunt.class)); + cards.add(new SetCardInfo("Bedeck // Bedazzle", 221, Rarity.RARE, mage.cards.b.BedeckBedazzle.class)); + cards.add(new SetCardInfo("Bedevil", 157, Rarity.RARE, mage.cards.b.Bedevil.class)); + cards.add(new SetCardInfo("Benthic Biomancer", 32, Rarity.RARE, mage.cards.b.BenthicBiomancer.class)); + cards.add(new SetCardInfo("Biogenic Ooze", 122, Rarity.MYTHIC, mage.cards.b.BiogenicOoze.class)); + cards.add(new SetCardInfo("Biogenic Upgrade", 123, Rarity.UNCOMMON, mage.cards.b.BiogenicUpgrade.class)); + cards.add(new SetCardInfo("Biomancer's Familiar", 158, Rarity.RARE, mage.cards.b.BiomancersFamiliar.class)); + cards.add(new SetCardInfo("Blade Juggler", 63, Rarity.COMMON, mage.cards.b.BladeJuggler.class)); + cards.add(new SetCardInfo("Bladebrand", 64, Rarity.COMMON, mage.cards.b.Bladebrand.class)); + cards.add(new SetCardInfo("Blood Crypt", 245, Rarity.RARE, mage.cards.b.BloodCrypt.class)); + cards.add(new SetCardInfo("Bloodmist Infiltrator", 65, Rarity.UNCOMMON, mage.cards.b.BloodmistInfiltrator.class)); + cards.add(new SetCardInfo("Bolrac-Clan Crusher", 159, Rarity.UNCOMMON, mage.cards.b.BolracClanCrusher.class)); + cards.add(new SetCardInfo("Breeding Pool", 246, Rarity.RARE, mage.cards.b.BreedingPool.class)); + cards.add(new SetCardInfo("Bring to Trial", 5, Rarity.COMMON, mage.cards.b.BringToTrial.class)); + cards.add(new SetCardInfo("Burn Bright", 93, Rarity.COMMON, mage.cards.b.BurnBright.class)); + cards.add(new SetCardInfo("Burning-Tree Vandal", 94, Rarity.COMMON, mage.cards.b.BurningTreeVandal.class)); + cards.add(new SetCardInfo("Captive Audience", 160, Rarity.MYTHIC, mage.cards.c.CaptiveAudience.class)); + cards.add(new SetCardInfo("Carnival // Carnage", 222, Rarity.UNCOMMON, mage.cards.c.CarnivalCarnage.class)); + cards.add(new SetCardInfo("Carrion Imp", 66, Rarity.COMMON, mage.cards.c.CarrionImp.class)); + cards.add(new SetCardInfo("Catacomb Crocodile", 67, Rarity.COMMON, mage.cards.c.CatacombCrocodile.class)); + cards.add(new SetCardInfo("Cavalcade of Calamity", 95, Rarity.UNCOMMON, mage.cards.c.CavalcadeOfCalamity.class)); + cards.add(new SetCardInfo("Charging War Boar", 271, Rarity.UNCOMMON, mage.cards.c.ChargingWarBoar.class)); + cards.add(new SetCardInfo("Chillbringer", 33, Rarity.COMMON, mage.cards.c.Chillbringer.class)); + cards.add(new SetCardInfo("Cindervines", 161, Rarity.RARE, mage.cards.c.Cindervines.class)); + cards.add(new SetCardInfo("Civic Stalwart", 6, Rarity.COMMON, mage.cards.c.CivicStalwart.class)); + cards.add(new SetCardInfo("Clamor Shaman", 96, Rarity.UNCOMMON, mage.cards.c.ClamorShaman.class)); + cards.add(new SetCardInfo("Clan Guildmage", 162, Rarity.UNCOMMON, mage.cards.c.ClanGuildmage.class)); + cards.add(new SetCardInfo("Clear the Mind", 34, Rarity.COMMON, mage.cards.c.ClearTheMind.class)); + cards.add(new SetCardInfo("Clear the Stage", 68, Rarity.UNCOMMON, mage.cards.c.ClearTheStage.class)); + cards.add(new SetCardInfo("Code of Constraint", 35, Rarity.UNCOMMON, mage.cards.c.CodeOfConstraint.class)); + cards.add(new SetCardInfo("Collision // Colossus", 223, Rarity.UNCOMMON, mage.cards.c.CollisionColossus.class)); + cards.add(new SetCardInfo("Combine Guildmage", 163, Rarity.UNCOMMON, mage.cards.c.CombineGuildmage.class)); + cards.add(new SetCardInfo("Consecrate // Consume", 224, Rarity.UNCOMMON, mage.cards.c.ConsecrateConsume.class)); + cards.add(new SetCardInfo("Concordia Pegasus", 7, Rarity.COMMON, mage.cards.c.ConcordiaPegasus.class)); + cards.add(new SetCardInfo("Consign to the Pit", 69, Rarity.COMMON, mage.cards.c.ConsignToThePit.class)); + cards.add(new SetCardInfo("Coral Commando", 36, Rarity.COMMON, mage.cards.c.CoralCommando.class)); + cards.add(new SetCardInfo("Cry of the Carnarium", 70, Rarity.UNCOMMON, mage.cards.c.CryOfTheCarnarium.class)); + cards.add(new SetCardInfo("Cult Guildmage", 164, Rarity.UNCOMMON, mage.cards.c.CultGuildmage.class)); + cards.add(new SetCardInfo("Dagger Caster", 97, Rarity.UNCOMMON, mage.cards.d.DaggerCaster.class)); + cards.add(new SetCardInfo("Dead Revels", 71, Rarity.COMMON, mage.cards.d.DeadRevels.class)); + cards.add(new SetCardInfo("Debtors' Transport", 72, Rarity.COMMON, mage.cards.d.DebtorsTransport.class)); + cards.add(new SetCardInfo("Deface", 98, Rarity.COMMON, mage.cards.d.Deface.class)); + cards.add(new SetCardInfo("Depose // Deploy", 225, Rarity.UNCOMMON, mage.cards.d.DeposeDeploy.class)); + cards.add(new SetCardInfo("Deputy of Detention", 165, Rarity.RARE, mage.cards.d.DeputyOfDetention.class)); + cards.add(new SetCardInfo("Domri's Nodorog", 272, Rarity.RARE, mage.cards.d.DomrisNodorog.class)); + cards.add(new SetCardInfo("Domri, Chaos Bringer", 166, Rarity.MYTHIC, mage.cards.d.DomriChaosBringer.class)); + cards.add(new SetCardInfo("Domri, City Smasher", 269, Rarity.MYTHIC, mage.cards.d.DomriCitySmasher.class)); + cards.add(new SetCardInfo("Dovin's Acuity", 168, Rarity.UNCOMMON, mage.cards.d.DovinsAcuity.class)); + cards.add(new SetCardInfo("Dovin's Automaton", 268, Rarity.UNCOMMON, mage.cards.d.DovinsAutomaton.class)); + cards.add(new SetCardInfo("Dovin's Dismissal", 267, Rarity.RARE, mage.cards.d.DovinsDismissal.class)); + cards.add(new SetCardInfo("Dovin, Architect of Law", 265, Rarity.MYTHIC, mage.cards.d.DovinArchitectOfLaw.class)); + cards.add(new SetCardInfo("Dovin, Grand Arbiter", 167, Rarity.MYTHIC, mage.cards.d.DovinGrandArbiter.class)); + cards.add(new SetCardInfo("Drill Bit", 73, Rarity.UNCOMMON, mage.cards.d.DrillBit.class)); + cards.add(new SetCardInfo("Electrodominance", 99, Rarity.RARE, mage.cards.e.Electrodominance.class)); + cards.add(new SetCardInfo("Elite Arrester", 266, Rarity.COMMON, mage.cards.e.EliteArrester.class)); + cards.add(new SetCardInfo("Emergency Powers", 169, Rarity.MYTHIC, mage.cards.e.EmergencyPowers.class)); + cards.add(new SetCardInfo("End-Raze Forerunners", 124, Rarity.RARE, mage.cards.e.EndRazeForerunners.class)); + cards.add(new SetCardInfo("Enraged Ceratok", 125, Rarity.UNCOMMON, mage.cards.e.EnragedCeratok.class)); + cards.add(new SetCardInfo("Essence Capture", 37, Rarity.UNCOMMON, mage.cards.e.EssenceCapture.class)); + cards.add(new SetCardInfo("Ethereal Absolution", 170, Rarity.RARE, mage.cards.e.EtherealAbsolution.class)); + cards.add(new SetCardInfo("Expose to Daylight", 8, Rarity.COMMON, mage.cards.e.ExposeToDaylight.class)); + cards.add(new SetCardInfo("Eyes Everywhere", 38, Rarity.UNCOMMON, mage.cards.e.EyesEverywhere.class)); + cards.add(new SetCardInfo("Faerie Duelist", 39, Rarity.COMMON, mage.cards.f.FaerieDuelist.class)); + cards.add(new SetCardInfo("Feral Maaka", 100, Rarity.COMMON, mage.cards.f.FeralMaaka.class)); + cards.add(new SetCardInfo("Final Payment", 171, Rarity.COMMON, mage.cards.f.FinalPayment.class)); + cards.add(new SetCardInfo("Fireblade Artist", 172, Rarity.UNCOMMON, mage.cards.f.FirebladeArtist.class)); + cards.add(new SetCardInfo("Flames of the Raze-Boar", 101, Rarity.UNCOMMON, mage.cards.f.FlamesOfTheRazeBoar.class)); + cards.add(new SetCardInfo("Font of Agonies", 74, Rarity.RARE, mage.cards.f.FontOfAgonies.class)); + cards.add(new SetCardInfo("Footlight Fiend", 216, Rarity.COMMON, mage.cards.f.FootlightFiend.class)); + cards.add(new SetCardInfo("Forbidding Spirit", 9, Rarity.UNCOMMON, mage.cards.f.ForbiddingSpirit.class)); + cards.add(new SetCardInfo("Forest", 264, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Frenzied Arynx", 173, Rarity.COMMON, mage.cards.f.FrenziedArynx.class)); + cards.add(new SetCardInfo("Frilled Mystic", 174, Rarity.UNCOMMON, mage.cards.f.FrilledMystic.class)); + cards.add(new SetCardInfo("Galloping Lizrog", 175, Rarity.UNCOMMON, mage.cards.g.GallopingLizrog.class)); + cards.add(new SetCardInfo("Gate Colossus", 232, Rarity.UNCOMMON, mage.cards.g.GateColossus.class)); + cards.add(new SetCardInfo("Gatebreaker Ram", 126, Rarity.UNCOMMON, mage.cards.g.GatebreakerRam.class)); + cards.add(new SetCardInfo("Gates Ablaze", 102, Rarity.UNCOMMON, mage.cards.g.GatesAblaze.class)); + cards.add(new SetCardInfo("Gateway Plaza", 247, Rarity.COMMON, mage.cards.g.GatewayPlaza.class)); + cards.add(new SetCardInfo("Gateway Sneak", 40, Rarity.UNCOMMON, mage.cards.g.GatewaySneak.class)); + cards.add(new SetCardInfo("Get the Point", 176, Rarity.COMMON, mage.cards.g.GetThePoint.class)); + cards.add(new SetCardInfo("Ghor-Clan Wrecker", 103, Rarity.COMMON, mage.cards.g.GhorClanWrecker.class)); + cards.add(new SetCardInfo("Gift of Strength", 127, Rarity.COMMON, mage.cards.g.GiftOfStrength.class)); + cards.add(new SetCardInfo("Glass of the Guildpact", 233, Rarity.RARE, mage.cards.g.GlassOfTheGuildpact.class)); + cards.add(new SetCardInfo("Goblin Gathering", 104, Rarity.COMMON, mage.cards.g.GoblinGathering.class)); + cards.add(new SetCardInfo("Godless Shrine", 248, Rarity.RARE, mage.cards.g.GodlessShrine.class)); + cards.add(new SetCardInfo("Grasping Thrull", 177, Rarity.COMMON, mage.cards.g.GraspingThrull.class)); + cards.add(new SetCardInfo("Gravel-Hide Goblin", 105, Rarity.COMMON, mage.cards.g.GravelHideGoblin.class)); + cards.add(new SetCardInfo("Grotesque Demise", 75, Rarity.COMMON, mage.cards.g.GrotesqueDemise.class)); + cards.add(new SetCardInfo("Growth Spiral", 178, Rarity.COMMON, mage.cards.g.GrowthSpiral.class)); + cards.add(new SetCardInfo("Growth-Chamber Guardian", 128, Rarity.RARE, mage.cards.g.GrowthChamberGuardian.class)); + cards.add(new SetCardInfo("Gruul Beastmaster", 129, Rarity.UNCOMMON, mage.cards.g.GruulBeastmaster.class)); + cards.add(new SetCardInfo("Gruul Guildgate", 249, Rarity.COMMON, mage.cards.g.GruulGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gruul Guildgate", 250, Rarity.COMMON, mage.cards.g.GruulGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gruul Locket", 234, Rarity.COMMON, mage.cards.g.GruulLocket.class)); + cards.add(new SetCardInfo("Gruul Spellbreaker", 179, Rarity.RARE, mage.cards.g.GruulSpellbreaker.class)); + cards.add(new SetCardInfo("Guardian Project", 130, Rarity.RARE, mage.cards.g.GuardianProject.class)); + cards.add(new SetCardInfo("Gutterbones", 76, Rarity.RARE, mage.cards.g.Gutterbones.class)); + cards.add(new SetCardInfo("Gyre Engineer", 180, Rarity.UNCOMMON, mage.cards.g.GyreEngineer.class)); + cards.add(new SetCardInfo("Haazda Officer", 10, Rarity.COMMON, mage.cards.h.HaazdaOfficer.class)); + cards.add(new SetCardInfo("Hackrobat", 181, Rarity.UNCOMMON, mage.cards.h.Hackrobat.class)); + cards.add(new SetCardInfo("Hallowed Fountain", 251, Rarity.RARE, mage.cards.h.HallowedFountain.class)); + cards.add(new SetCardInfo("Hero of Precinct One", 11, Rarity.RARE, mage.cards.h.HeroOfPrecinctOne.class)); + cards.add(new SetCardInfo("High Alert", 182, Rarity.UNCOMMON, mage.cards.h.HighAlert.class)); + cards.add(new SetCardInfo("Humongulus", 41, Rarity.COMMON, mage.cards.h.Humongulus.class)); + cards.add(new SetCardInfo("Hydroid Krasis", 183, Rarity.MYTHIC, mage.cards.h.HydroidKrasis.class)); + cards.add(new SetCardInfo("Ill-Gotten Inheritance", 77, Rarity.COMMON, mage.cards.i.IllGottenInheritance.class)); + cards.add(new SetCardInfo("Immolation Shaman", 106, Rarity.RARE, mage.cards.i.ImmolationShaman.class)); + cards.add(new SetCardInfo("Impassioned Orator", 12, Rarity.COMMON, mage.cards.i.ImpassionedOrator.class)); + cards.add(new SetCardInfo("Imperious Oligarch", 184, Rarity.COMMON, mage.cards.i.ImperiousOligarch.class)); + cards.add(new SetCardInfo("Incubation // Incongruity", 226, Rarity.UNCOMMON, mage.cards.i.IncubationIncongruity.class)); + cards.add(new SetCardInfo("Incubation Druid", 131, Rarity.RARE, mage.cards.i.IncubationDruid.class)); + cards.add(new SetCardInfo("Island", 261, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Judith, the Scourge Diva", 185, Rarity.RARE, mage.cards.j.JudithTheScourgeDiva.class)); + cards.add(new SetCardInfo("Junktroller", 235, Rarity.UNCOMMON, mage.cards.j.Junktroller.class)); + cards.add(new SetCardInfo("Justiciar's Portal", 13, Rarity.COMMON, mage.cards.j.JusticiarsPortal.class)); + cards.add(new SetCardInfo("Kaya's Wrath", 187, Rarity.RARE, mage.cards.k.KayasWrath.class)); + cards.add(new SetCardInfo("Kaya, Orzhov Usurper", 186, Rarity.MYTHIC, mage.cards.k.KayaOrzhovUsurper.class)); + cards.add(new SetCardInfo("Knight of Sorrows", 14, Rarity.COMMON, mage.cards.k.KnightOfSorrows.class)); + cards.add(new SetCardInfo("Knight of the Last Breath", 188, Rarity.UNCOMMON, mage.cards.k.KnightOfTheLastBreath.class)); + cards.add(new SetCardInfo("Lavinia, Azorius Renegade", 189, Rarity.RARE, mage.cards.l.LaviniaAzoriusRenegade.class)); + cards.add(new SetCardInfo("Lawmage's Binding", 190, Rarity.COMMON, mage.cards.l.LawmagesBinding.class)); + cards.add(new SetCardInfo("Light Up the Stage", 107, Rarity.UNCOMMON, mage.cards.l.LightUpTheStage.class)); + cards.add(new SetCardInfo("Lumbering Battlement", 15, Rarity.RARE, mage.cards.l.LumberingBattlement.class)); + cards.add(new SetCardInfo("Macabre Mockery", 191, Rarity.UNCOMMON, mage.cards.m.MacabreMockery.class)); + cards.add(new SetCardInfo("Mammoth Spider", 132, Rarity.COMMON, mage.cards.m.MammothSpider.class)); + cards.add(new SetCardInfo("Mass Manipulation", 42, Rarity.RARE, mage.cards.m.MassManipulation.class)); + cards.add(new SetCardInfo("Mesmerizing Benthid", 43, Rarity.MYTHIC, mage.cards.m.MesmerizingBenthid.class)); + cards.add(new SetCardInfo("Ministrant of Obligation", 16, Rarity.UNCOMMON, mage.cards.m.MinistrantOfObligation.class)); + cards.add(new SetCardInfo("Mirror March", 108, Rarity.RARE, mage.cards.m.MirrorMarch.class)); + cards.add(new SetCardInfo("Mortify", 192, Rarity.UNCOMMON, mage.cards.m.Mortify.class)); + cards.add(new SetCardInfo("Mountain", 263, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Nikya of the Old Ways", 193, Rarity.RARE, mage.cards.n.NikyaOfTheOldWays.class)); + cards.add(new SetCardInfo("Noxious Groodion", 78, Rarity.COMMON, mage.cards.n.NoxiousGroodion.class)); + cards.add(new SetCardInfo("Open the Gates", 133, Rarity.COMMON, mage.cards.o.OpenTheGates.class)); + cards.add(new SetCardInfo("Orzhov Enforcer", 79, Rarity.UNCOMMON, mage.cards.o.OrzhovEnforcer.class)); + cards.add(new SetCardInfo("Orzhov Guildgate", 252, Rarity.COMMON, mage.cards.o.OrzhovGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Orzhov Guildgate", 253, Rarity.COMMON, mage.cards.o.OrzhovGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Orzhov Locket", 236, Rarity.COMMON, mage.cards.o.OrzhovLocket.class)); + cards.add(new SetCardInfo("Orzhov Racketeers", 80, Rarity.UNCOMMON, mage.cards.o.OrzhovRacketeers.class)); + cards.add(new SetCardInfo("Persistent Petitioners", 44, Rarity.COMMON, mage.cards.p.PersistentPetitioners.class)); + cards.add(new SetCardInfo("Pestilent Spirit", 81, Rarity.RARE, mage.cards.p.PestilentSpirit.class)); + cards.add(new SetCardInfo("Pitiless Pontiff", 194, Rarity.UNCOMMON, mage.cards.p.PitilessPontiff.class)); + cards.add(new SetCardInfo("Plague Wight", 82, Rarity.COMMON, mage.cards.p.PlagueWight.class)); + cards.add(new SetCardInfo("Plains", 260, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plaza of Harmony", 254, Rarity.RARE, mage.cards.p.PlazaOfHarmony.class)); + cards.add(new SetCardInfo("Precognitive Perception", 45, Rarity.RARE, mage.cards.p.PrecognitivePerception.class)); + cards.add(new SetCardInfo("Priest of Forgotten Gods", 83, Rarity.RARE, mage.cards.p.PriestOfForgottenGods.class)); + cards.add(new SetCardInfo("Prime Speaker Vannifar", 195, Rarity.MYTHIC, mage.cards.p.PrimeSpeakerVannifar.class)); + cards.add(new SetCardInfo("Prowling Caracal", 17, Rarity.COMMON, mage.cards.p.ProwlingCaracal.class)); + cards.add(new SetCardInfo("Prying Eyes", 46, Rarity.COMMON, mage.cards.p.PryingEyes.class)); + cards.add(new SetCardInfo("Pteramander", 47, Rarity.UNCOMMON, mage.cards.p.Pteramander.class)); + cards.add(new SetCardInfo("Quench", 48, Rarity.COMMON, mage.cards.q.Quench.class)); + cards.add(new SetCardInfo("Rafter Demon", 196, Rarity.COMMON, mage.cards.r.RafterDemon.class)); + cards.add(new SetCardInfo("Ragefire", 270, Rarity.COMMON, mage.cards.r.Ragefire.class)); + cards.add(new SetCardInfo("Rakdos Firewheeler", 197, Rarity.UNCOMMON, mage.cards.r.RakdosFirewheeler.class)); + cards.add(new SetCardInfo("Rakdos Guildgate", 255, Rarity.COMMON, mage.cards.r.RakdosGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakdos Guildgate", 256, Rarity.COMMON, mage.cards.r.RakdosGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakdos Locket", 237, Rarity.COMMON, mage.cards.r.RakdosLocket.class)); + cards.add(new SetCardInfo("Rakdos Roustabout", 198, Rarity.COMMON, mage.cards.r.RakdosRoustabout.class)); + cards.add(new SetCardInfo("Rakdos Trumpeter", 84, Rarity.COMMON, mage.cards.r.RakdosTrumpeter.class)); + cards.add(new SetCardInfo("Rakdos, the Showstopper", 199, Rarity.MYTHIC, mage.cards.r.RakdosTheShowstopper.class)); + cards.add(new SetCardInfo("Rally to Battle", 18, Rarity.UNCOMMON, mage.cards.r.RallyToBattle.class)); + cards.add(new SetCardInfo("Rampage of the Clans", 134, Rarity.RARE, mage.cards.r.RampageOfTheClans.class)); + cards.add(new SetCardInfo("Rampaging Rendhorn", 135, Rarity.COMMON, mage.cards.r.RampagingRendhorn.class)); + cards.add(new SetCardInfo("Ravager Wurm", 200, Rarity.MYTHIC, mage.cards.r.RavagerWurm.class)); + cards.add(new SetCardInfo("Regenesis", 136, Rarity.UNCOMMON, mage.cards.r.Regenesis.class)); + cards.add(new SetCardInfo("Repudiate // Replicate", 227, Rarity.RARE, mage.cards.r.RepudiateReplicate.class)); + cards.add(new SetCardInfo("Resolute Watchdog", 19, Rarity.UNCOMMON, mage.cards.r.ResoluteWatchdog.class)); + cards.add(new SetCardInfo("Revival // Revenge", 228, Rarity.RARE, mage.cards.r.RevivalRevenge.class)); + cards.add(new SetCardInfo("Rhythm of the Wild", 201, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class)); + cards.add(new SetCardInfo("Rix Maadi Reveler", 109, Rarity.RARE, mage.cards.r.RixMaadiReveler.class)); + cards.add(new SetCardInfo("Root Snare", 137, Rarity.COMMON, mage.cards.r.RootSnare.class)); + cards.add(new SetCardInfo("Rubble Reading", 110, Rarity.COMMON, mage.cards.r.RubbleReading.class)); + cards.add(new SetCardInfo("Rubble Slinger", 217, Rarity.COMMON, mage.cards.r.RubbleSlinger.class)); + cards.add(new SetCardInfo("Rubblebelt Recluse", 111, Rarity.COMMON, mage.cards.r.RubblebeltRecluse.class)); + cards.add(new SetCardInfo("Rubblebelt Runner", 202, Rarity.COMMON, mage.cards.r.RubblebeltRunner.class)); + cards.add(new SetCardInfo("Rumbling Ruin", 112, Rarity.UNCOMMON, mage.cards.r.RumblingRuin.class)); + cards.add(new SetCardInfo("Sage's Row Savant", 49, Rarity.COMMON, mage.cards.s.SagesRowSavant.class)); + cards.add(new SetCardInfo("Sagittars' Volley", 138, Rarity.COMMON, mage.cards.s.SagittarsVolley.class)); + cards.add(new SetCardInfo("Saruli Caretaker", 139, Rarity.COMMON, mage.cards.s.SaruliCaretaker.class)); + cards.add(new SetCardInfo("Sauroform Hybrid", 140, Rarity.COMMON, mage.cards.s.SauroformHybrid.class)); + cards.add(new SetCardInfo("Savage Smash", 203, Rarity.COMMON, mage.cards.s.SavageSmash.class)); + cards.add(new SetCardInfo("Scorchmark", 113, Rarity.COMMON, mage.cards.s.Scorchmark.class)); + cards.add(new SetCardInfo("Scrabbling Claws", 238, Rarity.UNCOMMON, mage.cards.s.ScrabblingClaws.class)); + cards.add(new SetCardInfo("Screaming Shield", 239, Rarity.UNCOMMON, mage.cards.s.ScreamingShield.class)); + cards.add(new SetCardInfo("Scuttlegator", 218, Rarity.COMMON, mage.cards.s.Scuttlegator.class)); + cards.add(new SetCardInfo("Senate Courier", 50, Rarity.COMMON, mage.cards.s.SenateCourier.class)); + cards.add(new SetCardInfo("Senate Griffin", 219, Rarity.COMMON, mage.cards.s.SenateGriffin.class)); + cards.add(new SetCardInfo("Senate Guildmage", 204, Rarity.UNCOMMON, mage.cards.s.SenateGuildmage.class)); + cards.add(new SetCardInfo("Sentinel's Mark", 20, Rarity.UNCOMMON, mage.cards.s.SentinelsMark.class)); + cards.add(new SetCardInfo("Seraph of the Scales", 205, Rarity.MYTHIC, mage.cards.s.SeraphOfTheScales.class)); + cards.add(new SetCardInfo("Sharktocrab", 206, Rarity.UNCOMMON, mage.cards.s.Sharktocrab.class)); + cards.add(new SetCardInfo("Shimmer of Possibility", 51, Rarity.COMMON, mage.cards.s.ShimmerOfPossibility.class)); + cards.add(new SetCardInfo("Silhana Wayfinder", 141, Rarity.UNCOMMON, mage.cards.s.SilhanaWayfinder.class)); + cards.add(new SetCardInfo("Simic Ascendancy", 207, Rarity.RARE, mage.cards.s.SimicAscendancy.class)); + cards.add(new SetCardInfo("Simic Guildgate", 257, Rarity.COMMON, mage.cards.s.SimicGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Simic Guildgate", 258, Rarity.COMMON, mage.cards.s.SimicGuildgate.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Simic Locket", 240, Rarity.COMMON, mage.cards.s.SimicLocket.class)); + cards.add(new SetCardInfo("Skarrgan Hellkite", 114, Rarity.MYTHIC, mage.cards.s.SkarrganHellkite.class)); + cards.add(new SetCardInfo("Skatewing Spy", 52, Rarity.UNCOMMON, mage.cards.s.SkatewingSpy.class)); + cards.add(new SetCardInfo("Skewer the Critics", 115, Rarity.COMMON, mage.cards.s.SkewerTheCritics.class)); + cards.add(new SetCardInfo("Skitter Eel", 53, Rarity.COMMON, mage.cards.s.SkitterEel.class)); + cards.add(new SetCardInfo("Sky Tether", 21, Rarity.UNCOMMON, mage.cards.s.SkyTether.class)); + cards.add(new SetCardInfo("Slimebind", 54, Rarity.COMMON, mage.cards.s.Slimebind.class)); + cards.add(new SetCardInfo("Smelt-Ward Ignus", 116, Rarity.UNCOMMON, mage.cards.s.SmeltWardIgnus.class)); + cards.add(new SetCardInfo("Smothering Tithe", 22, Rarity.RARE, mage.cards.s.SmotheringTithe.class)); + cards.add(new SetCardInfo("Spawn of Mayhem", 85, Rarity.MYTHIC, mage.cards.s.SpawnOfMayhem.class)); + cards.add(new SetCardInfo("Spear Spewer", 117, Rarity.COMMON, mage.cards.s.SpearSpewer.class)); + cards.add(new SetCardInfo("Sphinx of Foresight", 55, Rarity.RARE, mage.cards.s.SphinxOfForesight.class)); + cards.add(new SetCardInfo("Sphinx of New Prahv", 208, Rarity.UNCOMMON, mage.cards.s.SphinxOfNewPrahv.class)); + cards.add(new SetCardInfo("Sphinx of the Guildpact", 241, Rarity.UNCOMMON, mage.cards.s.SphinxOfTheGuildpact.class)); + cards.add(new SetCardInfo("Sphinx's Insight", 209, Rarity.COMMON, mage.cards.s.SphinxsInsight.class)); + cards.add(new SetCardInfo("Spikewheel Acrobat", 118, Rarity.COMMON, mage.cards.s.SpikewheelAcrobat.class)); + cards.add(new SetCardInfo("Spire Mangler", 86, Rarity.UNCOMMON, mage.cards.s.SpireMangler.class)); + cards.add(new SetCardInfo("Spirit of the Spires", 23, Rarity.UNCOMMON, mage.cards.s.SpiritOfTheSpires.class)); + cards.add(new SetCardInfo("Steeple Creeper", 142, Rarity.COMMON, mage.cards.s.SteepleCreeper.class)); + cards.add(new SetCardInfo("Stomping Ground", 259, Rarity.RARE, mage.cards.s.StompingGround.class)); + cards.add(new SetCardInfo("Stony Strength", 143, Rarity.COMMON, mage.cards.s.StonyStrength.class)); + cards.add(new SetCardInfo("Storm Strike", 119, Rarity.COMMON, mage.cards.s.StormStrike.class)); + cards.add(new SetCardInfo("Summary Judgment", 24, Rarity.COMMON, mage.cards.s.SummaryJudgment.class)); + cards.add(new SetCardInfo("Sunder Shaman", 210, Rarity.UNCOMMON, mage.cards.s.SunderShaman.class)); + cards.add(new SetCardInfo("Swamp", 262, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swirling Torrent", 56, Rarity.UNCOMMON, mage.cards.s.SwirlingTorrent.class)); + cards.add(new SetCardInfo("Sylvan Brushstrider", 144, Rarity.COMMON, mage.cards.s.SylvanBrushstrider.class)); + cards.add(new SetCardInfo("Syndicate Guildmage", 211, Rarity.UNCOMMON, mage.cards.s.SyndicateGuildmage.class)); + cards.add(new SetCardInfo("Syndicate Messenger", 25, Rarity.COMMON, mage.cards.s.SyndicateMessenger.class)); + cards.add(new SetCardInfo("Tenth District Veteran", 26, Rarity.COMMON, mage.cards.t.TenthDistrictVeteran.class)); + cards.add(new SetCardInfo("Territorial Boar", 145, Rarity.COMMON, mage.cards.t.TerritorialBoar.class)); + cards.add(new SetCardInfo("Teysa Karlov", 212, Rarity.RARE, mage.cards.t.TeysaKarlov.class)); + cards.add(new SetCardInfo("The Haunt of Hightower", 273, Rarity.MYTHIC, mage.cards.t.TheHauntOfHightower.class)); + cards.add(new SetCardInfo("Theater of Horrors", 213, Rarity.RARE, mage.cards.t.TheaterOfHorrors.class)); + cards.add(new SetCardInfo("Thirsting Shade", 87, Rarity.COMMON, mage.cards.t.ThirstingShade.class)); + cards.add(new SetCardInfo("Thought Collapse", 57, Rarity.COMMON, mage.cards.t.ThoughtCollapse.class)); + cards.add(new SetCardInfo("Thrash // Threat", 229, Rarity.RARE, mage.cards.t.ThrashThreat.class)); + cards.add(new SetCardInfo("Tin Street Dodger", 120, Rarity.UNCOMMON, mage.cards.t.TinStreetDodger.class)); + cards.add(new SetCardInfo("Titanic Brawl", 146, Rarity.COMMON, mage.cards.t.TitanicBrawl.class)); + cards.add(new SetCardInfo("Tithe Taker", 27, Rarity.RARE, mage.cards.t.TitheTaker.class)); + cards.add(new SetCardInfo("Tome of the Guildpact", 242, Rarity.RARE, mage.cards.t.TomeOfTheGuildpact.class)); + cards.add(new SetCardInfo("Tower Defense", 147, Rarity.UNCOMMON, mage.cards.t.TowerDefense.class)); + cards.add(new SetCardInfo("Trollbred Guardian", 148, Rarity.UNCOMMON, mage.cards.t.TrollbredGuardian.class)); + cards.add(new SetCardInfo("Twilight Panther", 28, Rarity.COMMON, mage.cards.t.TwilightPanther.class)); + cards.add(new SetCardInfo("Unbreakable Formation", 29, Rarity.RARE, mage.cards.u.UnbreakableFormation.class)); + cards.add(new SetCardInfo("Undercity Scavenger", 88, Rarity.COMMON, mage.cards.u.UndercityScavenger.class)); + cards.add(new SetCardInfo("Undercity's Embrace", 89, Rarity.COMMON, mage.cards.u.UndercitysEmbrace.class)); + cards.add(new SetCardInfo("Verity Circle", 58, Rarity.RARE, mage.cards.v.VerityCircle.class)); + cards.add(new SetCardInfo("Vindictive Vampire", 90, Rarity.UNCOMMON, mage.cards.v.VindictiveVampire.class)); + cards.add(new SetCardInfo("Vizkopa Vampire", 220, Rarity.COMMON, mage.cards.v.VizkopaVampire.class)); + cards.add(new SetCardInfo("Wall of Lost Thoughts", 59, Rarity.UNCOMMON, mage.cards.w.WallOfLostThoughts.class)); + cards.add(new SetCardInfo("Warrant // Warden", 230, Rarity.RARE, mage.cards.w.WarrantWarden.class)); + cards.add(new SetCardInfo("Watchful Giant", 30, Rarity.COMMON, mage.cards.w.WatchfulGiant.class)); + cards.add(new SetCardInfo("Wilderness Reclamation", 149, Rarity.UNCOMMON, mage.cards.w.WildernessReclamation.class)); + cards.add(new SetCardInfo("Windstorm Drake", 60, Rarity.UNCOMMON, mage.cards.w.WindstormDrake.class)); + cards.add(new SetCardInfo("Wrecking Beast", 150, Rarity.COMMON, mage.cards.w.WreckingBeast.class)); + cards.add(new SetCardInfo("Zegana, Utopian Speaker", 214, Rarity.RARE, mage.cards.z.ZeganaUtopianSpeaker.class)); + cards.add(new SetCardInfo("Zhur-Taa Goblin", 215, Rarity.UNCOMMON, mage.cards.z.ZhurTaaGoblin.class)); + } + + @Override + public List getCardsByRarity(Rarity rarity) { + if (rarity == Rarity.COMMON) { + List savedCardsInfos = savedCards.get(rarity); + if (savedCardsInfos == null) { + CardCriteria criteria = new CardCriteria(); + criteria.setCodes(this.code).notTypes(CardType.LAND); + criteria.rarities(rarity).doubleFaced(false); + savedCardsInfos = CardRepository.instance.findCards(criteria); + if (maxCardNumberInBooster != Integer.MAX_VALUE) { + savedCardsInfos.removeIf(next -> next.getCardNumberAsInt() > maxCardNumberInBooster); + } + criteria = new CardCriteria(); + // Gateway Plaza is a normal common: https://twitter.com/EliShffrn/status/1043156989218414593s + criteria.setCodes(this.code).nameExact("Gateway Plaza"); + savedCardsInfos.addAll(CardRepository.instance.findCards(criteria)); + savedCards.put(rarity, savedCardsInfos); + } + // Return a copy of the saved cards information, as not to modify the original. + return new ArrayList<>(savedCardsInfos); + } else { + return super.getCardsByRarity(rarity); + } + } + + @Override + public List getSpecialCommon() { + List specialCards = getCardsByRarity(Rarity.SPECIAL); + if (specialCards.isEmpty()) { + CardCriteria criteria = new CardCriteria(); + criteria.rarities(Rarity.COMMON).setCodes(this.code).name("Guildgate"); + List specialCardsSave = CardRepository.instance.findCards(criteria); + savedCards.put(Rarity.SPECIAL, specialCardsSave); + specialCards.addAll(specialCardsSave); + } + return specialCards; + } +} diff --git a/Mage.Sets/src/mage/sets/RavnicaAllegianceGuildKits.java b/Mage.Sets/src/mage/sets/RavnicaAllegianceGuildKits.java new file mode 100644 index 0000000000..332434c087 --- /dev/null +++ b/Mage.Sets/src/mage/sets/RavnicaAllegianceGuildKits.java @@ -0,0 +1,157 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class RavnicaAllegianceGuildKits extends ExpansionSet { + + private static final RavnicaAllegianceGuildKits instance = new RavnicaAllegianceGuildKits(); + + public static RavnicaAllegianceGuildKits getInstance() { + return instance; + } + + private RavnicaAllegianceGuildKits() { + super("Ravnica Allegiance Guild Kits", "GK2", ExpansionSet.buildDate(2019, 2, 15), SetType.SUPPLEMENTAL); + this.blockName = "Guild Kits"; + this.hasBasicLands = true; + + cards.add(new SetCardInfo("Isperia, Supreme Judge", 1, Rarity.MYTHIC, mage.cards.i.IsperiaSupremeJudge.class)); + cards.add(new SetCardInfo("Azorius Herald", 2, Rarity.UNCOMMON, mage.cards.a.AzoriusHerald.class)); + cards.add(new SetCardInfo("Azorius Justiciar", 3, Rarity.UNCOMMON, mage.cards.a.AzoriusJusticiar.class)); + cards.add(new SetCardInfo("Stoic Ephemera", 4, Rarity.UNCOMMON, mage.cards.s.StoicEphemera.class)); + cards.add(new SetCardInfo("Court Hussar", 5, Rarity.UNCOMMON, mage.cards.c.CourtHussar.class)); + cards.add(new SetCardInfo("Hover Barrier", 6, Rarity.UNCOMMON, mage.cards.h.HoverBarrier.class)); + cards.add(new SetCardInfo("Archon of the Triumvirate", 7, Rarity.RARE, mage.cards.a.ArchonOfTheTriumvirate.class)); + cards.add(new SetCardInfo("Azorius Charm", 8, Rarity.UNCOMMON, mage.cards.a.AzoriusCharm.class)); + cards.add(new SetCardInfo("Azorius Guildmage", 9, Rarity.UNCOMMON, mage.cards.a.AzoriusGuildmage.class)); + cards.add(new SetCardInfo("Detention Sphere", 10, Rarity.RARE, mage.cards.d.DetentionSphere.class)); + cards.add(new SetCardInfo("Dovescape", 11, Rarity.RARE, mage.cards.d.Dovescape.class)); + cards.add(new SetCardInfo("Dramatic Rescue", 12, Rarity.COMMON, mage.cards.d.DramaticRescue.class)); + cards.add(new SetCardInfo("Isperia the Inscrutable", 13, Rarity.RARE, mage.cards.i.IsperiaTheInscrutable.class)); + cards.add(new SetCardInfo("Judge's Familiar", 14, Rarity.UNCOMMON, mage.cards.j.JudgesFamiliar.class)); + cards.add(new SetCardInfo("Lavinia of the Tenth", 15, Rarity.RARE, mage.cards.l.LaviniaOfTheTenth.class)); + cards.add(new SetCardInfo("Lyev Skyknight", 16, Rarity.UNCOMMON, mage.cards.l.LyevSkyknight.class)); + cards.add(new SetCardInfo("Pride of the Clouds", 17, Rarity.RARE, mage.cards.p.PrideOfTheClouds.class)); + cards.add(new SetCardInfo("Render Silent", 18, Rarity.RARE, mage.cards.r.RenderSilent.class)); + cards.add(new SetCardInfo("Sky Hussar", 19, Rarity.UNCOMMON, mage.cards.s.SkyHussar.class)); + cards.add(new SetCardInfo("Skymark Roc", 20, Rarity.UNCOMMON, mage.cards.s.SkymarkRoc.class)); + cards.add(new SetCardInfo("Sphinx's Revelation", 21, Rarity.MYTHIC, mage.cards.s.SphinxsRevelation.class)); + cards.add(new SetCardInfo("Windreaver", 22, Rarity.RARE, mage.cards.w.Windreaver.class)); + cards.add(new SetCardInfo("Azorius Keyrune", 23, Rarity.UNCOMMON, mage.cards.a.AzoriusKeyrune.class)); + cards.add(new SetCardInfo("Azorius Signet", 24, Rarity.UNCOMMON, mage.cards.a.AzoriusSignet.class)); + cards.add(new SetCardInfo("Azorius Chancery", 25, Rarity.UNCOMMON, mage.cards.a.AzoriusChancery.class)); + cards.add(new SetCardInfo("Plains", 26, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 27, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Teysa, Orzhov Scion", 28, Rarity.RARE, mage.cards.t.TeysaOrzhovScion.class)); + cards.add(new SetCardInfo("Belfry Spirit", 29, Rarity.UNCOMMON, mage.cards.b.BelfrySpirit.class)); + cards.add(new SetCardInfo("Martyred Rusalka", 30, Rarity.UNCOMMON, mage.cards.m.MartyredRusalka.class)); + cards.add(new SetCardInfo("Keening Banshee", 31, Rarity.UNCOMMON, mage.cards.k.KeeningBanshee.class)); + cards.add(new SetCardInfo("Plagued Rusalka", 32, Rarity.UNCOMMON, mage.cards.p.PlaguedRusalka.class)); + cards.add(new SetCardInfo("Pontiff of Blight", 33, Rarity.RARE, mage.cards.p.PontiffOfBlight.class)); + cards.add(new SetCardInfo("Skeletal Vampire", 34, Rarity.RARE, mage.cards.s.SkeletalVampire.class)); + cards.add(new SetCardInfo("Stab Wound", 35, Rarity.UNCOMMON, mage.cards.s.StabWound.class)); + cards.add(new SetCardInfo("Ultimate Price", 36, Rarity.UNCOMMON, mage.cards.u.UltimatePrice.class)); + cards.add(new SetCardInfo("Angel of Despair", 37, Rarity.RARE, mage.cards.a.AngelOfDespair.class)); + cards.add(new SetCardInfo("Deathpact Angel", 38, Rarity.MYTHIC, mage.cards.d.DeathpactAngel.class)); + cards.add(new SetCardInfo("Debtors' Knell", 39, Rarity.RARE, mage.cards.d.DebtorsKnell.class)); + cards.add(new SetCardInfo("Ghost Council of Orzhova", 40, Rarity.RARE, mage.cards.g.GhostCouncilOfOrzhova.class)); + cards.add(new SetCardInfo("One Thousand Lashes", 41, Rarity.UNCOMMON, mage.cards.o.OneThousandLashes.class)); + cards.add(new SetCardInfo("Orzhov Charm", 42, Rarity.UNCOMMON, mage.cards.o.OrzhovCharm.class)); + cards.add(new SetCardInfo("Orzhov Pontiff", 43, Rarity.RARE, mage.cards.o.OrzhovPontiff.class)); + cards.add(new SetCardInfo("Pillory of the Sleepless", 44, Rarity.UNCOMMON, mage.cards.p.PilloryOfTheSleepless.class)); + cards.add(new SetCardInfo("Sin Collector", 45, Rarity.UNCOMMON, mage.cards.s.SinCollector.class)); + cards.add(new SetCardInfo("Treasury Thrull", 46, Rarity.RARE, mage.cards.t.TreasuryThrull.class)); + cards.add(new SetCardInfo("Vizkopa Guildmage", 47, Rarity.UNCOMMON, mage.cards.v.VizkopaGuildmage.class)); + cards.add(new SetCardInfo("Orzhov Signet", 48, Rarity.COMMON, mage.cards.o.OrzhovSignet.class)); + cards.add(new SetCardInfo("Orzhov Basilica", 49, Rarity.COMMON, mage.cards.o.OrzhovBasilica.class)); + cards.add(new SetCardInfo("Plains", 50, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 51, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Rakdos, Lord of Riots", 52, Rarity.MYTHIC, mage.cards.r.RakdosLordOfRiots.class)); + cards.add(new SetCardInfo("Crypt Champion", 53, Rarity.UNCOMMON, mage.cards.c.CryptChampion.class)); + cards.add(new SetCardInfo("Thrill-Kill Assassin", 54, Rarity.UNCOMMON, mage.cards.t.ThrillKillAssassin.class)); + cards.add(new SetCardInfo("Cackling Flames", 55, Rarity.COMMON, mage.cards.c.CacklingFlames.class)); + cards.add(new SetCardInfo("Demonfire", 56, Rarity.RARE, mage.cards.d.Demonfire.class)); + cards.add(new SetCardInfo("Rakdos Pit Dragon", 57, Rarity.RARE, mage.cards.r.RakdosPitDragon.class)); + cards.add(new SetCardInfo("Splatter Thug", 58, Rarity.COMMON, mage.cards.s.SplatterThug.class)); + cards.add(new SetCardInfo("Utvara Hellkite", 59, Rarity.MYTHIC, mage.cards.u.UtvaraHellkite.class)); + cards.add(new SetCardInfo("Auger Spree", 60, Rarity.COMMON, mage.cards.a.AugerSpree.class)); + cards.add(new SetCardInfo("Avatar of Discord", 61, Rarity.RARE, mage.cards.a.AvatarOfDiscord.class)); + cards.add(new SetCardInfo("Carnival Hellsteed", 62, Rarity.RARE, mage.cards.c.CarnivalHellsteed.class)); + cards.add(new SetCardInfo("Dreadbore", 63, Rarity.RARE, mage.cards.d.Dreadbore.class)); + cards.add(new SetCardInfo("Jagged Poppet", 64, Rarity.UNCOMMON, mage.cards.j.JaggedPoppet.class)); + cards.add(new SetCardInfo("Lyzolda, the Blood Witch", 65, Rarity.RARE, mage.cards.l.LyzoldaTheBloodWitch.class)); + cards.add(new SetCardInfo("Master of Cruelties", 66, Rarity.MYTHIC, mage.cards.m.MasterOfCruelties.class)); + cards.add(new SetCardInfo("Rakdos Cackler", 67, Rarity.UNCOMMON, mage.cards.r.RakdosCackler.class)); + cards.add(new SetCardInfo("Rakdos Charm", 68, Rarity.UNCOMMON, mage.cards.r.RakdosCharm.class)); + cards.add(new SetCardInfo("Rakdos Guildmage", 69, Rarity.UNCOMMON, mage.cards.r.RakdosGuildmage.class)); + cards.add(new SetCardInfo("Rakdos Shred-Freak", 70, Rarity.COMMON, mage.cards.r.RakdosShredFreak.class)); + cards.add(new SetCardInfo("Rakdos the Defiler", 71, Rarity.RARE, mage.cards.r.RakdosTheDefiler.class)); + cards.add(new SetCardInfo("Rakdos's Return", 72, Rarity.MYTHIC, mage.cards.r.RakdossReturn.class)); + cards.add(new SetCardInfo("Riot Spikes", 73, Rarity.COMMON, mage.cards.r.RiotSpikes.class)); + cards.add(new SetCardInfo("Wrecking Ball", 74, Rarity.COMMON, mage.cards.w.WreckingBall.class)); + cards.add(new SetCardInfo("Rakdos Keyrune", 75, Rarity.UNCOMMON, mage.cards.r.RakdosKeyrune.class)); + cards.add(new SetCardInfo("Rakdos Signet", 76, Rarity.UNCOMMON, mage.cards.r.RakdosSignet.class)); + cards.add(new SetCardInfo("Rakdos Carnarium", 77, Rarity.COMMON, mage.cards.r.RakdosCarnarium.class)); + cards.add(new SetCardInfo("Swamp", 78, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 79, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Ruric Thar, the Unbowed", 80, Rarity.RARE, mage.cards.r.RuricTharTheUnbowed.class)); + cards.add(new SetCardInfo("Skarrgan Firebird", 81, Rarity.RARE, mage.cards.s.SkarrganFirebird.class)); + cards.add(new SetCardInfo("Birds of Paradise", 82, Rarity.RARE, mage.cards.b.BirdsOfParadise.class)); + cards.add(new SetCardInfo("Protean Hulk", 83, Rarity.RARE, mage.cards.p.ProteanHulk.class)); + cards.add(new SetCardInfo("Skarrgan Pit-Skulk", 84, Rarity.COMMON, mage.cards.s.SkarrganPitSkulk.class)); + cards.add(new SetCardInfo("Wasteland Viper", 85, Rarity.UNCOMMON, mage.cards.w.WastelandViper.class)); + cards.add(new SetCardInfo("Wurmweaver Coil", 86, Rarity.RARE, mage.cards.w.WurmweaverCoil.class)); + cards.add(new SetCardInfo("Borborygmos", 87, Rarity.RARE, mage.cards.b.Borborygmos.class)); + cards.add(new SetCardInfo("Burning-Tree Emissary", 88, Rarity.UNCOMMON, mage.cards.b.BurningTreeEmissary.class)); + cards.add(new SetCardInfo("Burning-Tree Shaman", 89, Rarity.RARE, mage.cards.b.BurningTreeShaman.class)); + cards.add(new SetCardInfo("Ghor-Clan Rampager", 90, Rarity.UNCOMMON, mage.cards.g.GhorClanRampager.class)); + cards.add(new SetCardInfo("Giant Solifuge", 91, Rarity.RARE, mage.cards.g.GiantSolifuge.class)); + cards.add(new SetCardInfo("Gruul Charm", 92, Rarity.UNCOMMON, mage.cards.g.GruulCharm.class)); + cards.add(new SetCardInfo("Pit Fight", 93, Rarity.COMMON, mage.cards.p.PitFight.class)); + cards.add(new SetCardInfo("Rubblebelt Raiders", 94, Rarity.RARE, mage.cards.r.RubblebeltRaiders.class)); + cards.add(new SetCardInfo("Rubblehulk", 95, Rarity.RARE, mage.cards.r.Rubblehulk.class)); + cards.add(new SetCardInfo("Rumbling Slum", 96, Rarity.RARE, mage.cards.r.RumblingSlum.class)); + cards.add(new SetCardInfo("Savage Twister", 97, Rarity.UNCOMMON, mage.cards.s.SavageTwister.class)); + cards.add(new SetCardInfo("Savageborn Hydra", 98, Rarity.MYTHIC, mage.cards.s.SavagebornHydra.class)); + cards.add(new SetCardInfo("Scab-Clan Mauler", 99, Rarity.COMMON, mage.cards.s.ScabClanMauler.class)); + cards.add(new SetCardInfo("Ulasht, the Hate Seed", 100, Rarity.RARE, mage.cards.u.UlashtTheHateSeed.class)); + cards.add(new SetCardInfo("Zhur-Taa Druid", 101, Rarity.COMMON, mage.cards.z.ZhurTaaDruid.class)); + cards.add(new SetCardInfo("Zhur-Taa Swine", 102, Rarity.COMMON, mage.cards.z.ZhurTaaSwine.class)); + cards.add(new SetCardInfo("Gruul Signet", 103, Rarity.UNCOMMON, mage.cards.g.GruulSignet.class)); + cards.add(new SetCardInfo("Gruul Turf", 104, Rarity.COMMON, mage.cards.g.GruulTurf.class)); + cards.add(new SetCardInfo("Mountain", 105, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 106, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Zegana, Utopian Speaker", 107, Rarity.RARE, mage.cards.z.ZeganaUtopianSpeaker.class)); + cards.add(new SetCardInfo("Cloudfin Raptor", 108, Rarity.COMMON, mage.cards.c.CloudfinRaptor.class)); + cards.add(new SetCardInfo("Rapid Hybridization", 109, Rarity.UNCOMMON, mage.cards.r.RapidHybridization.class)); + cards.add(new SetCardInfo("Cytoplast Root-Kin", 110, Rarity.RARE, mage.cards.c.CytoplastRootKin.class)); + cards.add(new SetCardInfo("Experiment One", 111, Rarity.UNCOMMON, mage.cards.e.ExperimentOne.class)); + cards.add(new SetCardInfo("Gyre Sage", 112, Rarity.RARE, mage.cards.g.GyreSage.class)); + cards.add(new SetCardInfo("Miming Slime", 113, Rarity.COMMON, mage.cards.m.MimingSlime.class)); + cards.add(new SetCardInfo("Vinelasher Kudzu", 114, Rarity.RARE, mage.cards.v.VinelasherKudzu.class)); + cards.add(new SetCardInfo("Coiling Oracle", 115, Rarity.COMMON, mage.cards.c.CoilingOracle.class)); + cards.add(new SetCardInfo("Elusive Krasis", 116, Rarity.UNCOMMON, mage.cards.e.ElusiveKrasis.class)); + cards.add(new SetCardInfo("Experiment Kraj", 117, Rarity.RARE, mage.cards.e.ExperimentKraj.class)); + cards.add(new SetCardInfo("Fathom Mage", 118, Rarity.RARE, mage.cards.f.FathomMage.class)); + cards.add(new SetCardInfo("Momir Vig, Simic Visionary", 119, Rarity.RARE, mage.cards.m.MomirVigSimicVisionary.class)); + cards.add(new SetCardInfo("Nimbus Swimmer", 120, Rarity.UNCOMMON, mage.cards.n.NimbusSwimmer.class)); + cards.add(new SetCardInfo("Omnibian", 121, Rarity.RARE, mage.cards.o.Omnibian.class)); + cards.add(new SetCardInfo("Plaxcaster Frogling", 122, Rarity.UNCOMMON, mage.cards.p.PlaxcasterFrogling.class)); + cards.add(new SetCardInfo("Progenitor Mimic", 123, Rarity.MYTHIC, mage.cards.p.ProgenitorMimic.class)); + cards.add(new SetCardInfo("Simic Sky Swallower", 124, Rarity.RARE, mage.cards.s.SimicSkySwallower.class)); + cards.add(new SetCardInfo("Trygon Predator", 125, Rarity.UNCOMMON, mage.cards.t.TrygonPredator.class)); + cards.add(new SetCardInfo("Urban Evolution", 126, Rarity.UNCOMMON, mage.cards.u.UrbanEvolution.class)); + cards.add(new SetCardInfo("Voidslime", 127, Rarity.RARE, mage.cards.v.Voidslime.class)); + cards.add(new SetCardInfo("Vorel of the Hull Clade", 128, Rarity.RARE, mage.cards.v.VorelOfTheHullClade.class)); + cards.add(new SetCardInfo("Zameck Guildmage", 129, Rarity.UNCOMMON, mage.cards.z.ZameckGuildmage.class)); + cards.add(new SetCardInfo("Simic Signet", 130, Rarity.UNCOMMON, mage.cards.s.SimicSignet.class)); + cards.add(new SetCardInfo("Simic Growth Chamber", 131, Rarity.UNCOMMON, mage.cards.s.SimicGrowthChamber.class)); + cards.add(new SetCardInfo("Forest", 132, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 133, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + } +} diff --git a/Mage.Sets/src/mage/sets/StarWars.java b/Mage.Sets/src/mage/sets/StarWars.java index 64a7d9de17..01f57bf33b 100644 --- a/Mage.Sets/src/mage/sets/StarWars.java +++ b/Mage.Sets/src/mage/sets/StarWars.java @@ -269,7 +269,7 @@ public final class StarWars extends ExpansionSet { cards.add(new SetCardInfo("Repurpose", 85, Rarity.COMMON, mage.cards.r.Repurpose.class)); cards.add(new SetCardInfo("Resistance", 310, Rarity.UNCOMMON, mage.cards.r.Resistance.class)); cards.add(new SetCardInfo("Resistance Bomber", 515, Rarity.UNCOMMON, mage.cards.r.ResistanceBomber.class)); - cards.add(new SetCardInfo("Revenge", 117, Rarity.COMMON, mage.cards.r.Revenge.class)); + cards.add(new SetCardInfo("Revenge", 117, Rarity.COMMON, mage.cards.r.RevengeStarWars.class)); cards.add(new SetCardInfo("Rey", 410, Rarity.RARE, mage.cards.r.Rey.class)); cards.add(new SetCardInfo("Riding Ronto", 28, Rarity.UNCOMMON, mage.cards.r.RidingRonto.class)); cards.add(new SetCardInfo("Riot Trooper", 411, Rarity.COMMON, mage.cards.r.RiotTrooper.class)); diff --git a/Mage.Sets/src/mage/sets/Starter1999.java b/Mage.Sets/src/mage/sets/Starter1999.java index e7e5d8050c..d41c6b095f 100644 --- a/Mage.Sets/src/mage/sets/Starter1999.java +++ b/Mage.Sets/src/mage/sets/Starter1999.java @@ -1,200 +1,201 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author LevelX2 - */ -public final class Starter1999 extends ExpansionSet { - - private static final Starter1999 instance = new Starter1999(); - - public static Starter1999 getInstance() { - return instance; - } - - private Starter1999() { - super("Starter 1999", "S99", ExpansionSet.buildDate(1999, 7, 1), SetType.SUPPLEMENTAL); - this.blockName = "Beginner"; - this.hasBasicLands = true; - this.hasBoosters = true; - this.numBoosterLands = 2; - this.numBoosterCommon = 9; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abyssal Horror", 63, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); - cards.add(new SetCardInfo("Air Elemental", 32, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); - cards.add(new SetCardInfo("Alluring Scent", 124, Rarity.RARE, mage.cards.a.AlluringScent.class)); - cards.add(new SetCardInfo("Ancient Craving", 64, Rarity.RARE, mage.cards.a.AncientCraving.class)); - cards.add(new SetCardInfo("Angelic Blessing", 3, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); - cards.add(new SetCardInfo("Angel of Light", 1, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); - cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); - cards.add(new SetCardInfo("Archangel", 4, Rarity.RARE, mage.cards.a.Archangel.class)); - cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); - cards.add(new SetCardInfo("Armageddon", 6, Rarity.RARE, mage.cards.a.Armageddon.class)); - cards.add(new SetCardInfo("Barbtooth Wurm", 125, Rarity.COMMON, mage.cards.b.BarbtoothWurm.class)); - cards.add(new SetCardInfo("Bargain", 7, Rarity.UNCOMMON, mage.cards.b.Bargain.class)); - cards.add(new SetCardInfo("Blinding Light", 8, Rarity.RARE, mage.cards.b.BlindingLight.class)); - cards.add(new SetCardInfo("Bog Imp", 65, Rarity.COMMON, mage.cards.b.BogImp.class)); - cards.add(new SetCardInfo("Bog Raiders", 66, Rarity.COMMON, mage.cards.b.BogRaiders.class)); - cards.add(new SetCardInfo("Bog Wraith", 67, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); - cards.add(new SetCardInfo("Border Guard", 9, Rarity.COMMON, mage.cards.b.BorderGuard.class)); - cards.add(new SetCardInfo("Breath of Life", 10, Rarity.UNCOMMON, mage.cards.b.BreathOfLife.class)); - cards.add(new SetCardInfo("Bull Hippo", 126, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); - cards.add(new SetCardInfo("Champion Lancer", 11, Rarity.RARE, mage.cards.c.ChampionLancer.class)); - cards.add(new SetCardInfo("Charging Paladin", 12, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); - cards.add(new SetCardInfo("Chorus of Woe", 68, Rarity.COMMON, mage.cards.c.ChorusOfWoe.class)); - cards.add(new SetCardInfo("Cinder Storm", 93, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); - cards.add(new SetCardInfo("Coercion", 69, Rarity.UNCOMMON, mage.cards.c.Coercion.class)); - cards.add(new SetCardInfo("Coral Eel", 33, Rarity.COMMON, mage.cards.c.CoralEel.class)); - cards.add(new SetCardInfo("Counterspell", 34, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Dakmor Ghoul", 70, Rarity.UNCOMMON, mage.cards.d.DakmorGhoul.class)); - cards.add(new SetCardInfo("Dakmor Lancer", 71, Rarity.RARE, mage.cards.d.DakmorLancer.class)); - cards.add(new SetCardInfo("Dakmor Plague", 72, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); - cards.add(new SetCardInfo("Dakmor Scorpion", 73, Rarity.COMMON, mage.cards.d.DakmorScorpion.class)); - cards.add(new SetCardInfo("Dakmor Sorceress", 74, Rarity.RARE, mage.cards.d.DakmorSorceress.class)); - cards.add(new SetCardInfo("Dark Offering", 75, Rarity.UNCOMMON, mage.cards.d.DarkOffering.class)); - cards.add(new SetCardInfo("Denizen of the Deep", 35, Rarity.RARE, mage.cards.d.DenizenOfTheDeep.class)); - cards.add(new SetCardInfo("Devastation", 94, Rarity.RARE, mage.cards.d.Devastation.class)); - cards.add(new SetCardInfo("Devoted Hero", 13, Rarity.COMMON, mage.cards.d.DevotedHero.class)); - cards.add(new SetCardInfo("Devout Monk", 14, Rarity.COMMON, mage.cards.d.DevoutMonk.class)); - cards.add(new SetCardInfo("Dread Reaper", 76, Rarity.RARE, mage.cards.d.DreadReaper.class)); - cards.add(new SetCardInfo("Durkwood Boars", 127, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); - cards.add(new SetCardInfo("Eager Cadet", 15, Rarity.COMMON, mage.cards.e.EagerCadet.class)); - cards.add(new SetCardInfo("Earth Elemental", 95, Rarity.UNCOMMON, mage.cards.e.EarthElemental.class)); - cards.add(new SetCardInfo("Exhaustion", 36, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); - cards.add(new SetCardInfo("Extinguish", 37, Rarity.COMMON, mage.cards.e.Extinguish.class)); - cards.add(new SetCardInfo("Eye Spy", 38, Rarity.UNCOMMON, mage.cards.e.EyeSpy.class)); - cards.add(new SetCardInfo("False Peace", 16, Rarity.UNCOMMON, mage.cards.f.FalsePeace.class)); - cards.add(new SetCardInfo("Feral Shadow", 77, Rarity.COMMON, mage.cards.f.FeralShadow.class)); - cards.add(new SetCardInfo("Fire Elemental", 96, Rarity.UNCOMMON, mage.cards.f.FireElemental.class)); - cards.add(new SetCardInfo("Fire Tempest", 97, Rarity.RARE, mage.cards.f.FireTempest.class)); - cards.add(new SetCardInfo("Foot Soldiers", 17, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); - cards.add(new SetCardInfo("Forest", 170, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 171, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 172, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 173, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Gerrard's Wisdom", 18, Rarity.RARE, mage.cards.g.GerrardsWisdom.class)); - cards.add(new SetCardInfo("Giant Octopus", 39, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); - cards.add(new SetCardInfo("Goblin Cavaliers", 98, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); - cards.add(new SetCardInfo("Goblin Chariot", 99, Rarity.COMMON, mage.cards.g.GoblinChariot.class)); - cards.add(new SetCardInfo("Goblin Commando", 100, Rarity.UNCOMMON, mage.cards.g.GoblinCommando.class)); - cards.add(new SetCardInfo("Goblin General", 101, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); - cards.add(new SetCardInfo("Goblin Glider", 102, Rarity.UNCOMMON, mage.cards.g.GoblinGlider.class)); - cards.add(new SetCardInfo("Goblin Hero", 103, Rarity.COMMON, mage.cards.g.GoblinHero.class)); - cards.add(new SetCardInfo("Goblin Lore", 104, Rarity.UNCOMMON, mage.cards.g.GoblinLore.class)); - cards.add(new SetCardInfo("Goblin Mountaineer", 105, Rarity.COMMON, mage.cards.g.GoblinMountaineer.class)); - cards.add(new SetCardInfo("Goblin Settler", 106, Rarity.UNCOMMON, mage.cards.g.GoblinSettler.class)); - cards.add(new SetCardInfo("Gorilla Warrior", 128, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); - cards.add(new SetCardInfo("Gravedigger", 78, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); - cards.add(new SetCardInfo("Grim Tutor", 79, Rarity.RARE, mage.cards.g.GrimTutor.class)); - cards.add(new SetCardInfo("Grizzly Bears", 129, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); - cards.add(new SetCardInfo("Hand of Death", 80, Rarity.COMMON, mage.cards.h.HandOfDeath.class)); - cards.add(new SetCardInfo("Hollow Dogs", 81, Rarity.COMMON, mage.cards.h.HollowDogs.class)); - cards.add(new SetCardInfo("Howling Fury", 82, Rarity.UNCOMMON, mage.cards.h.HowlingFury.class)); - cards.add(new SetCardInfo("Hulking Goblin", 107, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); - cards.add(new SetCardInfo("Hulking Ogre", 108, Rarity.UNCOMMON, mage.cards.h.HulkingOgre.class)); - cards.add(new SetCardInfo("Ingenious Thief", 40, Rarity.COMMON, mage.cards.i.IngeniousThief.class)); - cards.add(new SetCardInfo("Island", 158, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 159, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 160, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 161, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jagged Lightning", 109, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); - cards.add(new SetCardInfo("Knight Errant", 19, Rarity.COMMON, mage.cards.k.KnightErrant.class)); - cards.add(new SetCardInfo("Last Chance", 110, Rarity.RARE, mage.cards.l.LastChance.class)); - cards.add(new SetCardInfo("Lava Axe", 111, Rarity.COMMON, mage.cards.l.LavaAxe.class)); - cards.add(new SetCardInfo("Lone Wolf", 130, Rarity.COMMON, mage.cards.l.LoneWolf.class)); - cards.add(new SetCardInfo("Loyal Sentry", 20, Rarity.RARE, mage.cards.l.LoyalSentry.class)); - cards.add(new SetCardInfo("Lynx", 131, Rarity.UNCOMMON, mage.cards.l.Lynx.class)); - cards.add(new SetCardInfo("Man-o'-War", 41, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); - cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 42, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); - cards.add(new SetCardInfo("Mind Rot", 83, Rarity.COMMON, mage.cards.m.MindRot.class)); - cards.add(new SetCardInfo("Mons's Goblin Raiders", 112, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); - cards.add(new SetCardInfo("Monstrous Growth", 132, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class)); - cards.add(new SetCardInfo("Moon Sprite", 133, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); - cards.add(new SetCardInfo("Mountain", 166, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 167, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 168, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 169, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Muck Rats", 84, Rarity.COMMON, mage.cards.m.MuckRats.class)); - cards.add(new SetCardInfo("Natural Spring", 134, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); - cards.add(new SetCardInfo("Nature's Cloak", 135, Rarity.RARE, mage.cards.n.NaturesCloak.class)); - cards.add(new SetCardInfo("Nature's Lore", 136, Rarity.COMMON, mage.cards.n.NaturesLore.class)); - cards.add(new SetCardInfo("Norwood Archers", 137, Rarity.COMMON, mage.cards.n.NorwoodArchers.class)); - cards.add(new SetCardInfo("Norwood Ranger", 138, Rarity.COMMON, mage.cards.n.NorwoodRanger.class)); - cards.add(new SetCardInfo("Ogre Warrior", 113, Rarity.COMMON, mage.cards.o.OgreWarrior.class)); - cards.add(new SetCardInfo("Path of Peace", 21, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); - cards.add(new SetCardInfo("Phantom Warrior", 44, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); - cards.add(new SetCardInfo("Plains", 154, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 155, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 156, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 157, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Pride of Lions", 139, Rarity.UNCOMMON, mage.cards.p.PrideOfLions.class)); - cards.add(new SetCardInfo("Psychic Transfer", 46, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); - cards.add(new SetCardInfo("Raging Goblin", 114, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); - cards.add(new SetCardInfo("Raise Dead", 85, Rarity.COMMON, mage.cards.r.RaiseDead.class)); - cards.add(new SetCardInfo("Ravenous Rats", 86, Rarity.UNCOMMON, mage.cards.r.RavenousRats.class)); - cards.add(new SetCardInfo("Relearn", 48, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); - cards.add(new SetCardInfo("Relentless Assault", 115, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); - cards.add(new SetCardInfo("Remove Soul", 49, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); - cards.add(new SetCardInfo("Renewing Touch", 140, Rarity.UNCOMMON, mage.cards.r.RenewingTouch.class)); - cards.add(new SetCardInfo("Righteous Charge", 22, Rarity.UNCOMMON, mage.cards.r.RighteousCharge.class)); - cards.add(new SetCardInfo("Righteous Fury", 23, Rarity.RARE, mage.cards.r.RighteousFury.class)); - cards.add(new SetCardInfo("Royal Falcon", 24, Rarity.COMMON, mage.cards.r.RoyalFalcon.class)); - cards.add(new SetCardInfo("Royal Trooper", 25, Rarity.UNCOMMON, mage.cards.r.RoyalTrooper.class)); - cards.add(new SetCardInfo("Sacred Nectar", 26, Rarity.COMMON, mage.cards.s.SacredNectar.class)); - cards.add(new SetCardInfo("Scathe Zombies", 87, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); - cards.add(new SetCardInfo("Scorching Spear", 116, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); - cards.add(new SetCardInfo("Sea Eagle", 50, Rarity.COMMON, mage.cards.s.SeaEagle.class)); - cards.add(new SetCardInfo("Serpent Warrior", 88, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); - cards.add(new SetCardInfo("Shrieking Specter", 89, Rarity.UNCOMMON, mage.cards.s.ShriekingSpecter.class)); - cards.add(new SetCardInfo("Silverback Ape", 141, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); - cards.add(new SetCardInfo("Sleight of Hand", 51, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); - cards.add(new SetCardInfo("Snapping Drake", 52, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); - cards.add(new SetCardInfo("Soul Feast", 90, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); - cards.add(new SetCardInfo("Southern Elephant", 142, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); - cards.add(new SetCardInfo("Spitting Earth", 117, Rarity.UNCOMMON, mage.cards.s.SpittingEarth.class)); - cards.add(new SetCardInfo("Squall", 143, Rarity.COMMON, mage.cards.s.Squall.class)); - cards.add(new SetCardInfo("Steadfastness", 27, Rarity.COMMON, mage.cards.s.Steadfastness.class)); - cards.add(new SetCardInfo("Stone Rain", 118, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Storm Crow", 53, Rarity.COMMON, mage.cards.s.StormCrow.class)); - cards.add(new SetCardInfo("Stream of Acid", 91, Rarity.UNCOMMON, mage.cards.s.StreamOfAcid.class)); - cards.add(new SetCardInfo("Summer Bloom", 144, Rarity.RARE, mage.cards.s.SummerBloom.class)); - cards.add(new SetCardInfo("Swamp", 162, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 163, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 164, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 165, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Sylvan Basilisk", 145, Rarity.RARE, mage.cards.s.SylvanBasilisk.class)); - cards.add(new SetCardInfo("Sylvan Yeti", 146, Rarity.RARE, mage.cards.s.SylvanYeti.class)); - cards.add(new SetCardInfo("Thorn Elemental", 147, Rarity.RARE, mage.cards.t.ThornElemental.class)); - cards.add(new SetCardInfo("Thunder Dragon", 119, Rarity.RARE, mage.cards.t.ThunderDragon.class)); - cards.add(new SetCardInfo("Tidings", 54, Rarity.UNCOMMON, mage.cards.t.Tidings.class)); - cards.add(new SetCardInfo("Time Ebb", 55, Rarity.COMMON, mage.cards.t.TimeEbb.class)); - cards.add(new SetCardInfo("Time Warp", 56, Rarity.RARE, mage.cards.t.TimeWarp.class)); - cards.add(new SetCardInfo("Touch of Brilliance", 57, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); - cards.add(new SetCardInfo("Trained Orgg", 120, Rarity.RARE, mage.cards.t.TrainedOrgg.class)); - cards.add(new SetCardInfo("Tremor", 121, Rarity.COMMON, mage.cards.t.Tremor.class)); - cards.add(new SetCardInfo("Undo", 58, Rarity.UNCOMMON, mage.cards.u.Undo.class)); - cards.add(new SetCardInfo("Untamed Wilds", 148, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); - cards.add(new SetCardInfo("Venerable Monk", 28, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Vengeance", 29, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); - cards.add(new SetCardInfo("Veteran Cavalier", 30, Rarity.UNCOMMON, mage.cards.v.VeteranCavalier.class)); - cards.add(new SetCardInfo("Vizzerdrix", 59, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); - cards.add(new SetCardInfo("Volcanic Dragon", 122, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); - cards.add(new SetCardInfo("Volcanic Hammer", 123, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); - cards.add(new SetCardInfo("Water Elemental", 60, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); - cards.add(new SetCardInfo("Whiptail Wurm", 149, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); - cards.add(new SetCardInfo("Whirlwind", 150, Rarity.RARE, mage.cards.w.Whirlwind.class)); - cards.add(new SetCardInfo("Wicked Pact", 92, Rarity.RARE, mage.cards.w.WickedPact.class)); - cards.add(new SetCardInfo("Wild Griffin", 31, Rarity.COMMON, mage.cards.w.WildGriffin.class)); - cards.add(new SetCardInfo("Wild Ox", 151, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); - cards.add(new SetCardInfo("Willow Elf", 152, Rarity.COMMON, mage.cards.w.WillowElf.class)); - cards.add(new SetCardInfo("Wind Drake", 61, Rarity.COMMON, mage.cards.w.WindDrake.class)); - cards.add(new SetCardInfo("Wind Sail", 62, Rarity.UNCOMMON, mage.cards.w.WindSail.class)); - cards.add(new SetCardInfo("Wood Elves", 153, Rarity.UNCOMMON, mage.cards.w.WoodElves.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author LevelX2 + */ +public final class Starter1999 extends ExpansionSet { + + private static final Starter1999 instance = new Starter1999(); + + public static Starter1999 getInstance() { + return instance; + } + + private Starter1999() { + super("Starter 1999", "S99", ExpansionSet.buildDate(1999, 7, 1), SetType.SUPPLEMENTAL); + this.blockName = "Beginner"; + this.hasBasicLands = true; + this.hasBoosters = true; + this.numBoosterLands = 2; + this.numBoosterCommon = 9; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abyssal Horror", 63, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); + cards.add(new SetCardInfo("Air Elemental", 32, Rarity.UNCOMMON, mage.cards.a.AirElemental.class)); + cards.add(new SetCardInfo("Alluring Scent", 124, Rarity.RARE, mage.cards.a.AlluringScent.class)); + cards.add(new SetCardInfo("Ancient Craving", 64, Rarity.RARE, mage.cards.a.AncientCraving.class)); + cards.add(new SetCardInfo("Angelic Blessing", 3, Rarity.COMMON, mage.cards.a.AngelicBlessing.class)); + cards.add(new SetCardInfo("Angel of Light", 1, Rarity.UNCOMMON, mage.cards.a.AngelOfLight.class)); + cards.add(new SetCardInfo("Angel of Mercy", 2, Rarity.UNCOMMON, mage.cards.a.AngelOfMercy.class)); + cards.add(new SetCardInfo("Archangel", 4, Rarity.RARE, mage.cards.a.Archangel.class)); + cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.UNCOMMON, mage.cards.a.ArdentMilitia.class)); + cards.add(new SetCardInfo("Armageddon", 6, Rarity.RARE, mage.cards.a.Armageddon.class)); + cards.add(new SetCardInfo("Barbtooth Wurm", 125, Rarity.COMMON, mage.cards.b.BarbtoothWurm.class)); + cards.add(new SetCardInfo("Bargain", 7, Rarity.UNCOMMON, mage.cards.b.Bargain.class)); + cards.add(new SetCardInfo("Blinding Light", 8, Rarity.RARE, mage.cards.b.BlindingLight.class)); + cards.add(new SetCardInfo("Bog Imp", 65, Rarity.COMMON, mage.cards.b.BogImp.class)); + cards.add(new SetCardInfo("Bog Raiders", 66, Rarity.COMMON, mage.cards.b.BogRaiders.class)); + cards.add(new SetCardInfo("Bog Wraith", 67, Rarity.UNCOMMON, mage.cards.b.BogWraith.class)); + cards.add(new SetCardInfo("Border Guard", 9, Rarity.COMMON, mage.cards.b.BorderGuard.class)); + cards.add(new SetCardInfo("Breath of Life", 10, Rarity.UNCOMMON, mage.cards.b.BreathOfLife.class)); + cards.add(new SetCardInfo("Bull Hippo", 126, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); + cards.add(new SetCardInfo("Champion Lancer", 11, Rarity.RARE, mage.cards.c.ChampionLancer.class)); + cards.add(new SetCardInfo("Charging Paladin", 12, Rarity.UNCOMMON, mage.cards.c.ChargingPaladin.class)); + cards.add(new SetCardInfo("Chorus of Woe", 68, Rarity.COMMON, mage.cards.c.ChorusOfWoe.class)); + cards.add(new SetCardInfo("Cinder Storm", 93, Rarity.UNCOMMON, mage.cards.c.CinderStorm.class)); + cards.add(new SetCardInfo("Coercion", 69, Rarity.UNCOMMON, mage.cards.c.Coercion.class)); + cards.add(new SetCardInfo("Coral Eel", 33, Rarity.COMMON, mage.cards.c.CoralEel.class)); + cards.add(new SetCardInfo("Counterspell", 34, Rarity.UNCOMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Dakmor Ghoul", 70, Rarity.UNCOMMON, mage.cards.d.DakmorGhoul.class)); + cards.add(new SetCardInfo("Dakmor Lancer", 71, Rarity.RARE, mage.cards.d.DakmorLancer.class)); + cards.add(new SetCardInfo("Dakmor Plague", 72, Rarity.UNCOMMON, mage.cards.d.DakmorPlague.class)); + cards.add(new SetCardInfo("Dakmor Scorpion", 73, Rarity.COMMON, mage.cards.d.DakmorScorpion.class)); + cards.add(new SetCardInfo("Dakmor Sorceress", 74, Rarity.RARE, mage.cards.d.DakmorSorceress.class)); + cards.add(new SetCardInfo("Dark Offering", 75, Rarity.UNCOMMON, mage.cards.d.DarkOffering.class)); + cards.add(new SetCardInfo("Denizen of the Deep", 35, Rarity.RARE, mage.cards.d.DenizenOfTheDeep.class)); + cards.add(new SetCardInfo("Devastation", 94, Rarity.RARE, mage.cards.d.Devastation.class)); + cards.add(new SetCardInfo("Devoted Hero", 13, Rarity.COMMON, mage.cards.d.DevotedHero.class)); + cards.add(new SetCardInfo("Devout Monk", 14, Rarity.COMMON, mage.cards.d.DevoutMonk.class)); + cards.add(new SetCardInfo("Dread Reaper", 76, Rarity.RARE, mage.cards.d.DreadReaper.class)); + cards.add(new SetCardInfo("Durkwood Boars", 127, Rarity.COMMON, mage.cards.d.DurkwoodBoars.class)); + cards.add(new SetCardInfo("Eager Cadet", 15, Rarity.COMMON, mage.cards.e.EagerCadet.class)); + cards.add(new SetCardInfo("Earth Elemental", 95, Rarity.UNCOMMON, mage.cards.e.EarthElemental.class)); + cards.add(new SetCardInfo("Exhaustion", 36, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); + cards.add(new SetCardInfo("Extinguish", 37, Rarity.COMMON, mage.cards.e.Extinguish.class)); + cards.add(new SetCardInfo("Eye Spy", 38, Rarity.UNCOMMON, mage.cards.e.EyeSpy.class)); + cards.add(new SetCardInfo("False Peace", 16, Rarity.UNCOMMON, mage.cards.f.FalsePeace.class)); + cards.add(new SetCardInfo("Feral Shadow", 77, Rarity.COMMON, mage.cards.f.FeralShadow.class)); + cards.add(new SetCardInfo("Fire Elemental", 96, Rarity.UNCOMMON, mage.cards.f.FireElemental.class)); + cards.add(new SetCardInfo("Fire Tempest", 97, Rarity.RARE, mage.cards.f.FireTempest.class)); + cards.add(new SetCardInfo("Foot Soldiers", 17, Rarity.COMMON, mage.cards.f.FootSoldiers.class)); + cards.add(new SetCardInfo("Forest", 170, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 171, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 172, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 173, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gerrard's Wisdom", 18, Rarity.RARE, mage.cards.g.GerrardsWisdom.class)); + cards.add(new SetCardInfo("Giant Octopus", 39, Rarity.COMMON, mage.cards.g.GiantOctopus.class)); + cards.add(new SetCardInfo("Goblin Cavaliers", 98, Rarity.COMMON, mage.cards.g.GoblinCavaliers.class)); + cards.add(new SetCardInfo("Goblin Chariot", 99, Rarity.COMMON, mage.cards.g.GoblinChariot.class)); + cards.add(new SetCardInfo("Goblin Commando", 100, Rarity.UNCOMMON, mage.cards.g.GoblinCommando.class)); + cards.add(new SetCardInfo("Goblin General", 101, Rarity.UNCOMMON, mage.cards.g.GoblinGeneral.class)); + cards.add(new SetCardInfo("Goblin Glider", 102, Rarity.UNCOMMON, mage.cards.g.GoblinGlider.class)); + cards.add(new SetCardInfo("Goblin Hero", 103, Rarity.COMMON, mage.cards.g.GoblinHero.class)); + cards.add(new SetCardInfo("Goblin Lore", 104, Rarity.UNCOMMON, mage.cards.g.GoblinLore.class)); + cards.add(new SetCardInfo("Goblin Mountaineer", 105, Rarity.COMMON, mage.cards.g.GoblinMountaineer.class)); + cards.add(new SetCardInfo("Goblin Settler", 106, Rarity.UNCOMMON, mage.cards.g.GoblinSettler.class)); + cards.add(new SetCardInfo("Gorilla Warrior", 128, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); + cards.add(new SetCardInfo("Gravedigger", 78, Rarity.UNCOMMON, mage.cards.g.Gravedigger.class)); + cards.add(new SetCardInfo("Grim Tutor", 79, Rarity.RARE, mage.cards.g.GrimTutor.class)); + cards.add(new SetCardInfo("Grizzly Bears", 129, Rarity.COMMON, mage.cards.g.GrizzlyBears.class)); + cards.add(new SetCardInfo("Hand of Death", 80, Rarity.COMMON, mage.cards.h.HandOfDeath.class)); + cards.add(new SetCardInfo("Hollow Dogs", 81, Rarity.COMMON, mage.cards.h.HollowDogs.class)); + cards.add(new SetCardInfo("Howling Fury", 82, Rarity.UNCOMMON, mage.cards.h.HowlingFury.class)); + cards.add(new SetCardInfo("Hulking Goblin", 107, Rarity.COMMON, mage.cards.h.HulkingGoblin.class)); + cards.add(new SetCardInfo("Hulking Ogre", 108, Rarity.UNCOMMON, mage.cards.h.HulkingOgre.class)); + cards.add(new SetCardInfo("Ingenious Thief", 40, Rarity.COMMON, mage.cards.i.IngeniousThief.class)); + cards.add(new SetCardInfo("Island", 158, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 159, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 160, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 161, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jagged Lightning", 109, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); + cards.add(new SetCardInfo("Knight Errant", 19, Rarity.COMMON, mage.cards.k.KnightErrant.class)); + cards.add(new SetCardInfo("Last Chance", 110, Rarity.RARE, mage.cards.l.LastChance.class)); + cards.add(new SetCardInfo("Lava Axe", 111, Rarity.COMMON, mage.cards.l.LavaAxe.class)); + cards.add(new SetCardInfo("Lone Wolf", 130, Rarity.COMMON, mage.cards.l.LoneWolf.class)); + cards.add(new SetCardInfo("Loyal Sentry", 20, Rarity.RARE, mage.cards.l.LoyalSentry.class)); + cards.add(new SetCardInfo("Lynx", 131, Rarity.UNCOMMON, mage.cards.l.Lynx.class)); + cards.add(new SetCardInfo("Man-o'-War", 41, Rarity.UNCOMMON, mage.cards.m.ManOWar.class)); + cards.add(new SetCardInfo("Merfolk of the Pearl Trident", 42, Rarity.COMMON, mage.cards.m.MerfolkOfThePearlTrident.class)); + cards.add(new SetCardInfo("Mind Rot", 83, Rarity.COMMON, mage.cards.m.MindRot.class)); + cards.add(new SetCardInfo("Mons's Goblin Raiders", 112, Rarity.COMMON, mage.cards.m.MonssGoblinRaiders.class)); + cards.add(new SetCardInfo("Monstrous Growth", 132, Rarity.COMMON, mage.cards.m.MonstrousGrowth.class)); + cards.add(new SetCardInfo("Moon Sprite", 133, Rarity.UNCOMMON, mage.cards.m.MoonSprite.class)); + cards.add(new SetCardInfo("Mountain", 166, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 167, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 168, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 169, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Muck Rats", 84, Rarity.COMMON, mage.cards.m.MuckRats.class)); + cards.add(new SetCardInfo("Natural Spring", 134, Rarity.UNCOMMON, mage.cards.n.NaturalSpring.class)); + cards.add(new SetCardInfo("Nature's Cloak", 135, Rarity.RARE, mage.cards.n.NaturesCloak.class)); + cards.add(new SetCardInfo("Nature's Lore", 136, Rarity.COMMON, mage.cards.n.NaturesLore.class)); + cards.add(new SetCardInfo("Norwood Archers", 137, Rarity.COMMON, mage.cards.n.NorwoodArchers.class)); + cards.add(new SetCardInfo("Norwood Ranger", 138, Rarity.COMMON, mage.cards.n.NorwoodRanger.class)); + cards.add(new SetCardInfo("Ogre Warrior", 113, Rarity.COMMON, mage.cards.o.OgreWarrior.class)); + cards.add(new SetCardInfo("Path of Peace", 21, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); + cards.add(new SetCardInfo("Phantom Warrior", 44, Rarity.RARE, mage.cards.p.PhantomWarrior.class)); + cards.add(new SetCardInfo("Plains", 154, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 155, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 156, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 157, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Pride of Lions", 139, Rarity.UNCOMMON, mage.cards.p.PrideOfLions.class)); + cards.add(new SetCardInfo("Psychic Transfer", 46, Rarity.RARE, mage.cards.p.PsychicTransfer.class)); + cards.add(new SetCardInfo("Raging Goblin", 114, Rarity.COMMON, mage.cards.r.RagingGoblin.class)); + cards.add(new SetCardInfo("Raise Dead", 85, Rarity.COMMON, mage.cards.r.RaiseDead.class)); + cards.add(new SetCardInfo("Ransack", 47, Rarity.RARE, mage.cards.r.Ransack.class)); + cards.add(new SetCardInfo("Ravenous Rats", 86, Rarity.UNCOMMON, mage.cards.r.RavenousRats.class)); + cards.add(new SetCardInfo("Relearn", 48, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); + cards.add(new SetCardInfo("Relentless Assault", 115, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); + cards.add(new SetCardInfo("Remove Soul", 49, Rarity.COMMON, mage.cards.r.RemoveSoul.class)); + cards.add(new SetCardInfo("Renewing Touch", 140, Rarity.UNCOMMON, mage.cards.r.RenewingTouch.class)); + cards.add(new SetCardInfo("Righteous Charge", 22, Rarity.UNCOMMON, mage.cards.r.RighteousCharge.class)); + cards.add(new SetCardInfo("Righteous Fury", 23, Rarity.RARE, mage.cards.r.RighteousFury.class)); + cards.add(new SetCardInfo("Royal Falcon", 24, Rarity.COMMON, mage.cards.r.RoyalFalcon.class)); + cards.add(new SetCardInfo("Royal Trooper", 25, Rarity.UNCOMMON, mage.cards.r.RoyalTrooper.class)); + cards.add(new SetCardInfo("Sacred Nectar", 26, Rarity.COMMON, mage.cards.s.SacredNectar.class)); + cards.add(new SetCardInfo("Scathe Zombies", 87, Rarity.COMMON, mage.cards.s.ScatheZombies.class)); + cards.add(new SetCardInfo("Scorching Spear", 116, Rarity.COMMON, mage.cards.s.ScorchingSpear.class)); + cards.add(new SetCardInfo("Sea Eagle", 50, Rarity.COMMON, mage.cards.s.SeaEagle.class)); + cards.add(new SetCardInfo("Serpent Warrior", 88, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); + cards.add(new SetCardInfo("Shrieking Specter", 89, Rarity.UNCOMMON, mage.cards.s.ShriekingSpecter.class)); + cards.add(new SetCardInfo("Silverback Ape", 141, Rarity.UNCOMMON, mage.cards.s.SilverbackApe.class)); + cards.add(new SetCardInfo("Sleight of Hand", 51, Rarity.COMMON, mage.cards.s.SleightOfHand.class)); + cards.add(new SetCardInfo("Snapping Drake", 52, Rarity.COMMON, mage.cards.s.SnappingDrake.class)); + cards.add(new SetCardInfo("Soul Feast", 90, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); + cards.add(new SetCardInfo("Southern Elephant", 142, Rarity.COMMON, mage.cards.s.SouthernElephant.class)); + cards.add(new SetCardInfo("Spitting Earth", 117, Rarity.UNCOMMON, mage.cards.s.SpittingEarth.class)); + cards.add(new SetCardInfo("Squall", 143, Rarity.COMMON, mage.cards.s.Squall.class)); + cards.add(new SetCardInfo("Steadfastness", 27, Rarity.COMMON, mage.cards.s.Steadfastness.class)); + cards.add(new SetCardInfo("Stone Rain", 118, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Storm Crow", 53, Rarity.COMMON, mage.cards.s.StormCrow.class)); + cards.add(new SetCardInfo("Stream of Acid", 91, Rarity.UNCOMMON, mage.cards.s.StreamOfAcid.class)); + cards.add(new SetCardInfo("Summer Bloom", 144, Rarity.RARE, mage.cards.s.SummerBloom.class)); + cards.add(new SetCardInfo("Swamp", 162, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 163, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 164, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 165, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Sylvan Basilisk", 145, Rarity.RARE, mage.cards.s.SylvanBasilisk.class)); + cards.add(new SetCardInfo("Sylvan Yeti", 146, Rarity.RARE, mage.cards.s.SylvanYeti.class)); + cards.add(new SetCardInfo("Thorn Elemental", 147, Rarity.RARE, mage.cards.t.ThornElemental.class)); + cards.add(new SetCardInfo("Thunder Dragon", 119, Rarity.RARE, mage.cards.t.ThunderDragon.class)); + cards.add(new SetCardInfo("Tidings", 54, Rarity.UNCOMMON, mage.cards.t.Tidings.class)); + cards.add(new SetCardInfo("Time Ebb", 55, Rarity.COMMON, mage.cards.t.TimeEbb.class)); + cards.add(new SetCardInfo("Time Warp", 56, Rarity.RARE, mage.cards.t.TimeWarp.class)); + cards.add(new SetCardInfo("Touch of Brilliance", 57, Rarity.COMMON, mage.cards.t.TouchOfBrilliance.class)); + cards.add(new SetCardInfo("Trained Orgg", 120, Rarity.RARE, mage.cards.t.TrainedOrgg.class)); + cards.add(new SetCardInfo("Tremor", 121, Rarity.COMMON, mage.cards.t.Tremor.class)); + cards.add(new SetCardInfo("Undo", 58, Rarity.UNCOMMON, mage.cards.u.Undo.class)); + cards.add(new SetCardInfo("Untamed Wilds", 148, Rarity.UNCOMMON, mage.cards.u.UntamedWilds.class)); + cards.add(new SetCardInfo("Venerable Monk", 28, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); + cards.add(new SetCardInfo("Vengeance", 29, Rarity.UNCOMMON, mage.cards.v.Vengeance.class)); + cards.add(new SetCardInfo("Veteran Cavalier", 30, Rarity.UNCOMMON, mage.cards.v.VeteranCavalier.class)); + cards.add(new SetCardInfo("Vizzerdrix", 59, Rarity.RARE, mage.cards.v.Vizzerdrix.class)); + cards.add(new SetCardInfo("Volcanic Dragon", 122, Rarity.RARE, mage.cards.v.VolcanicDragon.class)); + cards.add(new SetCardInfo("Volcanic Hammer", 123, Rarity.COMMON, mage.cards.v.VolcanicHammer.class)); + cards.add(new SetCardInfo("Water Elemental", 60, Rarity.UNCOMMON, mage.cards.w.WaterElemental.class)); + cards.add(new SetCardInfo("Whiptail Wurm", 149, Rarity.UNCOMMON, mage.cards.w.WhiptailWurm.class)); + cards.add(new SetCardInfo("Whirlwind", 150, Rarity.RARE, mage.cards.w.Whirlwind.class)); + cards.add(new SetCardInfo("Wicked Pact", 92, Rarity.RARE, mage.cards.w.WickedPact.class)); + cards.add(new SetCardInfo("Wild Griffin", 31, Rarity.COMMON, mage.cards.w.WildGriffin.class)); + cards.add(new SetCardInfo("Wild Ox", 151, Rarity.UNCOMMON, mage.cards.w.WildOx.class)); + cards.add(new SetCardInfo("Willow Elf", 152, Rarity.COMMON, mage.cards.w.WillowElf.class)); + cards.add(new SetCardInfo("Wind Drake", 61, Rarity.COMMON, mage.cards.w.WindDrake.class)); + cards.add(new SetCardInfo("Wind Sail", 62, Rarity.UNCOMMON, mage.cards.w.WindSail.class)); + cards.add(new SetCardInfo("Wood Elves", 153, Rarity.UNCOMMON, mage.cards.w.WoodElves.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Stronghold.java b/Mage.Sets/src/mage/sets/Stronghold.java index 03ae248545..173d3fcf77 100644 --- a/Mage.Sets/src/mage/sets/Stronghold.java +++ b/Mage.Sets/src/mage/sets/Stronghold.java @@ -1,166 +1,174 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * @author North - */ -public final class Stronghold extends ExpansionSet { - - private static final Stronghold instance = new Stronghold(); - - public static Stronghold getInstance() { - return instance; - } - - private Stronghold() { - super("Stronghold", "STH", ExpansionSet.buildDate(1998, 3, 2), SetType.EXPANSION); - this.blockName = "Tempest"; - this.parentSet = Tempest.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Acidic Sliver", 126, Rarity.UNCOMMON, mage.cards.a.AcidicSliver.class)); - cards.add(new SetCardInfo("Amok", 76, Rarity.RARE, mage.cards.a.Amok.class)); - cards.add(new SetCardInfo("Awakening", 101, Rarity.RARE, mage.cards.a.Awakening.class)); - cards.add(new SetCardInfo("Bandage", 1, Rarity.COMMON, mage.cards.b.Bandage.class)); - cards.add(new SetCardInfo("Bottomless Pit", 51, Rarity.UNCOMMON, mage.cards.b.BottomlessPit.class)); - cards.add(new SetCardInfo("Brush with Death", 52, Rarity.COMMON, mage.cards.b.BrushWithDeath.class)); - cards.add(new SetCardInfo("Bullwhip", 132, Rarity.UNCOMMON, mage.cards.b.Bullwhip.class)); - cards.add(new SetCardInfo("Burgeoning", 102, Rarity.RARE, mage.cards.b.Burgeoning.class)); - cards.add(new SetCardInfo("Calming Licid", 2, Rarity.UNCOMMON, mage.cards.c.CalmingLicid.class)); - cards.add(new SetCardInfo("Cannibalize", 53, Rarity.COMMON, mage.cards.c.Cannibalize.class)); - cards.add(new SetCardInfo("Carnassid", 103, Rarity.RARE, mage.cards.c.Carnassid.class)); - cards.add(new SetCardInfo("Change of Heart", 3, Rarity.COMMON, mage.cards.c.ChangeOfHeart.class)); - cards.add(new SetCardInfo("Cloud Spirit", 26, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); - cards.add(new SetCardInfo("Constant Mists", 104, Rarity.UNCOMMON, mage.cards.c.ConstantMists.class)); - cards.add(new SetCardInfo("Contemplation", 4, Rarity.UNCOMMON, mage.cards.c.Contemplation.class)); - cards.add(new SetCardInfo("Conviction", 5, Rarity.COMMON, mage.cards.c.Conviction.class)); - cards.add(new SetCardInfo("Convulsing Licid", 77, Rarity.UNCOMMON, mage.cards.c.ConvulsingLicid.class)); - cards.add(new SetCardInfo("Corrupting Licid", 54, Rarity.UNCOMMON, mage.cards.c.CorruptingLicid.class)); - cards.add(new SetCardInfo("Craven Giant", 78, Rarity.COMMON, mage.cards.c.CravenGiant.class)); - cards.add(new SetCardInfo("Crossbow Ambush", 105, Rarity.COMMON, mage.cards.c.CrossbowAmbush.class)); - cards.add(new SetCardInfo("Crovax the Cursed", 55, Rarity.RARE, mage.cards.c.CrovaxTheCursed.class)); - cards.add(new SetCardInfo("Crystalline Sliver", 127, Rarity.UNCOMMON, mage.cards.c.CrystallineSliver.class)); - cards.add(new SetCardInfo("Dauthi Trapper", 56, Rarity.UNCOMMON, mage.cards.d.DauthiTrapper.class)); - cards.add(new SetCardInfo("Death Stroke", 57, Rarity.COMMON, mage.cards.d.DeathStroke.class)); - cards.add(new SetCardInfo("Dream Halls", 28, Rarity.RARE, mage.cards.d.DreamHalls.class)); - cards.add(new SetCardInfo("Dream Prowler", 29, Rarity.COMMON, mage.cards.d.DreamProwler.class)); - cards.add(new SetCardInfo("Duct Crawler", 79, Rarity.COMMON, mage.cards.d.DuctCrawler.class)); - cards.add(new SetCardInfo("Dungeon Shade", 58, Rarity.COMMON, mage.cards.d.DungeonShade.class)); - cards.add(new SetCardInfo("Elven Rite", 106, Rarity.UNCOMMON, mage.cards.e.ElvenRite.class)); - cards.add(new SetCardInfo("Endangered Armodon", 107, Rarity.COMMON, mage.cards.e.EndangeredArmodon.class)); - cards.add(new SetCardInfo("Ensnaring Bridge", 133, Rarity.RARE, mage.cards.e.EnsnaringBridge.class)); - cards.add(new SetCardInfo("Evacuation", 30, Rarity.RARE, mage.cards.e.Evacuation.class)); - cards.add(new SetCardInfo("Fanning the Flames", 80, Rarity.UNCOMMON, mage.cards.f.FanningTheFlames.class)); - cards.add(new SetCardInfo("Flame Wave", 81, Rarity.UNCOMMON, mage.cards.f.FlameWave.class)); - cards.add(new SetCardInfo("Fling", 82, Rarity.COMMON, mage.cards.f.Fling.class)); - cards.add(new SetCardInfo("Flowstone Blade", 83, Rarity.COMMON, mage.cards.f.FlowstoneBlade.class)); - cards.add(new SetCardInfo("Flowstone Hellion", 84, Rarity.UNCOMMON, mage.cards.f.FlowstoneHellion.class)); - cards.add(new SetCardInfo("Flowstone Mauler", 85, Rarity.RARE, mage.cards.f.FlowstoneMauler.class)); - cards.add(new SetCardInfo("Flowstone Shambler", 86, Rarity.COMMON, mage.cards.f.FlowstoneShambler.class)); - cards.add(new SetCardInfo("Foul Imp", 59, Rarity.COMMON, mage.cards.f.FoulImp.class)); - cards.add(new SetCardInfo("Furnace Spirit", 87, Rarity.COMMON, mage.cards.f.FurnaceSpirit.class)); - cards.add(new SetCardInfo("Gliding Licid", 31, Rarity.UNCOMMON, mage.cards.g.GlidingLicid.class)); - cards.add(new SetCardInfo("Grave Pact", 60, Rarity.RARE, mage.cards.g.GravePact.class)); - cards.add(new SetCardInfo("Hammerhead Shark", 32, Rarity.COMMON, mage.cards.h.HammerheadShark.class)); - cards.add(new SetCardInfo("Heartstone", 134, Rarity.UNCOMMON, mage.cards.h.Heartstone.class)); - cards.add(new SetCardInfo("Heat of Battle", 88, Rarity.UNCOMMON, mage.cards.h.HeatOfBattle.class)); - cards.add(new SetCardInfo("Hermit Druid", 108, Rarity.RARE, mage.cards.h.HermitDruid.class)); - cards.add(new SetCardInfo("Hesitation", 33, Rarity.UNCOMMON, mage.cards.h.Hesitation.class)); - cards.add(new SetCardInfo("Hibernation Sliver", 128, Rarity.UNCOMMON, mage.cards.h.HibernationSliver.class)); - cards.add(new SetCardInfo("Honor Guard", 7, Rarity.COMMON, mage.cards.h.HonorGuard.class)); - cards.add(new SetCardInfo("Horn of Greed", 135, Rarity.RARE, mage.cards.h.HornOfGreed.class)); - cards.add(new SetCardInfo("Hornet Cannon", 136, Rarity.UNCOMMON, mage.cards.h.HornetCannon.class)); - cards.add(new SetCardInfo("Intruder Alarm", 34, Rarity.RARE, mage.cards.i.IntruderAlarm.class)); - cards.add(new SetCardInfo("Invasion Plans", 89, Rarity.RARE, mage.cards.i.InvasionPlans.class)); - cards.add(new SetCardInfo("Jinxed Ring", 137, Rarity.RARE, mage.cards.j.JinxedRing.class)); - cards.add(new SetCardInfo("Lab Rats", 61, Rarity.COMMON, mage.cards.l.LabRats.class)); - cards.add(new SetCardInfo("Lancers en-Kor", 8, Rarity.UNCOMMON, mage.cards.l.LancersEnKor.class)); - cards.add(new SetCardInfo("Leap", 35, Rarity.COMMON, mage.cards.l.Leap.class)); - cards.add(new SetCardInfo("Lowland Basilisk", 109, Rarity.COMMON, mage.cards.l.LowlandBasilisk.class)); - cards.add(new SetCardInfo("Mana Leak", 36, Rarity.COMMON, mage.cards.m.ManaLeak.class)); - cards.add(new SetCardInfo("Mask of the Mimic", 37, Rarity.UNCOMMON, mage.cards.m.MaskOfTheMimic.class)); - cards.add(new SetCardInfo("Megrim", 62, Rarity.UNCOMMON, mage.cards.m.Megrim.class)); - cards.add(new SetCardInfo("Mind Games", 38, Rarity.COMMON, mage.cards.m.MindGames.class)); - cards.add(new SetCardInfo("Mind Peel", 63, Rarity.UNCOMMON, mage.cards.m.MindPeel.class)); - cards.add(new SetCardInfo("Mindwarper", 64, Rarity.RARE, mage.cards.m.Mindwarper.class)); - cards.add(new SetCardInfo("Mob Justice", 90, Rarity.COMMON, mage.cards.m.MobJustice.class)); - cards.add(new SetCardInfo("Mogg Flunkies", 92, Rarity.COMMON, mage.cards.m.MoggFlunkies.class)); - cards.add(new SetCardInfo("Mogg Infestation", 93, Rarity.RARE, mage.cards.m.MoggInfestation.class)); - cards.add(new SetCardInfo("Mogg Maniac", 94, Rarity.UNCOMMON, mage.cards.m.MoggManiac.class)); - cards.add(new SetCardInfo("Morgue Thrull", 65, Rarity.COMMON, mage.cards.m.MorgueThrull.class)); - cards.add(new SetCardInfo("Mortuary", 66, Rarity.RARE, mage.cards.m.Mortuary.class)); - cards.add(new SetCardInfo("Mox Diamond", 138, Rarity.RARE, mage.cards.m.MoxDiamond.class)); - cards.add(new SetCardInfo("Mulch", 110, Rarity.COMMON, mage.cards.m.Mulch.class)); - cards.add(new SetCardInfo("Nomads en-Kor", 9, Rarity.COMMON, mage.cards.n.NomadsEnKor.class)); - cards.add(new SetCardInfo("Overgrowth", 111, Rarity.COMMON, mage.cards.o.Overgrowth.class)); - cards.add(new SetCardInfo("Portcullis", 139, Rarity.RARE, mage.cards.p.Portcullis.class)); - cards.add(new SetCardInfo("Primal Rage", 112, Rarity.UNCOMMON, mage.cards.p.PrimalRage.class)); - cards.add(new SetCardInfo("Provoke", 113, Rarity.COMMON, mage.cards.p.Provoke.class)); - cards.add(new SetCardInfo("Pursuit of Knowledge", 10, Rarity.RARE, mage.cards.p.PursuitOfKnowledge.class)); - cards.add(new SetCardInfo("Rabid Rats", 67, Rarity.COMMON, mage.cards.r.RabidRats.class)); - cards.add(new SetCardInfo("Reins of Power", 41, Rarity.RARE, mage.cards.r.ReinsOfPower.class)); - cards.add(new SetCardInfo("Revenant", 68, Rarity.RARE, mage.cards.r.Revenant.class)); - cards.add(new SetCardInfo("Rolling Stones", 11, Rarity.RARE, mage.cards.r.RollingStones.class)); - cards.add(new SetCardInfo("Ruination", 95, Rarity.RARE, mage.cards.r.Ruination.class)); - cards.add(new SetCardInfo("Sacred Ground", 12, Rarity.RARE, mage.cards.s.SacredGround.class)); - cards.add(new SetCardInfo("Scapegoat", 14, Rarity.UNCOMMON, mage.cards.s.Scapegoat.class)); - cards.add(new SetCardInfo("Seething Anger", 96, Rarity.COMMON, mage.cards.s.SeethingAnger.class)); - cards.add(new SetCardInfo("Serpent Warrior", 69, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); - cards.add(new SetCardInfo("Shaman en-Kor", 15, Rarity.RARE, mage.cards.s.ShamanEnKor.class)); - cards.add(new SetCardInfo("Shard Phoenix", 97, Rarity.RARE, mage.cards.s.ShardPhoenix.class)); - cards.add(new SetCardInfo("Shifting Wall", 140, Rarity.UNCOMMON, mage.cards.s.ShiftingWall.class)); - cards.add(new SetCardInfo("Shock", 98, Rarity.COMMON, mage.cards.s.Shock.class)); - cards.add(new SetCardInfo("Sift", 42, Rarity.COMMON, mage.cards.s.Sift.class)); - cards.add(new SetCardInfo("Silver Wyvern", 43, Rarity.RARE, mage.cards.s.SilverWyvern.class)); - cards.add(new SetCardInfo("Skyshroud Archer", 114, Rarity.COMMON, mage.cards.s.SkyshroudArcher.class)); - cards.add(new SetCardInfo("Skyshroud Falcon", 16, Rarity.COMMON, mage.cards.s.SkyshroudFalcon.class)); - cards.add(new SetCardInfo("Skyshroud Troopers", 115, Rarity.COMMON, mage.cards.s.SkyshroudTroopers.class)); - cards.add(new SetCardInfo("Sliver Queen", 129, Rarity.RARE, mage.cards.s.SliverQueen.class)); - cards.add(new SetCardInfo("Smite", 17, Rarity.COMMON, mage.cards.s.Smite.class)); - cards.add(new SetCardInfo("Soltari Champion", 18, Rarity.RARE, mage.cards.s.SoltariChampion.class)); - cards.add(new SetCardInfo("Spike Breeder", 116, Rarity.RARE, mage.cards.s.SpikeBreeder.class)); - cards.add(new SetCardInfo("Spike Colony", 117, Rarity.COMMON, mage.cards.s.SpikeColony.class)); - cards.add(new SetCardInfo("Spike Feeder", 118, Rarity.UNCOMMON, mage.cards.s.SpikeFeeder.class)); - cards.add(new SetCardInfo("Spike Soldier", 119, Rarity.UNCOMMON, mage.cards.s.SpikeSoldier.class)); - cards.add(new SetCardInfo("Spike Worker", 120, Rarity.COMMON, mage.cards.s.SpikeWorker.class)); - cards.add(new SetCardInfo("Spindrift Drake", 44, Rarity.COMMON, mage.cards.s.SpindriftDrake.class)); - cards.add(new SetCardInfo("Spined Sliver", 130, Rarity.UNCOMMON, mage.cards.s.SpinedSliver.class)); - cards.add(new SetCardInfo("Spined Wurm", 121, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); - cards.add(new SetCardInfo("Spirit en-Kor", 19, Rarity.COMMON, mage.cards.s.SpiritEnKor.class)); - cards.add(new SetCardInfo("Spitting Hydra", 99, Rarity.RARE, mage.cards.s.SpittingHydra.class)); - cards.add(new SetCardInfo("Stronghold Assassin", 71, Rarity.RARE, mage.cards.s.StrongholdAssassin.class)); - cards.add(new SetCardInfo("Stronghold Taskmaster", 72, Rarity.UNCOMMON, mage.cards.s.StrongholdTaskmaster.class)); - cards.add(new SetCardInfo("Sword of the Chosen", 141, Rarity.RARE, mage.cards.s.SwordOfTheChosen.class)); - cards.add(new SetCardInfo("Temper", 20, Rarity.UNCOMMON, mage.cards.t.Temper.class)); - cards.add(new SetCardInfo("Tempting Licid", 122, Rarity.UNCOMMON, mage.cards.t.TemptingLicid.class)); - cards.add(new SetCardInfo("Thalakos Deceiver", 45, Rarity.RARE, mage.cards.t.ThalakosDeceiver.class)); - cards.add(new SetCardInfo("Tidal Surge", 46, Rarity.COMMON, mage.cards.t.TidalSurge.class)); - cards.add(new SetCardInfo("Tidal Warrior", 47, Rarity.COMMON, mage.cards.t.TidalWarrior.class)); - cards.add(new SetCardInfo("Torment", 73, Rarity.COMMON, mage.cards.t.Torment.class)); - cards.add(new SetCardInfo("Tortured Existence", 74, Rarity.COMMON, mage.cards.t.TorturedExistence.class)); - cards.add(new SetCardInfo("Venerable Monk", 21, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); - cards.add(new SetCardInfo("Verdant Touch", 123, Rarity.RARE, mage.cards.v.VerdantTouch.class)); - cards.add(new SetCardInfo("Victual Sliver", 131, Rarity.UNCOMMON, mage.cards.v.VictualSliver.class)); - cards.add(new SetCardInfo("Volrath's Gardens", 124, Rarity.RARE, mage.cards.v.VolrathsGardens.class)); - cards.add(new SetCardInfo("Volrath's Laboratory", 142, Rarity.RARE, mage.cards.v.VolrathsLaboratory.class)); - cards.add(new SetCardInfo("Volrath's Shapeshifter", 48, Rarity.RARE, mage.cards.v.VolrathsShapeshifter.class)); - cards.add(new SetCardInfo("Volrath's Stronghold", 143, Rarity.RARE, mage.cards.v.VolrathsStronghold.class)); - cards.add(new SetCardInfo("Wall of Blossoms", 125, Rarity.UNCOMMON, mage.cards.w.WallOfBlossoms.class)); - cards.add(new SetCardInfo("Wall of Essence", 22, Rarity.UNCOMMON, mage.cards.w.WallOfEssence.class)); - cards.add(new SetCardInfo("Wall of Razors", 100, Rarity.UNCOMMON, mage.cards.w.WallOfRazors.class)); - cards.add(new SetCardInfo("Wall of Souls", 75, Rarity.UNCOMMON, mage.cards.w.WallOfSouls.class)); - cards.add(new SetCardInfo("Wall of Tears", 50, Rarity.UNCOMMON, mage.cards.w.WallOfTears.class)); - cards.add(new SetCardInfo("Warrior Angel", 24, Rarity.RARE, mage.cards.w.WarriorAngel.class)); - cards.add(new SetCardInfo("Warrior en-Kor", 23, Rarity.UNCOMMON, mage.cards.w.WarriorEnKor.class)); - cards.add(new SetCardInfo("Youthful Knight", 25, Rarity.COMMON, mage.cards.y.YouthfulKnight.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author North + */ +public final class Stronghold extends ExpansionSet { + + private static final Stronghold instance = new Stronghold(); + + public static Stronghold getInstance() { + return instance; + } + + private Stronghold() { + super("Stronghold", "STH", ExpansionSet.buildDate(1998, 3, 2), SetType.EXPANSION); + this.blockName = "Tempest"; + this.parentSet = Tempest.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + + cards.add(new SetCardInfo("Acidic Sliver", 126, Rarity.UNCOMMON, mage.cards.a.AcidicSliver.class)); + cards.add(new SetCardInfo("Amok", 76, Rarity.RARE, mage.cards.a.Amok.class)); + cards.add(new SetCardInfo("Awakening", 101, Rarity.RARE, mage.cards.a.Awakening.class)); + cards.add(new SetCardInfo("Bandage", 1, Rarity.COMMON, mage.cards.b.Bandage.class)); + cards.add(new SetCardInfo("Bottomless Pit", 51, Rarity.UNCOMMON, mage.cards.b.BottomlessPit.class)); + cards.add(new SetCardInfo("Brush with Death", 52, Rarity.COMMON, mage.cards.b.BrushWithDeath.class)); + cards.add(new SetCardInfo("Bullwhip", 132, Rarity.UNCOMMON, mage.cards.b.Bullwhip.class)); + cards.add(new SetCardInfo("Burgeoning", 102, Rarity.RARE, mage.cards.b.Burgeoning.class)); + cards.add(new SetCardInfo("Calming Licid", 2, Rarity.UNCOMMON, mage.cards.c.CalmingLicid.class)); + cards.add(new SetCardInfo("Cannibalize", 53, Rarity.COMMON, mage.cards.c.Cannibalize.class)); + cards.add(new SetCardInfo("Carnassid", 103, Rarity.RARE, mage.cards.c.Carnassid.class)); + cards.add(new SetCardInfo("Change of Heart", 3, Rarity.COMMON, mage.cards.c.ChangeOfHeart.class)); + cards.add(new SetCardInfo("Cloud Spirit", 26, Rarity.COMMON, mage.cards.c.CloudSpirit.class)); + cards.add(new SetCardInfo("Constant Mists", 104, Rarity.UNCOMMON, mage.cards.c.ConstantMists.class)); + cards.add(new SetCardInfo("Contemplation", 4, Rarity.UNCOMMON, mage.cards.c.Contemplation.class)); + cards.add(new SetCardInfo("Contempt", 27, Rarity.COMMON, mage.cards.c.Contempt.class)); + cards.add(new SetCardInfo("Conviction", 5, Rarity.COMMON, mage.cards.c.Conviction.class)); + cards.add(new SetCardInfo("Convulsing Licid", 77, Rarity.UNCOMMON, mage.cards.c.ConvulsingLicid.class)); + cards.add(new SetCardInfo("Corrupting Licid", 54, Rarity.UNCOMMON, mage.cards.c.CorruptingLicid.class)); + cards.add(new SetCardInfo("Craven Giant", 78, Rarity.COMMON, mage.cards.c.CravenGiant.class)); + cards.add(new SetCardInfo("Crossbow Ambush", 105, Rarity.COMMON, mage.cards.c.CrossbowAmbush.class)); + cards.add(new SetCardInfo("Crovax the Cursed", 55, Rarity.RARE, mage.cards.c.CrovaxTheCursed.class)); + cards.add(new SetCardInfo("Crystalline Sliver", 127, Rarity.UNCOMMON, mage.cards.c.CrystallineSliver.class)); + cards.add(new SetCardInfo("Dauthi Trapper", 56, Rarity.UNCOMMON, mage.cards.d.DauthiTrapper.class)); + cards.add(new SetCardInfo("Death Stroke", 57, Rarity.COMMON, mage.cards.d.DeathStroke.class)); + cards.add(new SetCardInfo("Dream Halls", 28, Rarity.RARE, mage.cards.d.DreamHalls.class)); + cards.add(new SetCardInfo("Dream Prowler", 29, Rarity.COMMON, mage.cards.d.DreamProwler.class)); + cards.add(new SetCardInfo("Duct Crawler", 79, Rarity.COMMON, mage.cards.d.DuctCrawler.class)); + cards.add(new SetCardInfo("Dungeon Shade", 58, Rarity.COMMON, mage.cards.d.DungeonShade.class)); + cards.add(new SetCardInfo("Elven Rite", 106, Rarity.UNCOMMON, mage.cards.e.ElvenRite.class)); + cards.add(new SetCardInfo("Endangered Armodon", 107, Rarity.COMMON, mage.cards.e.EndangeredArmodon.class)); + cards.add(new SetCardInfo("Ensnaring Bridge", 133, Rarity.RARE, mage.cards.e.EnsnaringBridge.class)); + cards.add(new SetCardInfo("Evacuation", 30, Rarity.RARE, mage.cards.e.Evacuation.class)); + cards.add(new SetCardInfo("Fanning the Flames", 80, Rarity.UNCOMMON, mage.cards.f.FanningTheFlames.class)); + cards.add(new SetCardInfo("Flame Wave", 81, Rarity.UNCOMMON, mage.cards.f.FlameWave.class)); + cards.add(new SetCardInfo("Fling", 82, Rarity.COMMON, mage.cards.f.Fling.class)); + cards.add(new SetCardInfo("Flowstone Blade", 83, Rarity.COMMON, mage.cards.f.FlowstoneBlade.class)); + cards.add(new SetCardInfo("Flowstone Hellion", 84, Rarity.UNCOMMON, mage.cards.f.FlowstoneHellion.class)); + cards.add(new SetCardInfo("Flowstone Mauler", 85, Rarity.RARE, mage.cards.f.FlowstoneMauler.class)); + cards.add(new SetCardInfo("Flowstone Shambler", 86, Rarity.COMMON, mage.cards.f.FlowstoneShambler.class)); + cards.add(new SetCardInfo("Foul Imp", 59, Rarity.COMMON, mage.cards.f.FoulImp.class)); + cards.add(new SetCardInfo("Furnace Spirit", 87, Rarity.COMMON, mage.cards.f.FurnaceSpirit.class)); + cards.add(new SetCardInfo("Gliding Licid", 31, Rarity.UNCOMMON, mage.cards.g.GlidingLicid.class)); + cards.add(new SetCardInfo("Grave Pact", 60, Rarity.RARE, mage.cards.g.GravePact.class)); + cards.add(new SetCardInfo("Hammerhead Shark", 32, Rarity.COMMON, mage.cards.h.HammerheadShark.class)); + cards.add(new SetCardInfo("Heartstone", 134, Rarity.UNCOMMON, mage.cards.h.Heartstone.class)); + cards.add(new SetCardInfo("Heat of Battle", 88, Rarity.UNCOMMON, mage.cards.h.HeatOfBattle.class)); + cards.add(new SetCardInfo("Hermit Druid", 108, Rarity.RARE, mage.cards.h.HermitDruid.class)); + cards.add(new SetCardInfo("Hesitation", 33, Rarity.UNCOMMON, mage.cards.h.Hesitation.class)); + cards.add(new SetCardInfo("Hibernation Sliver", 128, Rarity.UNCOMMON, mage.cards.h.HibernationSliver.class)); + cards.add(new SetCardInfo("Hidden Retreat", 6, Rarity.RARE, mage.cards.h.HiddenRetreat.class)); + cards.add(new SetCardInfo("Honor Guard", 7, Rarity.COMMON, mage.cards.h.HonorGuard.class)); + cards.add(new SetCardInfo("Horn of Greed", 135, Rarity.RARE, mage.cards.h.HornOfGreed.class)); + cards.add(new SetCardInfo("Hornet Cannon", 136, Rarity.UNCOMMON, mage.cards.h.HornetCannon.class)); + cards.add(new SetCardInfo("Intruder Alarm", 34, Rarity.RARE, mage.cards.i.IntruderAlarm.class)); + cards.add(new SetCardInfo("Invasion Plans", 89, Rarity.RARE, mage.cards.i.InvasionPlans.class)); + cards.add(new SetCardInfo("Jinxed Ring", 137, Rarity.RARE, mage.cards.j.JinxedRing.class)); + cards.add(new SetCardInfo("Lab Rats", 61, Rarity.COMMON, mage.cards.l.LabRats.class)); + cards.add(new SetCardInfo("Lancers en-Kor", 8, Rarity.UNCOMMON, mage.cards.l.LancersEnKor.class)); + cards.add(new SetCardInfo("Leap", 35, Rarity.COMMON, mage.cards.l.Leap.class)); + cards.add(new SetCardInfo("Lowland Basilisk", 109, Rarity.COMMON, mage.cards.l.LowlandBasilisk.class)); + cards.add(new SetCardInfo("Mana Leak", 36, Rarity.COMMON, mage.cards.m.ManaLeak.class)); + cards.add(new SetCardInfo("Mask of the Mimic", 37, Rarity.UNCOMMON, mage.cards.m.MaskOfTheMimic.class)); + cards.add(new SetCardInfo("Megrim", 62, Rarity.UNCOMMON, mage.cards.m.Megrim.class)); + cards.add(new SetCardInfo("Mind Games", 38, Rarity.COMMON, mage.cards.m.MindGames.class)); + cards.add(new SetCardInfo("Mind Peel", 63, Rarity.UNCOMMON, mage.cards.m.MindPeel.class)); + cards.add(new SetCardInfo("Mindwarper", 64, Rarity.RARE, mage.cards.m.Mindwarper.class)); + cards.add(new SetCardInfo("Mob Justice", 90, Rarity.COMMON, mage.cards.m.MobJustice.class)); + cards.add(new SetCardInfo("Mogg Bombers", 91, Rarity.COMMON, mage.cards.m.MoggBombers.class)); + cards.add(new SetCardInfo("Mogg Flunkies", 92, Rarity.COMMON, mage.cards.m.MoggFlunkies.class)); + cards.add(new SetCardInfo("Mogg Infestation", 93, Rarity.RARE, mage.cards.m.MoggInfestation.class)); + cards.add(new SetCardInfo("Mogg Maniac", 94, Rarity.UNCOMMON, mage.cards.m.MoggManiac.class)); + cards.add(new SetCardInfo("Morgue Thrull", 65, Rarity.COMMON, mage.cards.m.MorgueThrull.class)); + cards.add(new SetCardInfo("Mortuary", 66, Rarity.RARE, mage.cards.m.Mortuary.class)); + cards.add(new SetCardInfo("Mox Diamond", 138, Rarity.RARE, mage.cards.m.MoxDiamond.class)); + cards.add(new SetCardInfo("Mulch", 110, Rarity.COMMON, mage.cards.m.Mulch.class)); + cards.add(new SetCardInfo("Nomads en-Kor", 9, Rarity.COMMON, mage.cards.n.NomadsEnKor.class)); + cards.add(new SetCardInfo("Overgrowth", 111, Rarity.COMMON, mage.cards.o.Overgrowth.class)); + cards.add(new SetCardInfo("Portcullis", 139, Rarity.RARE, mage.cards.p.Portcullis.class)); + cards.add(new SetCardInfo("Primal Rage", 112, Rarity.UNCOMMON, mage.cards.p.PrimalRage.class)); + cards.add(new SetCardInfo("Provoke", 113, Rarity.COMMON, mage.cards.p.Provoke.class)); + cards.add(new SetCardInfo("Pursuit of Knowledge", 10, Rarity.RARE, mage.cards.p.PursuitOfKnowledge.class)); + cards.add(new SetCardInfo("Rabid Rats", 67, Rarity.COMMON, mage.cards.r.RabidRats.class)); + cards.add(new SetCardInfo("Ransack", 39, Rarity.UNCOMMON, mage.cards.r.Ransack.class)); + cards.add(new SetCardInfo("Rebound", 40, Rarity.UNCOMMON, mage.cards.r.Rebound.class)); + cards.add(new SetCardInfo("Reins of Power", 41, Rarity.RARE, mage.cards.r.ReinsOfPower.class)); + cards.add(new SetCardInfo("Revenant", 68, Rarity.RARE, mage.cards.r.Revenant.class)); + cards.add(new SetCardInfo("Rolling Stones", 11, Rarity.RARE, mage.cards.r.RollingStones.class)); + cards.add(new SetCardInfo("Ruination", 95, Rarity.RARE, mage.cards.r.Ruination.class)); + cards.add(new SetCardInfo("Sacred Ground", 12, Rarity.RARE, mage.cards.s.SacredGround.class)); + cards.add(new SetCardInfo("Samite Blessing", 13, Rarity.COMMON, mage.cards.s.SamiteBlessing.class)); + cards.add(new SetCardInfo("Scapegoat", 14, Rarity.UNCOMMON, mage.cards.s.Scapegoat.class)); + cards.add(new SetCardInfo("Seething Anger", 96, Rarity.COMMON, mage.cards.s.SeethingAnger.class)); + cards.add(new SetCardInfo("Serpent Warrior", 69, Rarity.COMMON, mage.cards.s.SerpentWarrior.class)); + cards.add(new SetCardInfo("Shaman en-Kor", 15, Rarity.RARE, mage.cards.s.ShamanEnKor.class)); + cards.add(new SetCardInfo("Shard Phoenix", 97, Rarity.RARE, mage.cards.s.ShardPhoenix.class)); + cards.add(new SetCardInfo("Shifting Wall", 140, Rarity.UNCOMMON, mage.cards.s.ShiftingWall.class)); + cards.add(new SetCardInfo("Shock", 98, Rarity.COMMON, mage.cards.s.Shock.class)); + cards.add(new SetCardInfo("Sift", 42, Rarity.COMMON, mage.cards.s.Sift.class)); + cards.add(new SetCardInfo("Silver Wyvern", 43, Rarity.RARE, mage.cards.s.SilverWyvern.class)); + cards.add(new SetCardInfo("Skeleton Scavengers", 70, Rarity.RARE, mage.cards.s.SkeletonScavengers.class)); + cards.add(new SetCardInfo("Skyshroud Archer", 114, Rarity.COMMON, mage.cards.s.SkyshroudArcher.class)); + cards.add(new SetCardInfo("Skyshroud Falcon", 16, Rarity.COMMON, mage.cards.s.SkyshroudFalcon.class)); + cards.add(new SetCardInfo("Skyshroud Troopers", 115, Rarity.COMMON, mage.cards.s.SkyshroudTroopers.class)); + cards.add(new SetCardInfo("Sliver Queen", 129, Rarity.RARE, mage.cards.s.SliverQueen.class)); + cards.add(new SetCardInfo("Smite", 17, Rarity.COMMON, mage.cards.s.Smite.class)); + cards.add(new SetCardInfo("Soltari Champion", 18, Rarity.RARE, mage.cards.s.SoltariChampion.class)); + cards.add(new SetCardInfo("Spike Breeder", 116, Rarity.RARE, mage.cards.s.SpikeBreeder.class)); + cards.add(new SetCardInfo("Spike Colony", 117, Rarity.COMMON, mage.cards.s.SpikeColony.class)); + cards.add(new SetCardInfo("Spike Feeder", 118, Rarity.UNCOMMON, mage.cards.s.SpikeFeeder.class)); + cards.add(new SetCardInfo("Spike Soldier", 119, Rarity.UNCOMMON, mage.cards.s.SpikeSoldier.class)); + cards.add(new SetCardInfo("Spike Worker", 120, Rarity.COMMON, mage.cards.s.SpikeWorker.class)); + cards.add(new SetCardInfo("Spindrift Drake", 44, Rarity.COMMON, mage.cards.s.SpindriftDrake.class)); + cards.add(new SetCardInfo("Spined Sliver", 130, Rarity.UNCOMMON, mage.cards.s.SpinedSliver.class)); + cards.add(new SetCardInfo("Spined Wurm", 121, Rarity.COMMON, mage.cards.s.SpinedWurm.class)); + cards.add(new SetCardInfo("Spirit en-Kor", 19, Rarity.COMMON, mage.cards.s.SpiritEnKor.class)); + cards.add(new SetCardInfo("Spitting Hydra", 99, Rarity.RARE, mage.cards.s.SpittingHydra.class)); + cards.add(new SetCardInfo("Stronghold Assassin", 71, Rarity.RARE, mage.cards.s.StrongholdAssassin.class)); + cards.add(new SetCardInfo("Stronghold Taskmaster", 72, Rarity.UNCOMMON, mage.cards.s.StrongholdTaskmaster.class)); + cards.add(new SetCardInfo("Sword of the Chosen", 141, Rarity.RARE, mage.cards.s.SwordOfTheChosen.class)); + cards.add(new SetCardInfo("Temper", 20, Rarity.UNCOMMON, mage.cards.t.Temper.class)); + cards.add(new SetCardInfo("Tempting Licid", 122, Rarity.UNCOMMON, mage.cards.t.TemptingLicid.class)); + cards.add(new SetCardInfo("Thalakos Deceiver", 45, Rarity.RARE, mage.cards.t.ThalakosDeceiver.class)); + cards.add(new SetCardInfo("Tidal Surge", 46, Rarity.COMMON, mage.cards.t.TidalSurge.class)); + cards.add(new SetCardInfo("Tidal Warrior", 47, Rarity.COMMON, mage.cards.t.TidalWarrior.class)); + cards.add(new SetCardInfo("Torment", 73, Rarity.COMMON, mage.cards.t.Torment.class)); + cards.add(new SetCardInfo("Tortured Existence", 74, Rarity.COMMON, mage.cards.t.TorturedExistence.class)); + cards.add(new SetCardInfo("Venerable Monk", 21, Rarity.COMMON, mage.cards.v.VenerableMonk.class)); + cards.add(new SetCardInfo("Verdant Touch", 123, Rarity.RARE, mage.cards.v.VerdantTouch.class)); + cards.add(new SetCardInfo("Victual Sliver", 131, Rarity.UNCOMMON, mage.cards.v.VictualSliver.class)); + cards.add(new SetCardInfo("Volrath's Gardens", 124, Rarity.RARE, mage.cards.v.VolrathsGardens.class)); + cards.add(new SetCardInfo("Volrath's Laboratory", 142, Rarity.RARE, mage.cards.v.VolrathsLaboratory.class)); + cards.add(new SetCardInfo("Volrath's Shapeshifter", 48, Rarity.RARE, mage.cards.v.VolrathsShapeshifter.class)); + cards.add(new SetCardInfo("Volrath's Stronghold", 143, Rarity.RARE, mage.cards.v.VolrathsStronghold.class)); + cards.add(new SetCardInfo("Walking Dream", 49, Rarity.UNCOMMON, mage.cards.w.WalkingDream.class)); + cards.add(new SetCardInfo("Wall of Blossoms", 125, Rarity.UNCOMMON, mage.cards.w.WallOfBlossoms.class)); + cards.add(new SetCardInfo("Wall of Essence", 22, Rarity.UNCOMMON, mage.cards.w.WallOfEssence.class)); + cards.add(new SetCardInfo("Wall of Razors", 100, Rarity.UNCOMMON, mage.cards.w.WallOfRazors.class)); + cards.add(new SetCardInfo("Wall of Souls", 75, Rarity.UNCOMMON, mage.cards.w.WallOfSouls.class)); + cards.add(new SetCardInfo("Wall of Tears", 50, Rarity.UNCOMMON, mage.cards.w.WallOfTears.class)); + cards.add(new SetCardInfo("Warrior Angel", 24, Rarity.RARE, mage.cards.w.WarriorAngel.class)); + cards.add(new SetCardInfo("Warrior en-Kor", 23, Rarity.UNCOMMON, mage.cards.w.WarriorEnKor.class)); + cards.add(new SetCardInfo("Youthful Knight", 25, Rarity.COMMON, mage.cards.y.YouthfulKnight.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Tempest.java b/Mage.Sets/src/mage/sets/Tempest.java index 5269f4c17c..e1ec411d32 100644 --- a/Mage.Sets/src/mage/sets/Tempest.java +++ b/Mage.Sets/src/mage/sets/Tempest.java @@ -1,368 +1,369 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -public final class Tempest extends ExpansionSet { - - private static final Tempest instance = new Tempest(); - - public static Tempest getInstance() { - return instance; - } - - private Tempest() { - super("Tempest", "TMP", ExpansionSet.buildDate(1997, 10, 1), SetType.EXPANSION); - this.blockName = "Tempest"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abandon Hope", 107, Rarity.UNCOMMON, mage.cards.a.AbandonHope.class)); - cards.add(new SetCardInfo("Advance Scout", 1, Rarity.COMMON, mage.cards.a.AdvanceScout.class)); - cards.add(new SetCardInfo("Aftershock", 160, Rarity.COMMON, mage.cards.a.Aftershock.class)); - cards.add(new SetCardInfo("Altar of Dementia", 276, Rarity.RARE, mage.cards.a.AltarOfDementia.class)); - cards.add(new SetCardInfo("Aluren", 213, Rarity.RARE, mage.cards.a.Aluren.class)); - cards.add(new SetCardInfo("Ancient Runes", 161, Rarity.UNCOMMON, mage.cards.a.AncientRunes.class)); - cards.add(new SetCardInfo("Ancient Tomb", 315, Rarity.UNCOMMON, mage.cards.a.AncientTomb.class)); - cards.add(new SetCardInfo("Angelic Protector", 2, Rarity.UNCOMMON, mage.cards.a.AngelicProtector.class)); - cards.add(new SetCardInfo("Anoint", 3, Rarity.COMMON, mage.cards.a.Anoint.class)); - cards.add(new SetCardInfo("Apes of Rath", 214, Rarity.UNCOMMON, mage.cards.a.ApesOfRath.class)); - cards.add(new SetCardInfo("Apocalypse", 162, Rarity.RARE, mage.cards.a.Apocalypse.class)); - cards.add(new SetCardInfo("Armor Sliver", 4, Rarity.UNCOMMON, mage.cards.a.ArmorSliver.class)); - cards.add(new SetCardInfo("Armored Pegasus", 5, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); - cards.add(new SetCardInfo("Auratog", 6, Rarity.RARE, mage.cards.a.Auratog.class)); - cards.add(new SetCardInfo("Avenging Angel", 7, Rarity.RARE, mage.cards.a.AvengingAngel.class)); - cards.add(new SetCardInfo("Barbed Sliver", 163, Rarity.UNCOMMON, mage.cards.b.BarbedSliver.class)); - cards.add(new SetCardInfo("Bayou Dragonfly", 215, Rarity.COMMON, mage.cards.b.BayouDragonfly.class)); - cards.add(new SetCardInfo("Bellowing Fiend", 108, Rarity.RARE, mage.cards.b.BellowingFiend.class)); - cards.add(new SetCardInfo("Benthic Behemoth", 54, Rarity.RARE, mage.cards.b.BenthicBehemoth.class)); - cards.add(new SetCardInfo("Blood Frenzy", 164, Rarity.COMMON, mage.cards.b.BloodFrenzy.class)); - cards.add(new SetCardInfo("Blood Pet", 109, Rarity.COMMON, mage.cards.b.BloodPet.class)); - cards.add(new SetCardInfo("Boil", 165, Rarity.UNCOMMON, mage.cards.b.Boil.class)); - cards.add(new SetCardInfo("Booby Trap", 277, Rarity.RARE, mage.cards.b.BoobyTrap.class)); - cards.add(new SetCardInfo("Bottle Gnomes", 278, Rarity.UNCOMMON, mage.cards.b.BottleGnomes.class)); - cards.add(new SetCardInfo("Bounty Hunter", 110, Rarity.RARE, mage.cards.b.BountyHunter.class)); - cards.add(new SetCardInfo("Broken Fall", 216, Rarity.COMMON, mage.cards.b.BrokenFall.class)); - cards.add(new SetCardInfo("Caldera Lake", 316, Rarity.RARE, mage.cards.c.CalderaLake.class)); - cards.add(new SetCardInfo("Canopy Spider", 217, Rarity.COMMON, mage.cards.c.CanopySpider.class)); - cards.add(new SetCardInfo("Canyon Drake", 166, Rarity.RARE, mage.cards.c.CanyonDrake.class)); - cards.add(new SetCardInfo("Canyon Wildcat", 167, Rarity.COMMON, mage.cards.c.CanyonWildcat.class)); - cards.add(new SetCardInfo("Capsize", 55, Rarity.COMMON, mage.cards.c.Capsize.class)); - cards.add(new SetCardInfo("Carrionette", 111, Rarity.RARE, mage.cards.c.Carrionette.class)); - cards.add(new SetCardInfo("Chaotic Goo", 168, Rarity.RARE, mage.cards.c.ChaoticGoo.class)); - cards.add(new SetCardInfo("Charging Rhino", 218, Rarity.UNCOMMON, mage.cards.c.ChargingRhino.class)); - cards.add(new SetCardInfo("Chill", 56, Rarity.UNCOMMON, mage.cards.c.Chill.class)); - cards.add(new SetCardInfo("Choke", 219, Rarity.UNCOMMON, mage.cards.c.Choke.class)); - cards.add(new SetCardInfo("Cinder Marsh", 317, Rarity.UNCOMMON, mage.cards.c.CinderMarsh.class)); - cards.add(new SetCardInfo("Circle of Protection: Black", 8, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); - cards.add(new SetCardInfo("Circle of Protection: Blue", 9, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); - cards.add(new SetCardInfo("Circle of Protection: Green", 10, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); - cards.add(new SetCardInfo("Circle of Protection: Red", 11, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); - cards.add(new SetCardInfo("Circle of Protection: Shadow", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionShadow.class)); - cards.add(new SetCardInfo("Circle of Protection: White", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); - cards.add(new SetCardInfo("Clergy en-Vec", 14, Rarity.COMMON, mage.cards.c.ClergyEnVec.class)); - cards.add(new SetCardInfo("Clot Sliver", 112, Rarity.COMMON, mage.cards.c.ClotSliver.class)); - cards.add(new SetCardInfo("Cloudchaser Eagle", 15, Rarity.COMMON, mage.cards.c.CloudchaserEagle.class)); - cards.add(new SetCardInfo("Coercion", 113, Rarity.COMMON, mage.cards.c.Coercion.class)); - cards.add(new SetCardInfo("Coffin Queen", 114, Rarity.RARE, mage.cards.c.CoffinQueen.class)); - cards.add(new SetCardInfo("Coiled Tinviper", 279, Rarity.COMMON, mage.cards.c.CoiledTinviper.class)); - cards.add(new SetCardInfo("Cold Storage", 280, Rarity.RARE, mage.cards.c.ColdStorage.class)); - cards.add(new SetCardInfo("Commander Greven il-Vec", 115, Rarity.RARE, mage.cards.c.CommanderGrevenIlVec.class)); - cards.add(new SetCardInfo("Corpse Dance", 116, Rarity.RARE, mage.cards.c.CorpseDance.class)); - cards.add(new SetCardInfo("Counterspell", 57, Rarity.COMMON, mage.cards.c.Counterspell.class)); - cards.add(new SetCardInfo("Crazed Armodon", 220, Rarity.RARE, mage.cards.c.CrazedArmodon.class)); - cards.add(new SetCardInfo("Crown of Flames", 169, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); - cards.add(new SetCardInfo("Cursed Scroll", 281, Rarity.RARE, mage.cards.c.CursedScroll.class)); - cards.add(new SetCardInfo("Dark Banishing", 117, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); - cards.add(new SetCardInfo("Dark Ritual", 118, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Darkling Stalker", 119, Rarity.COMMON, mage.cards.d.DarklingStalker.class)); - cards.add(new SetCardInfo("Dauthi Embrace", 120, Rarity.UNCOMMON, mage.cards.d.DauthiEmbrace.class)); - cards.add(new SetCardInfo("Dauthi Ghoul", 121, Rarity.UNCOMMON, mage.cards.d.DauthiGhoul.class)); - cards.add(new SetCardInfo("Dauthi Horror", 122, Rarity.COMMON, mage.cards.d.DauthiHorror.class)); - cards.add(new SetCardInfo("Dauthi Marauder", 123, Rarity.COMMON, mage.cards.d.DauthiMarauder.class)); - cards.add(new SetCardInfo("Dauthi Mercenary", 124, Rarity.UNCOMMON, mage.cards.d.DauthiMercenary.class)); - cards.add(new SetCardInfo("Dauthi Mindripper", 125, Rarity.UNCOMMON, mage.cards.d.DauthiMindripper.class)); - cards.add(new SetCardInfo("Dauthi Slayer", 126, Rarity.COMMON, mage.cards.d.DauthiSlayer.class)); - cards.add(new SetCardInfo("Deadshot", 170, Rarity.RARE, mage.cards.d.Deadshot.class)); - cards.add(new SetCardInfo("Death Pits of Rath", 127, Rarity.RARE, mage.cards.d.DeathPitsOfRath.class)); - cards.add(new SetCardInfo("Diabolic Edict", 128, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); - cards.add(new SetCardInfo("Dirtcowl Wurm", 221, Rarity.RARE, mage.cards.d.DirtcowlWurm.class)); - cards.add(new SetCardInfo("Disenchant", 16, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Dismiss", 58, Rarity.UNCOMMON, mage.cards.d.Dismiss.class)); - cards.add(new SetCardInfo("Disturbed Burial", 129, Rarity.COMMON, mage.cards.d.DisturbedBurial.class)); - cards.add(new SetCardInfo("Dracoplasm", 266, Rarity.RARE, mage.cards.d.Dracoplasm.class)); - cards.add(new SetCardInfo("Dread of Night", 130, Rarity.UNCOMMON, mage.cards.d.DreadOfNight.class)); - cards.add(new SetCardInfo("Dream Cache", 59, Rarity.COMMON, mage.cards.d.DreamCache.class)); - cards.add(new SetCardInfo("Dregs of Sorrow", 131, Rarity.RARE, mage.cards.d.DregsOfSorrow.class)); - cards.add(new SetCardInfo("Earthcraft", 222, Rarity.RARE, mage.cards.e.Earthcraft.class)); - cards.add(new SetCardInfo("Echo Chamber", 282, Rarity.RARE, mage.cards.e.EchoChamber.class)); - cards.add(new SetCardInfo("Eladamri's Vineyard", 223, Rarity.RARE, mage.cards.e.EladamrisVineyard.class)); - cards.add(new SetCardInfo("Eladamri, Lord of Leaves", 224, Rarity.RARE, mage.cards.e.EladamriLordOfLeaves.class)); - cards.add(new SetCardInfo("Elite Javelineer", 17, Rarity.COMMON, mage.cards.e.EliteJavelineer.class)); - cards.add(new SetCardInfo("Elven Warhounds", 225, Rarity.RARE, mage.cards.e.ElvenWarhounds.class)); - cards.add(new SetCardInfo("Elvish Fury", 226, Rarity.COMMON, mage.cards.e.ElvishFury.class)); - cards.add(new SetCardInfo("Emerald Medallion", 283, Rarity.RARE, mage.cards.e.EmeraldMedallion.class)); - cards.add(new SetCardInfo("Emmessi Tome", 284, Rarity.RARE, mage.cards.e.EmmessiTome.class)); - cards.add(new SetCardInfo("Endless Scream", 132, Rarity.COMMON, mage.cards.e.EndlessScream.class)); - cards.add(new SetCardInfo("Energizer", 285, Rarity.RARE, mage.cards.e.Energizer.class)); - cards.add(new SetCardInfo("Enfeeblement", 133, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); - cards.add(new SetCardInfo("Enraging Licid", 171, Rarity.UNCOMMON, mage.cards.e.EnragingLicid.class)); - cards.add(new SetCardInfo("Essence Bottle", 286, Rarity.UNCOMMON, mage.cards.e.EssenceBottle.class)); - cards.add(new SetCardInfo("Evincar's Justice", 134, Rarity.COMMON, mage.cards.e.EvincarsJustice.class)); - cards.add(new SetCardInfo("Excavator", 287, Rarity.UNCOMMON, mage.cards.e.Excavator.class)); - cards.add(new SetCardInfo("Extinction", 135, Rarity.RARE, mage.cards.e.Extinction.class)); - cards.add(new SetCardInfo("Fevered Convulsions", 136, Rarity.RARE, mage.cards.f.FeveredConvulsions.class)); - cards.add(new SetCardInfo("Field of Souls", 18, Rarity.RARE, mage.cards.f.FieldOfSouls.class)); - cards.add(new SetCardInfo("Fighting Drake", 63, Rarity.UNCOMMON, mage.cards.f.FightingDrake.class)); - cards.add(new SetCardInfo("Firefly", 172, Rarity.UNCOMMON, mage.cards.f.Firefly.class)); - cards.add(new SetCardInfo("Fireslinger", 173, Rarity.COMMON, mage.cards.f.Fireslinger.class)); - cards.add(new SetCardInfo("Flailing Drake", 227, Rarity.UNCOMMON, mage.cards.f.FlailingDrake.class)); - cards.add(new SetCardInfo("Flickering Ward", 19, Rarity.UNCOMMON, mage.cards.f.FlickeringWard.class)); - cards.add(new SetCardInfo("Flowstone Giant", 174, Rarity.COMMON, mage.cards.f.FlowstoneGiant.class)); - cards.add(new SetCardInfo("Flowstone Salamander", 175, Rarity.UNCOMMON, mage.cards.f.FlowstoneSalamander.class)); - cards.add(new SetCardInfo("Flowstone Sculpture", 288, Rarity.RARE, mage.cards.f.FlowstoneSculpture.class)); - cards.add(new SetCardInfo("Flowstone Wyvern", 176, Rarity.RARE, mage.cards.f.FlowstoneWyvern.class)); - cards.add(new SetCardInfo("Fool's Tome", 289, Rarity.RARE, mage.cards.f.FoolsTome.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Frog Tongue", 228, Rarity.COMMON, mage.cards.f.FrogTongue.class)); - cards.add(new SetCardInfo("Fugitive Druid", 229, Rarity.RARE, mage.cards.f.FugitiveDruid.class)); - cards.add(new SetCardInfo("Furnace of Rath", 177, Rarity.RARE, mage.cards.f.FurnaceOfRath.class)); - cards.add(new SetCardInfo("Fylamarid", 64, Rarity.UNCOMMON, mage.cards.f.Fylamarid.class)); - cards.add(new SetCardInfo("Gallantry", 20, Rarity.UNCOMMON, mage.cards.g.Gallantry.class)); - cards.add(new SetCardInfo("Gaseous Form", 65, Rarity.COMMON, mage.cards.g.GaseousForm.class)); - cards.add(new SetCardInfo("Gerrard's Battle Cry", 21, Rarity.RARE, mage.cards.g.GerrardsBattleCry.class)); - cards.add(new SetCardInfo("Ghost Town", 318, Rarity.UNCOMMON, mage.cards.g.GhostTown.class)); - cards.add(new SetCardInfo("Giant Crab", 66, Rarity.COMMON, mage.cards.g.GiantCrab.class)); - cards.add(new SetCardInfo("Giant Strength", 178, Rarity.COMMON, mage.cards.g.GiantStrength.class)); - cards.add(new SetCardInfo("Goblin Bombardment", 179, Rarity.UNCOMMON, mage.cards.g.GoblinBombardment.class)); - cards.add(new SetCardInfo("Gravedigger", 137, Rarity.COMMON, mage.cards.g.Gravedigger.class)); - cards.add(new SetCardInfo("Grindstone", 290, Rarity.RARE, mage.cards.g.Grindstone.class)); - cards.add(new SetCardInfo("Hand to Hand", 180, Rarity.RARE, mage.cards.h.HandToHand.class)); - cards.add(new SetCardInfo("Hanna's Custody", 22, Rarity.RARE, mage.cards.h.HannasCustody.class)); - cards.add(new SetCardInfo("Harrow", 230, Rarity.UNCOMMON, mage.cards.h.Harrow.class)); - cards.add(new SetCardInfo("Havoc", 181, Rarity.UNCOMMON, mage.cards.h.Havoc.class)); - cards.add(new SetCardInfo("Heart Sliver", 182, Rarity.COMMON, mage.cards.h.HeartSliver.class)); - cards.add(new SetCardInfo("Heartwood Dryad", 231, Rarity.COMMON, mage.cards.h.HeartwoodDryad.class)); - cards.add(new SetCardInfo("Heartwood Giant", 232, Rarity.RARE, mage.cards.h.HeartwoodGiant.class)); - cards.add(new SetCardInfo("Heartwood Treefolk", 233, Rarity.UNCOMMON, mage.cards.h.HeartwoodTreefolk.class)); - cards.add(new SetCardInfo("Helm of Possession", 291, Rarity.RARE, mage.cards.h.HelmOfPossession.class)); - cards.add(new SetCardInfo("Hero's Resolve", 23, Rarity.COMMON, mage.cards.h.HerosResolve.class)); - cards.add(new SetCardInfo("Horned Sliver", 234, Rarity.UNCOMMON, mage.cards.h.HornedSliver.class)); - cards.add(new SetCardInfo("Horned Turtle", 67, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); - cards.add(new SetCardInfo("Humility", 24, Rarity.RARE, mage.cards.h.Humility.class)); - cards.add(new SetCardInfo("Imps' Taunt", 138, Rarity.UNCOMMON, mage.cards.i.ImpsTaunt.class)); - cards.add(new SetCardInfo("Insight", 68, Rarity.UNCOMMON, mage.cards.i.Insight.class)); - cards.add(new SetCardInfo("Interdict", 69, Rarity.UNCOMMON, mage.cards.i.Interdict.class)); - cards.add(new SetCardInfo("Intuition", 70, Rarity.RARE, mage.cards.i.Intuition.class)); - cards.add(new SetCardInfo("Invulnerability", 25, Rarity.UNCOMMON, mage.cards.i.Invulnerability.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jackal Pup", 183, Rarity.UNCOMMON, mage.cards.j.JackalPup.class)); - cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class)); - cards.add(new SetCardInfo("Jinxed Idol", 293, Rarity.RARE, mage.cards.j.JinxedIdol.class)); - cards.add(new SetCardInfo("Kezzerdrix", 139, Rarity.RARE, mage.cards.k.Kezzerdrix.class)); - cards.add(new SetCardInfo("Kindle", 184, Rarity.COMMON, mage.cards.k.Kindle.class)); - cards.add(new SetCardInfo("Knight of Dawn", 26, Rarity.UNCOMMON, mage.cards.k.KnightOfDawn.class)); - cards.add(new SetCardInfo("Knight of Dusk", 140, Rarity.UNCOMMON, mage.cards.k.KnightOfDusk.class)); - cards.add(new SetCardInfo("Krakilin", 235, Rarity.UNCOMMON, mage.cards.k.Krakilin.class)); - cards.add(new SetCardInfo("Leeching Licid", 141, Rarity.UNCOMMON, mage.cards.l.LeechingLicid.class)); - cards.add(new SetCardInfo("Legacy's Allure", 71, Rarity.UNCOMMON, mage.cards.l.LegacysAllure.class)); - cards.add(new SetCardInfo("Legerdemain", 72, Rarity.UNCOMMON, mage.cards.l.Legerdemain.class)); - cards.add(new SetCardInfo("Light of Day", 27, Rarity.UNCOMMON, mage.cards.l.LightOfDay.class)); - cards.add(new SetCardInfo("Lightning Blast", 185, Rarity.COMMON, mage.cards.l.LightningBlast.class)); - cards.add(new SetCardInfo("Lightning Elemental", 186, Rarity.COMMON, mage.cards.l.LightningElemental.class)); - cards.add(new SetCardInfo("Living Death", 142, Rarity.RARE, mage.cards.l.LivingDeath.class)); - cards.add(new SetCardInfo("Lobotomy", 267, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); - cards.add(new SetCardInfo("Lotus Petal", 294, Rarity.COMMON, mage.cards.l.LotusPetal.class)); - cards.add(new SetCardInfo("Lowland Giant", 187, Rarity.COMMON, mage.cards.l.LowlandGiant.class)); - cards.add(new SetCardInfo("Maddening Imp", 143, Rarity.RARE, mage.cards.m.MaddeningImp.class)); - cards.add(new SetCardInfo("Magmasaur", 188, Rarity.RARE, mage.cards.m.Magmasaur.class)); - cards.add(new SetCardInfo("Mana Severance", 73, Rarity.RARE, mage.cards.m.ManaSeverance.class)); - cards.add(new SetCardInfo("Manakin", 296, Rarity.COMMON, mage.cards.m.Manakin.class)); - cards.add(new SetCardInfo("Manta Riders", 74, Rarity.COMMON, mage.cards.m.MantaRiders.class)); - cards.add(new SetCardInfo("Marble Titan", 28, Rarity.RARE, mage.cards.m.MarbleTitan.class)); - cards.add(new SetCardInfo("Marsh Lurker", 144, Rarity.COMMON, mage.cards.m.MarshLurker.class)); - cards.add(new SetCardInfo("Master Decoy", 29, Rarity.COMMON, mage.cards.m.MasterDecoy.class)); - cards.add(new SetCardInfo("Mawcor", 75, Rarity.RARE, mage.cards.m.Mawcor.class)); - cards.add(new SetCardInfo("Maze of Shadows", 319, Rarity.UNCOMMON, mage.cards.m.MazeOfShadows.class)); - cards.add(new SetCardInfo("Meditate", 76, Rarity.RARE, mage.cards.m.Meditate.class)); - cards.add(new SetCardInfo("Metallic Sliver", 297, Rarity.COMMON, mage.cards.m.MetallicSliver.class)); - cards.add(new SetCardInfo("Mindwhip Sliver", 145, Rarity.UNCOMMON, mage.cards.m.MindwhipSliver.class)); - cards.add(new SetCardInfo("Minion of the Wastes", 146, Rarity.RARE, mage.cards.m.MinionOfTheWastes.class)); - cards.add(new SetCardInfo("Mirri's Guile", 236, Rarity.RARE, mage.cards.m.MirrisGuile.class)); - cards.add(new SetCardInfo("Mnemonic Sliver", 77, Rarity.UNCOMMON, mage.cards.m.MnemonicSliver.class)); - cards.add(new SetCardInfo("Mogg Cannon", 298, Rarity.UNCOMMON, mage.cards.m.MoggCannon.class)); - cards.add(new SetCardInfo("Mogg Conscripts", 189, Rarity.COMMON, mage.cards.m.MoggConscripts.class)); - cards.add(new SetCardInfo("Mogg Fanatic", 190, Rarity.COMMON, mage.cards.m.MoggFanatic.class)); - cards.add(new SetCardInfo("Mogg Hollows", 320, Rarity.UNCOMMON, mage.cards.m.MoggHollows.class)); - cards.add(new SetCardInfo("Mogg Raider", 191, Rarity.COMMON, mage.cards.m.MoggRaider.class)); - cards.add(new SetCardInfo("Mogg Squad", 192, Rarity.UNCOMMON, mage.cards.m.MoggSquad.class)); - cards.add(new SetCardInfo("Mongrel Pack", 237, Rarity.RARE, mage.cards.m.MongrelPack.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mounted Archers", 30, Rarity.COMMON, mage.cards.m.MountedArchers.class)); - cards.add(new SetCardInfo("Muscle Sliver", 238, Rarity.COMMON, mage.cards.m.MuscleSliver.class)); - cards.add(new SetCardInfo("Natural Spring", 239, Rarity.COMMON, mage.cards.n.NaturalSpring.class)); - cards.add(new SetCardInfo("Nature's Revolt", 240, Rarity.RARE, mage.cards.n.NaturesRevolt.class)); - cards.add(new SetCardInfo("Needle Storm", 241, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); - cards.add(new SetCardInfo("Nurturing Licid", 242, Rarity.UNCOMMON, mage.cards.n.NurturingLicid.class)); - cards.add(new SetCardInfo("Opportunist", 194, Rarity.UNCOMMON, mage.cards.o.Opportunist.class)); - cards.add(new SetCardInfo("Oracle en-Vec", 31, Rarity.RARE, mage.cards.o.OracleEnVec.class)); - cards.add(new SetCardInfo("Orim's Prayer", 32, Rarity.UNCOMMON, mage.cards.o.OrimsPrayer.class)); - cards.add(new SetCardInfo("Orim, Samite Healer", 33, Rarity.RARE, mage.cards.o.OrimSamiteHealer.class)); - cards.add(new SetCardInfo("Overrun", 243, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); - cards.add(new SetCardInfo("Pacifism", 34, Rarity.COMMON, mage.cards.p.Pacifism.class)); - cards.add(new SetCardInfo("Pallimud", 195, Rarity.RARE, mage.cards.p.Pallimud.class)); - cards.add(new SetCardInfo("Patchwork Gnomes", 299, Rarity.UNCOMMON, mage.cards.p.PatchworkGnomes.class)); - cards.add(new SetCardInfo("Pearl Medallion", 300, Rarity.RARE, mage.cards.p.PearlMedallion.class)); - cards.add(new SetCardInfo("Pegasus Refuge", 35, Rarity.RARE, mage.cards.p.PegasusRefuge.class)); - cards.add(new SetCardInfo("Perish", 147, Rarity.UNCOMMON, mage.cards.p.Perish.class)); - cards.add(new SetCardInfo("Phyrexian Grimoire", 301, Rarity.RARE, mage.cards.p.PhyrexianGrimoire.class)); - cards.add(new SetCardInfo("Phyrexian Hulk", 302, Rarity.UNCOMMON, mage.cards.p.PhyrexianHulk.class)); - cards.add(new SetCardInfo("Pincher Beetles", 244, Rarity.COMMON, mage.cards.p.PincherBeetles.class)); - cards.add(new SetCardInfo("Pine Barrens", 321, Rarity.RARE, mage.cards.p.PineBarrens.class)); - cards.add(new SetCardInfo("Pit Imp", 148, Rarity.COMMON, mage.cards.p.PitImp.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Power Sink", 78, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Precognition", 79, Rarity.RARE, mage.cards.p.Precognition.class)); - cards.add(new SetCardInfo("Propaganda", 80, Rarity.UNCOMMON, mage.cards.p.Propaganda.class)); - cards.add(new SetCardInfo("Puppet Strings", 304, Rarity.UNCOMMON, mage.cards.p.PuppetStrings.class)); - cards.add(new SetCardInfo("Quickening Licid", 36, Rarity.UNCOMMON, mage.cards.q.QuickeningLicid.class)); - cards.add(new SetCardInfo("Rain of Tears", 149, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); - cards.add(new SetCardInfo("Rampant Growth", 245, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); - cards.add(new SetCardInfo("Ranger en-Vec", 268, Rarity.UNCOMMON, mage.cards.r.RangerEnVec.class)); - cards.add(new SetCardInfo("Rathi Dragon", 196, Rarity.RARE, mage.cards.r.RathiDragon.class)); - cards.add(new SetCardInfo("Rats of Rath", 150, Rarity.COMMON, mage.cards.r.RatsOfRath.class)); - cards.add(new SetCardInfo("Reality Anchor", 246, Rarity.COMMON, mage.cards.r.RealityAnchor.class)); - cards.add(new SetCardInfo("Reanimate", 151, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); - cards.add(new SetCardInfo("Reap", 247, Rarity.UNCOMMON, mage.cards.r.Reap.class)); - cards.add(new SetCardInfo("Reckless Spite", 152, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); - cards.add(new SetCardInfo("Recycle", 248, Rarity.RARE, mage.cards.r.Recycle.class)); - cards.add(new SetCardInfo("Reflecting Pool", 322, Rarity.RARE, mage.cards.r.ReflectingPool.class)); - cards.add(new SetCardInfo("Renegade Warlord", 197, Rarity.UNCOMMON, mage.cards.r.RenegadeWarlord.class)); - cards.add(new SetCardInfo("Repentance", 37, Rarity.UNCOMMON, mage.cards.r.Repentance.class)); - cards.add(new SetCardInfo("Respite", 249, Rarity.COMMON, mage.cards.r.Respite.class)); - cards.add(new SetCardInfo("Rolling Thunder", 198, Rarity.COMMON, mage.cards.r.RollingThunder.class)); - cards.add(new SetCardInfo("Root Maze", 250, Rarity.RARE, mage.cards.r.RootMaze.class)); - cards.add(new SetCardInfo("Rootbreaker Wurm", 251, Rarity.COMMON, mage.cards.r.RootbreakerWurm.class)); - cards.add(new SetCardInfo("Rootwalla", 252, Rarity.COMMON, mage.cards.r.Rootwalla.class)); - cards.add(new SetCardInfo("Rootwater Depths", 323, Rarity.UNCOMMON, mage.cards.r.RootwaterDepths.class)); - cards.add(new SetCardInfo("Rootwater Diver", 81, Rarity.UNCOMMON, mage.cards.r.RootwaterDiver.class)); - cards.add(new SetCardInfo("Rootwater Hunter", 82, Rarity.COMMON, mage.cards.r.RootwaterHunter.class)); - cards.add(new SetCardInfo("Rootwater Matriarch", 83, Rarity.RARE, mage.cards.r.RootwaterMatriarch.class)); - cards.add(new SetCardInfo("Rootwater Shaman", 84, Rarity.RARE, mage.cards.r.RootwaterShaman.class)); - cards.add(new SetCardInfo("Ruby Medallion", 305, Rarity.RARE, mage.cards.r.RubyMedallion.class)); - cards.add(new SetCardInfo("Sacred Guide", 38, Rarity.RARE, mage.cards.s.SacredGuide.class)); - cards.add(new SetCardInfo("Sadistic Glee", 153, Rarity.COMMON, mage.cards.s.SadisticGlee.class)); - cards.add(new SetCardInfo("Safeguard", 39, Rarity.RARE, mage.cards.s.Safeguard.class)); - cards.add(new SetCardInfo("Salt Flats", 324, Rarity.RARE, mage.cards.s.SaltFlats.class)); - cards.add(new SetCardInfo("Sandstone Warrior", 199, Rarity.COMMON, mage.cards.s.SandstoneWarrior.class)); - cards.add(new SetCardInfo("Sapphire Medallion", 306, Rarity.RARE, mage.cards.s.SapphireMedallion.class)); - cards.add(new SetCardInfo("Sarcomancy", 154, Rarity.RARE, mage.cards.s.Sarcomancy.class)); - cards.add(new SetCardInfo("Scabland", 325, Rarity.RARE, mage.cards.s.Scabland.class)); - cards.add(new SetCardInfo("Scalding Tongs", 307, Rarity.RARE, mage.cards.s.ScaldingTongs.class)); - cards.add(new SetCardInfo("Scorched Earth", 200, Rarity.RARE, mage.cards.s.ScorchedEarth.class)); - cards.add(new SetCardInfo("Scragnoth", 253, Rarity.UNCOMMON, mage.cards.s.Scragnoth.class)); - cards.add(new SetCardInfo("Screeching Harpy", 155, Rarity.UNCOMMON, mage.cards.s.ScreechingHarpy.class)); - cards.add(new SetCardInfo("Scroll Rack", 308, Rarity.RARE, mage.cards.s.ScrollRack.class)); - cards.add(new SetCardInfo("Sea Monster", 85, Rarity.COMMON, mage.cards.s.SeaMonster.class)); - cards.add(new SetCardInfo("Searing Touch", 201, Rarity.UNCOMMON, mage.cards.s.SearingTouch.class)); - cards.add(new SetCardInfo("Seeker of Skybreak", 254, Rarity.COMMON, mage.cards.s.SeekerOfSkybreak.class)); - cards.add(new SetCardInfo("Segmented Wurm", 269, Rarity.UNCOMMON, mage.cards.s.SegmentedWurm.class)); - cards.add(new SetCardInfo("Selenia, Dark Angel", 270, Rarity.RARE, mage.cards.s.SeleniaDarkAngel.class)); - cards.add(new SetCardInfo("Serene Offering", 40, Rarity.UNCOMMON, mage.cards.s.SereneOffering.class)); - cards.add(new SetCardInfo("Servant of Volrath", 156, Rarity.COMMON, mage.cards.s.ServantOfVolrath.class)); - cards.add(new SetCardInfo("Shadow Rift", 86, Rarity.COMMON, mage.cards.s.ShadowRift.class)); - cards.add(new SetCardInfo("Shadowstorm", 202, Rarity.UNCOMMON, mage.cards.s.Shadowstorm.class)); - cards.add(new SetCardInfo("Shatter", 203, Rarity.COMMON, mage.cards.s.Shatter.class)); - cards.add(new SetCardInfo("Shimmering Wings", 87, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); - cards.add(new SetCardInfo("Shocker", 204, Rarity.RARE, mage.cards.s.Shocker.class)); - cards.add(new SetCardInfo("Sky Spirit", 271, Rarity.UNCOMMON, mage.cards.s.SkySpirit.class)); - cards.add(new SetCardInfo("Skyshroud Condor", 88, Rarity.UNCOMMON, mage.cards.s.SkyshroudCondor.class)); - cards.add(new SetCardInfo("Skyshroud Elf", 255, Rarity.COMMON, mage.cards.s.SkyshroudElf.class)); - cards.add(new SetCardInfo("Skyshroud Forest", 326, Rarity.RARE, mage.cards.s.SkyshroudForest.class)); - cards.add(new SetCardInfo("Skyshroud Ranger", 256, Rarity.COMMON, mage.cards.s.SkyshroudRanger.class)); - cards.add(new SetCardInfo("Skyshroud Troll", 257, Rarity.COMMON, mage.cards.s.SkyshroudTroll.class)); - cards.add(new SetCardInfo("Skyshroud Vampire", 157, Rarity.UNCOMMON, mage.cards.s.SkyshroudVampire.class)); - cards.add(new SetCardInfo("Soltari Crusader", 41, Rarity.UNCOMMON, mage.cards.s.SoltariCrusader.class)); - cards.add(new SetCardInfo("Soltari Emissary", 42, Rarity.RARE, mage.cards.s.SoltariEmissary.class)); - cards.add(new SetCardInfo("Soltari Foot Soldier", 43, Rarity.COMMON, mage.cards.s.SoltariFootSoldier.class)); - cards.add(new SetCardInfo("Soltari Guerrillas", 272, Rarity.RARE, mage.cards.s.SoltariGuerrillas.class)); - cards.add(new SetCardInfo("Soltari Lancer", 44, Rarity.COMMON, mage.cards.s.SoltariLancer.class)); - cards.add(new SetCardInfo("Soltari Monk", 45, Rarity.UNCOMMON, mage.cards.s.SoltariMonk.class)); - cards.add(new SetCardInfo("Soltari Priest", 46, Rarity.UNCOMMON, mage.cards.s.SoltariPriest.class)); - cards.add(new SetCardInfo("Soltari Trooper", 47, Rarity.COMMON, mage.cards.s.SoltariTrooper.class)); - cards.add(new SetCardInfo("Souldrinker", 158, Rarity.UNCOMMON, mage.cards.s.Souldrinker.class)); - cards.add(new SetCardInfo("Spell Blast", 89, Rarity.COMMON, mage.cards.s.SpellBlast.class)); - cards.add(new SetCardInfo("Spike Drone", 258, Rarity.COMMON, mage.cards.s.SpikeDrone.class)); - cards.add(new SetCardInfo("Spinal Graft", 159, Rarity.COMMON, mage.cards.s.SpinalGraft.class)); - cards.add(new SetCardInfo("Spirit Mirror", 48, Rarity.RARE, mage.cards.s.SpiritMirror.class)); - cards.add(new SetCardInfo("Spontaneous Combustion", 273, Rarity.UNCOMMON, mage.cards.s.SpontaneousCombustion.class)); - cards.add(new SetCardInfo("Squee's Toy", 309, Rarity.COMMON, mage.cards.s.SqueesToy.class)); - cards.add(new SetCardInfo("Stalking Stones", 327, Rarity.UNCOMMON, mage.cards.s.StalkingStones.class)); - cards.add(new SetCardInfo("Starke of Rath", 205, Rarity.RARE, mage.cards.s.StarkeOfRath.class)); - cards.add(new SetCardInfo("Static Orb", 310, Rarity.RARE, mage.cards.s.StaticOrb.class)); - cards.add(new SetCardInfo("Staunch Defenders", 49, Rarity.UNCOMMON, mage.cards.s.StaunchDefenders.class)); - cards.add(new SetCardInfo("Steal Enchantment", 90, Rarity.UNCOMMON, mage.cards.s.StealEnchantment.class)); - cards.add(new SetCardInfo("Stinging Licid", 91, Rarity.UNCOMMON, mage.cards.s.StingingLicid.class)); - cards.add(new SetCardInfo("Stone Rain", 206, Rarity.COMMON, mage.cards.s.StoneRain.class)); - cards.add(new SetCardInfo("Storm Front", 259, Rarity.UNCOMMON, mage.cards.s.StormFront.class)); - cards.add(new SetCardInfo("Stun", 207, Rarity.COMMON, mage.cards.s.Stun.class)); - cards.add(new SetCardInfo("Sudden Impact", 208, Rarity.UNCOMMON, mage.cards.s.SuddenImpact.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Tahngarth's Rage", 209, Rarity.UNCOMMON, mage.cards.t.TahngarthsRage.class)); - cards.add(new SetCardInfo("Talon Sliver", 50, Rarity.COMMON, mage.cards.t.TalonSliver.class)); - cards.add(new SetCardInfo("Telethopter", 311, Rarity.UNCOMMON, mage.cards.t.Telethopter.class)); - cards.add(new SetCardInfo("Thalakos Dreamsower", 92, Rarity.UNCOMMON, mage.cards.t.ThalakosDreamsower.class)); - cards.add(new SetCardInfo("Thalakos Lowlands", 328, Rarity.UNCOMMON, mage.cards.t.ThalakosLowlands.class)); - cards.add(new SetCardInfo("Thalakos Mistfolk", 93, Rarity.COMMON, mage.cards.t.ThalakosMistfolk.class)); - cards.add(new SetCardInfo("Thalakos Seer", 94, Rarity.COMMON, mage.cards.t.ThalakosSeer.class)); - cards.add(new SetCardInfo("Thalakos Sentry", 95, Rarity.COMMON, mage.cards.t.ThalakosSentry.class)); - cards.add(new SetCardInfo("Thumbscrews", 312, Rarity.RARE, mage.cards.t.Thumbscrews.class)); - cards.add(new SetCardInfo("Time Ebb", 96, Rarity.COMMON, mage.cards.t.TimeEbb.class)); - cards.add(new SetCardInfo("Time Warp", 97, Rarity.RARE, mage.cards.t.TimeWarp.class)); - cards.add(new SetCardInfo("Tooth and Claw", 210, Rarity.RARE, mage.cards.t.ToothAndClaw.class)); - cards.add(new SetCardInfo("Torture Chamber", 313, Rarity.RARE, mage.cards.t.TortureChamber.class)); - cards.add(new SetCardInfo("Tradewind Rider", 98, Rarity.RARE, mage.cards.t.TradewindRider.class)); - cards.add(new SetCardInfo("Trained Armodon", 260, Rarity.COMMON, mage.cards.t.TrainedArmodon.class)); - cards.add(new SetCardInfo("Tranquility", 261, Rarity.COMMON, mage.cards.t.Tranquility.class)); - cards.add(new SetCardInfo("Trumpeting Armodon", 262, Rarity.UNCOMMON, mage.cards.t.TrumpetingArmodon.class)); - cards.add(new SetCardInfo("Twitch", 99, Rarity.COMMON, mage.cards.t.Twitch.class)); - cards.add(new SetCardInfo("Unstable Shapeshifter", 100, Rarity.RARE, mage.cards.u.UnstableShapeshifter.class)); - cards.add(new SetCardInfo("Vec Townships", 329, Rarity.UNCOMMON, mage.cards.v.VecTownships.class)); - cards.add(new SetCardInfo("Verdant Force", 263, Rarity.RARE, mage.cards.v.VerdantForce.class)); - cards.add(new SetCardInfo("Verdigris", 264, Rarity.UNCOMMON, mage.cards.v.Verdigris.class)); - cards.add(new SetCardInfo("Vhati il-Dal", 274, Rarity.RARE, mage.cards.v.VhatiIlDal.class)); - cards.add(new SetCardInfo("Volrath's Curse", 101, Rarity.COMMON, mage.cards.v.VolrathsCurse.class)); - cards.add(new SetCardInfo("Wall of Diffusion", 211, Rarity.COMMON, mage.cards.w.WallOfDiffusion.class)); - cards.add(new SetCardInfo("Warmth", 51, Rarity.UNCOMMON, mage.cards.w.Warmth.class)); - cards.add(new SetCardInfo("Wasteland", 330, Rarity.UNCOMMON, mage.cards.w.Wasteland.class)); - cards.add(new SetCardInfo("Watchdog", 314, Rarity.UNCOMMON, mage.cards.w.Watchdog.class)); - cards.add(new SetCardInfo("Whispers of the Muse", 103, Rarity.UNCOMMON, mage.cards.w.WhispersOfTheMuse.class)); - cards.add(new SetCardInfo("Wild Wurm", 212, Rarity.UNCOMMON, mage.cards.w.WildWurm.class)); - cards.add(new SetCardInfo("Wind Dancer", 104, Rarity.UNCOMMON, mage.cards.w.WindDancer.class)); - cards.add(new SetCardInfo("Wind Drake", 105, Rarity.COMMON, mage.cards.w.WindDrake.class)); - cards.add(new SetCardInfo("Winds of Rath", 52, Rarity.RARE, mage.cards.w.WindsOfRath.class)); - cards.add(new SetCardInfo("Winged Sliver", 106, Rarity.COMMON, mage.cards.w.WingedSliver.class)); - cards.add(new SetCardInfo("Winter's Grasp", 265, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); - cards.add(new SetCardInfo("Wood Sage", 275, Rarity.RARE, mage.cards.w.WoodSage.class)); - cards.add(new SetCardInfo("Worthy Cause", 53, Rarity.UNCOMMON, mage.cards.w.WorthyCause.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class Tempest extends ExpansionSet { + + private static final Tempest instance = new Tempest(); + + public static Tempest getInstance() { + return instance; + } + + private Tempest() { + super("Tempest", "TMP", ExpansionSet.buildDate(1997, 10, 1), SetType.EXPANSION); + this.blockName = "Tempest"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abandon Hope", 107, Rarity.UNCOMMON, mage.cards.a.AbandonHope.class)); + cards.add(new SetCardInfo("Advance Scout", 1, Rarity.COMMON, mage.cards.a.AdvanceScout.class)); + cards.add(new SetCardInfo("Aftershock", 160, Rarity.COMMON, mage.cards.a.Aftershock.class)); + cards.add(new SetCardInfo("Altar of Dementia", 276, Rarity.RARE, mage.cards.a.AltarOfDementia.class)); + cards.add(new SetCardInfo("Aluren", 213, Rarity.RARE, mage.cards.a.Aluren.class)); + cards.add(new SetCardInfo("Ancient Runes", 161, Rarity.UNCOMMON, mage.cards.a.AncientRunes.class)); + cards.add(new SetCardInfo("Ancient Tomb", 315, Rarity.UNCOMMON, mage.cards.a.AncientTomb.class)); + cards.add(new SetCardInfo("Angelic Protector", 2, Rarity.UNCOMMON, mage.cards.a.AngelicProtector.class)); + cards.add(new SetCardInfo("Anoint", 3, Rarity.COMMON, mage.cards.a.Anoint.class)); + cards.add(new SetCardInfo("Apes of Rath", 214, Rarity.UNCOMMON, mage.cards.a.ApesOfRath.class)); + cards.add(new SetCardInfo("Apocalypse", 162, Rarity.RARE, mage.cards.a.Apocalypse.class)); + cards.add(new SetCardInfo("Armor Sliver", 4, Rarity.UNCOMMON, mage.cards.a.ArmorSliver.class)); + cards.add(new SetCardInfo("Armored Pegasus", 5, Rarity.COMMON, mage.cards.a.ArmoredPegasus.class)); + cards.add(new SetCardInfo("Auratog", 6, Rarity.RARE, mage.cards.a.Auratog.class)); + cards.add(new SetCardInfo("Avenging Angel", 7, Rarity.RARE, mage.cards.a.AvengingAngel.class)); + cards.add(new SetCardInfo("Barbed Sliver", 163, Rarity.UNCOMMON, mage.cards.b.BarbedSliver.class)); + cards.add(new SetCardInfo("Bayou Dragonfly", 215, Rarity.COMMON, mage.cards.b.BayouDragonfly.class)); + cards.add(new SetCardInfo("Bellowing Fiend", 108, Rarity.RARE, mage.cards.b.BellowingFiend.class)); + cards.add(new SetCardInfo("Benthic Behemoth", 54, Rarity.RARE, mage.cards.b.BenthicBehemoth.class)); + cards.add(new SetCardInfo("Blood Frenzy", 164, Rarity.COMMON, mage.cards.b.BloodFrenzy.class)); + cards.add(new SetCardInfo("Blood Pet", 109, Rarity.COMMON, mage.cards.b.BloodPet.class)); + cards.add(new SetCardInfo("Boil", 165, Rarity.UNCOMMON, mage.cards.b.Boil.class)); + cards.add(new SetCardInfo("Booby Trap", 277, Rarity.RARE, mage.cards.b.BoobyTrap.class)); + cards.add(new SetCardInfo("Bottle Gnomes", 278, Rarity.UNCOMMON, mage.cards.b.BottleGnomes.class)); + cards.add(new SetCardInfo("Bounty Hunter", 110, Rarity.RARE, mage.cards.b.BountyHunter.class)); + cards.add(new SetCardInfo("Broken Fall", 216, Rarity.COMMON, mage.cards.b.BrokenFall.class)); + cards.add(new SetCardInfo("Caldera Lake", 316, Rarity.RARE, mage.cards.c.CalderaLake.class)); + cards.add(new SetCardInfo("Canopy Spider", 217, Rarity.COMMON, mage.cards.c.CanopySpider.class)); + cards.add(new SetCardInfo("Canyon Drake", 166, Rarity.RARE, mage.cards.c.CanyonDrake.class)); + cards.add(new SetCardInfo("Canyon Wildcat", 167, Rarity.COMMON, mage.cards.c.CanyonWildcat.class)); + cards.add(new SetCardInfo("Capsize", 55, Rarity.COMMON, mage.cards.c.Capsize.class)); + cards.add(new SetCardInfo("Carrionette", 111, Rarity.RARE, mage.cards.c.Carrionette.class)); + cards.add(new SetCardInfo("Chaotic Goo", 168, Rarity.RARE, mage.cards.c.ChaoticGoo.class)); + cards.add(new SetCardInfo("Charging Rhino", 218, Rarity.UNCOMMON, mage.cards.c.ChargingRhino.class)); + cards.add(new SetCardInfo("Chill", 56, Rarity.UNCOMMON, mage.cards.c.Chill.class)); + cards.add(new SetCardInfo("Choke", 219, Rarity.UNCOMMON, mage.cards.c.Choke.class)); + cards.add(new SetCardInfo("Cinder Marsh", 317, Rarity.UNCOMMON, mage.cards.c.CinderMarsh.class)); + cards.add(new SetCardInfo("Circle of Protection: Black", 8, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlack.class)); + cards.add(new SetCardInfo("Circle of Protection: Blue", 9, Rarity.COMMON, mage.cards.c.CircleOfProtectionBlue.class)); + cards.add(new SetCardInfo("Circle of Protection: Green", 10, Rarity.COMMON, mage.cards.c.CircleOfProtectionGreen.class)); + cards.add(new SetCardInfo("Circle of Protection: Red", 11, Rarity.COMMON, mage.cards.c.CircleOfProtectionRed.class)); + cards.add(new SetCardInfo("Circle of Protection: Shadow", 12, Rarity.COMMON, mage.cards.c.CircleOfProtectionShadow.class)); + cards.add(new SetCardInfo("Circle of Protection: White", 13, Rarity.COMMON, mage.cards.c.CircleOfProtectionWhite.class)); + cards.add(new SetCardInfo("Clergy en-Vec", 14, Rarity.COMMON, mage.cards.c.ClergyEnVec.class)); + cards.add(new SetCardInfo("Clot Sliver", 112, Rarity.COMMON, mage.cards.c.ClotSliver.class)); + cards.add(new SetCardInfo("Cloudchaser Eagle", 15, Rarity.COMMON, mage.cards.c.CloudchaserEagle.class)); + cards.add(new SetCardInfo("Coercion", 113, Rarity.COMMON, mage.cards.c.Coercion.class)); + cards.add(new SetCardInfo("Coffin Queen", 114, Rarity.RARE, mage.cards.c.CoffinQueen.class)); + cards.add(new SetCardInfo("Coiled Tinviper", 279, Rarity.COMMON, mage.cards.c.CoiledTinviper.class)); + cards.add(new SetCardInfo("Cold Storage", 280, Rarity.RARE, mage.cards.c.ColdStorage.class)); + cards.add(new SetCardInfo("Commander Greven il-Vec", 115, Rarity.RARE, mage.cards.c.CommanderGrevenIlVec.class)); + cards.add(new SetCardInfo("Corpse Dance", 116, Rarity.RARE, mage.cards.c.CorpseDance.class)); + cards.add(new SetCardInfo("Counterspell", 57, Rarity.COMMON, mage.cards.c.Counterspell.class)); + cards.add(new SetCardInfo("Crazed Armodon", 220, Rarity.RARE, mage.cards.c.CrazedArmodon.class)); + cards.add(new SetCardInfo("Crown of Flames", 169, Rarity.COMMON, mage.cards.c.CrownOfFlames.class)); + cards.add(new SetCardInfo("Cursed Scroll", 281, Rarity.RARE, mage.cards.c.CursedScroll.class)); + cards.add(new SetCardInfo("Dark Banishing", 117, Rarity.COMMON, mage.cards.d.DarkBanishing.class)); + cards.add(new SetCardInfo("Dark Ritual", 118, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Darkling Stalker", 119, Rarity.COMMON, mage.cards.d.DarklingStalker.class)); + cards.add(new SetCardInfo("Dauthi Embrace", 120, Rarity.UNCOMMON, mage.cards.d.DauthiEmbrace.class)); + cards.add(new SetCardInfo("Dauthi Ghoul", 121, Rarity.UNCOMMON, mage.cards.d.DauthiGhoul.class)); + cards.add(new SetCardInfo("Dauthi Horror", 122, Rarity.COMMON, mage.cards.d.DauthiHorror.class)); + cards.add(new SetCardInfo("Dauthi Marauder", 123, Rarity.COMMON, mage.cards.d.DauthiMarauder.class)); + cards.add(new SetCardInfo("Dauthi Mercenary", 124, Rarity.UNCOMMON, mage.cards.d.DauthiMercenary.class)); + cards.add(new SetCardInfo("Dauthi Mindripper", 125, Rarity.UNCOMMON, mage.cards.d.DauthiMindripper.class)); + cards.add(new SetCardInfo("Dauthi Slayer", 126, Rarity.COMMON, mage.cards.d.DauthiSlayer.class)); + cards.add(new SetCardInfo("Deadshot", 170, Rarity.RARE, mage.cards.d.Deadshot.class)); + cards.add(new SetCardInfo("Death Pits of Rath", 127, Rarity.RARE, mage.cards.d.DeathPitsOfRath.class)); + cards.add(new SetCardInfo("Diabolic Edict", 128, Rarity.COMMON, mage.cards.d.DiabolicEdict.class)); + cards.add(new SetCardInfo("Dirtcowl Wurm", 221, Rarity.RARE, mage.cards.d.DirtcowlWurm.class)); + cards.add(new SetCardInfo("Disenchant", 16, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Dismiss", 58, Rarity.UNCOMMON, mage.cards.d.Dismiss.class)); + cards.add(new SetCardInfo("Disturbed Burial", 129, Rarity.COMMON, mage.cards.d.DisturbedBurial.class)); + cards.add(new SetCardInfo("Dracoplasm", 266, Rarity.RARE, mage.cards.d.Dracoplasm.class)); + cards.add(new SetCardInfo("Dread of Night", 130, Rarity.UNCOMMON, mage.cards.d.DreadOfNight.class)); + cards.add(new SetCardInfo("Dream Cache", 59, Rarity.COMMON, mage.cards.d.DreamCache.class)); + cards.add(new SetCardInfo("Dregs of Sorrow", 131, Rarity.RARE, mage.cards.d.DregsOfSorrow.class)); + cards.add(new SetCardInfo("Duplicity", 60, Rarity.RARE, mage.cards.d.Duplicity.class)); + cards.add(new SetCardInfo("Earthcraft", 222, Rarity.RARE, mage.cards.e.Earthcraft.class)); + cards.add(new SetCardInfo("Echo Chamber", 282, Rarity.RARE, mage.cards.e.EchoChamber.class)); + cards.add(new SetCardInfo("Eladamri's Vineyard", 223, Rarity.RARE, mage.cards.e.EladamrisVineyard.class)); + cards.add(new SetCardInfo("Eladamri, Lord of Leaves", 224, Rarity.RARE, mage.cards.e.EladamriLordOfLeaves.class)); + cards.add(new SetCardInfo("Elite Javelineer", 17, Rarity.COMMON, mage.cards.e.EliteJavelineer.class)); + cards.add(new SetCardInfo("Elven Warhounds", 225, Rarity.RARE, mage.cards.e.ElvenWarhounds.class)); + cards.add(new SetCardInfo("Elvish Fury", 226, Rarity.COMMON, mage.cards.e.ElvishFury.class)); + cards.add(new SetCardInfo("Emerald Medallion", 283, Rarity.RARE, mage.cards.e.EmeraldMedallion.class)); + cards.add(new SetCardInfo("Emmessi Tome", 284, Rarity.RARE, mage.cards.e.EmmessiTome.class)); + cards.add(new SetCardInfo("Endless Scream", 132, Rarity.COMMON, mage.cards.e.EndlessScream.class)); + cards.add(new SetCardInfo("Energizer", 285, Rarity.RARE, mage.cards.e.Energizer.class)); + cards.add(new SetCardInfo("Enfeeblement", 133, Rarity.COMMON, mage.cards.e.Enfeeblement.class)); + cards.add(new SetCardInfo("Enraging Licid", 171, Rarity.UNCOMMON, mage.cards.e.EnragingLicid.class)); + cards.add(new SetCardInfo("Essence Bottle", 286, Rarity.UNCOMMON, mage.cards.e.EssenceBottle.class)); + cards.add(new SetCardInfo("Evincar's Justice", 134, Rarity.COMMON, mage.cards.e.EvincarsJustice.class)); + cards.add(new SetCardInfo("Excavator", 287, Rarity.UNCOMMON, mage.cards.e.Excavator.class)); + cards.add(new SetCardInfo("Extinction", 135, Rarity.RARE, mage.cards.e.Extinction.class)); + cards.add(new SetCardInfo("Fevered Convulsions", 136, Rarity.RARE, mage.cards.f.FeveredConvulsions.class)); + cards.add(new SetCardInfo("Field of Souls", 18, Rarity.RARE, mage.cards.f.FieldOfSouls.class)); + cards.add(new SetCardInfo("Fighting Drake", 63, Rarity.UNCOMMON, mage.cards.f.FightingDrake.class)); + cards.add(new SetCardInfo("Firefly", 172, Rarity.UNCOMMON, mage.cards.f.Firefly.class)); + cards.add(new SetCardInfo("Fireslinger", 173, Rarity.COMMON, mage.cards.f.Fireslinger.class)); + cards.add(new SetCardInfo("Flailing Drake", 227, Rarity.UNCOMMON, mage.cards.f.FlailingDrake.class)); + cards.add(new SetCardInfo("Flickering Ward", 19, Rarity.UNCOMMON, mage.cards.f.FlickeringWard.class)); + cards.add(new SetCardInfo("Flowstone Giant", 174, Rarity.COMMON, mage.cards.f.FlowstoneGiant.class)); + cards.add(new SetCardInfo("Flowstone Salamander", 175, Rarity.UNCOMMON, mage.cards.f.FlowstoneSalamander.class)); + cards.add(new SetCardInfo("Flowstone Sculpture", 288, Rarity.RARE, mage.cards.f.FlowstoneSculpture.class)); + cards.add(new SetCardInfo("Flowstone Wyvern", 176, Rarity.RARE, mage.cards.f.FlowstoneWyvern.class)); + cards.add(new SetCardInfo("Fool's Tome", 289, Rarity.RARE, mage.cards.f.FoolsTome.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Frog Tongue", 228, Rarity.COMMON, mage.cards.f.FrogTongue.class)); + cards.add(new SetCardInfo("Fugitive Druid", 229, Rarity.RARE, mage.cards.f.FugitiveDruid.class)); + cards.add(new SetCardInfo("Furnace of Rath", 177, Rarity.RARE, mage.cards.f.FurnaceOfRath.class)); + cards.add(new SetCardInfo("Fylamarid", 64, Rarity.UNCOMMON, mage.cards.f.Fylamarid.class)); + cards.add(new SetCardInfo("Gallantry", 20, Rarity.UNCOMMON, mage.cards.g.Gallantry.class)); + cards.add(new SetCardInfo("Gaseous Form", 65, Rarity.COMMON, mage.cards.g.GaseousForm.class)); + cards.add(new SetCardInfo("Gerrard's Battle Cry", 21, Rarity.RARE, mage.cards.g.GerrardsBattleCry.class)); + cards.add(new SetCardInfo("Ghost Town", 318, Rarity.UNCOMMON, mage.cards.g.GhostTown.class)); + cards.add(new SetCardInfo("Giant Crab", 66, Rarity.COMMON, mage.cards.g.GiantCrab.class)); + cards.add(new SetCardInfo("Giant Strength", 178, Rarity.COMMON, mage.cards.g.GiantStrength.class)); + cards.add(new SetCardInfo("Goblin Bombardment", 179, Rarity.UNCOMMON, mage.cards.g.GoblinBombardment.class)); + cards.add(new SetCardInfo("Gravedigger", 137, Rarity.COMMON, mage.cards.g.Gravedigger.class)); + cards.add(new SetCardInfo("Grindstone", 290, Rarity.RARE, mage.cards.g.Grindstone.class)); + cards.add(new SetCardInfo("Hand to Hand", 180, Rarity.RARE, mage.cards.h.HandToHand.class)); + cards.add(new SetCardInfo("Hanna's Custody", 22, Rarity.RARE, mage.cards.h.HannasCustody.class)); + cards.add(new SetCardInfo("Harrow", 230, Rarity.UNCOMMON, mage.cards.h.Harrow.class)); + cards.add(new SetCardInfo("Havoc", 181, Rarity.UNCOMMON, mage.cards.h.Havoc.class)); + cards.add(new SetCardInfo("Heart Sliver", 182, Rarity.COMMON, mage.cards.h.HeartSliver.class)); + cards.add(new SetCardInfo("Heartwood Dryad", 231, Rarity.COMMON, mage.cards.h.HeartwoodDryad.class)); + cards.add(new SetCardInfo("Heartwood Giant", 232, Rarity.RARE, mage.cards.h.HeartwoodGiant.class)); + cards.add(new SetCardInfo("Heartwood Treefolk", 233, Rarity.UNCOMMON, mage.cards.h.HeartwoodTreefolk.class)); + cards.add(new SetCardInfo("Helm of Possession", 291, Rarity.RARE, mage.cards.h.HelmOfPossession.class)); + cards.add(new SetCardInfo("Hero's Resolve", 23, Rarity.COMMON, mage.cards.h.HerosResolve.class)); + cards.add(new SetCardInfo("Horned Sliver", 234, Rarity.UNCOMMON, mage.cards.h.HornedSliver.class)); + cards.add(new SetCardInfo("Horned Turtle", 67, Rarity.COMMON, mage.cards.h.HornedTurtle.class)); + cards.add(new SetCardInfo("Humility", 24, Rarity.RARE, mage.cards.h.Humility.class)); + cards.add(new SetCardInfo("Imps' Taunt", 138, Rarity.UNCOMMON, mage.cards.i.ImpsTaunt.class)); + cards.add(new SetCardInfo("Insight", 68, Rarity.UNCOMMON, mage.cards.i.Insight.class)); + cards.add(new SetCardInfo("Interdict", 69, Rarity.UNCOMMON, mage.cards.i.Interdict.class)); + cards.add(new SetCardInfo("Intuition", 70, Rarity.RARE, mage.cards.i.Intuition.class)); + cards.add(new SetCardInfo("Invulnerability", 25, Rarity.UNCOMMON, mage.cards.i.Invulnerability.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jackal Pup", 183, Rarity.UNCOMMON, mage.cards.j.JackalPup.class)); + cards.add(new SetCardInfo("Jet Medallion", 292, Rarity.RARE, mage.cards.j.JetMedallion.class)); + cards.add(new SetCardInfo("Jinxed Idol", 293, Rarity.RARE, mage.cards.j.JinxedIdol.class)); + cards.add(new SetCardInfo("Kezzerdrix", 139, Rarity.RARE, mage.cards.k.Kezzerdrix.class)); + cards.add(new SetCardInfo("Kindle", 184, Rarity.COMMON, mage.cards.k.Kindle.class)); + cards.add(new SetCardInfo("Knight of Dawn", 26, Rarity.UNCOMMON, mage.cards.k.KnightOfDawn.class)); + cards.add(new SetCardInfo("Knight of Dusk", 140, Rarity.UNCOMMON, mage.cards.k.KnightOfDusk.class)); + cards.add(new SetCardInfo("Krakilin", 235, Rarity.UNCOMMON, mage.cards.k.Krakilin.class)); + cards.add(new SetCardInfo("Leeching Licid", 141, Rarity.UNCOMMON, mage.cards.l.LeechingLicid.class)); + cards.add(new SetCardInfo("Legacy's Allure", 71, Rarity.UNCOMMON, mage.cards.l.LegacysAllure.class)); + cards.add(new SetCardInfo("Legerdemain", 72, Rarity.UNCOMMON, mage.cards.l.Legerdemain.class)); + cards.add(new SetCardInfo("Light of Day", 27, Rarity.UNCOMMON, mage.cards.l.LightOfDay.class)); + cards.add(new SetCardInfo("Lightning Blast", 185, Rarity.COMMON, mage.cards.l.LightningBlast.class)); + cards.add(new SetCardInfo("Lightning Elemental", 186, Rarity.COMMON, mage.cards.l.LightningElemental.class)); + cards.add(new SetCardInfo("Living Death", 142, Rarity.RARE, mage.cards.l.LivingDeath.class)); + cards.add(new SetCardInfo("Lobotomy", 267, Rarity.UNCOMMON, mage.cards.l.Lobotomy.class)); + cards.add(new SetCardInfo("Lotus Petal", 294, Rarity.COMMON, mage.cards.l.LotusPetal.class)); + cards.add(new SetCardInfo("Lowland Giant", 187, Rarity.COMMON, mage.cards.l.LowlandGiant.class)); + cards.add(new SetCardInfo("Maddening Imp", 143, Rarity.RARE, mage.cards.m.MaddeningImp.class)); + cards.add(new SetCardInfo("Magmasaur", 188, Rarity.RARE, mage.cards.m.Magmasaur.class)); + cards.add(new SetCardInfo("Mana Severance", 73, Rarity.RARE, mage.cards.m.ManaSeverance.class)); + cards.add(new SetCardInfo("Manakin", 296, Rarity.COMMON, mage.cards.m.Manakin.class)); + cards.add(new SetCardInfo("Manta Riders", 74, Rarity.COMMON, mage.cards.m.MantaRiders.class)); + cards.add(new SetCardInfo("Marble Titan", 28, Rarity.RARE, mage.cards.m.MarbleTitan.class)); + cards.add(new SetCardInfo("Marsh Lurker", 144, Rarity.COMMON, mage.cards.m.MarshLurker.class)); + cards.add(new SetCardInfo("Master Decoy", 29, Rarity.COMMON, mage.cards.m.MasterDecoy.class)); + cards.add(new SetCardInfo("Mawcor", 75, Rarity.RARE, mage.cards.m.Mawcor.class)); + cards.add(new SetCardInfo("Maze of Shadows", 319, Rarity.UNCOMMON, mage.cards.m.MazeOfShadows.class)); + cards.add(new SetCardInfo("Meditate", 76, Rarity.RARE, mage.cards.m.Meditate.class)); + cards.add(new SetCardInfo("Metallic Sliver", 297, Rarity.COMMON, mage.cards.m.MetallicSliver.class)); + cards.add(new SetCardInfo("Mindwhip Sliver", 145, Rarity.UNCOMMON, mage.cards.m.MindwhipSliver.class)); + cards.add(new SetCardInfo("Minion of the Wastes", 146, Rarity.RARE, mage.cards.m.MinionOfTheWastes.class)); + cards.add(new SetCardInfo("Mirri's Guile", 236, Rarity.RARE, mage.cards.m.MirrisGuile.class)); + cards.add(new SetCardInfo("Mnemonic Sliver", 77, Rarity.UNCOMMON, mage.cards.m.MnemonicSliver.class)); + cards.add(new SetCardInfo("Mogg Cannon", 298, Rarity.UNCOMMON, mage.cards.m.MoggCannon.class)); + cards.add(new SetCardInfo("Mogg Conscripts", 189, Rarity.COMMON, mage.cards.m.MoggConscripts.class)); + cards.add(new SetCardInfo("Mogg Fanatic", 190, Rarity.COMMON, mage.cards.m.MoggFanatic.class)); + cards.add(new SetCardInfo("Mogg Hollows", 320, Rarity.UNCOMMON, mage.cards.m.MoggHollows.class)); + cards.add(new SetCardInfo("Mogg Raider", 191, Rarity.COMMON, mage.cards.m.MoggRaider.class)); + cards.add(new SetCardInfo("Mogg Squad", 192, Rarity.UNCOMMON, mage.cards.m.MoggSquad.class)); + cards.add(new SetCardInfo("Mongrel Pack", 237, Rarity.RARE, mage.cards.m.MongrelPack.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mounted Archers", 30, Rarity.COMMON, mage.cards.m.MountedArchers.class)); + cards.add(new SetCardInfo("Muscle Sliver", 238, Rarity.COMMON, mage.cards.m.MuscleSliver.class)); + cards.add(new SetCardInfo("Natural Spring", 239, Rarity.COMMON, mage.cards.n.NaturalSpring.class)); + cards.add(new SetCardInfo("Nature's Revolt", 240, Rarity.RARE, mage.cards.n.NaturesRevolt.class)); + cards.add(new SetCardInfo("Needle Storm", 241, Rarity.UNCOMMON, mage.cards.n.NeedleStorm.class)); + cards.add(new SetCardInfo("Nurturing Licid", 242, Rarity.UNCOMMON, mage.cards.n.NurturingLicid.class)); + cards.add(new SetCardInfo("Opportunist", 194, Rarity.UNCOMMON, mage.cards.o.Opportunist.class)); + cards.add(new SetCardInfo("Oracle en-Vec", 31, Rarity.RARE, mage.cards.o.OracleEnVec.class)); + cards.add(new SetCardInfo("Orim's Prayer", 32, Rarity.UNCOMMON, mage.cards.o.OrimsPrayer.class)); + cards.add(new SetCardInfo("Orim, Samite Healer", 33, Rarity.RARE, mage.cards.o.OrimSamiteHealer.class)); + cards.add(new SetCardInfo("Overrun", 243, Rarity.UNCOMMON, mage.cards.o.Overrun.class)); + cards.add(new SetCardInfo("Pacifism", 34, Rarity.COMMON, mage.cards.p.Pacifism.class)); + cards.add(new SetCardInfo("Pallimud", 195, Rarity.RARE, mage.cards.p.Pallimud.class)); + cards.add(new SetCardInfo("Patchwork Gnomes", 299, Rarity.UNCOMMON, mage.cards.p.PatchworkGnomes.class)); + cards.add(new SetCardInfo("Pearl Medallion", 300, Rarity.RARE, mage.cards.p.PearlMedallion.class)); + cards.add(new SetCardInfo("Pegasus Refuge", 35, Rarity.RARE, mage.cards.p.PegasusRefuge.class)); + cards.add(new SetCardInfo("Perish", 147, Rarity.UNCOMMON, mage.cards.p.Perish.class)); + cards.add(new SetCardInfo("Phyrexian Grimoire", 301, Rarity.RARE, mage.cards.p.PhyrexianGrimoire.class)); + cards.add(new SetCardInfo("Phyrexian Hulk", 302, Rarity.UNCOMMON, mage.cards.p.PhyrexianHulk.class)); + cards.add(new SetCardInfo("Pincher Beetles", 244, Rarity.COMMON, mage.cards.p.PincherBeetles.class)); + cards.add(new SetCardInfo("Pine Barrens", 321, Rarity.RARE, mage.cards.p.PineBarrens.class)); + cards.add(new SetCardInfo("Pit Imp", 148, Rarity.COMMON, mage.cards.p.PitImp.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Power Sink", 78, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Precognition", 79, Rarity.RARE, mage.cards.p.Precognition.class)); + cards.add(new SetCardInfo("Propaganda", 80, Rarity.UNCOMMON, mage.cards.p.Propaganda.class)); + cards.add(new SetCardInfo("Puppet Strings", 304, Rarity.UNCOMMON, mage.cards.p.PuppetStrings.class)); + cards.add(new SetCardInfo("Quickening Licid", 36, Rarity.UNCOMMON, mage.cards.q.QuickeningLicid.class)); + cards.add(new SetCardInfo("Rain of Tears", 149, Rarity.UNCOMMON, mage.cards.r.RainOfTears.class)); + cards.add(new SetCardInfo("Rampant Growth", 245, Rarity.COMMON, mage.cards.r.RampantGrowth.class)); + cards.add(new SetCardInfo("Ranger en-Vec", 268, Rarity.UNCOMMON, mage.cards.r.RangerEnVec.class)); + cards.add(new SetCardInfo("Rathi Dragon", 196, Rarity.RARE, mage.cards.r.RathiDragon.class)); + cards.add(new SetCardInfo("Rats of Rath", 150, Rarity.COMMON, mage.cards.r.RatsOfRath.class)); + cards.add(new SetCardInfo("Reality Anchor", 246, Rarity.COMMON, mage.cards.r.RealityAnchor.class)); + cards.add(new SetCardInfo("Reanimate", 151, Rarity.UNCOMMON, mage.cards.r.Reanimate.class)); + cards.add(new SetCardInfo("Reap", 247, Rarity.UNCOMMON, mage.cards.r.Reap.class)); + cards.add(new SetCardInfo("Reckless Spite", 152, Rarity.UNCOMMON, mage.cards.r.RecklessSpite.class)); + cards.add(new SetCardInfo("Recycle", 248, Rarity.RARE, mage.cards.r.Recycle.class)); + cards.add(new SetCardInfo("Reflecting Pool", 322, Rarity.RARE, mage.cards.r.ReflectingPool.class)); + cards.add(new SetCardInfo("Renegade Warlord", 197, Rarity.UNCOMMON, mage.cards.r.RenegadeWarlord.class)); + cards.add(new SetCardInfo("Repentance", 37, Rarity.UNCOMMON, mage.cards.r.Repentance.class)); + cards.add(new SetCardInfo("Respite", 249, Rarity.COMMON, mage.cards.r.Respite.class)); + cards.add(new SetCardInfo("Rolling Thunder", 198, Rarity.COMMON, mage.cards.r.RollingThunder.class)); + cards.add(new SetCardInfo("Root Maze", 250, Rarity.RARE, mage.cards.r.RootMaze.class)); + cards.add(new SetCardInfo("Rootbreaker Wurm", 251, Rarity.COMMON, mage.cards.r.RootbreakerWurm.class)); + cards.add(new SetCardInfo("Rootwalla", 252, Rarity.COMMON, mage.cards.r.Rootwalla.class)); + cards.add(new SetCardInfo("Rootwater Depths", 323, Rarity.UNCOMMON, mage.cards.r.RootwaterDepths.class)); + cards.add(new SetCardInfo("Rootwater Diver", 81, Rarity.UNCOMMON, mage.cards.r.RootwaterDiver.class)); + cards.add(new SetCardInfo("Rootwater Hunter", 82, Rarity.COMMON, mage.cards.r.RootwaterHunter.class)); + cards.add(new SetCardInfo("Rootwater Matriarch", 83, Rarity.RARE, mage.cards.r.RootwaterMatriarch.class)); + cards.add(new SetCardInfo("Rootwater Shaman", 84, Rarity.RARE, mage.cards.r.RootwaterShaman.class)); + cards.add(new SetCardInfo("Ruby Medallion", 305, Rarity.RARE, mage.cards.r.RubyMedallion.class)); + cards.add(new SetCardInfo("Sacred Guide", 38, Rarity.RARE, mage.cards.s.SacredGuide.class)); + cards.add(new SetCardInfo("Sadistic Glee", 153, Rarity.COMMON, mage.cards.s.SadisticGlee.class)); + cards.add(new SetCardInfo("Safeguard", 39, Rarity.RARE, mage.cards.s.Safeguard.class)); + cards.add(new SetCardInfo("Salt Flats", 324, Rarity.RARE, mage.cards.s.SaltFlats.class)); + cards.add(new SetCardInfo("Sandstone Warrior", 199, Rarity.COMMON, mage.cards.s.SandstoneWarrior.class)); + cards.add(new SetCardInfo("Sapphire Medallion", 306, Rarity.RARE, mage.cards.s.SapphireMedallion.class)); + cards.add(new SetCardInfo("Sarcomancy", 154, Rarity.RARE, mage.cards.s.Sarcomancy.class)); + cards.add(new SetCardInfo("Scabland", 325, Rarity.RARE, mage.cards.s.Scabland.class)); + cards.add(new SetCardInfo("Scalding Tongs", 307, Rarity.RARE, mage.cards.s.ScaldingTongs.class)); + cards.add(new SetCardInfo("Scorched Earth", 200, Rarity.RARE, mage.cards.s.ScorchedEarth.class)); + cards.add(new SetCardInfo("Scragnoth", 253, Rarity.UNCOMMON, mage.cards.s.Scragnoth.class)); + cards.add(new SetCardInfo("Screeching Harpy", 155, Rarity.UNCOMMON, mage.cards.s.ScreechingHarpy.class)); + cards.add(new SetCardInfo("Scroll Rack", 308, Rarity.RARE, mage.cards.s.ScrollRack.class)); + cards.add(new SetCardInfo("Sea Monster", 85, Rarity.COMMON, mage.cards.s.SeaMonster.class)); + cards.add(new SetCardInfo("Searing Touch", 201, Rarity.UNCOMMON, mage.cards.s.SearingTouch.class)); + cards.add(new SetCardInfo("Seeker of Skybreak", 254, Rarity.COMMON, mage.cards.s.SeekerOfSkybreak.class)); + cards.add(new SetCardInfo("Segmented Wurm", 269, Rarity.UNCOMMON, mage.cards.s.SegmentedWurm.class)); + cards.add(new SetCardInfo("Selenia, Dark Angel", 270, Rarity.RARE, mage.cards.s.SeleniaDarkAngel.class)); + cards.add(new SetCardInfo("Serene Offering", 40, Rarity.UNCOMMON, mage.cards.s.SereneOffering.class)); + cards.add(new SetCardInfo("Servant of Volrath", 156, Rarity.COMMON, mage.cards.s.ServantOfVolrath.class)); + cards.add(new SetCardInfo("Shadow Rift", 86, Rarity.COMMON, mage.cards.s.ShadowRift.class)); + cards.add(new SetCardInfo("Shadowstorm", 202, Rarity.UNCOMMON, mage.cards.s.Shadowstorm.class)); + cards.add(new SetCardInfo("Shatter", 203, Rarity.COMMON, mage.cards.s.Shatter.class)); + cards.add(new SetCardInfo("Shimmering Wings", 87, Rarity.COMMON, mage.cards.s.ShimmeringWings.class)); + cards.add(new SetCardInfo("Shocker", 204, Rarity.RARE, mage.cards.s.Shocker.class)); + cards.add(new SetCardInfo("Sky Spirit", 271, Rarity.UNCOMMON, mage.cards.s.SkySpirit.class)); + cards.add(new SetCardInfo("Skyshroud Condor", 88, Rarity.UNCOMMON, mage.cards.s.SkyshroudCondor.class)); + cards.add(new SetCardInfo("Skyshroud Elf", 255, Rarity.COMMON, mage.cards.s.SkyshroudElf.class)); + cards.add(new SetCardInfo("Skyshroud Forest", 326, Rarity.RARE, mage.cards.s.SkyshroudForest.class)); + cards.add(new SetCardInfo("Skyshroud Ranger", 256, Rarity.COMMON, mage.cards.s.SkyshroudRanger.class)); + cards.add(new SetCardInfo("Skyshroud Troll", 257, Rarity.COMMON, mage.cards.s.SkyshroudTroll.class)); + cards.add(new SetCardInfo("Skyshroud Vampire", 157, Rarity.UNCOMMON, mage.cards.s.SkyshroudVampire.class)); + cards.add(new SetCardInfo("Soltari Crusader", 41, Rarity.UNCOMMON, mage.cards.s.SoltariCrusader.class)); + cards.add(new SetCardInfo("Soltari Emissary", 42, Rarity.RARE, mage.cards.s.SoltariEmissary.class)); + cards.add(new SetCardInfo("Soltari Foot Soldier", 43, Rarity.COMMON, mage.cards.s.SoltariFootSoldier.class)); + cards.add(new SetCardInfo("Soltari Guerrillas", 272, Rarity.RARE, mage.cards.s.SoltariGuerrillas.class)); + cards.add(new SetCardInfo("Soltari Lancer", 44, Rarity.COMMON, mage.cards.s.SoltariLancer.class)); + cards.add(new SetCardInfo("Soltari Monk", 45, Rarity.UNCOMMON, mage.cards.s.SoltariMonk.class)); + cards.add(new SetCardInfo("Soltari Priest", 46, Rarity.UNCOMMON, mage.cards.s.SoltariPriest.class)); + cards.add(new SetCardInfo("Soltari Trooper", 47, Rarity.COMMON, mage.cards.s.SoltariTrooper.class)); + cards.add(new SetCardInfo("Souldrinker", 158, Rarity.UNCOMMON, mage.cards.s.Souldrinker.class)); + cards.add(new SetCardInfo("Spell Blast", 89, Rarity.COMMON, mage.cards.s.SpellBlast.class)); + cards.add(new SetCardInfo("Spike Drone", 258, Rarity.COMMON, mage.cards.s.SpikeDrone.class)); + cards.add(new SetCardInfo("Spinal Graft", 159, Rarity.COMMON, mage.cards.s.SpinalGraft.class)); + cards.add(new SetCardInfo("Spirit Mirror", 48, Rarity.RARE, mage.cards.s.SpiritMirror.class)); + cards.add(new SetCardInfo("Spontaneous Combustion", 273, Rarity.UNCOMMON, mage.cards.s.SpontaneousCombustion.class)); + cards.add(new SetCardInfo("Squee's Toy", 309, Rarity.COMMON, mage.cards.s.SqueesToy.class)); + cards.add(new SetCardInfo("Stalking Stones", 327, Rarity.UNCOMMON, mage.cards.s.StalkingStones.class)); + cards.add(new SetCardInfo("Starke of Rath", 205, Rarity.RARE, mage.cards.s.StarkeOfRath.class)); + cards.add(new SetCardInfo("Static Orb", 310, Rarity.RARE, mage.cards.s.StaticOrb.class)); + cards.add(new SetCardInfo("Staunch Defenders", 49, Rarity.UNCOMMON, mage.cards.s.StaunchDefenders.class)); + cards.add(new SetCardInfo("Steal Enchantment", 90, Rarity.UNCOMMON, mage.cards.s.StealEnchantment.class)); + cards.add(new SetCardInfo("Stinging Licid", 91, Rarity.UNCOMMON, mage.cards.s.StingingLicid.class)); + cards.add(new SetCardInfo("Stone Rain", 206, Rarity.COMMON, mage.cards.s.StoneRain.class)); + cards.add(new SetCardInfo("Storm Front", 259, Rarity.UNCOMMON, mage.cards.s.StormFront.class)); + cards.add(new SetCardInfo("Stun", 207, Rarity.COMMON, mage.cards.s.Stun.class)); + cards.add(new SetCardInfo("Sudden Impact", 208, Rarity.UNCOMMON, mage.cards.s.SuddenImpact.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tahngarth's Rage", 209, Rarity.UNCOMMON, mage.cards.t.TahngarthsRage.class)); + cards.add(new SetCardInfo("Talon Sliver", 50, Rarity.COMMON, mage.cards.t.TalonSliver.class)); + cards.add(new SetCardInfo("Telethopter", 311, Rarity.UNCOMMON, mage.cards.t.Telethopter.class)); + cards.add(new SetCardInfo("Thalakos Dreamsower", 92, Rarity.UNCOMMON, mage.cards.t.ThalakosDreamsower.class)); + cards.add(new SetCardInfo("Thalakos Lowlands", 328, Rarity.UNCOMMON, mage.cards.t.ThalakosLowlands.class)); + cards.add(new SetCardInfo("Thalakos Mistfolk", 93, Rarity.COMMON, mage.cards.t.ThalakosMistfolk.class)); + cards.add(new SetCardInfo("Thalakos Seer", 94, Rarity.COMMON, mage.cards.t.ThalakosSeer.class)); + cards.add(new SetCardInfo("Thalakos Sentry", 95, Rarity.COMMON, mage.cards.t.ThalakosSentry.class)); + cards.add(new SetCardInfo("Thumbscrews", 312, Rarity.RARE, mage.cards.t.Thumbscrews.class)); + cards.add(new SetCardInfo("Time Ebb", 96, Rarity.COMMON, mage.cards.t.TimeEbb.class)); + cards.add(new SetCardInfo("Time Warp", 97, Rarity.RARE, mage.cards.t.TimeWarp.class)); + cards.add(new SetCardInfo("Tooth and Claw", 210, Rarity.RARE, mage.cards.t.ToothAndClaw.class)); + cards.add(new SetCardInfo("Torture Chamber", 313, Rarity.RARE, mage.cards.t.TortureChamber.class)); + cards.add(new SetCardInfo("Tradewind Rider", 98, Rarity.RARE, mage.cards.t.TradewindRider.class)); + cards.add(new SetCardInfo("Trained Armodon", 260, Rarity.COMMON, mage.cards.t.TrainedArmodon.class)); + cards.add(new SetCardInfo("Tranquility", 261, Rarity.COMMON, mage.cards.t.Tranquility.class)); + cards.add(new SetCardInfo("Trumpeting Armodon", 262, Rarity.UNCOMMON, mage.cards.t.TrumpetingArmodon.class)); + cards.add(new SetCardInfo("Twitch", 99, Rarity.COMMON, mage.cards.t.Twitch.class)); + cards.add(new SetCardInfo("Unstable Shapeshifter", 100, Rarity.RARE, mage.cards.u.UnstableShapeshifter.class)); + cards.add(new SetCardInfo("Vec Townships", 329, Rarity.UNCOMMON, mage.cards.v.VecTownships.class)); + cards.add(new SetCardInfo("Verdant Force", 263, Rarity.RARE, mage.cards.v.VerdantForce.class)); + cards.add(new SetCardInfo("Verdigris", 264, Rarity.UNCOMMON, mage.cards.v.Verdigris.class)); + cards.add(new SetCardInfo("Vhati il-Dal", 274, Rarity.RARE, mage.cards.v.VhatiIlDal.class)); + cards.add(new SetCardInfo("Volrath's Curse", 101, Rarity.COMMON, mage.cards.v.VolrathsCurse.class)); + cards.add(new SetCardInfo("Wall of Diffusion", 211, Rarity.COMMON, mage.cards.w.WallOfDiffusion.class)); + cards.add(new SetCardInfo("Warmth", 51, Rarity.UNCOMMON, mage.cards.w.Warmth.class)); + cards.add(new SetCardInfo("Wasteland", 330, Rarity.UNCOMMON, mage.cards.w.Wasteland.class)); + cards.add(new SetCardInfo("Watchdog", 314, Rarity.UNCOMMON, mage.cards.w.Watchdog.class)); + cards.add(new SetCardInfo("Whispers of the Muse", 103, Rarity.UNCOMMON, mage.cards.w.WhispersOfTheMuse.class)); + cards.add(new SetCardInfo("Wild Wurm", 212, Rarity.UNCOMMON, mage.cards.w.WildWurm.class)); + cards.add(new SetCardInfo("Wind Dancer", 104, Rarity.UNCOMMON, mage.cards.w.WindDancer.class)); + cards.add(new SetCardInfo("Wind Drake", 105, Rarity.COMMON, mage.cards.w.WindDrake.class)); + cards.add(new SetCardInfo("Winds of Rath", 52, Rarity.RARE, mage.cards.w.WindsOfRath.class)); + cards.add(new SetCardInfo("Winged Sliver", 106, Rarity.COMMON, mage.cards.w.WingedSliver.class)); + cards.add(new SetCardInfo("Winter's Grasp", 265, Rarity.UNCOMMON, mage.cards.w.WintersGrasp.class)); + cards.add(new SetCardInfo("Wood Sage", 275, Rarity.RARE, mage.cards.w.WoodSage.class)); + cards.add(new SetCardInfo("Worthy Cause", 53, Rarity.UNCOMMON, mage.cards.w.WorthyCause.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Torment.java b/Mage.Sets/src/mage/sets/Torment.java index 847347f882..71f87ed2f8 100644 --- a/Mage.Sets/src/mage/sets/Torment.java +++ b/Mage.Sets/src/mage/sets/Torment.java @@ -1,168 +1,169 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Torment extends ExpansionSet { - - private static final Torment instance = new Torment(); - - public static Torment getInstance() { - return instance; - } - - private Torment() { - super("Torment", "TOR", ExpansionSet.buildDate(2002, 1, 26), SetType.EXPANSION); - this.blockName = "Odyssey"; - this.parentSet = Odyssey.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Accelerate", 90, Rarity.COMMON, mage.cards.a.Accelerate.class)); - cards.add(new SetCardInfo("Acorn Harvest", 118, Rarity.COMMON, mage.cards.a.AcornHarvest.class)); - cards.add(new SetCardInfo("Ambassador Laquatus", 23, Rarity.RARE, mage.cards.a.AmbassadorLaquatus.class)); - cards.add(new SetCardInfo("Angel of Retribution", 1, Rarity.RARE, mage.cards.a.AngelOfRetribution.class)); - cards.add(new SetCardInfo("Anurid Scavenger", 119, Rarity.UNCOMMON, mage.cards.a.AnuridScavenger.class)); - cards.add(new SetCardInfo("Aquamoeba", 24, Rarity.COMMON, mage.cards.a.Aquamoeba.class)); - cards.add(new SetCardInfo("Arrogant Wurm", 120, Rarity.UNCOMMON, mage.cards.a.ArrogantWurm.class)); - cards.add(new SetCardInfo("Aven Trooper", 2, Rarity.COMMON, mage.cards.a.AvenTrooper.class)); - cards.add(new SetCardInfo("Balshan Collaborator", 25, Rarity.UNCOMMON, mage.cards.b.BalshanCollaborator.class)); - cards.add(new SetCardInfo("Balthor the Stout", 91, Rarity.RARE, mage.cards.b.BalthorTheStout.class)); - cards.add(new SetCardInfo("Barbarian Outcast", 92, Rarity.COMMON, mage.cards.b.BarbarianOutcast.class)); - cards.add(new SetCardInfo("Basking Rootwalla", 121, Rarity.COMMON, mage.cards.b.BaskingRootwalla.class)); - cards.add(new SetCardInfo("Boneshard Slasher", 50, Rarity.UNCOMMON, mage.cards.b.BoneshardSlasher.class)); - cards.add(new SetCardInfo("Breakthrough", 26, Rarity.UNCOMMON, mage.cards.b.Breakthrough.class)); - cards.add(new SetCardInfo("Cabal Coffers", 139, Rarity.UNCOMMON, mage.cards.c.CabalCoffers.class)); - cards.add(new SetCardInfo("Cabal Ritual", 51, Rarity.COMMON, mage.cards.c.CabalRitual.class)); - cards.add(new SetCardInfo("Cabal Surgeon", 52, Rarity.COMMON, mage.cards.c.CabalSurgeon.class)); - cards.add(new SetCardInfo("Cabal Torturer", 53, Rarity.COMMON, mage.cards.c.CabalTorturer.class)); - cards.add(new SetCardInfo("Centaur Chieftain", 122, Rarity.UNCOMMON, mage.cards.c.CentaurChieftain.class)); - cards.add(new SetCardInfo("Centaur Veteran", 123, Rarity.COMMON, mage.cards.c.CentaurVeteran.class)); - cards.add(new SetCardInfo("Cephalid Aristocrat", 27, Rarity.COMMON, mage.cards.c.CephalidAristocrat.class)); - cards.add(new SetCardInfo("Cephalid Illusionist", 28, Rarity.UNCOMMON, mage.cards.c.CephalidIllusionist.class)); - cards.add(new SetCardInfo("Cephalid Sage", 29, Rarity.UNCOMMON, mage.cards.c.CephalidSage.class)); - cards.add(new SetCardInfo("Cephalid Snitch", 30, Rarity.COMMON, mage.cards.c.CephalidSnitch.class)); - cards.add(new SetCardInfo("Cephalid Vandal", 31, Rarity.RARE, mage.cards.c.CephalidVandal.class)); - cards.add(new SetCardInfo("Chainer, Dementia Master", 56, Rarity.RARE, mage.cards.c.ChainerDementiaMaster.class)); - cards.add(new SetCardInfo("Chainer's Edict", 57, Rarity.UNCOMMON, mage.cards.c.ChainersEdict.class)); - cards.add(new SetCardInfo("Churning Eddy", 32, Rarity.COMMON, mage.cards.c.ChurningEddy.class)); - cards.add(new SetCardInfo("Circular Logic", 33, Rarity.UNCOMMON, mage.cards.c.CircularLogic.class)); - cards.add(new SetCardInfo("Cleansing Meditation", 3, Rarity.UNCOMMON, mage.cards.c.CleansingMeditation.class)); - cards.add(new SetCardInfo("Compulsion", 34, Rarity.UNCOMMON, mage.cards.c.Compulsion.class)); - cards.add(new SetCardInfo("Coral Net", 35, Rarity.COMMON, mage.cards.c.CoralNet.class)); - cards.add(new SetCardInfo("Crackling Club", 93, Rarity.COMMON, mage.cards.c.CracklingClub.class)); - cards.add(new SetCardInfo("Crazed Firecat", 94, Rarity.UNCOMMON, mage.cards.c.CrazedFirecat.class)); - cards.add(new SetCardInfo("Crippling Fatigue", 58, Rarity.COMMON, mage.cards.c.CripplingFatigue.class)); - cards.add(new SetCardInfo("Dawn of the Dead", 59, Rarity.RARE, mage.cards.d.DawnOfTheDead.class)); - cards.add(new SetCardInfo("Deep Analysis", 36, Rarity.COMMON, mage.cards.d.DeepAnalysis.class)); - cards.add(new SetCardInfo("Devastating Dreams", 95, Rarity.RARE, mage.cards.d.DevastatingDreams.class)); - cards.add(new SetCardInfo("Dwell on the Past", 124, Rarity.UNCOMMON, mage.cards.d.DwellOnThePast.class)); - cards.add(new SetCardInfo("Enslaved Dwarf", 96, Rarity.COMMON, mage.cards.e.EnslavedDwarf.class)); - cards.add(new SetCardInfo("Equal Treatment", 4, Rarity.UNCOMMON, mage.cards.e.EqualTreatment.class)); - cards.add(new SetCardInfo("Faceless Butcher", 60, Rarity.COMMON, mage.cards.f.FacelessButcher.class)); - cards.add(new SetCardInfo("False Memories", 37, Rarity.RARE, mage.cards.f.FalseMemories.class)); - cards.add(new SetCardInfo("Far Wanderings", 125, Rarity.COMMON, mage.cards.f.FarWanderings.class)); - cards.add(new SetCardInfo("Fiery Temper", 97, Rarity.COMMON, mage.cards.f.FieryTemper.class)); - cards.add(new SetCardInfo("Flash of Defiance", 99, Rarity.COMMON, mage.cards.f.FlashOfDefiance.class)); - cards.add(new SetCardInfo("Frantic Purification", 6, Rarity.COMMON, mage.cards.f.FranticPurification.class)); - cards.add(new SetCardInfo("Ghostly Wings", 38, Rarity.COMMON, mage.cards.g.GhostlyWings.class)); - cards.add(new SetCardInfo("Gloomdrifter", 61, Rarity.UNCOMMON, mage.cards.g.Gloomdrifter.class)); - cards.add(new SetCardInfo("Gravegouger", 62, Rarity.COMMON, mage.cards.g.Gravegouger.class)); - cards.add(new SetCardInfo("Grim Lavamancer", 100, Rarity.RARE, mage.cards.g.GrimLavamancer.class)); - cards.add(new SetCardInfo("Grotesque Hybrid", 63, Rarity.UNCOMMON, mage.cards.g.GrotesqueHybrid.class)); - cards.add(new SetCardInfo("Gurzigost", 126, Rarity.RARE, mage.cards.g.Gurzigost.class)); - cards.add(new SetCardInfo("Hell-Bent Raider", 101, Rarity.RARE, mage.cards.h.HellBentRaider.class)); - cards.add(new SetCardInfo("Hydromorph Guardian", 39, Rarity.COMMON, mage.cards.h.HydromorphGuardian.class)); - cards.add(new SetCardInfo("Hydromorph Gull", 40, Rarity.UNCOMMON, mage.cards.h.HydromorphGull.class)); - cards.add(new SetCardInfo("Hypochondria", 7, Rarity.UNCOMMON, mage.cards.h.Hypochondria.class)); - cards.add(new SetCardInfo("Hypnox", 64, Rarity.RARE, mage.cards.h.Hypnox.class)); - cards.add(new SetCardInfo("Ichorid", 65, Rarity.RARE, mage.cards.i.Ichorid.class)); - cards.add(new SetCardInfo("Insidious Dreams", 66, Rarity.RARE, mage.cards.i.InsidiousDreams.class)); - cards.add(new SetCardInfo("Insist", 127, Rarity.RARE, mage.cards.i.Insist.class)); - cards.add(new SetCardInfo("Invigorating Falls", 128, Rarity.COMMON, mage.cards.i.InvigoratingFalls.class)); - cards.add(new SetCardInfo("Kamahl's Sledge", 102, Rarity.COMMON, mage.cards.k.KamahlsSledge.class)); - cards.add(new SetCardInfo("Krosan Constrictor", 129, Rarity.COMMON, mage.cards.k.KrosanConstrictor.class)); - cards.add(new SetCardInfo("Krosan Restorer", 130, Rarity.COMMON, mage.cards.k.KrosanRestorer.class)); - cards.add(new SetCardInfo("Laquatus's Champion", 67, Rarity.RARE, mage.cards.l.LaquatussChampion.class)); - cards.add(new SetCardInfo("Last Laugh", 68, Rarity.RARE, mage.cards.l.LastLaugh.class)); - cards.add(new SetCardInfo("Liquify", 41, Rarity.COMMON, mage.cards.l.Liquify.class)); - cards.add(new SetCardInfo("Llawan, Cephalid Empress", 42, Rarity.RARE, mage.cards.l.LlawanCephalidEmpress.class)); - cards.add(new SetCardInfo("Longhorn Firebeast", 103, Rarity.COMMON, mage.cards.l.LonghornFirebeast.class)); - cards.add(new SetCardInfo("Major Teroh", 8, Rarity.RARE, mage.cards.m.MajorTeroh.class)); - cards.add(new SetCardInfo("Mesmeric Fiend", 69, Rarity.COMMON, mage.cards.m.MesmericFiend.class)); - cards.add(new SetCardInfo("Militant Monk", 9, Rarity.COMMON, mage.cards.m.MilitantMonk.class)); - cards.add(new SetCardInfo("Mind Sludge", 70, Rarity.UNCOMMON, mage.cards.m.MindSludge.class)); - cards.add(new SetCardInfo("Morningtide", 10, Rarity.RARE, mage.cards.m.Morningtide.class)); - cards.add(new SetCardInfo("Mortal Combat", 71, Rarity.RARE, mage.cards.m.MortalCombat.class)); - cards.add(new SetCardInfo("Mortiphobia", 72, Rarity.UNCOMMON, mage.cards.m.Mortiphobia.class)); - cards.add(new SetCardInfo("Mutilate", 73, Rarity.RARE, mage.cards.m.Mutilate.class)); - cards.add(new SetCardInfo("Mystic Familiar", 11, Rarity.COMMON, mage.cards.m.MysticFamiliar.class)); - cards.add(new SetCardInfo("Nantuko Blightcutter", 131, Rarity.RARE, mage.cards.n.NantukoBlightcutter.class)); - cards.add(new SetCardInfo("Nantuko Calmer", 132, Rarity.COMMON, mage.cards.n.NantukoCalmer.class)); - cards.add(new SetCardInfo("Nantuko Cultivator", 133, Rarity.RARE, mage.cards.n.NantukoCultivator.class)); - cards.add(new SetCardInfo("Nantuko Shade", 74, Rarity.RARE, mage.cards.n.NantukoShade.class)); - cards.add(new SetCardInfo("Narcissism", 134, Rarity.UNCOMMON, mage.cards.n.Narcissism.class)); - cards.add(new SetCardInfo("Nostalgic Dreams", 135, Rarity.RARE, mage.cards.n.NostalgicDreams.class)); - cards.add(new SetCardInfo("Obsessive Search", 43, Rarity.COMMON, mage.cards.o.ObsessiveSearch.class)); - cards.add(new SetCardInfo("Organ Grinder", 75, Rarity.COMMON, mage.cards.o.OrganGrinder.class)); - cards.add(new SetCardInfo("Overmaster", 104, Rarity.RARE, mage.cards.o.Overmaster.class)); - cards.add(new SetCardInfo("Parallel Evolution", 136, Rarity.RARE, mage.cards.p.ParallelEvolution.class)); - cards.add(new SetCardInfo("Pardic Arsonist", 105, Rarity.UNCOMMON, mage.cards.p.PardicArsonist.class)); - cards.add(new SetCardInfo("Pardic Collaborator", 106, Rarity.UNCOMMON, mage.cards.p.PardicCollaborator.class)); - cards.add(new SetCardInfo("Pardic Lancer", 107, Rarity.COMMON, mage.cards.p.PardicLancer.class)); - cards.add(new SetCardInfo("Pay No Heed", 12, Rarity.COMMON, mage.cards.p.PayNoHeed.class)); - cards.add(new SetCardInfo("Petradon", 108, Rarity.RARE, mage.cards.p.Petradon.class)); - cards.add(new SetCardInfo("Petravark", 109, Rarity.COMMON, mage.cards.p.Petravark.class)); - cards.add(new SetCardInfo("Pitchstone Wall", 110, Rarity.UNCOMMON, mage.cards.p.PitchstoneWall.class)); - cards.add(new SetCardInfo("Plagiarize", 44, Rarity.RARE, mage.cards.p.Plagiarize.class)); - cards.add(new SetCardInfo("Possessed Aven", 45, Rarity.RARE, mage.cards.p.PossessedAven.class)); - cards.add(new SetCardInfo("Possessed Barbarian", 111, Rarity.RARE, mage.cards.p.PossessedBarbarian.class)); - cards.add(new SetCardInfo("Possessed Centaur", 137, Rarity.RARE, mage.cards.p.PossessedCentaur.class)); - cards.add(new SetCardInfo("Possessed Nomad", 13, Rarity.RARE, mage.cards.p.PossessedNomad.class)); - cards.add(new SetCardInfo("Psychotic Haze", 76, Rarity.COMMON, mage.cards.p.PsychoticHaze.class)); - cards.add(new SetCardInfo("Putrid Imp", 77, Rarity.COMMON, mage.cards.p.PutridImp.class)); - cards.add(new SetCardInfo("Pyromania", 112, Rarity.UNCOMMON, mage.cards.p.Pyromania.class)); - cards.add(new SetCardInfo("Radiate", 113, Rarity.RARE, mage.cards.r.Radiate.class)); - cards.add(new SetCardInfo("Rancid Earth", 78, Rarity.COMMON, mage.cards.r.RancidEarth.class)); - cards.add(new SetCardInfo("Reborn Hero", 14, Rarity.RARE, mage.cards.r.RebornHero.class)); - cards.add(new SetCardInfo("Restless Dreams", 79, Rarity.COMMON, mage.cards.r.RestlessDreams.class)); - cards.add(new SetCardInfo("Sengir Vampire", 80, Rarity.RARE, mage.cards.s.SengirVampire.class)); - cards.add(new SetCardInfo("Seton's Scout", 138, Rarity.UNCOMMON, mage.cards.s.SetonsScout.class)); - cards.add(new SetCardInfo("Shade's Form", 81, Rarity.COMMON, mage.cards.s.ShadesForm.class)); - cards.add(new SetCardInfo("Shambling Swarm", 82, Rarity.RARE, mage.cards.s.ShamblingSwarm.class)); - cards.add(new SetCardInfo("Sickening Dreams", 83, Rarity.UNCOMMON, mage.cards.s.SickeningDreams.class)); - cards.add(new SetCardInfo("Skullscorch", 114, Rarity.RARE, mage.cards.s.Skullscorch.class)); - cards.add(new SetCardInfo("Skywing Aven", 47, Rarity.COMMON, mage.cards.s.SkywingAven.class)); - cards.add(new SetCardInfo("Slithery Stalker", 84, Rarity.UNCOMMON, mage.cards.s.SlitheryStalker.class)); - cards.add(new SetCardInfo("Sonic Seizure", 115, Rarity.COMMON, mage.cards.s.SonicSeizure.class)); - cards.add(new SetCardInfo("Soul Scourge", 85, Rarity.COMMON, mage.cards.s.SoulScourge.class)); - cards.add(new SetCardInfo("Stern Judge", 16, Rarity.UNCOMMON, mage.cards.s.SternJudge.class)); - cards.add(new SetCardInfo("Strength of Isolation", 17, Rarity.UNCOMMON, mage.cards.s.StrengthOfIsolation.class)); - cards.add(new SetCardInfo("Strength of Lunacy", 86, Rarity.UNCOMMON, mage.cards.s.StrengthOfLunacy.class)); - cards.add(new SetCardInfo("Stupefying Touch", 48, Rarity.UNCOMMON, mage.cards.s.StupefyingTouch.class)); - cards.add(new SetCardInfo("Tainted Field", 140, Rarity.UNCOMMON, mage.cards.t.TaintedField.class)); - cards.add(new SetCardInfo("Tainted Isle", 141, Rarity.UNCOMMON, mage.cards.t.TaintedIsle.class)); - cards.add(new SetCardInfo("Tainted Peak", 142, Rarity.UNCOMMON, mage.cards.t.TaintedPeak.class)); - cards.add(new SetCardInfo("Tainted Wood", 143, Rarity.UNCOMMON, mage.cards.t.TaintedWood.class)); - cards.add(new SetCardInfo("Temporary Insanity", 116, Rarity.UNCOMMON, mage.cards.t.TemporaryInsanity.class)); - cards.add(new SetCardInfo("Teroh's Faithful", 18, Rarity.COMMON, mage.cards.t.TerohsFaithful.class)); - cards.add(new SetCardInfo("Teroh's Vanguard", 19, Rarity.UNCOMMON, mage.cards.t.TerohsVanguard.class)); - cards.add(new SetCardInfo("Transcendence", 20, Rarity.RARE, mage.cards.t.Transcendence.class)); - cards.add(new SetCardInfo("Turbulent Dreams", 49, Rarity.RARE, mage.cards.t.TurbulentDreams.class)); - cards.add(new SetCardInfo("Unhinge", 87, Rarity.COMMON, mage.cards.u.Unhinge.class)); - cards.add(new SetCardInfo("Vengeful Dreams", 21, Rarity.RARE, mage.cards.v.VengefulDreams.class)); - cards.add(new SetCardInfo("Violent Eruption", 117, Rarity.UNCOMMON, mage.cards.v.ViolentEruption.class)); - cards.add(new SetCardInfo("Waste Away", 88, Rarity.COMMON, mage.cards.w.WasteAway.class)); - cards.add(new SetCardInfo("Zombie Trailblazer", 89, Rarity.UNCOMMON, mage.cards.z.ZombieTrailblazer.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Torment extends ExpansionSet { + + private static final Torment instance = new Torment(); + + public static Torment getInstance() { + return instance; + } + + private Torment() { + super("Torment", "TOR", ExpansionSet.buildDate(2002, 1, 26), SetType.EXPANSION); + this.blockName = "Odyssey"; + this.parentSet = Odyssey.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Accelerate", 90, Rarity.COMMON, mage.cards.a.Accelerate.class)); + cards.add(new SetCardInfo("Acorn Harvest", 118, Rarity.COMMON, mage.cards.a.AcornHarvest.class)); + cards.add(new SetCardInfo("Ambassador Laquatus", 23, Rarity.RARE, mage.cards.a.AmbassadorLaquatus.class)); + cards.add(new SetCardInfo("Angel of Retribution", 1, Rarity.RARE, mage.cards.a.AngelOfRetribution.class)); + cards.add(new SetCardInfo("Anurid Scavenger", 119, Rarity.UNCOMMON, mage.cards.a.AnuridScavenger.class)); + cards.add(new SetCardInfo("Aquamoeba", 24, Rarity.COMMON, mage.cards.a.Aquamoeba.class)); + cards.add(new SetCardInfo("Arrogant Wurm", 120, Rarity.UNCOMMON, mage.cards.a.ArrogantWurm.class)); + cards.add(new SetCardInfo("Aven Trooper", 2, Rarity.COMMON, mage.cards.a.AvenTrooper.class)); + cards.add(new SetCardInfo("Balshan Collaborator", 25, Rarity.UNCOMMON, mage.cards.b.BalshanCollaborator.class)); + cards.add(new SetCardInfo("Balthor the Stout", 91, Rarity.RARE, mage.cards.b.BalthorTheStout.class)); + cards.add(new SetCardInfo("Barbarian Outcast", 92, Rarity.COMMON, mage.cards.b.BarbarianOutcast.class)); + cards.add(new SetCardInfo("Basking Rootwalla", 121, Rarity.COMMON, mage.cards.b.BaskingRootwalla.class)); + cards.add(new SetCardInfo("Boneshard Slasher", 50, Rarity.UNCOMMON, mage.cards.b.BoneshardSlasher.class)); + cards.add(new SetCardInfo("Breakthrough", 26, Rarity.UNCOMMON, mage.cards.b.Breakthrough.class)); + cards.add(new SetCardInfo("Cabal Coffers", 139, Rarity.UNCOMMON, mage.cards.c.CabalCoffers.class)); + cards.add(new SetCardInfo("Cabal Ritual", 51, Rarity.COMMON, mage.cards.c.CabalRitual.class)); + cards.add(new SetCardInfo("Cabal Surgeon", 52, Rarity.COMMON, mage.cards.c.CabalSurgeon.class)); + cards.add(new SetCardInfo("Cabal Torturer", 53, Rarity.COMMON, mage.cards.c.CabalTorturer.class)); + cards.add(new SetCardInfo("Centaur Chieftain", 122, Rarity.UNCOMMON, mage.cards.c.CentaurChieftain.class)); + cards.add(new SetCardInfo("Centaur Veteran", 123, Rarity.COMMON, mage.cards.c.CentaurVeteran.class)); + cards.add(new SetCardInfo("Cephalid Aristocrat", 27, Rarity.COMMON, mage.cards.c.CephalidAristocrat.class)); + cards.add(new SetCardInfo("Cephalid Illusionist", 28, Rarity.UNCOMMON, mage.cards.c.CephalidIllusionist.class)); + cards.add(new SetCardInfo("Cephalid Sage", 29, Rarity.UNCOMMON, mage.cards.c.CephalidSage.class)); + cards.add(new SetCardInfo("Cephalid Snitch", 30, Rarity.COMMON, mage.cards.c.CephalidSnitch.class)); + cards.add(new SetCardInfo("Cephalid Vandal", 31, Rarity.RARE, mage.cards.c.CephalidVandal.class)); + cards.add(new SetCardInfo("Chainer, Dementia Master", 56, Rarity.RARE, mage.cards.c.ChainerDementiaMaster.class)); + cards.add(new SetCardInfo("Chainer's Edict", 57, Rarity.UNCOMMON, mage.cards.c.ChainersEdict.class)); + cards.add(new SetCardInfo("Churning Eddy", 32, Rarity.COMMON, mage.cards.c.ChurningEddy.class)); + cards.add(new SetCardInfo("Circular Logic", 33, Rarity.UNCOMMON, mage.cards.c.CircularLogic.class)); + cards.add(new SetCardInfo("Cleansing Meditation", 3, Rarity.UNCOMMON, mage.cards.c.CleansingMeditation.class)); + cards.add(new SetCardInfo("Compulsion", 34, Rarity.UNCOMMON, mage.cards.c.Compulsion.class)); + cards.add(new SetCardInfo("Coral Net", 35, Rarity.COMMON, mage.cards.c.CoralNet.class)); + cards.add(new SetCardInfo("Crackling Club", 93, Rarity.COMMON, mage.cards.c.CracklingClub.class)); + cards.add(new SetCardInfo("Crazed Firecat", 94, Rarity.UNCOMMON, mage.cards.c.CrazedFirecat.class)); + cards.add(new SetCardInfo("Crippling Fatigue", 58, Rarity.COMMON, mage.cards.c.CripplingFatigue.class)); + cards.add(new SetCardInfo("Dawn of the Dead", 59, Rarity.RARE, mage.cards.d.DawnOfTheDead.class)); + cards.add(new SetCardInfo("Deep Analysis", 36, Rarity.COMMON, mage.cards.d.DeepAnalysis.class)); + cards.add(new SetCardInfo("Devastating Dreams", 95, Rarity.RARE, mage.cards.d.DevastatingDreams.class)); + cards.add(new SetCardInfo("Dwell on the Past", 124, Rarity.UNCOMMON, mage.cards.d.DwellOnThePast.class)); + cards.add(new SetCardInfo("Enslaved Dwarf", 96, Rarity.COMMON, mage.cards.e.EnslavedDwarf.class)); + cards.add(new SetCardInfo("Equal Treatment", 4, Rarity.UNCOMMON, mage.cards.e.EqualTreatment.class)); + cards.add(new SetCardInfo("Faceless Butcher", 60, Rarity.COMMON, mage.cards.f.FacelessButcher.class)); + cards.add(new SetCardInfo("False Memories", 37, Rarity.RARE, mage.cards.f.FalseMemories.class)); + cards.add(new SetCardInfo("Far Wanderings", 125, Rarity.COMMON, mage.cards.f.FarWanderings.class)); + cards.add(new SetCardInfo("Fiery Temper", 97, Rarity.COMMON, mage.cards.f.FieryTemper.class)); + cards.add(new SetCardInfo("Flash of Defiance", 99, Rarity.COMMON, mage.cards.f.FlashOfDefiance.class)); + cards.add(new SetCardInfo("Frantic Purification", 6, Rarity.COMMON, mage.cards.f.FranticPurification.class)); + cards.add(new SetCardInfo("Ghostly Wings", 38, Rarity.COMMON, mage.cards.g.GhostlyWings.class)); + cards.add(new SetCardInfo("Gloomdrifter", 61, Rarity.UNCOMMON, mage.cards.g.Gloomdrifter.class)); + cards.add(new SetCardInfo("Gravegouger", 62, Rarity.COMMON, mage.cards.g.Gravegouger.class)); + cards.add(new SetCardInfo("Grim Lavamancer", 100, Rarity.RARE, mage.cards.g.GrimLavamancer.class)); + cards.add(new SetCardInfo("Grotesque Hybrid", 63, Rarity.UNCOMMON, mage.cards.g.GrotesqueHybrid.class)); + cards.add(new SetCardInfo("Gurzigost", 126, Rarity.RARE, mage.cards.g.Gurzigost.class)); + cards.add(new SetCardInfo("Hell-Bent Raider", 101, Rarity.RARE, mage.cards.h.HellBentRaider.class)); + cards.add(new SetCardInfo("Hydromorph Guardian", 39, Rarity.COMMON, mage.cards.h.HydromorphGuardian.class)); + cards.add(new SetCardInfo("Hydromorph Gull", 40, Rarity.UNCOMMON, mage.cards.h.HydromorphGull.class)); + cards.add(new SetCardInfo("Hypochondria", 7, Rarity.UNCOMMON, mage.cards.h.Hypochondria.class)); + cards.add(new SetCardInfo("Hypnox", 64, Rarity.RARE, mage.cards.h.Hypnox.class)); + cards.add(new SetCardInfo("Ichorid", 65, Rarity.RARE, mage.cards.i.Ichorid.class)); + cards.add(new SetCardInfo("Insidious Dreams", 66, Rarity.RARE, mage.cards.i.InsidiousDreams.class)); + cards.add(new SetCardInfo("Insist", 127, Rarity.RARE, mage.cards.i.Insist.class)); + cards.add(new SetCardInfo("Invigorating Falls", 128, Rarity.COMMON, mage.cards.i.InvigoratingFalls.class)); + cards.add(new SetCardInfo("Kamahl's Sledge", 102, Rarity.COMMON, mage.cards.k.KamahlsSledge.class)); + cards.add(new SetCardInfo("Krosan Constrictor", 129, Rarity.COMMON, mage.cards.k.KrosanConstrictor.class)); + cards.add(new SetCardInfo("Krosan Restorer", 130, Rarity.COMMON, mage.cards.k.KrosanRestorer.class)); + cards.add(new SetCardInfo("Laquatus's Champion", 67, Rarity.RARE, mage.cards.l.LaquatussChampion.class)); + cards.add(new SetCardInfo("Last Laugh", 68, Rarity.RARE, mage.cards.l.LastLaugh.class)); + cards.add(new SetCardInfo("Liquify", 41, Rarity.COMMON, mage.cards.l.Liquify.class)); + cards.add(new SetCardInfo("Llawan, Cephalid Empress", 42, Rarity.RARE, mage.cards.l.LlawanCephalidEmpress.class)); + cards.add(new SetCardInfo("Longhorn Firebeast", 103, Rarity.COMMON, mage.cards.l.LonghornFirebeast.class)); + cards.add(new SetCardInfo("Major Teroh", 8, Rarity.RARE, mage.cards.m.MajorTeroh.class)); + cards.add(new SetCardInfo("Mesmeric Fiend", 69, Rarity.COMMON, mage.cards.m.MesmericFiend.class)); + cards.add(new SetCardInfo("Militant Monk", 9, Rarity.COMMON, mage.cards.m.MilitantMonk.class)); + cards.add(new SetCardInfo("Mind Sludge", 70, Rarity.UNCOMMON, mage.cards.m.MindSludge.class)); + cards.add(new SetCardInfo("Morningtide", 10, Rarity.RARE, mage.cards.m.Morningtide.class)); + cards.add(new SetCardInfo("Mortal Combat", 71, Rarity.RARE, mage.cards.m.MortalCombat.class)); + cards.add(new SetCardInfo("Mortiphobia", 72, Rarity.UNCOMMON, mage.cards.m.Mortiphobia.class)); + cards.add(new SetCardInfo("Mutilate", 73, Rarity.RARE, mage.cards.m.Mutilate.class)); + cards.add(new SetCardInfo("Mystic Familiar", 11, Rarity.COMMON, mage.cards.m.MysticFamiliar.class)); + cards.add(new SetCardInfo("Nantuko Blightcutter", 131, Rarity.RARE, mage.cards.n.NantukoBlightcutter.class)); + cards.add(new SetCardInfo("Nantuko Calmer", 132, Rarity.COMMON, mage.cards.n.NantukoCalmer.class)); + cards.add(new SetCardInfo("Nantuko Cultivator", 133, Rarity.RARE, mage.cards.n.NantukoCultivator.class)); + cards.add(new SetCardInfo("Nantuko Shade", 74, Rarity.RARE, mage.cards.n.NantukoShade.class)); + cards.add(new SetCardInfo("Narcissism", 134, Rarity.UNCOMMON, mage.cards.n.Narcissism.class)); + cards.add(new SetCardInfo("Nostalgic Dreams", 135, Rarity.RARE, mage.cards.n.NostalgicDreams.class)); + cards.add(new SetCardInfo("Obsessive Search", 43, Rarity.COMMON, mage.cards.o.ObsessiveSearch.class)); + cards.add(new SetCardInfo("Organ Grinder", 75, Rarity.COMMON, mage.cards.o.OrganGrinder.class)); + cards.add(new SetCardInfo("Overmaster", 104, Rarity.RARE, mage.cards.o.Overmaster.class)); + cards.add(new SetCardInfo("Parallel Evolution", 136, Rarity.RARE, mage.cards.p.ParallelEvolution.class)); + cards.add(new SetCardInfo("Pardic Arsonist", 105, Rarity.UNCOMMON, mage.cards.p.PardicArsonist.class)); + cards.add(new SetCardInfo("Pardic Collaborator", 106, Rarity.UNCOMMON, mage.cards.p.PardicCollaborator.class)); + cards.add(new SetCardInfo("Pardic Lancer", 107, Rarity.COMMON, mage.cards.p.PardicLancer.class)); + cards.add(new SetCardInfo("Pay No Heed", 12, Rarity.COMMON, mage.cards.p.PayNoHeed.class)); + cards.add(new SetCardInfo("Petradon", 108, Rarity.RARE, mage.cards.p.Petradon.class)); + cards.add(new SetCardInfo("Petravark", 109, Rarity.COMMON, mage.cards.p.Petravark.class)); + cards.add(new SetCardInfo("Pitchstone Wall", 110, Rarity.UNCOMMON, mage.cards.p.PitchstoneWall.class)); + cards.add(new SetCardInfo("Plagiarize", 44, Rarity.RARE, mage.cards.p.Plagiarize.class)); + cards.add(new SetCardInfo("Possessed Aven", 45, Rarity.RARE, mage.cards.p.PossessedAven.class)); + cards.add(new SetCardInfo("Possessed Barbarian", 111, Rarity.RARE, mage.cards.p.PossessedBarbarian.class)); + cards.add(new SetCardInfo("Possessed Centaur", 137, Rarity.RARE, mage.cards.p.PossessedCentaur.class)); + cards.add(new SetCardInfo("Possessed Nomad", 13, Rarity.RARE, mage.cards.p.PossessedNomad.class)); + cards.add(new SetCardInfo("Psychotic Haze", 76, Rarity.COMMON, mage.cards.p.PsychoticHaze.class)); + cards.add(new SetCardInfo("Putrid Imp", 77, Rarity.COMMON, mage.cards.p.PutridImp.class)); + cards.add(new SetCardInfo("Pyromania", 112, Rarity.UNCOMMON, mage.cards.p.Pyromania.class)); + cards.add(new SetCardInfo("Radiate", 113, Rarity.RARE, mage.cards.r.Radiate.class)); + cards.add(new SetCardInfo("Rancid Earth", 78, Rarity.COMMON, mage.cards.r.RancidEarth.class)); + cards.add(new SetCardInfo("Reborn Hero", 14, Rarity.RARE, mage.cards.r.RebornHero.class)); + cards.add(new SetCardInfo("Restless Dreams", 79, Rarity.COMMON, mage.cards.r.RestlessDreams.class)); + cards.add(new SetCardInfo("Retraced Image", 46, Rarity.RARE, mage.cards.r.RetracedImage.class)); + cards.add(new SetCardInfo("Sengir Vampire", 80, Rarity.RARE, mage.cards.s.SengirVampire.class)); + cards.add(new SetCardInfo("Seton's Scout", 138, Rarity.UNCOMMON, mage.cards.s.SetonsScout.class)); + cards.add(new SetCardInfo("Shade's Form", 81, Rarity.COMMON, mage.cards.s.ShadesForm.class)); + cards.add(new SetCardInfo("Shambling Swarm", 82, Rarity.RARE, mage.cards.s.ShamblingSwarm.class)); + cards.add(new SetCardInfo("Sickening Dreams", 83, Rarity.UNCOMMON, mage.cards.s.SickeningDreams.class)); + cards.add(new SetCardInfo("Skullscorch", 114, Rarity.RARE, mage.cards.s.Skullscorch.class)); + cards.add(new SetCardInfo("Skywing Aven", 47, Rarity.COMMON, mage.cards.s.SkywingAven.class)); + cards.add(new SetCardInfo("Slithery Stalker", 84, Rarity.UNCOMMON, mage.cards.s.SlitheryStalker.class)); + cards.add(new SetCardInfo("Sonic Seizure", 115, Rarity.COMMON, mage.cards.s.SonicSeizure.class)); + cards.add(new SetCardInfo("Soul Scourge", 85, Rarity.COMMON, mage.cards.s.SoulScourge.class)); + cards.add(new SetCardInfo("Stern Judge", 16, Rarity.UNCOMMON, mage.cards.s.SternJudge.class)); + cards.add(new SetCardInfo("Strength of Isolation", 17, Rarity.UNCOMMON, mage.cards.s.StrengthOfIsolation.class)); + cards.add(new SetCardInfo("Strength of Lunacy", 86, Rarity.UNCOMMON, mage.cards.s.StrengthOfLunacy.class)); + cards.add(new SetCardInfo("Stupefying Touch", 48, Rarity.UNCOMMON, mage.cards.s.StupefyingTouch.class)); + cards.add(new SetCardInfo("Tainted Field", 140, Rarity.UNCOMMON, mage.cards.t.TaintedField.class)); + cards.add(new SetCardInfo("Tainted Isle", 141, Rarity.UNCOMMON, mage.cards.t.TaintedIsle.class)); + cards.add(new SetCardInfo("Tainted Peak", 142, Rarity.UNCOMMON, mage.cards.t.TaintedPeak.class)); + cards.add(new SetCardInfo("Tainted Wood", 143, Rarity.UNCOMMON, mage.cards.t.TaintedWood.class)); + cards.add(new SetCardInfo("Temporary Insanity", 116, Rarity.UNCOMMON, mage.cards.t.TemporaryInsanity.class)); + cards.add(new SetCardInfo("Teroh's Faithful", 18, Rarity.COMMON, mage.cards.t.TerohsFaithful.class)); + cards.add(new SetCardInfo("Teroh's Vanguard", 19, Rarity.UNCOMMON, mage.cards.t.TerohsVanguard.class)); + cards.add(new SetCardInfo("Transcendence", 20, Rarity.RARE, mage.cards.t.Transcendence.class)); + cards.add(new SetCardInfo("Turbulent Dreams", 49, Rarity.RARE, mage.cards.t.TurbulentDreams.class)); + cards.add(new SetCardInfo("Unhinge", 87, Rarity.COMMON, mage.cards.u.Unhinge.class)); + cards.add(new SetCardInfo("Vengeful Dreams", 21, Rarity.RARE, mage.cards.v.VengefulDreams.class)); + cards.add(new SetCardInfo("Violent Eruption", 117, Rarity.UNCOMMON, mage.cards.v.ViolentEruption.class)); + cards.add(new SetCardInfo("Waste Away", 88, Rarity.COMMON, mage.cards.w.WasteAway.class)); + cards.add(new SetCardInfo("Zombie Trailblazer", 89, Rarity.UNCOMMON, mage.cards.z.ZombieTrailblazer.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java b/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java new file mode 100644 index 0000000000..545985a829 --- /dev/null +++ b/Mage.Sets/src/mage/sets/UltimateBoxTopperPromos.java @@ -0,0 +1,65 @@ + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class UltimateBoxTopperPromos extends ExpansionSet { + + private static final UltimateBoxTopperPromos instance = new UltimateBoxTopperPromos(); + + public static UltimateBoxTopperPromos getInstance() { + return instance; + } + + private UltimateBoxTopperPromos() { + super("Ultimate Box Topper Promos", "PUMA", ExpansionSet.buildDate(2018, 12, 7), SetType.PROMOTIONAL); + this.hasBasicLands = false; + this.hasBoosters = false; + + cards.add(new SetCardInfo("Ancient Tomb", "U31", Rarity.MYTHIC, mage.cards.a.AncientTomb.class)); + cards.add(new SetCardInfo("Balefire Dragon", "U14", Rarity.MYTHIC, mage.cards.b.BalefireDragon.class)); + cards.add(new SetCardInfo("Bitterblossom", "U7", Rarity.MYTHIC, mage.cards.b.Bitterblossom.class)); + cards.add(new SetCardInfo("Cavern of Souls", "U32", Rarity.MYTHIC, mage.cards.c.CavernOfSouls.class)); + cards.add(new SetCardInfo("Celestial Colonnade", "U33", Rarity.MYTHIC, mage.cards.c.CelestialColonnade.class)); + cards.add(new SetCardInfo("Creeping Tar Pit", "U34", Rarity.MYTHIC, mage.cards.c.CreepingTarPit.class)); + cards.add(new SetCardInfo("Dark Depths", "U35", Rarity.MYTHIC, mage.cards.d.DarkDepths.class)); + cards.add(new SetCardInfo("Demonic Tutor", "U8", Rarity.MYTHIC, mage.cards.d.DemonicTutor.class)); + cards.add(new SetCardInfo("Emrakul, the Aeons Torn", "U1", Rarity.MYTHIC, mage.cards.e.EmrakulTheAeonsTorn.class)); + cards.add(new SetCardInfo("Engineered Explosives", "U28", Rarity.MYTHIC, mage.cards.e.EngineeredExplosives.class)); + cards.add(new SetCardInfo("Eternal Witness", "U16", Rarity.MYTHIC, mage.cards.e.EternalWitness.class)); + cards.add(new SetCardInfo("Fulminator Mage", "U26", Rarity.MYTHIC, mage.cards.f.FulminatorMage.class)); + cards.add(new SetCardInfo("Gaddock Teeg", "U21", Rarity.MYTHIC, mage.cards.g.GaddockTeeg.class)); + cards.add(new SetCardInfo("Goryo's Vengeance", "U9", Rarity.MYTHIC, mage.cards.g.GoryosVengeance.class)); + cards.add(new SetCardInfo("Karakas", "U36", Rarity.MYTHIC, mage.cards.k.Karakas.class)); + cards.add(new SetCardInfo("Karn Liberated", "U2", Rarity.MYTHIC, mage.cards.k.KarnLiberated.class)); + cards.add(new SetCardInfo("Kitchen Finks", "U27", Rarity.MYTHIC, mage.cards.k.KitchenFinks.class)); + cards.add(new SetCardInfo("Kozilek, Butcher of Truth", "U3", Rarity.MYTHIC, mage.cards.k.KozilekButcherOfTruth.class)); + cards.add(new SetCardInfo("Lavaclaw Reaches", "U37", Rarity.MYTHIC, mage.cards.l.LavaclawReaches.class)); + cards.add(new SetCardInfo("Leovold, Emissary of Trest", "U22", Rarity.MYTHIC, mage.cards.l.LeovoldEmissaryOfTrest.class)); + cards.add(new SetCardInfo("Life from the Loam", "U17", Rarity.MYTHIC, mage.cards.l.LifeFromTheLoam.class)); + cards.add(new SetCardInfo("Liliana of the Veil", "U10", Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class)); + cards.add(new SetCardInfo("Lord of Extinction", "U23", Rarity.MYTHIC, mage.cards.l.LordOfExtinction.class)); + cards.add(new SetCardInfo("Maelstrom Pulse", "U24", Rarity.MYTHIC, mage.cards.m.MaelstromPulse.class)); + cards.add(new SetCardInfo("Mana Vault", "U29", Rarity.MYTHIC, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Mikaeus, the Unhallowed", "U11", Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class)); + cards.add(new SetCardInfo("Noble Hierarch", "U18", Rarity.MYTHIC, mage.cards.n.NobleHierarch.class)); + cards.add(new SetCardInfo("Platinum Emperion", "U30", Rarity.MYTHIC, mage.cards.p.PlatinumEmperion.class)); + cards.add(new SetCardInfo("Raging Ravine", "U38", Rarity.MYTHIC, mage.cards.r.RagingRavine.class)); + cards.add(new SetCardInfo("Reanimate", "U12", Rarity.MYTHIC, mage.cards.r.Reanimate.class)); + cards.add(new SetCardInfo("Sigarda, Host of Herons", "U25", Rarity.MYTHIC, mage.cards.s.SigardaHostOfHerons.class)); + cards.add(new SetCardInfo("Snapcaster Mage", "U5", Rarity.MYTHIC, mage.cards.s.SnapcasterMage.class)); + cards.add(new SetCardInfo("Stirring Wildwood", "U39", Rarity.MYTHIC, mage.cards.s.StirringWildwood.class)); + cards.add(new SetCardInfo("Tarmogoyf", "U19", Rarity.MYTHIC, mage.cards.t.Tarmogoyf.class)); + cards.add(new SetCardInfo("Tasigur, the Golden Fang", "U13", Rarity.MYTHIC, mage.cards.t.TasigurTheGoldenFang.class)); + cards.add(new SetCardInfo("Temporal Manipulation", "U6", Rarity.MYTHIC, mage.cards.t.TemporalManipulation.class)); + cards.add(new SetCardInfo("Through the Breach", "U15", Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class)); + cards.add(new SetCardInfo("Ulamog, the Infinite Gyre", "U4", Rarity.MYTHIC, mage.cards.u.UlamogTheInfiniteGyre.class)); + cards.add(new SetCardInfo("Urborg, Tomb of Yawgmoth", "U40", Rarity.MYTHIC, mage.cards.u.UrborgTombOfYawgmoth.class)); + cards.add(new SetCardInfo("Vengevine", "U20", Rarity.MYTHIC, mage.cards.v.Vengevine.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/UltimateMasters.java b/Mage.Sets/src/mage/sets/UltimateMasters.java new file mode 100644 index 0000000000..7e39b5da52 --- /dev/null +++ b/Mage.Sets/src/mage/sets/UltimateMasters.java @@ -0,0 +1,284 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * @author JayDi85 + */ +public final class UltimateMasters extends ExpansionSet { + + private static final UltimateMasters instance = new UltimateMasters(); + + public static UltimateMasters getInstance() { + return instance; + } + + private UltimateMasters() { + super("Ultimate Masters", "UMA", ExpansionSet.buildDate(2018, 12, 7), SetType.SUPPLEMENTAL); + this.blockName = "Reprint"; + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + + cards.add(new SetCardInfo("Aethersnipe", 44, Rarity.COMMON, mage.cards.a.Aethersnipe.class)); + cards.add(new SetCardInfo("Akroan Crusader", 121, Rarity.COMMON, mage.cards.a.AkroanCrusader.class)); + cards.add(new SetCardInfo("All Is Dust", 1, Rarity.RARE, mage.cards.a.AllIsDust.class)); + cards.add(new SetCardInfo("Ancestor's Chosen", 9, Rarity.UNCOMMON, mage.cards.a.AncestorsChosen.class)); + cards.add(new SetCardInfo("Ancient Tomb", 236, Rarity.RARE, mage.cards.a.AncientTomb.class)); + cards.add(new SetCardInfo("Angel of Despair", 196, Rarity.UNCOMMON, mage.cards.a.AngelOfDespair.class)); + cards.add(new SetCardInfo("Angelic Renewal", 10, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); + cards.add(new SetCardInfo("Anger", 122, Rarity.UNCOMMON, mage.cards.a.Anger.class)); + cards.add(new SetCardInfo("Appetite for Brains", 83, Rarity.UNCOMMON, mage.cards.a.AppetiteForBrains.class)); + cards.add(new SetCardInfo("Apprentice Necromancer", 84, Rarity.UNCOMMON, mage.cards.a.ApprenticeNecromancer.class)); + cards.add(new SetCardInfo("Archaeomancer", 45, Rarity.COMMON, mage.cards.a.Archaeomancer.class)); + cards.add(new SetCardInfo("Arena Athlete", 123, Rarity.COMMON, mage.cards.a.ArenaAthlete.class)); + cards.add(new SetCardInfo("Artisan of Kozilek", 2, Rarity.UNCOMMON, mage.cards.a.ArtisanOfKozilek.class)); + cards.add(new SetCardInfo("Back to Basics", 46, Rarity.RARE, mage.cards.b.BackToBasics.class)); + cards.add(new SetCardInfo("Balefire Dragon", 124, Rarity.MYTHIC, mage.cards.b.BalefireDragon.class)); + cards.add(new SetCardInfo("Basking Rootwalla", 156, Rarity.COMMON, mage.cards.b.BaskingRootwalla.class)); + cards.add(new SetCardInfo("Beckon Apparition", 211, Rarity.COMMON, mage.cards.b.BeckonApparition.class)); + cards.add(new SetCardInfo("Become Immense", 157, Rarity.UNCOMMON, mage.cards.b.BecomeImmense.class)); + cards.add(new SetCardInfo("Bitterblossom", 85, Rarity.MYTHIC, mage.cards.b.Bitterblossom.class)); + cards.add(new SetCardInfo("Blast of Genius", 197, Rarity.UNCOMMON, mage.cards.b.BlastOfGenius.class)); + cards.add(new SetCardInfo("Bloodflow Connoisseur", 86, Rarity.COMMON, mage.cards.b.BloodflowConnoisseur.class)); + cards.add(new SetCardInfo("Boar Umbra", 158, Rarity.UNCOMMON, mage.cards.b.BoarUmbra.class)); + cards.add(new SetCardInfo("Boneyard Wurm", 159, Rarity.UNCOMMON, mage.cards.b.BoneyardWurm.class)); + cards.add(new SetCardInfo("Brawn", 160, Rarity.UNCOMMON, mage.cards.b.Brawn.class)); + cards.add(new SetCardInfo("Brazen Scourge", 125, Rarity.UNCOMMON, mage.cards.b.BrazenScourge.class)); + cards.add(new SetCardInfo("Bridge from Below", 87, Rarity.RARE, mage.cards.b.BridgeFromBelow.class)); + cards.add(new SetCardInfo("Buried Alive", 88, Rarity.UNCOMMON, mage.cards.b.BuriedAlive.class)); + cards.add(new SetCardInfo("Canker Abomination", 212, Rarity.COMMON, mage.cards.c.CankerAbomination.class)); + cards.add(new SetCardInfo("Cathodion", 226, Rarity.COMMON, mage.cards.c.Cathodion.class)); + cards.add(new SetCardInfo("Cavern of Souls", 237, Rarity.MYTHIC, mage.cards.c.CavernOfSouls.class)); + cards.add(new SetCardInfo("Celestial Colonnade", 238, Rarity.RARE, mage.cards.c.CelestialColonnade.class)); + cards.add(new SetCardInfo("Chainer's Edict", 89, Rarity.UNCOMMON, mage.cards.c.ChainersEdict.class)); + cards.add(new SetCardInfo("Circular Logic", 47, Rarity.UNCOMMON, mage.cards.c.CircularLogic.class)); + cards.add(new SetCardInfo("Conflagrate", 126, Rarity.UNCOMMON, mage.cards.c.Conflagrate.class)); + cards.add(new SetCardInfo("Containment Priest", 11, Rarity.RARE, mage.cards.c.ContainmentPriest.class)); + cards.add(new SetCardInfo("Conviction", 12, Rarity.COMMON, mage.cards.c.Conviction.class)); + cards.add(new SetCardInfo("Countersquall", 198, Rarity.UNCOMMON, mage.cards.c.Countersquall.class)); + cards.add(new SetCardInfo("Creeping Tar Pit", 239, Rarity.RARE, mage.cards.c.CreepingTarPit.class)); + cards.add(new SetCardInfo("Crow of Dark Tidings", 90, Rarity.COMMON, mage.cards.c.CrowOfDarkTidings.class)); + cards.add(new SetCardInfo("Crushing Canopy", 161, Rarity.COMMON, mage.cards.c.CrushingCanopy.class)); + cards.add(new SetCardInfo("Dakmor Salvage", 240, Rarity.UNCOMMON, mage.cards.d.DakmorSalvage.class)); + cards.add(new SetCardInfo("Dark Dabbling", 91, Rarity.COMMON, mage.cards.d.DarkDabbling.class)); + cards.add(new SetCardInfo("Dark Depths", 241, Rarity.MYTHIC, mage.cards.d.DarkDepths.class)); + cards.add(new SetCardInfo("Dawn Charm", 13, Rarity.UNCOMMON, mage.cards.d.DawnCharm.class)); + cards.add(new SetCardInfo("Daybreak Coronet", 14, Rarity.RARE, mage.cards.d.DaybreakCoronet.class)); + cards.add(new SetCardInfo("Death Denied", 92, Rarity.COMMON, mage.cards.d.DeathDenied.class)); + cards.add(new SetCardInfo("Defy Gravity", 48, Rarity.COMMON, mage.cards.d.DefyGravity.class)); + cards.add(new SetCardInfo("Demonic Tutor", 93, Rarity.RARE, mage.cards.d.DemonicTutor.class)); + cards.add(new SetCardInfo("Deranged Assistant", 49, Rarity.COMMON, mage.cards.d.DerangedAssistant.class)); + cards.add(new SetCardInfo("Desolate Lighthouse", 242, Rarity.RARE, mage.cards.d.DesolateLighthouse.class)); + cards.add(new SetCardInfo("Desperate Ritual", 127, Rarity.UNCOMMON, mage.cards.d.DesperateRitual.class)); + cards.add(new SetCardInfo("Devoted Druid", 162, Rarity.UNCOMMON, mage.cards.d.DevotedDruid.class)); + cards.add(new SetCardInfo("Dig Through Time", 50, Rarity.RARE, mage.cards.d.DigThroughTime.class)); + cards.add(new SetCardInfo("Dimir Guildmage", 213, Rarity.COMMON, mage.cards.d.DimirGuildmage.class)); + cards.add(new SetCardInfo("Disrupting Shoal", 51, Rarity.RARE, mage.cards.d.DisruptingShoal.class)); + cards.add(new SetCardInfo("Double Cleave", 214, Rarity.COMMON, mage.cards.d.DoubleCleave.class)); + cards.add(new SetCardInfo("Dreamscape Artist", 52, Rarity.UNCOMMON, mage.cards.d.DreamscapeArtist.class)); + cards.add(new SetCardInfo("Eel Umbra", 53, Rarity.COMMON, mage.cards.e.EelUmbra.class)); + cards.add(new SetCardInfo("Eldrazi Conscription", 3, Rarity.RARE, mage.cards.e.EldraziConscription.class)); + cards.add(new SetCardInfo("Emancipation Angel", 15, Rarity.UNCOMMON, mage.cards.e.EmancipationAngel.class)); + cards.add(new SetCardInfo("Emrakul, the Aeons Torn", 4, Rarity.MYTHIC, mage.cards.e.EmrakulTheAeonsTorn.class)); + cards.add(new SetCardInfo("Engineered Explosives", 227, Rarity.RARE, mage.cards.e.EngineeredExplosives.class)); + cards.add(new SetCardInfo("Entomb", 94, Rarity.RARE, mage.cards.e.Entomb.class)); + cards.add(new SetCardInfo("Eternal Witness", 163, Rarity.UNCOMMON, mage.cards.e.EternalWitness.class)); + cards.add(new SetCardInfo("Faith's Fetters", 16, Rarity.COMMON, mage.cards.f.FaithsFetters.class)); + cards.add(new SetCardInfo("Faithless Looting", 128, Rarity.COMMON, mage.cards.f.FaithlessLooting.class)); + cards.add(new SetCardInfo("Fauna Shaman", 164, Rarity.RARE, mage.cards.f.FaunaShaman.class)); + cards.add(new SetCardInfo("Fecundity", 165, Rarity.UNCOMMON, mage.cards.f.Fecundity.class)); + cards.add(new SetCardInfo("Fiend Hunter", 17, Rarity.UNCOMMON, mage.cards.f.FiendHunter.class)); + cards.add(new SetCardInfo("Fiery Temper", 129, Rarity.COMMON, mage.cards.f.FieryTemper.class)); + cards.add(new SetCardInfo("Fire // Ice", 225, Rarity.COMMON, mage.cards.f.FireIce.class)); + cards.add(new SetCardInfo("Firewing Phoenix", 130, Rarity.UNCOMMON, mage.cards.f.FirewingPhoenix.class)); + cards.add(new SetCardInfo("Flagstones of Trokair", 243, Rarity.RARE, mage.cards.f.FlagstonesOfTrokair.class)); + cards.add(new SetCardInfo("Flight of Fancy", 54, Rarity.COMMON, mage.cards.f.FlightOfFancy.class)); + cards.add(new SetCardInfo("Foil", 55, Rarity.COMMON, mage.cards.f.Foil.class)); + cards.add(new SetCardInfo("Forbidden Alchemy", 56, Rarity.UNCOMMON, mage.cards.f.ForbiddenAlchemy.class)); + cards.add(new SetCardInfo("Frantic Search", 57, Rarity.COMMON, mage.cards.f.FranticSearch.class)); + cards.add(new SetCardInfo("Fulminator Mage", 215, Rarity.RARE, mage.cards.f.FulminatorMage.class)); + cards.add(new SetCardInfo("Fume Spitter", 95, Rarity.COMMON, mage.cards.f.FumeSpitter.class)); + cards.add(new SetCardInfo("Furnace Celebration", 131, Rarity.UNCOMMON, mage.cards.f.FurnaceCelebration.class)); + cards.add(new SetCardInfo("Gaddock Teeg", 199, Rarity.RARE, mage.cards.g.GaddockTeeg.class)); + cards.add(new SetCardInfo("Gamble", 132, Rarity.RARE, mage.cards.g.Gamble.class)); + cards.add(new SetCardInfo("Garna, the Bloodflame", 200, Rarity.UNCOMMON, mage.cards.g.GarnaTheBloodflame.class)); + cards.add(new SetCardInfo("Generator Servant", 133, Rarity.COMMON, mage.cards.g.GeneratorServant.class)); + cards.add(new SetCardInfo("Ghoulcaller's Accomplice", 96, Rarity.COMMON, mage.cards.g.GhoulcallersAccomplice.class)); + cards.add(new SetCardInfo("Ghoulsteed", 97, Rarity.UNCOMMON, mage.cards.g.Ghoulsteed.class)); + cards.add(new SetCardInfo("Glen Elendra Archmage", 58, Rarity.RARE, mage.cards.g.GlenElendraArchmage.class)); + cards.add(new SetCardInfo("Gods Willing", 18, Rarity.COMMON, mage.cards.g.GodsWilling.class)); + cards.add(new SetCardInfo("Golgari Brownscale", 166, Rarity.COMMON, mage.cards.g.GolgariBrownscale.class)); + cards.add(new SetCardInfo("Golgari Charm", 201, Rarity.UNCOMMON, mage.cards.g.GolgariCharm.class)); + cards.add(new SetCardInfo("Golgari Grave-Troll", 167, Rarity.RARE, mage.cards.g.GolgariGraveTroll.class)); + cards.add(new SetCardInfo("Golgari Thug", 98, Rarity.UNCOMMON, mage.cards.g.GolgariThug.class)); + cards.add(new SetCardInfo("Goryo's Vengeance", 99, Rarity.RARE, mage.cards.g.GoryosVengeance.class)); + cards.add(new SetCardInfo("Grave Scrabbler", 100, Rarity.COMMON, mage.cards.g.GraveScrabbler.class)); + cards.add(new SetCardInfo("Grave Strength", 101, Rarity.UNCOMMON, mage.cards.g.GraveStrength.class)); + cards.add(new SetCardInfo("Groundskeeper", 168, Rarity.COMMON, mage.cards.g.Groundskeeper.class)); + cards.add(new SetCardInfo("Gurmag Angler", 102, Rarity.COMMON, mage.cards.g.GurmagAngler.class)); + cards.add(new SetCardInfo("Heap Doll", 228, Rarity.UNCOMMON, mage.cards.h.HeapDoll.class)); + cards.add(new SetCardInfo("Heliod's Pilgrim", 19, Rarity.COMMON, mage.cards.h.HeliodsPilgrim.class)); + cards.add(new SetCardInfo("Hero of Iroas", 20, Rarity.UNCOMMON, mage.cards.h.HeroOfIroas.class)); + cards.add(new SetCardInfo("Hero of Leina Tower", 169, Rarity.UNCOMMON, mage.cards.h.HeroOfLeinaTower.class)); + cards.add(new SetCardInfo("Hissing Iguanar", 134, Rarity.COMMON, mage.cards.h.HissingIguanar.class)); + cards.add(new SetCardInfo("Hooting Mandrills", 170, Rarity.COMMON, mage.cards.h.HootingMandrills.class)); + cards.add(new SetCardInfo("Hyena Umbra", 21, Rarity.COMMON, mage.cards.h.HyenaUmbra.class)); + cards.add(new SetCardInfo("Icatian Crier", 22, Rarity.COMMON, mage.cards.i.IcatianCrier.class)); + cards.add(new SetCardInfo("Ingot Chewer", 135, Rarity.COMMON, mage.cards.i.IngotChewer.class)); + cards.add(new SetCardInfo("Iridescent Drake", 59, Rarity.UNCOMMON, mage.cards.i.IridescentDrake.class)); + cards.add(new SetCardInfo("Just the Wind", 60, Rarity.COMMON, mage.cards.j.JustTheWind.class)); + cards.add(new SetCardInfo("Karakas", 244, Rarity.MYTHIC, mage.cards.k.Karakas.class)); + cards.add(new SetCardInfo("Karn Liberated", 5, Rarity.MYTHIC, mage.cards.k.KarnLiberated.class)); + cards.add(new SetCardInfo("Kitchen Finks", 216, Rarity.UNCOMMON, mage.cards.k.KitchenFinks.class)); + cards.add(new SetCardInfo("Kodama's Reach", 171, Rarity.COMMON, mage.cards.k.KodamasReach.class)); + cards.add(new SetCardInfo("Kozilek, Butcher of Truth", 6, Rarity.MYTHIC, mage.cards.k.KozilekButcherOfTruth.class)); + cards.add(new SetCardInfo("Laboratory Maniac", 61, Rarity.UNCOMMON, mage.cards.l.LaboratoryManiac.class)); + cards.add(new SetCardInfo("Last Gasp", 103, Rarity.COMMON, mage.cards.l.LastGasp.class)); + cards.add(new SetCardInfo("Lava Spike", 136, Rarity.UNCOMMON, mage.cards.l.LavaSpike.class)); + cards.add(new SetCardInfo("Lavaclaw Reaches", 245, Rarity.RARE, mage.cards.l.LavaclawReaches.class)); + cards.add(new SetCardInfo("Leovold, Emissary of Trest", 202, Rarity.MYTHIC, mage.cards.l.LeovoldEmissaryOfTrest.class)); + cards.add(new SetCardInfo("Life from the Loam", 172, Rarity.RARE, mage.cards.l.LifeFromTheLoam.class)); + cards.add(new SetCardInfo("Liliana of the Veil", 104, Rarity.MYTHIC, mage.cards.l.LilianaOfTheVeil.class)); + cards.add(new SetCardInfo("Living Lore", 62, Rarity.UNCOMMON, mage.cards.l.LivingLore.class)); + cards.add(new SetCardInfo("Lord of Extinction", 203, Rarity.MYTHIC, mage.cards.l.LordOfExtinction.class)); + cards.add(new SetCardInfo("Lotus-Eye Mystics", 23, Rarity.COMMON, mage.cards.l.LotusEyeMystics.class)); + cards.add(new SetCardInfo("Mad Prophet", 137, Rarity.COMMON, mage.cards.m.MadProphet.class)); + cards.add(new SetCardInfo("Maelstrom Pulse", 204, Rarity.RARE, mage.cards.m.MaelstromPulse.class)); + cards.add(new SetCardInfo("Mage-Ring Network", 246, Rarity.UNCOMMON, mage.cards.m.MageRingNetwork.class)); + cards.add(new SetCardInfo("Magmaw", 138, Rarity.UNCOMMON, mage.cards.m.Magmaw.class)); + cards.add(new SetCardInfo("Magus of the Bazaar", 63, Rarity.RARE, mage.cards.m.MagusOfTheBazaar.class)); + cards.add(new SetCardInfo("Mahamoti Djinn", 64, Rarity.UNCOMMON, mage.cards.m.MahamotiDjinn.class)); + cards.add(new SetCardInfo("Malevolent Whispers", 139, Rarity.UNCOMMON, mage.cards.m.MalevolentWhispers.class)); + cards.add(new SetCardInfo("Mammoth Umbra", 24, Rarity.COMMON, mage.cards.m.MammothUmbra.class)); + cards.add(new SetCardInfo("Mana Vault", 229, Rarity.MYTHIC, mage.cards.m.ManaVault.class)); + cards.add(new SetCardInfo("Marang River Prowler", 65, Rarity.UNCOMMON, mage.cards.m.MarangRiverProwler.class)); + cards.add(new SetCardInfo("Mark of the Vampire", 105, Rarity.COMMON, mage.cards.m.MarkOfTheVampire.class)); + cards.add(new SetCardInfo("Martyr of Sands", 25, Rarity.COMMON, mage.cards.m.MartyrOfSands.class)); + cards.add(new SetCardInfo("Mikaeus, the Unhallowed", 106, Rarity.MYTHIC, mage.cards.m.MikaeusTheUnhallowed.class)); + cards.add(new SetCardInfo("Miming Slime", 173, Rarity.COMMON, mage.cards.m.MimingSlime.class)); + cards.add(new SetCardInfo("Miraculous Recovery", 26, Rarity.UNCOMMON, mage.cards.m.MiraculousRecovery.class)); + cards.add(new SetCardInfo("Mistveil Plains", 247, Rarity.UNCOMMON, mage.cards.m.MistveilPlains.class)); + cards.add(new SetCardInfo("Moan of the Unhallowed", 107, Rarity.COMMON, mage.cards.m.MoanOfTheUnhallowed.class)); + cards.add(new SetCardInfo("Molten Birth", 140, Rarity.COMMON, mage.cards.m.MoltenBirth.class)); + cards.add(new SetCardInfo("Murderous Redcap", 217, Rarity.UNCOMMON, mage.cards.m.MurderousRedcap.class)); + cards.add(new SetCardInfo("Myr Servitor", 230, Rarity.COMMON, mage.cards.m.MyrServitor.class)); + cards.add(new SetCardInfo("Mystic Retrieval", 66, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class)); + cards.add(new SetCardInfo("Nightbird's Clutches", 141, Rarity.COMMON, mage.cards.n.NightbirdsClutches.class)); + cards.add(new SetCardInfo("Noble Hierarch", 174, Rarity.RARE, mage.cards.n.NobleHierarch.class)); + cards.add(new SetCardInfo("Nourishing Shoal", 175, Rarity.RARE, mage.cards.n.NourishingShoal.class)); + cards.add(new SetCardInfo("Offalsnout", 108, Rarity.COMMON, mage.cards.o.Offalsnout.class)); + cards.add(new SetCardInfo("Olivia's Dragoon", 109, Rarity.COMMON, mage.cards.o.OliviasDragoon.class)); + cards.add(new SetCardInfo("Patchwork Gnomes", 231, Rarity.COMMON, mage.cards.p.PatchworkGnomes.class)); + cards.add(new SetCardInfo("Pattern of Rebirth", 176, Rarity.RARE, mage.cards.p.PatternOfRebirth.class)); + cards.add(new SetCardInfo("Penumbra Wurm", 177, Rarity.UNCOMMON, mage.cards.p.PenumbraWurm.class)); + cards.add(new SetCardInfo("Phalanx Leader", 27, Rarity.UNCOMMON, mage.cards.p.PhalanxLeader.class)); + cards.add(new SetCardInfo("Phyrexian Altar", 232, Rarity.RARE, mage.cards.p.PhyrexianAltar.class)); + cards.add(new SetCardInfo("Phyrexian Tower", 248, Rarity.RARE, mage.cards.p.PhyrexianTower.class)); + cards.add(new SetCardInfo("Platinum Emperion", 233, Rarity.MYTHIC, mage.cards.p.PlatinumEmperion.class)); + cards.add(new SetCardInfo("Plumeveil", 218, Rarity.UNCOMMON, mage.cards.p.Plumeveil.class)); + cards.add(new SetCardInfo("Prey Upon", 178, Rarity.COMMON, mage.cards.p.PreyUpon.class)); + cards.add(new SetCardInfo("Prismatic Lens", 234, Rarity.UNCOMMON, mage.cards.p.PrismaticLens.class)); + cards.add(new SetCardInfo("Pulse of Murasa", 179, Rarity.COMMON, mage.cards.p.PulseOfMurasa.class)); + cards.add(new SetCardInfo("Raging Ravine", 249, Rarity.RARE, mage.cards.r.RagingRavine.class)); + cards.add(new SetCardInfo("Raid Bombardment", 142, Rarity.COMMON, mage.cards.r.RaidBombardment.class)); + cards.add(new SetCardInfo("Rakdos Shred-Freak", 219, Rarity.COMMON, mage.cards.r.RakdosShredFreak.class)); + cards.add(new SetCardInfo("Rally the Peasants", 28, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class)); + cards.add(new SetCardInfo("Reanimate", 110, Rarity.RARE, mage.cards.r.Reanimate.class)); + cards.add(new SetCardInfo("Reckless Charge", 143, Rarity.COMMON, mage.cards.r.RecklessCharge.class)); + cards.add(new SetCardInfo("Reckless Wurm", 144, Rarity.COMMON, mage.cards.r.RecklessWurm.class)); + cards.add(new SetCardInfo("Repel the Darkness", 29, Rarity.COMMON, mage.cards.r.RepelTheDarkness.class)); + cards.add(new SetCardInfo("Resurrection", 30, Rarity.COMMON, mage.cards.r.Resurrection.class)); + cards.add(new SetCardInfo("Reveillark", 31, Rarity.RARE, mage.cards.r.Reveillark.class)); + cards.add(new SetCardInfo("Reviving Vapors", 205, Rarity.UNCOMMON, mage.cards.r.RevivingVapors.class)); + cards.add(new SetCardInfo("Reya Dawnbringer", 32, Rarity.RARE, mage.cards.r.ReyaDawnbringer.class)); + cards.add(new SetCardInfo("Rise from the Tides", 67, Rarity.UNCOMMON, mage.cards.r.RiseFromTheTides.class)); + cards.add(new SetCardInfo("Rogue's Passage", 250, Rarity.UNCOMMON, mage.cards.r.RoguesPassage.class)); + cards.add(new SetCardInfo("Rolling Temblor", 145, Rarity.UNCOMMON, mage.cards.r.RollingTemblor.class)); + cards.add(new SetCardInfo("Ronom Unicorn", 33, Rarity.COMMON, mage.cards.r.RonomUnicorn.class)); + cards.add(new SetCardInfo("Rune Snag", 68, Rarity.COMMON, mage.cards.r.RuneSnag.class)); + cards.add(new SetCardInfo("Runed Halo", 34, Rarity.RARE, mage.cards.r.RunedHalo.class)); + cards.add(new SetCardInfo("Safehold Elite", 220, Rarity.COMMON, mage.cards.s.SafeholdElite.class)); + cards.add(new SetCardInfo("Sanitarium Skeleton", 111, Rarity.COMMON, mage.cards.s.SanitariumSkeleton.class)); + cards.add(new SetCardInfo("Satyr Wayfinder", 180, Rarity.COMMON, mage.cards.s.SatyrWayfinder.class)); + cards.add(new SetCardInfo("Scuzzback Marauders", 221, Rarity.COMMON, mage.cards.s.ScuzzbackMarauders.class)); + cards.add(new SetCardInfo("Seismic Assault", 146, Rarity.RARE, mage.cards.s.SeismicAssault.class)); + cards.add(new SetCardInfo("Seize the Day", 147, Rarity.RARE, mage.cards.s.SeizeTheDay.class)); + cards.add(new SetCardInfo("Shed Weakness", 181, Rarity.COMMON, mage.cards.s.ShedWeakness.class)); + cards.add(new SetCardInfo("Shielding Plax", 222, Rarity.COMMON, mage.cards.s.ShieldingPlax.class)); + cards.add(new SetCardInfo("Shirei, Shizo's Caretaker", 112, Rarity.UNCOMMON, mage.cards.s.ShireiShizosCaretaker.class)); + cards.add(new SetCardInfo("Shriekmaw", 113, Rarity.UNCOMMON, mage.cards.s.Shriekmaw.class)); + cards.add(new SetCardInfo("Sigarda, Host of Herons", 206, Rarity.MYTHIC, mage.cards.s.SigardaHostOfHerons.class)); + cards.add(new SetCardInfo("Sigil of the New Dawn", 35, Rarity.UNCOMMON, mage.cards.s.SigilOfTheNewDawn.class)); + cards.add(new SetCardInfo("Skyspear Cavalry", 36, Rarity.COMMON, mage.cards.s.SkyspearCavalry.class)); + cards.add(new SetCardInfo("Skywing Aven", 69, Rarity.COMMON, mage.cards.s.SkywingAven.class)); + cards.add(new SetCardInfo("Sleight of Hand", 70, Rarity.UNCOMMON, mage.cards.s.SleightOfHand.class)); + cards.add(new SetCardInfo("Slippery Bogle", 223, Rarity.UNCOMMON, mage.cards.s.SlipperyBogle.class)); + cards.add(new SetCardInfo("Slum Reaper", 114, Rarity.COMMON, mage.cards.s.SlumReaper.class)); + cards.add(new SetCardInfo("Snake Umbra", 182, Rarity.UNCOMMON, mage.cards.s.SnakeUmbra.class)); + cards.add(new SetCardInfo("Snapcaster Mage", 71, Rarity.MYTHIC, mage.cards.s.SnapcasterMage.class)); + cards.add(new SetCardInfo("Songs of the Damned", 115, Rarity.UNCOMMON, mage.cards.s.SongsOfTheDamned.class)); + cards.add(new SetCardInfo("Soul's Fire", 148, Rarity.COMMON, mage.cards.s.SoulsFire.class)); + cards.add(new SetCardInfo("Sovereigns of Lost Alara", 207, Rarity.RARE, mage.cards.s.SovereignsOfLostAlara.class)); + cards.add(new SetCardInfo("Sparkspitter", 149, Rarity.COMMON, mage.cards.s.Sparkspitter.class)); + cards.add(new SetCardInfo("Spider Spawning", 183, Rarity.UNCOMMON, mage.cards.s.SpiderSpawning.class)); + cards.add(new SetCardInfo("Spider Umbra", 184, Rarity.COMMON, mage.cards.s.SpiderUmbra.class)); + cards.add(new SetCardInfo("Spirit Cairn", 37, Rarity.UNCOMMON, mage.cards.s.SpiritCairn.class)); + cards.add(new SetCardInfo("Spoils of the Vault", 116, Rarity.RARE, mage.cards.s.SpoilsOfTheVault.class)); + cards.add(new SetCardInfo("Squee, Goblin Nabob", 150, Rarity.RARE, mage.cards.s.SqueeGoblinNabob.class)); + cards.add(new SetCardInfo("Staunch-Hearted Warrior", 185, Rarity.COMMON, mage.cards.s.StaunchHeartedWarrior.class)); + cards.add(new SetCardInfo("Stingerfling Spider", 186, Rarity.UNCOMMON, mage.cards.s.StingerflingSpider.class)); + cards.add(new SetCardInfo("Stirring Wildwood", 251, Rarity.RARE, mage.cards.s.StirringWildwood.class)); + cards.add(new SetCardInfo("Stitched Drake", 72, Rarity.COMMON, mage.cards.s.StitchedDrake.class)); + cards.add(new SetCardInfo("Stitcher's Apprentice", 73, Rarity.COMMON, mage.cards.s.StitchersApprentice.class)); + cards.add(new SetCardInfo("Stream of Consciousness", 74, Rarity.UNCOMMON, mage.cards.s.StreamOfConsciousness.class)); + cards.add(new SetCardInfo("Sublime Archangel", 38, Rarity.RARE, mage.cards.s.SublimeArchangel.class)); + cards.add(new SetCardInfo("Sultai Skullkeeper", 75, Rarity.COMMON, mage.cards.s.SultaiSkullkeeper.class)); + cards.add(new SetCardInfo("Swift Reckoning", 39, Rarity.UNCOMMON, mage.cards.s.SwiftReckoning.class)); + cards.add(new SetCardInfo("Talrand, Sky Summoner", 76, Rarity.RARE, mage.cards.t.TalrandSkySummoner.class)); + cards.add(new SetCardInfo("Tarmogoyf", 187, Rarity.MYTHIC, mage.cards.t.Tarmogoyf.class)); + cards.add(new SetCardInfo("Tasigur, the Golden Fang", 117, Rarity.RARE, mage.cards.t.TasigurTheGoldenFang.class)); + cards.add(new SetCardInfo("Temporal Manipulation", 77, Rarity.MYTHIC, mage.cards.t.TemporalManipulation.class)); + cards.add(new SetCardInfo("Terramorphic Expanse", 252, Rarity.COMMON, mage.cards.t.TerramorphicExpanse.class)); + cards.add(new SetCardInfo("Tethmos High Priest", 40, Rarity.COMMON, mage.cards.t.TethmosHighPriest.class)); + cards.add(new SetCardInfo("Thermo-Alchemist", 151, Rarity.COMMON, mage.cards.t.ThermoAlchemist.class)); + cards.add(new SetCardInfo("Thespian's Stage", 253, Rarity.RARE, mage.cards.t.ThespiansStage.class)); + cards.add(new SetCardInfo("Think Twice", 78, Rarity.COMMON, mage.cards.t.ThinkTwice.class)); + cards.add(new SetCardInfo("Through the Breach", 152, Rarity.RARE, mage.cards.t.ThroughTheBreach.class)); + cards.add(new SetCardInfo("Travel Preparations", 188, Rarity.UNCOMMON, mage.cards.t.TravelPreparations.class)); + cards.add(new SetCardInfo("Treasure Cruise", 79, Rarity.COMMON, mage.cards.t.TreasureCruise.class)); + cards.add(new SetCardInfo("Turn to Mist", 224, Rarity.COMMON, mage.cards.t.TurnToMist.class)); + cards.add(new SetCardInfo("Twins of Maurer Estate", 118, Rarity.COMMON, mage.cards.t.TwinsOfMaurerEstate.class)); + cards.add(new SetCardInfo("Ulamog's Crusher", 8, Rarity.COMMON, mage.cards.u.UlamogsCrusher.class)); + cards.add(new SetCardInfo("Ulamog, the Infinite Gyre", 7, Rarity.MYTHIC, mage.cards.u.UlamogTheInfiniteGyre.class)); + cards.add(new SetCardInfo("Unburial Rites", 119, Rarity.UNCOMMON, mage.cards.u.UnburialRites.class)); + cards.add(new SetCardInfo("Undying Rage", 153, Rarity.COMMON, mage.cards.u.UndyingRage.class)); + cards.add(new SetCardInfo("Unholy Hunger", 120, Rarity.COMMON, mage.cards.u.UnholyHunger.class)); + cards.add(new SetCardInfo("Unstable Mutation", 80, Rarity.UNCOMMON, mage.cards.u.UnstableMutation.class)); + cards.add(new SetCardInfo("Urban Evolution", 208, Rarity.UNCOMMON, mage.cards.u.UrbanEvolution.class)); + cards.add(new SetCardInfo("Urborg, Tomb of Yawgmoth", 254, Rarity.RARE, mage.cards.u.UrborgTombOfYawgmoth.class)); + cards.add(new SetCardInfo("Vengeful Rebirth", 209, Rarity.UNCOMMON, mage.cards.v.VengefulRebirth.class)); + cards.add(new SetCardInfo("Vengevine", 189, Rarity.MYTHIC, mage.cards.v.Vengevine.class)); + cards.add(new SetCardInfo("Verdant Eidolon", 190, Rarity.COMMON, mage.cards.v.VerdantEidolon.class)); + cards.add(new SetCardInfo("Vessel of Endless Rest", 235, Rarity.COMMON, mage.cards.v.VesselOfEndlessRest.class)); + cards.add(new SetCardInfo("Vexing Devil", 154, Rarity.RARE, mage.cards.v.VexingDevil.class)); + cards.add(new SetCardInfo("Visions of Beyond", 81, Rarity.RARE, mage.cards.v.VisionsOfBeyond.class)); + cards.add(new SetCardInfo("Walker of the Grove", 191, Rarity.COMMON, mage.cards.w.WalkerOfTheGrove.class)); + cards.add(new SetCardInfo("Wall of Reverence", 41, Rarity.RARE, mage.cards.w.WallOfReverence.class)); + cards.add(new SetCardInfo("Wandering Champion", 42, Rarity.COMMON, mage.cards.w.WanderingChampion.class)); + cards.add(new SetCardInfo("Warleader's Helix", 210, Rarity.UNCOMMON, mage.cards.w.WarleadersHelix.class)); + cards.add(new SetCardInfo("Whirlwind Adept", 82, Rarity.COMMON, mage.cards.w.WhirlwindAdept.class)); + cards.add(new SetCardInfo("Wickerbough Elder", 192, Rarity.COMMON, mage.cards.w.WickerboughElder.class)); + cards.add(new SetCardInfo("Wild Hunger", 193, Rarity.UNCOMMON, mage.cards.w.WildHunger.class)); + cards.add(new SetCardInfo("Wild Mongrel", 194, Rarity.COMMON, mage.cards.w.WildMongrel.class)); + cards.add(new SetCardInfo("Wingsteed Rider", 43, Rarity.COMMON, mage.cards.w.WingsteedRider.class)); + cards.add(new SetCardInfo("Woodfall Primus", 195, Rarity.RARE, mage.cards.w.WoodfallPrimus.class)); + cards.add(new SetCardInfo("Young Pyromancer", 155, Rarity.UNCOMMON, mage.cards.y.YoungPyromancer.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Unglued.java b/Mage.Sets/src/mage/sets/Unglued.java index b432e5833f..bfda5c412e 100644 --- a/Mage.Sets/src/mage/sets/Unglued.java +++ b/Mage.Sets/src/mage/sets/Unglued.java @@ -39,12 +39,14 @@ public final class Unglued extends ExpansionSet { cards.add(new SetCardInfo("Growth Spurt", 61, Rarity.COMMON, mage.cards.g.GrowthSpurt.class)); cards.add(new SetCardInfo("Hungry Hungry Heifer", 63, Rarity.UNCOMMON, mage.cards.h.HungryHungryHeifer.class)); cards.add(new SetCardInfo("Incoming!", 64, Rarity.RARE, mage.cards.i.Incoming.class)); + cards.add(new SetCardInfo("Infernal Spawn of Evil", 33, Rarity.RARE, mage.cards.i.InfernalSpawnOfEvil.class)); cards.add(new SetCardInfo("Island", 85, Rarity.LAND, mage.cards.basiclands.Island.class, new CardGraphicInfo(FrameStyle.UGL_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Jack-in-the-Mox", 75, Rarity.RARE, mage.cards.j.JackInTheMox.class)); cards.add(new SetCardInfo("Jalum Grifter", 47, Rarity.RARE, mage.cards.j.JalumGrifter.class)); cards.add(new SetCardInfo("Jumbo Imp", 34, Rarity.UNCOMMON, mage.cards.j.JumboImp.class)); cards.add(new SetCardInfo("Krazy Kow", 48, Rarity.COMMON, mage.cards.k.KrazyKow.class)); cards.add(new SetCardInfo("Mine, Mine, Mine!", 65, Rarity.RARE, mage.cards.m.MineMineMine.class)); + cards.add(new SetCardInfo("Miss Demeanor", 10, Rarity.UNCOMMON, mage.cards.m.MissDemeanor.class)); cards.add(new SetCardInfo("Mountain", 87, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.UGL_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Once More with Feeling", 11, Rarity.RARE, mage.cards.o.OnceMoreWithFeeling.class)); cards.add(new SetCardInfo("Paper Tiger", 78, Rarity.COMMON, mage.cards.p.PaperTiger.class)); diff --git a/Mage.Sets/src/mage/sets/Unhinged.java b/Mage.Sets/src/mage/sets/Unhinged.java index 9a927bad34..8e3e0bdeb5 100644 --- a/Mage.Sets/src/mage/sets/Unhinged.java +++ b/Mage.Sets/src/mage/sets/Unhinged.java @@ -27,6 +27,7 @@ public final class Unhinged extends ExpansionSet { cards.add(new SetCardInfo("Bloodletter", 50, Rarity.COMMON, mage.cards.b.Bloodletter.class)); cards.add(new SetCardInfo("Booster Tutor", 51, Rarity.UNCOMMON, mage.cards.b.BoosterTutor.class)); cards.add(new SetCardInfo("Double Header", 31, Rarity.COMMON, mage.cards.d.DoubleHeader.class)); + cards.add(new SetCardInfo("Elvish House Party", 94, Rarity.UNCOMMON, mage.cards.e.ElvishHouseParty.class)); cards.add(new SetCardInfo("First Come, First Served", 12, Rarity.UNCOMMON, mage.cards.f.FirstComeFirstServed.class)); cards.add(new SetCardInfo("Forest", 140, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Form of the Squirrel", 96, Rarity.RARE, mage.cards.f.FormOfTheSquirrel.class)); @@ -39,8 +40,10 @@ public final class Unhinged extends ExpansionSet { cards.add(new SetCardInfo("Mountain", 139, Rarity.LAND, mage.cards.basiclands.Mountain.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Mox Lotus", 124, Rarity.RARE, mage.cards.m.MoxLotus.class)); cards.add(new SetCardInfo("Now I Know My ABC's", 41, Rarity.RARE, mage.cards.n.NowIKnowMyABCs.class)); + cards.add(new SetCardInfo("Old Fogey", 106, Rarity.RARE, mage.cards.o.OldFogey.class)); cards.add(new SetCardInfo("Plains", 136, Rarity.LAND, mage.cards.basiclands.Plains.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Rare-B-Gone", 119, Rarity.RARE, mage.cards.r.RareBGone.class)); + cards.add(new SetCardInfo("Rod of Spanking", 127, Rarity.UNCOMMON, mage.cards.r.RodOfSpanking.class)); cards.add(new SetCardInfo("Six-y Beast", 89, Rarity.UNCOMMON, mage.cards.s.SixyBeast.class)); cards.add(new SetCardInfo("Swamp", 138, Rarity.LAND, mage.cards.basiclands.Swamp.class, new CardGraphicInfo(FrameStyle.UNH_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("Symbol Status", 114, Rarity.UNCOMMON, mage.cards.s.SymbolStatus.class)); diff --git a/Mage.Sets/src/mage/sets/Unstable.java b/Mage.Sets/src/mage/sets/Unstable.java index 83d3a8dd3a..5b874239b1 100644 --- a/Mage.Sets/src/mage/sets/Unstable.java +++ b/Mage.Sets/src/mage/sets/Unstable.java @@ -42,9 +42,13 @@ public final class Unstable extends ExpansionSet { cards.add(new SetCardInfo("Dr. Julius Jumblemorph", 130, Rarity.MYTHIC, mage.cards.d.DrJuliusJumblemorph.class)); cards.add(new SetCardInfo("Enraged Killbot", "145d", Rarity.COMMON, mage.cards.e.EnragedKillbot.class)); cards.add(new SetCardInfo("Earl of Squirrel", 108, Rarity.RARE, mage.cards.e.EarlOfSquirrel.class)); + cards.add(new SetCardInfo("Everythingamajig", "147b", Rarity.UNCOMMON, mage.cards.e.EverythingamajigB.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Everythingamajig", "147c", Rarity.UNCOMMON, mage.cards.e.EverythingamajigC.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Everythingamajig", "147e", Rarity.UNCOMMON, mage.cards.e.EverythingamajigE.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 216, Rarity.LAND, mage.cards.basiclands.Forest.class, new CardGraphicInfo(FrameStyle.UST_FULL_ART_BASIC, false))); cards.add(new SetCardInfo("GO TO JAIL", 8, Rarity.COMMON, mage.cards.g.GOTOJAIL.class)); - cards.add(new SetCardInfo("Garbage Elemental", "82c", Rarity.UNCOMMON, mage.cards.g.GarbageElementalC.class)); + cards.add(new SetCardInfo("Garbage Elemental", "82c", Rarity.UNCOMMON, mage.cards.g.GarbageElementalC.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Garbage Elemental", "82d", Rarity.UNCOMMON, mage.cards.g.GarbageElementalD.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Ground Pounder", 110, Rarity.COMMON, mage.cards.g.GroundPounder.class)); cards.add(new SetCardInfo("Hammer Helper", 85, Rarity.COMMON, mage.cards.h.HammerHelper.class)); cards.add(new SetCardInfo("Hammer Jammer", 86, Rarity.UNCOMMON, mage.cards.h.HammerJammer.class)); @@ -76,6 +80,7 @@ public final class Unstable extends ExpansionSet { cards.add(new SetCardInfo("Target Minotaur", "98d", Rarity.COMMON, mage.cards.t.TargetMinotaur.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("The Big Idea", 76, Rarity.RARE, mage.cards.t.TheBigIdea.class)); cards.add(new SetCardInfo("Time Out", 48, Rarity.COMMON, mage.cards.t.TimeOut.class)); + cards.add(new SetCardInfo("Urza, Academy Headmaster", 136, Rarity.MYTHIC, mage.cards.u.UrzaAcademyHeadmaster.class)); cards.add(new SetCardInfo("Very Cryptic Command", "49d", Rarity.RARE, mage.cards.v.VeryCrypticCommandD.class)); cards.add(new SetCardInfo("Willing Test Subject", 126, Rarity.COMMON, mage.cards.w.WillingTestSubject.class)); cards.add(new SetCardInfo("capital offense", 52, Rarity.COMMON, mage.cards.c.CapitalOffense.class)); diff --git a/Mage.Sets/src/mage/sets/UrzasDestiny.java b/Mage.Sets/src/mage/sets/UrzasDestiny.java index 17e0fd38ed..aae8ca309c 100644 --- a/Mage.Sets/src/mage/sets/UrzasDestiny.java +++ b/Mage.Sets/src/mage/sets/UrzasDestiny.java @@ -1,166 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author Backfir3 - */ -public final class UrzasDestiny extends ExpansionSet { - - private static final UrzasDestiny instance = new UrzasDestiny(); - - public static UrzasDestiny getInstance() { - return instance; - } - - private UrzasDestiny() { - super("Urza's Destiny", "UDS", ExpansionSet.buildDate(1999, 6, 7), SetType.EXPANSION); - this.blockName = "Urza"; - this.parentSet = UrzasSaga.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Academy Rector", 1, Rarity.RARE, mage.cards.a.AcademyRector.class)); - cards.add(new SetCardInfo("Aether Sting", 76, Rarity.UNCOMMON, mage.cards.a.AetherSting.class)); - cards.add(new SetCardInfo("Ancient Silverback", 101, Rarity.RARE, mage.cards.a.AncientSilverback.class)); - cards.add(new SetCardInfo("Apprentice Necromancer", 51, Rarity.RARE, mage.cards.a.ApprenticeNecromancer.class)); - cards.add(new SetCardInfo("Attrition", 52, Rarity.RARE, mage.cards.a.Attrition.class)); - cards.add(new SetCardInfo("Aura Thief", 26, Rarity.RARE, mage.cards.a.AuraThief.class)); - cards.add(new SetCardInfo("Blizzard Elemental", 27, Rarity.RARE, mage.cards.b.BlizzardElemental.class)); - cards.add(new SetCardInfo("Bloodshot Cyclops", 77, Rarity.RARE, mage.cards.b.BloodshotCyclops.class)); - cards.add(new SetCardInfo("Body Snatcher", 53, Rarity.RARE, mage.cards.b.BodySnatcher.class)); - cards.add(new SetCardInfo("Braidwood Cup", 126, Rarity.UNCOMMON, mage.cards.b.BraidwoodCup.class)); - cards.add(new SetCardInfo("Braidwood Sextant", 127, Rarity.UNCOMMON, mage.cards.b.BraidwoodSextant.class)); - cards.add(new SetCardInfo("Brass Secretary", 128, Rarity.UNCOMMON, mage.cards.b.BrassSecretary.class)); - cards.add(new SetCardInfo("Brine Seer", 28, Rarity.UNCOMMON, mage.cards.b.BrineSeer.class)); - cards.add(new SetCardInfo("Bubbling Beebles", 29, Rarity.COMMON, mage.cards.b.BubblingBeebles.class)); - cards.add(new SetCardInfo("Bubbling Muck", 54, Rarity.COMMON, mage.cards.b.BubblingMuck.class)); - cards.add(new SetCardInfo("Caltrops", 129, Rarity.UNCOMMON, mage.cards.c.Caltrops.class)); - cards.add(new SetCardInfo("Capashen Knight", 3, Rarity.COMMON, mage.cards.c.CapashenKnight.class)); - cards.add(new SetCardInfo("Capashen Standard", 4, Rarity.COMMON, mage.cards.c.CapashenStandard.class)); - cards.add(new SetCardInfo("Capashen Templar", 5, Rarity.COMMON, mage.cards.c.CapashenTemplar.class)); - cards.add(new SetCardInfo("Carnival of Souls", 55, Rarity.RARE, mage.cards.c.CarnivalOfSouls.class)); - cards.add(new SetCardInfo("Chime of Night", 56, Rarity.COMMON, mage.cards.c.ChimeOfNight.class)); - cards.add(new SetCardInfo("Cinder Seer", 78, Rarity.UNCOMMON, mage.cards.c.CinderSeer.class)); - cards.add(new SetCardInfo("Colos Yearling", 79, Rarity.COMMON, mage.cards.c.ColosYearling.class)); - cards.add(new SetCardInfo("Compost", 102, Rarity.UNCOMMON, mage.cards.c.Compost.class)); - cards.add(new SetCardInfo("Covetous Dragon", 80, Rarity.RARE, mage.cards.c.CovetousDragon.class)); - cards.add(new SetCardInfo("Disease Carriers", 57, Rarity.COMMON, mage.cards.d.DiseaseCarriers.class)); - cards.add(new SetCardInfo("Donate", 31, Rarity.RARE, mage.cards.d.Donate.class)); - cards.add(new SetCardInfo("Dying Wail", 58, Rarity.COMMON, mage.cards.d.DyingWail.class)); - cards.add(new SetCardInfo("Elvish Lookout", 103, Rarity.COMMON, mage.cards.e.ElvishLookout.class)); - cards.add(new SetCardInfo("Elvish Piper", 104, Rarity.RARE, mage.cards.e.ElvishPiper.class)); - cards.add(new SetCardInfo("Emperor Crocodile", 105, Rarity.RARE, mage.cards.e.EmperorCrocodile.class)); - cards.add(new SetCardInfo("Encroach", 59, Rarity.UNCOMMON, mage.cards.e.Encroach.class)); - cards.add(new SetCardInfo("Eradicate", 60, Rarity.UNCOMMON, mage.cards.e.Eradicate.class)); - cards.add(new SetCardInfo("Extruder", 130, Rarity.UNCOMMON, mage.cards.e.Extruder.class)); - cards.add(new SetCardInfo("False Prophet", 6, Rarity.RARE, mage.cards.f.FalseProphet.class)); - cards.add(new SetCardInfo("Festering Wound", 61, Rarity.UNCOMMON, mage.cards.f.FesteringWound.class)); - cards.add(new SetCardInfo("Field Surgeon", 8, Rarity.COMMON, mage.cards.f.FieldSurgeon.class)); - cards.add(new SetCardInfo("Flame Jet", 81, Rarity.COMMON, mage.cards.f.FlameJet.class)); - cards.add(new SetCardInfo("Fledgling Osprey", 33, Rarity.COMMON, mage.cards.f.FledglingOsprey.class)); - cards.add(new SetCardInfo("Flicker", 9, Rarity.RARE, mage.cards.f.Flicker.class)); - cards.add(new SetCardInfo("Fodder Cannon", 131, Rarity.UNCOMMON, mage.cards.f.FodderCannon.class)); - cards.add(new SetCardInfo("Gamekeeper", 106, Rarity.UNCOMMON, mage.cards.g.Gamekeeper.class)); - cards.add(new SetCardInfo("Goblin Berserker", 82, Rarity.UNCOMMON, mage.cards.g.GoblinBerserker.class)); - cards.add(new SetCardInfo("Goblin Festival", 83, Rarity.RARE, mage.cards.g.GoblinFestival.class)); - cards.add(new SetCardInfo("Goblin Gardener", 84, Rarity.COMMON, mage.cards.g.GoblinGardener.class)); - cards.add(new SetCardInfo("Goblin Marshal", 85, Rarity.RARE, mage.cards.g.GoblinMarshal.class)); - cards.add(new SetCardInfo("Goblin Masons", 86, Rarity.COMMON, mage.cards.g.GoblinMasons.class)); - cards.add(new SetCardInfo("Goliath Beetle", 107, Rarity.COMMON, mage.cards.g.GoliathBeetle.class)); - cards.add(new SetCardInfo("Heart Warden", 108, Rarity.COMMON, mage.cards.h.HeartWarden.class)); - cards.add(new SetCardInfo("Hulking Ogre", 87, Rarity.COMMON, mage.cards.h.HulkingOgre.class)); - cards.add(new SetCardInfo("Hunting Moa", 109, Rarity.UNCOMMON, mage.cards.h.HuntingMoa.class)); - cards.add(new SetCardInfo("Illuminated Wings", 34, Rarity.COMMON, mage.cards.i.IlluminatedWings.class)); - cards.add(new SetCardInfo("Impatience", 88, Rarity.RARE, mage.cards.i.Impatience.class)); - cards.add(new SetCardInfo("Iridescent Drake", 35, Rarity.UNCOMMON, mage.cards.i.IridescentDrake.class)); - cards.add(new SetCardInfo("Ivy Seer", 110, Rarity.UNCOMMON, mage.cards.i.IvySeer.class)); - cards.add(new SetCardInfo("Jasmine Seer", 10, Rarity.UNCOMMON, mage.cards.j.JasmineSeer.class)); - cards.add(new SetCardInfo("Junk Diver", 132, Rarity.RARE, mage.cards.j.JunkDiver.class)); - cards.add(new SetCardInfo("Keldon Champion", 90, Rarity.UNCOMMON, mage.cards.k.KeldonChampion.class)); - cards.add(new SetCardInfo("Keldon Vandals", 91, Rarity.COMMON, mage.cards.k.KeldonVandals.class)); - cards.add(new SetCardInfo("Kingfisher", 36, Rarity.COMMON, mage.cards.k.Kingfisher.class)); - cards.add(new SetCardInfo("Landslide", 92, Rarity.UNCOMMON, mage.cards.l.Landslide.class)); - cards.add(new SetCardInfo("Magnify", 111, Rarity.COMMON, mage.cards.m.Magnify.class)); - cards.add(new SetCardInfo("Mantis Engine", 133, Rarity.UNCOMMON, mage.cards.m.MantisEngine.class)); - cards.add(new SetCardInfo("Marker Beetles", 112, Rarity.COMMON, mage.cards.m.MarkerBeetles.class)); - cards.add(new SetCardInfo("Mark of Fury", 93, Rarity.COMMON, mage.cards.m.MarkOfFury.class)); - cards.add(new SetCardInfo("Mask of Law and Grace", 11, Rarity.COMMON, mage.cards.m.MaskOfLawAndGrace.class)); - cards.add(new SetCardInfo("Master Healer", 12, Rarity.RARE, mage.cards.m.MasterHealer.class)); - cards.add(new SetCardInfo("Masticore", 134, Rarity.RARE, mage.cards.m.Masticore.class)); - cards.add(new SetCardInfo("Mental Discipline", 37, Rarity.COMMON, mage.cards.m.MentalDiscipline.class)); - cards.add(new SetCardInfo("Metalworker", 135, Rarity.RARE, mage.cards.m.Metalworker.class)); - cards.add(new SetCardInfo("Metathran Soldier", 39, Rarity.COMMON, mage.cards.m.MetathranSoldier.class)); - cards.add(new SetCardInfo("Momentum", 113, Rarity.UNCOMMON, mage.cards.m.Momentum.class)); - cards.add(new SetCardInfo("Multani's Decree", 114, Rarity.COMMON, mage.cards.m.MultanisDecree.class)); - cards.add(new SetCardInfo("Nightshade Seer", 63, Rarity.UNCOMMON, mage.cards.n.NightshadeSeer.class)); - cards.add(new SetCardInfo("Opalescence", 13, Rarity.RARE, mage.cards.o.Opalescence.class)); - cards.add(new SetCardInfo("Opposition", 40, Rarity.RARE, mage.cards.o.Opposition.class)); - cards.add(new SetCardInfo("Pattern of Rebirth", 115, Rarity.RARE, mage.cards.p.PatternOfRebirth.class)); - cards.add(new SetCardInfo("Phyrexian Monitor", 64, Rarity.COMMON, mage.cards.p.PhyrexianMonitor.class)); - cards.add(new SetCardInfo("Phyrexian Negator", 65, Rarity.RARE, mage.cards.p.PhyrexianNegator.class)); - cards.add(new SetCardInfo("Plague Dogs", 66, Rarity.UNCOMMON, mage.cards.p.PlagueDogs.class)); - cards.add(new SetCardInfo("Plated Spider", 116, Rarity.COMMON, mage.cards.p.PlatedSpider.class)); - cards.add(new SetCardInfo("Plow Under", 117, Rarity.RARE, mage.cards.p.PlowUnder.class)); - cards.add(new SetCardInfo("Powder Keg", 136, Rarity.RARE, mage.cards.p.PowderKeg.class)); - cards.add(new SetCardInfo("Quash", 42, Rarity.UNCOMMON, mage.cards.q.Quash.class)); - cards.add(new SetCardInfo("Rapid Decay", 67, Rarity.RARE, mage.cards.r.RapidDecay.class)); - cards.add(new SetCardInfo("Ravenous Rats", 68, Rarity.COMMON, mage.cards.r.RavenousRats.class)); - cards.add(new SetCardInfo("Rayne, Academy Chancellor", 43, Rarity.RARE, mage.cards.r.RayneAcademyChancellor.class)); - cards.add(new SetCardInfo("Reckless Abandon", 94, Rarity.COMMON, mage.cards.r.RecklessAbandon.class)); - cards.add(new SetCardInfo("Reliquary Monk", 14, Rarity.COMMON, mage.cards.r.ReliquaryMonk.class)); - cards.add(new SetCardInfo("Repercussion", 95, Rarity.RARE, mage.cards.r.Repercussion.class)); - cards.add(new SetCardInfo("Replenish", 15, Rarity.RARE, mage.cards.r.Replenish.class)); - cards.add(new SetCardInfo("Rescue", 44, Rarity.COMMON, mage.cards.r.Rescue.class)); - cards.add(new SetCardInfo("Rofellos's Gift", 119, Rarity.COMMON, mage.cards.r.RofellossGift.class)); - cards.add(new SetCardInfo("Rofellos, Llanowar Emissary", 118, Rarity.RARE, mage.cards.r.RofellosLlanowarEmissary.class)); - cards.add(new SetCardInfo("Sanctimony", 16, Rarity.UNCOMMON, mage.cards.s.Sanctimony.class)); - cards.add(new SetCardInfo("Scent of Brine", 45, Rarity.COMMON, mage.cards.s.ScentOfBrine.class)); - cards.add(new SetCardInfo("Scent of Cinder", 96, Rarity.COMMON, mage.cards.s.ScentOfCinder.class)); - cards.add(new SetCardInfo("Scent of Ivy", 120, Rarity.COMMON, mage.cards.s.ScentOfIvy.class)); - cards.add(new SetCardInfo("Scent of Jasmine", 17, Rarity.COMMON, mage.cards.s.ScentOfJasmine.class)); - cards.add(new SetCardInfo("Scent of Nightshade", 69, Rarity.COMMON, mage.cards.s.ScentOfNightshade.class)); - cards.add(new SetCardInfo("Scour", 18, Rarity.UNCOMMON, mage.cards.s.Scour.class)); - cards.add(new SetCardInfo("Serra Advocate", 19, Rarity.UNCOMMON, mage.cards.s.SerraAdvocate.class)); - cards.add(new SetCardInfo("Sigil of Sleep", 46, Rarity.COMMON, mage.cards.s.SigilOfSleep.class)); - cards.add(new SetCardInfo("Skittering Horror", 70, Rarity.COMMON, mage.cards.s.SkitteringHorror.class)); - cards.add(new SetCardInfo("Slinking Skirge", 71, Rarity.COMMON, mage.cards.s.SlinkingSkirge.class)); - cards.add(new SetCardInfo("Solidarity", 20, Rarity.COMMON, mage.cards.s.Solidarity.class)); - cards.add(new SetCardInfo("Soul Feast", 72, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); - cards.add(new SetCardInfo("Sowing Salt", 97, Rarity.UNCOMMON, mage.cards.s.SowingSalt.class)); - cards.add(new SetCardInfo("Splinter", 121, Rarity.UNCOMMON, mage.cards.s.Splinter.class)); - cards.add(new SetCardInfo("Squirming Mass", 73, Rarity.COMMON, mage.cards.s.SquirmingMass.class)); - cards.add(new SetCardInfo("Storage Matrix", 138, Rarity.RARE, mage.cards.s.StorageMatrix.class)); - cards.add(new SetCardInfo("Taunting Elf", 122, Rarity.COMMON, mage.cards.t.TauntingElf.class)); - cards.add(new SetCardInfo("Telepathic Spies", 47, Rarity.COMMON, mage.cards.t.TelepathicSpies.class)); - cards.add(new SetCardInfo("Temporal Adept", 48, Rarity.RARE, mage.cards.t.TemporalAdept.class)); - cards.add(new SetCardInfo("Tethered Griffin", 21, Rarity.RARE, mage.cards.t.TetheredGriffin.class)); - cards.add(new SetCardInfo("Thieving Magpie", 49, Rarity.UNCOMMON, mage.cards.t.ThievingMagpie.class)); - cards.add(new SetCardInfo("Thorn Elemental", 123, Rarity.RARE, mage.cards.t.ThornElemental.class)); - cards.add(new SetCardInfo("Thran Dynamo", 139, Rarity.UNCOMMON, mage.cards.t.ThranDynamo.class)); - cards.add(new SetCardInfo("Thran Foundry", 140, Rarity.UNCOMMON, mage.cards.t.ThranFoundry.class)); - cards.add(new SetCardInfo("Thran Golem", 141, Rarity.RARE, mage.cards.t.ThranGolem.class)); - cards.add(new SetCardInfo("Tormented Angel", 22, Rarity.COMMON, mage.cards.t.TormentedAngel.class)); - cards.add(new SetCardInfo("Treachery", 50, Rarity.RARE, mage.cards.t.Treachery.class)); - cards.add(new SetCardInfo("Trumpet Blast", 98, Rarity.COMMON, mage.cards.t.TrumpetBlast.class)); - cards.add(new SetCardInfo("Twisted Experiment", 74, Rarity.COMMON, mage.cards.t.TwistedExperiment.class)); - cards.add(new SetCardInfo("Urza's Incubator", 142, Rarity.RARE, mage.cards.u.UrzasIncubator.class)); - cards.add(new SetCardInfo("Voice of Duty", 23, Rarity.UNCOMMON, mage.cards.v.VoiceOfDuty.class)); - cards.add(new SetCardInfo("Voice of Reason", 24, Rarity.UNCOMMON, mage.cards.v.VoiceOfReason.class)); - cards.add(new SetCardInfo("Wake of Destruction", 99, Rarity.RARE, mage.cards.w.WakeOfDestruction.class)); - cards.add(new SetCardInfo("Wall of Glare", 25, Rarity.COMMON, mage.cards.w.WallOfGlare.class)); - cards.add(new SetCardInfo("Wild Colos", 100, Rarity.COMMON, mage.cards.w.WildColos.class)); - cards.add(new SetCardInfo("Yavimaya Elder", 124, Rarity.COMMON, mage.cards.y.YavimayaElder.class)); - cards.add(new SetCardInfo("Yavimaya Enchantress", 125, Rarity.UNCOMMON, mage.cards.y.YavimayaEnchantress.class)); - cards.add(new SetCardInfo("Yavimaya Hollow", 143, Rarity.RARE, mage.cards.y.YavimayaHollow.class)); - cards.add(new SetCardInfo("Yawgmoth's Bargain", 75, Rarity.RARE, mage.cards.y.YawgmothsBargain.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author Backfir3 + */ +public final class UrzasDestiny extends ExpansionSet { + + private static final UrzasDestiny instance = new UrzasDestiny(); + + public static UrzasDestiny getInstance() { + return instance; + } + + private UrzasDestiny() { + super("Urza's Destiny", "UDS", ExpansionSet.buildDate(1999, 6, 7), SetType.EXPANSION); + this.blockName = "Urza"; + this.parentSet = UrzasSaga.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Academy Rector", 1, Rarity.RARE, mage.cards.a.AcademyRector.class)); + cards.add(new SetCardInfo("Aether Sting", 76, Rarity.UNCOMMON, mage.cards.a.AetherSting.class)); + cards.add(new SetCardInfo("Ancient Silverback", 101, Rarity.RARE, mage.cards.a.AncientSilverback.class)); + cards.add(new SetCardInfo("Apprentice Necromancer", 51, Rarity.RARE, mage.cards.a.ApprenticeNecromancer.class)); + cards.add(new SetCardInfo("Archery Training", 2, Rarity.UNCOMMON, mage.cards.a.ArcheryTraining.class)); + cards.add(new SetCardInfo("Attrition", 52, Rarity.RARE, mage.cards.a.Attrition.class)); + cards.add(new SetCardInfo("Aura Thief", 26, Rarity.RARE, mage.cards.a.AuraThief.class)); + cards.add(new SetCardInfo("Blizzard Elemental", 27, Rarity.RARE, mage.cards.b.BlizzardElemental.class)); + cards.add(new SetCardInfo("Bloodshot Cyclops", 77, Rarity.RARE, mage.cards.b.BloodshotCyclops.class)); + cards.add(new SetCardInfo("Body Snatcher", 53, Rarity.RARE, mage.cards.b.BodySnatcher.class)); + cards.add(new SetCardInfo("Braidwood Cup", 126, Rarity.UNCOMMON, mage.cards.b.BraidwoodCup.class)); + cards.add(new SetCardInfo("Braidwood Sextant", 127, Rarity.UNCOMMON, mage.cards.b.BraidwoodSextant.class)); + cards.add(new SetCardInfo("Brass Secretary", 128, Rarity.UNCOMMON, mage.cards.b.BrassSecretary.class)); + cards.add(new SetCardInfo("Brine Seer", 28, Rarity.UNCOMMON, mage.cards.b.BrineSeer.class)); + cards.add(new SetCardInfo("Bubbling Beebles", 29, Rarity.COMMON, mage.cards.b.BubblingBeebles.class)); + cards.add(new SetCardInfo("Bubbling Muck", 54, Rarity.COMMON, mage.cards.b.BubblingMuck.class)); + cards.add(new SetCardInfo("Caltrops", 129, Rarity.UNCOMMON, mage.cards.c.Caltrops.class)); + cards.add(new SetCardInfo("Capashen Knight", 3, Rarity.COMMON, mage.cards.c.CapashenKnight.class)); + cards.add(new SetCardInfo("Capashen Standard", 4, Rarity.COMMON, mage.cards.c.CapashenStandard.class)); + cards.add(new SetCardInfo("Capashen Templar", 5, Rarity.COMMON, mage.cards.c.CapashenTemplar.class)); + cards.add(new SetCardInfo("Carnival of Souls", 55, Rarity.RARE, mage.cards.c.CarnivalOfSouls.class)); + cards.add(new SetCardInfo("Chime of Night", 56, Rarity.COMMON, mage.cards.c.ChimeOfNight.class)); + cards.add(new SetCardInfo("Cinder Seer", 78, Rarity.UNCOMMON, mage.cards.c.CinderSeer.class)); + cards.add(new SetCardInfo("Colos Yearling", 79, Rarity.COMMON, mage.cards.c.ColosYearling.class)); + cards.add(new SetCardInfo("Compost", 102, Rarity.UNCOMMON, mage.cards.c.Compost.class)); + cards.add(new SetCardInfo("Covetous Dragon", 80, Rarity.RARE, mage.cards.c.CovetousDragon.class)); + cards.add(new SetCardInfo("Disappear", 30, Rarity.UNCOMMON, mage.cards.d.Disappear.class)); + cards.add(new SetCardInfo("Disease Carriers", 57, Rarity.COMMON, mage.cards.d.DiseaseCarriers.class)); + cards.add(new SetCardInfo("Donate", 31, Rarity.RARE, mage.cards.d.Donate.class)); + cards.add(new SetCardInfo("Dying Wail", 58, Rarity.COMMON, mage.cards.d.DyingWail.class)); + cards.add(new SetCardInfo("Elvish Lookout", 103, Rarity.COMMON, mage.cards.e.ElvishLookout.class)); + cards.add(new SetCardInfo("Elvish Piper", 104, Rarity.RARE, mage.cards.e.ElvishPiper.class)); + cards.add(new SetCardInfo("Emperor Crocodile", 105, Rarity.RARE, mage.cards.e.EmperorCrocodile.class)); + cards.add(new SetCardInfo("Encroach", 59, Rarity.UNCOMMON, mage.cards.e.Encroach.class)); + cards.add(new SetCardInfo("Eradicate", 60, Rarity.UNCOMMON, mage.cards.e.Eradicate.class)); + cards.add(new SetCardInfo("Extruder", 130, Rarity.UNCOMMON, mage.cards.e.Extruder.class)); + cards.add(new SetCardInfo("False Prophet", 6, Rarity.RARE, mage.cards.f.FalseProphet.class)); + cards.add(new SetCardInfo("Fatigue", 32, Rarity.COMMON, mage.cards.f.Fatigue.class)); + cards.add(new SetCardInfo("Fend Off", 7, Rarity.COMMON, mage.cards.f.FendOff.class)); + cards.add(new SetCardInfo("Festering Wound", 61, Rarity.UNCOMMON, mage.cards.f.FesteringWound.class)); + cards.add(new SetCardInfo("Field Surgeon", 8, Rarity.COMMON, mage.cards.f.FieldSurgeon.class)); + cards.add(new SetCardInfo("Flame Jet", 81, Rarity.COMMON, mage.cards.f.FlameJet.class)); + cards.add(new SetCardInfo("Fledgling Osprey", 33, Rarity.COMMON, mage.cards.f.FledglingOsprey.class)); + cards.add(new SetCardInfo("Flicker", 9, Rarity.RARE, mage.cards.f.Flicker.class)); + cards.add(new SetCardInfo("Fodder Cannon", 131, Rarity.UNCOMMON, mage.cards.f.FodderCannon.class)); + cards.add(new SetCardInfo("Gamekeeper", 106, Rarity.UNCOMMON, mage.cards.g.Gamekeeper.class)); + cards.add(new SetCardInfo("Goblin Berserker", 82, Rarity.UNCOMMON, mage.cards.g.GoblinBerserker.class)); + cards.add(new SetCardInfo("Goblin Festival", 83, Rarity.RARE, mage.cards.g.GoblinFestival.class)); + cards.add(new SetCardInfo("Goblin Gardener", 84, Rarity.COMMON, mage.cards.g.GoblinGardener.class)); + cards.add(new SetCardInfo("Goblin Marshal", 85, Rarity.RARE, mage.cards.g.GoblinMarshal.class)); + cards.add(new SetCardInfo("Goblin Masons", 86, Rarity.COMMON, mage.cards.g.GoblinMasons.class)); + cards.add(new SetCardInfo("Goliath Beetle", 107, Rarity.COMMON, mage.cards.g.GoliathBeetle.class)); + cards.add(new SetCardInfo("Heart Warden", 108, Rarity.COMMON, mage.cards.h.HeartWarden.class)); + cards.add(new SetCardInfo("Hulking Ogre", 87, Rarity.COMMON, mage.cards.h.HulkingOgre.class)); + cards.add(new SetCardInfo("Hunting Moa", 109, Rarity.UNCOMMON, mage.cards.h.HuntingMoa.class)); + cards.add(new SetCardInfo("Illuminated Wings", 34, Rarity.COMMON, mage.cards.i.IlluminatedWings.class)); + cards.add(new SetCardInfo("Impatience", 88, Rarity.RARE, mage.cards.i.Impatience.class)); + cards.add(new SetCardInfo("Incendiary", 89, Rarity.UNCOMMON, mage.cards.i.Incendiary.class)); + cards.add(new SetCardInfo("Iridescent Drake", 35, Rarity.UNCOMMON, mage.cards.i.IridescentDrake.class)); + cards.add(new SetCardInfo("Ivy Seer", 110, Rarity.UNCOMMON, mage.cards.i.IvySeer.class)); + cards.add(new SetCardInfo("Jasmine Seer", 10, Rarity.UNCOMMON, mage.cards.j.JasmineSeer.class)); + cards.add(new SetCardInfo("Junk Diver", 132, Rarity.RARE, mage.cards.j.JunkDiver.class)); + cards.add(new SetCardInfo("Keldon Champion", 90, Rarity.UNCOMMON, mage.cards.k.KeldonChampion.class)); + cards.add(new SetCardInfo("Keldon Vandals", 91, Rarity.COMMON, mage.cards.k.KeldonVandals.class)); + cards.add(new SetCardInfo("Kingfisher", 36, Rarity.COMMON, mage.cards.k.Kingfisher.class)); + cards.add(new SetCardInfo("Landslide", 92, Rarity.UNCOMMON, mage.cards.l.Landslide.class)); + cards.add(new SetCardInfo("Lurking Jackals", 62, Rarity.UNCOMMON, mage.cards.l.LurkingJackals.class)); + cards.add(new SetCardInfo("Magnify", 111, Rarity.COMMON, mage.cards.m.Magnify.class)); + cards.add(new SetCardInfo("Mantis Engine", 133, Rarity.UNCOMMON, mage.cards.m.MantisEngine.class)); + cards.add(new SetCardInfo("Marker Beetles", 112, Rarity.COMMON, mage.cards.m.MarkerBeetles.class)); + cards.add(new SetCardInfo("Mark of Fury", 93, Rarity.COMMON, mage.cards.m.MarkOfFury.class)); + cards.add(new SetCardInfo("Mask of Law and Grace", 11, Rarity.COMMON, mage.cards.m.MaskOfLawAndGrace.class)); + cards.add(new SetCardInfo("Master Healer", 12, Rarity.RARE, mage.cards.m.MasterHealer.class)); + cards.add(new SetCardInfo("Masticore", 134, Rarity.RARE, mage.cards.m.Masticore.class)); + cards.add(new SetCardInfo("Mental Discipline", 37, Rarity.COMMON, mage.cards.m.MentalDiscipline.class)); + cards.add(new SetCardInfo("Metalworker", 135, Rarity.RARE, mage.cards.m.Metalworker.class)); + cards.add(new SetCardInfo("Metathran Elite", 38, Rarity.UNCOMMON, mage.cards.m.MetathranElite.class)); + cards.add(new SetCardInfo("Metathran Soldier", 39, Rarity.COMMON, mage.cards.m.MetathranSoldier.class)); + cards.add(new SetCardInfo("Momentum", 113, Rarity.UNCOMMON, mage.cards.m.Momentum.class)); + cards.add(new SetCardInfo("Multani's Decree", 114, Rarity.COMMON, mage.cards.m.MultanisDecree.class)); + cards.add(new SetCardInfo("Nightshade Seer", 63, Rarity.UNCOMMON, mage.cards.n.NightshadeSeer.class)); + cards.add(new SetCardInfo("Opalescence", 13, Rarity.RARE, mage.cards.o.Opalescence.class)); + cards.add(new SetCardInfo("Opposition", 40, Rarity.RARE, mage.cards.o.Opposition.class)); + cards.add(new SetCardInfo("Pattern of Rebirth", 115, Rarity.RARE, mage.cards.p.PatternOfRebirth.class)); + cards.add(new SetCardInfo("Phyrexian Monitor", 64, Rarity.COMMON, mage.cards.p.PhyrexianMonitor.class)); + cards.add(new SetCardInfo("Phyrexian Negator", 65, Rarity.RARE, mage.cards.p.PhyrexianNegator.class)); + cards.add(new SetCardInfo("Plague Dogs", 66, Rarity.UNCOMMON, mage.cards.p.PlagueDogs.class)); + cards.add(new SetCardInfo("Plated Spider", 116, Rarity.COMMON, mage.cards.p.PlatedSpider.class)); + cards.add(new SetCardInfo("Plow Under", 117, Rarity.RARE, mage.cards.p.PlowUnder.class)); + cards.add(new SetCardInfo("Powder Keg", 136, Rarity.RARE, mage.cards.p.PowderKeg.class)); + cards.add(new SetCardInfo("Private Research", 41, Rarity.UNCOMMON, mage.cards.p.PrivateResearch.class)); + cards.add(new SetCardInfo("Quash", 42, Rarity.UNCOMMON, mage.cards.q.Quash.class)); + cards.add(new SetCardInfo("Rapid Decay", 67, Rarity.RARE, mage.cards.r.RapidDecay.class)); + cards.add(new SetCardInfo("Ravenous Rats", 68, Rarity.COMMON, mage.cards.r.RavenousRats.class)); + cards.add(new SetCardInfo("Rayne, Academy Chancellor", 43, Rarity.RARE, mage.cards.r.RayneAcademyChancellor.class)); + cards.add(new SetCardInfo("Reckless Abandon", 94, Rarity.COMMON, mage.cards.r.RecklessAbandon.class)); + cards.add(new SetCardInfo("Reliquary Monk", 14, Rarity.COMMON, mage.cards.r.ReliquaryMonk.class)); + cards.add(new SetCardInfo("Repercussion", 95, Rarity.RARE, mage.cards.r.Repercussion.class)); + cards.add(new SetCardInfo("Replenish", 15, Rarity.RARE, mage.cards.r.Replenish.class)); + cards.add(new SetCardInfo("Rescue", 44, Rarity.COMMON, mage.cards.r.Rescue.class)); + cards.add(new SetCardInfo("Rofellos's Gift", 119, Rarity.COMMON, mage.cards.r.RofellossGift.class)); + cards.add(new SetCardInfo("Rofellos, Llanowar Emissary", 118, Rarity.RARE, mage.cards.r.RofellosLlanowarEmissary.class)); + cards.add(new SetCardInfo("Sanctimony", 16, Rarity.UNCOMMON, mage.cards.s.Sanctimony.class)); + cards.add(new SetCardInfo("Scent of Brine", 45, Rarity.COMMON, mage.cards.s.ScentOfBrine.class)); + cards.add(new SetCardInfo("Scent of Cinder", 96, Rarity.COMMON, mage.cards.s.ScentOfCinder.class)); + cards.add(new SetCardInfo("Scent of Ivy", 120, Rarity.COMMON, mage.cards.s.ScentOfIvy.class)); + cards.add(new SetCardInfo("Scent of Jasmine", 17, Rarity.COMMON, mage.cards.s.ScentOfJasmine.class)); + cards.add(new SetCardInfo("Scent of Nightshade", 69, Rarity.COMMON, mage.cards.s.ScentOfNightshade.class)); + cards.add(new SetCardInfo("Scour", 18, Rarity.UNCOMMON, mage.cards.s.Scour.class)); + cards.add(new SetCardInfo("Scrying Glass", 137, Rarity.RARE, mage.cards.s.ScryingGlass.class)); + cards.add(new SetCardInfo("Serra Advocate", 19, Rarity.UNCOMMON, mage.cards.s.SerraAdvocate.class)); + cards.add(new SetCardInfo("Sigil of Sleep", 46, Rarity.COMMON, mage.cards.s.SigilOfSleep.class)); + cards.add(new SetCardInfo("Skittering Horror", 70, Rarity.COMMON, mage.cards.s.SkitteringHorror.class)); + cards.add(new SetCardInfo("Slinking Skirge", 71, Rarity.COMMON, mage.cards.s.SlinkingSkirge.class)); + cards.add(new SetCardInfo("Solidarity", 20, Rarity.COMMON, mage.cards.s.Solidarity.class)); + cards.add(new SetCardInfo("Soul Feast", 72, Rarity.UNCOMMON, mage.cards.s.SoulFeast.class)); + cards.add(new SetCardInfo("Sowing Salt", 97, Rarity.UNCOMMON, mage.cards.s.SowingSalt.class)); + cards.add(new SetCardInfo("Splinter", 121, Rarity.UNCOMMON, mage.cards.s.Splinter.class)); + cards.add(new SetCardInfo("Squirming Mass", 73, Rarity.COMMON, mage.cards.s.SquirmingMass.class)); + cards.add(new SetCardInfo("Storage Matrix", 138, Rarity.RARE, mage.cards.s.StorageMatrix.class)); + cards.add(new SetCardInfo("Taunting Elf", 122, Rarity.COMMON, mage.cards.t.TauntingElf.class)); + cards.add(new SetCardInfo("Telepathic Spies", 47, Rarity.COMMON, mage.cards.t.TelepathicSpies.class)); + cards.add(new SetCardInfo("Temporal Adept", 48, Rarity.RARE, mage.cards.t.TemporalAdept.class)); + cards.add(new SetCardInfo("Tethered Griffin", 21, Rarity.RARE, mage.cards.t.TetheredGriffin.class)); + cards.add(new SetCardInfo("Thieving Magpie", 49, Rarity.UNCOMMON, mage.cards.t.ThievingMagpie.class)); + cards.add(new SetCardInfo("Thorn Elemental", 123, Rarity.RARE, mage.cards.t.ThornElemental.class)); + cards.add(new SetCardInfo("Thran Dynamo", 139, Rarity.UNCOMMON, mage.cards.t.ThranDynamo.class)); + cards.add(new SetCardInfo("Thran Foundry", 140, Rarity.UNCOMMON, mage.cards.t.ThranFoundry.class)); + cards.add(new SetCardInfo("Thran Golem", 141, Rarity.RARE, mage.cards.t.ThranGolem.class)); + cards.add(new SetCardInfo("Tormented Angel", 22, Rarity.COMMON, mage.cards.t.TormentedAngel.class)); + cards.add(new SetCardInfo("Treachery", 50, Rarity.RARE, mage.cards.t.Treachery.class)); + cards.add(new SetCardInfo("Trumpet Blast", 98, Rarity.COMMON, mage.cards.t.TrumpetBlast.class)); + cards.add(new SetCardInfo("Twisted Experiment", 74, Rarity.COMMON, mage.cards.t.TwistedExperiment.class)); + cards.add(new SetCardInfo("Urza's Incubator", 142, Rarity.RARE, mage.cards.u.UrzasIncubator.class)); + cards.add(new SetCardInfo("Voice of Duty", 23, Rarity.UNCOMMON, mage.cards.v.VoiceOfDuty.class)); + cards.add(new SetCardInfo("Voice of Reason", 24, Rarity.UNCOMMON, mage.cards.v.VoiceOfReason.class)); + cards.add(new SetCardInfo("Wake of Destruction", 99, Rarity.RARE, mage.cards.w.WakeOfDestruction.class)); + cards.add(new SetCardInfo("Wall of Glare", 25, Rarity.COMMON, mage.cards.w.WallOfGlare.class)); + cards.add(new SetCardInfo("Wild Colos", 100, Rarity.COMMON, mage.cards.w.WildColos.class)); + cards.add(new SetCardInfo("Yavimaya Elder", 124, Rarity.COMMON, mage.cards.y.YavimayaElder.class)); + cards.add(new SetCardInfo("Yavimaya Enchantress", 125, Rarity.UNCOMMON, mage.cards.y.YavimayaEnchantress.class)); + cards.add(new SetCardInfo("Yavimaya Hollow", 143, Rarity.RARE, mage.cards.y.YavimayaHollow.class)); + cards.add(new SetCardInfo("Yawgmoth's Bargain", 75, Rarity.RARE, mage.cards.y.YawgmothsBargain.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/UrzasLegacy.java b/Mage.Sets/src/mage/sets/UrzasLegacy.java index eaa00b8c3c..431d2eb3f8 100644 --- a/Mage.Sets/src/mage/sets/UrzasLegacy.java +++ b/Mage.Sets/src/mage/sets/UrzasLegacy.java @@ -1,172 +1,175 @@ - -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author noxx - */ -public final class UrzasLegacy extends ExpansionSet { - - private static final UrzasLegacy instance = new UrzasLegacy(); - - public static UrzasLegacy getInstance() { - return instance; - } - - private UrzasLegacy() { - super("Urza's Legacy", "ULG", ExpansionSet.buildDate(1999, 2, 15), SetType.EXPANSION); - this.blockName = "Urza"; - this.parentSet = UrzasSaga.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("About Face", 73, Rarity.COMMON, mage.cards.a.AboutFace.class)); - cards.add(new SetCardInfo("Angel's Trumpet", 121, Rarity.UNCOMMON, mage.cards.a.AngelsTrumpet.class)); - cards.add(new SetCardInfo("Angelic Curator", 1, Rarity.COMMON, mage.cards.a.AngelicCurator.class)); - cards.add(new SetCardInfo("Anthroplasm", 25, Rarity.RARE, mage.cards.a.Anthroplasm.class)); - cards.add(new SetCardInfo("Archivist", 26, Rarity.RARE, mage.cards.a.Archivist.class)); - cards.add(new SetCardInfo("Aura Flux", 27, Rarity.COMMON, mage.cards.a.AuraFlux.class)); - cards.add(new SetCardInfo("Avalanche Riders", 74, Rarity.UNCOMMON, mage.cards.a.AvalancheRiders.class)); - cards.add(new SetCardInfo("Beast of Burden", 122, Rarity.RARE, mage.cards.b.BeastOfBurden.class)); - cards.add(new SetCardInfo("Blessed Reversal", 2, Rarity.RARE, mage.cards.b.BlessedReversal.class)); - cards.add(new SetCardInfo("Bloated Toad", 97, Rarity.UNCOMMON, mage.cards.b.BloatedToad.class)); - cards.add(new SetCardInfo("Bone Shredder", 49, Rarity.UNCOMMON, mage.cards.b.BoneShredder.class)); - cards.add(new SetCardInfo("Bouncing Beebles", 28, Rarity.COMMON, mage.cards.b.BouncingBeebles.class)); - cards.add(new SetCardInfo("Brink of Madness", 50, Rarity.RARE, mage.cards.b.BrinkOfMadness.class)); - cards.add(new SetCardInfo("Burst of Energy", 3, Rarity.COMMON, mage.cards.b.BurstOfEnergy.class)); - cards.add(new SetCardInfo("Cessation", 4, Rarity.COMMON, mage.cards.c.Cessation.class)); - cards.add(new SetCardInfo("Cloud of Faeries", 29, Rarity.COMMON, mage.cards.c.CloudOfFaeries.class)); - cards.add(new SetCardInfo("Crawlspace", 123, Rarity.RARE, mage.cards.c.Crawlspace.class)); - cards.add(new SetCardInfo("Crop Rotation", 98, Rarity.COMMON, mage.cards.c.CropRotation.class)); - cards.add(new SetCardInfo("Damping Engine", 124, Rarity.RARE, mage.cards.d.DampingEngine.class)); - cards.add(new SetCardInfo("Darkwatch Elves", 99, Rarity.UNCOMMON, mage.cards.d.DarkwatchElves.class)); - cards.add(new SetCardInfo("Defender of Chaos", 75, Rarity.COMMON, mage.cards.d.DefenderOfChaos.class)); - cards.add(new SetCardInfo("Defender of Law", 5, Rarity.COMMON, mage.cards.d.DefenderOfLaw.class)); - cards.add(new SetCardInfo("Defense Grid", 125, Rarity.RARE, mage.cards.d.DefenseGrid.class)); - cards.add(new SetCardInfo("Defense of the Heart", 100, Rarity.RARE, mage.cards.d.DefenseOfTheHeart.class)); - cards.add(new SetCardInfo("Delusions of Mediocrity", 30, Rarity.RARE, mage.cards.d.DelusionsOfMediocrity.class)); - cards.add(new SetCardInfo("Deranged Hermit", 101, Rarity.RARE, mage.cards.d.DerangedHermit.class)); - cards.add(new SetCardInfo("Devout Harpist", 6, Rarity.COMMON, mage.cards.d.DevoutHarpist.class)); - cards.add(new SetCardInfo("Engineered Plague", 51, Rarity.UNCOMMON, mage.cards.e.EngineeredPlague.class)); - cards.add(new SetCardInfo("Erase", 7, Rarity.COMMON, mage.cards.e.Erase.class)); - cards.add(new SetCardInfo("Eviscerator", 52, Rarity.RARE, mage.cards.e.Eviscerator.class)); - cards.add(new SetCardInfo("Expendable Troops", 8, Rarity.COMMON, mage.cards.e.ExpendableTroops.class)); - cards.add(new SetCardInfo("Faerie Conclave", 139, Rarity.UNCOMMON, mage.cards.f.FaerieConclave.class)); - cards.add(new SetCardInfo("Fleeting Image", 31, Rarity.RARE, mage.cards.f.FleetingImage.class)); - cards.add(new SetCardInfo("Fog of Gnats", 53, Rarity.COMMON, mage.cards.f.FogOfGnats.class)); - cards.add(new SetCardInfo("Forbidding Watchtower", 140, Rarity.UNCOMMON, mage.cards.f.ForbiddingWatchtower.class)); - cards.add(new SetCardInfo("Frantic Search", 32, Rarity.COMMON, mage.cards.f.FranticSearch.class)); - cards.add(new SetCardInfo("Gang of Elk", 102, Rarity.UNCOMMON, mage.cards.g.GangOfElk.class)); - cards.add(new SetCardInfo("Ghitu Encampment", 141, Rarity.UNCOMMON, mage.cards.g.GhituEncampment.class)); - cards.add(new SetCardInfo("Ghitu Fire-Eater", 76, Rarity.UNCOMMON, mage.cards.g.GhituFireEater.class)); - cards.add(new SetCardInfo("Ghitu Slinger", 77, Rarity.COMMON, mage.cards.g.GhituSlinger.class)); - cards.add(new SetCardInfo("Ghitu War Cry", 78, Rarity.UNCOMMON, mage.cards.g.GhituWarCry.class)); - cards.add(new SetCardInfo("Giant Cockroach", 54, Rarity.COMMON, mage.cards.g.GiantCockroach.class)); - cards.add(new SetCardInfo("Goblin Medics", 79, Rarity.COMMON, mage.cards.g.GoblinMedics.class)); - cards.add(new SetCardInfo("Goblin Welder", 80, Rarity.RARE, mage.cards.g.GoblinWelder.class)); - cards.add(new SetCardInfo("Granite Grip", 81, Rarity.COMMON, mage.cards.g.GraniteGrip.class)); - cards.add(new SetCardInfo("Grim Monolith", 126, Rarity.RARE, mage.cards.g.GrimMonolith.class)); - cards.add(new SetCardInfo("Harmonic Convergence", 103, Rarity.UNCOMMON, mage.cards.h.HarmonicConvergence.class)); - cards.add(new SetCardInfo("Hidden Gibbons", 104, Rarity.RARE, mage.cards.h.HiddenGibbons.class)); - cards.add(new SetCardInfo("Hope and Glory", 9, Rarity.UNCOMMON, mage.cards.h.HopeAndGlory.class)); - cards.add(new SetCardInfo("Impending Disaster", 82, Rarity.RARE, mage.cards.i.ImpendingDisaster.class)); - cards.add(new SetCardInfo("Intervene", 33, Rarity.COMMON, mage.cards.i.Intervene.class)); - cards.add(new SetCardInfo("Iron Maiden", 127, Rarity.RARE, mage.cards.i.IronMaiden.class)); - cards.add(new SetCardInfo("Iron Will", 10, Rarity.COMMON, mage.cards.i.IronWill.class)); - cards.add(new SetCardInfo("Jhoira's Toolbox", 128, Rarity.UNCOMMON, mage.cards.j.JhoirasToolbox.class)); - cards.add(new SetCardInfo("Karmic Guide", 11, Rarity.RARE, mage.cards.k.KarmicGuide.class)); - cards.add(new SetCardInfo("King Crab", 34, Rarity.UNCOMMON, mage.cards.k.KingCrab.class)); - cards.add(new SetCardInfo("Knighthood", 12, Rarity.UNCOMMON, mage.cards.k.Knighthood.class)); - cards.add(new SetCardInfo("Last-Ditch Effort", 83, Rarity.UNCOMMON, mage.cards.l.LastDitchEffort.class)); - cards.add(new SetCardInfo("Lava Axe", 84, Rarity.COMMON, mage.cards.l.LavaAxe.class)); - cards.add(new SetCardInfo("Levitation", 35, Rarity.UNCOMMON, mage.cards.l.Levitation.class)); - cards.add(new SetCardInfo("Lone Wolf", 105, Rarity.UNCOMMON, mage.cards.l.LoneWolf.class)); - cards.add(new SetCardInfo("Martyr's Cause", 13, Rarity.UNCOMMON, mage.cards.m.MartyrsCause.class)); - cards.add(new SetCardInfo("Memory Jar", 129, Rarity.RARE, mage.cards.m.MemoryJar.class)); - cards.add(new SetCardInfo("Might of Oaks", 106, Rarity.RARE, mage.cards.m.MightOfOaks.class)); - cards.add(new SetCardInfo("Miscalculation", 36, Rarity.COMMON, mage.cards.m.Miscalculation.class)); - cards.add(new SetCardInfo("Molten Hydra", 85, Rarity.RARE, mage.cards.m.MoltenHydra.class)); - cards.add(new SetCardInfo("Mother of Runes", 14, Rarity.UNCOMMON, mage.cards.m.MotherOfRunes.class)); - cards.add(new SetCardInfo("Multani's Acolyte", 108, Rarity.COMMON, mage.cards.m.MultanisAcolyte.class)); - cards.add(new SetCardInfo("Multani's Presence", 109, Rarity.UNCOMMON, mage.cards.m.MultanisPresence.class)); - cards.add(new SetCardInfo("Multani, Maro-Sorcerer", 107, Rarity.RARE, mage.cards.m.MultaniMaroSorcerer.class)); - cards.add(new SetCardInfo("No Mercy", 56, Rarity.RARE, mage.cards.n.NoMercy.class)); - cards.add(new SetCardInfo("Opal Champion", 16, Rarity.COMMON, mage.cards.o.OpalChampion.class)); - cards.add(new SetCardInfo("Opportunity", 37, Rarity.UNCOMMON, mage.cards.o.Opportunity.class)); - cards.add(new SetCardInfo("Ostracize", 57, Rarity.COMMON, mage.cards.o.Ostracize.class)); - cards.add(new SetCardInfo("Palinchron", 38, Rarity.RARE, mage.cards.p.Palinchron.class)); - cards.add(new SetCardInfo("Parch", 86, Rarity.COMMON, mage.cards.p.Parch.class)); - cards.add(new SetCardInfo("Peace and Quiet", 17, Rarity.UNCOMMON, mage.cards.p.PeaceAndQuiet.class)); - cards.add(new SetCardInfo("Phyrexian Broodlings", 58, Rarity.COMMON, mage.cards.p.PhyrexianBroodlings.class)); - cards.add(new SetCardInfo("Phyrexian Debaser", 59, Rarity.COMMON, mage.cards.p.PhyrexianDebaser.class)); - cards.add(new SetCardInfo("Phyrexian Defiler", 60, Rarity.UNCOMMON, mage.cards.p.PhyrexianDefiler.class)); - cards.add(new SetCardInfo("Phyrexian Denouncer", 61, Rarity.COMMON, mage.cards.p.PhyrexianDenouncer.class)); - cards.add(new SetCardInfo("Phyrexian Plaguelord", 62, Rarity.RARE, mage.cards.p.PhyrexianPlaguelord.class)); - cards.add(new SetCardInfo("Phyrexian Reclamation", 63, Rarity.UNCOMMON, mage.cards.p.PhyrexianReclamation.class)); - cards.add(new SetCardInfo("Plague Beetle", 64, Rarity.COMMON, mage.cards.p.PlagueBeetle.class)); - cards.add(new SetCardInfo("Planar Collapse", 18, Rarity.RARE, mage.cards.p.PlanarCollapse.class)); - cards.add(new SetCardInfo("Purify", 19, Rarity.RARE, mage.cards.p.Purify.class)); - cards.add(new SetCardInfo("Pygmy Pyrosaur", 87, Rarity.COMMON, mage.cards.p.PygmyPyrosaur.class)); - cards.add(new SetCardInfo("Pyromancy", 88, Rarity.RARE, mage.cards.p.Pyromancy.class)); - cards.add(new SetCardInfo("Quicksilver Amulet", 130, Rarity.RARE, mage.cards.q.QuicksilverAmulet.class)); - cards.add(new SetCardInfo("Rack and Ruin", 89, Rarity.UNCOMMON, mage.cards.r.RackAndRuin.class)); - cards.add(new SetCardInfo("Radiant's Dragoons", 21, Rarity.UNCOMMON, mage.cards.r.RadiantsDragoons.class)); - cards.add(new SetCardInfo("Radiant's Judgment", 22, Rarity.COMMON, mage.cards.r.RadiantsJudgment.class)); - cards.add(new SetCardInfo("Radiant, Archangel", 20, Rarity.RARE, mage.cards.r.RadiantArchangel.class)); - cards.add(new SetCardInfo("Rancor", 110, Rarity.COMMON, mage.cards.r.Rancor.class)); - cards.add(new SetCardInfo("Rank and File", 65, Rarity.UNCOMMON, mage.cards.r.RankAndFile.class)); - cards.add(new SetCardInfo("Raven Familiar", 39, Rarity.UNCOMMON, mage.cards.r.RavenFamiliar.class)); - cards.add(new SetCardInfo("Rebuild", 40, Rarity.UNCOMMON, mage.cards.r.Rebuild.class)); - cards.add(new SetCardInfo("Repopulate", 111, Rarity.COMMON, mage.cards.r.Repopulate.class)); - cards.add(new SetCardInfo("Ring of Gix", 131, Rarity.RARE, mage.cards.r.RingOfGix.class)); - cards.add(new SetCardInfo("Rivalry", 90, Rarity.RARE, mage.cards.r.Rivalry.class)); - cards.add(new SetCardInfo("Scrapheap", 132, Rarity.RARE, mage.cards.s.Scrapheap.class)); - cards.add(new SetCardInfo("Second Chance", 41, Rarity.RARE, mage.cards.s.SecondChance.class)); - cards.add(new SetCardInfo("Shivan Phoenix", 91, Rarity.RARE, mage.cards.s.ShivanPhoenix.class)); - cards.add(new SetCardInfo("Sick and Tired", 66, Rarity.COMMON, mage.cards.s.SickAndTired.class)); - cards.add(new SetCardInfo("Silk Net", 112, Rarity.COMMON, mage.cards.s.SilkNet.class)); - cards.add(new SetCardInfo("Simian Grunts", 113, Rarity.COMMON, mage.cards.s.SimianGrunts.class)); - cards.add(new SetCardInfo("Sleeper's Guile", 67, Rarity.COMMON, mage.cards.s.SleepersGuile.class)); - cards.add(new SetCardInfo("Slow Motion", 42, Rarity.COMMON, mage.cards.s.SlowMotion.class)); - cards.add(new SetCardInfo("Sluggishness", 92, Rarity.COMMON, mage.cards.s.Sluggishness.class)); - cards.add(new SetCardInfo("Snap", 43, Rarity.COMMON, mage.cards.s.Snap.class)); - cards.add(new SetCardInfo("Spawning Pool", 142, Rarity.UNCOMMON, mage.cards.s.SpawningPool.class)); - cards.add(new SetCardInfo("Subversion", 68, Rarity.RARE, mage.cards.s.Subversion.class)); - cards.add(new SetCardInfo("Sustainer of the Realm", 23, Rarity.UNCOMMON, mage.cards.s.SustainerOfTheRealm.class)); - cards.add(new SetCardInfo("Swat", 69, Rarity.COMMON, mage.cards.s.Swat.class)); - cards.add(new SetCardInfo("Tethered Skirge", 70, Rarity.UNCOMMON, mage.cards.t.TetheredSkirge.class)); - cards.add(new SetCardInfo("Thornwind Faeries", 44, Rarity.COMMON, mage.cards.t.ThornwindFaeries.class)); - cards.add(new SetCardInfo("Thran Lens", 133, Rarity.RARE, mage.cards.t.ThranLens.class)); - cards.add(new SetCardInfo("Thran War Machine", 134, Rarity.UNCOMMON, mage.cards.t.ThranWarMachine.class)); - cards.add(new SetCardInfo("Thran Weaponry", 135, Rarity.RARE, mage.cards.t.ThranWeaponry.class)); - cards.add(new SetCardInfo("Ticking Gnomes", 136, Rarity.UNCOMMON, mage.cards.t.TickingGnomes.class)); - cards.add(new SetCardInfo("Tinker", 45, Rarity.UNCOMMON, mage.cards.t.Tinker.class)); - cards.add(new SetCardInfo("Tragic Poet", 24, Rarity.COMMON, mage.cards.t.TragicPoet.class)); - cards.add(new SetCardInfo("Treacherous Link", 71, Rarity.UNCOMMON, mage.cards.t.TreacherousLink.class)); - cards.add(new SetCardInfo("Treefolk Mystic", 114, Rarity.COMMON, mage.cards.t.TreefolkMystic.class)); - cards.add(new SetCardInfo("Treetop Village", 143, Rarity.UNCOMMON, mage.cards.t.TreetopVillage.class)); - cards.add(new SetCardInfo("Unearth", 72, Rarity.COMMON, mage.cards.u.Unearth.class)); - cards.add(new SetCardInfo("Urza's Blueprints", 137, Rarity.RARE, mage.cards.u.UrzasBlueprints.class)); - cards.add(new SetCardInfo("Viashino Cutthroat", 94, Rarity.UNCOMMON, mage.cards.v.ViashinoCutthroat.class)); - cards.add(new SetCardInfo("Viashino Heretic", 95, Rarity.UNCOMMON, mage.cards.v.ViashinoHeretic.class)); - cards.add(new SetCardInfo("Viashino Sandscout", 96, Rarity.COMMON, mage.cards.v.ViashinoSandscout.class)); - cards.add(new SetCardInfo("Vigilant Drake", 46, Rarity.COMMON, mage.cards.v.VigilantDrake.class)); - cards.add(new SetCardInfo("Walking Sponge", 47, Rarity.UNCOMMON, mage.cards.w.WalkingSponge.class)); - cards.add(new SetCardInfo("Weatherseed Elf", 115, Rarity.COMMON, mage.cards.w.WeatherseedElf.class)); - cards.add(new SetCardInfo("Weatherseed Faeries", 48, Rarity.COMMON, mage.cards.w.WeatherseedFaeries.class)); - cards.add(new SetCardInfo("Weatherseed Treefolk", 116, Rarity.RARE, mage.cards.w.WeatherseedTreefolk.class)); - cards.add(new SetCardInfo("Wheel of Torture", 138, Rarity.RARE, mage.cards.w.WheelOfTorture.class)); - cards.add(new SetCardInfo("Wing Snare", 117, Rarity.UNCOMMON, mage.cards.w.WingSnare.class)); - cards.add(new SetCardInfo("Yavimaya Granger", 118, Rarity.COMMON, mage.cards.y.YavimayaGranger.class)); - cards.add(new SetCardInfo("Yavimaya Scion", 119, Rarity.COMMON, mage.cards.y.YavimayaScion.class)); - cards.add(new SetCardInfo("Yavimaya Wurm", 120, Rarity.COMMON, mage.cards.y.YavimayaWurm.class)); - } -} + +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author noxx + */ +public final class UrzasLegacy extends ExpansionSet { + + private static final UrzasLegacy instance = new UrzasLegacy(); + + public static UrzasLegacy getInstance() { + return instance; + } + + private UrzasLegacy() { + super("Urza's Legacy", "ULG", ExpansionSet.buildDate(1999, 2, 15), SetType.EXPANSION); + this.blockName = "Urza"; + this.parentSet = UrzasSaga.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("About Face", 73, Rarity.COMMON, mage.cards.a.AboutFace.class)); + cards.add(new SetCardInfo("Angel's Trumpet", 121, Rarity.UNCOMMON, mage.cards.a.AngelsTrumpet.class)); + cards.add(new SetCardInfo("Angelic Curator", 1, Rarity.COMMON, mage.cards.a.AngelicCurator.class)); + cards.add(new SetCardInfo("Anthroplasm", 25, Rarity.RARE, mage.cards.a.Anthroplasm.class)); + cards.add(new SetCardInfo("Archivist", 26, Rarity.RARE, mage.cards.a.Archivist.class)); + cards.add(new SetCardInfo("Aura Flux", 27, Rarity.COMMON, mage.cards.a.AuraFlux.class)); + cards.add(new SetCardInfo("Avalanche Riders", 74, Rarity.UNCOMMON, mage.cards.a.AvalancheRiders.class)); + cards.add(new SetCardInfo("Beast of Burden", 122, Rarity.RARE, mage.cards.b.BeastOfBurden.class)); + cards.add(new SetCardInfo("Blessed Reversal", 2, Rarity.RARE, mage.cards.b.BlessedReversal.class)); + cards.add(new SetCardInfo("Bloated Toad", 97, Rarity.UNCOMMON, mage.cards.b.BloatedToad.class)); + cards.add(new SetCardInfo("Bone Shredder", 49, Rarity.UNCOMMON, mage.cards.b.BoneShredder.class)); + cards.add(new SetCardInfo("Bouncing Beebles", 28, Rarity.COMMON, mage.cards.b.BouncingBeebles.class)); + cards.add(new SetCardInfo("Brink of Madness", 50, Rarity.RARE, mage.cards.b.BrinkOfMadness.class)); + cards.add(new SetCardInfo("Burst of Energy", 3, Rarity.COMMON, mage.cards.b.BurstOfEnergy.class)); + cards.add(new SetCardInfo("Cessation", 4, Rarity.COMMON, mage.cards.c.Cessation.class)); + cards.add(new SetCardInfo("Cloud of Faeries", 29, Rarity.COMMON, mage.cards.c.CloudOfFaeries.class)); + cards.add(new SetCardInfo("Crawlspace", 123, Rarity.RARE, mage.cards.c.Crawlspace.class)); + cards.add(new SetCardInfo("Crop Rotation", 98, Rarity.COMMON, mage.cards.c.CropRotation.class)); + cards.add(new SetCardInfo("Damping Engine", 124, Rarity.RARE, mage.cards.d.DampingEngine.class)); + cards.add(new SetCardInfo("Darkwatch Elves", 99, Rarity.UNCOMMON, mage.cards.d.DarkwatchElves.class)); + cards.add(new SetCardInfo("Defender of Chaos", 75, Rarity.COMMON, mage.cards.d.DefenderOfChaos.class)); + cards.add(new SetCardInfo("Defender of Law", 5, Rarity.COMMON, mage.cards.d.DefenderOfLaw.class)); + cards.add(new SetCardInfo("Defense Grid", 125, Rarity.RARE, mage.cards.d.DefenseGrid.class)); + cards.add(new SetCardInfo("Defense of the Heart", 100, Rarity.RARE, mage.cards.d.DefenseOfTheHeart.class)); + cards.add(new SetCardInfo("Delusions of Mediocrity", 30, Rarity.RARE, mage.cards.d.DelusionsOfMediocrity.class)); + cards.add(new SetCardInfo("Deranged Hermit", 101, Rarity.RARE, mage.cards.d.DerangedHermit.class)); + cards.add(new SetCardInfo("Devout Harpist", 6, Rarity.COMMON, mage.cards.d.DevoutHarpist.class)); + cards.add(new SetCardInfo("Engineered Plague", 51, Rarity.UNCOMMON, mage.cards.e.EngineeredPlague.class)); + cards.add(new SetCardInfo("Erase", 7, Rarity.COMMON, mage.cards.e.Erase.class)); + cards.add(new SetCardInfo("Eviscerator", 52, Rarity.RARE, mage.cards.e.Eviscerator.class)); + cards.add(new SetCardInfo("Expendable Troops", 8, Rarity.COMMON, mage.cards.e.ExpendableTroops.class)); + cards.add(new SetCardInfo("Faerie Conclave", 139, Rarity.UNCOMMON, mage.cards.f.FaerieConclave.class)); + cards.add(new SetCardInfo("Fleeting Image", 31, Rarity.RARE, mage.cards.f.FleetingImage.class)); + cards.add(new SetCardInfo("Fog of Gnats", 53, Rarity.COMMON, mage.cards.f.FogOfGnats.class)); + cards.add(new SetCardInfo("Forbidding Watchtower", 140, Rarity.UNCOMMON, mage.cards.f.ForbiddingWatchtower.class)); + cards.add(new SetCardInfo("Frantic Search", 32, Rarity.COMMON, mage.cards.f.FranticSearch.class)); + cards.add(new SetCardInfo("Gang of Elk", 102, Rarity.UNCOMMON, mage.cards.g.GangOfElk.class)); + cards.add(new SetCardInfo("Ghitu Encampment", 141, Rarity.UNCOMMON, mage.cards.g.GhituEncampment.class)); + cards.add(new SetCardInfo("Ghitu Fire-Eater", 76, Rarity.UNCOMMON, mage.cards.g.GhituFireEater.class)); + cards.add(new SetCardInfo("Ghitu Slinger", 77, Rarity.COMMON, mage.cards.g.GhituSlinger.class)); + cards.add(new SetCardInfo("Ghitu War Cry", 78, Rarity.UNCOMMON, mage.cards.g.GhituWarCry.class)); + cards.add(new SetCardInfo("Giant Cockroach", 54, Rarity.COMMON, mage.cards.g.GiantCockroach.class)); + cards.add(new SetCardInfo("Goblin Medics", 79, Rarity.COMMON, mage.cards.g.GoblinMedics.class)); + cards.add(new SetCardInfo("Goblin Welder", 80, Rarity.RARE, mage.cards.g.GoblinWelder.class)); + cards.add(new SetCardInfo("Granite Grip", 81, Rarity.COMMON, mage.cards.g.GraniteGrip.class)); + cards.add(new SetCardInfo("Grim Monolith", 126, Rarity.RARE, mage.cards.g.GrimMonolith.class)); + cards.add(new SetCardInfo("Harmonic Convergence", 103, Rarity.UNCOMMON, mage.cards.h.HarmonicConvergence.class)); + cards.add(new SetCardInfo("Hidden Gibbons", 104, Rarity.RARE, mage.cards.h.HiddenGibbons.class)); + cards.add(new SetCardInfo("Hope and Glory", 9, Rarity.UNCOMMON, mage.cards.h.HopeAndGlory.class)); + cards.add(new SetCardInfo("Impending Disaster", 82, Rarity.RARE, mage.cards.i.ImpendingDisaster.class)); + cards.add(new SetCardInfo("Intervene", 33, Rarity.COMMON, mage.cards.i.Intervene.class)); + cards.add(new SetCardInfo("Iron Maiden", 127, Rarity.RARE, mage.cards.i.IronMaiden.class)); + cards.add(new SetCardInfo("Iron Will", 10, Rarity.COMMON, mage.cards.i.IronWill.class)); + cards.add(new SetCardInfo("Jhoira's Toolbox", 128, Rarity.UNCOMMON, mage.cards.j.JhoirasToolbox.class)); + cards.add(new SetCardInfo("Karmic Guide", 11, Rarity.RARE, mage.cards.k.KarmicGuide.class)); + cards.add(new SetCardInfo("King Crab", 34, Rarity.UNCOMMON, mage.cards.k.KingCrab.class)); + cards.add(new SetCardInfo("Knighthood", 12, Rarity.UNCOMMON, mage.cards.k.Knighthood.class)); + cards.add(new SetCardInfo("Last-Ditch Effort", 83, Rarity.UNCOMMON, mage.cards.l.LastDitchEffort.class)); + cards.add(new SetCardInfo("Lava Axe", 84, Rarity.COMMON, mage.cards.l.LavaAxe.class)); + cards.add(new SetCardInfo("Levitation", 35, Rarity.UNCOMMON, mage.cards.l.Levitation.class)); + cards.add(new SetCardInfo("Lone Wolf", 105, Rarity.UNCOMMON, mage.cards.l.LoneWolf.class)); + cards.add(new SetCardInfo("Lurking Skirge", 55, Rarity.RARE, mage.cards.l.LurkingSkirge.class)); + cards.add(new SetCardInfo("Martyr's Cause", 13, Rarity.UNCOMMON, mage.cards.m.MartyrsCause.class)); + cards.add(new SetCardInfo("Memory Jar", 129, Rarity.RARE, mage.cards.m.MemoryJar.class)); + cards.add(new SetCardInfo("Might of Oaks", 106, Rarity.RARE, mage.cards.m.MightOfOaks.class)); + cards.add(new SetCardInfo("Miscalculation", 36, Rarity.COMMON, mage.cards.m.Miscalculation.class)); + cards.add(new SetCardInfo("Molten Hydra", 85, Rarity.RARE, mage.cards.m.MoltenHydra.class)); + cards.add(new SetCardInfo("Mother of Runes", 14, Rarity.UNCOMMON, mage.cards.m.MotherOfRunes.class)); + cards.add(new SetCardInfo("Multani's Acolyte", 108, Rarity.COMMON, mage.cards.m.MultanisAcolyte.class)); + cards.add(new SetCardInfo("Multani's Presence", 109, Rarity.UNCOMMON, mage.cards.m.MultanisPresence.class)); + cards.add(new SetCardInfo("Multani, Maro-Sorcerer", 107, Rarity.RARE, mage.cards.m.MultaniMaroSorcerer.class)); + cards.add(new SetCardInfo("No Mercy", 56, Rarity.RARE, mage.cards.n.NoMercy.class)); + cards.add(new SetCardInfo("Opal Avenger", 15, Rarity.RARE, mage.cards.o.OpalAvenger.class)); + cards.add(new SetCardInfo("Opal Champion", 16, Rarity.COMMON, mage.cards.o.OpalChampion.class)); + cards.add(new SetCardInfo("Opportunity", 37, Rarity.UNCOMMON, mage.cards.o.Opportunity.class)); + cards.add(new SetCardInfo("Ostracize", 57, Rarity.COMMON, mage.cards.o.Ostracize.class)); + cards.add(new SetCardInfo("Palinchron", 38, Rarity.RARE, mage.cards.p.Palinchron.class)); + cards.add(new SetCardInfo("Parch", 86, Rarity.COMMON, mage.cards.p.Parch.class)); + cards.add(new SetCardInfo("Peace and Quiet", 17, Rarity.UNCOMMON, mage.cards.p.PeaceAndQuiet.class)); + cards.add(new SetCardInfo("Phyrexian Broodlings", 58, Rarity.COMMON, mage.cards.p.PhyrexianBroodlings.class)); + cards.add(new SetCardInfo("Phyrexian Debaser", 59, Rarity.COMMON, mage.cards.p.PhyrexianDebaser.class)); + cards.add(new SetCardInfo("Phyrexian Defiler", 60, Rarity.UNCOMMON, mage.cards.p.PhyrexianDefiler.class)); + cards.add(new SetCardInfo("Phyrexian Denouncer", 61, Rarity.COMMON, mage.cards.p.PhyrexianDenouncer.class)); + cards.add(new SetCardInfo("Phyrexian Plaguelord", 62, Rarity.RARE, mage.cards.p.PhyrexianPlaguelord.class)); + cards.add(new SetCardInfo("Phyrexian Reclamation", 63, Rarity.UNCOMMON, mage.cards.p.PhyrexianReclamation.class)); + cards.add(new SetCardInfo("Plague Beetle", 64, Rarity.COMMON, mage.cards.p.PlagueBeetle.class)); + cards.add(new SetCardInfo("Planar Collapse", 18, Rarity.RARE, mage.cards.p.PlanarCollapse.class)); + cards.add(new SetCardInfo("Purify", 19, Rarity.RARE, mage.cards.p.Purify.class)); + cards.add(new SetCardInfo("Pygmy Pyrosaur", 87, Rarity.COMMON, mage.cards.p.PygmyPyrosaur.class)); + cards.add(new SetCardInfo("Pyromancy", 88, Rarity.RARE, mage.cards.p.Pyromancy.class)); + cards.add(new SetCardInfo("Quicksilver Amulet", 130, Rarity.RARE, mage.cards.q.QuicksilverAmulet.class)); + cards.add(new SetCardInfo("Rack and Ruin", 89, Rarity.UNCOMMON, mage.cards.r.RackAndRuin.class)); + cards.add(new SetCardInfo("Radiant's Dragoons", 21, Rarity.UNCOMMON, mage.cards.r.RadiantsDragoons.class)); + cards.add(new SetCardInfo("Radiant's Judgment", 22, Rarity.COMMON, mage.cards.r.RadiantsJudgment.class)); + cards.add(new SetCardInfo("Radiant, Archangel", 20, Rarity.RARE, mage.cards.r.RadiantArchangel.class)); + cards.add(new SetCardInfo("Rancor", 110, Rarity.COMMON, mage.cards.r.Rancor.class)); + cards.add(new SetCardInfo("Rank and File", 65, Rarity.UNCOMMON, mage.cards.r.RankAndFile.class)); + cards.add(new SetCardInfo("Raven Familiar", 39, Rarity.UNCOMMON, mage.cards.r.RavenFamiliar.class)); + cards.add(new SetCardInfo("Rebuild", 40, Rarity.UNCOMMON, mage.cards.r.Rebuild.class)); + cards.add(new SetCardInfo("Repopulate", 111, Rarity.COMMON, mage.cards.r.Repopulate.class)); + cards.add(new SetCardInfo("Ring of Gix", 131, Rarity.RARE, mage.cards.r.RingOfGix.class)); + cards.add(new SetCardInfo("Rivalry", 90, Rarity.RARE, mage.cards.r.Rivalry.class)); + cards.add(new SetCardInfo("Scrapheap", 132, Rarity.RARE, mage.cards.s.Scrapheap.class)); + cards.add(new SetCardInfo("Second Chance", 41, Rarity.RARE, mage.cards.s.SecondChance.class)); + cards.add(new SetCardInfo("Shivan Phoenix", 91, Rarity.RARE, mage.cards.s.ShivanPhoenix.class)); + cards.add(new SetCardInfo("Sick and Tired", 66, Rarity.COMMON, mage.cards.s.SickAndTired.class)); + cards.add(new SetCardInfo("Silk Net", 112, Rarity.COMMON, mage.cards.s.SilkNet.class)); + cards.add(new SetCardInfo("Simian Grunts", 113, Rarity.COMMON, mage.cards.s.SimianGrunts.class)); + cards.add(new SetCardInfo("Sleeper's Guile", 67, Rarity.COMMON, mage.cards.s.SleepersGuile.class)); + cards.add(new SetCardInfo("Slow Motion", 42, Rarity.COMMON, mage.cards.s.SlowMotion.class)); + cards.add(new SetCardInfo("Sluggishness", 92, Rarity.COMMON, mage.cards.s.Sluggishness.class)); + cards.add(new SetCardInfo("Snap", 43, Rarity.COMMON, mage.cards.s.Snap.class)); + cards.add(new SetCardInfo("Spawning Pool", 142, Rarity.UNCOMMON, mage.cards.s.SpawningPool.class)); + cards.add(new SetCardInfo("Subversion", 68, Rarity.RARE, mage.cards.s.Subversion.class)); + cards.add(new SetCardInfo("Sustainer of the Realm", 23, Rarity.UNCOMMON, mage.cards.s.SustainerOfTheRealm.class)); + cards.add(new SetCardInfo("Swat", 69, Rarity.COMMON, mage.cards.s.Swat.class)); + cards.add(new SetCardInfo("Tethered Skirge", 70, Rarity.UNCOMMON, mage.cards.t.TetheredSkirge.class)); + cards.add(new SetCardInfo("Thornwind Faeries", 44, Rarity.COMMON, mage.cards.t.ThornwindFaeries.class)); + cards.add(new SetCardInfo("Thran Lens", 133, Rarity.RARE, mage.cards.t.ThranLens.class)); + cards.add(new SetCardInfo("Thran War Machine", 134, Rarity.UNCOMMON, mage.cards.t.ThranWarMachine.class)); + cards.add(new SetCardInfo("Thran Weaponry", 135, Rarity.RARE, mage.cards.t.ThranWeaponry.class)); + cards.add(new SetCardInfo("Ticking Gnomes", 136, Rarity.UNCOMMON, mage.cards.t.TickingGnomes.class)); + cards.add(new SetCardInfo("Tinker", 45, Rarity.UNCOMMON, mage.cards.t.Tinker.class)); + cards.add(new SetCardInfo("Tragic Poet", 24, Rarity.COMMON, mage.cards.t.TragicPoet.class)); + cards.add(new SetCardInfo("Treacherous Link", 71, Rarity.UNCOMMON, mage.cards.t.TreacherousLink.class)); + cards.add(new SetCardInfo("Treefolk Mystic", 114, Rarity.COMMON, mage.cards.t.TreefolkMystic.class)); + cards.add(new SetCardInfo("Treetop Village", 143, Rarity.UNCOMMON, mage.cards.t.TreetopVillage.class)); + cards.add(new SetCardInfo("Unearth", 72, Rarity.COMMON, mage.cards.u.Unearth.class)); + cards.add(new SetCardInfo("Urza's Blueprints", 137, Rarity.RARE, mage.cards.u.UrzasBlueprints.class)); + cards.add(new SetCardInfo("Viashino Bey", 93, Rarity.COMMON, mage.cards.v.ViashinoBey.class)); + cards.add(new SetCardInfo("Viashino Cutthroat", 94, Rarity.UNCOMMON, mage.cards.v.ViashinoCutthroat.class)); + cards.add(new SetCardInfo("Viashino Heretic", 95, Rarity.UNCOMMON, mage.cards.v.ViashinoHeretic.class)); + cards.add(new SetCardInfo("Viashino Sandscout", 96, Rarity.COMMON, mage.cards.v.ViashinoSandscout.class)); + cards.add(new SetCardInfo("Vigilant Drake", 46, Rarity.COMMON, mage.cards.v.VigilantDrake.class)); + cards.add(new SetCardInfo("Walking Sponge", 47, Rarity.UNCOMMON, mage.cards.w.WalkingSponge.class)); + cards.add(new SetCardInfo("Weatherseed Elf", 115, Rarity.COMMON, mage.cards.w.WeatherseedElf.class)); + cards.add(new SetCardInfo("Weatherseed Faeries", 48, Rarity.COMMON, mage.cards.w.WeatherseedFaeries.class)); + cards.add(new SetCardInfo("Weatherseed Treefolk", 116, Rarity.RARE, mage.cards.w.WeatherseedTreefolk.class)); + cards.add(new SetCardInfo("Wheel of Torture", 138, Rarity.RARE, mage.cards.w.WheelOfTorture.class)); + cards.add(new SetCardInfo("Wing Snare", 117, Rarity.UNCOMMON, mage.cards.w.WingSnare.class)); + cards.add(new SetCardInfo("Yavimaya Granger", 118, Rarity.COMMON, mage.cards.y.YavimayaGranger.class)); + cards.add(new SetCardInfo("Yavimaya Scion", 119, Rarity.COMMON, mage.cards.y.YavimayaScion.class)); + cards.add(new SetCardInfo("Yavimaya Wurm", 120, Rarity.COMMON, mage.cards.y.YavimayaWurm.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/UrzasSaga.java b/Mage.Sets/src/mage/sets/UrzasSaga.java index 161a5e42ca..ab0632ed8e 100644 --- a/Mage.Sets/src/mage/sets/UrzasSaga.java +++ b/Mage.Sets/src/mage/sets/UrzasSaga.java @@ -1,362 +1,379 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author Backfir3 - */ -public final class UrzasSaga extends ExpansionSet { - - private static final UrzasSaga instance = new UrzasSaga(); - - public static UrzasSaga getInstance() { - return instance; - } - - private UrzasSaga() { - super("Urza's Saga", "USG", ExpansionSet.buildDate(1998, 10, 12), SetType.EXPANSION); - this.blockName = "Urza"; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Absolute Grace", 1, Rarity.UNCOMMON, mage.cards.a.AbsoluteGrace.class)); - cards.add(new SetCardInfo("Absolute Law", 2, Rarity.UNCOMMON, mage.cards.a.AbsoluteLaw.class)); - cards.add(new SetCardInfo("Abundance", 229, Rarity.RARE, mage.cards.a.Abundance.class)); - cards.add(new SetCardInfo("Abyssal Horror", 115, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); - cards.add(new SetCardInfo("Academy Researchers", 58, Rarity.UNCOMMON, mage.cards.a.AcademyResearchers.class)); - cards.add(new SetCardInfo("Acidic Soil", 172, Rarity.UNCOMMON, mage.cards.a.AcidicSoil.class)); - cards.add(new SetCardInfo("Acridian", 230, Rarity.COMMON, mage.cards.a.Acridian.class)); - cards.add(new SetCardInfo("Albino Troll", 231, Rarity.UNCOMMON, mage.cards.a.AlbinoTroll.class)); - cards.add(new SetCardInfo("Anaconda", 232, Rarity.UNCOMMON, mage.cards.a.Anaconda.class)); - cards.add(new SetCardInfo("Angelic Chorus", 3, Rarity.RARE, mage.cards.a.AngelicChorus.class)); - cards.add(new SetCardInfo("Angelic Page", 4, Rarity.COMMON, mage.cards.a.AngelicPage.class)); - cards.add(new SetCardInfo("Annul", 59, Rarity.COMMON, mage.cards.a.Annul.class)); - cards.add(new SetCardInfo("Arcane Laboratory", 60, Rarity.UNCOMMON, mage.cards.a.ArcaneLaboratory.class)); - cards.add(new SetCardInfo("Arc Lightning", 174, Rarity.COMMON, mage.cards.a.ArcLightning.class)); - cards.add(new SetCardInfo("Argothian Elder", 233, Rarity.UNCOMMON, mage.cards.a.ArgothianElder.class)); - cards.add(new SetCardInfo("Argothian Enchantress", 234, Rarity.RARE, mage.cards.a.ArgothianEnchantress.class)); - cards.add(new SetCardInfo("Argothian Swine", 235, Rarity.COMMON, mage.cards.a.ArgothianSwine.class)); - cards.add(new SetCardInfo("Argothian Wurm", 236, Rarity.RARE, mage.cards.a.ArgothianWurm.class)); - cards.add(new SetCardInfo("Attunement", 61, Rarity.RARE, mage.cards.a.Attunement.class)); - cards.add(new SetCardInfo("Back to Basics", 62, Rarity.RARE, mage.cards.b.BackToBasics.class)); - cards.add(new SetCardInfo("Barrin, Master Wizard", 63, Rarity.RARE, mage.cards.b.BarrinMasterWizard.class)); - cards.add(new SetCardInfo("Barrin's Codex", 286, Rarity.RARE, mage.cards.b.BarrinsCodex.class)); - cards.add(new SetCardInfo("Bedlam", 175, Rarity.RARE, mage.cards.b.Bedlam.class)); - cards.add(new SetCardInfo("Befoul", 116, Rarity.COMMON, mage.cards.b.Befoul.class)); - cards.add(new SetCardInfo("Bereavement", 117, Rarity.UNCOMMON, mage.cards.b.Bereavement.class)); - cards.add(new SetCardInfo("Blanchwood Armor", 237, Rarity.UNCOMMON, mage.cards.b.BlanchwoodArmor.class)); - cards.add(new SetCardInfo("Blanchwood Treefolk", 238, Rarity.COMMON, mage.cards.b.BlanchwoodTreefolk.class)); - cards.add(new SetCardInfo("Blasted Landscape", 319, Rarity.UNCOMMON, mage.cards.b.BlastedLandscape.class)); - cards.add(new SetCardInfo("Blood Vassal", 118, Rarity.COMMON, mage.cards.b.BloodVassal.class)); - cards.add(new SetCardInfo("Bog Raiders", 119, Rarity.COMMON, mage.cards.b.BogRaiders.class)); - cards.add(new SetCardInfo("Brand", 176, Rarity.RARE, mage.cards.b.Brand.class)); - cards.add(new SetCardInfo("Bravado", 177, Rarity.COMMON, mage.cards.b.Bravado.class)); - cards.add(new SetCardInfo("Breach", 120, Rarity.COMMON, mage.cards.b.Breach.class)); - cards.add(new SetCardInfo("Brilliant Halo", 5, Rarity.COMMON, mage.cards.b.BrilliantHalo.class)); - cards.add(new SetCardInfo("Bull Hippo", 239, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); - cards.add(new SetCardInfo("Bulwark", 178, Rarity.RARE, mage.cards.b.Bulwark.class)); - cards.add(new SetCardInfo("Cackling Fiend", 121, Rarity.COMMON, mage.cards.c.CacklingFiend.class)); - cards.add(new SetCardInfo("Carpet of Flowers", 240, Rarity.UNCOMMON, mage.cards.c.CarpetOfFlowers.class)); - cards.add(new SetCardInfo("Carrion Beetles", 122, Rarity.COMMON, mage.cards.c.CarrionBeetles.class)); - cards.add(new SetCardInfo("Catalog", 64, Rarity.COMMON, mage.cards.c.Catalog.class)); - cards.add(new SetCardInfo("Catastrophe", 6, Rarity.RARE, mage.cards.c.Catastrophe.class)); - cards.add(new SetCardInfo("Cathodion", 287, Rarity.UNCOMMON, mage.cards.c.Cathodion.class)); - cards.add(new SetCardInfo("Cave Tiger", 241, Rarity.COMMON, mage.cards.c.CaveTiger.class)); - cards.add(new SetCardInfo("Child of Gaea", 242, Rarity.RARE, mage.cards.c.ChildOfGaea.class)); - cards.add(new SetCardInfo("Chimeric Staff", 288, Rarity.RARE, mage.cards.c.ChimericStaff.class)); - cards.add(new SetCardInfo("Citanul Centaurs", 243, Rarity.RARE, mage.cards.c.CitanulCentaurs.class)); - cards.add(new SetCardInfo("Citanul Flute", 289, Rarity.RARE, mage.cards.c.CitanulFlute.class)); - cards.add(new SetCardInfo("Citanul Hierophants", 244, Rarity.RARE, mage.cards.c.CitanulHierophants.class)); - cards.add(new SetCardInfo("Claws of Gix", 290, Rarity.UNCOMMON, mage.cards.c.ClawsOfGix.class)); - cards.add(new SetCardInfo("Clear", 7, Rarity.UNCOMMON, mage.cards.c.Clear.class)); - cards.add(new SetCardInfo("Cloak of Mists", 65, Rarity.COMMON, mage.cards.c.CloakOfMists.class)); - cards.add(new SetCardInfo("Confiscate", 66, Rarity.UNCOMMON, mage.cards.c.Confiscate.class)); - cards.add(new SetCardInfo("Congregate", 8, Rarity.COMMON, mage.cards.c.Congregate.class)); - cards.add(new SetCardInfo("Contamination", 123, Rarity.RARE, mage.cards.c.Contamination.class)); - cards.add(new SetCardInfo("Copper Gnomes", 291, Rarity.RARE, mage.cards.c.CopperGnomes.class)); - cards.add(new SetCardInfo("Coral Merfolk", 67, Rarity.COMMON, mage.cards.c.CoralMerfolk.class)); - cards.add(new SetCardInfo("Corrupt", 124, Rarity.COMMON, mage.cards.c.Corrupt.class)); - cards.add(new SetCardInfo("Cradle Guard", 245, Rarity.UNCOMMON, mage.cards.c.CradleGuard.class)); - cards.add(new SetCardInfo("Crater Hellion", 179, Rarity.RARE, mage.cards.c.CraterHellion.class)); - cards.add(new SetCardInfo("Crazed Skirge", 125, Rarity.UNCOMMON, mage.cards.c.CrazedSkirge.class)); - cards.add(new SetCardInfo("Crosswinds", 246, Rarity.UNCOMMON, mage.cards.c.Crosswinds.class)); - cards.add(new SetCardInfo("Crystal Chimes", 292, Rarity.UNCOMMON, mage.cards.c.CrystalChimes.class)); - cards.add(new SetCardInfo("Curfew", 68, Rarity.COMMON, mage.cards.c.Curfew.class)); - cards.add(new SetCardInfo("Darkest Hour", 128, Rarity.RARE, mage.cards.d.DarkestHour.class)); - cards.add(new SetCardInfo("Dark Hatchling", 126, Rarity.RARE, mage.cards.d.DarkHatchling.class)); - cards.add(new SetCardInfo("Dark Ritual", 127, Rarity.COMMON, mage.cards.d.DarkRitual.class)); - cards.add(new SetCardInfo("Defensive Formation", 9, Rarity.UNCOMMON, mage.cards.d.DefensiveFormation.class)); - cards.add(new SetCardInfo("Despondency", 129, Rarity.COMMON, mage.cards.d.Despondency.class)); - cards.add(new SetCardInfo("Destructive Urge", 180, Rarity.UNCOMMON, mage.cards.d.DestructiveUrge.class)); - cards.add(new SetCardInfo("Diabolic Servitude", 130, Rarity.UNCOMMON, mage.cards.d.DiabolicServitude.class)); - cards.add(new SetCardInfo("Disciple of Grace", 10, Rarity.COMMON, mage.cards.d.DiscipleOfGrace.class)); - cards.add(new SetCardInfo("Disciple of Law", 11, Rarity.COMMON, mage.cards.d.DiscipleOfLaw.class)); - cards.add(new SetCardInfo("Disenchant", 12, Rarity.COMMON, mage.cards.d.Disenchant.class)); - cards.add(new SetCardInfo("Disorder", 181, Rarity.UNCOMMON, mage.cards.d.Disorder.class)); - cards.add(new SetCardInfo("Disruptive Student", 69, Rarity.COMMON, mage.cards.d.DisruptiveStudent.class)); - cards.add(new SetCardInfo("Douse", 70, Rarity.UNCOMMON, mage.cards.d.Douse.class)); - cards.add(new SetCardInfo("Dragon Blood", 293, Rarity.UNCOMMON, mage.cards.d.DragonBlood.class)); - cards.add(new SetCardInfo("Drifting Djinn", 71, Rarity.RARE, mage.cards.d.DriftingDjinn.class)); - cards.add(new SetCardInfo("Drifting Meadow", 320, Rarity.COMMON, mage.cards.d.DriftingMeadow.class)); - cards.add(new SetCardInfo("Dromosaur", 182, Rarity.COMMON, mage.cards.d.Dromosaur.class)); - cards.add(new SetCardInfo("Duress", 132, Rarity.COMMON, mage.cards.d.Duress.class)); - cards.add(new SetCardInfo("Eastern Paladin", 133, Rarity.RARE, mage.cards.e.EasternPaladin.class)); - cards.add(new SetCardInfo("Electryte", 183, Rarity.RARE, mage.cards.e.Electryte.class)); - cards.add(new SetCardInfo("Elite Archers", 13, Rarity.RARE, mage.cards.e.EliteArchers.class)); - cards.add(new SetCardInfo("Elvish Herder", 247, Rarity.COMMON, mage.cards.e.ElvishHerder.class)); - cards.add(new SetCardInfo("Elvish Lyrist", 248, Rarity.COMMON, mage.cards.e.ElvishLyrist.class)); - cards.add(new SetCardInfo("Endless Wurm", 249, Rarity.RARE, mage.cards.e.EndlessWurm.class)); - cards.add(new SetCardInfo("Endoskeleton", 294, Rarity.UNCOMMON, mage.cards.e.Endoskeleton.class)); - cards.add(new SetCardInfo("Energy Field", 73, Rarity.RARE, mage.cards.e.EnergyField.class)); - cards.add(new SetCardInfo("Exhaustion", 74, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); - cards.add(new SetCardInfo("Exhume", 134, Rarity.COMMON, mage.cards.e.Exhume.class)); - cards.add(new SetCardInfo("Exploration", 250, Rarity.RARE, mage.cards.e.Exploration.class)); - cards.add(new SetCardInfo("Expunge", 135, Rarity.COMMON, mage.cards.e.Expunge.class)); - cards.add(new SetCardInfo("Faith Healer", 14, Rarity.RARE, mage.cards.f.FaithHealer.class)); - cards.add(new SetCardInfo("Falter", 184, Rarity.COMMON, mage.cards.f.Falter.class)); - cards.add(new SetCardInfo("Fault Line", 185, Rarity.RARE, mage.cards.f.FaultLine.class)); - cards.add(new SetCardInfo("Fecundity", 251, Rarity.UNCOMMON, mage.cards.f.Fecundity.class)); - cards.add(new SetCardInfo("Fertile Ground", 252, Rarity.COMMON, mage.cards.f.FertileGround.class)); - cards.add(new SetCardInfo("Fiery Mantle", 186, Rarity.COMMON, mage.cards.f.FieryMantle.class)); - cards.add(new SetCardInfo("Fire Ants", 187, Rarity.UNCOMMON, mage.cards.f.FireAnts.class)); - cards.add(new SetCardInfo("Flesh Reaver", 136, Rarity.UNCOMMON, mage.cards.f.FleshReaver.class)); - cards.add(new SetCardInfo("Fluctuator", 295, Rarity.RARE, mage.cards.f.Fluctuator.class)); - cards.add(new SetCardInfo("Fog Bank", 75, Rarity.UNCOMMON, mage.cards.f.FogBank.class)); - cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Fortitude", 253, Rarity.COMMON, mage.cards.f.Fortitude.class)); - cards.add(new SetCardInfo("Gaea's Bounty", 254, Rarity.COMMON, mage.cards.g.GaeasBounty.class)); - cards.add(new SetCardInfo("Gaea's Cradle", 321, Rarity.RARE, mage.cards.g.GaeasCradle.class)); - cards.add(new SetCardInfo("Gaea's Embrace", 255, Rarity.UNCOMMON, mage.cards.g.GaeasEmbrace.class)); - cards.add(new SetCardInfo("Gamble", 188, Rarity.RARE, mage.cards.g.Gamble.class)); - cards.add(new SetCardInfo("Gilded Drake", 76, Rarity.RARE, mage.cards.g.GildedDrake.class)); - cards.add(new SetCardInfo("Glorious Anthem", 15, Rarity.RARE, mage.cards.g.GloriousAnthem.class)); - cards.add(new SetCardInfo("Goblin Cadets", 189, Rarity.UNCOMMON, mage.cards.g.GoblinCadets.class)); - cards.add(new SetCardInfo("Goblin Lackey", 190, Rarity.UNCOMMON, mage.cards.g.GoblinLackey.class)); - cards.add(new SetCardInfo("Goblin Matron", 191, Rarity.COMMON, mage.cards.g.GoblinMatron.class)); - cards.add(new SetCardInfo("Goblin Offensive", 192, Rarity.UNCOMMON, mage.cards.g.GoblinOffensive.class)); - cards.add(new SetCardInfo("Goblin Patrol", 193, Rarity.COMMON, mage.cards.g.GoblinPatrol.class)); - cards.add(new SetCardInfo("Goblin Raider", 194, Rarity.COMMON, mage.cards.g.GoblinRaider.class)); - cards.add(new SetCardInfo("Goblin Spelunkers", 195, Rarity.COMMON, mage.cards.g.GoblinSpelunkers.class)); - cards.add(new SetCardInfo("Goblin War Buggy", 196, Rarity.COMMON, mage.cards.g.GoblinWarBuggy.class)); - cards.add(new SetCardInfo("Gorilla Warrior", 256, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); - cards.add(new SetCardInfo("Grafted Skullcap", 296, Rarity.RARE, mage.cards.g.GraftedSkullcap.class)); - cards.add(new SetCardInfo("Greater Good", 257, Rarity.RARE, mage.cards.g.GreaterGood.class)); - cards.add(new SetCardInfo("Great Whale", 77, Rarity.RARE, mage.cards.g.GreatWhale.class)); - cards.add(new SetCardInfo("Greener Pastures", 258, Rarity.RARE, mage.cards.g.GreenerPastures.class)); - cards.add(new SetCardInfo("Guma", 197, Rarity.UNCOMMON, mage.cards.g.Guma.class)); - cards.add(new SetCardInfo("Hawkeater Moth", 259, Rarity.UNCOMMON, mage.cards.h.HawkeaterMoth.class)); - cards.add(new SetCardInfo("Headlong Rush", 198, Rarity.COMMON, mage.cards.h.HeadlongRush.class)); - cards.add(new SetCardInfo("Healing Salve", 16, Rarity.COMMON, mage.cards.h.HealingSalve.class)); - cards.add(new SetCardInfo("Heat Ray", 199, Rarity.COMMON, mage.cards.h.HeatRay.class)); - cards.add(new SetCardInfo("Herald of Serra", 17, Rarity.RARE, mage.cards.h.HeraldOfSerra.class)); - cards.add(new SetCardInfo("Hermetic Study", 78, Rarity.COMMON, mage.cards.h.HermeticStudy.class)); - cards.add(new SetCardInfo("Hibernation", 79, Rarity.UNCOMMON, mage.cards.h.Hibernation.class)); - cards.add(new SetCardInfo("Hidden Ancients", 260, Rarity.UNCOMMON, mage.cards.h.HiddenAncients.class)); - cards.add(new SetCardInfo("Hidden Guerrillas", 261, Rarity.UNCOMMON, mage.cards.h.HiddenGuerrillas.class)); - cards.add(new SetCardInfo("Hidden Herd", 262, Rarity.RARE, mage.cards.h.HiddenHerd.class)); - cards.add(new SetCardInfo("Hidden Spider", 264, Rarity.COMMON, mage.cards.h.HiddenSpider.class)); - cards.add(new SetCardInfo("Hollow Dogs", 137, Rarity.COMMON, mage.cards.h.HollowDogs.class)); - cards.add(new SetCardInfo("Hopping Automaton", 297, Rarity.UNCOMMON, mage.cards.h.HoppingAutomaton.class)); - cards.add(new SetCardInfo("Horseshoe Crab", 80, Rarity.COMMON, mage.cards.h.HorseshoeCrab.class)); - cards.add(new SetCardInfo("Humble", 18, Rarity.UNCOMMON, mage.cards.h.Humble.class)); - cards.add(new SetCardInfo("Hush", 266, Rarity.COMMON, mage.cards.h.Hush.class)); - cards.add(new SetCardInfo("Ill-Gotten Gains", 138, Rarity.RARE, mage.cards.i.IllGottenGains.class)); - cards.add(new SetCardInfo("Imaginary Pet", 81, Rarity.RARE, mage.cards.i.ImaginaryPet.class)); - cards.add(new SetCardInfo("Intrepid Hero", 19, Rarity.RARE, mage.cards.i.IntrepidHero.class)); - cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Jagged Lightning", 200, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); - cards.add(new SetCardInfo("Karn, Silver Golem", 298, Rarity.RARE, mage.cards.k.KarnSilverGolem.class)); - cards.add(new SetCardInfo("Launch", 82, Rarity.COMMON, mage.cards.l.Launch.class)); - cards.add(new SetCardInfo("Lay Waste", 201, Rarity.COMMON, mage.cards.l.LayWaste.class)); - cards.add(new SetCardInfo("Lifeline", 299, Rarity.RARE, mage.cards.l.Lifeline.class)); - cards.add(new SetCardInfo("Lightning Dragon", 202, Rarity.RARE, mage.cards.l.LightningDragon.class)); - cards.add(new SetCardInfo("Lilting Refrain", 83, Rarity.UNCOMMON, mage.cards.l.LiltingRefrain.class)); - cards.add(new SetCardInfo("Lingering Mirage", 84, Rarity.UNCOMMON, mage.cards.l.LingeringMirage.class)); - cards.add(new SetCardInfo("Looming Shade", 139, Rarity.COMMON, mage.cards.l.LoomingShade.class)); - cards.add(new SetCardInfo("Lotus Blossom", 300, Rarity.RARE, mage.cards.l.LotusBlossom.class)); - cards.add(new SetCardInfo("Lull", 267, Rarity.COMMON, mage.cards.l.Lull.class)); - cards.add(new SetCardInfo("Lurking Evil", 140, Rarity.RARE, mage.cards.l.LurkingEvil.class)); - cards.add(new SetCardInfo("Mana Leech", 141, Rarity.UNCOMMON, mage.cards.m.ManaLeech.class)); - cards.add(new SetCardInfo("Meltdown", 203, Rarity.UNCOMMON, mage.cards.m.Meltdown.class)); - cards.add(new SetCardInfo("Metrognome", 301, Rarity.RARE, mage.cards.m.Metrognome.class)); - cards.add(new SetCardInfo("Midsummer Revel", 268, Rarity.RARE, mage.cards.m.MidsummerRevel.class)); - cards.add(new SetCardInfo("Mishra's Helix", 302, Rarity.RARE, mage.cards.m.MishrasHelix.class)); - cards.add(new SetCardInfo("Mobile Fort", 303, Rarity.UNCOMMON, mage.cards.m.MobileFort.class)); - cards.add(new SetCardInfo("Monk Idealist", 20, Rarity.UNCOMMON, mage.cards.m.MonkIdealist.class)); - cards.add(new SetCardInfo("Monk Realist", 21, Rarity.COMMON, mage.cards.m.MonkRealist.class)); - cards.add(new SetCardInfo("Morphling", 85, Rarity.RARE, mage.cards.m.Morphling.class)); - cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("No Rest for the Wicked", 142, Rarity.UNCOMMON, mage.cards.n.NoRestForTheWicked.class)); - cards.add(new SetCardInfo("Noetic Scales", 304, Rarity.RARE, mage.cards.n.NoeticScales.class)); - cards.add(new SetCardInfo("Okk", 204, Rarity.RARE, mage.cards.o.Okk.class)); - cards.add(new SetCardInfo("Opal Archangel", 23, Rarity.RARE, mage.cards.o.OpalArchangel.class)); - cards.add(new SetCardInfo("Opal Caryatid", 24, Rarity.COMMON, mage.cards.o.OpalCaryatid.class)); - cards.add(new SetCardInfo("Opal Gargoyle", 25, Rarity.COMMON, mage.cards.o.OpalGargoyle.class)); - cards.add(new SetCardInfo("Oppression", 143, Rarity.RARE, mage.cards.o.Oppression.class)); - cards.add(new SetCardInfo("Order of Yawgmoth", 144, Rarity.UNCOMMON, mage.cards.o.OrderOfYawgmoth.class)); - cards.add(new SetCardInfo("Pacifism", 27, Rarity.COMMON, mage.cards.p.Pacifism.class)); - cards.add(new SetCardInfo("Parasitic Bond", 145, Rarity.UNCOMMON, mage.cards.p.ParasiticBond.class)); - cards.add(new SetCardInfo("Pariah", 28, Rarity.RARE, mage.cards.p.Pariah.class)); - cards.add(new SetCardInfo("Path of Peace", 29, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); - cards.add(new SetCardInfo("Pegasus Charger", 30, Rarity.COMMON, mage.cards.p.PegasusCharger.class)); - cards.add(new SetCardInfo("Pendrell Drake", 86, Rarity.COMMON, mage.cards.p.PendrellDrake.class)); - cards.add(new SetCardInfo("Pendrell Flux", 87, Rarity.COMMON, mage.cards.p.PendrellFlux.class)); - cards.add(new SetCardInfo("Peregrine Drake", 88, Rarity.UNCOMMON, mage.cards.p.PeregrineDrake.class)); - cards.add(new SetCardInfo("Persecute", 146, Rarity.RARE, mage.cards.p.Persecute.class)); - cards.add(new SetCardInfo("Pestilence", 147, Rarity.COMMON, mage.cards.p.Pestilence.class)); - cards.add(new SetCardInfo("Phyrexian Colossus", 305, Rarity.RARE, mage.cards.p.PhyrexianColossus.class)); - cards.add(new SetCardInfo("Phyrexian Ghoul", 148, Rarity.COMMON, mage.cards.p.PhyrexianGhoul.class)); - cards.add(new SetCardInfo("Phyrexian Processor", 306, Rarity.RARE, mage.cards.p.PhyrexianProcessor.class)); - cards.add(new SetCardInfo("Phyrexian Tower", 322, Rarity.RARE, mage.cards.p.PhyrexianTower.class)); - cards.add(new SetCardInfo("Pit Trap", 307, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); - cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Planar Birth", 31, Rarity.RARE, mage.cards.p.PlanarBirth.class)); - cards.add(new SetCardInfo("Planar Void", 149, Rarity.UNCOMMON, mage.cards.p.PlanarVoid.class)); - cards.add(new SetCardInfo("Polluted Mire", 323, Rarity.COMMON, mage.cards.p.PollutedMire.class)); - cards.add(new SetCardInfo("Pouncing Jaguar", 269, Rarity.COMMON, mage.cards.p.PouncingJaguar.class)); - cards.add(new SetCardInfo("Power Sink", 89, Rarity.COMMON, mage.cards.p.PowerSink.class)); - cards.add(new SetCardInfo("Presence of the Master", 32, Rarity.UNCOMMON, mage.cards.p.PresenceOfTheMaster.class)); - cards.add(new SetCardInfo("Priest of Gix", 150, Rarity.UNCOMMON, mage.cards.p.PriestOfGix.class)); - cards.add(new SetCardInfo("Priest of Titania", 270, Rarity.COMMON, mage.cards.p.PriestOfTitania.class)); - cards.add(new SetCardInfo("Purging Scythe", 308, Rarity.RARE, mage.cards.p.PurgingScythe.class)); - cards.add(new SetCardInfo("Rain of Filth", 151, Rarity.UNCOMMON, mage.cards.r.RainOfFilth.class)); - cards.add(new SetCardInfo("Rain of Salt", 206, Rarity.UNCOMMON, mage.cards.r.RainOfSalt.class)); - cards.add(new SetCardInfo("Ravenous Skirge", 152, Rarity.COMMON, mage.cards.r.RavenousSkirge.class)); - cards.add(new SetCardInfo("Raze", 207, Rarity.COMMON, mage.cards.r.Raze.class)); - cards.add(new SetCardInfo("Recantation", 91, Rarity.RARE, mage.cards.r.Recantation.class)); - cards.add(new SetCardInfo("Reclusive Wight", 153, Rarity.UNCOMMON, mage.cards.r.ReclusiveWight.class)); - cards.add(new SetCardInfo("Redeem", 33, Rarity.UNCOMMON, mage.cards.r.Redeem.class)); - cards.add(new SetCardInfo("Reflexes", 208, Rarity.COMMON, mage.cards.r.Reflexes.class)); - cards.add(new SetCardInfo("Rejuvenate", 271, Rarity.COMMON, mage.cards.r.Rejuvenate.class)); - cards.add(new SetCardInfo("Remembrance", 34, Rarity.RARE, mage.cards.r.Remembrance.class)); - cards.add(new SetCardInfo("Remote Isle", 324, Rarity.COMMON, mage.cards.r.RemoteIsle.class)); - cards.add(new SetCardInfo("Reprocess", 154, Rarity.RARE, mage.cards.r.Reprocess.class)); - cards.add(new SetCardInfo("Rescind", 92, Rarity.COMMON, mage.cards.r.Rescind.class)); - cards.add(new SetCardInfo("Retaliation", 272, Rarity.UNCOMMON, mage.cards.r.Retaliation.class)); - cards.add(new SetCardInfo("Retromancer", 209, Rarity.COMMON, mage.cards.r.Retromancer.class)); - cards.add(new SetCardInfo("Rewind", 93, Rarity.COMMON, mage.cards.r.Rewind.class)); - cards.add(new SetCardInfo("Rumbling Crescendo", 210, Rarity.RARE, mage.cards.r.RumblingCrescendo.class)); - cards.add(new SetCardInfo("Rune of Protection: Artifacts", 35, Rarity.UNCOMMON, mage.cards.r.RuneOfProtectionArtifacts.class)); - cards.add(new SetCardInfo("Rune of Protection: Black", 36, Rarity.COMMON, mage.cards.r.RuneOfProtectionBlack.class)); - cards.add(new SetCardInfo("Rune of Protection: Blue", 37, Rarity.COMMON, mage.cards.r.RuneOfProtectionBlue.class)); - cards.add(new SetCardInfo("Rune of Protection: Green", 38, Rarity.COMMON, mage.cards.r.RuneOfProtectionGreen.class)); - cards.add(new SetCardInfo("Rune of Protection: Lands", 39, Rarity.RARE, mage.cards.r.RuneOfProtectionLands.class)); - cards.add(new SetCardInfo("Rune of Protection: Red", 40, Rarity.COMMON, mage.cards.r.RuneOfProtectionRed.class)); - cards.add(new SetCardInfo("Rune of Protection: White", 41, Rarity.COMMON, mage.cards.r.RuneOfProtectionWhite.class)); - cards.add(new SetCardInfo("Sanctum Custodian", 42, Rarity.COMMON, mage.cards.s.SanctumCustodian.class)); - cards.add(new SetCardInfo("Sanctum Guardian", 43, Rarity.UNCOMMON, mage.cards.s.SanctumGuardian.class)); - cards.add(new SetCardInfo("Sandbar Merfolk", 94, Rarity.COMMON, mage.cards.s.SandbarMerfolk.class)); - cards.add(new SetCardInfo("Sandbar Serpent", 95, Rarity.UNCOMMON, mage.cards.s.SandbarSerpent.class)); - cards.add(new SetCardInfo("Sanguine Guard", 155, Rarity.UNCOMMON, mage.cards.s.SanguineGuard.class)); - cards.add(new SetCardInfo("Scald", 211, Rarity.UNCOMMON, mage.cards.s.Scald.class)); - cards.add(new SetCardInfo("Scoria Wurm", 212, Rarity.RARE, mage.cards.s.ScoriaWurm.class)); - cards.add(new SetCardInfo("Scrap", 213, Rarity.COMMON, mage.cards.s.Scrap.class)); - cards.add(new SetCardInfo("Seasoned Marshal", 44, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); - cards.add(new SetCardInfo("Serra Avatar", 45, Rarity.RARE, mage.cards.s.SerraAvatar.class)); - cards.add(new SetCardInfo("Serra's Embrace", 47, Rarity.UNCOMMON, mage.cards.s.SerrasEmbrace.class)); - cards.add(new SetCardInfo("Serra's Liturgy", 49, Rarity.RARE, mage.cards.s.SerrasLiturgy.class)); - cards.add(new SetCardInfo("Serra's Sanctum", 325, Rarity.RARE, mage.cards.s.SerrasSanctum.class)); - cards.add(new SetCardInfo("Serra Zealot", 46, Rarity.COMMON, mage.cards.s.SerraZealot.class)); - cards.add(new SetCardInfo("Shimmering Barrier", 50, Rarity.UNCOMMON, mage.cards.s.ShimmeringBarrier.class)); - cards.add(new SetCardInfo("Shivan Gorge", 326, Rarity.RARE, mage.cards.s.ShivanGorge.class)); - cards.add(new SetCardInfo("Shivan Hellkite", 214, Rarity.RARE, mage.cards.s.ShivanHellkite.class)); - cards.add(new SetCardInfo("Shivan Raptor", 215, Rarity.UNCOMMON, mage.cards.s.ShivanRaptor.class)); - cards.add(new SetCardInfo("Shiv's Embrace", 216, Rarity.UNCOMMON, mage.cards.s.ShivsEmbrace.class)); - cards.add(new SetCardInfo("Show and Tell", 96, Rarity.RARE, mage.cards.s.ShowAndTell.class)); - cards.add(new SetCardInfo("Shower of Sparks", 217, Rarity.COMMON, mage.cards.s.ShowerOfSparks.class)); - cards.add(new SetCardInfo("Sicken", 156, Rarity.COMMON, mage.cards.s.Sicken.class)); - cards.add(new SetCardInfo("Silent Attendant", 51, Rarity.COMMON, mage.cards.s.SilentAttendant.class)); - cards.add(new SetCardInfo("Skirge Familiar", 157, Rarity.UNCOMMON, mage.cards.s.SkirgeFamiliar.class)); - cards.add(new SetCardInfo("Skittering Skirge", 158, Rarity.COMMON, mage.cards.s.SkitteringSkirge.class)); - cards.add(new SetCardInfo("Sleeper Agent", 159, Rarity.RARE, mage.cards.s.SleeperAgent.class)); - cards.add(new SetCardInfo("Slippery Karst", 327, Rarity.COMMON, mage.cards.s.SlipperyKarst.class)); - cards.add(new SetCardInfo("Smokestack", 309, Rarity.RARE, mage.cards.s.Smokestack.class)); - cards.add(new SetCardInfo("Smoldering Crater", 328, Rarity.COMMON, mage.cards.s.SmolderingCrater.class)); - cards.add(new SetCardInfo("Sneak Attack", 218, Rarity.RARE, mage.cards.s.SneakAttack.class)); - cards.add(new SetCardInfo("Somnophore", 97, Rarity.RARE, mage.cards.s.Somnophore.class)); - cards.add(new SetCardInfo("Songstitcher", 52, Rarity.UNCOMMON, mage.cards.s.Songstitcher.class)); - cards.add(new SetCardInfo("Spined Fluke", 160, Rarity.UNCOMMON, mage.cards.s.SpinedFluke.class)); - cards.add(new SetCardInfo("Spire Owl", 98, Rarity.COMMON, mage.cards.s.SpireOwl.class)); - cards.add(new SetCardInfo("Sporogenesis", 273, Rarity.RARE, mage.cards.s.Sporogenesis.class)); - cards.add(new SetCardInfo("Spreading Algae", 274, Rarity.UNCOMMON, mage.cards.s.SpreadingAlgae.class)); - cards.add(new SetCardInfo("Steam Blast", 219, Rarity.UNCOMMON, mage.cards.s.SteamBlast.class)); - cards.add(new SetCardInfo("Stern Proctor", 99, Rarity.UNCOMMON, mage.cards.s.SternProctor.class)); - cards.add(new SetCardInfo("Stroke of Genius", 100, Rarity.RARE, mage.cards.s.StrokeOfGenius.class)); - cards.add(new SetCardInfo("Sulfuric Vapors", 220, Rarity.RARE, mage.cards.s.SulfuricVapors.class)); - cards.add(new SetCardInfo("Sunder", 101, Rarity.RARE, mage.cards.s.Sunder.class)); - cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); - cards.add(new SetCardInfo("Symbiosis", 275, Rarity.COMMON, mage.cards.s.Symbiosis.class)); - cards.add(new SetCardInfo("Tainted Aether", 161, Rarity.RARE, mage.cards.t.TaintedAether.class)); - cards.add(new SetCardInfo("Telepathy", 102, Rarity.UNCOMMON, mage.cards.t.Telepathy.class)); - cards.add(new SetCardInfo("Temporal Aperture", 310, Rarity.RARE, mage.cards.t.TemporalAperture.class)); - cards.add(new SetCardInfo("Thran Quarry", 329, Rarity.RARE, mage.cards.t.ThranQuarry.class)); - cards.add(new SetCardInfo("Thran Turbine", 311, Rarity.UNCOMMON, mage.cards.t.ThranTurbine.class)); - cards.add(new SetCardInfo("Thundering Giant", 221, Rarity.UNCOMMON, mage.cards.t.ThunderingGiant.class)); - cards.add(new SetCardInfo("Time Spiral", 103, Rarity.RARE, mage.cards.t.TimeSpiral.class)); - cards.add(new SetCardInfo("Titania's Boon", 276, Rarity.UNCOMMON, mage.cards.t.TitaniasBoon.class)); - cards.add(new SetCardInfo("Titania's Chosen", 277, Rarity.UNCOMMON, mage.cards.t.TitaniasChosen.class)); - cards.add(new SetCardInfo("Tolarian Academy", 330, Rarity.RARE, mage.cards.t.TolarianAcademy.class)); - cards.add(new SetCardInfo("Tolarian Winds", 104, Rarity.COMMON, mage.cards.t.TolarianWinds.class)); - cards.add(new SetCardInfo("Torch Song", 222, Rarity.UNCOMMON, mage.cards.t.TorchSong.class)); - cards.add(new SetCardInfo("Treefolk Seedlings", 278, Rarity.UNCOMMON, mage.cards.t.TreefolkSeedlings.class)); - cards.add(new SetCardInfo("Treetop Rangers", 279, Rarity.COMMON, mage.cards.t.TreetopRangers.class)); - cards.add(new SetCardInfo("Turnabout", 105, Rarity.UNCOMMON, mage.cards.t.Turnabout.class)); - cards.add(new SetCardInfo("Umbilicus", 312, Rarity.RARE, mage.cards.u.Umbilicus.class)); - cards.add(new SetCardInfo("Unnerve", 162, Rarity.COMMON, mage.cards.u.Unnerve.class)); - cards.add(new SetCardInfo("Unworthy Dead", 163, Rarity.COMMON, mage.cards.u.UnworthyDead.class)); - cards.add(new SetCardInfo("Urza's Armor", 313, Rarity.UNCOMMON, mage.cards.u.UrzasArmor.class)); - cards.add(new SetCardInfo("Vampiric Embrace", 164, Rarity.UNCOMMON, mage.cards.v.VampiricEmbrace.class)); - cards.add(new SetCardInfo("Vebulid", 165, Rarity.RARE, mage.cards.v.Vebulid.class)); - cards.add(new SetCardInfo("Vernal Bloom", 281, Rarity.RARE, mage.cards.v.VernalBloom.class)); - cards.add(new SetCardInfo("Viashino Outrider", 223, Rarity.COMMON, mage.cards.v.ViashinoOutrider.class)); - cards.add(new SetCardInfo("Viashino Runner", 224, Rarity.COMMON, mage.cards.v.ViashinoRunner.class)); - cards.add(new SetCardInfo("Viashino Sandswimmer", 225, Rarity.RARE, mage.cards.v.ViashinoSandswimmer.class)); - cards.add(new SetCardInfo("Viashino Weaponsmith", 226, Rarity.COMMON, mage.cards.v.ViashinoWeaponsmith.class)); - cards.add(new SetCardInfo("Victimize", 166, Rarity.UNCOMMON, mage.cards.v.Victimize.class)); - cards.add(new SetCardInfo("Vile Requiem", 167, Rarity.UNCOMMON, mage.cards.v.VileRequiem.class)); - cards.add(new SetCardInfo("Voice of Grace", 54, Rarity.UNCOMMON, mage.cards.v.VoiceOfGrace.class)); - cards.add(new SetCardInfo("Voice of Law", 55, Rarity.UNCOMMON, mage.cards.v.VoiceOfLaw.class)); - cards.add(new SetCardInfo("Voltaic Key", 314, Rarity.UNCOMMON, mage.cards.v.VoltaicKey.class)); - cards.add(new SetCardInfo("Vug Lizard", 227, Rarity.UNCOMMON, mage.cards.v.VugLizard.class)); - cards.add(new SetCardInfo("War Dance", 282, Rarity.UNCOMMON, mage.cards.w.WarDance.class)); - cards.add(new SetCardInfo("Wall of Junk", 315, Rarity.UNCOMMON, mage.cards.w.WallOfJunk.class)); - cards.add(new SetCardInfo("Waylay", 56, Rarity.UNCOMMON, mage.cards.w.Waylay.class)); - cards.add(new SetCardInfo("Western Paladin", 168, Rarity.RARE, mage.cards.w.WesternPaladin.class)); - cards.add(new SetCardInfo("Whetstone", 316, Rarity.RARE, mage.cards.w.Whetstone.class)); - cards.add(new SetCardInfo("Whirlwind", 283, Rarity.RARE, mage.cards.w.Whirlwind.class)); - cards.add(new SetCardInfo("Wild Dogs", 284, Rarity.COMMON, mage.cards.w.WildDogs.class)); - cards.add(new SetCardInfo("Wildfire", 228, Rarity.RARE, mage.cards.w.Wildfire.class)); - cards.add(new SetCardInfo("Windfall", 111, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); - cards.add(new SetCardInfo("Winding Wurm", 285, Rarity.COMMON, mage.cards.w.WindingWurm.class)); - cards.add(new SetCardInfo("Wirecat", 317, Rarity.UNCOMMON, mage.cards.w.Wirecat.class)); - cards.add(new SetCardInfo("Witch Engine", 169, Rarity.RARE, mage.cards.w.WitchEngine.class)); - cards.add(new SetCardInfo("Wizard Mentor", 112, Rarity.COMMON, mage.cards.w.WizardMentor.class)); - cards.add(new SetCardInfo("Worn Powerstone", 318, Rarity.UNCOMMON, mage.cards.w.WornPowerstone.class)); - cards.add(new SetCardInfo("Worship", 57, Rarity.RARE, mage.cards.w.Worship.class)); - cards.add(new SetCardInfo("Yawgmoth's Edict", 170, Rarity.UNCOMMON, mage.cards.y.YawgmothsEdict.class)); - cards.add(new SetCardInfo("Yawgmoth's Will", 171, Rarity.RARE, mage.cards.y.YawgmothsWill.class)); - cards.add(new SetCardInfo("Zephid", 113, Rarity.RARE, mage.cards.z.Zephid.class)); - cards.add(new SetCardInfo("Zephid's Embrace", 114, Rarity.UNCOMMON, mage.cards.z.ZephidsEmbrace.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author Backfir3 + */ +public final class UrzasSaga extends ExpansionSet { + + private static final UrzasSaga instance = new UrzasSaga(); + + public static UrzasSaga getInstance() { + return instance; + } + + private UrzasSaga() { + super("Urza's Saga", "USG", ExpansionSet.buildDate(1998, 10, 12), SetType.EXPANSION); + this.blockName = "Urza"; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Absolute Grace", 1, Rarity.UNCOMMON, mage.cards.a.AbsoluteGrace.class)); + cards.add(new SetCardInfo("Absolute Law", 2, Rarity.UNCOMMON, mage.cards.a.AbsoluteLaw.class)); + cards.add(new SetCardInfo("Abundance", 229, Rarity.RARE, mage.cards.a.Abundance.class)); + cards.add(new SetCardInfo("Abyssal Horror", 115, Rarity.RARE, mage.cards.a.AbyssalHorror.class)); + cards.add(new SetCardInfo("Academy Researchers", 58, Rarity.UNCOMMON, mage.cards.a.AcademyResearchers.class)); + cards.add(new SetCardInfo("Acidic Soil", 172, Rarity.UNCOMMON, mage.cards.a.AcidicSoil.class)); + cards.add(new SetCardInfo("Acridian", 230, Rarity.COMMON, mage.cards.a.Acridian.class)); + cards.add(new SetCardInfo("Albino Troll", 231, Rarity.UNCOMMON, mage.cards.a.AlbinoTroll.class)); + cards.add(new SetCardInfo("Anaconda", 232, Rarity.UNCOMMON, mage.cards.a.Anaconda.class)); + cards.add(new SetCardInfo("Angelic Chorus", 3, Rarity.RARE, mage.cards.a.AngelicChorus.class)); + cards.add(new SetCardInfo("Angelic Page", 4, Rarity.COMMON, mage.cards.a.AngelicPage.class)); + cards.add(new SetCardInfo("Annul", 59, Rarity.COMMON, mage.cards.a.Annul.class)); + cards.add(new SetCardInfo("Antagonism", 173, Rarity.RARE, mage.cards.a.Antagonism.class)); + cards.add(new SetCardInfo("Arcane Laboratory", 60, Rarity.UNCOMMON, mage.cards.a.ArcaneLaboratory.class)); + cards.add(new SetCardInfo("Arc Lightning", 174, Rarity.COMMON, mage.cards.a.ArcLightning.class)); + cards.add(new SetCardInfo("Argothian Elder", 233, Rarity.UNCOMMON, mage.cards.a.ArgothianElder.class)); + cards.add(new SetCardInfo("Argothian Enchantress", 234, Rarity.RARE, mage.cards.a.ArgothianEnchantress.class)); + cards.add(new SetCardInfo("Argothian Swine", 235, Rarity.COMMON, mage.cards.a.ArgothianSwine.class)); + cards.add(new SetCardInfo("Argothian Wurm", 236, Rarity.RARE, mage.cards.a.ArgothianWurm.class)); + cards.add(new SetCardInfo("Attunement", 61, Rarity.RARE, mage.cards.a.Attunement.class)); + cards.add(new SetCardInfo("Back to Basics", 62, Rarity.RARE, mage.cards.b.BackToBasics.class)); + cards.add(new SetCardInfo("Barrin, Master Wizard", 63, Rarity.RARE, mage.cards.b.BarrinMasterWizard.class)); + cards.add(new SetCardInfo("Barrin's Codex", 286, Rarity.RARE, mage.cards.b.BarrinsCodex.class)); + cards.add(new SetCardInfo("Bedlam", 175, Rarity.RARE, mage.cards.b.Bedlam.class)); + cards.add(new SetCardInfo("Befoul", 116, Rarity.COMMON, mage.cards.b.Befoul.class)); + cards.add(new SetCardInfo("Bereavement", 117, Rarity.UNCOMMON, mage.cards.b.Bereavement.class)); + cards.add(new SetCardInfo("Blanchwood Armor", 237, Rarity.UNCOMMON, mage.cards.b.BlanchwoodArmor.class)); + cards.add(new SetCardInfo("Blanchwood Treefolk", 238, Rarity.COMMON, mage.cards.b.BlanchwoodTreefolk.class)); + cards.add(new SetCardInfo("Blasted Landscape", 319, Rarity.UNCOMMON, mage.cards.b.BlastedLandscape.class)); + cards.add(new SetCardInfo("Blood Vassal", 118, Rarity.COMMON, mage.cards.b.BloodVassal.class)); + cards.add(new SetCardInfo("Bog Raiders", 119, Rarity.COMMON, mage.cards.b.BogRaiders.class)); + cards.add(new SetCardInfo("Brand", 176, Rarity.RARE, mage.cards.b.Brand.class)); + cards.add(new SetCardInfo("Bravado", 177, Rarity.COMMON, mage.cards.b.Bravado.class)); + cards.add(new SetCardInfo("Breach", 120, Rarity.COMMON, mage.cards.b.Breach.class)); + cards.add(new SetCardInfo("Brilliant Halo", 5, Rarity.COMMON, mage.cards.b.BrilliantHalo.class)); + cards.add(new SetCardInfo("Bull Hippo", 239, Rarity.UNCOMMON, mage.cards.b.BullHippo.class)); + cards.add(new SetCardInfo("Bulwark", 178, Rarity.RARE, mage.cards.b.Bulwark.class)); + cards.add(new SetCardInfo("Cackling Fiend", 121, Rarity.COMMON, mage.cards.c.CacklingFiend.class)); + cards.add(new SetCardInfo("Carpet of Flowers", 240, Rarity.UNCOMMON, mage.cards.c.CarpetOfFlowers.class)); + cards.add(new SetCardInfo("Carrion Beetles", 122, Rarity.COMMON, mage.cards.c.CarrionBeetles.class)); + cards.add(new SetCardInfo("Catalog", 64, Rarity.COMMON, mage.cards.c.Catalog.class)); + cards.add(new SetCardInfo("Catastrophe", 6, Rarity.RARE, mage.cards.c.Catastrophe.class)); + cards.add(new SetCardInfo("Cathodion", 287, Rarity.UNCOMMON, mage.cards.c.Cathodion.class)); + cards.add(new SetCardInfo("Cave Tiger", 241, Rarity.COMMON, mage.cards.c.CaveTiger.class)); + cards.add(new SetCardInfo("Child of Gaea", 242, Rarity.RARE, mage.cards.c.ChildOfGaea.class)); + cards.add(new SetCardInfo("Chimeric Staff", 288, Rarity.RARE, mage.cards.c.ChimericStaff.class)); + cards.add(new SetCardInfo("Citanul Centaurs", 243, Rarity.RARE, mage.cards.c.CitanulCentaurs.class)); + cards.add(new SetCardInfo("Citanul Flute", 289, Rarity.RARE, mage.cards.c.CitanulFlute.class)); + cards.add(new SetCardInfo("Citanul Hierophants", 244, Rarity.RARE, mage.cards.c.CitanulHierophants.class)); + cards.add(new SetCardInfo("Claws of Gix", 290, Rarity.UNCOMMON, mage.cards.c.ClawsOfGix.class)); + cards.add(new SetCardInfo("Clear", 7, Rarity.UNCOMMON, mage.cards.c.Clear.class)); + cards.add(new SetCardInfo("Cloak of Mists", 65, Rarity.COMMON, mage.cards.c.CloakOfMists.class)); + cards.add(new SetCardInfo("Confiscate", 66, Rarity.UNCOMMON, mage.cards.c.Confiscate.class)); + cards.add(new SetCardInfo("Congregate", 8, Rarity.COMMON, mage.cards.c.Congregate.class)); + cards.add(new SetCardInfo("Contamination", 123, Rarity.RARE, mage.cards.c.Contamination.class)); + cards.add(new SetCardInfo("Copper Gnomes", 291, Rarity.RARE, mage.cards.c.CopperGnomes.class)); + cards.add(new SetCardInfo("Coral Merfolk", 67, Rarity.COMMON, mage.cards.c.CoralMerfolk.class)); + cards.add(new SetCardInfo("Corrupt", 124, Rarity.COMMON, mage.cards.c.Corrupt.class)); + cards.add(new SetCardInfo("Cradle Guard", 245, Rarity.UNCOMMON, mage.cards.c.CradleGuard.class)); + cards.add(new SetCardInfo("Crater Hellion", 179, Rarity.RARE, mage.cards.c.CraterHellion.class)); + cards.add(new SetCardInfo("Crazed Skirge", 125, Rarity.UNCOMMON, mage.cards.c.CrazedSkirge.class)); + cards.add(new SetCardInfo("Crosswinds", 246, Rarity.UNCOMMON, mage.cards.c.Crosswinds.class)); + cards.add(new SetCardInfo("Crystal Chimes", 292, Rarity.UNCOMMON, mage.cards.c.CrystalChimes.class)); + cards.add(new SetCardInfo("Curfew", 68, Rarity.COMMON, mage.cards.c.Curfew.class)); + cards.add(new SetCardInfo("Darkest Hour", 128, Rarity.RARE, mage.cards.d.DarkestHour.class)); + cards.add(new SetCardInfo("Dark Hatchling", 126, Rarity.RARE, mage.cards.d.DarkHatchling.class)); + cards.add(new SetCardInfo("Dark Ritual", 127, Rarity.COMMON, mage.cards.d.DarkRitual.class)); + cards.add(new SetCardInfo("Defensive Formation", 9, Rarity.UNCOMMON, mage.cards.d.DefensiveFormation.class)); + cards.add(new SetCardInfo("Despondency", 129, Rarity.COMMON, mage.cards.d.Despondency.class)); + cards.add(new SetCardInfo("Destructive Urge", 180, Rarity.UNCOMMON, mage.cards.d.DestructiveUrge.class)); + cards.add(new SetCardInfo("Diabolic Servitude", 130, Rarity.UNCOMMON, mage.cards.d.DiabolicServitude.class)); + cards.add(new SetCardInfo("Disciple of Grace", 10, Rarity.COMMON, mage.cards.d.DiscipleOfGrace.class)); + cards.add(new SetCardInfo("Disciple of Law", 11, Rarity.COMMON, mage.cards.d.DiscipleOfLaw.class)); + cards.add(new SetCardInfo("Discordant Dirge", 131, Rarity.RARE, mage.cards.d.DiscordantDirge.class)); + cards.add(new SetCardInfo("Disenchant", 12, Rarity.COMMON, mage.cards.d.Disenchant.class)); + cards.add(new SetCardInfo("Disorder", 181, Rarity.UNCOMMON, mage.cards.d.Disorder.class)); + cards.add(new SetCardInfo("Disruptive Student", 69, Rarity.COMMON, mage.cards.d.DisruptiveStudent.class)); + cards.add(new SetCardInfo("Douse", 70, Rarity.UNCOMMON, mage.cards.d.Douse.class)); + cards.add(new SetCardInfo("Dragon Blood", 293, Rarity.UNCOMMON, mage.cards.d.DragonBlood.class)); + cards.add(new SetCardInfo("Drifting Djinn", 71, Rarity.RARE, mage.cards.d.DriftingDjinn.class)); + cards.add(new SetCardInfo("Drifting Meadow", 320, Rarity.COMMON, mage.cards.d.DriftingMeadow.class)); + cards.add(new SetCardInfo("Dromosaur", 182, Rarity.COMMON, mage.cards.d.Dromosaur.class)); + cards.add(new SetCardInfo("Duress", 132, Rarity.COMMON, mage.cards.d.Duress.class)); + cards.add(new SetCardInfo("Eastern Paladin", 133, Rarity.RARE, mage.cards.e.EasternPaladin.class)); + cards.add(new SetCardInfo("Electryte", 183, Rarity.RARE, mage.cards.e.Electryte.class)); + cards.add(new SetCardInfo("Elite Archers", 13, Rarity.RARE, mage.cards.e.EliteArchers.class)); + cards.add(new SetCardInfo("Elvish Herder", 247, Rarity.COMMON, mage.cards.e.ElvishHerder.class)); + cards.add(new SetCardInfo("Elvish Lyrist", 248, Rarity.COMMON, mage.cards.e.ElvishLyrist.class)); + cards.add(new SetCardInfo("Enchantment Alteration", 72, Rarity.UNCOMMON, mage.cards.e.EnchantmentAlteration.class)); + cards.add(new SetCardInfo("Endless Wurm", 249, Rarity.RARE, mage.cards.e.EndlessWurm.class)); + cards.add(new SetCardInfo("Endoskeleton", 294, Rarity.UNCOMMON, mage.cards.e.Endoskeleton.class)); + cards.add(new SetCardInfo("Energy Field", 73, Rarity.RARE, mage.cards.e.EnergyField.class)); + cards.add(new SetCardInfo("Exhaustion", 74, Rarity.UNCOMMON, mage.cards.e.Exhaustion.class)); + cards.add(new SetCardInfo("Exhume", 134, Rarity.COMMON, mage.cards.e.Exhume.class)); + cards.add(new SetCardInfo("Exploration", 250, Rarity.RARE, mage.cards.e.Exploration.class)); + cards.add(new SetCardInfo("Expunge", 135, Rarity.COMMON, mage.cards.e.Expunge.class)); + cards.add(new SetCardInfo("Faith Healer", 14, Rarity.RARE, mage.cards.f.FaithHealer.class)); + cards.add(new SetCardInfo("Falter", 184, Rarity.COMMON, mage.cards.f.Falter.class)); + cards.add(new SetCardInfo("Fault Line", 185, Rarity.RARE, mage.cards.f.FaultLine.class)); + cards.add(new SetCardInfo("Fecundity", 251, Rarity.UNCOMMON, mage.cards.f.Fecundity.class)); + cards.add(new SetCardInfo("Fertile Ground", 252, Rarity.COMMON, mage.cards.f.FertileGround.class)); + cards.add(new SetCardInfo("Fiery Mantle", 186, Rarity.COMMON, mage.cards.f.FieryMantle.class)); + cards.add(new SetCardInfo("Fire Ants", 187, Rarity.UNCOMMON, mage.cards.f.FireAnts.class)); + cards.add(new SetCardInfo("Flesh Reaver", 136, Rarity.UNCOMMON, mage.cards.f.FleshReaver.class)); + cards.add(new SetCardInfo("Fluctuator", 295, Rarity.RARE, mage.cards.f.Fluctuator.class)); + cards.add(new SetCardInfo("Fog Bank", 75, Rarity.UNCOMMON, mage.cards.f.FogBank.class)); + cards.add(new SetCardInfo("Forest", 347, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 348, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 349, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 350, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Fortitude", 253, Rarity.COMMON, mage.cards.f.Fortitude.class)); + cards.add(new SetCardInfo("Gaea's Bounty", 254, Rarity.COMMON, mage.cards.g.GaeasBounty.class)); + cards.add(new SetCardInfo("Gaea's Cradle", 321, Rarity.RARE, mage.cards.g.GaeasCradle.class)); + cards.add(new SetCardInfo("Gaea's Embrace", 255, Rarity.UNCOMMON, mage.cards.g.GaeasEmbrace.class)); + cards.add(new SetCardInfo("Gamble", 188, Rarity.RARE, mage.cards.g.Gamble.class)); + cards.add(new SetCardInfo("Gilded Drake", 76, Rarity.RARE, mage.cards.g.GildedDrake.class)); + cards.add(new SetCardInfo("Glorious Anthem", 15, Rarity.RARE, mage.cards.g.GloriousAnthem.class)); + cards.add(new SetCardInfo("Goblin Cadets", 189, Rarity.UNCOMMON, mage.cards.g.GoblinCadets.class)); + cards.add(new SetCardInfo("Goblin Lackey", 190, Rarity.UNCOMMON, mage.cards.g.GoblinLackey.class)); + cards.add(new SetCardInfo("Goblin Matron", 191, Rarity.COMMON, mage.cards.g.GoblinMatron.class)); + cards.add(new SetCardInfo("Goblin Offensive", 192, Rarity.UNCOMMON, mage.cards.g.GoblinOffensive.class)); + cards.add(new SetCardInfo("Goblin Patrol", 193, Rarity.COMMON, mage.cards.g.GoblinPatrol.class)); + cards.add(new SetCardInfo("Goblin Raider", 194, Rarity.COMMON, mage.cards.g.GoblinRaider.class)); + cards.add(new SetCardInfo("Goblin Spelunkers", 195, Rarity.COMMON, mage.cards.g.GoblinSpelunkers.class)); + cards.add(new SetCardInfo("Goblin War Buggy", 196, Rarity.COMMON, mage.cards.g.GoblinWarBuggy.class)); + cards.add(new SetCardInfo("Gorilla Warrior", 256, Rarity.COMMON, mage.cards.g.GorillaWarrior.class)); + cards.add(new SetCardInfo("Grafted Skullcap", 296, Rarity.RARE, mage.cards.g.GraftedSkullcap.class)); + cards.add(new SetCardInfo("Greater Good", 257, Rarity.RARE, mage.cards.g.GreaterGood.class)); + cards.add(new SetCardInfo("Great Whale", 77, Rarity.RARE, mage.cards.g.GreatWhale.class)); + cards.add(new SetCardInfo("Greener Pastures", 258, Rarity.RARE, mage.cards.g.GreenerPastures.class)); + cards.add(new SetCardInfo("Guma", 197, Rarity.UNCOMMON, mage.cards.g.Guma.class)); + cards.add(new SetCardInfo("Hawkeater Moth", 259, Rarity.UNCOMMON, mage.cards.h.HawkeaterMoth.class)); + cards.add(new SetCardInfo("Headlong Rush", 198, Rarity.COMMON, mage.cards.h.HeadlongRush.class)); + cards.add(new SetCardInfo("Healing Salve", 16, Rarity.COMMON, mage.cards.h.HealingSalve.class)); + cards.add(new SetCardInfo("Heat Ray", 199, Rarity.COMMON, mage.cards.h.HeatRay.class)); + cards.add(new SetCardInfo("Herald of Serra", 17, Rarity.RARE, mage.cards.h.HeraldOfSerra.class)); + cards.add(new SetCardInfo("Hermetic Study", 78, Rarity.COMMON, mage.cards.h.HermeticStudy.class)); + cards.add(new SetCardInfo("Hibernation", 79, Rarity.UNCOMMON, mage.cards.h.Hibernation.class)); + cards.add(new SetCardInfo("Hidden Ancients", 260, Rarity.UNCOMMON, mage.cards.h.HiddenAncients.class)); + cards.add(new SetCardInfo("Hidden Guerrillas", 261, Rarity.UNCOMMON, mage.cards.h.HiddenGuerrillas.class)); + cards.add(new SetCardInfo("Hidden Herd", 262, Rarity.RARE, mage.cards.h.HiddenHerd.class)); + cards.add(new SetCardInfo("Hidden Predators", 263, Rarity.RARE, mage.cards.h.HiddenPredators.class)); + cards.add(new SetCardInfo("Hidden Spider", 264, Rarity.COMMON, mage.cards.h.HiddenSpider.class)); + cards.add(new SetCardInfo("Hidden Stag", 265, Rarity.RARE, mage.cards.h.HiddenStag.class)); + cards.add(new SetCardInfo("Hollow Dogs", 137, Rarity.COMMON, mage.cards.h.HollowDogs.class)); + cards.add(new SetCardInfo("Hopping Automaton", 297, Rarity.UNCOMMON, mage.cards.h.HoppingAutomaton.class)); + cards.add(new SetCardInfo("Horseshoe Crab", 80, Rarity.COMMON, mage.cards.h.HorseshoeCrab.class)); + cards.add(new SetCardInfo("Humble", 18, Rarity.UNCOMMON, mage.cards.h.Humble.class)); + cards.add(new SetCardInfo("Hush", 266, Rarity.COMMON, mage.cards.h.Hush.class)); + cards.add(new SetCardInfo("Ill-Gotten Gains", 138, Rarity.RARE, mage.cards.i.IllGottenGains.class)); + cards.add(new SetCardInfo("Imaginary Pet", 81, Rarity.RARE, mage.cards.i.ImaginaryPet.class)); + cards.add(new SetCardInfo("Intrepid Hero", 19, Rarity.RARE, mage.cards.i.IntrepidHero.class)); + cards.add(new SetCardInfo("Island", 335, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 336, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 337, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 338, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jagged Lightning", 200, Rarity.UNCOMMON, mage.cards.j.JaggedLightning.class)); + cards.add(new SetCardInfo("Karn, Silver Golem", 298, Rarity.RARE, mage.cards.k.KarnSilverGolem.class)); + cards.add(new SetCardInfo("Launch", 82, Rarity.COMMON, mage.cards.l.Launch.class)); + cards.add(new SetCardInfo("Lay Waste", 201, Rarity.COMMON, mage.cards.l.LayWaste.class)); + cards.add(new SetCardInfo("Lifeline", 299, Rarity.RARE, mage.cards.l.Lifeline.class)); + cards.add(new SetCardInfo("Lightning Dragon", 202, Rarity.RARE, mage.cards.l.LightningDragon.class)); + cards.add(new SetCardInfo("Lilting Refrain", 83, Rarity.UNCOMMON, mage.cards.l.LiltingRefrain.class)); + cards.add(new SetCardInfo("Lingering Mirage", 84, Rarity.UNCOMMON, mage.cards.l.LingeringMirage.class)); + cards.add(new SetCardInfo("Looming Shade", 139, Rarity.COMMON, mage.cards.l.LoomingShade.class)); + cards.add(new SetCardInfo("Lotus Blossom", 300, Rarity.RARE, mage.cards.l.LotusBlossom.class)); + cards.add(new SetCardInfo("Lull", 267, Rarity.COMMON, mage.cards.l.Lull.class)); + cards.add(new SetCardInfo("Lurking Evil", 140, Rarity.RARE, mage.cards.l.LurkingEvil.class)); + cards.add(new SetCardInfo("Mana Leech", 141, Rarity.UNCOMMON, mage.cards.m.ManaLeech.class)); + cards.add(new SetCardInfo("Meltdown", 203, Rarity.UNCOMMON, mage.cards.m.Meltdown.class)); + cards.add(new SetCardInfo("Metrognome", 301, Rarity.RARE, mage.cards.m.Metrognome.class)); + cards.add(new SetCardInfo("Midsummer Revel", 268, Rarity.RARE, mage.cards.m.MidsummerRevel.class)); + cards.add(new SetCardInfo("Mishra's Helix", 302, Rarity.RARE, mage.cards.m.MishrasHelix.class)); + cards.add(new SetCardInfo("Mobile Fort", 303, Rarity.UNCOMMON, mage.cards.m.MobileFort.class)); + cards.add(new SetCardInfo("Monk Idealist", 20, Rarity.UNCOMMON, mage.cards.m.MonkIdealist.class)); + cards.add(new SetCardInfo("Monk Realist", 21, Rarity.COMMON, mage.cards.m.MonkRealist.class)); + cards.add(new SetCardInfo("Morphling", 85, Rarity.RARE, mage.cards.m.Morphling.class)); + cards.add(new SetCardInfo("Mountain", 343, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 344, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 345, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 346, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("No Rest for the Wicked", 142, Rarity.UNCOMMON, mage.cards.n.NoRestForTheWicked.class)); + cards.add(new SetCardInfo("Noetic Scales", 304, Rarity.RARE, mage.cards.n.NoeticScales.class)); + cards.add(new SetCardInfo("Okk", 204, Rarity.RARE, mage.cards.o.Okk.class)); + cards.add(new SetCardInfo("Opal Acrolith", 22, Rarity.UNCOMMON, mage.cards.o.OpalAcrolith.class)); + cards.add(new SetCardInfo("Opal Archangel", 23, Rarity.RARE, mage.cards.o.OpalArchangel.class)); + cards.add(new SetCardInfo("Opal Caryatid", 24, Rarity.COMMON, mage.cards.o.OpalCaryatid.class)); + cards.add(new SetCardInfo("Opal Gargoyle", 25, Rarity.COMMON, mage.cards.o.OpalGargoyle.class)); + cards.add(new SetCardInfo("Opal Titan", 26, Rarity.RARE, mage.cards.o.OpalTitan.class)); + cards.add(new SetCardInfo("Oppression", 143, Rarity.RARE, mage.cards.o.Oppression.class)); + cards.add(new SetCardInfo("Order of Yawgmoth", 144, Rarity.UNCOMMON, mage.cards.o.OrderOfYawgmoth.class)); + cards.add(new SetCardInfo("Outmaneuver", 205, Rarity.UNCOMMON, mage.cards.o.Outmaneuver.class)); + cards.add(new SetCardInfo("Pacifism", 27, Rarity.COMMON, mage.cards.p.Pacifism.class)); + cards.add(new SetCardInfo("Parasitic Bond", 145, Rarity.UNCOMMON, mage.cards.p.ParasiticBond.class)); + cards.add(new SetCardInfo("Pariah", 28, Rarity.RARE, mage.cards.p.Pariah.class)); + cards.add(new SetCardInfo("Path of Peace", 29, Rarity.COMMON, mage.cards.p.PathOfPeace.class)); + cards.add(new SetCardInfo("Pegasus Charger", 30, Rarity.COMMON, mage.cards.p.PegasusCharger.class)); + cards.add(new SetCardInfo("Pendrell Drake", 86, Rarity.COMMON, mage.cards.p.PendrellDrake.class)); + cards.add(new SetCardInfo("Pendrell Flux", 87, Rarity.COMMON, mage.cards.p.PendrellFlux.class)); + cards.add(new SetCardInfo("Peregrine Drake", 88, Rarity.UNCOMMON, mage.cards.p.PeregrineDrake.class)); + cards.add(new SetCardInfo("Persecute", 146, Rarity.RARE, mage.cards.p.Persecute.class)); + cards.add(new SetCardInfo("Pestilence", 147, Rarity.COMMON, mage.cards.p.Pestilence.class)); + cards.add(new SetCardInfo("Phyrexian Colossus", 305, Rarity.RARE, mage.cards.p.PhyrexianColossus.class)); + cards.add(new SetCardInfo("Phyrexian Ghoul", 148, Rarity.COMMON, mage.cards.p.PhyrexianGhoul.class)); + cards.add(new SetCardInfo("Phyrexian Processor", 306, Rarity.RARE, mage.cards.p.PhyrexianProcessor.class)); + cards.add(new SetCardInfo("Phyrexian Tower", 322, Rarity.RARE, mage.cards.p.PhyrexianTower.class)); + cards.add(new SetCardInfo("Pit Trap", 307, Rarity.UNCOMMON, mage.cards.p.PitTrap.class)); + cards.add(new SetCardInfo("Plains", 331, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 332, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 333, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 334, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Planar Birth", 31, Rarity.RARE, mage.cards.p.PlanarBirth.class)); + cards.add(new SetCardInfo("Planar Void", 149, Rarity.UNCOMMON, mage.cards.p.PlanarVoid.class)); + cards.add(new SetCardInfo("Polluted Mire", 323, Rarity.COMMON, mage.cards.p.PollutedMire.class)); + cards.add(new SetCardInfo("Pouncing Jaguar", 269, Rarity.COMMON, mage.cards.p.PouncingJaguar.class)); + cards.add(new SetCardInfo("Power Sink", 89, Rarity.COMMON, mage.cards.p.PowerSink.class)); + cards.add(new SetCardInfo("Power Taint", 90, Rarity.COMMON, mage.cards.p.PowerTaint.class)); + cards.add(new SetCardInfo("Presence of the Master", 32, Rarity.UNCOMMON, mage.cards.p.PresenceOfTheMaster.class)); + cards.add(new SetCardInfo("Priest of Gix", 150, Rarity.UNCOMMON, mage.cards.p.PriestOfGix.class)); + cards.add(new SetCardInfo("Priest of Titania", 270, Rarity.COMMON, mage.cards.p.PriestOfTitania.class)); + cards.add(new SetCardInfo("Purging Scythe", 308, Rarity.RARE, mage.cards.p.PurgingScythe.class)); + cards.add(new SetCardInfo("Rain of Filth", 151, Rarity.UNCOMMON, mage.cards.r.RainOfFilth.class)); + cards.add(new SetCardInfo("Rain of Salt", 206, Rarity.UNCOMMON, mage.cards.r.RainOfSalt.class)); + cards.add(new SetCardInfo("Ravenous Skirge", 152, Rarity.COMMON, mage.cards.r.RavenousSkirge.class)); + cards.add(new SetCardInfo("Raze", 207, Rarity.COMMON, mage.cards.r.Raze.class)); + cards.add(new SetCardInfo("Recantation", 91, Rarity.RARE, mage.cards.r.Recantation.class)); + cards.add(new SetCardInfo("Reclusive Wight", 153, Rarity.UNCOMMON, mage.cards.r.ReclusiveWight.class)); + cards.add(new SetCardInfo("Redeem", 33, Rarity.UNCOMMON, mage.cards.r.Redeem.class)); + cards.add(new SetCardInfo("Reflexes", 208, Rarity.COMMON, mage.cards.r.Reflexes.class)); + cards.add(new SetCardInfo("Rejuvenate", 271, Rarity.COMMON, mage.cards.r.Rejuvenate.class)); + cards.add(new SetCardInfo("Remembrance", 34, Rarity.RARE, mage.cards.r.Remembrance.class)); + cards.add(new SetCardInfo("Remote Isle", 324, Rarity.COMMON, mage.cards.r.RemoteIsle.class)); + cards.add(new SetCardInfo("Reprocess", 154, Rarity.RARE, mage.cards.r.Reprocess.class)); + cards.add(new SetCardInfo("Rescind", 92, Rarity.COMMON, mage.cards.r.Rescind.class)); + cards.add(new SetCardInfo("Retaliation", 272, Rarity.UNCOMMON, mage.cards.r.Retaliation.class)); + cards.add(new SetCardInfo("Retromancer", 209, Rarity.COMMON, mage.cards.r.Retromancer.class)); + cards.add(new SetCardInfo("Rewind", 93, Rarity.COMMON, mage.cards.r.Rewind.class)); + cards.add(new SetCardInfo("Rumbling Crescendo", 210, Rarity.RARE, mage.cards.r.RumblingCrescendo.class)); + cards.add(new SetCardInfo("Rune of Protection: Artifacts", 35, Rarity.UNCOMMON, mage.cards.r.RuneOfProtectionArtifacts.class)); + cards.add(new SetCardInfo("Rune of Protection: Black", 36, Rarity.COMMON, mage.cards.r.RuneOfProtectionBlack.class)); + cards.add(new SetCardInfo("Rune of Protection: Blue", 37, Rarity.COMMON, mage.cards.r.RuneOfProtectionBlue.class)); + cards.add(new SetCardInfo("Rune of Protection: Green", 38, Rarity.COMMON, mage.cards.r.RuneOfProtectionGreen.class)); + cards.add(new SetCardInfo("Rune of Protection: Lands", 39, Rarity.RARE, mage.cards.r.RuneOfProtectionLands.class)); + cards.add(new SetCardInfo("Rune of Protection: Red", 40, Rarity.COMMON, mage.cards.r.RuneOfProtectionRed.class)); + cards.add(new SetCardInfo("Rune of Protection: White", 41, Rarity.COMMON, mage.cards.r.RuneOfProtectionWhite.class)); + cards.add(new SetCardInfo("Sanctum Custodian", 42, Rarity.COMMON, mage.cards.s.SanctumCustodian.class)); + cards.add(new SetCardInfo("Sanctum Guardian", 43, Rarity.UNCOMMON, mage.cards.s.SanctumGuardian.class)); + cards.add(new SetCardInfo("Sandbar Merfolk", 94, Rarity.COMMON, mage.cards.s.SandbarMerfolk.class)); + cards.add(new SetCardInfo("Sandbar Serpent", 95, Rarity.UNCOMMON, mage.cards.s.SandbarSerpent.class)); + cards.add(new SetCardInfo("Sanguine Guard", 155, Rarity.UNCOMMON, mage.cards.s.SanguineGuard.class)); + cards.add(new SetCardInfo("Scald", 211, Rarity.UNCOMMON, mage.cards.s.Scald.class)); + cards.add(new SetCardInfo("Scoria Wurm", 212, Rarity.RARE, mage.cards.s.ScoriaWurm.class)); + cards.add(new SetCardInfo("Scrap", 213, Rarity.COMMON, mage.cards.s.Scrap.class)); + cards.add(new SetCardInfo("Seasoned Marshal", 44, Rarity.UNCOMMON, mage.cards.s.SeasonedMarshal.class)); + cards.add(new SetCardInfo("Serra Avatar", 45, Rarity.RARE, mage.cards.s.SerraAvatar.class)); + cards.add(new SetCardInfo("Serra's Embrace", 47, Rarity.UNCOMMON, mage.cards.s.SerrasEmbrace.class)); + cards.add(new SetCardInfo("Serra's Hymn", 48, Rarity.UNCOMMON, mage.cards.s.SerrasHymn.class)); + cards.add(new SetCardInfo("Serra's Liturgy", 49, Rarity.RARE, mage.cards.s.SerrasLiturgy.class)); + cards.add(new SetCardInfo("Serra's Sanctum", 325, Rarity.RARE, mage.cards.s.SerrasSanctum.class)); + cards.add(new SetCardInfo("Serra Zealot", 46, Rarity.COMMON, mage.cards.s.SerraZealot.class)); + cards.add(new SetCardInfo("Shimmering Barrier", 50, Rarity.UNCOMMON, mage.cards.s.ShimmeringBarrier.class)); + cards.add(new SetCardInfo("Shivan Gorge", 326, Rarity.RARE, mage.cards.s.ShivanGorge.class)); + cards.add(new SetCardInfo("Shivan Hellkite", 214, Rarity.RARE, mage.cards.s.ShivanHellkite.class)); + cards.add(new SetCardInfo("Shivan Raptor", 215, Rarity.UNCOMMON, mage.cards.s.ShivanRaptor.class)); + cards.add(new SetCardInfo("Shiv's Embrace", 216, Rarity.UNCOMMON, mage.cards.s.ShivsEmbrace.class)); + cards.add(new SetCardInfo("Show and Tell", 96, Rarity.RARE, mage.cards.s.ShowAndTell.class)); + cards.add(new SetCardInfo("Shower of Sparks", 217, Rarity.COMMON, mage.cards.s.ShowerOfSparks.class)); + cards.add(new SetCardInfo("Sicken", 156, Rarity.COMMON, mage.cards.s.Sicken.class)); + cards.add(new SetCardInfo("Silent Attendant", 51, Rarity.COMMON, mage.cards.s.SilentAttendant.class)); + cards.add(new SetCardInfo("Skirge Familiar", 157, Rarity.UNCOMMON, mage.cards.s.SkirgeFamiliar.class)); + cards.add(new SetCardInfo("Skittering Skirge", 158, Rarity.COMMON, mage.cards.s.SkitteringSkirge.class)); + cards.add(new SetCardInfo("Sleeper Agent", 159, Rarity.RARE, mage.cards.s.SleeperAgent.class)); + cards.add(new SetCardInfo("Slippery Karst", 327, Rarity.COMMON, mage.cards.s.SlipperyKarst.class)); + cards.add(new SetCardInfo("Smokestack", 309, Rarity.RARE, mage.cards.s.Smokestack.class)); + cards.add(new SetCardInfo("Smoldering Crater", 328, Rarity.COMMON, mage.cards.s.SmolderingCrater.class)); + cards.add(new SetCardInfo("Sneak Attack", 218, Rarity.RARE, mage.cards.s.SneakAttack.class)); + cards.add(new SetCardInfo("Somnophore", 97, Rarity.RARE, mage.cards.s.Somnophore.class)); + cards.add(new SetCardInfo("Songstitcher", 52, Rarity.UNCOMMON, mage.cards.s.Songstitcher.class)); + cards.add(new SetCardInfo("Soul Sculptor", 53, Rarity.RARE, mage.cards.s.SoulSculptor.class)); + cards.add(new SetCardInfo("Spined Fluke", 160, Rarity.UNCOMMON, mage.cards.s.SpinedFluke.class)); + cards.add(new SetCardInfo("Spire Owl", 98, Rarity.COMMON, mage.cards.s.SpireOwl.class)); + cards.add(new SetCardInfo("Sporogenesis", 273, Rarity.RARE, mage.cards.s.Sporogenesis.class)); + cards.add(new SetCardInfo("Spreading Algae", 274, Rarity.UNCOMMON, mage.cards.s.SpreadingAlgae.class)); + cards.add(new SetCardInfo("Steam Blast", 219, Rarity.UNCOMMON, mage.cards.s.SteamBlast.class)); + cards.add(new SetCardInfo("Stern Proctor", 99, Rarity.UNCOMMON, mage.cards.s.SternProctor.class)); + cards.add(new SetCardInfo("Stroke of Genius", 100, Rarity.RARE, mage.cards.s.StrokeOfGenius.class)); + cards.add(new SetCardInfo("Sulfuric Vapors", 220, Rarity.RARE, mage.cards.s.SulfuricVapors.class)); + cards.add(new SetCardInfo("Sunder", 101, Rarity.RARE, mage.cards.s.Sunder.class)); + cards.add(new SetCardInfo("Swamp", 339, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 340, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 341, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 342, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Symbiosis", 275, Rarity.COMMON, mage.cards.s.Symbiosis.class)); + cards.add(new SetCardInfo("Tainted Aether", 161, Rarity.RARE, mage.cards.t.TaintedAether.class)); + cards.add(new SetCardInfo("Telepathy", 102, Rarity.UNCOMMON, mage.cards.t.Telepathy.class)); + cards.add(new SetCardInfo("Temporal Aperture", 310, Rarity.RARE, mage.cards.t.TemporalAperture.class)); + cards.add(new SetCardInfo("Thran Quarry", 329, Rarity.RARE, mage.cards.t.ThranQuarry.class)); + cards.add(new SetCardInfo("Thran Turbine", 311, Rarity.UNCOMMON, mage.cards.t.ThranTurbine.class)); + cards.add(new SetCardInfo("Thundering Giant", 221, Rarity.UNCOMMON, mage.cards.t.ThunderingGiant.class)); + cards.add(new SetCardInfo("Time Spiral", 103, Rarity.RARE, mage.cards.t.TimeSpiral.class)); + cards.add(new SetCardInfo("Titania's Boon", 276, Rarity.UNCOMMON, mage.cards.t.TitaniasBoon.class)); + cards.add(new SetCardInfo("Titania's Chosen", 277, Rarity.UNCOMMON, mage.cards.t.TitaniasChosen.class)); + cards.add(new SetCardInfo("Tolarian Academy", 330, Rarity.RARE, mage.cards.t.TolarianAcademy.class)); + cards.add(new SetCardInfo("Tolarian Winds", 104, Rarity.COMMON, mage.cards.t.TolarianWinds.class)); + cards.add(new SetCardInfo("Torch Song", 222, Rarity.UNCOMMON, mage.cards.t.TorchSong.class)); + cards.add(new SetCardInfo("Treefolk Seedlings", 278, Rarity.UNCOMMON, mage.cards.t.TreefolkSeedlings.class)); + cards.add(new SetCardInfo("Treetop Rangers", 279, Rarity.COMMON, mage.cards.t.TreetopRangers.class)); + cards.add(new SetCardInfo("Turnabout", 105, Rarity.UNCOMMON, mage.cards.t.Turnabout.class)); + cards.add(new SetCardInfo("Umbilicus", 312, Rarity.RARE, mage.cards.u.Umbilicus.class)); + cards.add(new SetCardInfo("Unnerve", 162, Rarity.COMMON, mage.cards.u.Unnerve.class)); + cards.add(new SetCardInfo("Unworthy Dead", 163, Rarity.COMMON, mage.cards.u.UnworthyDead.class)); + cards.add(new SetCardInfo("Urza's Armor", 313, Rarity.UNCOMMON, mage.cards.u.UrzasArmor.class)); + cards.add(new SetCardInfo("Vampiric Embrace", 164, Rarity.UNCOMMON, mage.cards.v.VampiricEmbrace.class)); + cards.add(new SetCardInfo("Vebulid", 165, Rarity.RARE, mage.cards.v.Vebulid.class)); + cards.add(new SetCardInfo("Veil of Birds", 106, Rarity.COMMON, mage.cards.v.VeilOfBirds.class)); + cards.add(new SetCardInfo("Veiled Apparition", 107, Rarity.UNCOMMON, mage.cards.v.VeiledApparition.class)); + cards.add(new SetCardInfo("Veiled Crocodile", 108, Rarity.RARE, mage.cards.v.VeiledCrocodile.class)); + cards.add(new SetCardInfo("Veiled Sentry", 109, Rarity.UNCOMMON, mage.cards.v.VeiledSentry.class)); + cards.add(new SetCardInfo("Veiled Serpent", 110, Rarity.COMMON, mage.cards.v.VeiledSerpent.class)); + cards.add(new SetCardInfo("Venomous Fangs", 280, Rarity.COMMON, mage.cards.v.VenomousFangs.class)); + cards.add(new SetCardInfo("Vernal Bloom", 281, Rarity.RARE, mage.cards.v.VernalBloom.class)); + cards.add(new SetCardInfo("Viashino Outrider", 223, Rarity.COMMON, mage.cards.v.ViashinoOutrider.class)); + cards.add(new SetCardInfo("Viashino Runner", 224, Rarity.COMMON, mage.cards.v.ViashinoRunner.class)); + cards.add(new SetCardInfo("Viashino Sandswimmer", 225, Rarity.RARE, mage.cards.v.ViashinoSandswimmer.class)); + cards.add(new SetCardInfo("Viashino Weaponsmith", 226, Rarity.COMMON, mage.cards.v.ViashinoWeaponsmith.class)); + cards.add(new SetCardInfo("Victimize", 166, Rarity.UNCOMMON, mage.cards.v.Victimize.class)); + cards.add(new SetCardInfo("Vile Requiem", 167, Rarity.UNCOMMON, mage.cards.v.VileRequiem.class)); + cards.add(new SetCardInfo("Voice of Grace", 54, Rarity.UNCOMMON, mage.cards.v.VoiceOfGrace.class)); + cards.add(new SetCardInfo("Voice of Law", 55, Rarity.UNCOMMON, mage.cards.v.VoiceOfLaw.class)); + cards.add(new SetCardInfo("Voltaic Key", 314, Rarity.UNCOMMON, mage.cards.v.VoltaicKey.class)); + cards.add(new SetCardInfo("Vug Lizard", 227, Rarity.UNCOMMON, mage.cards.v.VugLizard.class)); + cards.add(new SetCardInfo("War Dance", 282, Rarity.UNCOMMON, mage.cards.w.WarDance.class)); + cards.add(new SetCardInfo("Wall of Junk", 315, Rarity.UNCOMMON, mage.cards.w.WallOfJunk.class)); + cards.add(new SetCardInfo("Waylay", 56, Rarity.UNCOMMON, mage.cards.w.Waylay.class)); + cards.add(new SetCardInfo("Western Paladin", 168, Rarity.RARE, mage.cards.w.WesternPaladin.class)); + cards.add(new SetCardInfo("Whetstone", 316, Rarity.RARE, mage.cards.w.Whetstone.class)); + cards.add(new SetCardInfo("Whirlwind", 283, Rarity.RARE, mage.cards.w.Whirlwind.class)); + cards.add(new SetCardInfo("Wild Dogs", 284, Rarity.COMMON, mage.cards.w.WildDogs.class)); + cards.add(new SetCardInfo("Wildfire", 228, Rarity.RARE, mage.cards.w.Wildfire.class)); + cards.add(new SetCardInfo("Windfall", 111, Rarity.UNCOMMON, mage.cards.w.Windfall.class)); + cards.add(new SetCardInfo("Winding Wurm", 285, Rarity.COMMON, mage.cards.w.WindingWurm.class)); + cards.add(new SetCardInfo("Wirecat", 317, Rarity.UNCOMMON, mage.cards.w.Wirecat.class)); + cards.add(new SetCardInfo("Witch Engine", 169, Rarity.RARE, mage.cards.w.WitchEngine.class)); + cards.add(new SetCardInfo("Wizard Mentor", 112, Rarity.COMMON, mage.cards.w.WizardMentor.class)); + cards.add(new SetCardInfo("Worn Powerstone", 318, Rarity.UNCOMMON, mage.cards.w.WornPowerstone.class)); + cards.add(new SetCardInfo("Worship", 57, Rarity.RARE, mage.cards.w.Worship.class)); + cards.add(new SetCardInfo("Yawgmoth's Edict", 170, Rarity.UNCOMMON, mage.cards.y.YawgmothsEdict.class)); + cards.add(new SetCardInfo("Yawgmoth's Will", 171, Rarity.RARE, mage.cards.y.YawgmothsWill.class)); + cards.add(new SetCardInfo("Zephid", 113, Rarity.RARE, mage.cards.z.Zephid.class)); + cards.add(new SetCardInfo("Zephid's Embrace", 114, Rarity.UNCOMMON, mage.cards.z.ZephidsEmbrace.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Visions.java b/Mage.Sets/src/mage/sets/Visions.java index ea27845253..63ca9aeb98 100644 --- a/Mage.Sets/src/mage/sets/Visions.java +++ b/Mage.Sets/src/mage/sets/Visions.java @@ -1,186 +1,191 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author North - */ -public final class Visions extends ExpansionSet { - - private static final Visions instance = new Visions(); - - public static Visions getInstance() { - return instance; - } - - private Visions() { - super("Visions", "VIS", ExpansionSet.buildDate(1997, 1, 11), SetType.EXPANSION); - this.blockName = "Mirage"; - this.parentSet = Mirage.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Aku Djinn", 51, Rarity.RARE, mage.cards.a.AkuDjinn.class)); - cards.add(new SetCardInfo("Anvil of Bogardan", 141, Rarity.RARE, mage.cards.a.AnvilOfBogardan.class)); - cards.add(new SetCardInfo("Archangel", 1, Rarity.RARE, mage.cards.a.Archangel.class)); - cards.add(new SetCardInfo("Army Ants", 126, Rarity.UNCOMMON, mage.cards.a.ArmyAnts.class)); - cards.add(new SetCardInfo("Betrayal", 26, Rarity.COMMON, mage.cards.b.Betrayal.class)); - cards.add(new SetCardInfo("Blanket of Night", 52, Rarity.UNCOMMON, mage.cards.b.BlanketOfNight.class)); - cards.add(new SetCardInfo("Bogardan Phoenix", 76, Rarity.RARE, mage.cards.b.BogardanPhoenix.class)); - cards.add(new SetCardInfo("Brass-Talon Chimera", 142, Rarity.UNCOMMON, mage.cards.b.BrassTalonChimera.class)); - cards.add(new SetCardInfo("Breathstealer's Crypt", 127, Rarity.RARE, mage.cards.b.BreathstealersCrypt.class)); - cards.add(new SetCardInfo("Breezekeeper", 27, Rarity.COMMON, mage.cards.b.Breezekeeper.class)); - cards.add(new SetCardInfo("Brood of Cockroaches", 53, Rarity.UNCOMMON, mage.cards.b.BroodOfCockroaches.class)); - cards.add(new SetCardInfo("Bull Elephant", 101, Rarity.COMMON, mage.cards.b.BullElephant.class)); - cards.add(new SetCardInfo("Chronatog", 28, Rarity.RARE, mage.cards.c.Chronatog.class)); - cards.add(new SetCardInfo("City of Solitude", 102, Rarity.RARE, mage.cards.c.CityOfSolitude.class)); - cards.add(new SetCardInfo("Cloud Elemental", 29, Rarity.COMMON, mage.cards.c.CloudElemental.class)); - cards.add(new SetCardInfo("Coercion", 54, Rarity.COMMON, mage.cards.c.Coercion.class)); - cards.add(new SetCardInfo("Coral Atoll", 160, Rarity.UNCOMMON, mage.cards.c.CoralAtoll.class)); - cards.add(new SetCardInfo("Corrosion", 128, Rarity.RARE, mage.cards.c.Corrosion.class)); - cards.add(new SetCardInfo("Creeping Mold", 103, Rarity.UNCOMMON, mage.cards.c.CreepingMold.class)); - cards.add(new SetCardInfo("Crypt Rats", 55, Rarity.COMMON, mage.cards.c.CryptRats.class)); - cards.add(new SetCardInfo("Daraja Griffin", 2, Rarity.UNCOMMON, mage.cards.d.DarajaGriffin.class)); - cards.add(new SetCardInfo("Dark Privilege", 56, Rarity.COMMON, mage.cards.d.DarkPrivilege.class)); - cards.add(new SetCardInfo("Death Watch", 57, Rarity.COMMON, mage.cards.d.DeathWatch.class)); - cards.add(new SetCardInfo("Desertion", 30, Rarity.RARE, mage.cards.d.Desertion.class)); - cards.add(new SetCardInfo("Desolation", 58, Rarity.UNCOMMON, mage.cards.d.Desolation.class)); - cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class)); - cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class)); - cards.add(new SetCardInfo("Dragon Mask", 144, Rarity.UNCOMMON, mage.cards.d.DragonMask.class)); - cards.add(new SetCardInfo("Dream Tides", 31, Rarity.UNCOMMON, mage.cards.d.DreamTides.class)); - cards.add(new SetCardInfo("Dwarven Vigilantes", 77, Rarity.COMMON, mage.cards.d.DwarvenVigilantes.class)); - cards.add(new SetCardInfo("Elephant Grass", 104, Rarity.UNCOMMON, mage.cards.e.ElephantGrass.class)); - cards.add(new SetCardInfo("Elkin Lair", 78, Rarity.RARE, mage.cards.e.ElkinLair.class)); - cards.add(new SetCardInfo("Elven Cache", 105, Rarity.COMMON, mage.cards.e.ElvenCache.class)); - cards.add(new SetCardInfo("Emerald Charm", 106, Rarity.COMMON, mage.cards.e.EmeraldCharm.class)); - cards.add(new SetCardInfo("Equipoise", 3, Rarity.RARE, mage.cards.e.Equipoise.class)); - cards.add(new SetCardInfo("Everglades", 162, Rarity.UNCOMMON, mage.cards.e.Everglades.class)); - cards.add(new SetCardInfo("Eye of Singularity", 4, Rarity.RARE, mage.cards.e.EyeOfSingularity.class)); - cards.add(new SetCardInfo("Fallen Askari", 59, Rarity.COMMON, mage.cards.f.FallenAskari.class)); - cards.add(new SetCardInfo("Femeref Enchantress", 129, Rarity.RARE, mage.cards.f.FemerefEnchantress.class)); - cards.add(new SetCardInfo("Feral Instinct", 107, Rarity.COMMON, mage.cards.f.FeralInstinct.class)); - cards.add(new SetCardInfo("Fireblast", 79, Rarity.COMMON, mage.cards.f.Fireblast.class)); - cards.add(new SetCardInfo("Firestorm Hellkite", 130, Rarity.RARE, mage.cards.f.FirestormHellkite.class)); - cards.add(new SetCardInfo("Flooded Shoreline", 32, Rarity.RARE, mage.cards.f.FloodedShoreline.class)); - cards.add(new SetCardInfo("Foreshadow", 33, Rarity.UNCOMMON, mage.cards.f.Foreshadow.class)); - cards.add(new SetCardInfo("Freewind Falcon", 5, Rarity.COMMON, mage.cards.f.FreewindFalcon.class)); - cards.add(new SetCardInfo("Funeral Charm", 61, Rarity.COMMON, mage.cards.f.FuneralCharm.class)); - cards.add(new SetCardInfo("Giant Caterpillar", 108, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); - cards.add(new SetCardInfo("Goblin Recruiter", 80, Rarity.UNCOMMON, mage.cards.g.GoblinRecruiter.class)); - cards.add(new SetCardInfo("Goblin Swine-Rider", 81, Rarity.COMMON, mage.cards.g.GoblinSwineRider.class)); - cards.add(new SetCardInfo("Gossamer Chains", 6, Rarity.COMMON, mage.cards.g.GossamerChains.class)); - cards.add(new SetCardInfo("Griffin Canyon", 163, Rarity.RARE, mage.cards.g.GriffinCanyon.class)); - cards.add(new SetCardInfo("Hearth Charm", 82, Rarity.COMMON, mage.cards.h.HearthCharm.class)); - cards.add(new SetCardInfo("Helm of Awakening", 145, Rarity.UNCOMMON, mage.cards.h.HelmOfAwakening.class)); - cards.add(new SetCardInfo("Honorable Passage", 7, Rarity.UNCOMMON, mage.cards.h.HonorablePassage.class)); - cards.add(new SetCardInfo("Hope Charm", 8, Rarity.COMMON, mage.cards.h.HopeCharm.class)); - cards.add(new SetCardInfo("Hulking Cyclops", 84, Rarity.UNCOMMON, mage.cards.h.HulkingCyclops.class)); - cards.add(new SetCardInfo("Impulse", 34, Rarity.COMMON, mage.cards.i.Impulse.class)); - cards.add(new SetCardInfo("Infantry Veteran", 9, Rarity.COMMON, mage.cards.i.InfantryVeteran.class)); - cards.add(new SetCardInfo("Inspiration", 35, Rarity.COMMON, mage.cards.i.Inspiration.class)); - cards.add(new SetCardInfo("Iron-Heart Chimera", 146, Rarity.UNCOMMON, mage.cards.i.IronHeartChimera.class)); - cards.add(new SetCardInfo("Jamuraan Lion", 10, Rarity.COMMON, mage.cards.j.JamuraanLion.class)); - cards.add(new SetCardInfo("Juju Bubble", 147, Rarity.UNCOMMON, mage.cards.j.JujuBubble.class)); - cards.add(new SetCardInfo("Jungle Basin", 164, Rarity.UNCOMMON, mage.cards.j.JungleBasin.class)); - cards.add(new SetCardInfo("Kaervek's Spite", 63, Rarity.RARE, mage.cards.k.KaerveksSpite.class)); - cards.add(new SetCardInfo("Karoo", 165, Rarity.UNCOMMON, mage.cards.k.Karoo.class)); - cards.add(new SetCardInfo("Katabatic Winds", 109, Rarity.RARE, mage.cards.k.KatabaticWinds.class)); - cards.add(new SetCardInfo("Keeper of Kookus", 85, Rarity.COMMON, mage.cards.k.KeeperOfKookus.class)); - cards.add(new SetCardInfo("King Cheetah", 110, Rarity.COMMON, mage.cards.k.KingCheetah.class)); - cards.add(new SetCardInfo("Knight of the Mists", 36, Rarity.COMMON, mage.cards.k.KnightOfTheMists.class)); - cards.add(new SetCardInfo("Knight of Valor", 11, Rarity.COMMON, mage.cards.k.KnightOfValor.class)); - cards.add(new SetCardInfo("Kookus", 86, Rarity.RARE, mage.cards.k.Kookus.class)); - cards.add(new SetCardInfo("Lead-Belly Chimera", 148, Rarity.UNCOMMON, mage.cards.l.LeadBellyChimera.class)); - cards.add(new SetCardInfo("Lichenthrope", 112, Rarity.RARE, mage.cards.l.Lichenthrope.class)); - cards.add(new SetCardInfo("Lightning Cloud", 87, Rarity.RARE, mage.cards.l.LightningCloud.class)); - cards.add(new SetCardInfo("Longbow Archer", 12, Rarity.UNCOMMON, mage.cards.l.LongbowArcher.class)); - cards.add(new SetCardInfo("Magma Mine", 149, Rarity.UNCOMMON, mage.cards.m.MagmaMine.class)); - cards.add(new SetCardInfo("Man-o'-War", 37, Rarity.COMMON, mage.cards.m.ManOWar.class)); - cards.add(new SetCardInfo("Miraculous Recovery", 13, Rarity.UNCOMMON, mage.cards.m.MiraculousRecovery.class)); - cards.add(new SetCardInfo("Mortal Wound", 113, Rarity.COMMON, mage.cards.m.MortalWound.class)); - cards.add(new SetCardInfo("Mundungu", 132, Rarity.UNCOMMON, mage.cards.m.Mundungu.class)); - cards.add(new SetCardInfo("Mystic Veil", 38, Rarity.COMMON, mage.cards.m.MysticVeil.class)); - cards.add(new SetCardInfo("Natural Order", 114, Rarity.RARE, mage.cards.n.NaturalOrder.class)); - cards.add(new SetCardInfo("Necromancy", 64, Rarity.UNCOMMON, mage.cards.n.Necromancy.class)); - cards.add(new SetCardInfo("Necrosavant", 65, Rarity.RARE, mage.cards.n.Necrosavant.class)); - cards.add(new SetCardInfo("Nekrataal", 66, Rarity.UNCOMMON, mage.cards.n.Nekrataal.class)); - cards.add(new SetCardInfo("Ovinomancer", 39, Rarity.UNCOMMON, mage.cards.o.Ovinomancer.class)); - cards.add(new SetCardInfo("Panther Warriors", 115, Rarity.COMMON, mage.cards.p.PantherWarriors.class)); - cards.add(new SetCardInfo("Parapet", 14, Rarity.COMMON, mage.cards.p.Parapet.class)); - cards.add(new SetCardInfo("Phyrexian Marauder", 151, Rarity.RARE, mage.cards.p.PhyrexianMarauder.class)); - cards.add(new SetCardInfo("Phyrexian Walker", 152, Rarity.COMMON, mage.cards.p.PhyrexianWalker.class)); - cards.add(new SetCardInfo("Pillar Tombs of Aku", 67, Rarity.RARE, mage.cards.p.PillarTombsOfAku.class)); - cards.add(new SetCardInfo("Prosperity", 40, Rarity.UNCOMMON, mage.cards.p.Prosperity.class)); - cards.add(new SetCardInfo("Python", 68, Rarity.COMMON, mage.cards.p.Python.class)); - cards.add(new SetCardInfo("Quicksand", 166, Rarity.UNCOMMON, mage.cards.q.Quicksand.class)); - cards.add(new SetCardInfo("Quirion Ranger", 117, Rarity.COMMON, mage.cards.q.QuirionRanger.class)); - cards.add(new SetCardInfo("Raging Gorilla", 90, Rarity.COMMON, mage.cards.r.RagingGorilla.class)); - cards.add(new SetCardInfo("Rainbow Efreet", 41, Rarity.RARE, mage.cards.r.RainbowEfreet.class)); - cards.add(new SetCardInfo("Relentless Assault", 91, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); - cards.add(new SetCardInfo("Relic Ward", 16, Rarity.UNCOMMON, mage.cards.r.RelicWard.class)); - cards.add(new SetCardInfo("Remedy", 17, Rarity.COMMON, mage.cards.r.Remedy.class)); - cards.add(new SetCardInfo("Resistance Fighter", 18, Rarity.COMMON, mage.cards.r.ResistanceFighter.class)); - cards.add(new SetCardInfo("Retribution of the Meek", 19, Rarity.RARE, mage.cards.r.RetributionOfTheMeek.class)); - cards.add(new SetCardInfo("Righteous Aura", 20, Rarity.COMMON, mage.cards.r.RighteousAura.class)); - cards.add(new SetCardInfo("Righteous War", 134, Rarity.RARE, mage.cards.r.RighteousWar.class)); - cards.add(new SetCardInfo("River Boa", 118, Rarity.COMMON, mage.cards.r.RiverBoa.class)); - cards.add(new SetCardInfo("Rock Slide", 92, Rarity.COMMON, mage.cards.r.RockSlide.class)); - cards.add(new SetCardInfo("Rowen", 119, Rarity.RARE, mage.cards.r.Rowen.class)); - cards.add(new SetCardInfo("Sands of Time", 153, Rarity.RARE, mage.cards.s.SandsOfTime.class)); - cards.add(new SetCardInfo("Scalebane's Elite", 135, Rarity.UNCOMMON, mage.cards.s.ScalebanesElite.class)); - cards.add(new SetCardInfo("Shimmering Efreet", 42, Rarity.UNCOMMON, mage.cards.s.ShimmeringEfreet.class)); - cards.add(new SetCardInfo("Shrieking Drake", 43, Rarity.COMMON, mage.cards.s.ShriekingDrake.class)); - cards.add(new SetCardInfo("Simoon", 136, Rarity.UNCOMMON, mage.cards.s.Simoon.class)); - cards.add(new SetCardInfo("Sisay's Ring", 154, Rarity.COMMON, mage.cards.s.SisaysRing.class)); - cards.add(new SetCardInfo("Snake Basket", 155, Rarity.RARE, mage.cards.s.SnakeBasket.class)); - cards.add(new SetCardInfo("Solfatara", 93, Rarity.COMMON, mage.cards.s.Solfatara.class)); - cards.add(new SetCardInfo("Song of Blood", 94, Rarity.COMMON, mage.cards.s.SongOfBlood.class)); - cards.add(new SetCardInfo("Spider Climb", 120, Rarity.COMMON, mage.cards.s.SpiderClimb.class)); - cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class)); - cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class)); - cards.add(new SetCardInfo("Stampeding Wildebeests", 121, Rarity.UNCOMMON, mage.cards.s.StampedingWildebeests.class)); - cards.add(new SetCardInfo("Suleiman's Legacy", 138, Rarity.RARE, mage.cards.s.SuleimansLegacy.class)); - cards.add(new SetCardInfo("Summer Bloom", 122, Rarity.UNCOMMON, mage.cards.s.SummerBloom.class)); - cards.add(new SetCardInfo("Sun Clasp", 21, Rarity.COMMON, mage.cards.s.SunClasp.class)); - cards.add(new SetCardInfo("Suq'Ata Assassin", 69, Rarity.UNCOMMON, mage.cards.s.SuqAtaAssassin.class)); - cards.add(new SetCardInfo("Suq'Ata Lancer", 96, Rarity.COMMON, mage.cards.s.SuqAtaLancer.class)); - cards.add(new SetCardInfo("Talruum Champion", 97, Rarity.COMMON, mage.cards.t.TalruumChampion.class)); - cards.add(new SetCardInfo("Talruum Piper", 98, Rarity.UNCOMMON, mage.cards.t.TalruumPiper.class)); - cards.add(new SetCardInfo("Tar Pit Warrior", 70, Rarity.COMMON, mage.cards.t.TarPitWarrior.class)); - cards.add(new SetCardInfo("Teferi's Honor Guard", 22, Rarity.UNCOMMON, mage.cards.t.TeferisHonorGuard.class)); - cards.add(new SetCardInfo("Teferi's Puzzle Box", 156, Rarity.RARE, mage.cards.t.TeferisPuzzleBox.class)); - cards.add(new SetCardInfo("Teferi's Realm", 44, Rarity.RARE, mage.cards.t.TeferisRealm.class)); - cards.add(new SetCardInfo("Tempest Drake", 139, Rarity.UNCOMMON, mage.cards.t.TempestDrake.class)); - cards.add(new SetCardInfo("Three Wishes", 45, Rarity.RARE, mage.cards.t.ThreeWishes.class)); - cards.add(new SetCardInfo("Tin-Wing Chimera", 157, Rarity.UNCOMMON, mage.cards.t.TinWingChimera.class)); - cards.add(new SetCardInfo("Tithe", 23, Rarity.RARE, mage.cards.t.Tithe.class)); - cards.add(new SetCardInfo("Tremor", 99, Rarity.COMMON, mage.cards.t.Tremor.class)); - cards.add(new SetCardInfo("Triangle of War", 158, Rarity.RARE, mage.cards.t.TriangleOfWar.class)); - cards.add(new SetCardInfo("Uktabi Orangutan", 123, Rarity.UNCOMMON, mage.cards.u.UktabiOrangutan.class)); - cards.add(new SetCardInfo("Undiscovered Paradise", 167, Rarity.RARE, mage.cards.u.UndiscoveredParadise.class)); - cards.add(new SetCardInfo("Undo", 47, Rarity.COMMON, mage.cards.u.Undo.class)); - cards.add(new SetCardInfo("Urborg Mindsucker", 71, Rarity.COMMON, mage.cards.u.UrborgMindsucker.class)); - cards.add(new SetCardInfo("Vampiric Tutor", 72, Rarity.RARE, mage.cards.v.VampiricTutor.class)); - cards.add(new SetCardInfo("Vampirism", 73, Rarity.UNCOMMON, mage.cards.v.Vampirism.class)); - cards.add(new SetCardInfo("Vanishing", 48, Rarity.COMMON, mage.cards.v.Vanishing.class)); - cards.add(new SetCardInfo("Viashino Sandstalker", 100, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class)); - cards.add(new SetCardInfo("Viashivan Dragon", 140, Rarity.RARE, mage.cards.v.ViashivanDragon.class)); - cards.add(new SetCardInfo("Vision Charm", 49, Rarity.COMMON, mage.cards.v.VisionCharm.class)); - cards.add(new SetCardInfo("Wake of Vultures", 74, Rarity.COMMON, mage.cards.w.WakeOfVultures.class)); - cards.add(new SetCardInfo("Wand of Denial", 159, Rarity.RARE, mage.cards.w.WandOfDenial.class)); - cards.add(new SetCardInfo("Warrior's Honor", 24, Rarity.COMMON, mage.cards.w.WarriorsHonor.class)); - cards.add(new SetCardInfo("Warthog", 124, Rarity.COMMON, mage.cards.w.Warthog.class)); - cards.add(new SetCardInfo("Waterspout Djinn", 50, Rarity.UNCOMMON, mage.cards.w.WaterspoutDjinn.class)); - cards.add(new SetCardInfo("Wicked Reward", 75, Rarity.COMMON, mage.cards.w.WickedReward.class)); - cards.add(new SetCardInfo("Wind Shear", 125, Rarity.UNCOMMON, mage.cards.w.WindShear.class)); - cards.add(new SetCardInfo("Zhalfirin Crusader", 25, Rarity.RARE, mage.cards.z.ZhalfirinCrusader.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author North + */ +public final class Visions extends ExpansionSet { + + private static final Visions instance = new Visions(); + + public static Visions getInstance() { + return instance; + } + + private Visions() { + super("Visions", "VIS", ExpansionSet.buildDate(1997, 1, 11), SetType.EXPANSION); + this.blockName = "Mirage"; + this.parentSet = Mirage.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Aku Djinn", 51, Rarity.RARE, mage.cards.a.AkuDjinn.class)); + cards.add(new SetCardInfo("Anvil of Bogardan", 141, Rarity.RARE, mage.cards.a.AnvilOfBogardan.class)); + cards.add(new SetCardInfo("Archangel", 1, Rarity.RARE, mage.cards.a.Archangel.class)); + cards.add(new SetCardInfo("Army Ants", 126, Rarity.UNCOMMON, mage.cards.a.ArmyAnts.class)); + cards.add(new SetCardInfo("Betrayal", 26, Rarity.COMMON, mage.cards.b.Betrayal.class)); + cards.add(new SetCardInfo("Blanket of Night", 52, Rarity.UNCOMMON, mage.cards.b.BlanketOfNight.class)); + cards.add(new SetCardInfo("Bogardan Phoenix", 76, Rarity.RARE, mage.cards.b.BogardanPhoenix.class)); + cards.add(new SetCardInfo("Brass-Talon Chimera", 142, Rarity.UNCOMMON, mage.cards.b.BrassTalonChimera.class)); + cards.add(new SetCardInfo("Breathstealer's Crypt", 127, Rarity.RARE, mage.cards.b.BreathstealersCrypt.class)); + cards.add(new SetCardInfo("Breezekeeper", 27, Rarity.COMMON, mage.cards.b.Breezekeeper.class)); + cards.add(new SetCardInfo("Brood of Cockroaches", 53, Rarity.UNCOMMON, mage.cards.b.BroodOfCockroaches.class)); + cards.add(new SetCardInfo("Bull Elephant", 101, Rarity.COMMON, mage.cards.b.BullElephant.class)); + cards.add(new SetCardInfo("Chronatog", 28, Rarity.RARE, mage.cards.c.Chronatog.class)); + cards.add(new SetCardInfo("City of Solitude", 102, Rarity.RARE, mage.cards.c.CityOfSolitude.class)); + cards.add(new SetCardInfo("Cloud Elemental", 29, Rarity.COMMON, mage.cards.c.CloudElemental.class)); + cards.add(new SetCardInfo("Coercion", 54, Rarity.COMMON, mage.cards.c.Coercion.class)); + cards.add(new SetCardInfo("Coral Atoll", 160, Rarity.UNCOMMON, mage.cards.c.CoralAtoll.class)); + cards.add(new SetCardInfo("Corrosion", 128, Rarity.RARE, mage.cards.c.Corrosion.class)); + cards.add(new SetCardInfo("Creeping Mold", 103, Rarity.UNCOMMON, mage.cards.c.CreepingMold.class)); + cards.add(new SetCardInfo("Crypt Rats", 55, Rarity.COMMON, mage.cards.c.CryptRats.class)); + cards.add(new SetCardInfo("Daraja Griffin", 2, Rarity.UNCOMMON, mage.cards.d.DarajaGriffin.class)); + cards.add(new SetCardInfo("Dark Privilege", 56, Rarity.COMMON, mage.cards.d.DarkPrivilege.class)); + cards.add(new SetCardInfo("Death Watch", 57, Rarity.COMMON, mage.cards.d.DeathWatch.class)); + cards.add(new SetCardInfo("Desertion", 30, Rarity.RARE, mage.cards.d.Desertion.class)); + cards.add(new SetCardInfo("Desolation", 58, Rarity.UNCOMMON, mage.cards.d.Desolation.class)); + cards.add(new SetCardInfo("Diamond Kaleidoscope", 143, Rarity.RARE, mage.cards.d.DiamondKaleidoscope.class)); + cards.add(new SetCardInfo("Dormant Volcano", 161, Rarity.UNCOMMON, mage.cards.d.DormantVolcano.class)); + cards.add(new SetCardInfo("Dragon Mask", 144, Rarity.UNCOMMON, mage.cards.d.DragonMask.class)); + cards.add(new SetCardInfo("Dream Tides", 31, Rarity.UNCOMMON, mage.cards.d.DreamTides.class)); + cards.add(new SetCardInfo("Dwarven Vigilantes", 77, Rarity.COMMON, mage.cards.d.DwarvenVigilantes.class)); + cards.add(new SetCardInfo("Elephant Grass", 104, Rarity.UNCOMMON, mage.cards.e.ElephantGrass.class)); + cards.add(new SetCardInfo("Elkin Lair", 78, Rarity.RARE, mage.cards.e.ElkinLair.class)); + cards.add(new SetCardInfo("Elven Cache", 105, Rarity.COMMON, mage.cards.e.ElvenCache.class)); + cards.add(new SetCardInfo("Emerald Charm", 106, Rarity.COMMON, mage.cards.e.EmeraldCharm.class)); + cards.add(new SetCardInfo("Equipoise", 3, Rarity.RARE, mage.cards.e.Equipoise.class)); + cards.add(new SetCardInfo("Everglades", 162, Rarity.UNCOMMON, mage.cards.e.Everglades.class)); + cards.add(new SetCardInfo("Eye of Singularity", 4, Rarity.RARE, mage.cards.e.EyeOfSingularity.class)); + cards.add(new SetCardInfo("Fallen Askari", 59, Rarity.COMMON, mage.cards.f.FallenAskari.class)); + cards.add(new SetCardInfo("Femeref Enchantress", 129, Rarity.RARE, mage.cards.f.FemerefEnchantress.class)); + cards.add(new SetCardInfo("Feral Instinct", 107, Rarity.COMMON, mage.cards.f.FeralInstinct.class)); + cards.add(new SetCardInfo("Fireblast", 79, Rarity.COMMON, mage.cards.f.Fireblast.class)); + cards.add(new SetCardInfo("Firestorm Hellkite", 130, Rarity.RARE, mage.cards.f.FirestormHellkite.class)); + cards.add(new SetCardInfo("Flooded Shoreline", 32, Rarity.RARE, mage.cards.f.FloodedShoreline.class)); + cards.add(new SetCardInfo("Foreshadow", 33, Rarity.UNCOMMON, mage.cards.f.Foreshadow.class)); + cards.add(new SetCardInfo("Freewind Falcon", 5, Rarity.COMMON, mage.cards.f.FreewindFalcon.class)); + cards.add(new SetCardInfo("Funeral Charm", 61, Rarity.COMMON, mage.cards.f.FuneralCharm.class)); + cards.add(new SetCardInfo("Giant Caterpillar", 108, Rarity.COMMON, mage.cards.g.GiantCaterpillar.class)); + cards.add(new SetCardInfo("Goblin Recruiter", 80, Rarity.UNCOMMON, mage.cards.g.GoblinRecruiter.class)); + cards.add(new SetCardInfo("Goblin Swine-Rider", 81, Rarity.COMMON, mage.cards.g.GoblinSwineRider.class)); + cards.add(new SetCardInfo("Gossamer Chains", 6, Rarity.COMMON, mage.cards.g.GossamerChains.class)); + cards.add(new SetCardInfo("Griffin Canyon", 163, Rarity.RARE, mage.cards.g.GriffinCanyon.class)); + cards.add(new SetCardInfo("Guiding Spirit", 131, Rarity.RARE, mage.cards.g.GuidingSpirit.class)); + cards.add(new SetCardInfo("Hearth Charm", 82, Rarity.COMMON, mage.cards.h.HearthCharm.class)); + cards.add(new SetCardInfo("Helm of Awakening", 145, Rarity.UNCOMMON, mage.cards.h.HelmOfAwakening.class)); + cards.add(new SetCardInfo("Honorable Passage", 7, Rarity.UNCOMMON, mage.cards.h.HonorablePassage.class)); + cards.add(new SetCardInfo("Hope Charm", 8, Rarity.COMMON, mage.cards.h.HopeCharm.class)); + cards.add(new SetCardInfo("Hulking Cyclops", 84, Rarity.UNCOMMON, mage.cards.h.HulkingCyclops.class)); + cards.add(new SetCardInfo("Impulse", 34, Rarity.COMMON, mage.cards.i.Impulse.class)); + cards.add(new SetCardInfo("Infantry Veteran", 9, Rarity.COMMON, mage.cards.i.InfantryVeteran.class)); + cards.add(new SetCardInfo("Inspiration", 35, Rarity.COMMON, mage.cards.i.Inspiration.class)); + cards.add(new SetCardInfo("Iron-Heart Chimera", 146, Rarity.UNCOMMON, mage.cards.i.IronHeartChimera.class)); + cards.add(new SetCardInfo("Jamuraan Lion", 10, Rarity.COMMON, mage.cards.j.JamuraanLion.class)); + cards.add(new SetCardInfo("Juju Bubble", 147, Rarity.UNCOMMON, mage.cards.j.JujuBubble.class)); + cards.add(new SetCardInfo("Jungle Basin", 164, Rarity.UNCOMMON, mage.cards.j.JungleBasin.class)); + cards.add(new SetCardInfo("Kaervek's Spite", 63, Rarity.RARE, mage.cards.k.KaerveksSpite.class)); + cards.add(new SetCardInfo("Karoo", 165, Rarity.UNCOMMON, mage.cards.k.Karoo.class)); + cards.add(new SetCardInfo("Katabatic Winds", 109, Rarity.RARE, mage.cards.k.KatabaticWinds.class)); + cards.add(new SetCardInfo("Keeper of Kookus", 85, Rarity.COMMON, mage.cards.k.KeeperOfKookus.class)); + cards.add(new SetCardInfo("King Cheetah", 110, Rarity.COMMON, mage.cards.k.KingCheetah.class)); + cards.add(new SetCardInfo("Knight of the Mists", 36, Rarity.COMMON, mage.cards.k.KnightOfTheMists.class)); + cards.add(new SetCardInfo("Knight of Valor", 11, Rarity.COMMON, mage.cards.k.KnightOfValor.class)); + cards.add(new SetCardInfo("Kookus", 86, Rarity.RARE, mage.cards.k.Kookus.class)); + cards.add(new SetCardInfo("Kyscu Drake", 111, Rarity.RARE, mage.cards.k.KyscuDrake.class)); + cards.add(new SetCardInfo("Lead-Belly Chimera", 148, Rarity.UNCOMMON, mage.cards.l.LeadBellyChimera.class)); + cards.add(new SetCardInfo("Lichenthrope", 112, Rarity.RARE, mage.cards.l.Lichenthrope.class)); + cards.add(new SetCardInfo("Lightning Cloud", 87, Rarity.RARE, mage.cards.l.LightningCloud.class)); + cards.add(new SetCardInfo("Longbow Archer", 12, Rarity.UNCOMMON, mage.cards.l.LongbowArcher.class)); + cards.add(new SetCardInfo("Magma Mine", 149, Rarity.UNCOMMON, mage.cards.m.MagmaMine.class)); + cards.add(new SetCardInfo("Man-o'-War", 37, Rarity.COMMON, mage.cards.m.ManOWar.class)); + cards.add(new SetCardInfo("Miraculous Recovery", 13, Rarity.UNCOMMON, mage.cards.m.MiraculousRecovery.class)); + cards.add(new SetCardInfo("Mob Mentality", 88, Rarity.UNCOMMON, mage.cards.m.MobMentality.class)); + cards.add(new SetCardInfo("Mortal Wound", 113, Rarity.COMMON, mage.cards.m.MortalWound.class)); + cards.add(new SetCardInfo("Mundungu", 132, Rarity.UNCOMMON, mage.cards.m.Mundungu.class)); + cards.add(new SetCardInfo("Mystic Veil", 38, Rarity.COMMON, mage.cards.m.MysticVeil.class)); + cards.add(new SetCardInfo("Natural Order", 114, Rarity.RARE, mage.cards.n.NaturalOrder.class)); + cards.add(new SetCardInfo("Necromancy", 64, Rarity.UNCOMMON, mage.cards.n.Necromancy.class)); + cards.add(new SetCardInfo("Necrosavant", 65, Rarity.RARE, mage.cards.n.Necrosavant.class)); + cards.add(new SetCardInfo("Nekrataal", 66, Rarity.UNCOMMON, mage.cards.n.Nekrataal.class)); + cards.add(new SetCardInfo("Ovinomancer", 39, Rarity.UNCOMMON, mage.cards.o.Ovinomancer.class)); + cards.add(new SetCardInfo("Panther Warriors", 115, Rarity.COMMON, mage.cards.p.PantherWarriors.class)); + cards.add(new SetCardInfo("Parapet", 14, Rarity.COMMON, mage.cards.p.Parapet.class)); + cards.add(new SetCardInfo("Peace Talks", 15, Rarity.UNCOMMON, mage.cards.p.PeaceTalks.class)); + cards.add(new SetCardInfo("Phyrexian Marauder", 151, Rarity.RARE, mage.cards.p.PhyrexianMarauder.class)); + cards.add(new SetCardInfo("Phyrexian Walker", 152, Rarity.COMMON, mage.cards.p.PhyrexianWalker.class)); + cards.add(new SetCardInfo("Pillar Tombs of Aku", 67, Rarity.RARE, mage.cards.p.PillarTombsOfAku.class)); + cards.add(new SetCardInfo("Prosperity", 40, Rarity.UNCOMMON, mage.cards.p.Prosperity.class)); + cards.add(new SetCardInfo("Python", 68, Rarity.COMMON, mage.cards.p.Python.class)); + cards.add(new SetCardInfo("Quicksand", 166, Rarity.UNCOMMON, mage.cards.q.Quicksand.class)); + cards.add(new SetCardInfo("Quirion Druid", 116, Rarity.RARE, mage.cards.q.QuirionDruid.class)); + cards.add(new SetCardInfo("Quirion Ranger", 117, Rarity.COMMON, mage.cards.q.QuirionRanger.class)); + cards.add(new SetCardInfo("Raging Gorilla", 90, Rarity.COMMON, mage.cards.r.RagingGorilla.class)); + cards.add(new SetCardInfo("Rainbow Efreet", 41, Rarity.RARE, mage.cards.r.RainbowEfreet.class)); + cards.add(new SetCardInfo("Relentless Assault", 91, Rarity.RARE, mage.cards.r.RelentlessAssault.class)); + cards.add(new SetCardInfo("Relic Ward", 16, Rarity.UNCOMMON, mage.cards.r.RelicWard.class)); + cards.add(new SetCardInfo("Remedy", 17, Rarity.COMMON, mage.cards.r.Remedy.class)); + cards.add(new SetCardInfo("Resistance Fighter", 18, Rarity.COMMON, mage.cards.r.ResistanceFighter.class)); + cards.add(new SetCardInfo("Retribution of the Meek", 19, Rarity.RARE, mage.cards.r.RetributionOfTheMeek.class)); + cards.add(new SetCardInfo("Righteous Aura", 20, Rarity.COMMON, mage.cards.r.RighteousAura.class)); + cards.add(new SetCardInfo("Righteous War", 134, Rarity.RARE, mage.cards.r.RighteousWar.class)); + cards.add(new SetCardInfo("River Boa", 118, Rarity.COMMON, mage.cards.r.RiverBoa.class)); + cards.add(new SetCardInfo("Rock Slide", 92, Rarity.COMMON, mage.cards.r.RockSlide.class)); + cards.add(new SetCardInfo("Rowen", 119, Rarity.RARE, mage.cards.r.Rowen.class)); + cards.add(new SetCardInfo("Sands of Time", 153, Rarity.RARE, mage.cards.s.SandsOfTime.class)); + cards.add(new SetCardInfo("Scalebane's Elite", 135, Rarity.UNCOMMON, mage.cards.s.ScalebanesElite.class)); + cards.add(new SetCardInfo("Shimmering Efreet", 42, Rarity.UNCOMMON, mage.cards.s.ShimmeringEfreet.class)); + cards.add(new SetCardInfo("Shrieking Drake", 43, Rarity.COMMON, mage.cards.s.ShriekingDrake.class)); + cards.add(new SetCardInfo("Simoon", 136, Rarity.UNCOMMON, mage.cards.s.Simoon.class)); + cards.add(new SetCardInfo("Sisay's Ring", 154, Rarity.COMMON, mage.cards.s.SisaysRing.class)); + cards.add(new SetCardInfo("Snake Basket", 155, Rarity.RARE, mage.cards.s.SnakeBasket.class)); + cards.add(new SetCardInfo("Solfatara", 93, Rarity.COMMON, mage.cards.s.Solfatara.class)); + cards.add(new SetCardInfo("Song of Blood", 94, Rarity.COMMON, mage.cards.s.SongOfBlood.class)); + cards.add(new SetCardInfo("Spider Climb", 120, Rarity.COMMON, mage.cards.s.SpiderClimb.class)); + cards.add(new SetCardInfo("Spitting Drake", 95, Rarity.UNCOMMON, mage.cards.s.SpittingDrake.class)); + cards.add(new SetCardInfo("Squandered Resources", 137, Rarity.RARE, mage.cards.s.SquanderedResources.class)); + cards.add(new SetCardInfo("Stampeding Wildebeests", 121, Rarity.UNCOMMON, mage.cards.s.StampedingWildebeests.class)); + cards.add(new SetCardInfo("Suleiman's Legacy", 138, Rarity.RARE, mage.cards.s.SuleimansLegacy.class)); + cards.add(new SetCardInfo("Summer Bloom", 122, Rarity.UNCOMMON, mage.cards.s.SummerBloom.class)); + cards.add(new SetCardInfo("Sun Clasp", 21, Rarity.COMMON, mage.cards.s.SunClasp.class)); + cards.add(new SetCardInfo("Suq'Ata Assassin", 69, Rarity.UNCOMMON, mage.cards.s.SuqAtaAssassin.class)); + cards.add(new SetCardInfo("Suq'Ata Lancer", 96, Rarity.COMMON, mage.cards.s.SuqAtaLancer.class)); + cards.add(new SetCardInfo("Talruum Champion", 97, Rarity.COMMON, mage.cards.t.TalruumChampion.class)); + cards.add(new SetCardInfo("Talruum Piper", 98, Rarity.UNCOMMON, mage.cards.t.TalruumPiper.class)); + cards.add(new SetCardInfo("Tar Pit Warrior", 70, Rarity.COMMON, mage.cards.t.TarPitWarrior.class)); + cards.add(new SetCardInfo("Teferi's Honor Guard", 22, Rarity.UNCOMMON, mage.cards.t.TeferisHonorGuard.class)); + cards.add(new SetCardInfo("Teferi's Puzzle Box", 156, Rarity.RARE, mage.cards.t.TeferisPuzzleBox.class)); + cards.add(new SetCardInfo("Teferi's Realm", 44, Rarity.RARE, mage.cards.t.TeferisRealm.class)); + cards.add(new SetCardInfo("Tempest Drake", 139, Rarity.UNCOMMON, mage.cards.t.TempestDrake.class)); + cards.add(new SetCardInfo("Three Wishes", 45, Rarity.RARE, mage.cards.t.ThreeWishes.class)); + cards.add(new SetCardInfo("Tin-Wing Chimera", 157, Rarity.UNCOMMON, mage.cards.t.TinWingChimera.class)); + cards.add(new SetCardInfo("Tithe", 23, Rarity.RARE, mage.cards.t.Tithe.class)); + cards.add(new SetCardInfo("Tremor", 99, Rarity.COMMON, mage.cards.t.Tremor.class)); + cards.add(new SetCardInfo("Triangle of War", 158, Rarity.RARE, mage.cards.t.TriangleOfWar.class)); + cards.add(new SetCardInfo("Uktabi Orangutan", 123, Rarity.UNCOMMON, mage.cards.u.UktabiOrangutan.class)); + cards.add(new SetCardInfo("Undiscovered Paradise", 167, Rarity.RARE, mage.cards.u.UndiscoveredParadise.class)); + cards.add(new SetCardInfo("Undo", 47, Rarity.COMMON, mage.cards.u.Undo.class)); + cards.add(new SetCardInfo("Urborg Mindsucker", 71, Rarity.COMMON, mage.cards.u.UrborgMindsucker.class)); + cards.add(new SetCardInfo("Vampiric Tutor", 72, Rarity.RARE, mage.cards.v.VampiricTutor.class)); + cards.add(new SetCardInfo("Vampirism", 73, Rarity.UNCOMMON, mage.cards.v.Vampirism.class)); + cards.add(new SetCardInfo("Vanishing", 48, Rarity.COMMON, mage.cards.v.Vanishing.class)); + cards.add(new SetCardInfo("Viashino Sandstalker", 100, Rarity.UNCOMMON, mage.cards.v.ViashinoSandstalker.class)); + cards.add(new SetCardInfo("Viashivan Dragon", 140, Rarity.RARE, mage.cards.v.ViashivanDragon.class)); + cards.add(new SetCardInfo("Vision Charm", 49, Rarity.COMMON, mage.cards.v.VisionCharm.class)); + cards.add(new SetCardInfo("Wake of Vultures", 74, Rarity.COMMON, mage.cards.w.WakeOfVultures.class)); + cards.add(new SetCardInfo("Wand of Denial", 159, Rarity.RARE, mage.cards.w.WandOfDenial.class)); + cards.add(new SetCardInfo("Warrior's Honor", 24, Rarity.COMMON, mage.cards.w.WarriorsHonor.class)); + cards.add(new SetCardInfo("Warthog", 124, Rarity.COMMON, mage.cards.w.Warthog.class)); + cards.add(new SetCardInfo("Waterspout Djinn", 50, Rarity.UNCOMMON, mage.cards.w.WaterspoutDjinn.class)); + cards.add(new SetCardInfo("Wicked Reward", 75, Rarity.COMMON, mage.cards.w.WickedReward.class)); + cards.add(new SetCardInfo("Wind Shear", 125, Rarity.UNCOMMON, mage.cards.w.WindShear.class)); + cards.add(new SetCardInfo("Zhalfirin Crusader", 25, Rarity.RARE, mage.cards.z.ZhalfirinCrusader.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/WarOfTheSpark.java b/Mage.Sets/src/mage/sets/WarOfTheSpark.java new file mode 100644 index 0000000000..c4ec025a00 --- /dev/null +++ b/Mage.Sets/src/mage/sets/WarOfTheSpark.java @@ -0,0 +1,303 @@ +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +public final class WarOfTheSpark extends ExpansionSet { + + private static final WarOfTheSpark instance = new WarOfTheSpark(); + + public static WarOfTheSpark getInstance() { + return instance; + } + + private WarOfTheSpark() { + super("War of the Spark", "WAR", ExpansionSet.buildDate(2019, 5, 3), SetType.EXPANSION); + this.blockName = "Guilds of Ravnica"; + this.hasBoosters = true; + this.numBoosterLands = 1; + this.numBoosterCommon = 10; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 8; + this.needsPlaneswalker = true; + this.maxCardNumberInBooster = 264; + + cards.add(new SetCardInfo("Ahn-Crop Invader", 113, Rarity.COMMON, mage.cards.a.AhnCropInvader.class)); + cards.add(new SetCardInfo("Aid the Fallen", 76, Rarity.COMMON, mage.cards.a.AidTheFallen.class)); + cards.add(new SetCardInfo("Ajani's Pridemate", 4, Rarity.UNCOMMON, mage.cards.a.AjanisPridemate.class)); + cards.add(new SetCardInfo("Ajani, the Greathearted", 184, Rarity.RARE, mage.cards.a.AjaniTheGreathearted.class)); + cards.add(new SetCardInfo("Angrath's Rampage", 185, Rarity.UNCOMMON, mage.cards.a.AngrathsRampage.class)); + cards.add(new SetCardInfo("Angrath, Captain of Chaos", 227, Rarity.UNCOMMON, mage.cards.a.AngrathCaptainOfChaos.class)); + cards.add(new SetCardInfo("Arboreal Grazer", 149, Rarity.COMMON, mage.cards.a.ArborealGrazer.class)); + cards.add(new SetCardInfo("Arlinn's Wolf", 151, Rarity.COMMON, mage.cards.a.ArlinnsWolf.class)); + cards.add(new SetCardInfo("Arlinn, Voice of the Pack", 150, Rarity.UNCOMMON, mage.cards.a.ArlinnVoiceOfThePack.class)); + cards.add(new SetCardInfo("Ashiok's Skulker", 40, Rarity.COMMON, mage.cards.a.AshioksSkulker.class)); + cards.add(new SetCardInfo("Ashiok, Dream Render", 228, Rarity.UNCOMMON, mage.cards.a.AshiokDreamRender.class)); + cards.add(new SetCardInfo("Augur of Bolas", 41, Rarity.UNCOMMON, mage.cards.a.AugurOfBolas.class)); + cards.add(new SetCardInfo("Aven Eternal", 42, Rarity.COMMON, mage.cards.a.AvenEternal.class)); + cards.add(new SetCardInfo("Awakening of Vitu-Ghazi", 152, Rarity.RARE, mage.cards.a.AwakeningOfVituGhazi.class)); + cards.add(new SetCardInfo("Band Together", 153, Rarity.COMMON, mage.cards.b.BandTogether.class)); + cards.add(new SetCardInfo("Banehound", 77, Rarity.COMMON, mage.cards.b.Banehound.class)); + cards.add(new SetCardInfo("Battlefield Promotion", 5, Rarity.COMMON, mage.cards.b.BattlefieldPromotion.class)); + cards.add(new SetCardInfo("Bioessence Hydra", 186, Rarity.RARE, mage.cards.b.BioessenceHydra.class)); + cards.add(new SetCardInfo("Blast Zone", 244, Rarity.RARE, mage.cards.b.BlastZone.class)); + cards.add(new SetCardInfo("Bleeding Edge", 78, Rarity.UNCOMMON, mage.cards.b.BleedingEdge.class)); + cards.add(new SetCardInfo("Blindblast", 114, Rarity.COMMON, mage.cards.b.Blindblast.class)); + cards.add(new SetCardInfo("Bloom Hulk", 154, Rarity.COMMON, mage.cards.b.BloomHulk.class)); + cards.add(new SetCardInfo("Bolas's Citadel", 79, Rarity.RARE, mage.cards.b.BolassCitadel.class)); + cards.add(new SetCardInfo("Bolt Bend", 115, Rarity.UNCOMMON, mage.cards.b.BoltBend.class)); + cards.add(new SetCardInfo("Bond of Discipline", 6, Rarity.UNCOMMON, mage.cards.b.BondOfDiscipline.class)); + cards.add(new SetCardInfo("Bond of Flourishing", 155, Rarity.UNCOMMON, mage.cards.b.BondOfFlourishing.class)); + cards.add(new SetCardInfo("Bond of Insight", 43, Rarity.UNCOMMON, mage.cards.b.BondOfInsight.class)); + cards.add(new SetCardInfo("Bond of Passion", 116, Rarity.UNCOMMON, mage.cards.b.BondOfPassion.class)); + cards.add(new SetCardInfo("Bond of Revival", 80, Rarity.UNCOMMON, mage.cards.b.BondOfRevival.class)); + cards.add(new SetCardInfo("Bulwark Giant", 7, Rarity.COMMON, mage.cards.b.BulwarkGiant.class)); + cards.add(new SetCardInfo("Burning Prophet", 117, Rarity.COMMON, mage.cards.b.BurningProphet.class)); + cards.add(new SetCardInfo("Callous Dismissal", 44, Rarity.COMMON, mage.cards.c.CallousDismissal.class)); + cards.add(new SetCardInfo("Casualties of War", 187, Rarity.RARE, mage.cards.c.CasualtiesOfWar.class)); + cards.add(new SetCardInfo("Centaur Nurturer", 156, Rarity.COMMON, mage.cards.c.CentaurNurturer.class)); + cards.add(new SetCardInfo("Chainwhip Cyclops", 118, Rarity.COMMON, mage.cards.c.ChainwhipCyclops.class)); + cards.add(new SetCardInfo("Challenger Troll", 157, Rarity.UNCOMMON, mage.cards.c.ChallengerTroll.class)); + cards.add(new SetCardInfo("Chandra's Pyrohelix", 120, Rarity.COMMON, mage.cards.c.ChandrasPyrohelix.class)); + cards.add(new SetCardInfo("Chandra's Triumph", 121, Rarity.UNCOMMON, mage.cards.c.ChandrasTriumph.class)); + cards.add(new SetCardInfo("Chandra, Fire Artisan", 119, Rarity.RARE, mage.cards.c.ChandraFireArtisan.class)); + cards.add(new SetCardInfo("Charity Extractor", 81, Rarity.COMMON, mage.cards.c.CharityExtractor.class)); + cards.add(new SetCardInfo("Charmed Stray", 8, Rarity.COMMON, mage.cards.c.CharmedStray.class)); + cards.add(new SetCardInfo("Command the Dreadhorde", 82, Rarity.RARE, mage.cards.c.CommandTheDreadhorde.class)); + cards.add(new SetCardInfo("Commence the Endgame", 45, Rarity.RARE, mage.cards.c.CommenceTheEndgame.class)); + cards.add(new SetCardInfo("Contentious Plan", 46, Rarity.COMMON, mage.cards.c.ContentiousPlan.class)); + cards.add(new SetCardInfo("Courage in Crisis", 158, Rarity.COMMON, mage.cards.c.CourageInCrisis.class)); + cards.add(new SetCardInfo("Cruel Celebrant", 188, Rarity.UNCOMMON, mage.cards.c.CruelCelebrant.class)); + cards.add(new SetCardInfo("Crush Dissent", 47, Rarity.COMMON, mage.cards.c.CrushDissent.class)); + cards.add(new SetCardInfo("Cyclops Electromancer", 122, Rarity.UNCOMMON, mage.cards.c.CyclopsElectromancer.class)); + cards.add(new SetCardInfo("Davriel's Shadowfugue", 84, Rarity.COMMON, mage.cards.d.DavrielsShadowfugue.class)); + cards.add(new SetCardInfo("Davriel, Rogue Shadowmage", 83, Rarity.UNCOMMON, mage.cards.d.DavrielRogueShadowmage.class)); + cards.add(new SetCardInfo("Deathsprout", 189, Rarity.UNCOMMON, mage.cards.d.Deathsprout.class)); + cards.add(new SetCardInfo("Defiant Strike", 9, Rarity.COMMON, mage.cards.d.DefiantStrike.class)); + cards.add(new SetCardInfo("Deliver Unto Evil", 85, Rarity.RARE, mage.cards.d.DeliverUntoEvil.class)); + cards.add(new SetCardInfo("Demolish", 123, Rarity.COMMON, mage.cards.d.Demolish.class)); + cards.add(new SetCardInfo("Despark", 190, Rarity.UNCOMMON, mage.cards.d.Despark.class)); + cards.add(new SetCardInfo("Desperate Lunge", 266, Rarity.COMMON, mage.cards.d.DesperateLunge.class)); + cards.add(new SetCardInfo("Devouring Hellion", 124, Rarity.UNCOMMON, mage.cards.d.DevouringHellion.class)); + cards.add(new SetCardInfo("Divine Arrow", 10, Rarity.COMMON, mage.cards.d.DivineArrow.class)); + cards.add(new SetCardInfo("Domri's Ambush", 192, Rarity.UNCOMMON, mage.cards.d.DomrisAmbush.class)); + cards.add(new SetCardInfo("Domri, Anarch of Bolas", 191, Rarity.RARE, mage.cards.d.DomriAnarchOfBolas.class)); + cards.add(new SetCardInfo("Dovin's Veto", 193, Rarity.UNCOMMON, mage.cards.d.DovinsVeto.class)); + cards.add(new SetCardInfo("Dovin, Hand of Control", 229, Rarity.UNCOMMON, mage.cards.d.DovinHandOfControl.class)); + cards.add(new SetCardInfo("Dreadhorde Arcanist", 125, Rarity.RARE, mage.cards.d.DreadhordeArcanist.class)); + cards.add(new SetCardInfo("Dreadhorde Butcher", 194, Rarity.RARE, mage.cards.d.DreadhordeButcher.class)); + cards.add(new SetCardInfo("Dreadhorde Invasion", 86, Rarity.RARE, mage.cards.d.DreadhordeInvasion.class)); + cards.add(new SetCardInfo("Dreadhorde Twins", 126, Rarity.UNCOMMON, mage.cards.d.DreadhordeTwins.class)); + cards.add(new SetCardInfo("Dreadmalkin", 87, Rarity.UNCOMMON, mage.cards.d.Dreadmalkin.class)); + cards.add(new SetCardInfo("Duskmantle Operative", 88, Rarity.COMMON, mage.cards.d.DuskmantleOperative.class)); + cards.add(new SetCardInfo("Elite Guardmage", 195, Rarity.UNCOMMON, mage.cards.e.EliteGuardmage.class)); + cards.add(new SetCardInfo("Emergence Zone", 245, Rarity.UNCOMMON, mage.cards.e.EmergenceZone.class)); + cards.add(new SetCardInfo("Enforcer Griffin", 11, Rarity.COMMON, mage.cards.e.EnforcerGriffin.class)); + cards.add(new SetCardInfo("Enter the God-Eternals", 196, Rarity.RARE, mage.cards.e.EnterTheGodEternals.class)); + cards.add(new SetCardInfo("Erratic Visionary", 48, Rarity.COMMON, mage.cards.e.ErraticVisionary.class)); + cards.add(new SetCardInfo("Eternal Skylord", 49, Rarity.UNCOMMON, mage.cards.e.EternalSkylord.class)); + cards.add(new SetCardInfo("Eternal Taskmaster", 90, Rarity.UNCOMMON, mage.cards.e.EternalTaskmaster.class)); + cards.add(new SetCardInfo("Evolution Sage", 159, Rarity.UNCOMMON, mage.cards.e.EvolutionSage.class)); + cards.add(new SetCardInfo("Fblthp, the Lost", 50, Rarity.RARE, mage.cards.f.FblthpTheLost.class)); + cards.add(new SetCardInfo("Feather, the Redeemed", 197, Rarity.RARE, mage.cards.f.FeatherTheRedeemed.class)); + cards.add(new SetCardInfo("Finale of Devastation", 160, Rarity.MYTHIC, mage.cards.f.FinaleOfDevastation.class)); + cards.add(new SetCardInfo("Finale of Eternity", 91, Rarity.MYTHIC, mage.cards.f.FinaleOfEternity.class)); + cards.add(new SetCardInfo("Finale of Glory", 12, Rarity.MYTHIC, mage.cards.f.FinaleOfGlory.class)); + cards.add(new SetCardInfo("Finale of Promise", 127, Rarity.MYTHIC, mage.cards.f.FinaleOfPromise.class)); + cards.add(new SetCardInfo("Finale of Revelation", 51, Rarity.MYTHIC, mage.cards.f.FinaleOfRevelation.class)); + cards.add(new SetCardInfo("Firemind Vessel", 237, Rarity.UNCOMMON, mage.cards.f.FiremindVessel.class)); + cards.add(new SetCardInfo("Flux Channeler", 52, Rarity.UNCOMMON, mage.cards.f.FluxChanneler.class)); + cards.add(new SetCardInfo("Forced Landing", 161, Rarity.COMMON, mage.cards.f.ForcedLanding.class)); + cards.add(new SetCardInfo("Forest", 262, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 263, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Forest", 264, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Gateway Plaza", 246, Rarity.COMMON, mage.cards.g.GatewayPlaza.class)); + cards.add(new SetCardInfo("Giant Growth", 162, Rarity.COMMON, mage.cards.g.GiantGrowth.class)); + cards.add(new SetCardInfo("Gideon Blackblade", 13, Rarity.MYTHIC, mage.cards.g.GideonBlackblade.class)); + cards.add(new SetCardInfo("Gideon's Battle Cry", 267, Rarity.RARE, mage.cards.g.GideonsBattleCry.class)); + cards.add(new SetCardInfo("Gideon's Company", 268, Rarity.UNCOMMON, mage.cards.g.GideonsCompany.class)); + cards.add(new SetCardInfo("Gideon's Sacrifice", 14, Rarity.COMMON, mage.cards.g.GideonsSacrifice.class)); + cards.add(new SetCardInfo("Gideon's Triumph", 15, Rarity.UNCOMMON, mage.cards.g.GideonsTriumph.class)); + cards.add(new SetCardInfo("Gideon, the Oathsworn", 265, Rarity.MYTHIC, mage.cards.g.GideonTheOathsworn.class)); + cards.add(new SetCardInfo("Gleaming Overseer", 198, Rarity.UNCOMMON, mage.cards.g.GleamingOverseer.class)); + cards.add(new SetCardInfo("Goblin Assailant", 128, Rarity.COMMON, mage.cards.g.GoblinAssailant.class)); + cards.add(new SetCardInfo("Goblin Assault Team", 129, Rarity.COMMON, mage.cards.g.GoblinAssaultTeam.class)); + cards.add(new SetCardInfo("God-Eternal Bontu", 92, Rarity.MYTHIC, mage.cards.g.GodEternalBontu.class)); + cards.add(new SetCardInfo("God-Eternal Kefnet", 53, Rarity.MYTHIC, mage.cards.g.GodEternalKefnet.class)); + cards.add(new SetCardInfo("God-Eternal Oketra", 16, Rarity.MYTHIC, mage.cards.g.GodEternalOketra.class)); + cards.add(new SetCardInfo("God-Eternal Rhonas", 163, Rarity.MYTHIC, mage.cards.g.GodEternalRhonas.class)); + cards.add(new SetCardInfo("God-Pharaoh's Statue", 238, Rarity.UNCOMMON, mage.cards.g.GodPharaohsStatue.class)); + cards.add(new SetCardInfo("Grateful Apparition", 17, Rarity.UNCOMMON, mage.cards.g.GratefulApparition.class)); + cards.add(new SetCardInfo("Grim Initiate", 130, Rarity.COMMON, mage.cards.g.GrimInitiate.class)); + cards.add(new SetCardInfo("Guild Globe", 239, Rarity.COMMON, mage.cards.g.GuildGlobe.class)); + cards.add(new SetCardInfo("Guildpact Informant", 271, Rarity.COMMON, mage.cards.g.GuildpactInformant.class)); + cards.add(new SetCardInfo("Heartfire", 131, Rarity.COMMON, mage.cards.h.Heartfire.class)); + cards.add(new SetCardInfo("Heartwarming Redemption", 199, Rarity.UNCOMMON, mage.cards.h.HeartwarmingRedemption.class)); + cards.add(new SetCardInfo("Herald of the Dreadhorde", 93, Rarity.COMMON, mage.cards.h.HeraldOfTheDreadhorde.class)); + cards.add(new SetCardInfo("Honor the God-Pharaoh", 132, Rarity.COMMON, mage.cards.h.HonorTheGodPharaoh.class)); + cards.add(new SetCardInfo("Huatli's Raptor", 200, Rarity.UNCOMMON, mage.cards.h.HuatlisRaptor.class)); + cards.add(new SetCardInfo("Huatli, the Sun's Heart", 230, Rarity.UNCOMMON, mage.cards.h.HuatliTheSunsHeart.class)); + cards.add(new SetCardInfo("Ignite the Beacon", 18, Rarity.RARE, mage.cards.i.IgniteTheBeacon.class)); + cards.add(new SetCardInfo("Ilharg, the Raze-Boar", 133, Rarity.MYTHIC, mage.cards.i.IlhargTheRazeBoar.class)); + cards.add(new SetCardInfo("Interplanar Beacon", 247, Rarity.UNCOMMON, mage.cards.i.InterplanarBeacon.class)); + cards.add(new SetCardInfo("Invade the City", 201, Rarity.UNCOMMON, mage.cards.i.InvadeTheCity.class)); + cards.add(new SetCardInfo("Invading Manticore", 134, Rarity.COMMON, mage.cards.i.InvadingManticore.class)); + cards.add(new SetCardInfo("Iron Bully", 240, Rarity.COMMON, mage.cards.i.IronBully.class)); + cards.add(new SetCardInfo("Ironclad Krovod", 19, Rarity.COMMON, mage.cards.i.IroncladKrovod.class)); + cards.add(new SetCardInfo("Island", 253, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 254, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Island", 255, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Jace's Projection", 272, Rarity.UNCOMMON, mage.cards.j.JacesProjection.class)); + cards.add(new SetCardInfo("Jace's Ruse", 273, Rarity.RARE, mage.cards.j.JacesRuse.class)); + cards.add(new SetCardInfo("Jace's Triumph", 55, Rarity.UNCOMMON, mage.cards.j.JacesTriumph.class)); + cards.add(new SetCardInfo("Jace, Arcane Strategist", 270, Rarity.MYTHIC, mage.cards.j.JaceArcaneStrategist.class)); + cards.add(new SetCardInfo("Jace, Wielder of Mysteries", 54, Rarity.RARE, mage.cards.j.JaceWielderOfMysteries.class)); + cards.add(new SetCardInfo("Jaya's Greeting", 136, Rarity.COMMON, mage.cards.j.JayasGreeting.class)); + cards.add(new SetCardInfo("Jaya, Venerated Firemage", 135, Rarity.UNCOMMON, mage.cards.j.JayaVeneratedFiremage.class)); + cards.add(new SetCardInfo("Jiang Yanggu, Wildcrafter", 164, Rarity.UNCOMMON, mage.cards.j.JiangYangguWildcrafter.class)); + cards.add(new SetCardInfo("Karn's Bastion", 248, Rarity.RARE, mage.cards.k.KarnsBastion.class)); + cards.add(new SetCardInfo("Karn, the Great Creator", 1, Rarity.RARE, mage.cards.k.KarnTheGreatCreator.class)); + cards.add(new SetCardInfo("Kasmina's Transmutation", 57, Rarity.COMMON, mage.cards.k.KasminasTransmutation.class)); + cards.add(new SetCardInfo("Kasmina, Enigmatic Mentor", 56, Rarity.UNCOMMON, mage.cards.k.KasminaEnigmaticMentor.class)); + cards.add(new SetCardInfo("Kaya's Ghostform", 94, Rarity.COMMON, mage.cards.k.KayasGhostform.class)); + cards.add(new SetCardInfo("Kaya, Bane of the Dead", 231, Rarity.UNCOMMON, mage.cards.k.KayaBaneOfTheDead.class)); + cards.add(new SetCardInfo("Kiora's Dambreaker", 58, Rarity.COMMON, mage.cards.k.KiorasDambreaker.class)); + cards.add(new SetCardInfo("Kiora, Behemoth Beckoner", 232, Rarity.UNCOMMON, mage.cards.k.KioraBehemothBeckoner.class)); + cards.add(new SetCardInfo("Kraul Stinger", 165, Rarity.COMMON, mage.cards.k.KraulStinger.class)); + cards.add(new SetCardInfo("Krenko, Tin Street Kingpin", 137, Rarity.RARE, mage.cards.k.KrenkoTinStreetKingpin.class)); + cards.add(new SetCardInfo("Kronch Wrangler", 166, Rarity.COMMON, mage.cards.k.KronchWrangler.class)); + cards.add(new SetCardInfo("Law-Rune Enforcer", 20, Rarity.COMMON, mage.cards.l.LawRuneEnforcer.class)); + cards.add(new SetCardInfo("Lazotep Behemoth", 95, Rarity.COMMON, mage.cards.l.LazotepBehemoth.class)); + cards.add(new SetCardInfo("Lazotep Plating", 59, Rarity.UNCOMMON, mage.cards.l.LazotepPlating.class)); + cards.add(new SetCardInfo("Lazotep Reaver", 96, Rarity.COMMON, mage.cards.l.LazotepReaver.class)); + cards.add(new SetCardInfo("Leyline Prowler", 202, Rarity.UNCOMMON, mage.cards.l.LeylineProwler.class)); + cards.add(new SetCardInfo("Liliana's Triumph", 98, Rarity.UNCOMMON, mage.cards.l.LilianasTriumph.class)); + cards.add(new SetCardInfo("Liliana, Dreadhorde General", 97, Rarity.MYTHIC, mage.cards.l.LilianaDreadhordeGeneral.class)); + cards.add(new SetCardInfo("Living Twister", 203, Rarity.RARE, mage.cards.l.LivingTwister.class)); + cards.add(new SetCardInfo("Loxodon Sergeant", 21, Rarity.COMMON, mage.cards.l.LoxodonSergeant.class)); + cards.add(new SetCardInfo("Makeshift Battalion", 22, Rarity.COMMON, mage.cards.m.MakeshiftBattalion.class)); + cards.add(new SetCardInfo("Mana Geode", 241, Rarity.COMMON, mage.cards.m.ManaGeode.class)); + cards.add(new SetCardInfo("Martyr for the Cause", 23, Rarity.COMMON, mage.cards.m.MartyrForTheCause.class)); + cards.add(new SetCardInfo("Massacre Girl", 99, Rarity.RARE, mage.cards.m.MassacreGirl.class)); + cards.add(new SetCardInfo("Mayhem Devil", 204, Rarity.UNCOMMON, mage.cards.m.MayhemDevil.class)); + cards.add(new SetCardInfo("Merfolk Skydiver", 205, Rarity.UNCOMMON, mage.cards.m.MerfolkSkydiver.class)); + cards.add(new SetCardInfo("Mizzium Tank", 138, Rarity.RARE, mage.cards.m.MizziumTank.class)); + cards.add(new SetCardInfo("Mobilized District", 249, Rarity.RARE, mage.cards.m.MobilizedDistrict.class)); + cards.add(new SetCardInfo("Mountain", 259, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 260, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mountain", 261, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Mowu, Loyal Companion", 167, Rarity.UNCOMMON, mage.cards.m.MowuLoyalCompanion.class)); + cards.add(new SetCardInfo("Naga Eternal", 60, Rarity.COMMON, mage.cards.n.NagaEternal.class)); + cards.add(new SetCardInfo("Nahiri's Stoneblades", 139, Rarity.COMMON, mage.cards.n.NahirisStoneblades.class)); + cards.add(new SetCardInfo("Nahiri, Storm of Stone", 233, Rarity.UNCOMMON, mage.cards.n.NahiriStormOfStone.class)); + cards.add(new SetCardInfo("Narset's Reversal", 62, Rarity.RARE, mage.cards.n.NarsetsReversal.class)); + cards.add(new SetCardInfo("Narset, Parter of Veils", 61, Rarity.UNCOMMON, mage.cards.n.NarsetParterOfVeils.class)); + cards.add(new SetCardInfo("Neheb, Dreadhorde Champion", 140, Rarity.RARE, mage.cards.n.NehebDreadhordeChampion.class)); + cards.add(new SetCardInfo("Neoform", 206, Rarity.UNCOMMON, mage.cards.n.Neoform.class)); + cards.add(new SetCardInfo("New Horizons", 168, Rarity.COMMON, mage.cards.n.NewHorizons.class)); + cards.add(new SetCardInfo("Nicol Bolas, Dragon-God", 207, Rarity.MYTHIC, mage.cards.n.NicolBolasDragonGod.class)); + cards.add(new SetCardInfo("Nissa's Triumph", 170, Rarity.UNCOMMON, mage.cards.n.NissasTriumph.class)); + cards.add(new SetCardInfo("Nissa, Who Shakes the World", 169, Rarity.RARE, mage.cards.n.NissaWhoShakesTheWorld.class)); + cards.add(new SetCardInfo("Niv-Mizzet Reborn", 208, Rarity.MYTHIC, mage.cards.n.NivMizzetReborn.class)); + cards.add(new SetCardInfo("No Escape", 63, Rarity.COMMON, mage.cards.n.NoEscape.class)); + cards.add(new SetCardInfo("Oath of Kaya", 209, Rarity.RARE, mage.cards.o.OathOfKaya.class)); + cards.add(new SetCardInfo("Ob Nixilis's Cruelty", 101, Rarity.COMMON, mage.cards.o.ObNixilissCruelty.class)); + cards.add(new SetCardInfo("Ob Nixilis, the Hate-Twisted", 100, Rarity.UNCOMMON, mage.cards.o.ObNixilisTheHateTwisted.class)); + cards.add(new SetCardInfo("Orzhov Guildgate", 269, Rarity.COMMON, mage.cards.o.OrzhovGuildgate.class)); + cards.add(new SetCardInfo("Paradise Druid", 171, Rarity.UNCOMMON, mage.cards.p.ParadiseDruid.class)); + cards.add(new SetCardInfo("Parhelion II", 24, Rarity.RARE, mage.cards.p.ParhelionII.class)); + cards.add(new SetCardInfo("Plains", 250, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 251, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Plains", 252, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Planewide Celebration", 172, Rarity.RARE, mage.cards.p.PlanewideCelebration.class)); + cards.add(new SetCardInfo("Pledge of Unity", 210, Rarity.UNCOMMON, mage.cards.p.PledgeOfUnity.class)); + cards.add(new SetCardInfo("Pollenbright Druid", 173, Rarity.COMMON, mage.cards.p.PollenbrightDruid.class)); + cards.add(new SetCardInfo("Pouncing Lynx", 25, Rarity.COMMON, mage.cards.p.PouncingLynx.class)); + cards.add(new SetCardInfo("Price of Betrayal", 102, Rarity.UNCOMMON, mage.cards.p.PriceOfBetrayal.class)); + cards.add(new SetCardInfo("Primordial Wurm", 174, Rarity.COMMON, mage.cards.p.PrimordialWurm.class)); + cards.add(new SetCardInfo("Prismite", 242, Rarity.COMMON, mage.cards.p.Prismite.class)); + cards.add(new SetCardInfo("Prison Realm", 26, Rarity.UNCOMMON, mage.cards.p.PrisonRealm.class)); + cards.add(new SetCardInfo("Raging Kronch", 141, Rarity.COMMON, mage.cards.r.RagingKronch.class)); + cards.add(new SetCardInfo("Ral's Outburst", 212, Rarity.UNCOMMON, mage.cards.r.RalsOutburst.class)); + cards.add(new SetCardInfo("Ral, Storm Conduit", 211, Rarity.RARE, mage.cards.r.RalStormConduit.class)); + cards.add(new SetCardInfo("Rally of Wings", 27, Rarity.UNCOMMON, mage.cards.r.RallyOfWings.class)); + cards.add(new SetCardInfo("Ravnica at War", 28, Rarity.RARE, mage.cards.r.RavnicaAtWar.class)); + cards.add(new SetCardInfo("Relentless Advance", 64, Rarity.COMMON, mage.cards.r.RelentlessAdvance.class)); + cards.add(new SetCardInfo("Rescuer Sphinx", 65, Rarity.UNCOMMON, mage.cards.r.RescuerSphinx.class)); + cards.add(new SetCardInfo("Return to Nature", 175, Rarity.COMMON, mage.cards.r.ReturnToNature.class)); + cards.add(new SetCardInfo("Rising Populace", 29, Rarity.COMMON, mage.cards.r.RisingPopulace.class)); + cards.add(new SetCardInfo("Roalesk, Apex Hybrid", 213, Rarity.MYTHIC, mage.cards.r.RoaleskApexHybrid.class)); + cards.add(new SetCardInfo("Role Reversal", 214, Rarity.RARE, mage.cards.r.RoleReversal.class)); + cards.add(new SetCardInfo("Rubblebelt Rioters", 215, Rarity.UNCOMMON, mage.cards.r.RubblebeltRioters.class)); + cards.add(new SetCardInfo("Saheeli's Silverwing", 243, Rarity.COMMON, mage.cards.s.SaheelisSilverwing.class)); + cards.add(new SetCardInfo("Saheeli, Sublime Artificer", 234, Rarity.UNCOMMON, mage.cards.s.SaheeliSublimeArtificer.class)); + cards.add(new SetCardInfo("Samut's Sprint", 142, Rarity.COMMON, mage.cards.s.SamutsSprint.class)); + cards.add(new SetCardInfo("Samut, Tyrant Smasher", 235, Rarity.UNCOMMON, mage.cards.s.SamutTyrantSmasher.class)); + cards.add(new SetCardInfo("Sarkhan the Masterless", 143, Rarity.RARE, mage.cards.s.SarkhanTheMasterless.class)); + cards.add(new SetCardInfo("Sarkhan's Catharsis", 144, Rarity.COMMON, mage.cards.s.SarkhansCatharsis.class)); + cards.add(new SetCardInfo("Shriekdiver", 103, Rarity.COMMON, mage.cards.s.Shriekdiver.class)); + cards.add(new SetCardInfo("Silent Submersible", 66, Rarity.RARE, mage.cards.s.SilentSubmersible.class)); + cards.add(new SetCardInfo("Simic Guildgate", 274, Rarity.COMMON, mage.cards.s.SimicGuildgate.class)); + cards.add(new SetCardInfo("Single Combat", 30, Rarity.RARE, mage.cards.s.SingleCombat.class)); + cards.add(new SetCardInfo("Sky Theater Strix", 67, Rarity.COMMON, mage.cards.s.SkyTheaterStrix.class)); + cards.add(new SetCardInfo("Snarespinner", 176, Rarity.COMMON, mage.cards.s.Snarespinner.class)); + cards.add(new SetCardInfo("Solar Blaze", 216, Rarity.RARE, mage.cards.s.SolarBlaze.class)); + cards.add(new SetCardInfo("Sorin's Thirst", 104, Rarity.COMMON, mage.cards.s.SorinsThirst.class)); + cards.add(new SetCardInfo("Sorin, Vengeful Bloodlord", 217, Rarity.RARE, mage.cards.s.SorinVengefulBloodlord.class)); + cards.add(new SetCardInfo("Soul Diviner", 218, Rarity.RARE, mage.cards.s.SoulDiviner.class)); + cards.add(new SetCardInfo("Spark Double", 68, Rarity.RARE, mage.cards.s.SparkDouble.class)); + cards.add(new SetCardInfo("Spark Harvest", 105, Rarity.COMMON, mage.cards.s.SparkHarvest.class)); + cards.add(new SetCardInfo("Spark Reaper", 106, Rarity.COMMON, mage.cards.s.SparkReaper.class)); + cards.add(new SetCardInfo("Spellgorger Weird", 145, Rarity.COMMON, mage.cards.s.SpellgorgerWeird.class)); + cards.add(new SetCardInfo("Spellkeeper Weird", 69, Rarity.COMMON, mage.cards.s.SpellkeeperWeird.class)); + cards.add(new SetCardInfo("Steady Aim", 177, Rarity.COMMON, mage.cards.s.SteadyAim.class)); + cards.add(new SetCardInfo("Stealth Mission", 70, Rarity.COMMON, mage.cards.s.StealthMission.class)); + cards.add(new SetCardInfo("Storm the Citadel", 178, Rarity.UNCOMMON, mage.cards.s.StormTheCitadel.class)); + cards.add(new SetCardInfo("Storrev, Devkarin Lich", 219, Rarity.RARE, mage.cards.s.StorrevDevkarinLich.class)); + cards.add(new SetCardInfo("Sunblade Angel", 31, Rarity.UNCOMMON, mage.cards.s.SunbladeAngel.class)); + cards.add(new SetCardInfo("Swamp", 256, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 257, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Swamp", 258, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Tamiyo's Epiphany", 71, Rarity.COMMON, mage.cards.t.TamiyosEpiphany.class)); + cards.add(new SetCardInfo("Tamiyo, Collector of Tales", 220, Rarity.RARE, mage.cards.t.TamiyoCollectorOfTales.class)); + cards.add(new SetCardInfo("Teferi's Time Twist", 72, Rarity.COMMON, mage.cards.t.TeferisTimeTwist.class)); + cards.add(new SetCardInfo("Teferi, Time Raveler", 221, Rarity.RARE, mage.cards.t.TeferiTimeRaveler.class)); + cards.add(new SetCardInfo("Tenth District Legionnaire", 222, Rarity.UNCOMMON, mage.cards.t.TenthDistrictLegionnaire.class)); + cards.add(new SetCardInfo("Teyo's Lightshield", 33, Rarity.COMMON, mage.cards.t.TeyosLightshield.class)); + cards.add(new SetCardInfo("Teyo, the Shieldmage", 32, Rarity.UNCOMMON, mage.cards.t.TeyoTheShieldmage.class)); + cards.add(new SetCardInfo("Tezzeret, Master of the Bridge", 275, Rarity.MYTHIC, mage.cards.t.TezzeretMasterOfTheBridge.class)); + cards.add(new SetCardInfo("The Elderspell", 89, Rarity.RARE, mage.cards.t.TheElderspell.class)); + cards.add(new SetCardInfo("The Wanderer", 37, Rarity.UNCOMMON, mage.cards.t.TheWanderer.class)); + cards.add(new SetCardInfo("Thunder Drake", 73, Rarity.COMMON, mage.cards.t.ThunderDrake.class)); + cards.add(new SetCardInfo("Thundering Ceratok", 179, Rarity.COMMON, mage.cards.t.ThunderingCeratok.class)); + cards.add(new SetCardInfo("Tibalt's Rager", 147, Rarity.UNCOMMON, mage.cards.t.TibaltsRager.class)); + cards.add(new SetCardInfo("Tibalt, Rakish Instigator", 146, Rarity.UNCOMMON, mage.cards.t.TibaltRakishInstigator.class)); + cards.add(new SetCardInfo("Time Wipe", 223, Rarity.RARE, mage.cards.t.TimeWipe.class)); + cards.add(new SetCardInfo("Tithebearer Giant", 107, Rarity.COMMON, mage.cards.t.TithebearerGiant.class)); + cards.add(new SetCardInfo("Toll of the Invasion", 108, Rarity.COMMON, mage.cards.t.TollOfTheInvasion.class)); + cards.add(new SetCardInfo("Tolsimir, Friend to Wolves", 224, Rarity.RARE, mage.cards.t.TolsimirFriendToWolves.class)); + cards.add(new SetCardInfo("Tomik, Distinguished Advokist", 34, Rarity.RARE, mage.cards.t.TomikDistinguishedAdvokist.class)); + cards.add(new SetCardInfo("Topple the Statue", 35, Rarity.COMMON, mage.cards.t.ToppleTheStatue.class)); + cards.add(new SetCardInfo("Totally Lost", 74, Rarity.COMMON, mage.cards.t.TotallyLost.class)); + cards.add(new SetCardInfo("Trusted Pegasus", 36, Rarity.COMMON, mage.cards.t.TrustedPegasus.class)); + cards.add(new SetCardInfo("Turret Ogre", 148, Rarity.COMMON, mage.cards.t.TurretOgre.class)); + cards.add(new SetCardInfo("Tyrant's Scorn", 225, Rarity.UNCOMMON, mage.cards.t.TyrantsScorn.class)); + cards.add(new SetCardInfo("Ugin's Conjurant", 3, Rarity.UNCOMMON, mage.cards.u.UginsConjurant.class)); + cards.add(new SetCardInfo("Ugin, the Ineffable", 2, Rarity.RARE, mage.cards.u.UginTheIneffable.class)); + cards.add(new SetCardInfo("Unlikely Aid", 109, Rarity.COMMON, mage.cards.u.UnlikelyAid.class)); + cards.add(new SetCardInfo("Vampire Opportunist", 110, Rarity.COMMON, mage.cards.v.VampireOpportunist.class)); + cards.add(new SetCardInfo("Vivien's Arkbow", 181, Rarity.RARE, mage.cards.v.ViviensArkbow.class)); + cards.add(new SetCardInfo("Vivien's Grizzly", 182, Rarity.COMMON, mage.cards.v.ViviensGrizzly.class)); + cards.add(new SetCardInfo("Vivien, Champion of the Wilds", 180, Rarity.RARE, mage.cards.v.VivienChampionOfTheWilds.class)); + cards.add(new SetCardInfo("Vizier of the Scorpion", 111, Rarity.UNCOMMON, mage.cards.v.VizierOfTheScorpion.class)); + cards.add(new SetCardInfo("Vraska's Finisher", 112, Rarity.COMMON, mage.cards.v.VraskasFinisher.class)); + cards.add(new SetCardInfo("Vraska, Swarm's Eminence", 236, Rarity.UNCOMMON, mage.cards.v.VraskaSwarmsEminence.class)); + cards.add(new SetCardInfo("Wall of Runes", 75, Rarity.COMMON, mage.cards.w.WallOfRunes.class)); + cards.add(new SetCardInfo("Wanderer's Strike", 38, Rarity.COMMON, mage.cards.w.WanderersStrike.class)); + cards.add(new SetCardInfo("War Screecher", 39, Rarity.COMMON, mage.cards.w.WarScreecher.class)); + cards.add(new SetCardInfo("Wardscale Crocodile", 183, Rarity.COMMON, mage.cards.w.WardscaleCrocodile.class)); + cards.add(new SetCardInfo("Widespread Brutality", 226, Rarity.RARE, mage.cards.w.WidespreadBrutality.class)); + } +} diff --git a/Mage.Sets/src/mage/sets/Weatherlight.java b/Mage.Sets/src/mage/sets/Weatherlight.java index 01abb9f2b1..23770049ec 100644 --- a/Mage.Sets/src/mage/sets/Weatherlight.java +++ b/Mage.Sets/src/mage/sets/Weatherlight.java @@ -1,184 +1,188 @@ -package mage.sets; - -import mage.cards.ExpansionSet; -import mage.constants.Rarity; -import mage.constants.SetType; - -/** - * - * @author noxx - */ -public final class Weatherlight extends ExpansionSet { - - private static final Weatherlight instance = new Weatherlight(); - - public static Weatherlight getInstance() { - return instance; - } - - private Weatherlight() { - super("Weatherlight", "WTH", ExpansionSet.buildDate(1997, 5, 31), SetType.EXPANSION); - this.blockName = "Mirage"; - this.parentSet = Mirage.getInstance(); - this.hasBasicLands = false; - this.hasBoosters = true; - this.numBoosterLands = 0; - this.numBoosterCommon = 11; - this.numBoosterUncommon = 3; - this.numBoosterRare = 1; - this.ratioBoosterMythic = 0; - cards.add(new SetCardInfo("Abduction", 30, Rarity.UNCOMMON, mage.cards.a.Abduction.class)); - cards.add(new SetCardInfo("Abeyance", 1, Rarity.RARE, mage.cards.a.Abeyance.class)); - cards.add(new SetCardInfo("Abjure", 31, Rarity.COMMON, mage.cards.a.Abjure.class)); - cards.add(new SetCardInfo("Aboroth", 117, Rarity.RARE, mage.cards.a.Aboroth.class)); - cards.add(new SetCardInfo("Abyssal Gatekeeper", 59, Rarity.COMMON, mage.cards.a.AbyssalGatekeeper.class)); - cards.add(new SetCardInfo("Aether Flash", 88, Rarity.UNCOMMON, mage.cards.a.AetherFlash.class)); - cards.add(new SetCardInfo("Agonizing Memories", 60, Rarity.UNCOMMON, mage.cards.a.AgonizingMemories.class)); - cards.add(new SetCardInfo("Alabaster Dragon", 2, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); - cards.add(new SetCardInfo("Alms", 3, Rarity.COMMON, mage.cards.a.Alms.class)); - cards.add(new SetCardInfo("Ancestral Knowledge", 32, Rarity.RARE, mage.cards.a.AncestralKnowledge.class)); - cards.add(new SetCardInfo("Angelic Renewal", 4, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); - cards.add(new SetCardInfo("Arctic Wolves", 118, Rarity.UNCOMMON, mage.cards.a.ArcticWolves.class)); - cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.COMMON, mage.cards.a.ArdentMilitia.class)); - cards.add(new SetCardInfo("Argivian Find", 6, Rarity.UNCOMMON, mage.cards.a.ArgivianFind.class)); - cards.add(new SetCardInfo("Argivian Restoration", 34, Rarity.UNCOMMON, mage.cards.a.ArgivianRestoration.class)); - cards.add(new SetCardInfo("Aura of Silence", 7, Rarity.UNCOMMON, mage.cards.a.AuraOfSilence.class)); - cards.add(new SetCardInfo("Avizoa", 35, Rarity.RARE, mage.cards.a.Avizoa.class)); - cards.add(new SetCardInfo("Barishi", 119, Rarity.UNCOMMON, mage.cards.b.Barishi.class)); - cards.add(new SetCardInfo("Barrow Ghoul", 61, Rarity.COMMON, mage.cards.b.BarrowGhoul.class)); - cards.add(new SetCardInfo("Benalish Infantry", 8, Rarity.COMMON, mage.cards.b.BenalishInfantry.class)); - cards.add(new SetCardInfo("Benalish Knight", 9, Rarity.COMMON, mage.cards.b.BenalishKnight.class)); - cards.add(new SetCardInfo("Benalish Missionary", 10, Rarity.COMMON, mage.cards.b.BenalishMissionary.class)); - cards.add(new SetCardInfo("Bloodrock Cyclops", 90, Rarity.COMMON, mage.cards.b.BloodrockCyclops.class)); - cards.add(new SetCardInfo("Blossoming Wreath", 120, Rarity.COMMON, mage.cards.b.BlossomingWreath.class)); - cards.add(new SetCardInfo("Bogardan Firefiend", 91, Rarity.COMMON, mage.cards.b.BogardanFirefiend.class)); - cards.add(new SetCardInfo("Boiling Blood", 92, Rarity.COMMON, mage.cards.b.BoilingBlood.class)); - cards.add(new SetCardInfo("Bone Dancer", 62, Rarity.RARE, mage.cards.b.BoneDancer.class)); - cards.add(new SetCardInfo("Briar Shield", 121, Rarity.COMMON, mage.cards.b.BriarShield.class)); - cards.add(new SetCardInfo("Bubble Matrix", 146, Rarity.RARE, mage.cards.b.BubbleMatrix.class)); - cards.add(new SetCardInfo("Buried Alive", 63, Rarity.UNCOMMON, mage.cards.b.BuriedAlive.class)); - cards.add(new SetCardInfo("Call of the Wild", 122, Rarity.RARE, mage.cards.c.CallOfTheWild.class)); - cards.add(new SetCardInfo("Chimeric Sphere", 148, Rarity.UNCOMMON, mage.cards.c.ChimericSphere.class)); - cards.add(new SetCardInfo("Cinder Giant", 93, Rarity.UNCOMMON, mage.cards.c.CinderGiant.class)); - cards.add(new SetCardInfo("Cinder Wall", 94, Rarity.COMMON, mage.cards.c.CinderWall.class)); - cards.add(new SetCardInfo("Cloud Djinn", 36, Rarity.UNCOMMON, mage.cards.c.CloudDjinn.class)); - cards.add(new SetCardInfo("Cone of Flame", 95, Rarity.UNCOMMON, mage.cards.c.ConeOfFlame.class)); - cards.add(new SetCardInfo("Debt of Loyalty", 11, Rarity.RARE, mage.cards.d.DebtOfLoyalty.class)); - cards.add(new SetCardInfo("Dense Foliage", 124, Rarity.RARE, mage.cards.d.DenseFoliage.class)); - cards.add(new SetCardInfo("Desperate Gambit", 96, Rarity.UNCOMMON, mage.cards.d.DesperateGambit.class)); - cards.add(new SetCardInfo("Dingus Staff", 149, Rarity.UNCOMMON, mage.cards.d.DingusStaff.class)); - cards.add(new SetCardInfo("Disrupt", 37, Rarity.COMMON, mage.cards.d.Disrupt.class)); - cards.add(new SetCardInfo("Doomsday", 66, Rarity.RARE, mage.cards.d.Doomsday.class)); - cards.add(new SetCardInfo("Downdraft", 125, Rarity.UNCOMMON, mage.cards.d.Downdraft.class)); - cards.add(new SetCardInfo("Duskrider Falcon", 12, Rarity.COMMON, mage.cards.d.DuskriderFalcon.class)); - cards.add(new SetCardInfo("Dwarven Berserker", 97, Rarity.COMMON, mage.cards.d.DwarvenBerserker.class)); - cards.add(new SetCardInfo("Dwarven Thaumaturgist", 98, Rarity.RARE, mage.cards.d.DwarvenThaumaturgist.class)); - cards.add(new SetCardInfo("Empyrial Armor", 13, Rarity.COMMON, mage.cards.e.EmpyrialArmor.class)); - cards.add(new SetCardInfo("Fallow Wurm", 126, Rarity.UNCOMMON, mage.cards.f.FallowWurm.class)); - cards.add(new SetCardInfo("Familiar Ground", 127, Rarity.UNCOMMON, mage.cards.f.FamiliarGround.class)); - cards.add(new SetCardInfo("Fatal Blow", 67, Rarity.COMMON, mage.cards.f.FatalBlow.class)); - cards.add(new SetCardInfo("Fervor", 99, Rarity.RARE, mage.cards.f.Fervor.class)); - cards.add(new SetCardInfo("Festering Evil", 68, Rarity.UNCOMMON, mage.cards.f.FesteringEvil.class)); - cards.add(new SetCardInfo("Fire Whip", 100, Rarity.COMMON, mage.cards.f.FireWhip.class)); - cards.add(new SetCardInfo("Firestorm", 101, Rarity.RARE, mage.cards.f.Firestorm.class)); - cards.add(new SetCardInfo("Fit of Rage", 102, Rarity.COMMON, mage.cards.f.FitOfRage.class)); - cards.add(new SetCardInfo("Fledgling Djinn", 69, Rarity.COMMON, mage.cards.f.FledglingDjinn.class)); - cards.add(new SetCardInfo("Flux", 39, Rarity.COMMON, mage.cards.f.Flux.class)); - cards.add(new SetCardInfo("Fog Elemental", 40, Rarity.COMMON, mage.cards.f.FogElemental.class)); - cards.add(new SetCardInfo("Foriysian Brigade", 14, Rarity.UNCOMMON, mage.cards.f.ForiysianBrigade.class)); - cards.add(new SetCardInfo("Fungus Elemental", 128, Rarity.RARE, mage.cards.f.FungusElemental.class)); - cards.add(new SetCardInfo("Gaea's Blessing", 129, Rarity.UNCOMMON, mage.cards.g.GaeasBlessing.class)); - cards.add(new SetCardInfo("Gallowbraid", 70, Rarity.RARE, mage.cards.g.Gallowbraid.class)); - cards.add(new SetCardInfo("Gemstone Mine", 164, Rarity.UNCOMMON, mage.cards.g.GemstoneMine.class)); - cards.add(new SetCardInfo("Gerrard's Wisdom", 15, Rarity.UNCOMMON, mage.cards.g.GerrardsWisdom.class)); - cards.add(new SetCardInfo("Goblin Bomb", 103, Rarity.RARE, mage.cards.g.GoblinBomb.class)); - cards.add(new SetCardInfo("Goblin Grenadiers", 104, Rarity.UNCOMMON, mage.cards.g.GoblinGrenadiers.class)); - cards.add(new SetCardInfo("Goblin Vandal", 105, Rarity.COMMON, mage.cards.g.GoblinVandal.class)); - cards.add(new SetCardInfo("Guided Strike", 16, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); - cards.add(new SetCardInfo("Harvest Wurm", 130, Rarity.COMMON, mage.cards.h.HarvestWurm.class)); - cards.add(new SetCardInfo("Haunting Misery", 71, Rarity.COMMON, mage.cards.h.HauntingMisery.class)); - cards.add(new SetCardInfo("Heart of Bogardan", 106, Rarity.RARE, mage.cards.h.HeartOfBogardan.class)); - cards.add(new SetCardInfo("Heat Stroke", 107, Rarity.RARE, mage.cards.h.HeatStroke.class)); - cards.add(new SetCardInfo("Heavy Ballista", 17, Rarity.COMMON, mage.cards.h.HeavyBallista.class)); - cards.add(new SetCardInfo("Hidden Horror", 72, Rarity.UNCOMMON, mage.cards.h.HiddenHorror.class)); - cards.add(new SetCardInfo("Hurloon Shaman", 108, Rarity.UNCOMMON, mage.cards.h.HurloonShaman.class)); - cards.add(new SetCardInfo("Infernal Tribute", 73, Rarity.RARE, mage.cards.i.InfernalTribute.class)); - cards.add(new SetCardInfo("Inner Sanctum", 18, Rarity.RARE, mage.cards.i.InnerSanctum.class)); - cards.add(new SetCardInfo("Jabari's Banner", 150, Rarity.UNCOMMON, mage.cards.j.JabarisBanner.class)); - cards.add(new SetCardInfo("Lava Hounds", 109, Rarity.UNCOMMON, mage.cards.l.LavaHounds.class)); - cards.add(new SetCardInfo("Llanowar Behemoth", 132, Rarity.UNCOMMON, mage.cards.l.LlanowarBehemoth.class)); - cards.add(new SetCardInfo("Llanowar Druid", 133, Rarity.COMMON, mage.cards.l.LlanowarDruid.class)); - cards.add(new SetCardInfo("Llanowar Sentinel", 134, Rarity.COMMON, mage.cards.l.LlanowarSentinel.class)); - cards.add(new SetCardInfo("Lotus Vale", 165, Rarity.RARE, mage.cards.l.LotusVale.class)); - cards.add(new SetCardInfo("Mana Chains", 41, Rarity.COMMON, mage.cards.m.ManaChains.class)); - cards.add(new SetCardInfo("Mana Web", 152, Rarity.RARE, mage.cards.m.ManaWeb.class)); - cards.add(new SetCardInfo("Manta Ray", 42, Rarity.COMMON, mage.cards.m.MantaRay.class)); - cards.add(new SetCardInfo("Maraxus of Keld", 111, Rarity.RARE, mage.cards.m.MaraxusOfKeld.class)); - cards.add(new SetCardInfo("Master of Arms", 20, Rarity.UNCOMMON, mage.cards.m.MasterOfArms.class)); - cards.add(new SetCardInfo("Merfolk Traders", 43, Rarity.COMMON, mage.cards.m.MerfolkTraders.class)); - cards.add(new SetCardInfo("Mind Stone", 153, Rarity.COMMON, mage.cards.m.MindStone.class)); - cards.add(new SetCardInfo("Mischievous Poltergeist", 74, Rarity.UNCOMMON, mage.cards.m.MischievousPoltergeist.class)); - cards.add(new SetCardInfo("Mistmoon Griffin", 21, Rarity.UNCOMMON, mage.cards.m.MistmoonGriffin.class)); - cards.add(new SetCardInfo("Morinfen", 75, Rarity.RARE, mage.cards.m.Morinfen.class)); - cards.add(new SetCardInfo("Mwonvuli Ooze", 135, Rarity.RARE, mage.cards.m.MwonvuliOoze.class)); - cards.add(new SetCardInfo("Nature's Kiss", 136, Rarity.COMMON, mage.cards.n.NaturesKiss.class)); - cards.add(new SetCardInfo("Nature's Resurgence", 137, Rarity.RARE, mage.cards.n.NaturesResurgence.class)); - cards.add(new SetCardInfo("Necratog", 76, Rarity.UNCOMMON, mage.cards.n.Necratog.class)); - cards.add(new SetCardInfo("Noble Benefactor", 44, Rarity.UNCOMMON, mage.cards.n.NobleBenefactor.class)); - cards.add(new SetCardInfo("Null Rod", 154, Rarity.RARE, mage.cards.n.NullRod.class)); - cards.add(new SetCardInfo("Odylic Wraith", 77, Rarity.UNCOMMON, mage.cards.o.OdylicWraith.class)); - cards.add(new SetCardInfo("Ophidian", 45, Rarity.COMMON, mage.cards.o.Ophidian.class)); - cards.add(new SetCardInfo("Orcish Settlers", 112, Rarity.UNCOMMON, mage.cards.o.OrcishSettlers.class)); - cards.add(new SetCardInfo("Paradigm Shift", 46, Rarity.RARE, mage.cards.p.ParadigmShift.class)); - cards.add(new SetCardInfo("Peacekeeper", 22, Rarity.RARE, mage.cards.p.Peacekeeper.class)); - cards.add(new SetCardInfo("Pendrell Mists", 47, Rarity.RARE, mage.cards.p.PendrellMists.class)); - cards.add(new SetCardInfo("Phantom Warrior", 48, Rarity.UNCOMMON, mage.cards.p.PhantomWarrior.class)); - cards.add(new SetCardInfo("Phantom Wings", 49, Rarity.COMMON, mage.cards.p.PhantomWings.class)); - cards.add(new SetCardInfo("Phyrexian Furnace", 155, Rarity.UNCOMMON, mage.cards.p.PhyrexianFurnace.class)); - cards.add(new SetCardInfo("Psychic Vortex", 50, Rarity.RARE, mage.cards.p.PsychicVortex.class)); - cards.add(new SetCardInfo("Razortooth Rats", 78, Rarity.COMMON, mage.cards.r.RazortoothRats.class)); - cards.add(new SetCardInfo("Redwood Treefolk", 138, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); - cards.add(new SetCardInfo("Relearn", 51, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); - cards.add(new SetCardInfo("Revered Unicorn", 23, Rarity.UNCOMMON, mage.cards.r.ReveredUnicorn.class)); - cards.add(new SetCardInfo("Roc Hatchling", 113, Rarity.UNCOMMON, mage.cards.r.RocHatchling.class)); - cards.add(new SetCardInfo("Rogue Elephant", 139, Rarity.COMMON, mage.cards.r.RogueElephant.class)); - cards.add(new SetCardInfo("Sage Owl", 52, Rarity.COMMON, mage.cards.s.SageOwl.class)); - cards.add(new SetCardInfo("Scorched Ruins", 166, Rarity.RARE, mage.cards.s.ScorchedRuins.class)); - cards.add(new SetCardInfo("Serenity", 24, Rarity.RARE, mage.cards.s.Serenity.class)); - cards.add(new SetCardInfo("Serra's Blessing", 25, Rarity.UNCOMMON, mage.cards.s.SerrasBlessing.class)); - cards.add(new SetCardInfo("Serrated Biskelion", 156, Rarity.UNCOMMON, mage.cards.s.SerratedBiskelion.class)); - cards.add(new SetCardInfo("Shadow Rider", 79, Rarity.COMMON, mage.cards.s.ShadowRider.class)); - cards.add(new SetCardInfo("Shattered Crypt", 80, Rarity.COMMON, mage.cards.s.ShatteredCrypt.class)); - cards.add(new SetCardInfo("Soul Shepherd", 26, Rarity.COMMON, mage.cards.s.SoulShepherd.class)); - cards.add(new SetCardInfo("Southern Paladin", 27, Rarity.RARE, mage.cards.s.SouthernPaladin.class)); - cards.add(new SetCardInfo("Spinning Darkness", 81, Rarity.COMMON, mage.cards.s.SpinningDarkness.class)); - cards.add(new SetCardInfo("Steel Golem", 157, Rarity.UNCOMMON, mage.cards.s.SteelGolem.class)); - cards.add(new SetCardInfo("Strands of Night", 82, Rarity.UNCOMMON, mage.cards.s.StrandsOfNight.class)); - cards.add(new SetCardInfo("Straw Golem", 158, Rarity.UNCOMMON, mage.cards.s.StrawGolem.class)); - cards.add(new SetCardInfo("Striped Bears", 140, Rarity.COMMON, mage.cards.s.StripedBears.class)); - cards.add(new SetCardInfo("Tariff", 28, Rarity.RARE, mage.cards.t.Tariff.class)); - cards.add(new SetCardInfo("Teferi's Veil", 53, Rarity.UNCOMMON, mage.cards.t.TeferisVeil.class)); - cards.add(new SetCardInfo("Tendrils of Despair", 83, Rarity.COMMON, mage.cards.t.TendrilsOfDespair.class)); - cards.add(new SetCardInfo("Thran Forge", 159, Rarity.UNCOMMON, mage.cards.t.ThranForge.class)); - cards.add(new SetCardInfo("Thunderbolt", 115, Rarity.COMMON, mage.cards.t.Thunderbolt.class)); - cards.add(new SetCardInfo("Thundermare", 116, Rarity.RARE, mage.cards.t.Thundermare.class)); - cards.add(new SetCardInfo("Timid Drake", 54, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); - cards.add(new SetCardInfo("Tolarian Drake", 55, Rarity.COMMON, mage.cards.t.TolarianDrake.class)); - cards.add(new SetCardInfo("Tolarian Entrancer", 56, Rarity.RARE, mage.cards.t.TolarianEntrancer.class)); - cards.add(new SetCardInfo("Tolarian Serpent", 57, Rarity.RARE, mage.cards.t.TolarianSerpent.class)); - cards.add(new SetCardInfo("Touchstone", 161, Rarity.UNCOMMON, mage.cards.t.Touchstone.class)); - cards.add(new SetCardInfo("Tranquil Grove", 142, Rarity.RARE, mage.cards.t.TranquilGrove.class)); - cards.add(new SetCardInfo("Uktabi Efreet", 143, Rarity.COMMON, mage.cards.u.UktabiEfreet.class)); - cards.add(new SetCardInfo("Urborg Justice", 84, Rarity.RARE, mage.cards.u.UrborgJustice.class)); - cards.add(new SetCardInfo("Urborg Stalker", 85, Rarity.RARE, mage.cards.u.UrborgStalker.class)); - cards.add(new SetCardInfo("Veteran Explorer", 144, Rarity.UNCOMMON, mage.cards.v.VeteranExplorer.class)); - cards.add(new SetCardInfo("Vitalize", 145, Rarity.COMMON, mage.cards.v.Vitalize.class)); - cards.add(new SetCardInfo("Vodalian Illusionist", 58, Rarity.UNCOMMON, mage.cards.v.VodalianIllusionist.class)); - cards.add(new SetCardInfo("Volunteer Reserves", 29, Rarity.UNCOMMON, mage.cards.v.VolunteerReserves.class)); - cards.add(new SetCardInfo("Wave of Terror", 86, Rarity.RARE, mage.cards.w.WaveOfTerror.class)); - cards.add(new SetCardInfo("Well of Knowledge", 162, Rarity.RARE, mage.cards.w.WellOfKnowledge.class)); - cards.add(new SetCardInfo("Winding Canyons", 167, Rarity.RARE, mage.cards.w.WindingCanyons.class)); - cards.add(new SetCardInfo("Xanthic Statue", 163, Rarity.RARE, mage.cards.x.XanthicStatue.class)); - cards.add(new SetCardInfo("Zombie Scavengers", 87, Rarity.COMMON, mage.cards.z.ZombieScavengers.class)); - } -} +package mage.sets; + +import mage.cards.ExpansionSet; +import mage.constants.Rarity; +import mage.constants.SetType; + +/** + * + * @author noxx + */ +public final class Weatherlight extends ExpansionSet { + + private static final Weatherlight instance = new Weatherlight(); + + public static Weatherlight getInstance() { + return instance; + } + + private Weatherlight() { + super("Weatherlight", "WTH", ExpansionSet.buildDate(1997, 5, 31), SetType.EXPANSION); + this.blockName = "Mirage"; + this.parentSet = Mirage.getInstance(); + this.hasBasicLands = false; + this.hasBoosters = true; + this.numBoosterLands = 0; + this.numBoosterCommon = 11; + this.numBoosterUncommon = 3; + this.numBoosterRare = 1; + this.ratioBoosterMythic = 0; + cards.add(new SetCardInfo("Abduction", 30, Rarity.UNCOMMON, mage.cards.a.Abduction.class)); + cards.add(new SetCardInfo("Abeyance", 1, Rarity.RARE, mage.cards.a.Abeyance.class)); + cards.add(new SetCardInfo("Abjure", 31, Rarity.COMMON, mage.cards.a.Abjure.class)); + cards.add(new SetCardInfo("Aboroth", 117, Rarity.RARE, mage.cards.a.Aboroth.class)); + cards.add(new SetCardInfo("Abyssal Gatekeeper", 59, Rarity.COMMON, mage.cards.a.AbyssalGatekeeper.class)); + cards.add(new SetCardInfo("Aether Flash", 88, Rarity.UNCOMMON, mage.cards.a.AetherFlash.class)); + cards.add(new SetCardInfo("Agonizing Memories", 60, Rarity.UNCOMMON, mage.cards.a.AgonizingMemories.class)); + cards.add(new SetCardInfo("Alabaster Dragon", 2, Rarity.RARE, mage.cards.a.AlabasterDragon.class)); + cards.add(new SetCardInfo("Alms", 3, Rarity.COMMON, mage.cards.a.Alms.class)); + cards.add(new SetCardInfo("Ancestral Knowledge", 32, Rarity.RARE, mage.cards.a.AncestralKnowledge.class)); + cards.add(new SetCardInfo("Angelic Renewal", 4, Rarity.COMMON, mage.cards.a.AngelicRenewal.class)); + cards.add(new SetCardInfo("Arctic Wolves", 118, Rarity.UNCOMMON, mage.cards.a.ArcticWolves.class)); + cards.add(new SetCardInfo("Ardent Militia", 5, Rarity.COMMON, mage.cards.a.ArdentMilitia.class)); + cards.add(new SetCardInfo("Argivian Find", 6, Rarity.UNCOMMON, mage.cards.a.ArgivianFind.class)); + cards.add(new SetCardInfo("Argivian Restoration", 34, Rarity.UNCOMMON, mage.cards.a.ArgivianRestoration.class)); + cards.add(new SetCardInfo("Aura of Silence", 7, Rarity.UNCOMMON, mage.cards.a.AuraOfSilence.class)); + cards.add(new SetCardInfo("Avizoa", 35, Rarity.RARE, mage.cards.a.Avizoa.class)); + cards.add(new SetCardInfo("Barishi", 119, Rarity.UNCOMMON, mage.cards.b.Barishi.class)); + cards.add(new SetCardInfo("Barrow Ghoul", 61, Rarity.COMMON, mage.cards.b.BarrowGhoul.class)); + cards.add(new SetCardInfo("Benalish Infantry", 8, Rarity.COMMON, mage.cards.b.BenalishInfantry.class)); + cards.add(new SetCardInfo("Benalish Knight", 9, Rarity.COMMON, mage.cards.b.BenalishKnight.class)); + cards.add(new SetCardInfo("Benalish Missionary", 10, Rarity.COMMON, mage.cards.b.BenalishMissionary.class)); + cards.add(new SetCardInfo("Betrothed of Fire", 89, Rarity.COMMON, mage.cards.b.BetrothedOfFire.class)); + cards.add(new SetCardInfo("Bloodrock Cyclops", 90, Rarity.COMMON, mage.cards.b.BloodrockCyclops.class)); + cards.add(new SetCardInfo("Blossoming Wreath", 120, Rarity.COMMON, mage.cards.b.BlossomingWreath.class)); + cards.add(new SetCardInfo("Bogardan Firefiend", 91, Rarity.COMMON, mage.cards.b.BogardanFirefiend.class)); + cards.add(new SetCardInfo("Boiling Blood", 92, Rarity.COMMON, mage.cards.b.BoilingBlood.class)); + cards.add(new SetCardInfo("Bone Dancer", 62, Rarity.RARE, mage.cards.b.BoneDancer.class)); + cards.add(new SetCardInfo("Briar Shield", 121, Rarity.COMMON, mage.cards.b.BriarShield.class)); + cards.add(new SetCardInfo("Bubble Matrix", 146, Rarity.RARE, mage.cards.b.BubbleMatrix.class)); + cards.add(new SetCardInfo("Buried Alive", 63, Rarity.UNCOMMON, mage.cards.b.BuriedAlive.class)); + cards.add(new SetCardInfo("Call of the Wild", 122, Rarity.RARE, mage.cards.c.CallOfTheWild.class)); + cards.add(new SetCardInfo("Chimeric Sphere", 148, Rarity.UNCOMMON, mage.cards.c.ChimericSphere.class)); + cards.add(new SetCardInfo("Cinder Giant", 93, Rarity.UNCOMMON, mage.cards.c.CinderGiant.class)); + cards.add(new SetCardInfo("Cinder Wall", 94, Rarity.COMMON, mage.cards.c.CinderWall.class)); + cards.add(new SetCardInfo("Cloud Djinn", 36, Rarity.UNCOMMON, mage.cards.c.CloudDjinn.class)); + cards.add(new SetCardInfo("Cone of Flame", 95, Rarity.UNCOMMON, mage.cards.c.ConeOfFlame.class)); + cards.add(new SetCardInfo("Debt of Loyalty", 11, Rarity.RARE, mage.cards.d.DebtOfLoyalty.class)); + cards.add(new SetCardInfo("Dense Foliage", 124, Rarity.RARE, mage.cards.d.DenseFoliage.class)); + cards.add(new SetCardInfo("Desperate Gambit", 96, Rarity.UNCOMMON, mage.cards.d.DesperateGambit.class)); + cards.add(new SetCardInfo("Dingus Staff", 149, Rarity.UNCOMMON, mage.cards.d.DingusStaff.class)); + cards.add(new SetCardInfo("Disrupt", 37, Rarity.COMMON, mage.cards.d.Disrupt.class)); + cards.add(new SetCardInfo("Doomsday", 66, Rarity.RARE, mage.cards.d.Doomsday.class)); + cards.add(new SetCardInfo("Downdraft", 125, Rarity.UNCOMMON, mage.cards.d.Downdraft.class)); + cards.add(new SetCardInfo("Duskrider Falcon", 12, Rarity.COMMON, mage.cards.d.DuskriderFalcon.class)); + cards.add(new SetCardInfo("Dwarven Berserker", 97, Rarity.COMMON, mage.cards.d.DwarvenBerserker.class)); + cards.add(new SetCardInfo("Dwarven Thaumaturgist", 98, Rarity.RARE, mage.cards.d.DwarvenThaumaturgist.class)); + cards.add(new SetCardInfo("Empyrial Armor", 13, Rarity.COMMON, mage.cards.e.EmpyrialArmor.class)); + cards.add(new SetCardInfo("Fallow Wurm", 126, Rarity.UNCOMMON, mage.cards.f.FallowWurm.class)); + cards.add(new SetCardInfo("Familiar Ground", 127, Rarity.UNCOMMON, mage.cards.f.FamiliarGround.class)); + cards.add(new SetCardInfo("Fatal Blow", 67, Rarity.COMMON, mage.cards.f.FatalBlow.class)); + cards.add(new SetCardInfo("Fervor", 99, Rarity.RARE, mage.cards.f.Fervor.class)); + cards.add(new SetCardInfo("Festering Evil", 68, Rarity.UNCOMMON, mage.cards.f.FesteringEvil.class)); + cards.add(new SetCardInfo("Fire Whip", 100, Rarity.COMMON, mage.cards.f.FireWhip.class)); + cards.add(new SetCardInfo("Firestorm", 101, Rarity.RARE, mage.cards.f.Firestorm.class)); + cards.add(new SetCardInfo("Fit of Rage", 102, Rarity.COMMON, mage.cards.f.FitOfRage.class)); + cards.add(new SetCardInfo("Fledgling Djinn", 69, Rarity.COMMON, mage.cards.f.FledglingDjinn.class)); + cards.add(new SetCardInfo("Flux", 39, Rarity.COMMON, mage.cards.f.Flux.class)); + cards.add(new SetCardInfo("Fog Elemental", 40, Rarity.COMMON, mage.cards.f.FogElemental.class)); + cards.add(new SetCardInfo("Foriysian Brigade", 14, Rarity.UNCOMMON, mage.cards.f.ForiysianBrigade.class)); + cards.add(new SetCardInfo("Fungus Elemental", 128, Rarity.RARE, mage.cards.f.FungusElemental.class)); + cards.add(new SetCardInfo("Gaea's Blessing", 129, Rarity.UNCOMMON, mage.cards.g.GaeasBlessing.class)); + cards.add(new SetCardInfo("Gallowbraid", 70, Rarity.RARE, mage.cards.g.Gallowbraid.class)); + cards.add(new SetCardInfo("Gemstone Mine", 164, Rarity.UNCOMMON, mage.cards.g.GemstoneMine.class)); + cards.add(new SetCardInfo("Gerrard's Wisdom", 15, Rarity.UNCOMMON, mage.cards.g.GerrardsWisdom.class)); + cards.add(new SetCardInfo("Goblin Bomb", 103, Rarity.RARE, mage.cards.g.GoblinBomb.class)); + cards.add(new SetCardInfo("Goblin Grenadiers", 104, Rarity.UNCOMMON, mage.cards.g.GoblinGrenadiers.class)); + cards.add(new SetCardInfo("Goblin Vandal", 105, Rarity.COMMON, mage.cards.g.GoblinVandal.class)); + cards.add(new SetCardInfo("Guided Strike", 16, Rarity.COMMON, mage.cards.g.GuidedStrike.class)); + cards.add(new SetCardInfo("Harvest Wurm", 130, Rarity.COMMON, mage.cards.h.HarvestWurm.class)); + cards.add(new SetCardInfo("Haunting Misery", 71, Rarity.COMMON, mage.cards.h.HauntingMisery.class)); + cards.add(new SetCardInfo("Heart of Bogardan", 106, Rarity.RARE, mage.cards.h.HeartOfBogardan.class)); + cards.add(new SetCardInfo("Heat Stroke", 107, Rarity.RARE, mage.cards.h.HeatStroke.class)); + cards.add(new SetCardInfo("Heavy Ballista", 17, Rarity.COMMON, mage.cards.h.HeavyBallista.class)); + cards.add(new SetCardInfo("Hidden Horror", 72, Rarity.UNCOMMON, mage.cards.h.HiddenHorror.class)); + cards.add(new SetCardInfo("Hurloon Shaman", 108, Rarity.UNCOMMON, mage.cards.h.HurloonShaman.class)); + cards.add(new SetCardInfo("Infernal Tribute", 73, Rarity.RARE, mage.cards.i.InfernalTribute.class)); + cards.add(new SetCardInfo("Inner Sanctum", 18, Rarity.RARE, mage.cards.i.InnerSanctum.class)); + cards.add(new SetCardInfo("Jabari's Banner", 150, Rarity.UNCOMMON, mage.cards.j.JabarisBanner.class)); + cards.add(new SetCardInfo("Kithkin Armor", 19, Rarity.COMMON, mage.cards.k.KithkinArmor.class)); + cards.add(new SetCardInfo("Lava Hounds", 109, Rarity.UNCOMMON, mage.cards.l.LavaHounds.class)); + cards.add(new SetCardInfo("Lava Storm", 110, Rarity.COMMON, mage.cards.l.LavaStorm.class)); + cards.add(new SetCardInfo("Llanowar Behemoth", 132, Rarity.UNCOMMON, mage.cards.l.LlanowarBehemoth.class)); + cards.add(new SetCardInfo("Llanowar Druid", 133, Rarity.COMMON, mage.cards.l.LlanowarDruid.class)); + cards.add(new SetCardInfo("Llanowar Sentinel", 134, Rarity.COMMON, mage.cards.l.LlanowarSentinel.class)); + cards.add(new SetCardInfo("Lotus Vale", 165, Rarity.RARE, mage.cards.l.LotusVale.class)); + cards.add(new SetCardInfo("Mana Chains", 41, Rarity.COMMON, mage.cards.m.ManaChains.class)); + cards.add(new SetCardInfo("Mana Web", 152, Rarity.RARE, mage.cards.m.ManaWeb.class)); + cards.add(new SetCardInfo("Manta Ray", 42, Rarity.COMMON, mage.cards.m.MantaRay.class)); + cards.add(new SetCardInfo("Maraxus of Keld", 111, Rarity.RARE, mage.cards.m.MaraxusOfKeld.class)); + cards.add(new SetCardInfo("Master of Arms", 20, Rarity.UNCOMMON, mage.cards.m.MasterOfArms.class)); + cards.add(new SetCardInfo("Merfolk Traders", 43, Rarity.COMMON, mage.cards.m.MerfolkTraders.class)); + cards.add(new SetCardInfo("Mind Stone", 153, Rarity.COMMON, mage.cards.m.MindStone.class)); + cards.add(new SetCardInfo("Mischievous Poltergeist", 74, Rarity.UNCOMMON, mage.cards.m.MischievousPoltergeist.class)); + cards.add(new SetCardInfo("Mistmoon Griffin", 21, Rarity.UNCOMMON, mage.cards.m.MistmoonGriffin.class)); + cards.add(new SetCardInfo("Morinfen", 75, Rarity.RARE, mage.cards.m.Morinfen.class)); + cards.add(new SetCardInfo("Mwonvuli Ooze", 135, Rarity.RARE, mage.cards.m.MwonvuliOoze.class)); + cards.add(new SetCardInfo("Nature's Kiss", 136, Rarity.COMMON, mage.cards.n.NaturesKiss.class)); + cards.add(new SetCardInfo("Nature's Resurgence", 137, Rarity.RARE, mage.cards.n.NaturesResurgence.class)); + cards.add(new SetCardInfo("Necratog", 76, Rarity.UNCOMMON, mage.cards.n.Necratog.class)); + cards.add(new SetCardInfo("Noble Benefactor", 44, Rarity.UNCOMMON, mage.cards.n.NobleBenefactor.class)); + cards.add(new SetCardInfo("Null Rod", 154, Rarity.RARE, mage.cards.n.NullRod.class)); + cards.add(new SetCardInfo("Odylic Wraith", 77, Rarity.UNCOMMON, mage.cards.o.OdylicWraith.class)); + cards.add(new SetCardInfo("Ophidian", 45, Rarity.COMMON, mage.cards.o.Ophidian.class)); + cards.add(new SetCardInfo("Orcish Settlers", 112, Rarity.UNCOMMON, mage.cards.o.OrcishSettlers.class)); + cards.add(new SetCardInfo("Paradigm Shift", 46, Rarity.RARE, mage.cards.p.ParadigmShift.class)); + cards.add(new SetCardInfo("Peacekeeper", 22, Rarity.RARE, mage.cards.p.Peacekeeper.class)); + cards.add(new SetCardInfo("Pendrell Mists", 47, Rarity.RARE, mage.cards.p.PendrellMists.class)); + cards.add(new SetCardInfo("Phantom Warrior", 48, Rarity.UNCOMMON, mage.cards.p.PhantomWarrior.class)); + cards.add(new SetCardInfo("Phantom Wings", 49, Rarity.COMMON, mage.cards.p.PhantomWings.class)); + cards.add(new SetCardInfo("Phyrexian Furnace", 155, Rarity.UNCOMMON, mage.cards.p.PhyrexianFurnace.class)); + cards.add(new SetCardInfo("Psychic Vortex", 50, Rarity.RARE, mage.cards.p.PsychicVortex.class)); + cards.add(new SetCardInfo("Razortooth Rats", 78, Rarity.COMMON, mage.cards.r.RazortoothRats.class)); + cards.add(new SetCardInfo("Redwood Treefolk", 138, Rarity.COMMON, mage.cards.r.RedwoodTreefolk.class)); + cards.add(new SetCardInfo("Relearn", 51, Rarity.UNCOMMON, mage.cards.r.Relearn.class)); + cards.add(new SetCardInfo("Revered Unicorn", 23, Rarity.UNCOMMON, mage.cards.r.ReveredUnicorn.class)); + cards.add(new SetCardInfo("Roc Hatchling", 113, Rarity.UNCOMMON, mage.cards.r.RocHatchling.class)); + cards.add(new SetCardInfo("Rogue Elephant", 139, Rarity.COMMON, mage.cards.r.RogueElephant.class)); + cards.add(new SetCardInfo("Sage Owl", 52, Rarity.COMMON, mage.cards.s.SageOwl.class)); + cards.add(new SetCardInfo("Scorched Ruins", 166, Rarity.RARE, mage.cards.s.ScorchedRuins.class)); + cards.add(new SetCardInfo("Serenity", 24, Rarity.RARE, mage.cards.s.Serenity.class)); + cards.add(new SetCardInfo("Serra's Blessing", 25, Rarity.UNCOMMON, mage.cards.s.SerrasBlessing.class)); + cards.add(new SetCardInfo("Serrated Biskelion", 156, Rarity.UNCOMMON, mage.cards.s.SerratedBiskelion.class)); + cards.add(new SetCardInfo("Shadow Rider", 79, Rarity.COMMON, mage.cards.s.ShadowRider.class)); + cards.add(new SetCardInfo("Shattered Crypt", 80, Rarity.COMMON, mage.cards.s.ShatteredCrypt.class)); + cards.add(new SetCardInfo("Soul Shepherd", 26, Rarity.COMMON, mage.cards.s.SoulShepherd.class)); + cards.add(new SetCardInfo("Southern Paladin", 27, Rarity.RARE, mage.cards.s.SouthernPaladin.class)); + cards.add(new SetCardInfo("Spinning Darkness", 81, Rarity.COMMON, mage.cards.s.SpinningDarkness.class)); + cards.add(new SetCardInfo("Steel Golem", 157, Rarity.UNCOMMON, mage.cards.s.SteelGolem.class)); + cards.add(new SetCardInfo("Strands of Night", 82, Rarity.UNCOMMON, mage.cards.s.StrandsOfNight.class)); + cards.add(new SetCardInfo("Straw Golem", 158, Rarity.UNCOMMON, mage.cards.s.StrawGolem.class)); + cards.add(new SetCardInfo("Striped Bears", 140, Rarity.COMMON, mage.cards.s.StripedBears.class)); + cards.add(new SetCardInfo("Sylvan Hierophant", 141, Rarity.UNCOMMON, mage.cards.s.SylvanHierophant.class)); + cards.add(new SetCardInfo("Tariff", 28, Rarity.RARE, mage.cards.t.Tariff.class)); + cards.add(new SetCardInfo("Teferi's Veil", 53, Rarity.UNCOMMON, mage.cards.t.TeferisVeil.class)); + cards.add(new SetCardInfo("Tendrils of Despair", 83, Rarity.COMMON, mage.cards.t.TendrilsOfDespair.class)); + cards.add(new SetCardInfo("Thran Forge", 159, Rarity.UNCOMMON, mage.cards.t.ThranForge.class)); + cards.add(new SetCardInfo("Thunderbolt", 115, Rarity.COMMON, mage.cards.t.Thunderbolt.class)); + cards.add(new SetCardInfo("Thundermare", 116, Rarity.RARE, mage.cards.t.Thundermare.class)); + cards.add(new SetCardInfo("Timid Drake", 54, Rarity.UNCOMMON, mage.cards.t.TimidDrake.class)); + cards.add(new SetCardInfo("Tolarian Drake", 55, Rarity.COMMON, mage.cards.t.TolarianDrake.class)); + cards.add(new SetCardInfo("Tolarian Entrancer", 56, Rarity.RARE, mage.cards.t.TolarianEntrancer.class)); + cards.add(new SetCardInfo("Tolarian Serpent", 57, Rarity.RARE, mage.cards.t.TolarianSerpent.class)); + cards.add(new SetCardInfo("Touchstone", 161, Rarity.UNCOMMON, mage.cards.t.Touchstone.class)); + cards.add(new SetCardInfo("Tranquil Grove", 142, Rarity.RARE, mage.cards.t.TranquilGrove.class)); + cards.add(new SetCardInfo("Uktabi Efreet", 143, Rarity.COMMON, mage.cards.u.UktabiEfreet.class)); + cards.add(new SetCardInfo("Urborg Justice", 84, Rarity.RARE, mage.cards.u.UrborgJustice.class)); + cards.add(new SetCardInfo("Urborg Stalker", 85, Rarity.RARE, mage.cards.u.UrborgStalker.class)); + cards.add(new SetCardInfo("Veteran Explorer", 144, Rarity.UNCOMMON, mage.cards.v.VeteranExplorer.class)); + cards.add(new SetCardInfo("Vitalize", 145, Rarity.COMMON, mage.cards.v.Vitalize.class)); + cards.add(new SetCardInfo("Vodalian Illusionist", 58, Rarity.UNCOMMON, mage.cards.v.VodalianIllusionist.class)); + cards.add(new SetCardInfo("Volunteer Reserves", 29, Rarity.UNCOMMON, mage.cards.v.VolunteerReserves.class)); + cards.add(new SetCardInfo("Wave of Terror", 86, Rarity.RARE, mage.cards.w.WaveOfTerror.class)); + cards.add(new SetCardInfo("Well of Knowledge", 162, Rarity.RARE, mage.cards.w.WellOfKnowledge.class)); + cards.add(new SetCardInfo("Winding Canyons", 167, Rarity.RARE, mage.cards.w.WindingCanyons.class)); + cards.add(new SetCardInfo("Xanthic Statue", 163, Rarity.RARE, mage.cards.x.XanthicStatue.class)); + cards.add(new SetCardInfo("Zombie Scavengers", 87, Rarity.COMMON, mage.cards.z.ZombieScavengers.class)); + } +} diff --git a/Mage.Stats/pom.xml b/Mage.Stats/pom.xml deleted file mode 100644 index 394db54aa1..0000000000 --- a/Mage.Stats/pom.xml +++ /dev/null @@ -1,160 +0,0 @@ - - - 4.0.0 - - - org.mage - mage-root - 1.4.31 - - - org.mage - mage-stats - war - XMage Stats Web Service - - - - JBoss repository - https://repository.jboss.org/nexus/content/groups/public-jboss/ - - - - - - - org.mage - mage-common - ${project.version} - - - - org.mage - mage-server - ${project.version} - - - - junit - junit - test - - - - net.minidev - json-smart - 2.1.1 - - - - org.aspectj - aspectjrt - 1.8.2 - - - - net.sf.opencsv - opencsv - 2.3 - - - - - org.jboss.resteasy - resteasy-jaxrs - 2.3.7.Final - provided - - - - ch.qos.logback - logback-classic - 1.1.2 - - - - org.apache.sling - org.apache.sling.commons.json - 2.0.10 - - - - org.jboss.resteasy - resteasy-multipart-provider - 2.3.1.GA - - - - commons-io - commons-io - 2.4 - - - - commons-httpclient - commons-httpclient - 3.1 - - - - javax.servlet - servlet-api - 2.5 - - - - joda-time - joda-time - 2.7 - - - - - mage-stats-ws - - - - org.apache.maven.plugins - maven-compiler-plugin - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-war-plugin - 2.6 - - src\main\webapp\WEB-INF\web.xml - . - - - - org.codehaus.mojo - aspectj-maven-plugin - 1.7 - - - - ${project.basedir}/src/main/java - - - 1.7 - - - - - compile - - - - - - - - - UTF-8 - - diff --git a/Mage.Stats/src/main/java/com/xmage/core/builders/Builder.java b/Mage.Stats/src/main/java/com/xmage/core/builders/Builder.java deleted file mode 100644 index 52cf3daa5f..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/builders/Builder.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xmage.core.builders; - -public abstract class Builder { - - protected E entity; - - protected Builder() { - //entity = E.class.newInstance(); - } - - abstract protected void validate(); - - public final E build() { - validate(); - return entity; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/constants/Constants.java b/Mage.Stats/src/main/java/com/xmage/core/constants/Constants.java deleted file mode 100644 index bd9ee16b41..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/constants/Constants.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.xmage.core.constants; - -public class Constants { - - -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/decorators/Decorator.java b/Mage.Stats/src/main/java/com/xmage/core/decorators/Decorator.java deleted file mode 100644 index 5d9c03e961..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/decorators/Decorator.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.xmage.core.decorators; - -/** - * @author noxx - */ -public interface Decorator { -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/entity/model/EntityModel.java b/Mage.Stats/src/main/java/com/xmage/core/entity/model/EntityModel.java deleted file mode 100644 index 7725f01e69..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/entity/model/EntityModel.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.xmage.core.entity.model; - - -/** - * Marker interface for entity models. - * - * @author noxx - */ -public interface EntityModel { - -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/entity/model/ServerStats.java b/Mage.Stats/src/main/java/com/xmage/core/entity/model/ServerStats.java deleted file mode 100644 index 9cd5af8c15..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/entity/model/ServerStats.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.xmage.core.entity.model; - - -/** - * Class representing XMage server stats. - * - * @author noxx - */ -public class ServerStats implements EntityModel { - - private int numberOfGamesPlayed; - - private int numberOfUniquePlayers; - - private String top3Players; - - private int numberOfPlayersPlayedOnce; - - public int getNumberOfGamesPlayed() { - return numberOfGamesPlayed; - } - - public void setNumberOfGamesPlayed(int numberOfGamesPlayed) { - this.numberOfGamesPlayed = numberOfGamesPlayed; - } - - public int getNumberOfUniquePlayers() { - return numberOfUniquePlayers; - } - - public void setNumberOfUniquePlayers(int numberOfUniquePlayers) { - this.numberOfUniquePlayers = numberOfUniquePlayers; - } - - public int getNumberOfPlayersPlayedOnce() { - return numberOfPlayersPlayedOnce; - } - - public void setNumberOfPlayersPlayedOnce(int numberOfPlayersPlayedOnce) { - this.numberOfPlayersPlayedOnce = numberOfPlayersPlayedOnce; - } - - public String getTop3Players() { - return top3Players; - } - - public void setTop3Players(String top3Players) { - this.top3Players = top3Players; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - ServerStats stats = (ServerStats) o; - - if (numberOfGamesPlayed != stats.numberOfGamesPlayed) return false; - if (numberOfUniquePlayers != stats.numberOfUniquePlayers) return false; - if (numberOfPlayersPlayedOnce != stats.numberOfPlayersPlayedOnce) return false; - if (top3Players != null ? !top3Players.equals(stats.top3Players) : stats.top3Players != null) return false; - - return true; - } - - @Override - public int hashCode() { - int result = numberOfGamesPlayed; - result = 31 * result + numberOfUniquePlayers; - result = 31 * result + numberOfPlayersPlayedOnce; - result = 31 * result + (top3Players != null ? top3Players.hashCode() : 0); - - return result; - } - - -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/entity/repositories/XMageStatsRepository.java b/Mage.Stats/src/main/java/com/xmage/core/entity/repositories/XMageStatsRepository.java deleted file mode 100644 index 4a5cc4310a..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/entity/repositories/XMageStatsRepository.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.xmage.core.entity.repositories; - -import com.xmage.core.entity.model.ServerStats; - -/** - * Repository interface for XMage server stats. - * - * Responsible for fetching stats information. - * - * @author noxx - */ -public interface XMageStatsRepository { - - ServerStats getServerStats(); - -} diff --git a/Mage.Stats/src/main/java/com/xmage/core/exceptions/XMageStatsNotFoundException.java b/Mage.Stats/src/main/java/com/xmage/core/exceptions/XMageStatsNotFoundException.java deleted file mode 100644 index 0050af7214..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/core/exceptions/XMageStatsNotFoundException.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.xmage.core.exceptions; - -/** - * - * @author noxx - */ -public class XMageStatsNotFoundException extends Exception { -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/aspect/RequestAspect.java b/Mage.Stats/src/main/java/com/xmage/ws/aspect/RequestAspect.java deleted file mode 100644 index 5d6ffc977b..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/aspect/RequestAspect.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.xmage.ws.aspect; - -import com.xmage.ws.json.ResponseBuilder; -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.resource.ErrorResource; -import com.xmage.ws.resource.Resource; -import com.xmage.ws.util.IPHolderUtil; -import net.minidev.json.JSONObject; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.core.Response; - -/** - * Base aspect for getting request metadata - * - * @author noxx - */ -@Aspect -public class RequestAspect { - - private static final Logger logger = LoggerFactory.getLogger(RequestAspect.class); - - @Around("execution(* *(..)) && within(com.xmage.ws.rest.services.*)") - public Object advice(ProceedingJoinPoint pjp) throws Throwable { - - try { - String ip = IPHolderUtil.getRememberedIP(); - String userAgent = IPHolderUtil.getRememberedUserAgent(); - logger.info("ip: " + ip + ", user-agent: " + userAgent); - - return pjp.proceed(); - } catch (Exception e) { - logger.error("Error: ", e); - } - - Resource resource = new ErrorResource(DomainErrors.Errors.STATUS_SERVER_ERROR, "server_error"); - JSONObject serverError = ResponseBuilder.build(resource); - - return Response.status(200).entity(serverError.toJSONString()).build(); - } - - -} \ No newline at end of file diff --git a/Mage.Stats/src/main/java/com/xmage/ws/filter/IPFilter.java b/Mage.Stats/src/main/java/com/xmage/ws/filter/IPFilter.java deleted file mode 100644 index 7fd7ba6abc..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/filter/IPFilter.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.xmage.ws.filter; - -import com.xmage.ws.util.IPHolderUtil; - -import javax.servlet.*; -import javax.servlet.http.HttpServletRequest; -import java.io.IOException; - -/** - * Filter gets ip address and user agent and stores it using {@link com.xmage.ws.util.IPHolderUtil} - * - * @author noxx - */ -public class IPFilter implements Filter { - - private FilterConfig config; - - public IPFilter() {} - - public void init(FilterConfig filterConfig) throws ServletException { - this.config = filterConfig; - } - - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { - - String ip = request.getRemoteAddr(); - IPHolderUtil.rememberIP(ip); - - if (request instanceof HttpServletRequest) { - HttpServletRequest req = (HttpServletRequest) request; - String uaString = req.getHeader("User-Agent"); - IPHolderUtil.rememberUserAgent(uaString); - } - - chain.doFilter(request, response); - - }// doFilter - - public void destroy() { - /* - * called before the Filter instance is removed from service by the web - * container - */ - } - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/json/JSONBuilder.java b/Mage.Stats/src/main/java/com/xmage/ws/json/JSONBuilder.java deleted file mode 100644 index 1aee3735df..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/json/JSONBuilder.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xmage.ws.json; - -import com.xmage.core.entity.model.EntityModel; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; - -/** - * Converts {@link com.xmage.core.entity.model.EntityModel} to json. - * - * @author noxx - */ -public interface JSONBuilder { - - JSONObject buildFrom(Resource resource); -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/json/ResponseBuilder.java b/Mage.Stats/src/main/java/com/xmage/ws/json/ResponseBuilder.java deleted file mode 100644 index cee6c8bffb..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/json/ResponseBuilder.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xmage.ws.json; - -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; - -public final class ResponseBuilder { - - public static JSONObject build(int code) { - JSONObject response = new JSONObject(); - response.put("code", code); - - return response; - } - - public static JSONObject build(int code, String name, JSONObject jsonObject) { - JSONObject response = new JSONObject(); - response.put("code", code); - response.put(name, jsonObject); - - return response; - } - - public static JSONObject build(Resource resource) { - if (resource.getError() != DomainErrors.Errors.STATUS_OK.getCode()) { - JSONObject response = ResponseBuilder.build(resource.getError()); - response.put("message", resource.getErrorMessage()); - return response; - } else { - JSONObject json = resource.getJSONBody(); - return ResponseBuilder.build(DomainErrors.Errors.STATUS_OK.getCode(), resource.getName(), json); - } - - } - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/json/XMageStatsJSONBuilder.java b/Mage.Stats/src/main/java/com/xmage/ws/json/XMageStatsJSONBuilder.java deleted file mode 100644 index 82c2177cf0..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/json/XMageStatsJSONBuilder.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.xmage.ws.json; - -import com.xmage.core.entity.model.ServerStats; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.SimpleDateFormat; - -/** - * Converts {@link com.xmage.core.entity.model.ServerStats} resource to json. - * - * @author noxx - */ -public class XMageStatsJSONBuilder implements JSONBuilder { - - private static final Logger logger = LoggerFactory.getLogger(XMageStatsJSONBuilder.class); - - private static final SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy"); - - static final class StaticHolder { - static XMageStatsJSONBuilder instance = new XMageStatsJSONBuilder(); - } - - public static XMageStatsJSONBuilder getInstance() { - return StaticHolder.instance; - } - - public JSONObject buildFrom(Resource resource) { - - ServerStats serverStats = resource.getDefault(); - - JSONObject statsJson = new JSONObject(); - - statsJson.put("numberOfGamesPlayed", serverStats.getNumberOfGamesPlayed()); - statsJson.put("numberOfUniquePlayers", serverStats.getNumberOfUniquePlayers()); - statsJson.put("numberOfPlayersPlayedOnlyOnce", serverStats.getNumberOfPlayersPlayedOnce()); - statsJson.put("top3Players", serverStats.getTop3Players()); - - return statsJson; - } - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/model/DomainErrors.java b/Mage.Stats/src/main/java/com/xmage/ws/model/DomainErrors.java deleted file mode 100644 index c60e869389..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/model/DomainErrors.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xmage.ws.model; - -/** - * Domain status error codes. - * - * @author noxx - */ -public class DomainErrors { - - public enum Errors { - STATUS_OK(100, "OK"), - STATUS_SERVER_ERROR(101, "Server Internal Error"), - STATUS_AUTH_FAILED(102, "Auth failed"), - STATUS_ACCESS_DENIED(108, "Access denied"), - STATUS_NOT_ENOUGH_PARAMETERS(301, "Not enough parameters"), - STATUS_WRONG_PARAM_FORMAT(302, "Wrong param format"), - STATUS_NOT_IMPLEMENTED(800, "Not implemented"), - STATUS_NOT_FOUND(1000, "Resource Not Found"); - - private int code; - private String message; - - Errors(int code, String message) { - this.code = code; - this.message = message; - } - - public int getCode() { - return code; - } - - public String getMessage() { - return message; - } - - public void setCustomMessage(String message) { - this.message = message; - } - } - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/model/SimpleResponse.java b/Mage.Stats/src/main/java/com/xmage/ws/model/SimpleResponse.java deleted file mode 100644 index b859b043f8..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/model/SimpleResponse.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.xmage.ws.model; - - -/** - * Some services may return simple response that is not related to domain or contain minor information. - * Example: return OK or FALSE only for checking server state. - * - * @author noxx - */ -public class SimpleResponse { - - private int code; - - private String message; - - public SimpleResponse(int code, String message) { - this.code = code; - this.message = message; - } - - public SimpleResponse(DomainErrors.Errors error) { - this(error.getCode(), error.getMessage()); - } - - public int getCode() { - return code; - } - - public void setCode(int code) { - this.code = code; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/representer/Representer.java b/Mage.Stats/src/main/java/com/xmage/ws/representer/Representer.java deleted file mode 100644 index d5a471d3af..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/representer/Representer.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.xmage.ws.representer; - -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; - -/** - * Now we have only JSON based representation. - * - * @author noxx - */ -public interface Representer { - - JSONObject toJSON(Resource resource); -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/representer/SimpleResponseRepresenter.java b/Mage.Stats/src/main/java/com/xmage/ws/representer/SimpleResponseRepresenter.java deleted file mode 100644 index 1d4117eaf7..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/representer/SimpleResponseRepresenter.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.xmage.ws.representer; - -import com.xmage.ws.model.SimpleResponse; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; - -/** - * This is useful when we have {@link SimpleResponse} - * - * @author noxx - */ -public class SimpleResponseRepresenter implements Representer { - - public JSONObject toJSON(Resource resource) { - SimpleResponse response = resource.getDefault(); - - JSONObject json = new JSONObject(); - json.put("code", response.getCode()); - json.put("message", response.getMessage()); - - return json; - } - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/representer/XMageStatsRepresenter.java b/Mage.Stats/src/main/java/com/xmage/ws/representer/XMageStatsRepresenter.java deleted file mode 100644 index a54b374347..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/representer/XMageStatsRepresenter.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.xmage.ws.representer; - -import com.xmage.core.entity.model.ServerStats; -import com.xmage.ws.json.XMageStatsJSONBuilder; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; - -/** - * - * @author noxx - */ -public class XMageStatsRepresenter implements Representer { - - public XMageStatsRepresenter() { - } - - public JSONObject toJSON(Resource resource) { - return XMageStatsJSONBuilder.getInstance().buildFrom(resource); - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/resource/DefaultResource.java b/Mage.Stats/src/main/java/com/xmage/ws/resource/DefaultResource.java deleted file mode 100644 index 5b858f0614..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/resource/DefaultResource.java +++ /dev/null @@ -1,64 +0,0 @@ -package com.xmage.ws.resource; - -import com.xmage.core.decorators.Decorator; -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.representer.Representer; -import java.util.ArrayList; -import net.minidev.json.JSONObject; - -/** - * - * @author noxx - */ -public abstract class DefaultResource implements Resource { - - protected DomainErrors.Errors error = DomainErrors.Errors.STATUS_OK; - - protected R defaultResource; - - protected Representer representer; - - protected java.util.List decorators = new ArrayList<>(); - - protected int version; - - protected DefaultResource(Representer representer) { - this.representer = representer; - } - - @Override - public int getError() { - return error.getCode(); - } - - @Override - public R getDefault() { - return defaultResource; - } - - @Override - public java.util.List getDecorators() { - return decorators; - } - - @Override - public void addDecorator(Decorator decorator) { - if (decorator != null) { - this.decorators.add(decorator); - } - } - - @Override - public JSONObject getJSONBody() { - return representer.toJSON(this); - } - - @Override - public String getErrorMessage() { - return error.getMessage(); - } - - public int getVersion() { - return version; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/resource/ErrorResource.java b/Mage.Stats/src/main/java/com/xmage/ws/resource/ErrorResource.java deleted file mode 100644 index d1cc7ddb42..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/resource/ErrorResource.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.xmage.ws.resource; - -import com.xmage.ws.model.DomainErrors; - -/** - * - * @author noxx - */ -public class ErrorResource extends DefaultResource { - - private String name; - - public ErrorResource(DomainErrors.Errors error, String name) { - super(null); - this.name = name; - this.error = error; - } - - @Override - public String getName() { - return this.name; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/resource/Resource.java b/Mage.Stats/src/main/java/com/xmage/ws/resource/Resource.java deleted file mode 100644 index 5a51732ea5..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/resource/Resource.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.xmage.ws.resource; - -import com.xmage.core.decorators.Decorator; -import net.minidev.json.JSONObject; - -/** - * - * @author noxx - */ -public interface Resource { - - int getError(); - - String getErrorMessage(); - - String getName(); - - JSONObject getJSONBody(); - - R getDefault(); - - java.util.List getDecorators(); - - void addDecorator(Decorator decorator); -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/resource/XMageStatsResource.java b/Mage.Stats/src/main/java/com/xmage/ws/resource/XMageStatsResource.java deleted file mode 100644 index 3f3bf64350..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/resource/XMageStatsResource.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.xmage.ws.resource; - -import com.xmage.core.entity.model.ServerStats; -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.representer.XMageStatsRepresenter; -import com.xmage.ws.representer.Representer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class XMageStatsResource extends DefaultResource { - - private static final Logger logger = LoggerFactory.getLogger(XMageStatsResource.class); - - private static final Representer defaultRepresenter = new XMageStatsRepresenter(); - - public XMageStatsResource() { - super(defaultRepresenter); - } - - public Resource getAll() { - error = DomainErrors.Errors.STATUS_NOT_FOUND; - return this; - } - - @Override - public String getName() { - return "serverStats"; - } - - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/resource/impl/SimpleResource.java b/Mage.Stats/src/main/java/com/xmage/ws/resource/impl/SimpleResource.java deleted file mode 100644 index d72dd96edb..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/resource/impl/SimpleResource.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.xmage.ws.resource.impl; - -import com.xmage.ws.model.SimpleResponse; -import com.xmage.ws.representer.SimpleResponseRepresenter; -import com.xmage.ws.resource.DefaultResource; - -public class SimpleResource extends DefaultResource { - - public SimpleResource() { - super(new SimpleResponseRepresenter()); - } - - @Override - public String getName() { - return "simple"; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/rest/XMageStatsAPIApplication.java b/Mage.Stats/src/main/java/com/xmage/ws/rest/XMageStatsAPIApplication.java deleted file mode 100644 index 074a979e39..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/rest/XMageStatsAPIApplication.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.xmage.ws.rest; - -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; - -@ApplicationPath("/api") -public class XMageStatsAPIApplication extends Application { -} \ No newline at end of file diff --git a/Mage.Stats/src/main/java/com/xmage/ws/rest/services/XMageStatsService.java b/Mage.Stats/src/main/java/com/xmage/ws/rest/services/XMageStatsService.java deleted file mode 100644 index 7124993d3c..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/rest/services/XMageStatsService.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.xmage.ws.rest.services; - -import com.xmage.ws.resource.XMageStatsResource; -import com.xmage.ws.resource.Resource; -import com.xmage.ws.rest.services.base.AbstractService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Response; - -/** - * - * @author noxx - */ -@Path("/xmage/stats") -@Produces("application/json;charset=utf-8") -public class XMageStatsService extends AbstractService { - - static final Logger logger = LoggerFactory.getLogger(XMageStatsService.class); - - @GET - @Path("/getAll") - public Response getAllStats() { - logger.trace("getAllStats"); - Resource resource = new XMageStatsResource().getAll(); - - return responseWithError(resource); - } - - -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/rest/services/base/AbstractService.java b/Mage.Stats/src/main/java/com/xmage/ws/rest/services/base/AbstractService.java deleted file mode 100644 index 1ffc7c80d6..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/rest/services/base/AbstractService.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.xmage.ws.rest.services.base; - -import com.xmage.ws.json.ResponseBuilder; -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.resource.Resource; -import net.minidev.json.JSONObject; -import org.apache.sling.commons.json.JSONException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.ws.rs.core.Response; - -/** - * General approach for ws requests/responses. - * - * Consists of building response object, verifying response, prettifying, execution time calculating. - * - * @author noxx - */ -public abstract class AbstractService { - - private static final Logger logger = LoggerFactory.getLogger(AbstractService.class); - - /** - * Create {@link Response} from {@link com.xmage.ws.resource.Resource} - * - * @param resource Resource to build response based on - * @return - */ - public final Response responseWithError(Resource resource) { - long t1 = System.currentTimeMillis(); - JSONObject response = buildResponse(resource); - response = verifyResponse(response); - String json = prettifyResponse(response); - - Response responseObject = Response.status(200).entity(json).build(); - long t2 = System.currentTimeMillis(); - logger.info("responseWithError time: " + (t2 - t1) + "ms"); - return responseObject; - } - - private JSONObject buildResponse(Resource resource) { - JSONObject response = null; - try { - response = ResponseBuilder.build(resource); - } catch (Exception e) { - logger.error("responseWithError: ", e); - - } - - return response; - } - - private String prettifyResponse(JSONObject response) { - String json = response.toJSONString(); - - try { - json = new org.apache.sling.commons.json.JSONObject(json).toString(1); - } catch (JSONException jse) { - jse.printStackTrace(); - } - - return json; - } - - private JSONObject verifyResponse(JSONObject response) { - if (response == null) { - logger.error("Something bad happened on response creation"); - response = ResponseBuilder.build(DomainErrors.Errors.STATUS_SERVER_ERROR.getCode()); - } - return response; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/util/IPHolderUtil.java b/Mage.Stats/src/main/java/com/xmage/ws/util/IPHolderUtil.java deleted file mode 100644 index ac9ea26bba..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/util/IPHolderUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.xmage.ws.util; - -/** - * Stores ip addresses to allow access from. - * Stores user-agents to allow access for. - * - * @author noxx - */ -public final class IPHolderUtil { - - private static final ThreadLocal ipThreadLocal = new ThreadLocal<>(); - private static final ThreadLocal userAgentThreadLocal = new ThreadLocal<>(); - - private IPHolderUtil() {} - - public static void rememberIP(String ip) { - ipThreadLocal.set(ip); - } - - public static String getRememberedIP() { - return ipThreadLocal.get(); - } - - public static void rememberUserAgent(String userAgent) { - userAgentThreadLocal.set(userAgent); - } - - public static String getRememberedUserAgent() { - return userAgentThreadLocal.get(); - } -} - diff --git a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONOperationErrorException.java b/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONOperationErrorException.java deleted file mode 100644 index b40927abb8..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONOperationErrorException.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.xmage.ws.util.json; - -/** - * - * @author noxx - */ -public class JSONOperationErrorException extends RuntimeException { - - public JSONOperationErrorException(String message) { - super(message); - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONParser.java b/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONParser.java deleted file mode 100644 index ac96be11cb..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONParser.java +++ /dev/null @@ -1,198 +0,0 @@ -package com.xmage.ws.util.json; - - -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import net.minidev.json.JSONValue; - -import java.util.HashMap; -import java.util.Map; - -/** - * Enhances working with json. - * - * @author noxx - */ -public class JSONParser { - - public enum CachePolicy { - CACHE_ONE_LEVEL_ONLY, - CACHE_ALL_LEVELS - } - - private static final Map extendedIndexes = new HashMap() {{ - put("$first", 0); - put("$second", 1); - put("$third", 2); - put("$fourth", 3); - put("$fifth", 4); - }}; - - private String json; - private JSONObject root; - private boolean hitCache; - - private CachePolicy cachePolicy = CachePolicy.CACHE_ONE_LEVEL_ONLY; - - private Map cache = new HashMap<>(); - - public void parseJSON(String jsonString) throws JSONValidationException { - parseJSON(jsonString, true); - } - - public void parseJSON(String jsonString, boolean validate) throws JSONValidationException { - this.json = jsonString; - prepare(); - if (validate) { - validate(); - } - } - - public Object get(String path) { - return getObject(path); - } - - public int getInt(String path) { - return (Integer)getObject(path); - } - - public int getIntSafe(String path) { - if (getObject(path) == null) { - return 0; - } - return (Integer)getObject(path); - } - - public String getString(String path) { - return (String)getObject(path); - } - - public JSONObject getJSON(String path) { - return (JSONObject)getObject(path); - } - - private Object getObject(String path) { - this.hitCache = false; - if (cache.containsKey(path)) { - this.hitCache = true; - return cache.get(path); - } - String[] params = path.split("\\."); - JSONObject json = this.root; - JSONArray jsonArray = null; - String currentPath = ""; - for (int i = 0; i < params.length - 1; i++) { - String param = params[i]; - if (cachePolicy == CachePolicy.CACHE_ALL_LEVELS) { - if (!currentPath.isEmpty()) { - currentPath += "."; - } - currentPath += param; - } - if (param.startsWith("$")) { - if (jsonArray == null) { - throw new JSONOperationErrorException("Not illegal syntax at this place: " + param); - } - int index = getIndex(param); - json = (JSONObject) jsonArray.get(index); - jsonArray = null; - } else if (param.contains("[")) { - int find = param.indexOf('['); - String newParam = param.substring(0, find); - String s = param.substring(find+1, param.indexOf(']')); - if (s.isEmpty()) { - jsonArray = (JSONArray) json.get(newParam); - json = null; - } else { - int index = Integer.parseInt(s); - json = (JSONObject)((JSONArray) json.get(newParam)).get(index); - jsonArray = null; - } - } else { - Object obj = json.get(param); - if (obj instanceof JSONObject) { - json = (JSONObject) obj; - jsonArray = null; - } else if (obj instanceof JSONArray) { - jsonArray = (JSONArray) obj; - json = null; - } else if (obj == null) { - throw new IllegalStateException("json object is null"); - } else { - throw new IllegalStateException("json object ('"+param+"') has wrong type: " + obj.getClass()); - } - - } - if (cachePolicy == CachePolicy.CACHE_ALL_LEVELS) { - saveToCache(currentPath, json); - } - } - String name = params[params.length - 1]; - - Object value; - if (name.startsWith("$")) { - if (jsonArray == null) { - throw new JSONOperationErrorException("Not illegal syntax at this place: " + name); - } - int index = getIndex(name); - value = jsonArray.get(index); - } else { - value = json.get(name); - } - - saveToCache(path, value); - - return value; - } - - private int getIndex(String extendedIndex) { - if (extendedIndexes.containsKey(extendedIndex)) { - return extendedIndexes.get(extendedIndex); - } else { - throw new JSONOperationErrorException("Can't parse extended index: " + extendedIndex); - } - } - - private void saveToCache(String path, Object value) { - cache.put(path, value); - } - - public JSONArray getJSONArray(String path) { - return (JSONArray)getObject(path); - } - - private void prepare() { - reset(); - if (this.json != null) { - this.json = this.json.trim(); - } - } - - private void validate() throws JSONValidationException { - if (this.json == null) { - throw new JSONValidationException("JSON is null"); - } - try { - this.root = (JSONObject) JSONValue.parse(this.json); - if (this.root == null) { - throw new JSONValidationException("Root json is null"); - } - } catch (Exception e) { - throw new JSONValidationException("JSON is not valid", e); - } - } - - public void reset() { - this.hitCache = false; - this.cachePolicy = CachePolicy.CACHE_ONE_LEVEL_ONLY; - this.cache.clear(); - } - - public boolean isHitCache() { - return hitCache; - } - - public void setCachePolicy(CachePolicy cachePolicy) { - this.cachePolicy = cachePolicy; - } -} diff --git a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONValidationException.java b/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONValidationException.java deleted file mode 100644 index a7271a49a4..0000000000 --- a/Mage.Stats/src/main/java/com/xmage/ws/util/json/JSONValidationException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.xmage.ws.util.json; - -/** - * - * @author noxx - */ -public class JSONValidationException extends Exception { - - public JSONValidationException(String message) { - super(message); - } - - public JSONValidationException(String message, Exception e) { - super(message, e); - } -} diff --git a/Mage.Stats/src/main/resources/META-INF/c3p0.properties b/Mage.Stats/src/main/resources/META-INF/c3p0.properties deleted file mode 100644 index b8792e248a..0000000000 --- a/Mage.Stats/src/main/resources/META-INF/c3p0.properties +++ /dev/null @@ -1,4 +0,0 @@ -###c3p0 -с3p0.testConnectionOnCheckout=true -с3p0.acquireRetryDelay=1000 -с3p0.acquireRetryAttempts=1 \ No newline at end of file diff --git a/Mage.Stats/src/main/resources/logback.xml b/Mage.Stats/src/main/resources/logback.xml deleted file mode 100644 index 79104d854a..0000000000 --- a/Mage.Stats/src/main/resources/logback.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - server.log - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - - - \ No newline at end of file diff --git a/Mage.Stats/src/main/resources/messages.properties b/Mage.Stats/src/main/resources/messages.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Mage.Stats/src/main/resources/messages_en.properties b/Mage.Stats/src/main/resources/messages_en.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Mage.Stats/src/main/resources/messages_ru.properties b/Mage.Stats/src/main/resources/messages_ru.properties deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Mage.Stats/src/main/resources/xmage.properties b/Mage.Stats/src/main/resources/xmage.properties deleted file mode 100644 index 68e6141898..0000000000 --- a/Mage.Stats/src/main/resources/xmage.properties +++ /dev/null @@ -1,2 +0,0 @@ -db.log.url=jdbc:h2:file:../Mage.Server/db/mage.h2;AUTO_SERVER=TRUE -db.feedback.url=jdbc:h2:file:../Mage.Server/db/feedback.h2;AUTO_SERVER=TRUE \ No newline at end of file diff --git a/Mage.Stats/src/main/webapp/WEB-INF/web.xml b/Mage.Stats/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index 14005be18f..0000000000 --- a/Mage.Stats/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - XMage Stats Restful Web Application - - - IPFilter - com.xmage.ws.filter.IPFilter - - - - IPFilter - /* - - - diff --git a/Mage.Stats/src/main/webapp/index.jsp b/Mage.Stats/src/main/webapp/index.jsp deleted file mode 100644 index c38169bb95..0000000000 --- a/Mage.Stats/src/main/webapp/index.jsp +++ /dev/null @@ -1,5 +0,0 @@ - - -

    Hello World!

    - - diff --git a/Mage.Stats/src/test/java/com/anygo/ws/json/TestJSONParser.java b/Mage.Stats/src/test/java/com/anygo/ws/json/TestJSONParser.java deleted file mode 100644 index 8960155f3b..0000000000 --- a/Mage.Stats/src/test/java/com/anygo/ws/json/TestJSONParser.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.anygo.ws.json; - -import com.xmage.ws.util.json.JSONParser; -import com.xmage.ws.util.json.JSONValidationException; -import junit.framework.Assert; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.junit.Test; - -/** - * - * @author noxx - */ -public class TestJSONParser { - - @Test - public void testParse() throws Exception { - JSONParser parser = new JSONParser(); - parser.parseJSON("{}"); - parser.parseJSON("{\"test\" : 1}"); - parser.parseJSON("{\"test\" : \"test\"}"); - parser.parseJSON("{\"list\" : [\"1\", \"2\", \"3\"]}"); - parser.parseJSON("{test:test}"); - - testError(parser, "{"); - testError(parser, "}"); - testError(parser, "{{}"); - testError(parser, "{\"test\" : [}}"); - } - - @Test - public void testQueryForInt() throws Exception { - JSONParser parser = new JSONParser(); - parser.parseJSON("{\"test\" : 1}"); - Assert.assertEquals(1, parser.getInt("test")); - - parser = new JSONParser(); - parser.parseJSON("{test : { internal : {level : 2}}}"); - Assert.assertEquals(2, parser.getInt("test.internal.level")); - Assert.assertFalse("No cache should have been used", parser.isHitCache()); - - Assert.assertEquals(2, parser.getInt("test.internal.level")); - Assert.assertTrue("Cache should have been used this time!", parser.isHitCache()); - } - - @Test - public void testQueryForJSONArray() throws Exception { - JSONParser parser = new JSONParser(); - parser.parseJSON("{\"test\" : [\"1\", \"2\", \"3\"]}"); - Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray); - Assert.assertEquals("1", parser.getJSONArray("test").get(0)); - - parser = new JSONParser(); - parser.parseJSON("{\"test\" : [1,2,3]}"); - Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray); - Assert.assertFalse(parser.isHitCache()); - Assert.assertEquals(2, parser.getJSONArray("test").get(1)); - Assert.assertTrue(parser.isHitCache()); - - Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray); - Assert.assertEquals(2, parser.getJSONArray("test").get(1)); - Assert.assertTrue(parser.isHitCache()); - - parser = new JSONParser(); - parser.parseJSON("{\"test\" : [{second_level: \"3\"}, {\"third_level\" : 2}]}"); - Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray); - Assert.assertTrue(parser.getJSONArray("test").get(0) instanceof JSONObject); - Assert.assertEquals(2, parser.getInt("test[1].third_level")); - Assert.assertEquals("3", parser.getString("test[0].second_level")); - - parser = new JSONParser(); - parser.parseJSON("{\"test\" : [{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{1:1},{2:3},{4:5}]}"); - Assert.assertTrue(parser.getJSONArray("test") instanceof JSONArray); - Assert.assertEquals(5, parser.getInt("test[10].4")); - } - - @Test - //TODO: implement - public void testErrors() throws Exception { - //JSONParser parser = new JSONParser(); - //parser.parseJSON("{test : { internal : {level : \"2\"}}}"); - //parser.getInt("test.internal.level"); - } - - @Test - public void testExtendedCache() throws Exception { - JSONParser parser = new JSONParser(); - parser.parseJSON("{test : { internal : {level : 2}}}"); - Assert.assertEquals(2, parser.getInt("test.internal.level")); - Assert.assertFalse("No cache should have been used", parser.isHitCache()); - - Assert.assertTrue(parser.getJSON("test") instanceof JSONObject); - Assert.assertFalse("No cache should have been used", parser.isHitCache()); - Assert.assertTrue(parser.getJSON("test.internal") instanceof JSONObject); - Assert.assertFalse("No cache should have been used", parser.isHitCache()); - - parser = new JSONParser(); - parser.parseJSON("{test : { internal : {level : 2}}}"); - parser.setCachePolicy(JSONParser.CachePolicy.CACHE_ALL_LEVELS); - Assert.assertEquals(2, parser.getInt("test.internal.level")); - Assert.assertFalse("No cache should have been used", parser.isHitCache()); - - Assert.assertTrue(parser.getJSON("test") instanceof JSONObject); - Assert.assertTrue("Cache should have been used this time!", parser.isHitCache()); - Assert.assertTrue(parser.getJSON("test.internal") instanceof JSONObject); - Assert.assertTrue("Cache should have been used this time!", parser.isHitCache()); - } - - @Test - public void testExtendedIndexes() throws Exception { - JSONParser parser = new JSONParser(); - parser.parseJSON("{\"test\" : [1,2,3,4,5]}"); - Assert.assertEquals(1, parser.getInt("test[].$first")); - Assert.assertEquals(2, parser.getInt("test[].$second")); - Assert.assertEquals(3, parser.getInt("test[].$third")); - Assert.assertEquals(4, parser.getInt("test[].$fourth")); - Assert.assertEquals(5, parser.getInt("test[].$fifth")); - - parser = new JSONParser(); - parser.parseJSON("{\"test\" : [{1:1},{2:2},{3:3},{4:4},{5:5}]}"); - Assert.assertEquals(1, parser.getInt("test[].$first.1")); - Assert.assertEquals(2, parser.getInt("test[].$second.2")); - Assert.assertEquals(3, parser.getInt("test[].$third.3")); - Assert.assertEquals(4, parser.getInt("test[].$fourth.4")); - Assert.assertEquals(5, parser.getInt("test[].$fifth.5")); - - parser = new JSONParser(); - parser.parseJSON("{\"contacts\": {\"phones\": [\n" + - " {\"phone\": \"100000\"},\n" + - " {\"phone\": \"+7 999 1234567\"}\n" + - " ]}}"); - - Assert.assertEquals("100000", parser.getString("contacts.phones[].$first.phone")); - - } - - private void testError(JSONParser parser, String jsonToTest) throws Exception { - try { - parser.parseJSON(jsonToTest); - Assert.assertTrue("Should have thrown an exception", false); - } catch (JSONValidationException j) { - // ok - } - } -} diff --git a/Mage.Stats/src/test/java/com/anygo/ws/rest/XMageStatsServiceTest.java b/Mage.Stats/src/test/java/com/anygo/ws/rest/XMageStatsServiceTest.java deleted file mode 100644 index 02a2951b12..0000000000 --- a/Mage.Stats/src/test/java/com/anygo/ws/rest/XMageStatsServiceTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.anygo.ws.rest; - -import com.xmage.ws.model.DomainErrors; -import com.xmage.ws.rest.services.XMageStatsService; -import com.xmage.ws.util.json.JSONParser; -import org.junit.Assert; -import org.junit.Test; - -import javax.ws.rs.core.Response; - -/** - * Testings XMage stats service without need to deploy. - * - * @author noxx - */ -public class XMageStatsServiceTest { - - @Test - public void testAddNewAndGet() throws Exception { - - XMageStatsService xMageStatsService = new XMageStatsService(); - - Response response = xMageStatsService.getAllStats(); - - JSONParser parser = new JSONParser(); - parser.parseJSON((String) response.getEntity()); - - Assert.assertEquals(DomainErrors.Errors.STATUS_NOT_FOUND.getCode(), parser.getInt("code")); - System.out.println("response = " + response.getEntity().toString()); - } - - -} diff --git a/Mage.Stats/src/test/java/com/anygo/ws/util/FileUtil.java b/Mage.Stats/src/test/java/com/anygo/ws/util/FileUtil.java deleted file mode 100644 index 163b418404..0000000000 --- a/Mage.Stats/src/test/java/com/anygo/ws/util/FileUtil.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.anygo.ws.util; - -import java.io.*; - -/** - * - * @author noxx - */ -public final class FileUtil { - - private FileUtil() {} - - public static String readFile(String file) throws IOException { - InputStream in = FileUtil.class.getResourceAsStream(file); - if (in == null) { - throw new FileNotFoundException("Couldn't find file " + file); - } - Reader fr = new InputStreamReader(in, "utf-8"); - - BufferedReader reader = new BufferedReader(fr); - String line; - StringBuilder stringBuilder = new StringBuilder(); - String ls = System.getProperty("line.separator"); - - while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - stringBuilder.append(ls); - } - - return stringBuilder.toString(); - } -} diff --git a/Mage.Tests/CommanderOviya.dck b/Mage.Tests/CommanderOviya.dck new file mode 100644 index 0000000000..ffbcf0dbfd --- /dev/null +++ b/Mage.Tests/CommanderOviya.dck @@ -0,0 +1,77 @@ +NAME:Oviya Test Deck +1 [C14:56] Loreseeker's Stone +1 [C14:54] Commander's Sphere +1 [C14:53] Assault Suit +1 [C14:52] Wolfcaller's Howl +1 [C14:51] Wave of Vitriol +1 [C14:50] Titania, Protector of Argoth +1 [C14:305] Oran-Rief, the Vastwood +1 [C14:227] Wren's Run Packmaster +1 [C14:226] Wood Elves +1 [C14:225] Wolfbriar Elemental +1 [C14:302] Jungle Basin +1 [C14:268] Skullclamp +1 [C14:224] Whirlwind +1 [C14:301] Havenwood Battleground +1 [C14:223] Wellwisher +1 [C14:267] Seer's Sundial +1 [C14:300] Haunted Fengraf +1 [C14:189] Drove of Elves +1 [C14:222] Tornado Elemental +1 [C14:221] Titania's Chosen +1 [C14:188] Desert Twister +1 [C14:220] Timberwatch Elf +1 [C14:187] Collective Unconscious +1 [C14:263] Predator, Flagship +1 [C14:186] Beastmaster Ascension +1 [C14:61] Myriad Landscape +1 [C14:316] Tranquil Thicket +1 [C14:315] Terramorphic Expanse +1 [C14:237] Emerald Medallion +1 [C14:311] Slippery Karst +1 [C14:199] Harrow +1 [C14:275] Swiftfoot Boots +1 [C14:198] Grim Flowering +1 [C14:197] Fresh Meat +1 [C14:196] Farhaven Elf +1 [C14:195] Ezuri, Renegade Leader +1 [C14:194] Essence Warden +1 [C14:193] Elvish Visionary +1 [C14:270] Sol Ring +1 [C14:192] Elvish Skysweeper +1 [C14:191] Elvish Mystic +1 [C14:190] Elvish Archdruid +1 [C14:209] Praetor's Counsel +1 [C14:208] Overwhelming Stampede +1 [C14:207] Overrun +1 [C14:206] Masked Admirers +1 [C14:205] Lys Alana Huntmaster +1 [C14:204] Llanowar Elves +1 [C14:203] Joraga Warcaller +1 [C14:202] Imperious Perfect +1 [C14:201] Immaculate Magistrate +1 [C14:289] Crystal Vein +1 [C14:200] Hunting Triad +1 [C14:45] Lifeblood Hydra +1 [C14:44] Grave Sifter +1 [C14:42] Creeperhulk +1 [C14:219] Thornweald Archer +1 [C14:49] Thunderfoot Baloth +1 [C14:218] Terastodon +1 [C14:217] Sylvan Safekeeper +1 [C14:48] Sylvan Offering +1 [C14:216] Sylvan Ranger +1 [C14:47] Song of the Dryads +1 [C14:215] Soul of the Harvest +1 [C14:46] Siege Behemoth +1 [C14:214] Silklash Spider +1 [C14:213] Reclamation Sage +25 [C14:334] Forest +1 [C14:212] Rampaging Baloths +1 [C14:211] Primordial Sage +1 [C14:210] Priest of Titania +1 [C14:298] Ghost Quarter +1 [C14:297] Gargoyle Castle +1 [C14:252] Moss Diamond +1 [C14:295] Evolving Wilds +SB: 1 [KLD:165] Oviya Pashiri, Sage Lifecrafter diff --git a/Mage.Tests/pom.xml b/Mage.Tests/pom.xml index 1f5e349640..33c0ad55c7 100644 --- a/Mage.Tests/pom.xml +++ b/Mage.Tests/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-tests @@ -64,6 +64,17 @@ mage-game-freeforall ${project.version} + + com.sun.xml.bind + jaxb-impl + 2.3.2 + + + + org.glassfish.jaxb + jaxb-runtime + 2.3.2 + diff --git a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java index ff7a6990ad..057c83b1f3 100644 --- a/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java +++ b/Mage.Tests/src/frozen/org/mage/test/clientside/base/MageBase.java @@ -1,13 +1,5 @@ package org.mage.test.clientside.base; -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.Date; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.match.MatchOptions; @@ -20,7 +12,15 @@ import mage.interfaces.callback.ClientCallback; import mage.server.Main; import mage.sets.Sets; import mage.util.Logging; -import mage.view.*; + +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Date; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; /** * Base for starting Mage server. Controls interactions between MageAPI and Mage @@ -189,9 +189,9 @@ public class MageBase { } catch (MageException ex) { logger.log(Level.SEVERE, null, ex); } catch (RemoteException ex) { - logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + logger.log(Level.SEVERE, "Unable connect to server - ", ex); } catch (NotBoundException ex) { - logger.log(Level.SEVERE, "Unable to connect to server - ", ex); + logger.log(Level.SEVERE, "Unable connect to server - ", ex); } } @@ -205,7 +205,7 @@ public class MageBase { } gameView = server.getGameView(gameId, sessionId, playerId); for (CardView card : gameView.getHand().values()) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { return true; } } @@ -224,7 +224,7 @@ public class MageBase { CardsView cards = gameView.getHand(); CardView cardToPlay = null; for (CardView card : cards.values()) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName)) { cardToPlay = card; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/abilitywords/RevoltTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/abilitywords/RevoltTest.java index b5e1ca8afd..c25d6cad2d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/abilitywords/RevoltTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/abilitywords/RevoltTest.java @@ -1,56 +1,56 @@ - -package org.mage.test.cards.abilities.abilitywords; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class RevoltTest extends CardTestPlayerBase { - - /** - * In a duel commander match, I played a turn 1 Narnam Renegade off a basic - * forest, and it entered the battlefield with a +1/+1 counter (it shouldn't - * have). - */ - @Test - public void testFalseCondition() { - // Deathtouch - // Revolt — Narnam Renegade enters the battlefield with a +1/+1 counter on it if a permanent you controlled left this battlefield this turn. - addCard(Zone.HAND, playerA, "Narnam Renegade", 1); // Creature 1/2 {G} - addCard(Zone.HAND, playerA, "Forest", 1); - - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Narnam Renegade"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPowerToughness(playerA, "Narnam Renegade", 1, 2); - } - - @Test - public void testTrueCondition() { - // Deathtouch - // Revolt — Narnam Renegade enters the battlefield with a +1/+1 counter on it if a permanent you controlled left this battlefield this turn. - addCard(Zone.HAND, playerA, "Narnam Renegade", 1); // Creature 1/2 {G} - // {T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library. - addCard(Zone.BATTLEFIELD, playerA, "Terramorphic Expanse", 1); - addCard(Zone.HAND, playerA, "Forest", 1); - - playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Narnam Renegade"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertGraveyardCount(playerA, "Terramorphic Expanse", 1); - assertPowerToughness(playerA, "Narnam Renegade", 2, 3); - } - -} + +package org.mage.test.cards.abilities.abilitywords; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class RevoltTest extends CardTestPlayerBase { + + /** + * In a duel commander match, I played a turn 1 Narnam Renegade off a basic + * forest, and it entered the battlefield with a +1/+1 counter (it shouldn't + * have). + */ + @Test + public void testFalseCondition() { + // Deathtouch + // Revolt — Narnam Renegade enters the battlefield with a +1/+1 counter on it if a permanent you controlled left this battlefield this turn. + addCard(Zone.HAND, playerA, "Narnam Renegade", 1); // Creature 1/2 {G} + addCard(Zone.HAND, playerA, "Forest", 1); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Narnam Renegade"); + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPowerToughness(playerA, "Narnam Renegade", 1, 2); + } + + @Test + public void testTrueCondition() { + // Deathtouch + // Revolt — Narnam Renegade enters the battlefield with a +1/+1 counter on it if a permanent you controlled left this battlefield this turn. + addCard(Zone.HAND, playerA, "Narnam Renegade", 1); // Creature 1/2 {G} + // {T}, Sacrifice Terramorphic Expanse: Search your library for a basic land card and put it onto the battlefield tapped. Then shuffle your library. + addCard(Zone.BATTLEFIELD, playerA, "Terramorphic Expanse", 1); + addCard(Zone.HAND, playerA, "Forest", 1); + + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}, Sacrifice"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Narnam Renegade"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Terramorphic Expanse", 1); + assertPowerToughness(playerA, "Narnam Renegade", 2, 3); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java index 5d4eca287e..62f5cef145 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/LicidAbilityTest.java @@ -59,7 +59,7 @@ public class LicidAbilityTest extends CardTestPlayerBase { execute(); - assertActionCount(playerA, 0); + assertActionsCount(playerA, 0); assertAbility(playerA, "Pillarfield Ox", HasteAbility.getInstance(), false); assertAbility(playerA, "Enraging Licid", new LicidAbility(new ColoredManaCost(ColoredManaSymbol.R), new ColoredManaCost(ColoredManaSymbol.R)), true); assertType("Enraging Licid", CardType.ENCHANTMENT, false); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java new file mode 100644 index 0000000000..8edd083aa4 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CurseOfShallowGravesTest.java @@ -0,0 +1,79 @@ +package org.mage.test.cards.abilities.curses; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class CurseOfShallowGravesTest extends CardTestPlayerBase { + + /* + Curse of Shallow Graves + {2}{B} + Enchant player + Whenever a player attacks enchanted player with one or more creatures, that attacking player may create a tapped 2/2 black Zombie creature token. + + bug: https://www.slightlymagic.net/forum/viewtopic.php?f=70&t=23164&p=229567#p229567 + */ + + @Test + public void test_AttackPlayer() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, "Curse of Shallow Graves"); + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Shallow Graves", playerB); + checkPermanentCount("curse on battle", 1, PhaseStep.BEGIN_COMBAT, playerA, "Curse of Shallow Graves", 1); + + // turn 1 - attack without token + attack(1, playerA, "Balduvian Bears", playerB); + setChoice(playerA, "No"); // don't create token + checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + + // turn 3 - attack with token + attack(3, playerA, "Balduvian Bears", playerB); + setChoice(playerA, "Yes"); // create token + checkPermanentCount("zombie 1", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 1); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 - 2); + } + + @Test + public void test_AttackPlaneswalker() { + // planeswalker only attack must be ignored by token's effect + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerA, "Curse of Shallow Graves"); + addCard(Zone.BATTLEFIELD, playerA, "Balduvian Bears", 1); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Chandra Ablaze", 1); // 5 loyalty + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Shallow Graves", playerB); + checkPermanentCount("curse on battle", 1, PhaseStep.BEGIN_COMBAT, playerA, "Curse of Shallow Graves", 1); + + // turn 1 - attack player without token + attack(1, playerA, "Balduvian Bears", playerB); + setChoice(playerA, "No"); // don't create token + checkPermanentCount("zombie 0", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + + // turn 3 - attack planeswalker (no choices at all) + attack(3, playerA, "Balduvian Bears", "Chandra Ablaze"); + //setChoice(playerA, "Yes"); + checkPermanentCount("zombie 0", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Zombie", 0); + + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2); + assertCounterCount(playerB, "Chandra Ablaze", CounterType.LOYALTY, 5 - 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java index 6d7715abb6..fd43fd2061 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/curses/CursesTest.java @@ -196,7 +196,7 @@ public class CursesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Curse of Bloodletting"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Bloodletting", playerB); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Thirst", playerB); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Curse of Thirst", playerB); setStopAt(2, PhaseStep.DRAW); execute(); @@ -284,9 +284,9 @@ public class CursesTest extends CardTestPlayerBase { // {2}{G/U}{G/U}: Put the top two cards of your library into your graveyard, then return a nonland card of an opponent's choice from your graveyard to your hand. activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}{G/U}{G/U}: Put the top two cards"); - castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Curse of Death's Hold", playerB); + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Curse of Death's Hold", playerB); - setStopAt(3, PhaseStep.END_COMBAT); + setStopAt(3, PhaseStep.END_TURN); execute(); assertLife(playerA, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java index 9fa648f438..c7c39c5f60 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/enters/BloodMoonTest.java @@ -192,9 +192,9 @@ public class BloodMoonTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Pithing Needle"); setChoice(playerB, "Blood Moon"); - playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Ghost Quarter"); + playLand(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ghost Quarter"); - setStopAt(2, PhaseStep.BEGIN_COMBAT); + setStopAt(2, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Blood Moon", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java index e6013f7d61..0f2193091e 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/equipped/EquipRestrictedTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.equipped; import mage.constants.PhaseStep; @@ -9,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EquipRestrictedTest extends CardTestPlayerBase { @@ -21,7 +19,7 @@ public class EquipRestrictedTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Leonin Scimitar"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: Attach target Equipment you control to target creature you control.", "Leonin Scimitar"); - addTarget(playerB, "Silvercout Lion"); + addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); @@ -43,7 +41,7 @@ public class EquipRestrictedTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Konda's Banner"); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{T}: Attach target Equipment you control to target creature you control.", "Konda's Banner"); - addTarget(playerB, "Silvercout Lion"); + addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java index a1e4302162..2f109ed839 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/CipherTest.java @@ -1,68 +1,66 @@ - -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 LevelX2 - */ -public class CipherTest extends CardTestPlayerBase { - - /** - * Produced a copy of the opponents Roil Elemental with Stolen Identity and - * used Cipher on that same token. The token's landfall ability then did - * trigger normally up to the point where a target creature could be - * selected. The selection was logged by XMage, but the effect simply did - * not work. The original Roil Elemental controlled by the other player - * worked as intended, though. - * - * Edit: Opponent was AI, if that helps. - */ - @Test - public void testStolenIdentity() { - addCard(Zone.BATTLEFIELD, playerA, "Island", 6); - addCard(Zone.HAND, playerA, "Mountain", 1); - - // Create a token that's a copy of target artifact or creature. - // Cipher (Then you may exile this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of the encoded card without paying its mana cost.) - addCard(Zone.HAND, playerA, "Stolen Identity"); // Sorcery {4}{U}{U} - - // Flying - // Landfall - Whenever a land enters the battlefield under your control, you may gain control of target creature for as long as you control Roil Elemental. - addCard(Zone.BATTLEFIELD, playerB, "Roil Elemental"); - addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox"); - addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", "Roil Elemental"); - setChoice(playerA, "Yes"); - - playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); - addTarget(playerA, "Silvercoat Lion"); // Triggered ability of copied Roil Elemental to gain control - - attack(3, playerA, "Roil Elemental"); // Creature 3/2 - addTarget(playerA, "Pillarfield Ox"); - - setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); - execute(); - - assertLife(playerB, 17); - - assertExileCount(playerA, "Stolen Identity", 1); - - assertPermanentCount(playerA, "Mountain", 1); - - assertPermanentCount(playerB, "Pillarfield Ox", 1); - assertPermanentCount(playerA, "Pillarfield Ox", 1); // a copy from the cipered Stolen Identity caused by the Roil Elelemtal Attack - - assertPermanentCount(playerB, "Silvercoat Lion", 0); - assertPermanentCount(playerA, "Silvercoat Lion", 1); // Gain control from triggered ability of the copied Roil Elemental ????? TARGET ??? - - assertPermanentCount(playerB, "Roil Elemental", 1); - assertPermanentCount(playerA, "Roil Elemental", 1); - - } -} + +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 LevelX2 + */ +public class CipherTest extends CardTestPlayerBase { + + /** + * Produced a copy of the opponents Roil Elemental with Stolen Identity and + * used Cipher on that same token. The token's landfall ability then did + * trigger normally up to the point where a target creature could be + * selected. The selection was logged by XMage, but the effect simply did + * not work. The original Roil Elemental controlled by the other player + * worked as intended, though. + * + * Edit: Opponent was AI, if that helps. + */ + @Test + public void testStolenIdentity() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 6); + addCard(Zone.HAND, playerA, "Mountain", 1); + + // Create a token that's a copy of target artifact or creature. + // Cipher (Then you may exile this spell card encoded on a creature you control. Whenever that creature deals combat damage to a player, its controller may cast a copy of the encoded card without paying its mana cost.) + addCard(Zone.HAND, playerA, "Stolen Identity"); // Sorcery {4}{U}{U} + + // Flying + // Landfall - Whenever a land enters the battlefield under your control, you may gain control of target creature for as long as you control Roil Elemental. + addCard(Zone.BATTLEFIELD, playerB, "Roil Elemental"); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox"); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + + // cast spell, create copy token, exile spell card and encode it to that token of Roil Elemental + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", "Roil Elemental"); + setChoice(playerA, "Yes"); // Cipher activate + addTarget(playerA, "Roil Elemental"); // Cipher target for encode + checkPermanentCount("playerA must have Roil Elemental", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Roil Elemental", 1); + checkPermanentCount("playerB must have Roil Elemental", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Roil Elemental", 1); + checkExileCount("Stolen Identity must be in exile zone", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Stolen Identity", 1); + + // Roil Elemental must activated on new land + playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Mountain"); + setChoice(playerA, "Yes"); // activate landfall to control opponent creature + addTarget(playerA, "Silvercoat Lion"); // Triggered ability of copied Roil Elemental to gain control + checkPermanentCount("must gain control of Lion", 3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion", 1); + checkPermanentCount("must lose control of Lion", 3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + + // on attack must activated ability to free cast + attack(5, playerA, "Roil Elemental"); + setChoice(playerA, "Yes"); // activate free cast of encoded card + checkPermanentCount("playerA must have 2 Roil Elemental", 5, PhaseStep.POSTCOMBAT_MAIN, playerA, "Roil Elemental", 2); + checkPermanentCount("playerB must have Roil Elemental", 5, PhaseStep.POSTCOMBAT_MAIN, playerB, "Roil Elemental", 1); + + setStopAt(5, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerB, 17); // -3 by Roil + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java index c75ebd9b23..07cf2e1902 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EchoTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; @@ -7,29 +6,27 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class EchoTest extends CardTestPlayerBase { - /* - * I flickered an Avalanche Riders with its Echo trigger on the stack with Restoration Angel. - * When the trigger resolved, my Riders was sacrificed, even though it should have been - * considered a new permanent. - */ + /* + * I flickered an Avalanche Riders with its Echo trigger on the stack with Restoration Angel. + * When the trigger resolved, my Riders was sacrificed, even though it should have been + * considered a new permanent. + */ @Test public void testEchoTriggerChecksIdentity() { - - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); - // Avalanche Riders Creature - Human Nomad 2/2 + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Avalanche Riders Creature - Human Nomad 2/2 {3}{R} // Haste // Echo (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.) // When Avalanche Riders enters the battlefield, destroy target land. addCard(Zone.HAND, playerA, "Avalanche Riders"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); // Restoration Angel {3}{W} // Flash // Flying @@ -37,12 +34,19 @@ public class EchoTest extends CardTestPlayerBase { // then return that card to the battlefield under your control. addCard(Zone.HAND, playerA, "Restoration Angel"); - addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + // cast Avalanche Riders and destroy forest + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Avalanche Riders"); + addTarget(playerA, "Forest"); + // Avalanche Riders go to echo, cast Restoration Angel to restore rider (do not apply echo with 4 mana) + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); + activateManaAbility(3, PhaseStep.UPKEEP, playerA, "{T}: Add {W}"); castSpell(3, PhaseStep.UPKEEP, playerA, "Restoration Angel", null, "Echo {3}{R} (At the beginning of your upkeep, if this came under your control since the beginning of your last upkeep, sacrifice it unless you pay its echo cost.)"); - addTarget(playerA, "Avalanche Riders"); + setChoice(playerA, "Yes"); // raider do restore setStopAt(3, PhaseStep.PRECOMBAT_MAIN); execute(); @@ -52,7 +56,9 @@ public class EchoTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Avalanche Riders", 1); assertPermanentCount(playerA, "Restoration Angel", 1); - assertPermanentCount(playerB, "Mountain", 0); + assertPermanentCount(playerB, "Forest", 0); + assertTappedCount("Plains", true, 4); + assertTappedCount("Mountain", true, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java index a1a900ba11..23abdec9c3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/FlashbackTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.abilities.keyword.TrampleAbility; @@ -9,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class FlashbackTest extends CardTestPlayerBase { @@ -71,10 +69,9 @@ public class FlashbackTest extends CardTestPlayerBase { } /** - * * Test Granting Flashback to spells with X in manacost which have targeting * requirements depending on the choice of X - * + *

    * Specific instance: Snapcaster Mage granting Flashback to Repeal */ @Test @@ -84,7 +81,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Repeal", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Repeal"); + addTarget(playerA, "Repeal"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); setChoice(playerA, "X=2"); @@ -100,10 +97,9 @@ public class FlashbackTest extends CardTestPlayerBase { } /** - * * Test Granting Flashback to spells with X in mana cost, where X has no * influence on targeting requirements - * + *

    * Specific instance: Snapcaster Mage granting Flashback to Blaze */ @Test @@ -115,7 +111,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Blaze", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Blaze"); + addTarget(playerA, "Blaze"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); setChoice(playerA, "X=1"); @@ -133,7 +129,6 @@ public class FlashbackTest extends CardTestPlayerBase { /** * My opponent put Iona on the battlefield using Unburial Rites, but my game * log didn't show me the color he has chosen. - * */ @Test public void testUnburialRites() { @@ -238,7 +233,7 @@ public class FlashbackTest extends CardTestPlayerBase { * Ancestral Vision has no casting cost (this is different to a casting cost * of {0}). Snapcaster Mage, for example, is able to give it flashback * whilst it is in the graveyard. - * + *

    * However the controller should not be able to cast Ancestral Visions from * the graveyard for {0} mana. */ @@ -348,7 +343,7 @@ public class FlashbackTest extends CardTestPlayerBase { // When Snapcaster Mage enters the battlefield, target instant or sorcery card in your graveyard gains flashback until end of turn. The flashback cost is equal to its mana cost. castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Terminate"); + addTarget(playerA, "Terminate"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback"); // Flashback Terminate addTarget(playerA, "Icefall Regent"); @@ -537,7 +532,7 @@ public class FlashbackTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Force of Will"); + addTarget(playerA, "Force of Will"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lightning Bolt", "Snapcaster Mage"); activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Flashback", null, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java index 75bbdb228d..55b8347561 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/ManifestTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.abilities.keywords; import mage.cards.Card; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -10,7 +10,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class ManifestTest extends CardTestPlayerBase { @@ -34,15 +33,16 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); assertLife(playerB, 20); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // not tapped - assertTapped("", false); + assertTapped(EmptyNames.FACE_DOWN_CREATURE.toString(), false); } /** @@ -66,13 +66,14 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); assertLife(playerB, 20); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // PlayerB's Silvercoat Lion should not have get -1/-1/ assertPermanentCount(playerB, "Silvercoat Lion", 1); assertPowerToughness(playerB, "Silvercoat Lion", 2, 2); @@ -101,6 +102,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -108,8 +110,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); // PlayerA's Pillarfield Ox should not have get -1/-1/ assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 2, 4); @@ -137,6 +139,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -144,8 +147,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @@ -173,6 +176,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -180,8 +184,8 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Reality Shift", 1); assertExileCount("Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); assertPowerToughness(playerA, "Foundry Street Denizen", 1, 1); } @@ -199,7 +203,6 @@ public class ManifestTest extends CardTestPlayerBase { // Strive — Silence the Believers costs more to cast for each target beyond the first. // Exile any number of target creatures and all Auras attached to them. addCard(Zone.HAND, playerB, "Silence the Believers"); - addTarget(playerB, ""); // Gore Swine {2}{R} // 4/1 addCard(Zone.LIBRARY, playerA, "Gore Swine"); @@ -210,10 +213,13 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Reality Shift", "Silvercoat Lion"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Silence the Believers", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerB); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silence the Believers", EmptyNames.FACE_DOWN_CREATURE.toString()); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -222,7 +228,7 @@ public class ManifestTest extends CardTestPlayerBase { assertExileCount("Silvercoat Lion", 1); assertExileCount("Gore Swine", 1); // no facedown creature is on the battlefield - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); for (Card card : currentGame.getExile().getAllCards(currentGame)) { if (card.getName().equals("Gore Swine")) { @@ -248,10 +254,11 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -261,7 +268,7 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); // a facedown creature is on the battlefield - assertPermanentCount(playerB, "", 1); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -284,12 +291,13 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "{5}{G}: Turn"); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -297,7 +305,7 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerB, "", 0); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerB, "Aerie Bowmasters", 1); assertPowerToughness(playerB, "Aerie Bowmasters", 4, 5); // 3/4 and the +1/+1 counter from Megamorph Permanent aerie = getPermanent("Aerie Bowmasters", playerB); @@ -308,7 +316,6 @@ public class ManifestTest extends CardTestPlayerBase { /** * When a Forest came manifested into play my Courser of Kruphix gained me a * life. - * */ @Test public void testManifestForest() { @@ -328,10 +335,11 @@ public class ManifestTest extends CardTestPlayerBase { skipInitShuffling(); activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{1}{B}, {T}, Sacrifice another creature"); - addTarget(playerB, "Silvercoat Lion"); + setChoice(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -339,13 +347,12 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Silvercoat Lion", 1); - assertPermanentCount(playerB, "", 1); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } /** * Whisperwood Elemental - Its sacrifice ability doesn't work.. - * */ @Test public void testWhisperwoodElemental() { @@ -365,6 +372,7 @@ public class ManifestTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); @@ -374,14 +382,13 @@ public class ManifestTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Whisperwood Elemental", 1); assertGraveyardCount(playerB, "Silvercoat Lion", 2); - assertPermanentCount(playerB, "", 2); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 2); } /** * I sacrificed a manifested face-down Smothering Abomination to Nantuko * Husk and it made me draw a card. - * */ @Test public void testDiesTriggeredAbilitiesOfManifestedCreatures() { @@ -409,10 +416,11 @@ public class ManifestTest extends CardTestPlayerBase { setChoice(playerB, "Silvercoat Lion"); activateAbility(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Sacrifice a creature"); - setChoice(playerB, ""); + setChoice(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); // no life gain assertLife(playerA, 20); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java index c3b430166c..50bf73e391 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/MorphTest.java @@ -1,11 +1,7 @@ - package org.mage.test.cards.abilities.keywords; import mage.cards.Card; -import mage.constants.CardType; -import mage.constants.PhaseStep; -import mage.constants.SubType; -import mage.constants.Zone; +import mage.constants.*; import mage.filter.Filter; import mage.game.permanent.Permanent; import org.junit.Assert; @@ -13,7 +9,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author levelX2 */ public class MorphTest extends CardTestPlayerBase { @@ -21,7 +16,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Tests if a creature with Morph is cast normal, it behaves as normal * creature - * */ @Test public void testCastMorphCreatureWithoutMorph() { @@ -60,8 +54,8 @@ public class MorphTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @@ -76,7 +70,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); setStopAt(3, PhaseStep.END_TURN); @@ -84,7 +78,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 18); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 5, 5); assertTapped("Pine Walker", false); @@ -94,7 +88,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Test that the triggered "turned face up" ability of Pine Walker does not * trigger as long as Pine Walker is not turned face up. - * */ @Test public void testDoesNotTriggerFaceDown() { @@ -110,8 +103,8 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Icefeather Aven", NO_TARGET, "Pine Walker", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{1}{G}{U}: Turn this face-down permanent face up."); setChoice(playerA, "No"); // Don't use return permanent to hand effect @@ -123,7 +116,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Pine Walker", 0); assertHandCount(playerA, "Icefeather Aven", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertPermanentCount(playerA, "Icefeather Aven", 1); assertTapped("Icefeather Aven", true); @@ -132,7 +125,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Test that Morph creature do not trigger abilities with their face up * attributes - * */ @Test public void testMorphedRemovesAttributesCreature() { @@ -156,14 +148,13 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 20); // and not 21 - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertPermanentCount(playerB, "Soldier of the Pantheon", 1); } /** * Test to copy a morphed 2/2 creature - * */ @Test public void testCopyAMorphedCreature() { @@ -182,22 +173,21 @@ public class MorphTest extends CardTestPlayerBase { castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Clever Impersonator"); setChoice(playerB, "Yes"); // use to copy a nonland permanent - addTarget(playerB, ""); // Morphed creature + addTarget(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); // Morphed creature setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); assertLife(playerB, 20); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); - assertPermanentCount(playerB, "", 1); - assertPowerToughness(playerB, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } /** - * * */ @Test @@ -229,7 +219,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Pine Walker", 0); assertHandCount(playerB, "Doomwake Giant", 0); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerB, "Doomwake Giant", 1); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 4, 4); @@ -241,7 +231,6 @@ public class MorphTest extends CardTestPlayerBase { * morph goes down to 1/1 correctly. If you unmorph the 2/2 and is also a * 2/2 after umorphing, the morph will be erroneously reduced to 0/0 and * die. - * */ @Test public void testDoomwakeGiantEffect() { @@ -271,7 +260,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Ponyback Brigade", 0); assertHandCount(playerB, "Doomwake Giant", 0); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Goblin", 3); assertPowerToughness(playerA, "Goblin", 1, 1, Filter.ComparisonScope.Any); assertPermanentCount(playerB, "Doomwake Giant", 1); @@ -283,7 +272,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Clone a Morph creature that was cast face down and meanwhile was turned * face up - * */ @Test public void testCloneFaceUpMorphEffect() { @@ -317,7 +305,6 @@ public class MorphTest extends CardTestPlayerBase { /** * Check that you can't counter a creature cast for it morph costs with * Disdainful Stroke if it's normal cmc > 3 - * */ @Test public void testCounterCastWithMorphEffect() { @@ -346,7 +333,7 @@ public class MorphTest extends CardTestPlayerBase { assertHandCount(playerA, "Sagu Mauler", 0); assertHandCount(playerB, "Disdainful Stroke", 1); // can't be cast - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -355,7 +342,6 @@ public class MorphTest extends CardTestPlayerBase { * the same name" does only effect one face down creature, also if multiple * on the battlefield. Because they have no name, they don't have the same * name. - * */ @Test public void testEchoingDecaySameNameEffect() { @@ -376,18 +362,23 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sagu Mauler", NO_TARGET, "Sagu Mauler", StackClause.WHILE_NOT_ON_STACK); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Echoing Decay", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Echoing Decay", EmptyNames.FACE_DOWN_CREATURE.toString()); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + showBattlefield("A battle after", 1, PhaseStep.END_TURN, playerA); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertLife(playerB, 20); + assertHandCount(playerB, "Echoing Decay", 0); + assertGraveyardCount(playerB, "Echoing Decay", 1); + assertHandCount(playerA, "Sagu Mauler", 0); assertHandCount(playerB, "Echoing Decay", 0); - - assertPermanentCount(playerA, "", 1); - + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertGraveyardCount(playerA, "Sagu Mauler", 1); } /** @@ -472,7 +463,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ashcloud Phoenix"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", ""); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -513,7 +504,7 @@ public class MorphTest extends CardTestPlayerBase { setChoice(playerA, "Yes"); // cast it face down as 2/2 creature attack(2, playerB, "Mirri, Cat Warrior"); - block(2, playerA, "", "Mirri, Cat Warrior"); + block(2, playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), "Mirri, Cat Warrior"); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); @@ -549,20 +540,27 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Akroma, Angel of Fury"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Supplant Form", ""); + showBattlefield("A battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B battle", 1, PhaseStep.POSTCOMBAT_MAIN, playerB); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Supplant Form"); + addTarget(playerB, EmptyNames.FACE_DOWN_CREATURE.toString()); + + showBattlefield("A battle end", 1, PhaseStep.END_TURN, playerA); + showBattlefield("B battle end", 1, PhaseStep.END_TURN, playerB); + setStopAt(1, PhaseStep.END_TURN); execute(); assertLife(playerB, 20); - assertGraveyardCount(playerB, "Supplant Form", 1); assertHandCount(playerA, "Akroma, Angel of Fury", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); + assertPermanentCount(playerA, "Akroma, Angel of Fury", 0); + assertGraveyardCount(playerB, "Supplant Form", 1); assertPermanentCount(playerB, "Akroma, Angel of Fury", 0); - assertPermanentCount(playerB, "", 1); - assertPowerToughness(playerB, "", 2, 2); - + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_TOKEN.toString(), 1); + assertPowerToughness(playerB, EmptyNames.FACE_DOWN_TOKEN.toString(), 2, 2); } /** @@ -588,7 +586,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerA, 20); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } @@ -613,7 +611,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pine Walker"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - attack(3, playerA, ""); + attack(3, playerA, EmptyNames.FACE_DOWN_CREATURE.toString()); activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "{4}{G}: Turn this face-down permanent face up."); setStopAt(3, PhaseStep.END_TURN); @@ -621,7 +619,7 @@ public class MorphTest extends CardTestPlayerBase { assertLife(playerB, 18); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertPermanentCount(playerA, "Pine Walker", 1); assertPowerToughness(playerA, "Pine Walker", 5, 5); assertTapped("Pine Walker", false); @@ -631,7 +629,7 @@ public class MorphTest extends CardTestPlayerBase { * Reflector Mage bouncing a creature that can be played as a morph should * not prevent the card from being replayed as a morph. Morph creatures are * nameless. - * + *

    * Reported bug: Face-up morph creatures that are bounced by Reflector Mage * should be able to be replayed as morphs without the "until the next turn" * restriction." @@ -666,18 +664,18 @@ public class MorphTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Reflector Mage", 1); assertPermanentCount(playerB, "Rattleclaw Mystic", 0); assertHandCount(playerB, "Rattleclaw Mystic", 0); // should have been replayed - assertPermanentCount(playerB, "", 1); // Rattleclaw played as a morph + assertPermanentCount(playerB, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); // Rattleclaw played as a morph } /** * Reflector Mage bouncing a creature that can be played as a morph should * not prevent the card from being replayed as a morph. Morph creatures are * nameless. - * + *

    * Reported bug: Face-up morph creatures that are bounced by Reflector Mage * should be able to be replayed as morphs without the "until the next turn" * restriction." - * + *

    * Testing bouncing a face-down creature played next turn face-up. */ @Test @@ -701,7 +699,6 @@ public class MorphTest extends CardTestPlayerBase { setChoice(playerA, "Yes"); // cast it face down as 2/2 creature castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Reflector Mage"); - addTarget(playerB, ""); castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Rattleclaw Mystic"); setChoice(playerA, "No"); // cast it face down as 2/2 creature @@ -790,7 +787,7 @@ public class MorphTest extends CardTestPlayerBase { assertGraveyardCount(playerB, "Fatal Push", 1); assertGraveyardCount(playerA, "Pine Walker", 1); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); } @@ -824,7 +821,7 @@ public class MorphTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertHandCount(playerA, 0); assertTappedCount("Island", true, 3); @@ -859,7 +856,7 @@ public class MorphTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Quicksilver Dragon"); setChoice(playerA, "Yes"); // cast it face down as 2/2 creature - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", ""); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", EmptyNames.FACE_DOWN_CREATURE.toString()); setStopAt(2, PhaseStep.UPKEEP); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OfferingTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OfferingTest.java index a909755a9d..37c9d12e65 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OfferingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/OfferingTest.java @@ -7,7 +7,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; public class OfferingTest extends CardTestPlayerBase { - private final static String nezumiPatron = "Patron of the Nezumi"; + private static final String nezumiPatron = "Patron of the Nezumi"; @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RiotTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RiotTest.java new file mode 100644 index 0000000000..5c0cd5bce1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/RiotTest.java @@ -0,0 +1,167 @@ +package org.mage.test.cards.abilities.keywords; + +import mage.abilities.keyword.HasteAbility; +import mage.abilities.keyword.RiotAbility; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author LevelX2 + */ +public class RiotTest extends CardTestPlayerBase { + + /** + * A creature with riot enters the battlefield with a +1/+1 counter on it or + * with haste, its controller's choice. This choice is made as the creature + * enters the battlefield, so no one can respond to the choice. + *

    + * The creature will have the chosen bonus the moment it enters the + * battlefield. If you choose to have the creature gain haste, it keeps + * haste even after the turn ends. This could matter if another player gains + * control of the creature later. + */ + @Test + public void RiotBoost() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + + // Riot (This creature enters the battleifled with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Rampaging Rendhorn", 1); // Creature {4}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rampaging Rendhorn"); + setChoice(playerA, "Yes"); // yes - counter + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Rampaging Rendhorn", 1); + assertPowerToughness(playerA, "Rampaging Rendhorn", 5, 5); + assertAbility(playerA, "Rampaging Rendhorn", HasteAbility.getInstance(), false); + + } + + @Test + public void RiotHaste() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 5); + + // Riot (This creature enters the battlefield with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Rampaging Rendhorn", 1); // Creature {4}{G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rampaging Rendhorn"); + setChoice(playerA, "No"); // no - haste + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Rampaging Rendhorn", 1); + assertPowerToughness(playerA, "Rampaging Rendhorn", 4, 4); + assertAbility(playerA, "Rampaging Rendhorn", HasteAbility.getInstance(), true); + } + + @Test + public void RiotRhythmOfTheWildBoost() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + // Creature spells you control can't be countered. + // Nontoken creatures you control have riot. + addCard(Zone.BATTLEFIELD, playerA, "Rhythm of the Wild", 1); + + // Riot (This creature enters the battleifled with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); // Creature {1}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + setChoice(playerA, "Yes"); // yes - counter + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 3, 3); + assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), false); + assertAbility(playerA, "Silvercoat Lion", new RiotAbility(), true); + } + + @Test + public void RiotRhythmOfTheWildHaste() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + + // Creature spells you control can't be countered. + // Nontoken creatures you control have riot. + addCard(Zone.BATTLEFIELD, playerA, "Rhythm of the Wild", 1); + + // Riot (This creature enters the battleifled with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); // Creature {1}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + setChoice(playerA, "No"); // no - haste + + setStopAt(2, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 2); + assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true); + assertAbility(playerA, "Silvercoat Lion", new RiotAbility(), true); + } + + @Test + public void RiotRhythmOfTheWildNotCastBoost() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + // Creature spells you control can't be countered. + // Nontoken creatures you control have riot. + addCard(Zone.BATTLEFIELD, playerA, "Rhythm of the Wild", 1); + + // Riot (This creature enters the battleifled with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Exhume", 1); // Each player returns a creature card from their graveyard to the battlefield + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); // Creature {1}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhume"); + setChoice(playerA, "Yes"); // yes - counter + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 3, 3); + assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), false); + assertAbility(playerA, "Silvercoat Lion", new RiotAbility(), true); + } + + @Test + public void RiotRhythmOfTheWildNotCastHaste() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + + // Creature spells you control can't be countered. + // Nontoken creatures you control have riot. + addCard(Zone.BATTLEFIELD, playerA, "Rhythm of the Wild", 1); + + // Riot (This creature enters the battleifled with your choice of a +1/+1 counter or haste.) + addCard(Zone.HAND, playerA, "Exhume", 1); // Each player returns a creature card from their graveyard to the battlefield + addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1); // Creature {1}{W} 2/2 + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exhume"); + setChoice(playerA, "No"); // no - haste + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 1); + assertPowerToughness(playerA, "Silvercoat Lion", 2, 2); + assertAbility(playerA, "Silvercoat Lion", HasteAbility.getInstance(), true); + assertAbility(playerA, "Silvercoat Lion", new RiotAbility(), true); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java index a5abc4c3f3..48f7759381 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/SpliceOnArcaneTest.java @@ -1,15 +1,14 @@ - package org.mage.test.cards.abilities.keywords; import mage.abilities.keyword.HasteAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class SpliceOnArcaneTest extends CardTestPlayerBase { @@ -17,7 +16,6 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { /** * Test that it works to cast Through the Breach by slicing it on an arcane * spell - * */ @Test public void testSpliceThroughTheBreach() { @@ -32,7 +30,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB); - setChoice(playerA, "Silvercoat Lion"); + // activate splice: yes -> card with splice ability -> new target for spliced ability + setChoice(playerA, "Yes"); + addTarget(playerA, "Through the Breach"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: put from hand to battlefield setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -60,8 +61,12 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + // cast arcane Lava Spike castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lava Spike", playerB); - addTarget(playerA, "Silvercoat Lion"); + // activate splice: yes -> card with splice ability -> new target for spliced ability + setChoice(playerA, "Yes"); + addTarget(playerA, "Torrent of Stone"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: 4 damage setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -97,8 +102,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nourishing Shoal"); + // activate splice: yes -> card with splice ability -> new target for spliced ability setChoice(playerA, "Yes"); - setChoice(playerA, "Silvercoat Lion"); + addTarget(playerA, "Through the Breach"); + addTarget(playerA, "Silvercoat Lion"); // target for spliced ability: put from hand to battlefield setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -117,12 +124,12 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { /** * Cards involved: Nourishing Shoal, Goryo's Vengeance, Griselbrand, * Terminate - * + *

    * I actually noticed this bug on the 1.4.3 client, but I didn't see it in * the change log for 1.4.4, so I assume it is still unknown. Also, it is a * bit of a rules corner case and I haven't seen anyone else report it, so * the players of this deck may actually not realize it's incorrect. - * + *

    * The scenario was that I cast a Nourishing Shoal with a Goryo's Vengeance * spliced to it targeting Griselbrand in my graveyard and exiling * Worldspine Wurm. My opponent responded with a Snapcaster Mage, so to @@ -132,7 +139,7 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { * resolve, it should have been countered due to no legal target. However, * it caused me to gain 11 life. It did not resurrect Griselbrand * (correctly), but it should have done nothing at all. - * + *

    * I include the info about the Terminate because thinking through, it could * be pertinent. I would guess what is going on here is one of two things. * Either the client doesn't recognize the Shoal with a spliced Vengeance as @@ -145,7 +152,10 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { * the error against a bot and update this report. */ @Test + @Ignore public void testCounteredBecauseOfNoLegalTarget() { + // TODO: rewrite test, it's wrong and misleading-- user report about Griselbrand was destroyed by Terminate after splice anounce, but tests don't use it at all (Griselbrand legal target all the time) + addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 8); // You may exile a green card with converted mana cost X from your hand rather than pay Nourishing Shoal's mana cost. @@ -174,5 +184,4 @@ public class SpliceOnArcaneTest extends CardTestPlayerBase { assertLife(playerB, 20); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java index 42628bca6c..4eaffcbd2b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/damage/SpitefulShadowsTest.java @@ -39,9 +39,11 @@ public class SpitefulShadowsTest extends CardTestPlayerBase { @Test public void testCard1() { - addCard(Zone.BATTLEFIELD, playerA, "Craw Wurm"); + addCard(Zone.BATTLEFIELD, playerA, "Craw Wurm"); // Creature 6/4 addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Enchant creature + // Whenever enchanted creature is dealt damage, it deals that much damage to its controller. addCard(Zone.HAND, playerA, "Spiteful Shadows"); addCard(Zone.HAND, playerA, "Lightning Bolt"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java index 705a274c36..e7aa5a62bd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/FiendHunterTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.oneshot.exile; import mage.constants.PhaseStep; @@ -70,10 +69,9 @@ public class FiendHunterTest extends CardTestPlayerBase { execute(); assertExileCount("Silvercoat Lion", 1); - assertPermanentCount(playerB, "Primeval Titan", 1); - assertPermanentCount(playerA, "Fiend Hunter", 1); assertPermanentCount(playerA, "Restoration Angel", 1); + assertPermanentCount(playerB, "Primeval Titan", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java index 3dcb48df92..19680d1380 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/oneshot/exile/OblivionSowerTest.java @@ -30,6 +30,7 @@ public class OblivionSowerTest extends CardTestPlayerBase { skipInitShuffling(); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oblivion Sower"); + addTarget(playerA, playerB); addTarget(playerA, "Canopy Vista^Canopy Vista^Canopy Vista"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java index 7901a6d153..74b14b0b2f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/LimitedCountedActivationsTest.java @@ -1,179 +1,180 @@ - -package org.mage.test.cards.abilities.other; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class LimitedCountedActivationsTest extends CardTestPlayerBase { - - /** - * Tests usage of ActivationInfo class - */ - @Test - public void testDragonWhelpActivatedThreeTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 15); - } - - @Test - public void testDragonWhelpActivatedFourTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 0); - assertGraveyardCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 14); - } - - @Test - public void testDragonWhelpActivatedFiveTimes() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertPermanentCount(playerA, "Dragon Whelp", 0); - assertGraveyardCount(playerA, "Dragon Whelp", 1); - - assertLife(playerA, 20); - assertLife(playerB, 13); - } - - @Test - public void testDragonWhelpTwoObjects() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. - addCard(Zone.HAND, playerA, "Reanimate", 1); - // Target creature gains haste until end of turn. - addCard(Zone.HAND, playerA, "Unnatural Speed", 1); - - addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); - // Destroy target nonartifact, nonblack creature. It can't be regenerated. - addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} - - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); - - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertGraveyardCount(playerA, "Unnatural Speed", 1); - assertGraveyardCount(playerA, "Reanimate", 1); - - assertGraveyardCount(playerB, "Terror", 1); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - assertPowerToughness(playerA, "Dragon Whelp", 2, 3); - assertGraveyardCount(playerA, "Dragon Whelp", 0); - - assertLife(playerA, 16); - assertLife(playerB, 15); - } - - @Test - public void testDragonWhelpDontSacrificeNewObject() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); - addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - // Flying - // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. - addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 - // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. - addCard(Zone.HAND, playerA, "Reanimate", 1); - // Target creature gains haste until end of turn. - addCard(Zone.HAND, playerA, "Unnatural Speed", 1); - - addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); - // Destroy target nonartifact, nonblack creature. It can't be regenerated. - addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} - - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); - - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); - - attack(1, playerA, "Dragon Whelp"); - - setStopAt(2, PhaseStep.UPKEEP); - execute(); - - assertGraveyardCount(playerA, "Unnatural Speed", 1); - assertGraveyardCount(playerA, "Reanimate", 1); - - assertGraveyardCount(playerB, "Terror", 1); - - assertPermanentCount(playerA, "Dragon Whelp", 1); - assertPowerToughness(playerA, "Dragon Whelp", 2, 3); - assertGraveyardCount(playerA, "Dragon Whelp", 0); - - assertLife(playerA, 16); - assertLife(playerB, 15); - } -} +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class LimitedCountedActivationsTest extends CardTestPlayerBase { + + /** + * Tests usage of ActivationInfo class + */ + @Test + public void testDragonWhelpActivatedThreeTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 15); + } + + @Test + public void testDragonWhelpActivatedFourTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 0); + assertGraveyardCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 14); + } + + @Test + public void testDragonWhelpActivatedFiveTimes() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Dragon Whelp", 0); + assertGraveyardCount(playerA, "Dragon Whelp", 1); + + assertLife(playerA, 20); + assertLife(playerB, 13); + } + + @Test + public void testDragonWhelpTwoObjects() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); + // Target creature gains haste until end of turn. + addCard(Zone.HAND, playerA, "Unnatural Speed", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); + + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerA, "Unnatural Speed", 1); + assertGraveyardCount(playerA, "Reanimate", 1); + + assertGraveyardCount(playerB, "Terror", 1); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + assertPowerToughness(playerA, "Dragon Whelp", 2, 3); + assertGraveyardCount(playerA, "Dragon Whelp", 0); + + assertLife(playerA, 16); + assertLife(playerB, 15); + } + + @Test + public void testDragonWhelpDontSacrificeNewObject() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 8); + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); + // Flying + // {R}: Dragon Whelp gets +1/+0 until end of turn. If this ability has been activated four or more times this turn, sacrifice Dragon Whelp at the beginning of the next end step. + addCard(Zone.BATTLEFIELD, playerA, "Dragon Whelp", 1); // 3/3 + // Put target creature card from a graveyard onto the battlefield under your control. You lose life equal to its converted mana cost. + addCard(Zone.HAND, playerA, "Reanimate", 1); + // Target creature gains haste until end of turn. + addCard(Zone.HAND, playerA, "Unnatural Speed", 1); + + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerB, "Terror", 1); // {1}{B} + + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + activateAbility(1, PhaseStep.UPKEEP, playerA, "{R}: "); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Terror", "Dragon Whelp"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Dragon Whelp"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Unnatural Speed", "Dragon Whelp"); + + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + activateAbility(1, PhaseStep.DECLARE_ATTACKERS, playerA, "{R}: "); + + attack(1, playerA, "Dragon Whelp"); + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertGraveyardCount(playerA, "Unnatural Speed", 1); + assertGraveyardCount(playerA, "Reanimate", 1); + + assertGraveyardCount(playerB, "Terror", 1); + + assertLife(playerA, 16); + assertLife(playerB, 15); + + assertGraveyardCount(playerA, "Dragon Whelp", 0); + + assertPermanentCount(playerA, "Dragon Whelp", 1); + assertPowerToughness(playerA, "Dragon Whelp", 2, 3); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java index 2c8d49e50a..3b4b2b2f35 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/NaturesWillTest.java @@ -7,6 +7,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -15,7 +16,7 @@ import java.io.FileNotFoundException; public class NaturesWillTest extends CardTestPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); playerC = createPlayer(game, playerC, "PlayerC"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/OathOfKayaTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/OathOfKayaTest.java new file mode 100644 index 0000000000..cd78d60a12 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/OathOfKayaTest.java @@ -0,0 +1,80 @@ +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class OathOfKayaTest extends CardTestPlayerBase { + + @Test + public void test_AttackingPlayer() { + // Whenever an opponent attacks a planeswalker you control with one or more creatures, + // Oath of Kaya deals 2 damage to that player and you gain 2 life. + addCard(Zone.BATTLEFIELD, playerB, "Oath of Kaya", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 2); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Dreadhorde General", 1); + + attack(1, playerA, "Grizzly Bears", playerB); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerB, "Liliana, Dreadhorde General", CounterType.LOYALTY, 6); + assertLife(playerA, 20); + assertLife(playerB, 20 - 2); + } + + @Test + public void test_AttackingPlaneswalker() { + // Whenever an opponent attacks a planeswalker you control with one or more creatures, + // Oath of Kaya deals 2 damage to that player and you gain 2 life. + addCard(Zone.BATTLEFIELD, playerB, "Oath of Kaya", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 2); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Dreadhorde General", 1); + + attack(1, playerA, "Grizzly Bears", "Liliana, Dreadhorde General"); + attack(1, playerA, "Grizzly Bears", "Liliana, Dreadhorde General"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerB, "Liliana, Dreadhorde General", CounterType.LOYALTY, 6 - 2 * 2); + assertLife(playerA, 20 - 2); + assertLife(playerB, 20 + 2); + } + + @Test + public void test_AttackingTwoPlaneswalkers() { + // Whenever an opponent attacks a planeswalker you control with one or more creatures, + // Oath of Kaya deals 2 damage to that player and you gain 2 life. + addCard(Zone.BATTLEFIELD, playerB, "Oath of Kaya", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears", 2); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Liliana, Dreadhorde General", 1); + addCard(Zone.BATTLEFIELD, playerB, "Vivien, Champion of the Wilds", 1); + + attack(1, playerA, "Grizzly Bears", "Liliana, Dreadhorde General"); + attack(1, playerA, "Grizzly Bears", "Vivien, Champion of the Wilds"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertCounterCount(playerB, "Liliana, Dreadhorde General", CounterType.LOYALTY, 6 - 2); + assertCounterCount(playerB, "Vivien, Champion of the Wilds", CounterType.LOYALTY, 4 - 2); + assertLife(playerA, 20 - 2); + assertLife(playerB, 20 + 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/PaupersCageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/PaupersCageTest.java new file mode 100644 index 0000000000..460b433fcf --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/PaupersCageTest.java @@ -0,0 +1,81 @@ +package org.mage.test.cards.abilities.other; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class PaupersCageTest extends CardTestPlayerBase { + + // Paupers' Cage + // At the beginning of each opponent's upkeep, if that player has two or fewer cards in hand, + // Paupers' Cage deals 2 damage to him or her. + + @Test + public void test_TooManyCards() { + addCard(Zone.BATTLEFIELD, playerA, "Paupers' Cage", 1); + // + addCard(Zone.HAND, playerA, "Island", 5); + addCard(Zone.HAND, playerB, "Island", 5); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + public void test_YouHaveFewCards() { + addCard(Zone.BATTLEFIELD, playerA, "Paupers' Cage", 1); + // + //addCard(Zone.HAND, playerA, "Island", 5); + addCard(Zone.HAND, playerB, "Island", 5); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + @Test + public void test_OpponentHaveFewCards() { + addCard(Zone.BATTLEFIELD, playerA, "Paupers' Cage", 1); + // + addCard(Zone.HAND, playerA, "Island", 5); + //addCard(Zone.HAND, playerB, "Island", 5); + + setStrictChooseMode(true); + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2); + } + + @Test + public void test_OpponentHaveFewCardsMultipleTurns() { + addCard(Zone.BATTLEFIELD, playerA, "Paupers' Cage", 1); + // + addCard(Zone.HAND, playerA, "Island", 5); + //addCard(Zone.HAND, playerB, "Island", 5); + + setStrictChooseMode(true); + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertLife(playerA, 20); + assertLife(playerB, 20 - 2 * 2); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java index 75f279af42..287f6828c7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/other/StormTheVaultTest.java @@ -7,6 +7,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -15,7 +16,7 @@ import java.io.FileNotFoundException; public class StormTheVaultTest extends CardTestPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); playerC = createPlayer(game, playerC, "PlayerC"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/CastFromLibraryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/CastFromLibraryTest.java index 6482f1731a..63380c9cce 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/CastFromLibraryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/CastFromLibraryTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.asthough; import mage.constants.PhaseStep; @@ -14,17 +13,16 @@ public class CastFromLibraryTest extends CardTestPlayerBase { /** * Any creature that you cast through Vizier of the Menagerie (ie the card - * on top of your deck) is castable at instant speed. This means that they + * on top of your deck) is cast-able at instant speed. This means that they * can be cast on your opponent's turn, before you scry (and thus change the * top card), or even right before the Vizier gets destroyed by a fatal push * or similar. */ @Test - public void testVizierOfTheMenagerie() { + public void testVizierOfTheMenagerieWithGenericCreatures() { addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 2); - // You may look at the top card of your library. (You may do this at any time.) // You may cast the top card of your library if it's a creature card. // You may spend mana as though it were mana of any type to cast creature spells. @@ -44,4 +42,28 @@ public class CastFromLibraryTest extends CardTestPlayerBase { assertLibraryCount(playerA, "Silvercoat Lion", 1); } + + @Test + public void testVizierOfTheMenagerieWithDryadArbor() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 8); + addCard(Zone.LIBRARY, playerA, "Dryad Arbor", 2); + // You may look at the top card of your library. (You may do this at any time.) + // You may cast the top card of your library if it's a creature card. + // You may spend mana as though it were mana of any type to cast creature spells. + addCard(Zone.HAND, playerA, "Vizier of the Menagerie", 1); // Creature 3/4 {3}{G} + + skipInitShuffling(); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vizier of the Menagerie"); + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Dryad Arbor"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Dryad Arbor"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Vizier of the Menagerie", 1); + assertPermanentCount(playerA, "Dryad Arbor", 0); // can't be cast, only played + assertLibraryCount(playerA, "Dryad Arbor", 2); + + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/IcequakeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/IcequakeTest.java new file mode 100644 index 0000000000..f3db7d6379 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/IcequakeTest.java @@ -0,0 +1,25 @@ +package org.mage.test.cards.conditional; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class IcequakeTest extends CardTestPlayerBase { + + @Test + public void testIcequakeOnSnowLand(){ + + addCard(Zone.BATTLEFIELD, playerB, "Snow-Covered Plains"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp",10); + addCard(Zone.HAND, playerA, "Icequake"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN,playerA, "Icequake", "Snow-Covered Plains"); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java index 0bbcfee3ab..8d272382fb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/conditional/TragicSlipTest.java @@ -1,4 +1,4 @@ - package org.mage.test.cards.conditional; +package org.mage.test.cards.conditional; import mage.constants.PhaseStep; import mage.constants.Zone; @@ -6,12 +6,8 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ - - - public class TragicSlipTest extends CardTestPlayerBase { @Test @@ -108,7 +104,7 @@ public class TragicSlipTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tragic Slip", "Silvercoat Lion"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Snapcaster Mage"); - setChoice(playerA, "Tragic Slip"); + addTarget(playerA, "Tragic Slip"); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Snapcaster Mage"); @@ -122,7 +118,7 @@ public class TragicSlipTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Snapcaster Mage", 0); assertExileCount("Tragic Slip", 1); assertPermanentCount(playerB, "Silvercoat Lion", 1); - assertPowerToughness(playerB, "Silvercoat Lion", 1,1); + assertPowerToughness(playerB, "Silvercoat Lion", 1, 1); assertGraveyardCount(playerB, "Tarmogoyf", 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/AuratouchedMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/AuratouchedMageTest.java index 387e141593..590ce9b6a7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/AuratouchedMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/AuratouchedMageTest.java @@ -12,15 +12,15 @@ public class AuratouchedMageTest extends CardTestPlayerBase { @Test public void testSearch() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.HAND, playerA, "Auratouched Mage"); - addCard(Zone.HAND, playerA, "Auratouched Mage"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Auratouched Mage"); + addCard(Zone.LIBRARY, playerA, "White Ward", 1); + addTarget(playerA, "White Ward"); - castSpell(0, PhaseStep.PRECOMBAT_MAIN, playerA, "Auratouched Mage"); - addCard(Zone.LIBRARY, playerA, "White Ward", 1); - setChoice(playerA, "White ward"); - setStopAt(0, PhaseStep.PRECOMBAT_MAIN); - execute(); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); } - } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GoblinGoliathTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GoblinGoliathTest.java new file mode 100644 index 0000000000..b3151c9535 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/GoblinGoliathTest.java @@ -0,0 +1,47 @@ +package org.mage.test.cards.continuous; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class GoblinGoliathTest extends CardTestPlayerBase { + + @Test + public void test_DoubleDamage() { + // test double damage on creature (no), on yourself (no) and on opponent (yes) by bold damage + + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 20); + // {3}{R}, {T}: If a source you control would deal damage to an opponent this turn, it deals double that damage to that player instead. + addCard(Zone.BATTLEFIELD, playerA, "Goblin Goliath"); + addCard(Zone.HAND, playerA, "Lightning Bolt", 4); // 3 damage + addCard(Zone.BATTLEFIELD, playerB, "Barktooth Warbeard"); // 6/5 + + // normal damage without ability + castSpell(1, PhaseStep.UPKEEP, playerA, "Lightning Bolt", playerB); + checkLife("normal damage to opponent", 1, PhaseStep.PRECOMBAT_MAIN, playerB, 20 - 3); + + // activate double damage + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{R}"); + // cast bolt to player (2x damage) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + checkLife("double damage to opponent", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + // cast bolt to creature (1x damage) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", "Barktooth Warbeard"); + checkPermanentCount("normal damage to creature", 1, PhaseStep.END_COMBAT, playerB, "Barktooth Warbeard", 1); + // cast bolt to yourself (1x damage) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerA); + checkLife("normal damage to yourself", 1, PhaseStep.END_COMBAT, playerA, 20 - 3); + + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 4); + assertLife(playerA, 20 - 3); + assertLife(playerB, 20 - 3 - 3 * 2); + assertGraveyardCount(playerB, "Barktooth Warbeard", 0); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java index 12b594c155..ce9d973e1b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/LandTypeChangingEffectsTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.continuous; import mage.abilities.keyword.IndestructibleAbility; @@ -11,7 +10,6 @@ import mage.counters.CounterType; import mage.filter.StaticFilters; import mage.game.permanent.Permanent; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -114,10 +112,6 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { String bloodmoon = "Blood Moon"; String canopyvista = "Canopy Vista"; - /* - TODO: NOTE: this test is currently failing due to bug in code. See issue #3072 - */ - //@Ignore @Test public void testBloodMoonBeforeUrborg() { // Blood Moon 2R @@ -147,10 +141,6 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { Assert.assertTrue("The mana the land can produce should be [{R}] but it's " + playerB.getManaAvailable(currentGame).toString(), playerB.getManaAvailable(currentGame).toString().equals("[{R}]")); } - /* - TODO: NOTE: this test is currently failing due to bug in code. See issue #3072 - */ - //@Ignore @Test public void testBloodMoonAfterUrborg() { // Blood Moon 2R @@ -186,6 +176,7 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { In terms of time-stamp order, Urborg was down first, then Kormus Bell, then Quicksilver. When I put a flood counter on a basic swamp, it would become a 0/0 instead of a 1/1 and die. */ + @Test public void testCormusBellAfterUrborg() { // Land - Legendary @@ -250,19 +241,19 @@ public class LandTypeChangingEffectsTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Blood Sun"); // all lands lose all abilities except for mana-producing addCard(Zone.BATTLEFIELD, playerA, "Stormtide Leviathan"); // all lands are islands in addition to their other types addCard(Zone.BATTLEFIELD, playerA, "Darksteel Citadel"); // land has indestructible ability - + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); execute(); - + Permanent darksteel = getPermanent("Darksteel Citadel", playerA.getId()); Assert.assertNotNull(darksteel); Assert.assertFalse(darksteel.getAbilities().contains(IndestructibleAbility.getInstance())); // The ability is removed - + /* If a continuous effect has started applying in an earlier layer, it will continue to apply in later layers even if the ability that created that effect has been removed. Urborg ability is applied in the 4th layer. The Blood Sun works in the 6th. So the effect still applies to the lands. - */ + */ assertType(urborgtoy, CardType.LAND, SubType.SWAMP); assertType("Mountain", CardType.LAND, SubType.SWAMP); assertType(urborgtoy, CardType.LAND, SubType.ISLAND); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java index ba821b9a54..8bfe2420bd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/continuous/MasterThiefTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.continuous; +import mage.abilities.keyword.VigilanceAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author JayDi85 */ public class MasterThiefTest extends CardTestPlayerBase { @@ -42,7 +41,7 @@ public class MasterThiefTest extends CardTestPlayerBase { // cast and get control of shield castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Master Thief"); - addTarget(playerB, "Accorder's Shield"); + addTarget(playerA, "Accorder's Shield"); // sacrifice Master Thief -- must lost control activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a creature"); @@ -72,11 +71,13 @@ public class MasterThiefTest extends CardTestPlayerBase { // cast and get control of shield castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Master Thief"); - addTarget(playerB, "Accorder's Shield"); + addTarget(playerA, "Accorder's Shield"); + checkPermanentCount("must control shield", 1, PhaseStep.BEGIN_COMBAT, playerA, "Accorder's Shield", 1); // attach and boost activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Equip {3}"); addTarget(playerA, "Bearer of the Heavens"); + checkAbility("bear must have boost", 1, PhaseStep.END_TURN, playerA, "Bearer of the Heavens", VigilanceAbility.class, true); // sacrifice Master Thief -- must lost control, but attached and boosted activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice a creature"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/DackFaydenTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/DackFaydenTest.java index ec07d31058..643b869a3a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/DackFaydenTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/DackFaydenTest.java @@ -59,7 +59,7 @@ public class DackFaydenTest extends CardTestPlayerBase { castSpell(10, PhaseStep.PRECOMBAT_MAIN, playerA, "Gut Shot", "Ornithopter"); castSpell(10, PhaseStep.PRECOMBAT_MAIN, playerA, "Unsummon", "Ornithopter", "Gut Shot", StackClause.WHILE_NOT_ON_STACK); - castSpell(10, PhaseStep.PRECOMBAT_MAIN, playerB, "Ornithopter"); + castSpell(10, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ornithopter"); setStopAt(10, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java index 59009ff581..8d5cbf28f5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ExileAndReturnUnderYourControl.java @@ -1,5 +1,6 @@ package org.mage.test.cards.control; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Assert; @@ -9,7 +10,7 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** * Tests the effect: - Exile target creature you control, then return that card * to the battlefield under your control - * + *

    * This effect grants you permanent control over the returned creature. So you * mail steal opponent's creature with "Act of Treason" and then use this effect * for permanent control effect. @@ -103,8 +104,8 @@ public class ExileAndReturnUnderYourControl extends CardTestPlayerBase { assertExileCount("Secret Plans", 0); assertPermanentCount(playerA, "Secret Plans", 1); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 3); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 3); } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java index 02341d56f5..c22fe6f299 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopyCreatureCardToTokenImplTest.java @@ -7,6 +7,7 @@ package org.mage.test.cards.copy; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -23,6 +24,7 @@ public class CopyCreatureCardToTokenImplTest extends CardTestPlayerBase { * either. */ @Test + @Ignore public void testTokenTriggeresETBEffect() { // Flying // Sphinx spells you cast cost {2} less to cast. diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java index 2ec1c261ed..9c39f31353 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CopySpellTest.java @@ -1,14 +1,13 @@ - package org.mage.test.cards.copy; import mage.abilities.keyword.FlyingAbility; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CopySpellTest extends CardTestPlayerBase { @@ -17,23 +16,38 @@ public class CopySpellTest extends CardTestPlayerBase { public void copyChainOfVapor() { // Return target nonland permanent to its owner's hand. Then that permanent's controller may sacrifice a land. If the player does, he or she may copy this spell and may choose a new target for that copy. addCard(Zone.HAND, playerA, "Chain of Vapor", 1); - addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Island", 10); - addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 10); - addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); - addCard(Zone.BATTLEFIELD, playerB, "Island", 1); + addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 10); + addCard(Zone.BATTLEFIELD, playerB, "Island", 10); + // start chain from A - return pillar to hand castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Chain of Vapor", "Pillarfield Ox"); - setChoice(playerB, "Yes"); - addTarget(playerB, "Silvercoat Lion"); + // chain 1 - B can return + addTarget(playerB, "Island"); // select a land to sacrifice + setChoice(playerB, "Yes"); // want to copy spell + setChoice(playerB, "Yes"); // want to change target + addTarget(playerB, "Silvercoat Lion"); // new target after copy + // chain 2 - A can return + addTarget(playerA, "Island"); // select a land to sacrifice + setChoice(playerA, "Yes"); // want to copy spell + setChoice(playerA, "Yes"); // want to change target + addTarget(playerA, "Pillarfield Ox"); // new target after copy + // stop the chain by B + addTarget(playerB, TestPlayer.TARGET_SKIP); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertGraveyardCount(playerB, "Island", 1); - assertHandCount(playerB, "Pillarfield Ox", 1); assertHandCount(playerA, "Silvercoat Lion", 1); + assertHandCount(playerB, "Pillarfield Ox", 2); + assertPermanentCount(playerA, "Silvercoat Lion", 10 - 1); + assertPermanentCount(playerB, "Pillarfield Ox", 10 - 2); + assertGraveyardCount(playerA, "Island", 1); + assertGraveyardCount(playerB, "Island", 1); } @Test @@ -135,7 +149,7 @@ public class CopySpellTest extends CardTestPlayerBase { * before it is cast and therefore before Zada's ability triggers, e.g. * Desperate Ritual spliced onto Into the Fray should generate 3 red mana * for every creature i control. - * + *

    * 702.46a Splice is a static ability that functions while a card is in your * hand. “Splice onto [subtype] [cost]” means “You may reveal this card from * your hand as you cast a [subtype] spell. If you do, copy this card's text @@ -184,7 +198,7 @@ public class CopySpellTest extends CardTestPlayerBase { * {4}{U} Enchantment (Enchant Player) Whenever enchanted player casts an * instant or sorcery spell, each other player may copy that spell and may * choose new targets for the copy he or she controls. - * + *

    * Reported bug: "A player with Curse of Echoes attached to them played * Bribery and the player who controlled the curse had control of all 3 * copies. This seems to be the case for all spells." diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java index ec85a76ada..34c014aed2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/CryptoplasmTest.java @@ -52,15 +52,24 @@ public class CryptoplasmTest extends CardTestPlayerBase { // At the beginning of your upkeep, you may have Cryptoplasm become a copy of another target creature. If you do, Cryptoplasm gains this ability. addCard(Zone.BATTLEFIELD, playerB, "Cryptoplasm", 1); // {1}{U}{U} + // turn 2 - prepare (crypto to paladin, footsteps to crypto) + // crypto: copy as paladin on upkeep + setChoice(playerB, "Yes"); + addTarget(playerB, "Sigiled Paladin"); + // footsteps: enchant copy of paladin (crypto) castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Followed Footsteps"); addTarget(playerB, "Sigiled Paladin[only copy]"); + // turn 4 - ignore crypto ask for new copy + setChoice(playerB, "No"); + setStopAt(4, PhaseStep.END_TURN); execute(); assertPermanentCount(playerB, "Followed Footsteps", 1); - assertPermanentCount(playerB, "Cryptoplasm", 0); - assertPermanentCount(playerB, "Sigiled Paladin", 2); + assertPermanentCount(playerB, "Cryptoplasm", 0); // it's a copy + assertPermanentCount(playerB, "Sigiled Paladin", 2); // crypto as copy + footstep token as copy + assertPermanentCount(playerA, "Sigiled Paladin", 1); // original } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java new file mode 100644 index 0000000000..bbe31c5770 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildCopyTest.java @@ -0,0 +1,127 @@ +package org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class EssenceOfTheWildCopyTest extends CardTestPlayerBase { + + // Essence of the Wild {3}{G}{G}{G} + // Creatures you control enter the battlefield as a copy of Essence of the Wild. + + private Permanent findCopyPermanent(Game game, int num) { + int currentCopyNumber = 1; + for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { + if (perm.isCopy()) { + if (currentCopyNumber == num) { + return perm; + } + currentCopyNumber++; + } + } + Assert.fail("copy " + num + " must exist"); + return null; + } + + private Permanent findOriginPermanent(Game game, String permName) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { + if (!perm.isCopy() && perm.getName().equals(permName)) { + return perm; + } + } + Assert.fail("can't find origin"); + return null; + } + + @Test + public void test_CopyCreature() { + // essence copy creature + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 2); + + Permanent copy = findCopyPermanent(currentGame, 1); + Assert.assertEquals("must have 6 p/t", 6, copy.getPower().getValue()); + Assert.assertEquals("must have 6 p/t", 6, copy.getToughness().getValue()); + } + + @Test + @Ignore // TODO: enable and fix random failes with replace effects + public void test_CopyCreatureByCopied() { + // essence copy to creature 1 -> creature 1 copy to creature + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 3); + + Permanent copy1 = findCopyPermanent(currentGame, 1); + Permanent copy2 = findCopyPermanent(currentGame, 2); + Assert.assertFalse("copy must be diffent", copy1.equals(copy2)); + Assert.assertEquals("copy 1 must have 6 p/t", 6, copy1.getPower().getValue()); + Assert.assertEquals("copy 1 must have 6 p/t", 6, copy1.getToughness().getValue()); + Assert.assertEquals("copy 2 must have 6 p/t", 6, copy2.getPower().getValue()); + Assert.assertEquals("copy 2 must have 6 p/t", 6, copy2.getToughness().getValue()); + } + + @Test + public void test_CopyCreatureWithContinuousEffect() { + // essence with -1/-1 must copy creature with normal p/t + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Liliana, Death Wielder", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + // apply -1/-1 effect (+2: Put a -1/-1 counter on up to one target creature.) + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "+2:", "Essence of the Wild"); + + // copy + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 2); + + Permanent origin = findOriginPermanent(currentGame, "Essence of the Wild"); + Permanent copy = findCopyPermanent(currentGame, 1); + Assert.assertEquals("origin must have 5 p/t", 6 - 1, origin.getPower().getValue()); + Assert.assertEquals("origin must have 5 p/t", 6 - 1, origin.getToughness().getValue()); + Assert.assertEquals("copy must have 6 p/t", 6, copy.getPower().getValue()); + Assert.assertEquals("copy must have 6 p/t", 6, copy.getToughness().getValue()); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java new file mode 100644 index 0000000000..19d3072581 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildTest.java @@ -0,0 +1,127 @@ +package org.mage.test.cards.copy; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class EssenceOfTheWildTest extends CardTestPlayerBase { + + // Essence of the Wild {3}{G}{G}{G} + // Creatures you control enter the battlefield as a copy of Essence of the Wild. + + private Permanent findCopyPermanent(Game game, int num) { + int currentCopyNumber = 1; + for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { + if (perm.isCopy()) { + if (currentCopyNumber == num) { + return perm; + } + currentCopyNumber++; + } + } + Assert.fail("copy " + num + " must exist"); + return null; + } + + private Permanent findOriginPermanent(Game game, String permName) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { + if (!perm.isCopy() && perm.getName().equals(permName)) { + return perm; + } + } + Assert.fail("can't find origin"); + return null; + } + + @Test + public void test_CopyCreature() { + // essence copy creature + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 2); + + Permanent copy = findCopyPermanent(currentGame, 1); + Assert.assertEquals("must have 6 p/t", 6, copy.getPower().getValue()); + Assert.assertEquals("must have 6 p/t", 6, copy.getToughness().getValue()); + } + + @Test + @Ignore // TODO: enable for copy effect tests and random replacement effects fix + public void test_CopyCreatureByCopied() { + // essence copy to creature 1 -> creature 1 copy to creature + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 3); + + Permanent copy1 = findCopyPermanent(currentGame, 1); + Permanent copy2 = findCopyPermanent(currentGame, 2); + Assert.assertFalse("copy must be diffent", copy1.equals(copy2)); + Assert.assertEquals("copy 1 must have 6 p/t", 6, copy1.getPower().getValue()); + Assert.assertEquals("copy 1 must have 6 p/t", 6, copy1.getToughness().getValue()); + Assert.assertEquals("copy 2 must have 6 p/t", 6, copy2.getPower().getValue()); + Assert.assertEquals("copy 2 must have 6 p/t", 6, copy2.getToughness().getValue()); + } + + @Test + public void test_CopyCreatureWithContinuusEffect() { + // essence with -1/-1 must copy creature with normal p/t + addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Liliana, Death Wielder", 1); + // + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.HAND, playerA, "Silvercoat Lion", 1); + + // apply -1/-1 effect (+2: Put a -1/-1 counter on up to one target creature.) + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "+2:", "Essence of the Wild"); + + // copy + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Silvercoat Lion"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Silvercoat Lion", 0); + assertPermanentCount(playerA, "Essence of the Wild", 2); + + Permanent origin = findOriginPermanent(currentGame, "Essence of the Wild"); + Permanent copy = findCopyPermanent(currentGame, 1); + Assert.assertEquals("origin must have 5 p/t", 6 - 1, origin.getPower().getValue()); + Assert.assertEquals("origin must have 5 p/t", 6 - 1, origin.getToughness().getValue()); + Assert.assertEquals("copy must have 6 p/t", 6, copy.getPower().getValue()); + Assert.assertEquals("copy must have 6 p/t", 6, copy.getToughness().getValue()); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildtest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildtest.java deleted file mode 100644 index b389a74beb..0000000000 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/EssenceOfTheWildtest.java +++ /dev/null @@ -1,77 +0,0 @@ - -package org.mage.test.cards.copy; - -import mage.constants.PhaseStep; -import mage.constants.Zone; -import mage.filter.Filter; -import org.junit.Test; -import org.mage.test.serverside.base.CardTestPlayerBase; - -/** - * - * @author LevelX2 - */ -public class EssenceOfTheWildtest extends CardTestPlayerBase { - - /** - * Essence of the Wild does not seem to correctly apply its copy effect to - * your creatures. Upon entering the battlefield the other creatures had a - * small symbol at the top right of their card to view the original card - - * however, both 'sides' showed only the same, original card. - * Power/Toughness and other abilities were also still those of the original - * cards. - * - * Note: This was observed in a deck controlled by the computer when testing - * other decks. - * - */ - @Test - public void testCreatureCast() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // Creatures you control enter the battlefield as a copy of Essence of the Wild. - addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild"); // 6/6 - addCard(Zone.HAND, playerA, "Silvercoat Lion"); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPermanentCount(playerA, "Essence of the Wild", 2); - assertPowerToughness(playerA, "Essence of the Wild", 6, 6, Filter.ComparisonScope.All); - - } - - /** - * I control Essence of the Wild and Back from the Brink on the battlefield, - * and start using Back from the Brink on the creatures in my graveyard. The - * creature tokens don't enter the battlefield as copies of Essence of the - * Wild. - * - * Since it's an unusual situation, I checked around if there's something in - * the rules that would prevent this combo from working. Found this link and - * they confirmed that it should work, the tokens should come into play as - * 6/6s. - */ - @Test - public void testWithBackFromTheBrink() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // Creatures you control enter the battlefield as a copy of Essence of the Wild. - addCard(Zone.BATTLEFIELD, playerA, "Essence of the Wild"); // 6/6 - // Exile a creature card from your graveyard and pay its mana cost: Create a tokenonto the battlefield that's a copy of that card. Activate this ability only any time you could cast a sorcery. - addCard(Zone.BATTLEFIELD, playerA, "Back from the Brink"); // Enchantment - - addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion"); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Exile a creature card"); - setChoice(playerA, "Silvercoat Lion"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertExileCount("Silvercoat Lion", 1); - assertPermanentCount(playerA, "Essence of the Wild", 2); - assertPowerToughness(playerA, "Essence of the Wild", 6, 6, Filter.ComparisonScope.All); - - } -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java index c49391815c..810e5ea628 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/IsochronScepterTest.java @@ -44,10 +44,12 @@ public class IsochronScepterTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Lightning Bolt"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Isochron Scepter"); - addTarget(playerA, "Lightning Bolt"); + setChoice(playerA, "Yes"); // use imprint + setChoice(playerA, "Lightning Bolt"); // target for imprint (excile from hand) + + // copy and cast imprinted card activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}, {T}:"); setChoice(playerA, "Yes"); - setChoice(playerA, "Yes"); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java index ad5641993a..a47e832365 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/ReversalOfFortuneTest.java @@ -28,8 +28,8 @@ public class ReversalOfFortuneTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Lightning Bolt"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reversal of Fortune", playerB); - addTarget(playerA, "Lightning Bolt"); - setChoice(playerA, "Yes"); + setChoice(playerA, "Lightning Bolt"); // select to copy + setChoice(playerA, "Yes"); // cast copy setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java index 5421dfca18..0ac2a0db44 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SharuumTheHegemonTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.copy; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ @@ -15,34 +13,33 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { /** * http://www.slightlymagic.net/forum/viewtopic.php?f=70&t=16732&p=172937&hilit=Sharuum+the+Hegemon#p172920 - * - * My Sharuum EDH deck uses the standard Sharuum + Clone Effect + Blood Artist as one of the win - * conditions, but when I have Sharuum in plan and play a Clever Impersonator, targetting Sharuum - * and choose to keep the Clever Impersonator and send the original Sharuum to the graveyard Xmage - * never gives me the option to use the Sharuum Ability that the Clever Impersonator should get, + *

    + * My Sharuum EDH deck uses the standard Sharuum + Clone Effect + Blood Artist as one of the win + * conditions, but when I have Sharuum in plan and play a Clever Impersonator, targetting Sharuum + * and choose to keep the Clever Impersonator and send the original Sharuum to the graveyard Xmage + * never gives me the option to use the Sharuum Ability that the Clever Impersonator should get, * making the combo not work. - * - * I run a Sharuum EDH deck that wins by cloning Sharuum for infinite death triggers. I know the rules + *

    + * I run a Sharuum EDH deck that wins by cloning Sharuum for infinite death triggers. I know the rules * check out on this combo irl, but no matter how I stack the triggers for cloning Sharuum and her enter * the battlefield effect it does not work. It either ends with Sharuum in my graveyard or the reanimate * effect hits the stack before the legend rule applies - * - [1] Sharuum the Hegemon is on the battlefield. - [2] You cast Clone (or any other Clone-like card). - [3] When Clone resolves, you choose Sharuum for the replacement effect. - [4] Since fake-Sharuum entered the battlefield, its EtB ability triggers. - [5] State-based actions are checked and you are prompted to keep one Sharuum. You sacrifice real-Sharuum. - * 116.2a Triggered abilities can trigger at any time, including while a spell is being cast, an ability is being activated, or a spell or - * ability is resolving. (See rule 603, "Handling Triggered Abilities.") However, nothing actually happens at the time an ability triggers. - * Each time a player would receive priority, each ability that has triggered but hasn't yet been put on the stack is put on the stack. See rule 116.5 - * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, - * "State-Based Actions"), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack - * (see rule 603, "Handling Triggered Abilities"). These steps repeat in order until no further state-based actions are performed and no abilities - * trigger. Then the player who would have received priority does so. - [6] Once State-based actions are finished, triggered abilities go on the stack. You put the EtB from [4] choosing real-Sharuum. - [7] Real-Sharuum enters the battlefield. - [8] Rinse and repeat. - * + *

    + * [1] Sharuum the Hegemon is on the battlefield. + * [2] You cast Clone (or any other Clone-like card). + * [3] When Clone resolves, you choose Sharuum for the replacement effect. + * [4] Since fake-Sharuum entered the battlefield, its EtB ability triggers. + * [5] State-based actions are checked and you are prompted to keep one Sharuum. You sacrifice real-Sharuum. + * 116.2a Triggered abilities can trigger at any time, including while a spell is being cast, an ability is being activated, or a spell or + * ability is resolving. (See rule 603, "Handling Triggered Abilities.") However, nothing actually happens at the time an ability triggers. + * Each time a player would receive priority, each ability that has triggered but hasn't yet been put on the stack is put on the stack. See rule 116.5 + * 116.5. Each time a player would get priority, the game first performs all applicable state-based actions as a single event (see rule 704, + * "State-Based Actions"), then repeats this process until no state-based actions are performed. Then triggered abilities are put on the stack + * (see rule 603, "Handling Triggered Abilities"). These steps repeat in order until no further state-based actions are performed and no abilities + * trigger. Then the player who would have received priority does so. + * [6] Once State-based actions are finished, triggered abilities go on the stack. You put the EtB from [4] choosing real-Sharuum. + * [7] Real-Sharuum enters the battlefield. + * [8] Rinse and repeat. */ @Test public void testCloneTriggered() { @@ -59,17 +56,26 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { setChoice(playerA, "Sharuum the Hegemon"); // what creature to clone addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); - - addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep - setChoice(playerA, "Yes"); + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum + + addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep + setChoice(playerA, "Whenever {this} or another creature dies"); // blood first + addTarget(playerA, playerB); // damage by blood + setChoice(playerA, "Yes"); // return + addTarget(playerA, "Sharuum the Hegemon"); // return real sharuum addTarget(playerA, "Sharuum the Hegemon[only copy]"); // which legend to keep setChoice(playerA, "No"); // Don't use it anymore - + setStopAt(1, PhaseStep.END_TURN); execute(); @@ -77,7 +83,6 @@ public class SharuumTheHegemonTest extends CardTestPlayerBase { assertLife(playerB, 16); - } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java new file mode 100644 index 0000000000..b11ff19852 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SparkDoubleTest.java @@ -0,0 +1,157 @@ +package org.mage.test.cards.copy; + +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.CardType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.permanent.Permanent; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class SparkDoubleTest extends CardTestPlayerBase { + + private Permanent findDoubleSparkPermanent(Game game) { + for (Permanent perm : game.getBattlefield().getAllActivePermanents()) { + if (perm.isCopy()) { + return perm; + } + } + Assert.fail("spark must exist"); + return null; + } + + @Test + public void test_CopyCreatureAndGetOneCounter() { + addCard(Zone.BATTLEFIELD, playerA, "Abbey Griffin", 1); // 2/2, fly, vig + // + addCard(Zone.HAND, playerA, "Spark Double"); // {3}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spark Double"); + setChoice(playerA, "Yes"); + setChoice(playerA, "Abbey Griffin"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Abbey Griffin", 2); + + Permanent spark = findDoubleSparkPermanent(currentGame); + Assert.assertEquals("must add 1 counter", 1, spark.getCounters(currentGame).getCount(CounterType.P1P1)); + // + Assert.assertEquals("must copy p/t", 3, spark.getPower().getValue()); + Assert.assertEquals("must copy p/t", 3, spark.getToughness().getValue()); + Assert.assertTrue("must copy ability", spark.getAbilities().contains(VigilanceAbility.getInstance())); + } + + @Test + public void test_CopyPlaneswalkerWithoutLegendaryWithOneCounter() { + addCard(Zone.BATTLEFIELD, playerA, "Ajani, the Greathearted", 1); + // + addCard(Zone.HAND, playerA, "Spark Double"); // {3}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spark Double"); + setChoice(playerA, "Yes"); + setChoice(playerA, "Ajani, the Greathearted"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Ajani, the Greathearted", 2); + + Permanent spark = findDoubleSparkPermanent(currentGame); + Assert.assertEquals("must add 1 loyalty", 5 + 1, spark.getCounters(currentGame).getCount(CounterType.LOYALTY)); + } + + @Test + public void test_CopyCreatureAndGetDoubleCounter() { + addCard(Zone.BATTLEFIELD, playerA, "Abbey Griffin", 1); // 2/2, fly, vig + addCard(Zone.BATTLEFIELD, playerA, "Doubling Season", 1); + // + addCard(Zone.HAND, playerA, "Spark Double"); // {3}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spark Double"); + setChoice(playerA, "Yes"); + setChoice(playerA, "Abbey Griffin"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Abbey Griffin", 2); + + Permanent spark = findDoubleSparkPermanent(currentGame); + Assert.assertEquals("must add 2 counter", 2, spark.getCounters(currentGame).getCount(CounterType.P1P1)); + } + + @Test + public void test_CopyPlaneswalkerWithCreatureActivated() { + addCard(Zone.BATTLEFIELD, playerA, "Gideon, Ally of Zendikar", 1); + // + addCard(Zone.HAND, playerA, "Spark Double"); // {3}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // activate creature ability + checkType("planeswalker not creature", 1, PhaseStep.UPKEEP, playerA, "Gideon, Ally of Zendikar", CardType.CREATURE, false); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:"); + checkType("planeswalker is creature", 1, PhaseStep.BEGIN_COMBAT, playerA, "Gideon, Ally of Zendikar", CardType.CREATURE, true); + + // copy + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Spark Double"); + setChoice(playerA, "Yes"); + setChoice(playerA, "Gideon, Ally of Zendikar"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Gideon, Ally of Zendikar", 2); + + Permanent spark = findDoubleSparkPermanent(currentGame); + Assert.assertEquals("must add 1 loyalty", 4 + 1, spark.getCounters(currentGame).getCount(CounterType.LOYALTY)); + Assert.assertEquals("must not add creature counter", 0, spark.getCounters(currentGame).getCount(CounterType.P1P1)); + } + + @Test + @Ignore // TODO: enabled after Blood Moon type changing effect will be fixed + public void test_CopyPlaneswalkerWithCreatureTypeChangedEffect() { + addCard(Zone.BATTLEFIELD, playerA, "Gideon Blackblade", 1); + // + addCard(Zone.HAND, playerA, "Spark Double"); // {3}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 4); + + // Gideon Blackblade is creature on your turn (by type changing effect) + checkType("planeswalker is creature", 1, PhaseStep.UPKEEP, playerA, "Gideon Blackblade", CardType.CREATURE, true); + + // copy + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spark Double"); + setChoice(playerA, "Yes"); + setChoice(playerA, "Gideon Blackblade"); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Gideon Blackblade", 2); + + Permanent spark = findDoubleSparkPermanent(currentGame); + Assert.assertEquals("must add 1 loyalty", 4 + 1, spark.getCounters(currentGame).getCount(CounterType.LOYALTY)); + Assert.assertEquals("must add 1 creature counter", 1, spark.getCounters(currentGame).getCount(CounterType.P1P1)); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java index 548f752852..f4859dc486 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/copy/SpelltwineTest.java @@ -1,8 +1,8 @@ - package org.mage.test.cards.copy; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -48,6 +48,7 @@ public class SpelltwineTest extends CardTestPlayerBase { * after this, failing to be in the stack box or resolve all. */ @Test + @Ignore // TODO: test is wrong -- mirari exile cards and must cast their copies, on copies cast mirari triggers again (two times). public void testCopyCardsMirari() { addCard(Zone.BATTLEFIELD, playerA, "Island", 9); // Exile target instant or sorcery card from your graveyard and target instant or sorcery card from an opponent's graveyard. @@ -66,9 +67,13 @@ public class SpelltwineTest extends CardTestPlayerBase { // Whenever you cast an instant or sorcery spell, you may pay {3}. If you do, copy that spell. You may choose new targets for the copy. addCard(Zone.BATTLEFIELD, playerA, "Mirari", 1); + // cast spellwin castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spelltwine"); - addTarget(playerA, "Impulse"); - addTarget(playerA, "Blasphemous Act"); + addTarget(playerA, "Impulse"); // target 1 to excile + addTarget(playerA, "Blasphemous Act"); // target 2 to excile + + + setChoice(playerA, "Yes"); // pay {3} and copy spell setChoice(playerA, "Yes"); // Change targets addTarget(playerA, "Night's Whisper"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java index ae388836b4..5d0b75df07 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/cost/splitcards/CastSplitCardsFromOtherZonesTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.cost.splitcards; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { @@ -27,31 +25,6 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} addCard(Zone.BATTLEFIELD, playerB, "Sanguine Bond", 1); // Enchantment to destroy - // Wear - // Destroy target artifact. - // Tear - // Destroy target enchantment. - addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Sanguine Bond"); - - setStopAt(1, PhaseStep.BEGIN_COMBAT); - execute(); - - assertPermanentCount(playerA, "Mindclaw Shaman", 1); - assertGraveyardCount(playerB, "Wear // Tear", 1); - assertGraveyardCount(playerB, "Sanguine Bond", 1); - - } - - @Test - public void testCastFearFromOpponentsHand() { - addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); - // When Mindclaw Shaman enters the battlefield, target opponent reveals their hand. - // You may cast an instant or sorcery card from it without paying its mana cost. - addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} - addCard(Zone.BATTLEFIELD, playerB, "Icy Manipulator", 1); // Artifact to destroy // Wear // Destroy target artifact. @@ -60,7 +33,42 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Icy Manipulator"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Tear"); // select tear side + addTarget(playerA, "Sanguine Bond"); // target for tear + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertPermanentCount(playerA, "Mindclaw Shaman", 1); + assertGraveyardCount(playerB, "Wear // Tear", 1); + assertGraveyardCount(playerB, "Icy Manipulator", 0); + assertGraveyardCount(playerB, "Sanguine Bond", 1); + } + + @Test + public void testCastWearFromOpponentsHand() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + // When Mindclaw Shaman enters the battlefield, target opponent reveals their hand. + // You may cast an instant or sorcery card from it without paying its mana cost. + addCard(Zone.HAND, playerA, "Mindclaw Shaman"); // Creature {4}{R} + + addCard(Zone.BATTLEFIELD, playerB, "Sanguine Bond", 1); // Enchantment to destroy + addCard(Zone.BATTLEFIELD, playerB, "Icy Manipulator", 1); // Artifact to destroy + // Wear + // Destroy target artifact. + // Tear + // Destroy target enchantment. + addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Wear"); // select wear side + addTarget(playerA, "Icy Manipulator"); // target for wear setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); @@ -68,7 +76,7 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); assertGraveyardCount(playerB, "Icy Manipulator", 1); - + assertGraveyardCount(playerB, "Sanguine Bond", 0); } @Test @@ -87,16 +95,20 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Wear // Tear"); // Instant {1}{R} // {W} castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mindclaw Shaman"); - addTarget(playerA, "Sanguine Bond"); + addTarget(playerA, playerB); + setChoice(playerA, "Wear // Tear"); // select card + setChoice(playerA, "Yes"); // confirm to cast + setChoice(playerA, "Wear // Tear"); // select fused + addTarget(playerA, "Icy Manipulator"); // target for wear + addTarget(playerA, "Sanguine Bond"); // target for tear setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Mindclaw Shaman", 1); assertGraveyardCount(playerB, "Wear // Tear", 1); - assertGraveyardCount(playerB, "Sanguine Bond", 1); assertGraveyardCount(playerB, "Icy Manipulator", 1); - + assertGraveyardCount(playerB, "Sanguine Bond", 1); } /** @@ -119,7 +131,7 @@ public class CastSplitCardsFromOtherZonesTest extends CardTestPlayerBase { attack(2, playerB, "Etali, Primal Storm"); setChoice(playerB, "Yes"); - setChoice(playerB, "Cast Fire"); + setChoice(playerB, "Fire"); addTarget(playerB, "Silvercoat Lion"); setStopAt(2, PhaseStep.END_COMBAT); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java index 68788a4429..61942c0313 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/dynamicvalue/SweepTest.java @@ -1,14 +1,12 @@ - - package org.mage.test.cards.dynamicvalue; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; +import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author BetaSteward */ public class SweepTest extends CardTestPlayerBase { @@ -18,10 +16,9 @@ public class SweepTest extends CardTestPlayerBase { * Plow Through Reito * 1W * Instant -- Arcane - * Sweep -- Return any number of Plains you control to their owner's hand. + * Sweep -- Return any number of Plains you control to their owner's hand. * Target creature gets +1/+1 until end of turn for each Plains returned this way. - * - */ + */ @Test public void testSweep1x() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); @@ -29,17 +26,17 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 4); - assertPowerToughness(playerA, "Raging Goblin", 2, 2); - + assertPowerToughness(playerA, "Raging Goblin", 2, 2); } - + @Test public void testSweep2x() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); @@ -47,15 +44,15 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains^Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains^Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 3); - assertPowerToughness(playerA, "Raging Goblin", 3, 3); - + assertPowerToughness(playerA, "Raging Goblin", 3, 3); } @Test @@ -65,15 +62,15 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); - addTarget(playerA, "Plains^Plains^Plains"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, "Plains^Plains^Plains"); // targets to sweep setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 2); - assertPowerToughness(playerA, "Raging Goblin", 4, 4); - + assertPowerToughness(playerA, "Raging Goblin", 4, 4); } @Test @@ -83,14 +80,16 @@ public class SweepTest extends CardTestPlayerBase { addCard(Zone.HAND, playerA, "Plow Through Reito"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plow Through Reito"); + addTarget(playerA, "Raging Goblin"); // target to boost + addTarget(playerA, TestPlayer.TARGET_SKIP); // targets to sweep (zero) setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Raging Goblin", 1); assertPermanentCount(playerA, "Plains", 5); - assertPowerToughness(playerA, "Raging Goblin", 1, 1); - + assertPowerToughness(playerA, "Raging Goblin", 1, 1); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java index 2334af2b07..6db1d8e572 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/OathOfLiegesTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.enchantments; import mage.constants.PhaseStep; @@ -7,93 +6,229 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class OathOfLiegesTest extends CardTestPlayerBase { + //addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + //addCard(Zone.HAND, playerA, "Breath of Life", 1); // {3}{W} // return creatures + //addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + @Test - public void testSearchLandOwner() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} - addCard(Zone.LIBRARY, playerA, "Plains", 1); + public void testOath_OwnCardTriggersOnOwnTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Oath of Lieges", 1); // {1}{W} + // B + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - addCard(Zone.BATTLEFIELD, playerB, "Plains", 3); + // turn 1 - A + // oath A triggers for A and activates + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); - addTarget(playerA, playerB); - addTarget(playerA, "Plains"); - - setStopAt(3, PhaseStep.PRECOMBAT_MAIN); + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerA, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Plains", 3); - + assertPermanentCount(playerA, "Plains", 4 + 1); + assertPermanentCount(playerB, "Island", 5); } @Test - public void testSearchLandOpponent() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} + public void testOath_OwnCardTriggersOnOpponentTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 5); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 4); + addCard(Zone.LIBRARY, playerB, "Plains", 5); - addCard(Zone.BATTLEFIELD, playerB, "Plains", 1); - addCard(Zone.LIBRARY, playerB, "Plains", 1); + // turn 1 - A (play oath from grave) + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + checkPermanentCount("A have oath", 1, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("A have 5 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 5); + checkPermanentCount("B have 4 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 4); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); - addTarget(playerB, playerA); - addTarget(playerB, "Plains"); + // turn 2 - B + // oath A triggers for B and activates + addTarget(playerB, playerA); // who control more lands + setChoice(playerB, "Yes"); // search library + addTarget(playerB, "Plains"); // card from library - setStopAt(2, PhaseStep.PRECOMBAT_MAIN); + setStopAt(2, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerA, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Plains", 2); - assertPermanentCount(playerB, "Plains", 2); + assertPermanentCount(playerA, "Plains", 5); + assertPermanentCount(playerB, "Plains", 4 + 1); } @Test - public void testSearchLandOwnerCopy() { - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - // At the beginning of each player's upkeep, that player chooses target player who controls more lands than he or she does and is their opponent. - // The first player may search their library for a basic land card, put that card onto the battlefield, then shuffle their library. - addCard(Zone.HAND, playerA, "Oath of Lieges", 1); // {1}{W} - addCard(Zone.LIBRARY, playerA, "Plains", 3); - addCard(Zone.HAND, playerA, "Plains", 1); + public void testOath_OpponentCardTriggersOnOwnTurn() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + // B + addCard(Zone.LIBRARY, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Oath of Lieges", 1); // {1}{W} + // turn 1 - A + // oath B triggers for A and activates + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 4 + 1); + assertPermanentCount(playerB, "Plains", 5); + } + + @Test + public void testOath_DoubleOath() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Oath of Lieges", 2); // {1}{W} + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + + // turn 1 - A + // oath A triggers for A and activates + // oath B triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 3 + 2); + assertPermanentCount(playerB, "Plains", 5); + } + + @Test + public void testOath_OwnNormalAndOwnCopy() { + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); // for copy + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + addCard(Zone.HAND, playerA, "Copy Enchantment", 1); // {2}{U} // copy target + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 12); addCard(Zone.BATTLEFIELD, playerB, "Island", 3); - addCard(Zone.HAND, playerB, "Copy Enchantment", 1); // {2}{U} - addCard(Zone.LIBRARY, playerB, "Plains", 3); + addCard(Zone.LIBRARY, playerB, "Plains", 5); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oath of Lieges"); + // turn 1 - A + // cast oath A + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + showBattlefield("A perms", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + // cast oath copy + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Copy Enchantment"); + setChoice(playerA, "Yes"); // use copy effect + setChoice(playerA, "Oath of Lieges"); // target for copy + checkPermanentCount("A have 2 oath", 1, PhaseStep.END_TURN, playerA, "Oath of Lieges", 2); + checkPermanentCount("A have 10 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 12); - castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Copy Enchantment"); - setChoice(playerB, "Oath of Lieges"); + // turn 2 - B + // oath A triggers for B and do nothing + // copy oath A triggers for B and do nothing + checkPermanentCount("A have 10 plains", 1, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 1, PhaseStep.END_TURN, playerB, "Plains", 12); - // turn 3 - addTarget(playerA, playerB); - addTarget(playerA, "Plains"); // 3rd land - addTarget(playerA, "Plains"); // second trigger will fail because target player has no longer more lands than controller + // turn 3 - A + // oath A triggers for A and activates + // copy oath A triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library - playLand(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); // 4th land - - // turn 4 - addTarget(playerB, playerA); - addTarget(playerB, "Plains"); - addTarget(playerB, "Plains"); // second trigger will fail because target player has no longer more lands than controller - - setStopAt(4, PhaseStep.PRECOMBAT_MAIN); + setStopAt(3, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); - assertPermanentCount(playerB, "Oath of Lieges", 1); - assertPermanentCount(playerA, "Oath of Lieges", 1); + assertPermanentCount(playerA, "Plains", 10 + 2); + assertPermanentCount(playerB, "Plains", 12); + } - assertPermanentCount(playerB, "Plains", 1); - assertPermanentCount(playerA, "Plains", 4); + @Test + public void testOath_OwnNormalAndOpponentCopy() { + // special test to check targetadjusters (copy card must used target adjuster from original card, not from copied) + // A + addCard(Zone.BATTLEFIELD, playerA, "Plains", 10); + addCard(Zone.BATTLEFIELD, playerA, "Island", 3); + addCard(Zone.LIBRARY, playerA, "Plains", 5); + addCard(Zone.GRAVEYARD, playerA, "Oath of Lieges", 1); // {1}{W} + addCard(Zone.HAND, playerA, "Replenish", 1); // {3}{W} // return all enchantments + addCard(Zone.BATTLEFIELD, playerA, "Hypersonic Dragon", 1); // can cast spells at any time + // B + addCard(Zone.BATTLEFIELD, playerB, "Plains", 12); + addCard(Zone.BATTLEFIELD, playerB, "Island", 3); // for copy + addCard(Zone.LIBRARY, playerB, "Plains", 5); + addCard(Zone.HAND, playerB, "Copy Enchantment", 1); // {2}{U} // copy target + + // turn 1 - A + // nothing + + // turn 2 - B + // cast oath A + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Replenish"); + // cast oath copy by opponent + showBattlefield("A perms", 2, PhaseStep.POSTCOMBAT_MAIN, playerA); + showBattlefield("B perms", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + showAvaileableAbilities("B abils", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + showHand("B hand", 2, PhaseStep.POSTCOMBAT_MAIN, playerB); + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Copy Enchantment"); + setChoice(playerB, "Yes"); // use copy effect + setChoice(playerB, "Oath of Lieges"); // target for copy + checkPermanentCount("A have 1 oath", 2, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("B have 1 oath", 2, PhaseStep.END_TURN, playerA, "Oath of Lieges", 1); + checkPermanentCount("A have 10 plains", 2, PhaseStep.END_TURN, playerA, "Plains", 10); + checkPermanentCount("B have 12 plains", 2, PhaseStep.END_TURN, playerB, "Plains", 12); + showLibrary("lib B", 2, PhaseStep.END_TURN, playerB); + + // turn 3 - A + // oath A triggers for A and activates + // copy oath B triggers for A and activates + // 1 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + // 2 + addTarget(playerA, playerB); // who control more lands + setChoice(playerA, "Yes"); // search library + addTarget(playerA, "Plains"); // card from library + + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Plains", 10 + 2); + assertPermanentCount(playerB, "Plains", 12); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java index ec167a6315..882c8e1efb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/StarfieldOfNyxTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.enchantments; import mage.abilities.keyword.FlyingAbility; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.Filter; @@ -11,7 +11,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class StarfieldOfNyxTest extends CardTestPlayerBase { @@ -22,7 +21,6 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { * Starfield of Nyx not only turned both of them into creatures (it * shouldn't, because they're auras), but it also destroyed them. The * manifests stayed on the battlefield without Flying or Hexproof. - * */ @Test public void testCloudform() { @@ -49,7 +47,7 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { execute(); assertGraveyardCount(playerA, "Thopter Spy Network", 0); - assertPowerToughness(playerA, "", 2, 2, Filter.ComparisonScope.All); // the manifested cards + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2, Filter.ComparisonScope.All); // the manifested cards assertPermanentCount(playerA, "Starfield of Nyx", 1); assertPowerToughness(playerA, "Thopter Spy Network", 4, 4, Filter.ComparisonScope.All); assertPermanentCount(playerA, "Cloudform", 2); @@ -97,19 +95,19 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { Assert.assertEquals("Singing Bell Strike not on the battlefield", false, true); } } - + @Test public void testStarfieldOfNyxLayers() { - + addCard(Zone.BATTLEFIELD, playerA, "Starfield of Nyx"); // enchantments you control become creatures addCard(Zone.BATTLEFIELD, playerA, "Humility"); // creatures lose all abilities and are 1/1 addCard(Zone.BATTLEFIELD, playerA, "Pharika, God of Affliction"); // enchantment addCard(Zone.BATTLEFIELD, playerA, "Emrakul, the Aeons Torn"); //15/15 creature addCard(Zone.BATTLEFIELD, playerA, "Crusade", 4); // enchantments to fulfill requirement of Starfield of Nyx - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPowerToughness(playerA, "Pharika, God of Affliction", 3, 3, Filter.ComparisonScope.All); assertPowerToughness(playerA, "Humility", 4, 4, Filter.ComparisonScope.All); // Humility loses its ability in layer 6. Layer 7 never gets Humility's effect @@ -117,6 +115,6 @@ public class StarfieldOfNyxTest extends CardTestPlayerBase { Permanent emrakul = getPermanent("Emrakul, the Aeons Torn", playerA.getId()); Assert.assertNotNull(emrakul); Assert.assertFalse(emrakul.getAbilities().contains(FlyingAbility.getInstance())); // loses flying though - + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java index e4a92ee726..b516159d9b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/GhastlyConscriptionTest.java @@ -1,5 +1,6 @@ package org.mage.test.cards.facedown; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -13,13 +14,12 @@ public class GhastlyConscriptionTest extends CardTestPlayerBase { /** * Ghastly Conscription * Sorcery, 5BB (7) - * Exile all creature cards from target player's graveyard in a face-down pile, - * shuffle that pile, then manifest those cards. (To manifest a card, put it - * onto the battlefield face down as a 2/2 creature. Turn it face up any time + * Exile all creature cards from target player's graveyard in a face-down pile, + * shuffle that pile, then manifest those cards. (To manifest a card, put it + * onto the battlefield face down as a 2/2 creature. Turn it face up any time * for its mana cost if it's a creature card.) - * */ - + // test that cards exiled using Ghastly Conscription return face down @Test public void testGhastlyConscription() { @@ -36,9 +36,9 @@ public class GhastlyConscriptionTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 20); - + assertGraveyardCount(playerA, 2); - assertPermanentCount(playerA, "", 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java index b0755813af..77ec01543d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/ObscuringAetherTest.java @@ -1,13 +1,12 @@ - package org.mage.test.cards.facedown; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class ObscuringAetherTest extends CardTestPlayerBase { @@ -15,7 +14,6 @@ public class ObscuringAetherTest extends CardTestPlayerBase { /** * Obscuring Aether cannot turn into a face down 2/2 like it should. When * activating the ability to turn it over it, it dies immediately. - * */ // test that cards exiled using Ghastly Conscription return face down @Test @@ -35,8 +33,8 @@ public class ObscuringAetherTest extends CardTestPlayerBase { assertHandCount(playerA, "Obscuring Aether", 0); assertGraveyardCount(playerA, "Obscuring Aether", 0); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java index e9354e7a8d..ab984d69d8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/SummonersEggTest.java @@ -27,17 +27,16 @@ public class SummonersEggTest extends CardTestPlayerBase { @Test public void testSummonersEggImprint() { addCard(Zone.HAND, playerA, "Summoner's Egg"); - addCard(Zone.HAND, playerA, "Sejiri Merfolk"); + addCard(Zone.HAND, playerA, "Maritime Guard"); addCard(Zone.HAND, playerA, "Goblin Roughrider"); addCard(Zone.BATTLEFIELD, playerA, "Island", 4); - - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Summoner's Egg"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Summoner's Egg"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertHandCount(playerA, 1); - assertHandCount(playerA, "Sejiri Merfolk", 1); + assertHandCount(playerA, "Maritime Guard", 1); assertHandCount(playerA, "Goblin Roughrider", 0); assertExileCount("Goblin Roughrider", 1); @@ -53,7 +52,7 @@ public class SummonersEggTest extends CardTestPlayerBase { @Test public void testSummonersEggDies() { addCard(Zone.HAND, playerA, "Summoner's Egg"); - addCard(Zone.HAND, playerA, "Sejiri Merfolk"); + addCard(Zone.HAND, playerA, "Maritime Guard"); addCard(Zone.HAND, playerA, "Goblin Roughrider"); addCard(Zone.BATTLEFIELD, playerA, "Island", 4); addCard(Zone.HAND, playerB, "Char"); @@ -67,7 +66,7 @@ public class SummonersEggTest extends CardTestPlayerBase { execute(); assertHandCount(playerA, 1); - assertHandCount(playerA, "Sejiri Merfolk", 1); + assertHandCount(playerA, "Maritime Guard", 1); assertHandCount(playerA, "Goblin Roughrider", 0); assertGraveyardCount(playerA, "Summoner's Egg", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/GaeasGradleTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/GaeasGradleTest.java new file mode 100644 index 0000000000..92c0ddd9dc --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/GaeasGradleTest.java @@ -0,0 +1,28 @@ +package org.mage.test.cards.mana; + +import mage.constants.ManaType; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class GaeasGradleTest extends CardTestPlayerBase { + + private final String cradle = "Gaea's Cradle"; + private final String bears = "Grizzly Bears"; + private final String thopter = "Ornithopter"; + + @Test + public void testGradle(){ + addCard(Zone.BATTLEFIELD, playerA, cradle); + addCard(Zone.BATTLEFIELD, playerA, bears, 2); + addCard(Zone.BATTLEFIELD, playerB, thopter); + + activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,"{T}: "); + + checkManaPool("gaeas cradle ",1, PhaseStep.PRECOMBAT_MAIN, playerA, "G", 2); + setStopAt(1, PhaseStep.PRECOMBAT_MAIN); + execute(); + + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java new file mode 100644 index 0000000000..ac39080b79 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/mana/HarvestMageTest.java @@ -0,0 +1,35 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.mage.test.cards.mana; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class HarvestMageTest extends CardTestPlayerBase { + + @Test + public void testOneInstance() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + + // {G}, {T}, Discard a card: Until end of turn, if you tap a land for mana, it produces one mana of a color of your choice instead of any other type and amount. + addCard(Zone.HAND, playerA, "Harvest Mage", 1); // Creature 1/1 {G} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Harvest Mage"); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{G}, {T}, Discard a card: Until end of turn"); + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Harvest Mage", 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/GlarecasterTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/GlarecasterTest.java new file mode 100644 index 0000000000..817761420f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/redirect/GlarecasterTest.java @@ -0,0 +1,48 @@ +package org.mage.test.cards.replacement.redirect; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * + * @author LevelX2 + */ +public class GlarecasterTest extends CardTestPlayerBase { + + /** + * I can activate Glarecaster's redirection ability, immediately cast two + * Lightning Bolts on it and both get redirected towards the chosen target. + * If I pass until the next step and cast another Bolt on it, it's not being + * redirected anymore. + * + */ + @Test + public void testTwoTimesInstantSpellDamage() { + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + + // Flying + // {5}{W}: The next time damage would be dealt to Glarecaster and/or you this turn, that damage is dealt to any target instead. + addCard(Zone.BATTLEFIELD, playerB, "Glarecaster"); // Creature 3/3 + addCard(Zone.BATTLEFIELD, playerB, "Plains", 6); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{5}{W}: The next time damage would be dealt to", playerA); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Glarecaster"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Lightning Bolt", 2); + + assertPermanentCount(playerB, "Glarecaster", 1); + + assertLife(playerA, 17); + assertLife(playerB, 17); + + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ReflectorMageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ReflectorMageTest.java index 5730041f0f..72ee6078d4 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ReflectorMageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/ReflectorMageTest.java @@ -7,64 +7,64 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public class ReflectorMageTest extends CardTestPlayerBase { - + /** * Reported bug: Reflector Mage returning a creature to its owners hand is additionally * incorrectly preventing the Reflector Mage's owner from casting that same creature. */ @Test public void testReflectorMageAllowsOwnerToCastCreatureReturnedOnSameTurn() { - + // {1}{W}{U} When Reflector Mage enters the battlefield, return target creature an opponent controls to its owner's hand. // That creature's owner can't cast spells with the same name as that creature until your next turn. addCard(Zone.HAND, playerA, "Reflector Mage"); // 2/3 addCard(Zone.HAND, playerA, "Bronze Sable", 1); // (2) 2/1 - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); - + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reflector Mage"); addTarget(playerA, "Bronze Sable"); - + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Bronze Sable"); - + execute(); - + assertPermanentCount(playerB, "Bronze Sable", 0); - assertHandCount(playerB, "Bronze Sable", 1); + assertHandCount(playerB, "Bronze Sable", 1); assertPermanentCount(playerA, "Reflector Mage", 1); assertPermanentCount(playerA, "Bronze Sable", 1); } - + /** * Basic test to confirm the restriction effect still works on the opponent. */ @Test public void testReflectorMageRestrictionEffect() { - + // {1}{W}{U} When Reflector Mage enters the battlefield, return target creature an opponent controls to its owner's hand. // That creature's owner can't cast spells with the same name as that creature until your next turn. addCard(Zone.HAND, playerA, "Reflector Mage"); // 2/3 - addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); - addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); - + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); // (2) 2/1 - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reflector Mage"); addTarget(playerA, "Bronze Sable"); - + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Bronze Sable"); // should not be allowed + setStopAt(2, PhaseStep.END_TURN); execute(); - + assertPermanentCount(playerB, "Bronze Sable", 0); assertHandCount(playerB, "Bronze Sable", 1); assertPermanentCount(playerA, "Reflector Mage", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java index 7fb74ea1ad..4a8ac07bbe 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/rules/CantCastTest.java @@ -1,6 +1,6 @@ - package org.mage.test.cards.rules; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.counters.CounterType; @@ -8,7 +8,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class CantCastTest extends CardTestPlayerBase { @@ -113,7 +112,7 @@ public class CantCastTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 0); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 0); assertHandCount(playerA, "Pine Walker", 1); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/GiselaBladeOfGoldnightTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/GiselaBladeOfGoldnightTest.java index 087c19901b..672e6b8d1d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/GiselaBladeOfGoldnightTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/GiselaBladeOfGoldnightTest.java @@ -7,8 +7,8 @@ import org.mage.test.serverside.base.CardTestPlayerBase; /** * Gisela, Blade of Goldnight: - * If a source would deal damage to an opponent or a permanent an opponent controls, that source deals double that damage to that player or permanent instead. - * If a source would deal damage to you or a permanent you control, prevent half that damage, rounded up. + * If a source would deal damage to an opponent or a permanent an opponent controls, that source deals double that damage to that player or permanent instead. + * If a source would deal damage to you or a permanent you control, prevent half that damage, rounded up. * * @author noxx */ @@ -47,4 +47,143 @@ public class GiselaBladeOfGoldnightTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Air Elemental", 0); } + @Test + public void test_DamageToOpponent_WithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6); + addCard(Zone.BATTLEFIELD, playerB, "Gisela, Blade of Goldnight"); + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", playerA); + setChoice(playerB, "X=5"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // Player A should take double damage + assertLife(playerA, 20 - 10); + } + + @Test + public void test_DamageToOpponentsCreature_WithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + addCard(Zone.BATTLEFIELD, playerB, "Gisela, Blade of Goldnight"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2 + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", "Grizzly Bears"); + setChoice(playerB, "X=1"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // creature takes 2 damage and dies + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertLife(playerA, 20); + } + + @Test + public void test_DamageToPlayer_Preventable() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", playerA); + setChoice(playerB, "X=4"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // Player A should take the full 4 damage + assertLife(playerA, 20 - 4); + } + + @Test + public void test_DamageToPlayer_Unpreventable() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6); + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", playerA); + setChoice(playerB, "X=5"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // Player A should take the full 5 damage + assertLife(playerA, 15); + } + + @Test + public void test_DamageToPlayer_PreventableWithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + addCard(Zone.BATTLEFIELD, playerA, "Gisela, Blade of Goldnight"); + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", playerA); + setChoice(playerB, "X=4"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // Player A should take half damage 2 (prevent 4/2 round up = 2 damage) + assertLife(playerA, 20 - 2); + } + + @Test + public void test_DamageToPlayer_UnpreventableWithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 6); + addCard(Zone.BATTLEFIELD, playerA, "Gisela, Blade of Goldnight"); + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", playerA); + setChoice(playerB, "X=5"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // Player A should take full damage 5 (wrong result: 2 damage) + assertLife(playerA, 20 - 5); + } + + @Test + public void test_DamageToCreature_PreventableWithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Gisela, Blade of Goldnight"); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); // 2/2 + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", "Grizzly Bears"); + setChoice(playerB, "X=2"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // creature must be alife, half damage done + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertLife(playerA, 20); + } + + @Test + public void test_DamageToCreature_UnpreventableWithGisela() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 7); + addCard(Zone.BATTLEFIELD, playerA, "Gisela, Blade of Goldnight"); + addCard(Zone.BATTLEFIELD, playerA, "Colossal Dreadmaw"); // 6/6 + addCard(Zone.HAND, playerB, "Banefire"); + + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Banefire", "Colossal Dreadmaw"); + setChoice(playerB, "X=6"); + + setStopAt(2, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + // creature must die, full damage + assertPermanentCount(playerA, "Colossal Dreadmaw", 0); + assertLife(playerA, 20); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java index a84870f89d..efb30757b7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/MisdirectionTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.single; import mage.constants.PhaseStep; @@ -7,8 +6,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class MisdirectionTest extends CardTestPlayerBase { @@ -17,10 +15,58 @@ public class MisdirectionTest extends CardTestPlayerBase { * Tests if Misdirection for target opponent works correctly * https://github.com/magefree/mage/issues/574 */ + @Test - public void testChangeTargetOpponent() { + public void test_RakshaDiscardWorks() { // Target opponent discards two cards. Put the top two cards of your library into your graveyard. - addCard(Zone.HAND, playerA, "Rakshasa's Secret"); + addCard(Zone.HAND, playerA, "Rakshasa's Secret"); // {2}{B} + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); + addCard(Zone.HAND, playerB, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerB, "Ashcoat Bear", 5); + + // A cast discard + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakshasa's Secret", playerB); + setChoice(playerB, "Silvercoat Lion"); // select target 1 + setChoice(playerB, "Silvercoat Lion"); // select target 2 + checkHandCardCount("B haven't lions", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + checkHandCardCount("B have 5 bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 5); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_MisdirectionRetargetWorks() { + // Return target permanent to its owner’s hand. + addCard(Zone.HAND, playerA, "Boomerang", 1); // {U}{U} + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Ashcoat Bear", 1); + // Change the target of target spell with a single target. + addCard(Zone.HAND, playerB, "Misdirection"); // {3}{U}{U} + addCard(Zone.BATTLEFIELD, playerB, "Island", 5); + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion", 1); + + // A cast Boomerang to remove lion + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Silvercoat Lion"); + // B counter it by Misdirection and remove bear + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Boomerang", "Boomerang"); + addTarget(playerB, "Ashcoat Bear"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Boomerang", 1); + assertPermanentCount(playerA, "Ashcoat Bear", 0); + assertGraveyardCount(playerB, "Misdirection", 1); + assertPermanentCount(playerB, "Silvercoat Lion", 1); + } + + @Test + public void test_MisdirectionCantTargetToIllegal() { + // Target opponent discards two cards. Put the top two cards of your library into your graveyard. + addCard(Zone.HAND, playerA, "Rakshasa's Secret"); // {2}{B} addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3); /* Misdirection {3}{U}{U} @@ -30,23 +76,31 @@ public class MisdirectionTest extends CardTestPlayerBase { */ addCard(Zone.HAND, playerB, "Misdirection"); addCard(Zone.HAND, playerB, "Silvercoat Lion", 2); + addCard(Zone.HAND, playerB, "Ashcoat Bear", 5); addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + + // cast Raksha and select B castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rakshasa's Secret", playerB); + // cast misdir, but it's not apply and taget will be same castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Rakshasa's Secret", "Rakshasa's Secret"); - addTarget(playerB, playerA); // only legal target is player B as opponent - so player A should not be allowed - - setStopAt(1, PhaseStep.BEGIN_COMBAT); + // B must select cards to discard (2 lions, not bears) + setChoice(playerB, "Silvercoat Lion"); // select target 1 + setChoice(playerB, "Silvercoat Lion"); // select target 2 + checkHandCardCount("B haven't lions", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Silvercoat Lion", 0); + checkHandCardCount("B have 5 bears", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Ashcoat Bear", 5); + + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Rakshasa's Secret", 1); assertGraveyardCount(playerB, "Misdirection", 1); assertHandCount(playerB, "Silvercoat Lion", 0); } - + // check to change target permanent creature legal to to a creature the opponent of the spell controller controls @Test - public void testChangePublicExecution() { + public void test_ChangePublicExecution() { // Destroy target creature an opponent controls. Each other creature that player controls gets -2/-0 until end of turn. addCard(Zone.HAND, playerA, "Public Execution"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); @@ -60,26 +114,27 @@ public class MisdirectionTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); addCard(Zone.BATTLEFIELD, playerB, "Custodian of the Trove", 1); // 4/3 addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Execution", "Pillarfield Ox"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Public Execution", "Public Execution"); - addTarget(playerB, "Custodian of the Trove"); - + addTarget(playerB, "Custodian of the Trove"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Public Execution", 1); assertGraveyardCount(playerB, "Misdirection", 1); - - assertGraveyardCount(playerB, "Custodian of the Trove",1); + + assertGraveyardCount(playerB, "Custodian of the Trove", 1); assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 0, 4); - } - + } + // check to change target permanent creature not legal to to a creature the your opponent controls @Test - public void testChangePublicExecution2() { + public void test_ChangePublicExecution2() { // Destroy target creature an opponent controls. Each other creature that player controls gets -2/-0 until end of turn. addCard(Zone.HAND, playerA, "Public Execution"); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 6); @@ -94,13 +149,13 @@ public class MisdirectionTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Pillarfield Ox", 1); addCard(Zone.BATTLEFIELD, playerB, "Custodian of the Trove", 1); // 4/3 addCard(Zone.BATTLEFIELD, playerB, "Island", 5); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Public Execution", "Custodian of the Trove"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Misdirection", "Public Execution", "Public Execution"); - addTarget(playerB, "Keeper of the Lens"); - + setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Public Execution", 1); assertGraveyardCount(playerB, "Misdirection", 1); @@ -108,8 +163,7 @@ public class MisdirectionTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Pillarfield Ox", 1); assertPowerToughness(playerB, "Pillarfield Ox", 0, 4); - - assertGraveyardCount(playerB, "Custodian of the Trove",1); - } + assertGraveyardCount(playerB, "Custodian of the Trove", 1); + } } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ThousandYearStormTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ThousandYearStormTest.java new file mode 100644 index 0000000000..1e0198075d --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ThousandYearStormTest.java @@ -0,0 +1,331 @@ +package org.mage.test.cards.single; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ +public class ThousandYearStormTest extends CardTestPlayerBase { + + /* + Thousand-Year Storm {4}{U}{R} + Enchantment + Whenever you cast an instant or sorcery spell, copy it for each other instant and sorcery spell you’ve cast before it this turn. You may choose new targets for the copies. + */ + + @Test + public void test_CalcBeforeStorm() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 5); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // bolt before + castSpell(1, PhaseStep.UPKEEP, playerA, "Lightning Bolt", playerB); + checkLife("before", 1, PhaseStep.PRECOMBAT_MAIN, playerB, 20 - 3); + + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + + // bolt after (1 + 1x copy) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("copy", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CalcStackBefore() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 5); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // bolt stack before + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + + // bolt after (1 + 1x copy) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("copy", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CalcStackAfter() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 5); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + // bolt stack after + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + + // bolt after (1 + 1x copy) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("copy", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CalcAfterStormOnSameStep() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 5); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + + // bolt after + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + // bolt after (1 + 1x copy) + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("copy", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CalcAfterStormOnDiffStep() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 5); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + + // bolt after + castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Lightning Bolt", playerB); + // bolt after (1 + 1x copy) + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("copy", 1, PhaseStep.END_TURN, playerB, 20 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_OwnCounts() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 10); + // + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Island", 1); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // turn 1 + int startLife = 100; + setLife(playerA, 100); + setLife(playerB, 100); + + // before storm (must counts too) + castSpell(1, PhaseStep.UPKEEP, playerA, "Lightning Bolt", playerB); + checkLife("0x copy", 1, PhaseStep.PRECOMBAT_MAIN, playerB, startLife - 3); + + // storm + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thousand-Year Storm"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + // 1 + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + checkLife("1x copy", 1, PhaseStep.BEGIN_COMBAT, playerB, startLife - 3 - 3 * 2); + setChoice(playerA, "No"); // change target for copy 1 + // 2 + castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + setChoice(playerA, "No"); // change target for copy 2 + checkLife("2x copy", 1, PhaseStep.END_COMBAT, playerB, startLife - 3 - 3 * 2 - 3 * 3); + // 3 + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + setChoice(playerA, "No"); // change target for copy 2 + setChoice(playerA, "No"); // change target for copy 3 + checkLife("3x copy", 1, PhaseStep.END_TURN, playerB, startLife - 3 - 3 * 2 - 3 * 3 - 3 * 4); + + // turn 3 + startLife = startLife - 3 - 3 * 2 - 3 * 3 - 3 * 4; + logger.info("start life on turn 3: " + startLife); + // after storm 0x + castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + checkLife("3. no copy", 3, PhaseStep.BEGIN_COMBAT, playerB, startLife - 3); + // after storm 1x + castSpell(3, PhaseStep.DECLARE_ATTACKERS, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("3. 1x copy", 3, PhaseStep.END_COMBAT, playerB, startLife - 3 - 3 * 2); + // after storm 2x + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + setChoice(playerA, "No"); // change target for copy 2 + checkLife("3. 2x copy", 3, PhaseStep.END_TURN, playerB, startLife - 3 - 3 * 2 - 3 * 3); + + setStrictChooseMode(true); + setStopAt(3, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_OpponentDontCounts() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 10); + // + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + addCard(Zone.HAND, playerB, "Lightning Bolt", 10); + // + addCard(Zone.BATTLEFIELD, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Augmenting Automaton"); + + // turn 1 + + // 1a + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + checkLife("0x copy", 1, PhaseStep.BEGIN_COMBAT, playerB, 20 - 3); + // 1b + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + checkLife("0x copy", 1, PhaseStep.BEGIN_COMBAT, playerA, 20 - 3); + + // 2a + castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("1x copy", 1, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + // 2b + castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerB, "Lightning Bolt", playerA); + checkLife("0x copy", 1, PhaseStep.END_COMBAT, playerA, 20 - 3 - 3); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + + @Test + public void test_WaitStackResolvedWithBolts() { + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + addCard(Zone.HAND, playerB, "Lightning Bolt", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); + + castSpell(2, PhaseStep.END_TURN, playerB, "Lightning Bolt", playerA); + castSpell(2, PhaseStep.END_TURN, playerB, "Lightning Bolt", playerA); + castSpell(2, PhaseStep.END_TURN, playerA, "Lightning Bolt", playerB); + waitStackResolved(2, PhaseStep.END_TURN); + checkLife("A must get damage", 2, PhaseStep.END_TURN, playerA, 20 - 3 - 3); + checkLife("B must get damage", 2, PhaseStep.END_TURN, playerB, 20 - 3); + + setStrictChooseMode(true); + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + /* + Lay Claim {5}{U}{U} + Enchant permanent + You control enchanted permanent. + Cycling {2} ({2}, Discard this card: Draw a card.) + */ + @Test + public void test_GetControlNotCounts() { + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); + // + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 5); + addCard(Zone.HAND, playerB, "Lightning Bolt", 3); + // + addCard(Zone.BATTLEFIELD, playerA, "Thousand-Year Storm"); + // + addCard(Zone.BATTLEFIELD, playerB, "Island", 7); + addCard(Zone.HAND, playerB, "Lay Claim"); + + // turn 2 + + // pump card for A + // 1 + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); + checkLife("a 0x copy", 2, PhaseStep.BEGIN_COMBAT, playerB, 20 - 3); + // 2 + castSpell(2, PhaseStep.DECLARE_ATTACKERS, playerA, "Lightning Bolt", playerB); + setChoice(playerA, "No"); // change target for copy 1 + checkLife("a 1x copy", 2, PhaseStep.END_COMBAT, playerB, 20 - 3 - 3 * 2); + + // change controller to B + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerB, "Lay Claim", "Thousand-Year Storm"); + // cast bolt without pump + castSpell(2, PhaseStep.END_TURN, playerB, "Lightning Bolt", playerA); + checkLife("b 0x copy after control", 3, PhaseStep.UPKEEP, playerA, 20 - 3); + + // turn 4 + + // pump for B + // 1 + castSpell(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", playerA); + checkLife("b 0x copy", 4, PhaseStep.BEGIN_COMBAT, playerA, 20 - 3 - 3); + // 2 + castSpell(4, PhaseStep.DECLARE_ATTACKERS, playerB, "Lightning Bolt", playerA); + setChoice(playerB, "No"); // change target for copy 1 + checkLife("b 1x copy", 4, PhaseStep.END_COMBAT, playerA, 20 - 3 - 3 - 3 * 2); + + setStrictChooseMode(true); + setStopAt(4, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/RagsRichesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/RagsRichesTest.java index 9df146aca7..f7acc869de 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/RagsRichesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/akh/RagsRichesTest.java @@ -7,6 +7,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -18,7 +19,7 @@ import java.io.FileNotFoundException; public class RagsRichesTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); + Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java index 7421496e7d..bfbaef65bb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/avr/CavernOfSoulsTest.java @@ -2,6 +2,7 @@ package org.mage.test.cards.single.avr; import mage.constants.PhaseStep; import mage.constants.Zone; +import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; @@ -197,6 +198,7 @@ public class CavernOfSoulsTest extends CardTestPlayerBase { * */ @Test + @Ignore public void testCastWithColorlessManaCanBeCountered() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 2); addCard(Zone.HAND, playerA, "Cavern of Souls"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java index 713ea046c0..0b86e47c8b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/fut/MuragandaPetroglyphsTest.java @@ -1,5 +1,6 @@ package org.mage.test.cards.single.fut; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.filter.Filter; @@ -50,8 +51,8 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 4, 4); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 4, 4); } @Test @@ -69,8 +70,8 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - assertPermanentCount(playerA, "", 1); - assertPowerToughness(playerA, "", 2, 2); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); + assertPowerToughness(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 2, 2); } @Test @@ -155,7 +156,7 @@ public class MuragandaPetroglyphsTest extends CardTestPlayerBase { // Enchanted creature doesn't untap during itscontroller's untap step. addCard(Zone.HAND, playerA, "Dehydration"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA,"Rancor", "Grizzly Bears"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rancor", "Grizzly Bears"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Dehydration", "Runeclaw Bear"); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java index 0cd8182c34..6dc75feb43 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/soi/PrizedAmalgamTest.java @@ -26,8 +26,7 @@ public class PrizedAmalgamTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Prized Amalgam", 1); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate"); - addTarget(playerA, "Bronze Sable"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate", "Bronze Sable"); setStopAt(1, PhaseStep.END_TURN); execute(); @@ -67,24 +66,24 @@ public class PrizedAmalgamTest extends CardTestPlayerBase { public void testOpponentReturnsCreatureFromGrave() { addCard(Zone.HAND, playerA, "Reanimate", 1); - addCard(Zone.GRAVEYARD, playerA, "Hill Giant", 1); // {3}{R} 3/3 + addCard(Zone.GRAVEYARD, playerA, "Hill Giant", 1); // {3}{R} 3/3, 4 CMC addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - addCard(Zone.GRAVEYARD, playerB, "Prized Amalgam", 1); + addCard(Zone.GRAVEYARD, playerB, "Prized Amalgam", 1); // {1}{U}{B}, 3 CMC castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Reanimate"); addTarget(playerA, "Hill Giant"); setStopAt(1, PhaseStep.END_TURN); execute(); - assertLife(playerA, 16); // lose 4 life from reanimate 4 CMC + assertLife(playerA, 16); // lose 4 life from reanimate 4 CMC by Hill Giant assertPermanentCount(playerA, "Hill Giant", 1); assertPermanentCount(playerB, "Prized Amalgam", 0); // should not recur assertGraveyardCount(playerB, "Prized Amalgam", 1); // stays in grave } /* - * Test opponent returning a card from your graveyard to battlefield. + * Test opponent returning a card from your graveyard to battlefield. */ @Test public void testOpponentReturnsCreatureFromYourGrave() { @@ -95,8 +94,7 @@ public class PrizedAmalgamTest extends CardTestPlayerBase { // Whenever a creature enters the battlefield, if it entered from your graveyard or you cast it from your graveyard, return Prized Amalgam from your graveyard to the battlefield tapped at the beginning of the next end step. addCard(Zone.GRAVEYARD, playerB, "Prized Amalgam", 1); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Necromantic Summons"); - addTarget(playerA, "Merfolk Looter"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Necromantic Summons", "Merfolk Looter"); setStopAt(1, PhaseStep.END_TURN); execute(); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java index 18e0ded9a0..d124f0882a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/ths/PurphorosGodOfTheForgeTest.java @@ -1,7 +1,7 @@ - package org.mage.test.cards.single.ths; import mage.constants.CardType; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import mage.game.permanent.Permanent; @@ -10,26 +10,25 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { /** * I had a situation come up today where I had a Purphoros on the field - * and 5 devotion with an Eidolon and Phoenix. My opponent killed the + * and 5 devotion with an Eidolon and Phoenix. My opponent killed the * Phoenix, but Purphoros still was "turned on". */ @Test public void testFacedownNotCountedForDevotion1() { addCard(Zone.BATTLEFIELD, playerB, "Swamp", 5); addCard(Zone.HAND, playerB, "Reach of Shadows"); - + // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. // {2}{R}: Creatures you control get +1/+0 until end of turn. addCard(Zone.BATTLEFIELD, playerA, "Purphoros, God of the Forge"); - + // Whenever a player casts a spell with converted mana cost 3 or less, // Eidolon of the Great Revel deals 2 damage to that player. addCard(Zone.BATTLEFIELD, playerA, "Eidolon of the Great Revel"); @@ -46,24 +45,24 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { assertLife(playerA, 20); assertLife(playerB, 18); // 2 damage from the returning Phoenix - + assertGraveyardCount(playerB, "Reach of Shadows", 1); assertPermanentCount(playerA, "Ashcloud Phoenix", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertFalse("Purphoros may not be a creature but it is", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); } - + @Test - public void testFacedownNotCountedForDevotion2() { + public void testFacedownNotCountedForDevotion2() { addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. // {2}{R}: Creatures you control get +1/+0 until end of turn. addCard(Zone.BATTLEFIELD, playerA, "Purphoros, God of the Forge"); - + // Whenever a player casts a spell with converted mana cost 3 or less, // Eidolon of the Great Revel deals 2 damage to that player. addCard(Zone.BATTLEFIELD, playerA, "Eidolon of the Great Revel"); @@ -81,18 +80,18 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { execute(); assertPermanentCount(playerA, "Ashcloud Phoenix", 0); - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); assertLife(playerA, 18); // 2 damage from Eidolon of the Great Revel assertLife(playerB, 18); // 2 damage from Purphoros for the morphed Phoenix - + Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertFalse("Purphoros may not be a creature but it is", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); - } - + } + @Test public void testHybridManaCostsForDevotion() { - + // Indestructible // As long as your devotion to red is less than five, Purphoros isn't a creature. // Whenever another creature enters the battlefield under your control, Purphoros deals 2 damage to each opponent. @@ -101,11 +100,11 @@ public class PurphorosGodOfTheForgeTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Goblin Guide", 1); // {R} addCard(Zone.HAND, playerA, "Boros Reckoner", 1); // {R/W}{R/W}{R/W} addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boros Reckoner"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertLife(playerB, 18); Permanent purphorosGodOfTheForge = getPermanent("Purphoros, God of the Forge", playerA); Assert.assertTrue("Purphoros should be a creature now but is not", purphorosGodOfTheForge.getCardType().contains(CardType.CREATURE)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java index 95d3140bdc..f66f66b05c 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/vis/BroodOfCockroachesTest.java @@ -1,15 +1,16 @@ package org.mage.test.cards.single.vis; -import java.util.UUID; import mage.game.permanent.Permanent; import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; -import static org.hamcrest.core.Is.is; -import static org.junit.Assert.*; +import java.util.UUID; -import static mage.constants.Zone.*; import static mage.constants.PhaseStep.*; +import static mage.constants.Zone.BATTLEFIELD; +import static mage.constants.Zone.HAND; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; public class BroodOfCockroachesTest extends CardTestPlayerBase { @@ -20,7 +21,7 @@ public class BroodOfCockroachesTest extends CardTestPlayerBase { @Test public void should_display_correct_text() { - String expectedText = "When {this} dies, at the beginning of the next end step, you lose 1 life and return Brood of Cockroaches to your hand."; + String expectedText = "When {this} is put into your graveyard from the battlefield, at the beginning of the next end step, you lose 1 life and return {this} to your hand."; playerA_casts_Brood_of_Cockroaches_at_precombat_main_phase(); @@ -29,7 +30,6 @@ public class BroodOfCockroachesTest extends CardTestPlayerBase { Permanent permanent = getPermanent(BROOD_OF_COCKROACHES, playerA); assertThat(permanent.getAbilities().get(1).toString(), is(expectedText)); - } @Test diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PollutedBondsTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PollutedBondsTest.java new file mode 100644 index 0000000000..216e4403a3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/PollutedBondsTest.java @@ -0,0 +1,35 @@ +package org.mage.test.cards.triggers; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class PollutedBondsTest extends CardTestPlayerBase { + + final String pollutedBonds = "Polluted Bonds"; + + @Test + public void PollutedBondsSimple(){ + addCard(Zone.BATTLEFIELD, playerA, pollutedBonds); + addCard(Zone.HAND, playerB, "Forest"); + playLand(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Forest"); + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + assertLife(playerA, 22); + assertLife(playerB, 18); + } + + @Test + public void PollutedBondsOwnLand(){ + addCard(Zone.BATTLEFIELD, playerA, pollutedBonds); + addCard(Zone.HAND, playerA, "Forest"); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest"); + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); + execute(); + assertAllCommandsUsed(); + assertLife(playerA, 20); + assertLife(playerB, 20); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java index 9c45cc42e7..af57b93243 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/SpellskiteTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class SpellskiteTest extends CardTestPlayerBase { @@ -30,6 +28,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Lightning Bolt", 1); assertPermanentCount(playerA, "Spellskite", 1); @@ -80,6 +79,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Spellskite", 1); assertPermanentCount(playerB, "Frost Titan", 1); @@ -119,6 +119,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Lightning Bolt", 1); @@ -160,6 +161,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(2, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Cryptic Command", 1); @@ -188,16 +190,16 @@ public class SpellskiteTest extends CardTestPlayerBase { castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target of target spell or ability to {this}.", "Lightning Bolt"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Lightning Bolt"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Lightning Bolt", 1); assertLife(playerA, 20); assertLife(playerB, 18); - } /** @@ -219,6 +221,7 @@ public class SpellskiteTest extends CardTestPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Flame Slash", 1); assertPowerToughness(playerB, "Spellskite", 3, 7); @@ -238,24 +241,36 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Spellskite"); addCard(Zone.BATTLEFIELD, playerB, "Scute Mob"); addCard(Zone.BATTLEFIELD, playerB, "Island"); + // + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.HAND, playerA, "Fiery Justice"); + // A cast Fiery Justice castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); - addTarget(playerA, "Scute Mob"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Spellskite"); - setChoice(playerA, "X=4"); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "Yes"); + addTarget(playerA, playerB); // 5 life to B + addTarget(playerA, "Scute Mob^X=1"); // target 1 + addTarget(playerA, "Spellskite^X=4"); // target 2 + // B activate Spellskite, but can't change any targets cause it's already targeted + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + showBattlefield("B battle", 1, PhaseStep.BEGIN_COMBAT, playerB); + showGraveyard("B grave", 1, PhaseStep.BEGIN_COMBAT, playerB); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); + assertLife(playerB, 20 + 5 - 2); assertGraveyardCount(playerB, 2); + assertGraveyardCount(playerB, "Scute Mob", 1); + assertGraveyardCount(playerB, "Spellskite", 1); } + @Test public void testThatSplitDamageCanGetRedirected() { /* Standard redirect test The Spellskite should die from the 5 damage that was redirected to it @@ -267,59 +282,64 @@ public class SpellskiteTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Spellskite");// 0/4 creature addCard(Zone.BATTLEFIELD, playerB, "Scute Mob"); // 1/1 creauture addCard(Zone.BATTLEFIELD, playerB, "Island"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.HAND, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets - addTarget(playerA, "Scute Mob"); - setChoice(playerA, "X=5"); + addTarget(playerA, "Scute Mob^X=5"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "Yes"); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + setChoice(playerB, "Yes"); // retarget setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); + assertLife(playerB, 20 + 5 - 2); assertGraveyardCount(playerB, 1); assertPermanentCount(playerB, "Scute Mob", 1); } + @Test public void testThatSplitDamageGetsRedirectedFromTheCorrectChoice() { addCard(Zone.BATTLEFIELD, playerA, "Plains", 1); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); addCard(Zone.BATTLEFIELD, playerA, "Forest", 1); addCard(Zone.BATTLEFIELD, playerB, "Spellskite");// 0/4 creature - addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 creauture - addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); - addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); - addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); + addCard(Zone.BATTLEFIELD, playerB, "Memnite"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Royal Assassin"); // 1/1 + addCard(Zone.BATTLEFIELD, playerB, "Blinking Spirit"); // 2/2 + addCard(Zone.BATTLEFIELD, playerB, "Pearled Unicorn"); // 2/2 addCard(Zone.BATTLEFIELD, playerB, "Island"); addCard(Zone.HAND, playerA, "Fiery Justice"); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fiery Justice"); // 5 damage distributed to any number of targets - addTarget(playerA, "Memnite"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Royal Assassin"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Blinking Spirit"); - setChoice(playerA, "X=1"); - addTarget(playerA, "Pearled Unicorn"); - setChoice(playerA, "X=2");//the unicorn deserves it + addTarget(playerA, "Royal Assassin^X=1"); + addTarget(playerA, "Blinking Spirit^X=2"); + addTarget(playerA, "Pearled Unicorn^X=2"); - - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{UP}: Change a target of target spell or ability to {this}.", "Fiery Justice", "Fiery Justice"); - setChoice(playerA, "No"); - setChoice(playerA, "No"); - setChoice(playerA, "No"); - setChoice(playerA, "Yes"); //of course + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerB, "{U/P}: Change a target", "Fiery Justice", "Fiery Justice"); + setChoice(playerB, "Yes"); // pay 2 life + setChoice(playerB, "No"); // skip royal + setChoice(playerB, "No"); // skip blink + setChoice(playerB, "Yes"); // change pearl setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); - assertGraveyardCount(playerB, 3); - assertPermanentCount(playerB, "Pearled Unicorn", 1);//it lives on - assertPowerToughness(playerB, "Spellskite", 0, 2); + assertLife(playerB, 20 + 5 - 2); + assertGraveyardCount(playerB, "Memnite", 0); + assertGraveyardCount(playerB, "Royal Assassin", 1); + assertGraveyardCount(playerB, "Blinking Spirit", 1); + assertGraveyardCount(playerB, "Pearled Unicorn", 0); + assertGraveyardCount(playerB, "Spellskite", 0); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java index 16973a7acb..f77652b4dd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/BrainMaggotTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class BrainMaggotTest extends CardTestPlayerBase { @@ -16,7 +14,6 @@ public class BrainMaggotTest extends CardTestPlayerBase { * When Brain Maggot enters the battlefield, target opponent reveals his or * her hand and you choose a nonland card from it. Exile that card until * Brain Maggot leaves the battlefield. - * */ @Test public void testCardFromHandWillBeExiled() { @@ -26,10 +23,12 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brain Maggot"); - addTarget(playerA, "Bloodflow Connoisseur"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertPermanentCount(playerA, "Brain Maggot", 1); assertExileCount("Bloodflow Connoisseur", 1); @@ -45,12 +44,22 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.HAND, playerB, "Lightning Bolt", 1); addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + // exile castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Brain Maggot"); - addTarget(playerA, "Bloodflow Connoisseur"); - castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Brain Maggot"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); + showExile("exile", 1, PhaseStep.BEGIN_COMBAT, playerB); + checkExileCount("blood must be in exile", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 1); - setStopAt(1, PhaseStep.DECLARE_ATTACKERS); + // return + castSpell(1, PhaseStep.END_COMBAT, playerB, "Lightning Bolt", "Brain Maggot"); + checkPermanentCount("brain must die", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Brain Maggot", 0); + checkExileCount("blood must return from exile", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Bloodflow Connoisseur", 0); + checkHandCardCount("blood must be in hand", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Bloodflow Connoisseur", 1); + + setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Brain Maggot", 1); assertGraveyardCount(playerB, "Lightning Bolt", 1); @@ -68,11 +77,14 @@ public class BrainMaggotTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Mesmeric Fiend"); - addTarget(playerA, "Bloodflow Connoisseur"); + addTarget(playerA, playerB); + setChoice(playerA, "Bloodflow Connoisseur"); + // castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Mesmeric Fiend"); setStopAt(1, PhaseStep.DECLARE_ATTACKERS); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerA, "Mesmeric Fiend", 1); assertGraveyardCount(playerB, "Lightning Bolt", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java index 0b7b8221ea..63bfb1557f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/OmnathLocusOfRageTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,7 +6,6 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class OmnathLocusOfRageTest extends CardTestPlayerBase { @@ -27,10 +25,10 @@ public class OmnathLocusOfRageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Diabolic Edict", playerA); - addTarget(playerA, playerB); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Diabolic Edict", 1); assertGraveyardCount(playerA, "Omnath, Locus of Rage", 1); @@ -53,12 +51,11 @@ public class OmnathLocusOfRageTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerB, "Mountain", 7); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Lightning Bolt", "Lightning Elemental"); // Dying Lightning Elemental does no longer trigger ability of Omnath - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Blastfire Bolt", "Omnath, Locus of Rage", "Lightning Bolt"); - addTarget(playerA, playerB); - addTarget(playerA, playerB); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Blastfire Bolt", "Omnath, Locus of Rage"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertGraveyardCount(playerB, "Lightning Bolt", 1); assertGraveyardCount(playerB, "Blastfire Bolt", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java index 3551024a71..7661906c85 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/TidehollowScullerTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.triggers.dies; import mage.constants.PhaseStep; @@ -7,8 +6,7 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * - * @author LevelX2 + * @author LevelX2, JayDi85 */ public class TidehollowScullerTest extends CardTestPlayerBase { @@ -17,43 +15,104 @@ public class TidehollowScullerTest extends CardTestPlayerBase { * Test if the same Tidehollow Sculler is cast multiple times, the correct * corresponding exiled cards are returned */ + @Test - public void testCardFromHandWillBeExiled() { + public void test_CastOneCardFromHandWillBeExiled() { addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); addCard(Zone.BATTLEFIELD, playerA, "Island", 2); addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); // Tidehollow Sculler {W}{B} // When Tidehollow Sculler enters the battlefield, target opponent reveals their hand and you choose a nonland card from it. Exile that card. // When Tidehollow Sculler leaves the battlefield, return the exiled card to its owner's hand. - addCard(Zone.HAND, playerA, "Tidehollow Sculler", 1); - // Boomerang {U}{U} - // Return target creature card from your graveyard to your hand. - addCard(Zone.HAND, playerA, "Boomerang", 1); - // Scout's Warning {W} - // The next creature card you play this turn can be played as though it had flash. - // Draw a card. - addCard(Zone.HAND, playerA, "Scout's Warning", 1); + addCard(Zone.HAND, playerA, "Tidehollow Sculler", 1); // 2/2 + addCard(Zone.HAND, playerA, "Lightning Bolt", 1); // {R} + // + addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); + + // cast and exile from hand + checkHandCardCount("B hand must have blood", 1, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 1); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Bloodflow Connoisseur"); // card to exile + checkHandCardCount("B hand must lost blood", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 0); + + // destroy and return card to hand + checkPermanentCount("A must have tide", 1, PhaseStep.END_COMBAT, playerA, "Tidehollow Sculler", 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Tidehollow Sculler"); + checkPermanentCount("A must lost tide", 1, PhaseStep.END_TURN, playerA, "Tidehollow Sculler", 0); + checkHandCardCount("B must return blood", 1, PhaseStep.END_TURN, playerB, "Bloodflow Connoisseur", 1); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertHandCount(playerB, "Bloodflow Connoisseur", 1); + assertPermanentCount(playerA, "Tidehollow Sculler", 0); + } + + @Test + public void test_CastTwoCardFromHandWillBeExiled() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2); + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2); + // Tidehollow Sculler {W}{B} + // When Tidehollow Sculler enters the battlefield, target opponent reveals their hand and you choose a nonland card from it. Exile that card. + // When Tidehollow Sculler leaves the battlefield, return the exiled card to its owner's hand. + addCard(Zone.HAND, playerA, "Tidehollow Sculler@tide", 2); // 2/2 + addCard(Zone.HAND, playerA, "Lightning Bolt", 2); // {R} + // addCard(Zone.HAND, playerB, "Bloodflow Connoisseur", 1); addCard(Zone.HAND, playerB, "Silvercoat Lion", 1); + // turn 1 - A + // cast 1 and exile from hand + checkHandCardCount("B hand must have blood", 1, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 1); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler"); - addTarget(playerA, "Bloodflow Connoisseur"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Tidehollow Sculler"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Scout's Warning", null, "Boomerang"); - castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tidehollow Sculler", null, "", "When {this} leaves the battlefield, return the exiled card to its owner's hand."); - addTarget(playerA, "Silvercoat Lion"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Bloodflow Connoisseur"); // card to exile + checkHandCardCount("B hand must lost blood", 1, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 0); + // cast 2 and exile from hand + checkHandCardCount("B hand must have lion", 1, PhaseStep.END_COMBAT, playerB, "Silvercoat Lion", 1); + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tidehollow Sculler"); + addTarget(playerA, playerB); // choose opponent + setChoice(playerA, "Silvercoat Lion"); // card to exile + checkHandCardCount("B hand must lost lion", 1, PhaseStep.END_TURN, playerB, "Silvercoat Lion", 0); - setStopAt(1, PhaseStep.BEGIN_COMBAT); + // turn 2 - B + // destroy 1 and return card to hand + checkPermanentCount("A must have 2 tide", 2, PhaseStep.UPKEEP, playerA, "Tidehollow Sculler", 2); + checkHandCardCount("B hand must have 0 blood", 2, PhaseStep.UPKEEP, playerB, "Bloodflow Connoisseur", 0); + castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@tide.1"); + showHand("B hand", 2, PhaseStep.BEGIN_COMBAT, playerB); + checkPermanentCount("A must have 1 tide", 2, PhaseStep.BEGIN_COMBAT, playerA, "Tidehollow Sculler", 1); + checkHandCardCount("B hand must have 1 blood", 2, PhaseStep.BEGIN_COMBAT, playerB, "Bloodflow Connoisseur", 1); + // destroy 2 and return card to hand + checkPermanentCount("A must have 1 tide", 2, PhaseStep.END_COMBAT, playerA, "Tidehollow Sculler", 1); + checkHandCardCount("B hand must have 0 lion", 2, PhaseStep.END_COMBAT, playerB, "Silvercoat Lion", 0); + castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "@tide.2"); + checkPermanentCount("A must have 0 tide", 2, PhaseStep.END_TURN, playerA, "Tidehollow Sculler", 0); + checkHandCardCount("B hand must have 1 lion", 2, PhaseStep.END_TURN, playerB, "Silvercoat Lion", 1); + + setStopAt(2, PhaseStep.END_TURN); execute(); - - assertGraveyardCount(playerA,"Boomerang", 1); - assertGraveyardCount(playerA,"Scout's Warning", 1); - assertHandCount(playerB, "Bloodflow Connoisseur", 0); // never comes back because first Tidehollow Sculler left battlefield before target was exiled - assertHandCount(playerB, "Silvercoat Lion", 0); - assertExileCount("Silvercoat Lion", 1); - - assertPermanentCount(playerA, "Tidehollow Sculler", 1); - + assertAllCommandsUsed(); } + + @Test + public void test_MultipleRuns() { + // test random selection by AI (must use direct select by alias, not AI) + for (int i = 1; i <= 10; i++) { + try { + this.reset(); + System.out.println("run " + i); + test_CastTwoCardFromHandWillBeExiled(); + } catch (Exception e) { + // + } + } + } + } \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java index e2a1849c84..e6a48d117a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/triggers/dies/WhisperwoodElementalTest.java @@ -1,6 +1,6 @@ - package org.mage.test.cards.triggers.dies; +import mage.constants.EmptyNames; import mage.constants.PhaseStep; import mage.constants.Zone; import org.junit.Test; @@ -18,7 +18,6 @@ public class WhisperwoodElementalTest extends CardTestPlayerBase { /** * Tests that the dies triggered ability of silvercoat lion (gained by sacrificed Whisperwood Elemental) * triggers as he dies from Ligning Bolt - * */ @Test public void testDiesTriggeredAbility() { @@ -30,17 +29,20 @@ public class WhisperwoodElementalTest extends CardTestPlayerBase { activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice {this}: Until end of turn, face-up, nontoken creatures you control gain \"When this creature dies, manifest the top card of your library."); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion"); + showBattlefield("A battle", 1, PhaseStep.END_TURN, playerA); + showGraveyard("A grave", 1, PhaseStep.END_TURN, playerA); setStopAt(1, PhaseStep.END_TURN); execute(); + assertAllCommandsUsed(); assertLife(playerA, 20); assertLife(playerB, 20); - + assertGraveyardCount(playerA, "Whisperwood Elemental", 1); assertGraveyardCount(playerA, "Silvercoat Lion", 1); // Manifested creature from dying Silvercoat Lion - assertPermanentCount(playerA, "", 1); + assertPermanentCount(playerA, EmptyNames.FACE_DOWN_CREATURE.toString(), 1); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/CommanderColorIdentityTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/CommanderColorIdentityTest.java index 293bde40aa..7dcfa0c827 100644 --- a/Mage.Tests/src/test/java/org/mage/test/commander/CommanderColorIdentityTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/commander/CommanderColorIdentityTest.java @@ -1,11 +1,9 @@ - package org.mage.test.commander; import mage.cards.Card; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.filter.FilterMana; -import mage.util.CardUtil; import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestCommander3PlayersFFA; diff --git a/Mage.Tests/src/test/java/org/mage/test/commander/duel/MythUnboundTest.java b/Mage.Tests/src/test/java/org/mage/test/commander/duel/MythUnboundTest.java new file mode 100644 index 0000000000..0388fbde92 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/commander/duel/MythUnboundTest.java @@ -0,0 +1,51 @@ +package org.mage.test.commander.duel; + +import java.io.FileNotFoundException; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.GameException; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestCommanderDuelBase; + +/** + * + * @author LevelX2 + */ +public class MythUnboundTest extends CardTestCommanderDuelBase { + + @Override + protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { + // Karador, Ghost Chieftain costs {1} less to cast for each creature card in your graveyard. + // During each of your turns, you may cast one creature card from your graveyard. + setDecknamePlayerA("CommanderOviya.dck"); // Commander = Oviya Pashiri, Sage Lifecrafter {G} + setDecknamePlayerB("CMDNorinTheWary.dck"); + + return super.createNewGameAndPlayers(); + } + + @Test + public void castCommanderTwice() { + addCard(Zone.BATTLEFIELD, playerA, "Forest", 4); + // Your commander costs {1} less to cast for each time it's been cast from the command zone this game. + // Whenever your commander is put into the command zone from anywhere, draw a card. + addCard(Zone.BATTLEFIELD, playerA, "Myth Unbound", 1); // Enchantment {2}{G} + + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 2); + addCard(Zone.HAND, playerB, "Lightning Bolt", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Oviya Pashiri, Sage Lifecrafter"); + + castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Oviya Pashiri, Sage Lifecrafter"); + + castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Oviya Pashiri, Sage Lifecrafter"); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Myth Unbound", 1); + assertGraveyardCount(playerB, "Lightning Bolt", 1); + assertPermanentCount(playerA, "Oviya Pashiri, Sage Lifecrafter", 1); + assertHandCount(playerA, 1); + assertTappedCount("Forest", false, 1); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java index ef91492177..352ec36de5 100644 --- a/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/lki/LastKnownInformationTest.java @@ -58,7 +58,7 @@ public class LastKnownInformationTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Soldier", 2); assertGraveyardCount(playerB, "Lightning Bolt", 2); - assertActionCount(playerB, 0); + assertActionsCount(playerB, 0); } diff --git a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java index afe179f7c7..3db7ae9200 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/LoadTest.java @@ -1,18 +1,11 @@ package org.mage.test.load; -import java.time.Instant; -import java.time.temporal.ChronoUnit; -import java.util.*; import mage.cards.Card; -import mage.cards.Sets; import mage.cards.decks.Deck; -import mage.cards.decks.DeckCardInfo; import mage.cards.decks.DeckCardLists; -import mage.cards.repository.CardInfo; -import mage.cards.repository.CardRepository; +import mage.cards.repository.CardScanner; import mage.constants.*; import mage.game.match.MatchOptions; -import mage.player.ai.ComputerPlayer; import mage.players.PlayerType; import mage.remote.Connection; import mage.remote.MageRemoteException; @@ -22,16 +15,22 @@ import mage.util.RandomUtil; import mage.view.*; import org.apache.log4j.Logger; import org.junit.Assert; +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; +import org.mage.test.utils.DeckTestUtils; + +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.*; /** * Intended to test Mage server under different load patterns. - * + *

    * These tests do use server started separately, so Mage server should be * started before running them. In case you want to debug these tests, use * -Ddebug.mage that would disable client-server request timeout. - * + *

    * Then it's also better to use -Xms256M -Xmx512M JVM options for these stests. * * @author JayDi85 @@ -45,48 +44,61 @@ public class LoadTest { private static final String TEST_PROXY_TYPE = "None"; private static final String TEST_USER_NAME = "user"; + @BeforeClass + public static void initDatabase() { + // recreate missing cards db + CardScanner.scan(); + } + @Test public void test_CreateRandomDeck() { Deck deck; - deck = generateRandomDeck("G", false); + deck = DeckTestUtils.buildRandomDeck("G", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in G", card.getColorIdentity().isGreen()); } - deck = generateRandomDeck("U", false); + deck = DeckTestUtils.buildRandomDeck("U", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in U", card.getColorIdentity().isBlue()); } - deck = generateRandomDeck("BR", false); + deck = DeckTestUtils.buildRandomDeck("BR", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BR", card.getColorIdentity().isBlack() || card.getColorIdentity().isRed()); } - deck = generateRandomDeck("BUG", false); + deck = DeckTestUtils.buildRandomDeck("BUG", false); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in BUG", card.getColorIdentity().isBlack() || card.getColorIdentity().isBlue() || card.getColorIdentity().isGreen()); } // lands - deck = generateRandomDeck("UR", true); + deck = DeckTestUtils.buildRandomDeck("UR", true); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in UR", card.getColorIdentity().isBlue() || card.getColorIdentity().isRed()); Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity()); } - deck = generateRandomDeck("B", true); + deck = DeckTestUtils.buildRandomDeck("B", true); for (Card card : deck.getCards()) { Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in B", card.getColorIdentity().isBlack()); Assert.assertEquals("card " + card.getName() + " must be basic land ", Rarity.LAND, card.getRarity()); } + + // allowed sets + deck = DeckTestUtils.buildRandomDeck("B", true, "GRN"); + for (Card card : deck.getCards()) { + Assert.assertTrue("card " + card.getName() + " color " + card.getColorIdentity().toString() + " must be in B", card.getColorIdentity().isBlack()); + Assert.assertEquals("card " + card.getName() + " have wrong set code " + card.getExpansionSetCode(), "GRN", card.getExpansionSetCode()); + } } @Test @@ -131,7 +143,7 @@ public class LoadTest { UUID tableId = game.getTableId(); Assert.assertEquals(player1.userName, game.getControllerName()); - DeckCardLists deckList = createSimpleDeck("GR", true); + DeckCardLists deckList = DeckTestUtils.buildRandomDeckAndInitCards("GR", true); Optional checkGame; /* @@ -176,9 +188,9 @@ public class LoadTest { } } - @Test - @Ignore - public void test_TwoAIPlayGameUntilEnd() { + public void playTwoAIGame(String deckColors, String deckAllowedSets) { + Assert.assertFalse("need deck colors", deckColors.isEmpty()); + Assert.assertFalse("need allowed sets", deckAllowedSets.isEmpty()); // monitor and game source LoadPlayer monitor = new LoadPlayer("monitor"); @@ -189,7 +201,7 @@ public class LoadTest { TableView game = monitor.session.createTable(monitor.roomID, gameOptions); UUID tableId = game.getTableId(); - DeckCardLists deckList = createSimpleDeck("GR", false); + DeckCardLists deckList = DeckTestUtils.buildRandomDeckAndInitCards(deckColors, false, deckAllowedSets); Optional checkGame; // join AI @@ -220,7 +232,6 @@ public class LoadTest { for (PlayerView p : gameView.getPlayers()) { logger.info(p.getName() + " - Life=" + p.getLife() + "; Lib=" + p.getLibraryCount()); } - } try { @@ -231,6 +242,31 @@ public class LoadTest { } } + @Test + @Ignore + public void test_TwoAIPlayGame_One() { + playTwoAIGame("GR", "GRN"); + } + + @Test + @Ignore + public void test_TwoAIPlayGame_Multiple() { + + // save random seeds for repeated results + Integer gamesAmount = 1000; + List seedsList = new ArrayList<>(); + for (int i = 1; i <= gamesAmount; i++) { + seedsList.add(RandomUtil.nextInt()); + } + + for (int i = 1; i <= 1000; i++) { + long randomSeed = seedsList.get(i); + logger.info("RANDOM seed: " + randomSeed); + RandomUtil.setSeed(randomSeed); + playTwoAIGame("WGUBR", "SWS"); + } + } + @Test @Ignore public void test_GameThread() { @@ -239,8 +275,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); @@ -263,8 +299,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); game.gameEnd(true); // abort -- close client thread @@ -279,8 +315,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", false), - createSimpleDeck("GR", false) + DeckTestUtils.buildRandomDeckAndInitCards("GR", false, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", false, "") ); game.gameStart(); @@ -296,8 +332,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game", "thread", - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); game.gameStart(); @@ -329,8 +365,8 @@ public class LoadTest { LoadGame game = new LoadGame( "game" + i, "game" + i, - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); gamesList.add(game); @@ -380,7 +416,7 @@ public class LoadTest { } if (errors.size() > 0) { - System.out.println("Not all games finished, founded " + errors.size() + " errors: "); + System.out.println("Not all games finished, found " + errors.size() + " errors: "); for (String s : errors) { System.out.println(s); } @@ -421,31 +457,6 @@ public class LoadTest { return createSimpleGameOptions("AI test game", gameTypeView, session, PlayerType.COMPUTER_MAD); } - private Deck generateRandomDeck(String colors, boolean onlyBasicLands) { - logger.info("Building " + (onlyBasicLands ? "only lands" : "random") + " deck with colors: " + colors); - - List allowedColors = new ArrayList<>(); - for (int i = 0; i < colors.length(); i++) { - char c = colors.charAt(i); - allowedColors.add(ColoredManaSymbol.lookup(c)); - } - List cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands); - return ComputerPlayer.buildDeck(cardPool, allowedColors, onlyBasicLands); - } - - private DeckCardLists createSimpleDeck(String colors, boolean onlyBasicLands) { - Deck deck = generateRandomDeck(colors, onlyBasicLands); - - DeckCardLists deckList = new DeckCardLists(); - for (Card card : deck.getCards()) { - CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber()); - if (cardInfo != null) { - deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); - } - } - return deckList; - } - private class LoadPlayer { String userName; @@ -541,8 +552,8 @@ public class LoadTest { public LoadGame(String gameName, String playerPrefix) { this(gameName, playerPrefix, - createSimpleDeck("GR", true), - createSimpleDeck("GR", true) + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, ""), + DeckTestUtils.buildRandomDeckAndInitCards("GR", true, "") ); } diff --git a/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java b/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java index 305b041106..2a5b9445d0 100644 --- a/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java +++ b/Mage.Tests/src/test/java/org/mage/test/load/SimpleMageClient.java @@ -1,6 +1,5 @@ package org.mage.test.load; -import java.util.UUID; import mage.interfaces.MageClient; import mage.interfaces.callback.ClientCallback; import mage.remote.Session; @@ -8,6 +7,8 @@ import mage.utils.MageVersion; import mage.view.GameView; import org.apache.log4j.Logger; +import java.util.UUID; + /** * For tests only * @@ -16,7 +17,7 @@ import org.apache.log4j.Logger; public class SimpleMageClient implements MageClient { private final UUID clientId; - private static final MageVersion version = new MageVersion(MageVersion.MAGE_VERSION_MAJOR, MageVersion.MAGE_VERSION_MINOR, MageVersion.MAGE_VERSION_PATCH, MageVersion.MAGE_VERSION_MINOR_PATCH, MageVersion.MAGE_VERSION_INFO); + private static final MageVersion version = new MageVersion(MageClient.class); private static final Logger log = Logger.getLogger(SimpleMageClient.class); @@ -38,7 +39,7 @@ public class SimpleMageClient implements MageClient { } @Override - public void disconnected(boolean errorCall) { + public void disconnected(boolean askToReconnect) { // do nothing } @@ -62,11 +63,11 @@ public class SimpleMageClient implements MageClient { } public void setSession(Session session) { - ((LoadCallbackClient) callbackClient).setSession(session); + callbackClient.setSession(session); } public boolean isGameOver() { - return ((LoadCallbackClient) callbackClient).isGameOver(); + return callbackClient.isGameOver(); } public void setConcede(boolean needToConcede) { diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/CanadianHighlanderMulliganTest.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/CanadianHighlanderMulliganTest.java new file mode 100644 index 0000000000..74e72cd76f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/CanadianHighlanderMulliganTest.java @@ -0,0 +1,249 @@ +package org.mage.test.mulligan; + +import mage.game.mulligan.MulliganType; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +public class CanadianHighlanderMulliganTest extends MulliganTestBase { + + @Test + public void testCanadianHighlanderMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testCanadianHighlanderMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNTopOfLibrary(1))); + }); + } + + @Test + public void testCanadianHighlanderMulligan_OneMulligan_Scry() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return true; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNBottomOfLibrary(1))); + }); + } + + @Test + public void testCanadianHighlanderMulligan_TwoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(21, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(28, 6))); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(21, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(28, 6))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(21, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(28, 6))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNTopOfLibrary(1))); + }); + } + + @Test + public void testCanadianHighlanderMulligan_ThreeMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + Set hand4 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(21, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(28, 6))); + hand3.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(16, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(23, 6))); + assertEquals(hand3, new HashSet<>(scenario.getLibraryRangeSize(29, 6))); + hand4.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + scenario.assertSizes(5, 35); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(16, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(23, 6))); + assertEquals(hand3, new HashSet<>(scenario.getLibraryRangeSize(29, 6))); + assertEquals(hand4, scenario.getHand()); + scry.add(scenario.getLibraryTopCard()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(5, 35); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(16, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(23, 6))); + assertEquals(hand3, new HashSet<>(scenario.getLibraryRangeSize(29, 6))); + assertEquals(hand4, scenario.getHand()); + assertEquals(scry, new HashSet<>(scenario.getNTopOfLibrary(1))); + }); + } + + @Test + public void testCanadianHighlanderMulligan_AlwaysMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.CANADIAN_HIGHLANDER, 0); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(4, 36); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(4, 36); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(3, 37); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(3, 37); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(2, 38); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(2, 38); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(1, 39); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(1, 39); + return true; + }); + scenario.scry(() -> { + scenario.assertSizes(0, 40); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(0, 40); + }); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/LondonMulliganTest.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/LondonMulliganTest.java new file mode 100644 index 0000000000..ed9a7c8abb --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/LondonMulliganTest.java @@ -0,0 +1,277 @@ +package org.mage.test.mulligan; + +import com.google.common.collect.Sets; +import mage.game.mulligan.MulliganType; +import org.junit.Test; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; + +public class LondonMulliganTest extends MulliganTestBase { + + @Test + public void testLondonMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 0); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testLondonMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + List discarded = new ArrayList<>(); + Set remainingHand = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(1, count); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + scenario.getHand().stream().limit(count).forEach(discarded::add); + remainingHand.addAll(Sets.difference(scenario.getHand(), new HashSet<>(discarded))); + return discarded; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(remainingHand, scenario.getHand()); + hand2.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(remainingHand, new HashSet<>(scenario.getHand())); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, scenario.getHand()); + assertEquals(discarded, scenario.getNBottomOfLibrary(1)); + }); + } + + @Test + public void testLondonMulligan_TwoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + List discarded = new ArrayList<>(); + Set remainingHand = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(1, count); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + scenario.getHand().stream().limit(count).forEach(discarded::add); + remainingHand.addAll(Sets.difference(scenario.getHand(), new HashSet<>(discarded))); + return discarded; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(2, count); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(discarded, scenario.getLibraryRangeSize(26, 1)); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 6))); + discarded.clear(); + remainingHand.clear(); + scenario.getHand().stream().limit(count).forEach(discarded::add); + remainingHand.addAll(Sets.difference(scenario.getHand(), new HashSet<>(discarded))); + return discarded; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 6))); + assertEquals(discarded, scenario.getNBottomOfLibrary(2)); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(5, 35); + assertEquals(remainingHand, new HashSet<>(scenario.getHand())); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 6))); + assertEquals(hand3, scenario.getHand()); + assertEquals(discarded, scenario.getNBottomOfLibrary(2)); + }); + } + + @Test + public void testLondonMulligan_FreeMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 1); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testLondonMulligan_FreeMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand2.addAll(scenario.getHand()); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testLondonMulligan_FreeMulligan_TwoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + List discarded = new ArrayList<>(); + Set remainingHand = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(1, count); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + scenario.getHand().stream().limit(count).forEach(discarded::add); + remainingHand.addAll(Sets.difference(scenario.getHand(), new HashSet<>(discarded))); + return discarded; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(discarded, scenario.getNBottomOfLibrary(1)); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand3, scenario.getHand()); + assertEquals(remainingHand, new HashSet<>(scenario.getHand())); + assertEquals(discarded, scenario.getNBottomOfLibrary(1)); + }); + } + + @Test + public void testLondonMulligan_AlwaysMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.LONDON, 0); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(1, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(2, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(3, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(4, 36); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(4, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(3, 37); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(5, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(2, 38); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(6, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.mulligan(() -> { + scenario.assertSizes(1, 39); + return true; + }); + scenario.discardBottom(count -> { + scenario.assertSizes(7, 33); + assertEquals(7, count); + return scenario.getHand().stream().limit(count).collect(Collectors.toList()); + }); + scenario.run(() -> { + scenario.assertSizes(0, 40); + }); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganTestBase.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganTestBase.java new file mode 100644 index 0000000000..711d9792b7 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/MulliganTestBase.java @@ -0,0 +1,433 @@ + +package org.mage.test.mulligan; + +import mage.MageItem; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.Modes; +import mage.abilities.TriggeredAbility; +import mage.abilities.costs.VariableCost; +import mage.abilities.costs.mana.ManaCost; +import mage.cards.Card; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.basiclands.Forest; +import mage.cards.decks.Deck; +import mage.choices.Choice; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.game.GameOptions; +import mage.game.TwoPlayerDuel; +import mage.game.combat.CombatGroup; +import mage.game.draft.Draft; +import mage.game.match.Match; +import mage.game.mulligan.Mulligan; +import mage.game.mulligan.MulliganType; +import mage.game.permanent.Permanent; +import mage.game.tournament.Tournament; +import mage.players.Player; +import mage.players.PlayerImpl; +import mage.target.Target; +import mage.target.TargetAmount; +import mage.target.TargetCard; +import mage.target.TargetPlayer; +import org.apache.log4j.Logger; + +import java.io.Serializable; +import java.util.*; +import java.util.stream.Stream; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkState; +import static com.google.common.collect.Iterables.getOnlyElement; +import static java.util.Collections.unmodifiableList; +import static java.util.Collections.unmodifiableSet; +import static java.util.stream.Collectors.toList; +import static mage.constants.MultiplayerAttackOption.LEFT; +import static mage.constants.RangeOfInfluence.ONE; +import static mage.constants.Rarity.LAND; +import static org.junit.Assert.*; + +public class MulliganTestBase { + + protected static Logger logger = Logger.getLogger(MulliganTestBase.class); + + static class MulliganScenarioTest { + + private final MulliganType mulliganType; + private final int freeMulligans; + private final List steps = new ArrayList<>(); + + private PlayerProxy player1; + + public MulliganScenarioTest(MulliganType mulliganType, int freeMulligans) { + this.mulliganType = mulliganType; + this.freeMulligans = freeMulligans; + } + + public void mulligan(MulliganStep step) { + steps.add(step); + } + + public void scry(ScryStep step) { + steps.add(step); + } + + public void discardBottom(DiscardBottomStep step) { + steps.add(step); + } + + public void run(Runnable callback) { + Mulligan mulligan = mulliganType.getMulligan(freeMulligans); + Game game = new TwoPlayerDuel(LEFT, ONE, mulligan, 20) { + @Override + public void fireStatusEvent(String message, boolean withTime) { + super.fireStatusEvent(message, withTime); + } + + @Override + protected void play(UUID nextPlayerId) { + } + }; + GameOptions options = new GameOptions(); + options.skipInitShuffling = true; + game.setGameOptions(options); + + this.player1 = new PlayerProxy("p1", ONE); + player1.setSteps(steps); + Deck deck1 = generateDeck(player1.getId(), 40); + game.loadCards(deck1.getCards(), player1.getId()); + game.addPlayer(player1, deck1); + + PlayerProxy player2 = new PlayerProxy("p2", ONE); + Deck deck2 = generateDeck(player2.getId(), 40); + game.loadCards(deck2.getCards(), player2.getId()); + game.addPlayer(player2, deck2); + + game.start(player1.getId()); + + player1.assertStepsComplete(); + callback.run(); + } + + public Set getHand() { + checkState(player1 != null); + return unmodifiableSet(player1.getHand()); + } + + public List getLibrary() { + checkState(player1 != null); + return unmodifiableList(player1.getLibrary().getCardList()); + } + + public List getNTopOfLibrary(int n) { + checkState(player1 != null); + List library = getLibrary(); + checkArgument(n <= library.size()); + return unmodifiableList(library.subList(0, n)); + } + + public List getNBottomOfLibrary(int n) { + checkState(player1 != null); + List library = getLibrary(); + checkArgument(n <= library.size()); + return unmodifiableList(library.subList(library.size() - n, library.size())); + } + + + public List getLibraryRangeSize(int start, int n) { + return getLibraryRangeIndex(start, start + n); + } + + public List getLibraryRangeIndex(int start, int end) { + checkArgument(end >= start); + checkState(player1 != null); + List library = getLibrary(); + checkArgument(end <= library.size()); + return unmodifiableList(library.subList(start, end)); + } + + public UUID getLibraryTopCard() { + return getOnlyElement(getNTopOfLibrary(1)); + } + + public void assertSizes(int handSize, int librarySize) { + assertEquals("hand size", handSize, getHand().size()); + assertEquals("library size", librarySize, getLibrary().size()); + } + + } + + public static Deck generateDeck(UUID playerId, int count) { + Deck deck = new Deck(); + Stream.generate(() -> new Forest(playerId, new CardSetInfo("Forest", "TEST", "1", LAND))) + .limit(count) + .forEach(deck.getCards()::add); + return deck; + } + + interface Step {} + + interface MulliganStep extends Step { + boolean mulligan(); + } + + interface ScryStep extends Step { + boolean scry(); + } + + interface DiscardBottomStep extends Step { + List discardBottom(int count); + } + + static class PlayerProxy extends StubPlayer { + + private List steps = null; + private int current = 0; + + public PlayerProxy(String name, RangeOfInfluence range) { + super(name, range); + } + + @Override + public boolean chooseMulligan(Game game) { + if (steps == null) { + return super.chooseMulligan(game); + } + if (current >= steps.size()) { + fail("Tried to mulligan without a test step."); + } + Step step = steps.get(current++); + assertTrue("Expected mulligan step.", + MulliganStep.class.isAssignableFrom(step.getClass())); + return ((MulliganStep) step).mulligan(); + } + + @Override + public boolean chooseScry(Game game, UUID cardId) { + if (steps == null) { + return super.chooseScry(game, cardId); + } + if (current >= steps.size()) { + fail("Tried to scry without a test step."); + } + Step step = steps.get(current++); + assertTrue("Expected scry step.", + ScryStep.class.isAssignableFrom(step.getClass())); + return ((ScryStep) step).scry(); + } + + @Override + public List chooseDiscardBottom(Game game, int count, List cardIds) { + if (steps == null) { + return super.chooseDiscardBottom(game, count, cardIds); + } + if (current >= steps.size()) { + fail("Tried to discard without a test step."); + } + Step step = steps.get(current++); + assertTrue("Expected discard bottom step.", + DiscardBottomStep.class.isAssignableFrom(step.getClass())); + return ((DiscardBottomStep) step).discardBottom(count); + } + + public void setSteps(List steps) { + this.steps = steps; + } + + public void assertStepsComplete() { + assertEquals(steps.size(), current); + } + + } + + static class StubPlayer extends PlayerImpl implements Player { + + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + if (target instanceof TargetPlayer) { + for (Player player : game.getPlayers().values()) { + if (player.getId().equals(getId()) && target.canTarget(getId(), game)) { + target.add(player.getId(), game); + return true; + } + } + } + return false; + } + + public boolean choose(Outcome outcome, Cards cards, TargetCard target, Game game) { + cards.getCards(game).stream().map(MageItem::getId).forEach(cardId -> target.add(cardId, game)); + return true; + } + + @Override + public boolean chooseTarget(Outcome outcome, Cards cards, TargetCard target, Ability source, Game game) { + if ("cards to PUT on the BOTTOM of your library (Discard for Mulligan)".equals(target.getFilter().getMessage())) { + chooseDiscardBottom(game, target.getMinNumberOfTargets(), cards.getCards(game) + .stream().map(MageItem::getId).collect(toList())).forEach(cardId -> target.add(cardId, game)); + } else { + UUID cardId = getOnlyElement(cards.getCards(game)).getId(); + if (chooseScry(game, cardId)) { + target.add(cardId, game); + return true; + } + } + return false; + } + + public List chooseDiscardBottom(Game game, int count, List cardIds) { + return cardIds.subList(0, count); + } + + public boolean chooseScry(Game game, UUID cardId) { + return false; + } + + @Override + public void shuffleLibrary(Ability source, Game game) { + + } + + public StubPlayer(String name, RangeOfInfluence range) { + super(name, range); + } + + @Override + public void abort() { + + } + + @Override + public void skip() { + + } + + @Override + public Player copy() { + return null; + } + + @Override + public boolean priority(Game game) { + return false; + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { + return false; + } + + @Override + public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { + return false; + } + + @Override + public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game) { + return false; + } + + @Override + public boolean chooseMulligan(Game game) { + return false; + } + + @Override + public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { + return false; + } + + @Override + public boolean chooseUse(Outcome outcome, String message, String secondMessage, String trueText, String falseText, Ability source, Game game) { + return false; + } + + @Override + public boolean choose(Outcome outcome, Choice choice, Game game) { + return false; + } + + @Override + public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { + return false; + } + + @Override + public boolean playMana(Ability ability, ManaCost unpaid, String promptText, Game game) { + return false; + } + + @Override + public int announceXMana(int min, int max, String message, Game game, Ability ability) { + return 0; + } + + @Override + public int announceXCost(int min, int max, String message, Game game, Ability ability, VariableCost variableCost) { + return 0; + } + + @Override + public int chooseReplacementEffect(Map abilityMap, Game game) { + return 0; + } + + @Override + public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { + return null; + } + + @Override + public Mode chooseMode(Modes modes, Ability source, Game game) { + return null; + } + + @Override + public void selectAttackers(Game game, UUID attackingPlayerId) { + + } + + @Override + public void selectBlockers(Game game, UUID defendingPlayerId) { + + } + + @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 void assignDamage(int damage, List targets, String singleTargetName, UUID sourceId, Game game) { + + } + + @Override + public int getAmount(int min, int max, String message, Game game) { + return 0; + } + + @Override + public void sideboard(Match match, Deck deck) { + + } + + @Override + public void construct(Tournament tournament, Deck deck) { + + } + + @Override + public void pickCard(List cards, Deck deck, Draft draft) { + + } + + } + +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/ParisMulliganTest.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/ParisMulliganTest.java new file mode 100644 index 0000000000..fc99d063ca --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/ParisMulliganTest.java @@ -0,0 +1,181 @@ +package org.mage.test.mulligan; + +import mage.game.mulligan.MulliganType; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +public class ParisMulliganTest extends MulliganTestBase { + + @Test + public void testParisMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 0); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testParisMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + hand2.addAll(scenario.getHand()); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testParisMulligan_OneMulligan_Scry() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + hand2.addAll(scenario.getHand()); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testParisMulligan_FreeMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 1); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testParisMulligan_FreeMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand2.addAll(scenario.getHand()); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testParisMulligan_FreeMulligan_TwoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testParisMulligan_AlwaysMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.PARIS, 0); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(4, 36); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(3, 37); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(2, 38); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(1, 39); + return true; + }); + scenario.run(() -> { + scenario.assertSizes(0, 40); + }); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/mulligan/VancouverMulliganTest.java b/Mage.Tests/src/test/java/org/mage/test/mulligan/VancouverMulliganTest.java new file mode 100644 index 0000000000..1a5e2a5b0e --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/mulligan/VancouverMulliganTest.java @@ -0,0 +1,251 @@ +package org.mage.test.mulligan; + +import mage.game.mulligan.MulliganType; +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import static org.junit.Assert.assertEquals; + +public class VancouverMulliganTest extends MulliganTestBase { + + @Test + public void testVancouverMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 0); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testVancouverMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNTopOfLibrary(1))); + }); + } + + @Test + public void testVancouverMulligan_OneMulligan_Scry() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 0); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand2.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return true; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNBottomOfLibrary(1))); + }); + } + + @Test + public void testVancouverMulligan_FreeMulligan_NoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 1); + Set hand1 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, scenario.getHand()); + }); + } + + @Test + public void testVancouverMulligan_FreeMulligan_OneMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand2.addAll(scenario.getHand()); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand2, new HashSet<>(scenario.getHand())); + }); + } + + @Test + public void testVancouverMulligan_FreeMulligan_TwoMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNTopOfLibrary(1))); + }); + } + + @Test + public void testVancouverMulligan_FreeMulligan_TwoMulligan_Scry() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 1); + Set hand1 = new HashSet<>(); + Set hand2 = new HashSet<>(); + Set hand3 = new HashSet<>(); + Set scry = new HashSet<>(); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + hand1.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + hand2.addAll(scenario.getHand()); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + hand3.addAll(scenario.getHand()); + return false; + }); + scenario.scry(() -> { + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(20, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(27, 7))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + scry.add(scenario.getLibraryTopCard()); + return true; + }); + scenario.run(() -> { + scenario.assertSizes(6, 34); + assertEquals(hand1, new HashSet<>(scenario.getLibraryRangeSize(19, 7))); + assertEquals(hand2, new HashSet<>(scenario.getLibraryRangeSize(26, 7))); + assertEquals(hand3, new HashSet<>(scenario.getHand())); + assertEquals(scry, new HashSet<>(scenario.getNBottomOfLibrary(1))); + }); + } + + @Test + public void testVancouverMulligan_AlwaysMulligan() { + MulliganScenarioTest scenario = new MulliganScenarioTest(MulliganType.VANCOUVER, 0); + scenario.mulligan(() -> { + scenario.assertSizes(7, 33); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(6, 34); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(5, 35); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(4, 36); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(3, 37); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(2, 38); + return true; + }); + scenario.mulligan(() -> { + scenario.assertSizes(1, 39); + return true; + }); + scenario.scry(() -> { + scenario.assertSizes(0, 40); + return false; + }); + scenario.run(() -> { + scenario.assertSizes(0, 40); + }); + } + +} diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java index a5447b94b1..7bf3411dde 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/BlatantThieveryTest.java @@ -13,6 +13,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -24,7 +25,7 @@ public class BlatantThieveryTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 20); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); @@ -52,6 +53,7 @@ public class BlatantThieveryTest extends CardTestMultiPlayerBase { setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertGraveyardCount(playerA, "Blatant Thievery", 1); assertPermanentCount(playerA, "Silvercoat Lion", 1); assertPermanentCount(playerA, "Walking Corpse", 1); assertPermanentCount(playerA, "Pillarfield Ox", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/CreepingDreadTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/CreepingDreadTest.java index 6c508213d9..6be02becc8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/CreepingDreadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/CreepingDreadTest.java @@ -8,6 +8,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -23,7 +24,7 @@ public class CreepingDreadTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 40); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 40); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MultiplayerTriggerTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MultiplayerTriggerTest.java index ed53f82394..fa693669c2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MultiplayerTriggerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MultiplayerTriggerTest.java @@ -8,6 +8,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -15,7 +16,7 @@ public class MultiplayerTriggerTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 40); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 40); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java index 8f93c6ebee..e4e420112a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/MyriadTest.java @@ -1,7 +1,5 @@ - package org.mage.test.multiplayer; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; @@ -9,18 +7,20 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; +import java.io.FileNotFoundException; + /** - * * @author LevelX2 */ public class MyriadTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 40); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 40); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); @@ -72,27 +72,32 @@ public class MyriadTest extends CardTestMultiPlayerBase { // Myriad (Whenever this creature attacks, for each opponent other than the defending player, put a token that's a copy of this creature onto the battlefield tapped and attacking that player or a planeswalker he or she controls. Exile those tokens at the end of combat.) addCard(Zone.BATTLEFIELD, playerD, "Caller of the Pack"); // 8/6 + // turns: A, D, C, B + // +1: You gain 2 life. // -1: Put a +1/+1 counter on each creature you control. Those creatures gain vigilance until end of turn. // -6: Create a white Avatar creature token. It has "This creature's power and toughness are each equal to your life total." addCard(Zone.BATTLEFIELD, playerA, "Ajani Goldmane"); + // +2 life activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1:"); + checkLife("must have +2 life", 2, PhaseStep.PRECOMBAT_MAIN, playerA, 40 + 2); + // D attack C, create 2 copy of caller (for each opponent exclude defender = 2) and attack to ajani attack(2, playerD, "Caller of the Pack", playerC); - addTarget(playerD, "Ajani Goldmane"); + addTarget(playerD, "Ajani Goldmane"); // select ajani instead playerA for pack attack + checkPermanentCount("must have 3 packs", 2, PhaseStep.END_COMBAT, playerD, "Caller of the Pack", 3); + checkPermanentCount("ajani must die", 2, PhaseStep.END_COMBAT, playerA, "Ajani Goldmane", 0); + checkLife("pack must not damage playerA", 2, PhaseStep.END_COMBAT, playerA, 40 + 2); + checkLife("pack must damage playerB by 8", 2, PhaseStep.END_COMBAT, playerB, 40 - 8); + checkLife("pack must damage playerC", 2, PhaseStep.END_COMBAT, playerC, 40 - 8); + checkLife("pack must not damage playerD", 2, PhaseStep.END_COMBAT, playerD, 40); setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); execute(); assertPermanentCount(playerD, "Caller of the Pack", 1); assertGraveyardCount(playerA, "Ajani Goldmane", 1); - - assertLife(playerA, 42); - assertLife(playerB, 32); - assertLife(playerC, 32); - assertLife(playerD, 40); - } /** diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerDiedStackTargetHandlingTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerDiedStackTargetHandlingTest.java index 808ce5c696..505351f83b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerDiedStackTargetHandlingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerDiedStackTargetHandlingTest.java @@ -13,6 +13,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -26,7 +27,7 @@ public class PlayerDiedStackTargetHandlingTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { // Start Life = 2 - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 3); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, new VancouverMulligan(0), 3); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java index 4c37d738d9..df74f38875 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRange1Test.java @@ -10,6 +10,7 @@ import mage.counters.CounterType; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import mage.game.permanent.Permanent; import org.junit.Assert; import org.junit.Test; @@ -24,7 +25,7 @@ public class PlayerLeftGameRange1Test extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { // Start Life = 2 - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 2); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, new VancouverMulligan(0), 2); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRangeAllTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRangeAllTest.java index f2fbfe06a7..c1c1e1d11f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRangeAllTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PlayerLeftGameRangeAllTest.java @@ -9,6 +9,7 @@ import mage.counters.CounterType; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Assert; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -22,7 +23,7 @@ public class PlayerLeftGameRangeAllTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { // Start Life = 2 - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 2); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 2); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PrivilegedPositionTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PrivilegedPositionTest.java index b935b12442..c404a37a38 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/PrivilegedPositionTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/PrivilegedPositionTest.java @@ -9,6 +9,7 @@ import mage.counters.CounterType; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -21,7 +22,7 @@ public class PrivilegedPositionTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 40); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 40); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/multiplayer/VindictiveLichTest.java b/Mage.Tests/src/test/java/org/mage/test/multiplayer/VindictiveLichTest.java index fc58244a4b..ae115daaa2 100644 --- a/Mage.Tests/src/test/java/org/mage/test/multiplayer/VindictiveLichTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/multiplayer/VindictiveLichTest.java @@ -9,6 +9,7 @@ import mage.constants.Zone; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.junit.Test; import org.mage.test.serverside.base.CardTestMultiPlayerBase; @@ -20,7 +21,7 @@ public class VindictiveLichTest extends CardTestMultiPlayerBase { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, 0, 40); + Game game = new FreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 40); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java index bfc977bc4e..2e59c4e012 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/RandomPlayer.java @@ -1,18 +1,6 @@ - package org.mage.test.player; -import java.io.Serializable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.UUID; -import mage.abilities.Ability; -import mage.abilities.ActivatedAbility; -import mage.abilities.Mode; -import mage.abilities.Modes; -import mage.abilities.TriggeredAbility; +import mage.abilities.*; import mage.abilities.common.PassAbility; import mage.abilities.costs.mana.GenericManaCost; import mage.cards.Card; @@ -30,9 +18,12 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetAmount; import mage.target.TargetCard; +import mage.util.RandomUtil; + +import java.io.Serializable; +import java.util.*; /** - * * plays randomly * * @author BetaSteward_at_googlemail.com @@ -40,7 +31,6 @@ import mage.target.TargetCard; public class RandomPlayer extends ComputerPlayer { private boolean isSimulatedPlayer; - private static Random rnd = new Random(); private int actionCount = 0; protected PassAbility pass = new PassAbility(); @@ -89,21 +79,21 @@ public class RandomPlayer extends ComputerPlayer { if (playables.size() == 1) { ability = playables.get(0); } else { - ability = playables.get(rnd.nextInt(playables.size())); + ability = playables.get(RandomUtil.nextInt(playables.size())); } List options = getPlayableOptions(ability, game); if (!options.isEmpty()) { if (options.size() == 1) { ability = options.get(0); } else { - ability = options.get(rnd.nextInt(options.size())); + ability = options.get(RandomUtil.nextInt(options.size())); } } if (!ability.getManaCosts().getVariableCosts().isEmpty()) { int amount = getAvailableManaProducers(game).size() - ability.getManaCosts().convertedManaCost(); if (amount > 0) { ability = ability.copy(); - ability.getManaCostsToPay().add(new GenericManaCost(rnd.nextInt(amount))); + ability.getManaCostsToPay().add(new GenericManaCost(RandomUtil.nextInt(amount))); } } // check if ability kills player, if not then it's ok to play @@ -142,7 +132,7 @@ public class RandomPlayer extends ComputerPlayer { if (options.size() == 1) { ability = options.get(0); } else { - ability = options.get(rnd.nextInt(options.size())); + ability = options.get(RandomUtil.nextInt(options.size())); } } if (ability.isUsesStack()) { @@ -170,7 +160,7 @@ public class RandomPlayer extends ComputerPlayer { List attackersList = super.getAvailableAttackers(defenderId, game); //use binary digits to calculate powerset of attackers int powerElements = (int) Math.pow(2, attackersList.size()); - int value = rnd.nextInt(powerElements); + int value = RandomUtil.nextInt(powerElements); StringBuilder binary = new StringBuilder(); binary.append(Integer.toBinaryString(value)); while (binary.length() < attackersList.size()) { @@ -196,7 +186,7 @@ public class RandomPlayer extends ComputerPlayer { List blockers = getAvailableBlockers(game); for (Permanent blocker : blockers) { - int check = rnd.nextInt(numGroups + 1); + int check = RandomUtil.nextInt(numGroups + 1); if (check < numGroups) { CombatGroup group = game.getCombat().getGroups().get(check); if (!group.getAttackers().isEmpty()) { @@ -222,7 +212,7 @@ public class RandomPlayer extends ComputerPlayer { return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); @@ -237,21 +227,21 @@ public class RandomPlayer extends ComputerPlayer { return false; } if (!target.isRequired(source)) { - if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + if (RandomUtil.nextInt(possibleTargets.size() + 1) == 0) { return false; } } if (possibleTargets.size() == 1) { - target.addTarget(possibleTargets.iterator().next(), source, game); + target.addTarget(possibleTargets.iterator().next(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); } - target.addTarget(targetId, source, game); + target.addTarget(targetId, source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } @@ -275,7 +265,7 @@ public class RandomPlayer extends ComputerPlayer { return !false; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); @@ -296,7 +286,7 @@ public class RandomPlayer extends ComputerPlayer { } Card card = cards.getRandom(game); if (card != null) { - target.addTarget(card.getId(), source, game); + target.addTarget(card.getId(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } return false; @@ -309,37 +299,37 @@ public class RandomPlayer extends ComputerPlayer { return !target.isRequired(source); } if (!target.isRequired(source)) { - if (rnd.nextInt(possibleTargets.size() + 1) == 0) { + if (RandomUtil.nextInt(possibleTargets.size() + 1) == 0) { return false; } } if (possibleTargets.size() == 1) { - target.addTarget(possibleTargets.iterator().next(), target.getAmountRemaining(), source, game); + target.addTarget(possibleTargets.iterator().next(), target.getAmountRemaining(), source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } Iterator it = possibleTargets.iterator(); - int targetNum = rnd.nextInt(possibleTargets.size()); + int targetNum = RandomUtil.nextInt(possibleTargets.size()); UUID targetId = it.next(); for (int i = 0; i < targetNum; i++) { targetId = it.next(); } - target.addTarget(targetId, rnd.nextInt(target.getAmountRemaining()) + 1, source, game); + target.addTarget(targetId, RandomUtil.nextInt(target.getAmountRemaining()) + 1, source, game); // todo: addtryaddtarget or return type (see computerPlayer) return true; } @Override public boolean chooseMulligan(Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override public boolean chooseUse(Outcome outcome, String message, Ability source, Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override public boolean choosePile(Outcome outcome, String message, List pile1, List pile2, Game game) { - return rnd.nextBoolean(); + return RandomUtil.nextBoolean(); } @Override @@ -350,12 +340,12 @@ public class RandomPlayer extends ComputerPlayer { @Override public int chooseReplacementEffect(Map rEffects, Game game) { - return rnd.nextInt(rEffects.size()); + return RandomUtil.nextInt(rEffects.size()); } @Override public TriggeredAbility chooseTriggeredAbility(List abilities, Game game) { - return abilities.get(rnd.nextInt(abilities.size())); + return abilities.get(RandomUtil.nextInt(abilities.size())); } @Override @@ -365,7 +355,7 @@ public class RandomPlayer extends ComputerPlayer { if (modes.size() == 1) { return mode; } - int modeNum = rnd.nextInt(modes.getAvailableModes(source, game).size()); + int modeNum = RandomUtil.nextInt(modes.getAvailableModes(source, game).size()); for (int i = 0; i < modeNum; i++) { mode = it.next(); } @@ -374,12 +364,12 @@ public class RandomPlayer extends ComputerPlayer { @Override public UUID chooseAttackerOrder(List attackers, Game game) { - return attackers.get(rnd.nextInt(attackers.size())).getId(); + return attackers.get(RandomUtil.nextInt(attackers.size())).getId(); } @Override public UUID chooseBlockerOrder(List blockers, CombatGroup combatGroup, List blockerOrder, Game game) { - return blockers.get(rnd.nextInt(blockers.size())).getId(); + return blockers.get(RandomUtil.nextInt(blockers.size())).getId(); } @Override @@ -392,8 +382,8 @@ public class RandomPlayer extends ComputerPlayer { targetId = targets.get(0); amount = remainingDamage; } else { - targetId = targets.get(rnd.nextInt(targets.size())); - amount = rnd.nextInt(damage + 1); + targetId = targets.get(RandomUtil.nextInt(targets.size())); + amount = RandomUtil.nextInt(damage + 1); } Permanent permanent = game.getPermanent(targetId); if (permanent != null) { @@ -412,7 +402,7 @@ public class RandomPlayer extends ComputerPlayer { @Override public int getAmount(int min, int max, String message, Game game) { - return rnd.nextInt(max - min) + min; + return RandomUtil.nextInt(max - min) + min; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java new file mode 100644 index 0000000000..7e9d8b2cf1 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer.java @@ -0,0 +1,73 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer; +import mage.target.Target; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override to override AI logic for test +public class TestComputerPlayer extends ComputerPlayer { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer(String name, RangeOfInfluence range) { + super(name, range); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + // copy-paste for TestComputerXXX + + // workaround for discard spells + // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose + return testPlayerLink.choose(outcome, target, sourceId, game); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java new file mode 100644 index 0000000000..e647128bb6 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestComputerPlayer7.java @@ -0,0 +1,73 @@ +package org.mage.test.player; + +import mage.MageObject; +import mage.abilities.ActivatedAbility; +import mage.abilities.SpellAbility; +import mage.constants.Outcome; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.player.ai.ComputerPlayer7; +import mage.target.Target; + +import java.util.LinkedHashMap; +import java.util.UUID; + +/** + * @author JayDi85 + */ + +// mock class to override AI logic in tests +public class TestComputerPlayer7 extends ComputerPlayer7 { + + private TestPlayer testPlayerLink; + + public TestComputerPlayer7(String name, RangeOfInfluence range, int skill) { + super(name, range, skill); + } + + public void setTestPlayerLink(TestPlayer testPlayerLink) { + this.testPlayerLink = testPlayerLink; + } + + @Override + public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { + // copy-paste for TestComputerXXX + + // workaround to cast fused cards in tests by it's NAMES (Wear, Tear, Wear // Tear) + // reason: TestPlayer uses outer computerPlayer to cast, not TestPlayer + switch (ability.getSpellAbilityType()) { + case SPLIT: + case SPLIT_FUSED: + case SPLIT_AFTERMATH: + if (!this.testPlayerLink.getChoices().isEmpty()) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + LinkedHashMap useableAbilities = this.getSpellAbilities(object, game.getState().getZone(object.getId()), game); + + // left, right or fused cast + for (String choose : this.testPlayerLink.getChoices()) { + for (ActivatedAbility activatedAbility : useableAbilities.values()) { + if (activatedAbility instanceof SpellAbility) { + if (((SpellAbility) activatedAbility).getCardName().equals(choose)) { + return (SpellAbility) activatedAbility; + } + } + } + } + } + } + } + + // default implementation by AI + return super.chooseSpellAbilityForCast(ability, game, noMana); + } + + @Override + public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game) { + // copy-paste for TestComputerXXX + + // workaround for discard spells + // reason: TestPlayer uses outer computerPlayer to discard but inner code uses choose + return testPlayerLink.choose(outcome, target, sourceId, game); + } +} 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 0fa4a84a09..18c40b0c9b 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 @@ -1,5 +1,6 @@ package org.mage.test.player; +import mage.MageItem; import mage.MageObject; import mage.MageObjectReference; import mage.ObjectColor; @@ -46,6 +47,8 @@ import mage.players.Player; import mage.players.net.UserData; import mage.target.*; import mage.target.common.*; +import mage.util.CardUtil; +import org.apache.log4j.Logger; import org.junit.Assert; import org.junit.Ignore; @@ -53,6 +56,7 @@ import java.io.Serializable; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; @@ -64,15 +68,21 @@ import static org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl.*; @Ignore public class TestPlayer implements Player { + private static final Logger logger = Logger.getLogger(TestPlayer.class); + + public static final String TARGET_SKIP = "[skip]"; + private int maxCallsWithoutAction = 100; private int foundNoAction = 0; private boolean AIPlayer; private final List actions = new ArrayList<>(); - private final List choices = new ArrayList<>(); - private final List targets = new ArrayList<>(); + private final List choices = new ArrayList<>(); // choices stack for choice + private final List targets = new ArrayList<>(); // targets stack for choose (it's uses on empty direct target by cast command) + private final Map aliases = new HashMap<>(); // aliases for game objects/players (use it for cards with same name to save and use) private final List modesSet = new ArrayList<>(); private final ComputerPlayer computerPlayer; + private boolean strictChooseMode = false; // test will raise error on empty choice/target (e.g. devs must setup all choices/targets for all spells) private String[] groupsForTargetHandling = null; @@ -80,9 +90,16 @@ public class TestPlayer implements Player { // Before actual turns start. Needed for checking attacker/blocker legality in the tests private static int initialTurns = 0; - public TestPlayer(ComputerPlayer computerPlayer) { + public TestPlayer(TestComputerPlayer computerPlayer) { this.computerPlayer = computerPlayer; AIPlayer = false; + computerPlayer.setTestPlayerLink(this); + } + + public TestPlayer(TestComputerPlayer7 computerPlayer) { + this.computerPlayer = computerPlayer; + AIPlayer = false; + computerPlayer.setTestPlayerLink(this); } public TestPlayer(final TestPlayer testPlayer) { @@ -91,17 +108,39 @@ public class TestPlayer implements Player { this.actions.addAll(testPlayer.actions); this.choices.addAll(testPlayer.choices); this.targets.addAll(testPlayer.targets); + this.aliases.putAll(testPlayer.aliases); this.modesSet.addAll(testPlayer.modesSet); this.computerPlayer = testPlayer.computerPlayer.copy(); if (testPlayer.groupsForTargetHandling != null) { this.groupsForTargetHandling = testPlayer.groupsForTargetHandling.clone(); } + this.strictChooseMode = testPlayer.strictChooseMode; } public void addChoice(String choice) { choices.add(choice); } + public List getChoices() { + return this.choices; + } + + public List getTargets() { + return this.targets; + } + + public Map getAliases() { + return this.aliases; + } + + public UUID getAliasByName(String searchName) { + if (searchName.startsWith("@")) { + return this.aliases.getOrDefault(searchName.substring(1), null); + } else { + return this.aliases.getOrDefault(searchName, null); + } + } + public void addModeChoice(String mode) { modesSet.add(mode); } @@ -110,6 +149,10 @@ public class TestPlayer implements Player { targets.add(target); } + public void addAlias(String name, UUID Id) { + aliases.put(name, Id); + } + public ManaOptions getAvailableManaTest(Game game) { return computerPlayer.getManaAvailable(game); } @@ -180,7 +223,7 @@ public class TestPlayer implements Player { filteredName = indexedMatcher.group(1); index = Integer.valueOf(indexedMatcher.group(2)); } - filter.add(new NamePredicate(filteredName)); + filter.add(new NamePredicate(filteredName, true)); // must find any cards even without names List allPermanents = game.getBattlefield().getAllActivePermanents(filter, controllerID, game); if (allPermanents.isEmpty()) { if (failOnNotFound) { @@ -227,9 +270,7 @@ public class TestPlayer implements Player { String spellOnTopOFStack = groups[2].substring(18); if (!game.getStack().isEmpty()) { StackObject stackObject = game.getStack().getFirst(); - if (stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack)) { - return true; - } + return stackObject != null && stackObject.getStackAbility().toString().contains(spellOnTopOFStack); } return false; } else if (groups[2].startsWith("manaInPool=")) { @@ -295,6 +336,31 @@ public class TestPlayer implements Player { return result; } + public String generateAliasName(String baseAlias, boolean useMiltiNames, int iteration) { + if (useMiltiNames) { + return baseAlias + "." + iteration; + } else { + return baseAlias; + } + } + + private boolean isObjectHaveTargetNameOrAliase(MageObject object, String nameOrAliase) { + if (object == null || nameOrAliase == null) { + return false; + } + + if (nameOrAliase.startsWith("@") && object.getId().equals(getAliasByName(nameOrAliase))) { + return true; + } + + // must search any names, even empty + if (CardUtil.haveSameNames(nameOrAliase, object.getName(), true)) { + return true; + } + + return object.getName().startsWith(nameOrAliase); + } + private boolean handleNonPlayerTargetTarget(String target, Ability ability, Game game) { boolean result = true; if (target == null) { @@ -356,28 +422,46 @@ public class TestPlayer implements Player { for (UUID id : currentTarget.possibleTargets(ability.getSourceId(), ability.getControllerId(), game)) { if (!currentTarget.getTargets().contains(id)) { MageObject object = game.getObject(id); - if (object != null - && ((object.isCopy() && !originOnly) || (!object.isCopy() && !copyOnly)) - && ((!targetName.isEmpty() && object.getName().startsWith(targetName)) || (targetName.isEmpty() && object.getName().isEmpty()))) { - if (currentTarget.getNumberOfTargets() == 1) { - currentTarget.clearChosen(); - } - if (currentTarget instanceof TargetCreaturePermanentAmount) { - // supports only to set the complete amount to one target - TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; - targetAmount.setAmount(ability, game); - int amount = targetAmount.getAmountRemaining(); - targetAmount.addTarget(id, amount, ability, game); - targetsSet++; - } else { - currentTarget.addTarget(id, ability, game); - targetsSet++; - } - if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { - index++; - } - break; + + if (object == null) { + continue; } + + // only origin + if (originOnly && object.isCopy()) { + continue; + } + + // only copy + if (copyOnly && !object.isCopy()) { + continue; + } + + // need by alias or by name + if (!isObjectHaveTargetNameOrAliase(object, targetName)) { + continue; + } + + // found, can use as target + + if (currentTarget.getNumberOfTargets() == 1) { + currentTarget.clearChosen(); + } + if (currentTarget instanceof TargetCreaturePermanentAmount) { + // supports only to set the complete amount to one target + TargetCreaturePermanentAmount targetAmount = (TargetCreaturePermanentAmount) currentTarget; + targetAmount.setAmount(ability, game); + int amount = targetAmount.getAmountRemaining(); + targetAmount.addTarget(id, amount, ability, game); + targetsSet++; + } else { + currentTarget.addTarget(id, ability, game); + targetsSet++; + } + if (currentTarget.getTargets().size() == currentTarget.getMaxNumberOfTargets()) { + index++; + } + break; } } } @@ -431,6 +515,8 @@ public class TestPlayer implements Player { groupsForTargetHandling = null; } } + // TODO: fix wrong commands (on non existing card), it's HUGE (350+ failed tests with wrong commands) + //Assert.fail("Can't find ability to activate command: " + command); } else if (action.getAction().startsWith("manaActivate:")) { String command = action.getAction(); command = command.substring(command.indexOf("manaActivate:") + 13); @@ -489,6 +575,14 @@ public class TestPlayer implements Player { break; } } + } else if (action.getAction().startsWith("waitStackResolved")) { + if (game.getStack().isEmpty()) { + // can use next command + actions.remove(action); + } else { + // need pass to empty stack + break; + } } else if (action.getAction().startsWith("playerAction:")) { String command = action.getAction(); command = command.substring(command.indexOf("playerAction:") + 13); @@ -511,64 +605,175 @@ public class TestPlayer implements Player { } } else if (action.getAction().startsWith("check:")) { String command = action.getAction(); - command = command.substring(command.indexOf("check:") + 6); + command = command.substring(command.indexOf("check:") + "check:".length()); String[] params = command.split("@"); - boolean checkProccessed = false; + boolean wasProccessed = false; if (params.length > 0) { // check PT: card name, P, T if (params[0].equals(CHECK_COMMAND_PT) && params.length == 4) { assertPT(action, game, computerPlayer, params[1], Integer.parseInt(params[2]), Integer.parseInt(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check life: life + if (params[0].equals(CHECK_COMMAND_LIFE) && params.length == 2) { + assertLife(action, game, computerPlayer, Integer.parseInt(params[1])); + actions.remove(action); + wasProccessed = true; } // check ability: card name, ability class, must have if (params[0].equals(CHECK_COMMAND_ABILITY) && params.length == 4) { assertAbility(action, game, computerPlayer, params[1], params[2], Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check battlefield count: card name, count if (params[0].equals(CHECK_COMMAND_PERMANENT_COUNT) && params.length == 3) { assertPermanentCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check exile count: card name, count + if (params[0].equals(CHECK_COMMAND_EXILE_COUNT) && params.length == 3) { + assertExileCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); + actions.remove(action); + wasProccessed = true; } // check hand count: count if (params[0].equals(CHECK_COMMAND_HAND_COUNT) && params.length == 2) { assertHandCount(action, game, computerPlayer, Integer.parseInt(params[1])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check hand card count: card name, count + if (params[0].equals(CHECK_COMMAND_HAND_CARD_COUNT) && params.length == 3) { + assertHandCardCount(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); + actions.remove(action); + wasProccessed = true; } // check color: card name, colors, must have if (params[0].equals(CHECK_COMMAND_COLOR) && params.length == 4) { assertColor(action, game, computerPlayer, params[1], params[2], Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check type: card name, type, must have + if (params[0].equals(CHECK_COMMAND_TYPE) && params.length == 4) { + assertType(action, game, computerPlayer, params[1], CardType.fromString(params[2]), Boolean.parseBoolean(params[3])); + actions.remove(action); + wasProccessed = true; } // check subtype: card name, subtype, must have if (params[0].equals(CHECK_COMMAND_SUBTYPE) && params.length == 4) { assertSubType(action, game, computerPlayer, params[1], SubType.fromString(params[2]), Boolean.parseBoolean(params[3])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; } // check mana pool: colors, amount if (params[0].equals(CHECK_COMMAND_MANA_POOL) && params.length == 3) { assertManaPool(action, game, computerPlayer, params[1], Integer.parseInt(params[2])); actions.remove(action); - checkProccessed = true; + wasProccessed = true; + } + + // check aliase at zone: alias name, zone, must have (only for TestPlayer) + if (params[0].equals(CHECK_COMMAND_ALIAS_ZONE) && params.length == 4) { + assertAliasZone(action, game, this, params[1], Zone.valueOf(params[2]), Boolean.parseBoolean(params[3])); + actions.remove(action); + wasProccessed = true; + } + } + if (!wasProccessed) { + Assert.fail("Unknow check command or params: " + command); + } + } else if (action.getAction().startsWith("show:")) { + String command = action.getAction(); + command = command.substring(command.indexOf("show:") + "show:".length()); + + String[] params = command.split("@"); + boolean wasProccessed = false; + if (params.length > 0) { + + // show library + if (params[0].equals(SHOW_COMMAND_LIBRARY) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getLibrary().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show hand + if (params[0].equals(SHOW_COMMAND_HAND) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getHand().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show battlefield + if (params[0].equals(SHOW_COMMAND_BATTLEFIELD) && params.length == 1) { + printStart(action.getActionName()); + printPermanents(game, game.getBattlefield().getAllActivePermanents(computerPlayer.getId())); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show graveyard + if (params[0].equals(SHOW_COMMAND_GRAVEYEARD) && params.length == 1) { + printStart(action.getActionName()); + printCards(computerPlayer.getGraveyard().getCards(game)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show exile + if (params[0].equals(SHOW_COMMAND_EXILE) && params.length == 1) { + printStart(action.getActionName()); + printCards(game.getExile().getAllCards(game).stream() + .filter(card -> card.isOwnedBy(computerPlayer.getId())) + .collect(Collectors.toList())); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show available abilities + if (params[0].equals(SHOW_COMMAND_AVAILABLE_ABILITIES) && params.length == 1) { + printStart(action.getActionName()); + printAbilities(game, computerPlayer.getPlayable(game, true)); + printEnd(); + actions.remove(action); + wasProccessed = true; + } + + // show aliases + if (params[0].equals(SHOW_COMMAND_ALIASES) && params.length == 1) { + printStart(action.getActionName()); + printAliases(game, this); + printEnd(); + actions.remove(action); + wasProccessed = true; } } - if (!checkProccessed) { - Assert.fail("Unknow check command or params: " + command); + if (!wasProccessed) { + Assert.fail("Unknow show command or params: " + command); } } } @@ -601,6 +806,106 @@ public class TestPlayer implements Player { return null; } + private void printStart(String name) { + System.out.println("\n" + name + ":"); + } + + private void printEnd() { + System.out.println(); + } + + private void printCards(Set cards) { + printCards(new ArrayList<>(cards)); + } + + private void printCards(List cards) { + System.out.println("Total cards: " + cards.size()); + + List data = cards.stream() + .map(Card::getIdName) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + private void printPermanents(Game game, List cards) { + System.out.println("Total permanents: " + cards.size()); + + List data = cards.stream() + .map(c -> (c.getIdName() + + " - " + c.getPower().getValue() + + "/" + c.getToughness().getValue() + + ", " + (c.isTapped() ? "Tapped" : "Untapped") + + (c.getAttachedTo() == null ? "" : ", attached to " + game.getPermanent(c.getAttachedTo()).getIdName()) + )) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + private void printAbilities(Game game, List abilities) { + + + System.out.println("Total abilities: " + (abilities != null ? abilities.size() : 0)); + if (abilities == null) { + return; + } + + List data = abilities.stream() + .map(a -> ( + a.getZone() + " -> " + + a.getSourceObject(game).getIdName() + " -> " + + (a.getRule().length() > 0 + ? a.getRule().substring(0, Math.min(20, a.getRule().length()) - 1) + : a.getClass().getSimpleName()) + + "..." + )) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + + + private String getAliasInfo(Game game, TestPlayer player, String aliasName) { + MageItem item = findAliasObject(game, player, aliasName); + if (item == null) { + return aliasName + " [not exists]"; + } + + if (item instanceof MageObject) { + Zone zone = game.getState().getZone(item.getId()); + return aliasName + " - " + ((MageObject) item).getIdName() + " - " + (zone != null ? zone.toString() : "null"); + } + + if (item instanceof Player) { + return aliasName + " - " + ((Player) item).getName(); + } + + return aliasName + " [unknown object " + item.getId() + "]"; + } + + private void printAliases(Game game, TestPlayer player) { + System.out.println("Total aliases: " + player.getAliases().size()); + + List data = player.getAliases().entrySet().stream() + .map(entry -> (getAliasInfo(game, player, entry.getKey()))) + .sorted() + .collect(Collectors.toList()); + + for (String s : data) { + System.out.println(s); + } + } + private void assertPT(PlayerAction action, Game game, Player player, String permanentName, int Power, int Toughness) { Permanent perm = findPermanentWithAssert(action, game, player, permanentName); @@ -610,6 +915,11 @@ public class TestPlayer implements Player { Toughness, perm.getToughness().getValue()); } + private void assertLife(PlayerAction action, Game game, Player player, int Life) { + Assert.assertEquals(action.getActionName() + " - " + player.getName() + " have wrong life: " + player.getLife() + " <> " + Life, + Life, player.getLife()); + } + private void assertAbility(PlayerAction action, Game game, Player player, String permanentName, String abilityClass, boolean mustHave) { Permanent perm = findPermanentWithAssert(action, game, player, permanentName); @@ -639,10 +949,33 @@ public class TestPlayer implements Player { Assert.assertEquals(action.getActionName() + " - permanent " + permanentName + " must exists in " + count + " instances", count, foundedCount); } + private void assertExileCount(PlayerAction action, Game game, Player player, String permanentName, int count) { + int foundedCount = 0; + for (Card card : game.getExile().getAllCards(game)) { + if (card.getName().equals(permanentName) && card.isOwnedBy(player.getId())) { + foundedCount++; + } + } + + Assert.assertEquals(action.getActionName() + " - card " + permanentName + " must exists in exile zone with " + count + " instances", count, foundedCount); + } + private void assertHandCount(PlayerAction action, Game game, Player player, int count) { Assert.assertEquals(action.getActionName() + " - hand must contain " + count, count, player.getHand().size()); } + private void assertHandCardCount(PlayerAction action, Game game, Player player, String cardName, int count) { + int realCount = 0; + for (UUID cardId : player.getHand()) { + Card card = game.getCard(cardId); + if (card != null && card.getName().equals(cardName)) { + realCount++; + } + } + + Assert.assertEquals(action.getActionName() + " - hand must contain " + count + " cards of " + cardName, count, realCount); + } + private void assertColor(PlayerAction action, Game game, Player player, String permanentName, String colors, boolean mustHave) { Assert.assertNotEquals(action.getActionName() + " - must setup colors", "", colors); @@ -668,6 +1001,25 @@ public class TestPlayer implements Player { } } + private void assertType(PlayerAction action, Game game, Player player, String permanentName, CardType type, boolean mustHave) { + + Permanent perm = findPermanentWithAssert(action, game, player, permanentName); + + boolean founded = false; + for (CardType ct : perm.getCardType()) { + if (ct.equals(type)) { + founded = true; + break; + } + } + + if (mustHave) { + Assert.assertEquals(action.getActionName() + " - permanent " + permanentName + " must have type " + type, true, founded); + } else { + Assert.assertEquals(action.getActionName() + " - permanent " + permanentName + " must have not type " + type, false, founded); + } + } + private void assertSubType(PlayerAction action, Game game, Player player, String permanentName, SubType subType, boolean mustHave) { Permanent perm = findPermanentWithAssert(action, game, player, permanentName); @@ -687,6 +1039,33 @@ public class TestPlayer implements Player { } } + private MageItem findAliasObject(Game game, TestPlayer player, String aliasName) { + UUID objectId = player.getAliasByName(aliasName); + if (objectId == null) { + return null; + } + + MageObject itemObject = game.getObject(objectId); + if (itemObject != null) { + return itemObject; + } + + Player itemPlayer = game.getPlayer(objectId); + return itemPlayer; + + } + + private void assertAliasZone(PlayerAction action, Game game, TestPlayer player, String aliasName, Zone needZone, boolean mustHave) { + MageItem item = findAliasObject(game, player, aliasName); + Zone currentZone = (item == null ? null : game.getState().getZone(item.getId())); + + if (mustHave) { + Assert.assertEquals(action.getActionName() + " - alias " + aliasName + " must have zone " + needZone.toString(), needZone, currentZone); + } else { + Assert.assertNotEquals(action.getActionName() + " - alias " + aliasName + " must have not zone " + needZone.toString(), needZone, currentZone); + } + } + private void assertManaPoolInner(PlayerAction action, Player player, ManaType manaType, Integer amount) { Integer current = player.getManaPool().get(manaType); Assert.assertEquals(action.getActionName() + " - mana pool must contain [" + amount.toString() + " " + manaType.toString() + "], but found [" + current.toString() + "]", amount, current); @@ -812,7 +1191,7 @@ public class TestPlayer implements Player { findPermanent(firstFilter, groups[0], computerPlayer.getId(), game); // Second check to filter creature for combat - less strict to workaround issue in #3038 FilterCreatureForCombat secondFilter = new FilterCreatureForCombat(); - // secondFilter.add(Predicates.not(new AttackingPredicate())); + // secondFilter.add(Predicates.not(AttackingPredicate.instance)); secondFilter.add(Predicates.not(new SummoningSicknessPredicate())); // TODO: Cannot enforce legal attackers multiple times per combat. See issue #3038 Permanent attacker = findPermanent(secondFilter, groups[0], computerPlayer.getId(), game, false); @@ -902,6 +1281,24 @@ public class TestPlayer implements Player { // No errors raised - all the blockers pass the test! } + private String getInfo(MageObject o) { + return o != null ? o.getClass().getSimpleName() + ": " + o.getName() : "null"; + } + + private String getInfo(Ability o) { + return o != null ? o.getClass().getSimpleName() + ": " + o.getRule() : "null"; + } + + private String getInfo(Target o) { + return o != null ? o.getClass().getSimpleName() + ": " + o.getMessage() : "null"; + } + + private void chooseStrictModeFailed(Game game, String reason) { + if (strictChooseMode) { + Assert.fail("Missing target/choice def for turn " + game.getTurnNum() + ", " + game.getStep().getType().name() + ": " + reason); + } + } + @Override public Mode chooseMode(Modes modes, Ability source, Game game) { if (!modesSet.isEmpty() && modes.getMaxModes() > modes.getSelectedModes().size()) { @@ -923,7 +1320,9 @@ public class TestPlayer implements Player { if (modes.getMinModes() <= modes.getSelectedModes().size()) { return null; } - return computerPlayer.chooseMode(modes, source, game); //To change body of generated methods, choose Tools | Templates. + + this.chooseStrictModeFailed(game, getInfo(source)); + return computerPlayer.chooseMode(modes, source, game); } @Override @@ -932,12 +1331,19 @@ public class TestPlayer implements Player { if (choice.setChoiceByAnswers(choices, true)) { return true; } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } + + this.chooseStrictModeFailed(game, choice.getMessage()); return computerPlayer.choose(outcome, choice, game); } @Override public int chooseReplacementEffect(Map rEffects, Game game) { + if (rEffects.size() <= 1) { + return 0; + } if (!choices.isEmpty()) { for (String choice : choices) { for (int index = 0; index < rEffects.size(); index++) { @@ -947,18 +1353,27 @@ public class TestPlayer implements Player { } } } + // TODO: enable fail checks and fix tests + //Assert.fail("wrong choice"); } + + this.chooseStrictModeFailed(game, String.join("; ", rEffects.values())); return computerPlayer.chooseReplacementEffect(rEffects, game); } @Override public boolean choose(Outcome outcome, Target target, UUID sourceId, Game game, Map options) { if (!choices.isEmpty()) { + + List usedChoices = new ArrayList<>(); + List usedTargets = new ArrayList<>(); + Ability source = null; StackObject stackObject = game.getStack().getStackObject(sourceId); if (stackObject != null) { source = stackObject.getStackAbility(); } + if ((target instanceof TargetPermanent) || (target instanceof TargetPermanentOrPlayer)) { // player target not implemted yet FilterPermanent filterPermanent; if (target instanceof TargetPermanentOrPlayer) { @@ -988,7 +1403,7 @@ public class TestPlayer implements Player { } if (permanent.getName().equals(targetName)) { - if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), source, game)) { + if (target.isNotTarget() || target.canTarget(computerPlayer.getId(), permanent.getId(), source, game)) { if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { target.add(permanent.getId(), game); targetFound = true; @@ -996,7 +1411,7 @@ public class TestPlayer implements Player { } } } else if ((permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { - if (target.isNotTarget() || ((TargetPermanent) target).canTarget(computerPlayer.getId(), permanent.getId(), source, game)) { + if (target.isNotTarget() || target.canTarget(computerPlayer.getId(), permanent.getId(), source, game)) { if ((permanent.isCopy() && !originOnly) || (!permanent.isCopy() && !copyOnly)) { target.add(permanent.getId(), game); targetFound = true; @@ -1012,11 +1427,12 @@ public class TestPlayer implements Player { } } } + if (target instanceof TargetPlayer) { for (Player player : game.getPlayers().values()) { for (String choose2 : choices) { if (player.getName().equals(choose2)) { - if (((TargetPlayer) target).canTarget(computerPlayer.getId(), player.getId(), null, game) && !target.getTargets().contains(player.getId())) { + if (target.canTarget(computerPlayer.getId(), player.getId(), null, game) && !target.getTargets().contains(player.getId())) { target.add(player.getId(), game); choices.remove(choose2); return true; @@ -1025,42 +1441,74 @@ public class TestPlayer implements Player { } } } + + // TODO: add same choices fixes for other target types (one choice must uses only one time for one target) if (target instanceof TargetCard) { - TargetCard targetCard = ((TargetCard) target); - Set possibleTargets = targetCard.possibleTargets(sourceId, target.getTargetController() == null ? getId() : target.getTargetController(), game); - for (String choose2 : choices) { - String[] targetList = choose2.split("\\^"); + // one choice per target + // only unique targets + //TargetCard targetFull = ((TargetCard) target); + + usedChoices.clear(); + usedTargets.clear(); + boolean targetCompleted = false; + + CheckAllChoices: + for (String choiceRecord : choices) { + if (targetCompleted) { + break CheckAllChoices; + } + boolean targetFound = false; - Choice: - for (String targetName : targetList) { - for (UUID targetId : possibleTargets) { + String[] possibleChoices = choiceRecord.split("\\^"); + + CheckOneChoice: + for (String possibleChoice : possibleChoices) { + Set possibleCards = target.possibleTargets(sourceId, target.getTargetController() == null ? getId() : target.getTargetController(), game); + CheckTargetsList: + for (UUID targetId : possibleCards) { MageObject targetObject = game.getObject(targetId); - if (targetObject != null) { - if (targetObject.getName().equals(targetName)) { - if (targetCard.canTarget(targetObject.getId(), game)) { - if (targetCard.getTargets() != null && !targetCard.getTargets().contains(targetObject.getId())) { - targetCard.add(targetObject.getId(), game); - targetFound = true; - if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { - break Choice; - } - } + if (targetObject != null && targetObject.getName().equals(possibleChoice)) { + if (target.canTarget(targetObject.getId(), game)) { + // only unique targets + if (usedTargets.contains(targetObject.getId())) { + continue; } + + // OK, can use it + target.add(targetObject.getId(), game); + targetFound = true; + usedTargets.add(targetObject.getId()); + + // break on full targets list + if (target.getTargets().size() >= target.getMaxNumberOfTargets()) { + targetCompleted = true; + break CheckOneChoice; + } + + // restart search + break CheckTargetsList; } } - } } + if (targetFound) { - if (targetCard.isChosen()) { - choices.remove(choose2); - return true; - } else { - target.clearChosen(); - } + usedChoices.add(choiceRecord); + } + } + + // apply only on ALL targets or revert + if (usedChoices.size() > 0) { + if (target.isChosen()) { + choices.removeAll(usedChoices); + return true; + } else { + Assert.fail("Not full targets list."); + target.clearChosen(); } } } + if (target instanceof TargetSource) { Set possibleTargets; TargetSource t = ((TargetSource) target); @@ -1091,10 +1539,44 @@ public class TestPlayer implements Player { } } } + + // TODO: enable fail checks and fix tests + /* + if (!target.getTargetName().equals("starting player")) { + Assert.fail("Wrong choice"); + } + */ + } + + // ignore player select + if (!target.getMessage().equals("Select a starting player")) { + this.chooseStrictModeFailed(game, getInfo(game.getObject(sourceId)) + "; " + getInfo(target)); } return computerPlayer.choose(outcome, target, sourceId, game, options); } + private void checkTargetDefinitionMarksSupport(Target needTarget, String targetDefinition, String canSupportChars) { + // fail on wrong chars in definition + // ^ - multiple targets + // [] - special option like [no copy] + // = - target type like targetPlayer=PlayerA + Boolean foundMulti = targetDefinition.contains("^"); + Boolean foundSpecialStart = targetDefinition.contains("["); + Boolean foundSpecialClose = targetDefinition.contains("]"); + Boolean foundEquals = targetDefinition.contains("="); + + Boolean canMulti = canSupportChars.contains("^"); + Boolean canSpecialStart = canSupportChars.contains("["); + Boolean canSpecialClose = canSupportChars.contains("]"); + Boolean canEquals = canSupportChars.contains("="); + + // how to fix: change target definition for addTarget in test's code or update choose from targets implementation in TestPlayer + if ((foundMulti && !canMulti) || (foundSpecialStart && !canSpecialStart) || (foundSpecialClose && !canSpecialClose) || (foundEquals && !canEquals)) { + Assert.fail("Targets list was setup by addTarget with " + targets + ", but target definition [" + targetDefinition + "]" + + " is not supported by [" + canSupportChars + "] for target class " + needTarget.getClass().getSimpleName()); + } + } + @Override public boolean chooseTarget(Outcome outcome, Target target, Ability source, Game game) { if (!targets.isEmpty()) { @@ -1102,11 +1584,22 @@ public class TestPlayer implements Player { if (target.getTargetController() != null && target.getAbilityController() != null) { abilityControllerId = target.getAbilityController(); } + + // do not select + if (targets.get(0).equals(TARGET_SKIP)) { + Assert.assertEquals("found empty choice, but target is not support 0 choice", 0, target.getMinNumberOfTargets()); + targets.remove(0); + return true; + } + + // player if (target instanceof TargetPlayer || target instanceof TargetAnyTarget || target instanceof TargetCreatureOrPlayer - || target instanceof TargetPermanentOrPlayer) { + || target instanceof TargetPermanentOrPlayer + || target instanceof TargetDefender) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "="); if (targetDefinition.startsWith("targetPlayer=")) { String playerName = targetDefinition.substring(targetDefinition.indexOf("targetPlayer=") + 13); for (Player player : game.getPlayers().values()) { @@ -1121,11 +1614,15 @@ public class TestPlayer implements Player { } } + + // permanent in battlefield if ((target instanceof TargetPermanent) || (target instanceof TargetPermanentOrPlayer) || (target instanceof TargetAnyTarget) - || (target instanceof TargetCreatureOrPlayer)) { + || (target instanceof TargetCreatureOrPlayer) + || (target instanceof TargetDefender)) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^[]"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -1148,8 +1645,11 @@ public class TestPlayer implements Player { if (filter instanceof FilterCreaturePlayerOrPlaneswalker) { filter = ((FilterCreaturePlayerOrPlaneswalker) filter).getCreatureFilter(); } - if (filter instanceof TargetPermanentOrPlayer) { - filter = ((TargetPermanentOrPlayer) filter).getFilterPermanent(); + if (filter instanceof FilterPermanentOrPlayer) { + filter = ((FilterPermanentOrPlayer) filter).getPermanentFilter(); + } + if (filter instanceof FilterPlaneswalkerOrPlayer) { + filter = ((FilterPlaneswalkerOrPlayer) filter).getFilterPermanent(); } for (Permanent permanent : game.getBattlefield().getAllActivePermanents((FilterPermanent) filter, game)) { if (permanent.getName().equals(targetName) || (permanent.getName() + '-' + permanent.getExpansionSetCode()).equals(targetName)) { @@ -1171,14 +1671,16 @@ public class TestPlayer implements Player { } } + // card in hand if (target instanceof TargetCardInHand) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { for (Card card : computerPlayer.getHand().getCards(((TargetCardInHand) target).getFilter(), game)) { if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInHand) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { + if (target.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { target.add(card.getId(), game); targetFound = true; break; @@ -1191,17 +1693,20 @@ public class TestPlayer implements Player { return true; } } - } - if (target instanceof TargetCardInYourGraveyard) { + + // card in exile + if (target instanceof TargetCardInExile) { + TargetCardInExile targetFull = (TargetCardInExile) target; for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { - for (Card card : computerPlayer.getGraveyard().getCards(((TargetCardInYourGraveyard) target).getFilter(), game)) { + for (Card card : game.getExile().getCards(targetFull.getFilter(), game)) { if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInYourGraveyard) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { - target.add(card.getId(), game); + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) { + targetFull.add(card.getId(), game); targetFound = true; break; } @@ -1213,30 +1718,80 @@ public class TestPlayer implements Player { return true; } } - } - if (target instanceof TargetCardInOpponentsGraveyard) { + + // card in battlefield + if (target instanceof TargetCardInGraveyardOrBattlefield) { + TargetCard targetFull = (TargetCard) target; for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; - for (String targetName : targetList) { - IterateOpponentsGraveyards: - for (UUID opponentId : game.getState().getPlayersInRange(getId(), game)) { - if (computerPlayer.hasOpponent(opponentId, game)) { - Player opponent = game.getPlayer(opponentId); - for (Card card : opponent.getGraveyard().getCards(((TargetCardInOpponentsGraveyard) target).getFilter(), game)) { - if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { - if (((TargetCardInOpponentsGraveyard) target).canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { - target.add(card.getId(), game); - targetFound = true; - break IterateOpponentsGraveyards; - } + for (Card card : game.getBattlefield().getAllActivePermanents()) { + if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !targetFull.getTargets().contains(card.getId())) { + targetFull.add(card.getId(), game); + targetFound = true; + break; + } + } + } + } + if (targetFound) { + targets.remove(targetDefinition); + return true; + } + } + } + + + // card in graveyard + if (target instanceof TargetCardInOpponentsGraveyard + || target instanceof TargetCardInYourGraveyard + || target instanceof TargetCardInGraveyard + || target instanceof TargetCardInGraveyardOrBattlefield) { + TargetCard targetFull = (TargetCard) target; + + List needPlayers = game.getState().getPlayersInRange(getId(), game).toList(); + // fix for opponent graveyard + if (target instanceof TargetCardInOpponentsGraveyard) { + // current player remove + Assert.assertTrue(needPlayers.contains(getId())); + needPlayers.remove(getId()); + Assert.assertFalse(needPlayers.contains(getId())); + } + // fix for your graveyard + if (target instanceof TargetCardInYourGraveyard) { + // only current player + Assert.assertTrue(needPlayers.contains(getId())); + needPlayers.clear(); + needPlayers.add(getId()); + Assert.assertEquals(1, needPlayers.size()); + } + + for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); + + String[] targetList = targetDefinition.split("\\^"); + boolean targetFound = false; + for (String targetName : targetList) { + IterateGraveyards: + for (UUID playerId : needPlayers) { + Player player = game.getPlayer(playerId); + for (Card card : player.getGraveyard().getCards(targetFull.getFilter(), game)) { + if (card.getName().equals(targetName) || (card.getName() + '-' + card.getExpansionSetCode()).equals(targetName)) { + if (targetFull.canTarget(abilityControllerId, card.getId(), source, game) && !target.getTargets().contains(card.getId())) { + target.add(card.getId(), game); + targetFound = true; + break IterateGraveyards; } } } + } } + if (targetFound) { targets.remove(targetDefinition); return true; @@ -1244,8 +1799,11 @@ public class TestPlayer implements Player { } } + + // stack if (target instanceof TargetSpell) { for (String targetDefinition : targets) { + checkTargetDefinitionMarksSupport(target, targetDefinition, "^"); String[] targetList = targetDefinition.split("\\^"); boolean targetFound = false; for (String targetName : targetList) { @@ -1263,8 +1821,29 @@ public class TestPlayer implements Player { } } } - } + + // wrong target settings by addTarget + // how to fix: implement target class processing above + if (!targets.isEmpty()) { + String message; + + if (source != null) { + message = "Targets list was setup by addTarget with " + targets + ", but not used in [" + + "card " + source.getSourceObject(game) + + " -> ability " + source.getClass().getSimpleName() + " (" + source.getRule().substring(0, Math.min(20, source.getRule().length()) - 1) + "..." + ")" + + " -> target " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "]"; + } else { + message = "Targets list was setup by addTarget with " + targets + ", but not used in [" + + "card XXX" + + " -> target " + target.getClass().getSimpleName() + " (" + target.getMessage() + ")" + + "]"; + } + Assert.fail(message); + } + + this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTarget(outcome, target, source, game); } @@ -1288,7 +1867,12 @@ public class TestPlayer implements Player { return true; } } + + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong target"); } + + this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTarget(outcome, cards, target, source, game); } @@ -1301,7 +1885,11 @@ public class TestPlayer implements Player { return ability; } } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } + + this.chooseStrictModeFailed(game, abilities.stream().map(this::getInfo).collect(Collectors.joining("; "))); return computerPlayer.chooseTriggeredAbility(abilities, game); } @@ -1324,7 +1912,11 @@ public class TestPlayer implements Player { choices.remove(0); return true; } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } + + this.chooseStrictModeFailed(game, getInfo(source) + "; " + message + ": " + trueText + " - " + falseText); return computerPlayer.chooseUse(outcome, message, secondMessage, trueText, falseText, source, game); } @@ -1339,6 +1931,8 @@ public class TestPlayer implements Player { } } } + + this.chooseStrictModeFailed(game, getInfo(ability) + "; " + message); return computerPlayer.announceXMana(min, max, message, game, ability); } @@ -1351,6 +1945,8 @@ public class TestPlayer implements Player { return xValue; } } + + this.chooseStrictModeFailed(game, getInfo(ability) + "; " + message); return computerPlayer.announceXCost(min, max, message, game, ability, null); } @@ -1363,6 +1959,8 @@ public class TestPlayer implements Player { return xValue; } } + + this.chooseStrictModeFailed(game, message); return computerPlayer.getAmount(min, max, message, game); } @@ -1406,6 +2004,8 @@ public class TestPlayer implements Player { this.choices.addAll(((TestPlayer) player).choices); this.targets.clear(); this.targets.addAll(((TestPlayer) player).targets); + this.aliases.clear(); + this.aliases.putAll(((TestPlayer) player).aliases); computerPlayer.restore(player); } @@ -1639,6 +2239,8 @@ public class TestPlayer implements Player { @Override public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference reference) { + // TestPlayer, ComputerPlayer always call inherited cast() from PlayerImpl + // that's why chooseSpellAbilityForCast will be ignored in TestPlayer, see workaround with TestComputerPlayerXXX return computerPlayer.cast(ability, game, noMana, reference); } @@ -1842,6 +2444,11 @@ public class TestPlayer implements Player { return computerPlayer.gainLife(amount, game, sourceId); } + @Override + public int damage(int damage, UUID sourceId, Game game) { + return computerPlayer.damage(damage, sourceId, game); + } + @Override public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) { return computerPlayer.damage(damage, sourceId, game, combatDamage, preventable); @@ -2053,33 +2660,38 @@ public class TestPlayer implements Player { } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game) { - return computerPlayer.searchLibrary(target, game); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game) { + return computerPlayer.searchLibrary(target, source, game); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, boolean triggerEvents) { - return computerPlayer.searchLibrary(target, game, triggerEvents); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, boolean triggerEvents) { + return computerPlayer.searchLibrary(target, source, game, triggerEvents); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId) { - return computerPlayer.searchLibrary(target, game, targetPlayerId); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId) { + return computerPlayer.searchLibrary(target, source, game, targetPlayerId); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents) { - return computerPlayer.searchLibrary(target, game, targetPlayerId, triggerEvents); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, boolean triggerEvents) { + return computerPlayer.searchLibrary(target, source, game, targetPlayerId, triggerEvents); } @Override - public boolean flipCoin(Game game) { - return computerPlayer.flipCoin(game); + public void lookAtAllLibraries(Ability source, Game game) { + computerPlayer.lookAtAllLibraries(source, game); } @Override - public boolean flipCoin(Game game, ArrayList appliedEffects) { - return computerPlayer.flipCoin(game, appliedEffects); + public boolean flipCoin(Ability source, Game game, boolean winnable) { + return computerPlayer.flipCoin(source, game, true); + } + + @Override + public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList appliedEffects) { + return computerPlayer.flipCoin(source, game, true, appliedEffects); } @Override @@ -2252,8 +2864,8 @@ public class TestPlayer implements Player { } @Override - public boolean lookAtFaceDownCard(Card card, Game game) { - return computerPlayer.lookAtFaceDownCard(card, game); + public boolean lookAtFaceDownCard(Card card, Game game, int abilitiesToActivate) { + return computerPlayer.lookAtFaceDownCard(card, game, abilitiesToActivate); } @Override @@ -2433,24 +3045,7 @@ public class TestPlayer implements Player { @Override public SpellAbility chooseSpellAbilityForCast(SpellAbility ability, Game game, boolean noMana) { - switch (ability.getSpellAbilityType()) { - case SPLIT: - case SPLIT_FUSED: - case SPLIT_AFTERMATH: - if (!choices.isEmpty()) { - MageObject object = game.getObject(ability.getSourceId()); - if (object != null) { - LinkedHashMap useableAbilities = computerPlayer.getSpellAbilities(object, game.getState().getZone(object.getId()), game); - for (String choose : choices) { - for (ActivatedAbility actiavtedAbility : useableAbilities.values()) { - if (actiavtedAbility.getRule().startsWith(choose)) { - return (SpellAbility) actiavtedAbility; - } - } - } - } - } - } + Assert.fail("That's method must calls only from computerPlayer->cast(), see TestComputerPlayerXXX"); return computerPlayer.chooseSpellAbilityForCast(ability, game, noMana); } @@ -2495,7 +3090,11 @@ public class TestPlayer implements Player { return true; } } + // TODO: enable fail checks and fix tests + //Assert.fail("Wrong choice"); } + + this.chooseStrictModeFailed(game, getInfo(target)); return computerPlayer.choose(outcome, cards, target, game); } @@ -2503,6 +3102,52 @@ public class TestPlayer implements Player { public boolean chooseTargetAmount(Outcome outcome, TargetAmount target, Ability source, Game game ) { + // command format: targetName^X=3 + + // chooseTargetAmount calls by TargetAmount for EACH target cycle + Assert.assertTrue("chooseTargetAmount supports only one target, but found " + target.getMaxNumberOfTargets(), target.getMaxNumberOfTargets() <= 1); + Assert.assertNotEquals("chooseTargetAmount need remaining > 0", 0, target.getAmountRemaining()); + + if (!targets.isEmpty()) { + + boolean founded = false; + String foundedRecord = ""; + CheckTargets: + for (String targetRecord : targets) { + String[] choiceSettings = targetRecord.split("\\^"); + if (choiceSettings.length == 2 && choiceSettings[1].startsWith("X=")) { + // can choice + String choiceName = choiceSettings[0]; + int choiceAmount = Integer.parseInt(choiceSettings[1].substring(2)); + + Assert.assertNotEquals("choice amount must be not zero", 0, choiceAmount); + Assert.assertTrue("choice amount " + choiceAmount + "must be <= remaining " + target.getAmountRemaining(), choiceAmount <= target.getAmountRemaining()); + + for (UUID possibleTarget : target.possibleTargets(source.getSourceId(), source.getControllerId(), game)) { + MageObject objectPermanent = game.getObject(possibleTarget); + Player objectPlayer = game.getPlayer(possibleTarget); + String objectName = objectPermanent != null ? objectPermanent.getName() : objectPlayer.getName(); + if (objectName.equals(choiceName)) { + if (!target.getTargets().contains(possibleTarget) && target.canTarget(possibleTarget, source, game)) { + // can select + target.addTarget(possibleTarget, choiceAmount, source, game); + founded = true; + foundedRecord = targetRecord; + break CheckTargets; + } + } + } + } + } + + if (founded) { + // all done + targets.remove(foundedRecord); + return true; + } + } + + this.chooseStrictModeFailed(game, getInfo(source) + "; " + getInfo(target)); return computerPlayer.chooseTargetAmount(outcome, target, source, game); } @@ -2684,4 +3329,8 @@ public class TestPlayer implements Player { return this.getId().equals(obj.getId()); } + + public void setChooseStrictMode(boolean enable) { + this.strictChooseMode = enable; + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java index e98ef90bce..1036836343 100644 --- a/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/rollback/NewCreaturesAreRemovedTest.java @@ -7,18 +7,16 @@ import org.junit.Test; import org.mage.test.serverside.base.CardTestPlayerBase; /** - * * @author LevelX2 */ public class NewCreaturesAreRemovedTest extends CardTestPlayerBase { /** * I was playing with a Tamiyo's Journal in the battlefield. - * + *

    * During my turn I rollbacked. The clue generated by Tamiyo's Journal * stayed on battlefield and when my turn started again, it re-investigated * for another one. - * */ @Test public void testTamiyosJournal() { @@ -93,9 +91,9 @@ public class NewCreaturesAreRemovedTest extends CardTestPlayerBase { playLand(7, PhaseStep.PRECOMBAT_MAIN, playerA, "Port Town"); attack(7, playerA, "Silvercoat Lion"); - rollbackTurns(7, PhaseStep.END_TURN, playerA, 0); + rollbackTurns(7, PhaseStep.POSTCOMBAT_MAIN, playerA, 0); - setStopAt(7, PhaseStep.POSTCOMBAT_MAIN); + setStopAt(7, PhaseStep.END_TURN); execute(); assertPermanentCount(playerA, "Port Town", 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java index ab1e8568d7..77f8e4aaad 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/PlayGameTest.java @@ -1,11 +1,5 @@ package org.mage.test.serverside; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Random; import mage.cards.Card; import mage.cards.Sets; import mage.cards.decks.Deck; @@ -16,32 +10,41 @@ import mage.game.Game; import mage.game.GameException; import mage.game.GameOptions; import mage.game.TwoPlayerDuel; +import mage.game.mulligan.VancouverMulligan; import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.players.PlayerType; +import mage.util.RandomUtil; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + /** * @author ayratn */ public class PlayGameTest extends MageTestBase { - private final static List colorChoices = Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu"); + private static final List colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu")); + private static final int DECK_SIZE = 40; @Ignore @Test public void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); Player computerA = createPlayer("ComputerA", PlayerType.COMPUTER_MINIMAX_HYBRID); // Player playerA = createPlayer("ComputerA", "Computer - mad"); // Deck deck = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck = generateRandomDeck(); - if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + if (deck.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); @@ -50,8 +53,8 @@ public class PlayGameTest extends MageTestBase { // Player playerB = createPlayer("ComputerB", "Computer - mad"); // Deck deck2 = Deck.load(Sets.loadDeck("RB Aggro.dck")); Deck deck2 = generateRandomDeck(); - if (deck2.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + if (deck2.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck2.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); @@ -79,7 +82,7 @@ public class PlayGameTest extends MageTestBase { } private Deck generateRandomDeck() { - String selectedColors = colorChoices.get(new Random().nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); + String selectedColors = colorChoices.get(RandomUtil.nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); List allowedColors = new ArrayList<>(); logger.info("Building deck with colors: " + selectedColors); for (int i = 0; i < selectedColors.length(); i++) { @@ -87,6 +90,6 @@ public class PlayGameTest extends MageTestBase { allowedColors.add(ColoredManaSymbol.lookup(c)); } List cardPool = Sets.generateRandomCardPool(45, allowedColors); - return ComputerPlayer.buildDeck(cardPool, allowedColors); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java index 01aecf546f..3d51dff3bb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/TestPlayRandomGame.java @@ -1,11 +1,5 @@ package org.mage.test.serverside; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.Random; import mage.cards.Card; import mage.cards.Sets; import mage.cards.decks.Deck; @@ -16,18 +10,27 @@ import mage.game.Game; import mage.game.GameException; import mage.game.GameOptions; import mage.game.TwoPlayerDuel; +import mage.game.mulligan.VancouverMulligan; import mage.player.ai.ComputerPlayer; import mage.players.Player; +import mage.util.RandomUtil; import org.junit.Ignore; import org.junit.Test; import org.mage.test.serverside.base.MageTestBase; +import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + /** * @author ayratn */ public class TestPlayRandomGame extends MageTestBase { - private final static List colorChoices = Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu"); + private static final List colorChoices = new ArrayList<>(Arrays.asList("bu", "bg", "br", "bw", "ug", "ur", "uw", "gr", "gw", "rw", "bur", "buw", "bug", "brg", "brw", "bgw", "wur", "wug", "wrg", "rgu")); + private static final int DECK_SIZE = 40; @Test @Ignore @@ -39,21 +42,21 @@ public class TestPlayRandomGame extends MageTestBase { } private void playOneGame() throws GameException, FileNotFoundException, IllegalArgumentException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, 0, 20); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ALL, new VancouverMulligan(0), 20); Player computerA = createRandomPlayer("ComputerA"); Deck deck = generateRandomDeck(); - if (deck.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); + if (deck.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size = " + deck.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerA, deck); game.loadCards(deck.getCards(), computerA.getId()); Player computerB = createRandomPlayer("ComputerB"); Deck deck2 = generateRandomDeck(); - if (deck2.getCards().size() < 40) { - throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size()); + if (deck2.getCards().size() < DECK_SIZE) { + throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck2.getCards().size() + ", but must be " + DECK_SIZE); } game.addPlayer(computerB, deck2); game.loadCards(deck2.getCards(), computerB.getId()); @@ -70,7 +73,7 @@ public class TestPlayRandomGame extends MageTestBase { } private Deck generateRandomDeck() { - String selectedColors = colorChoices.get(new Random().nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); + String selectedColors = colorChoices.get(RandomUtil.nextInt(colorChoices.size())).toUpperCase(Locale.ENGLISH); List allowedColors = new ArrayList<>(); logger.info("Building deck with colors: " + selectedColors); for (int i = 0; i < selectedColors.length(); i++) { @@ -78,6 +81,6 @@ public class TestPlayRandomGame extends MageTestBase { allowedColors.add(ColoredManaSymbol.lookup(c)); } List cardPool = Sets.generateRandomCardPool(45, allowedColors); - return ComputerPlayer.buildDeck(cardPool, allowedColors); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommander3PlayersFFA.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommander3PlayersFFA.java index c094cf874c..d259dd05ac 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommander3PlayersFFA.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommander3PlayersFFA.java @@ -6,6 +6,7 @@ import mage.constants.RangeOfInfluence; import mage.game.CommanderFreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; /** @@ -23,7 +24,7 @@ public abstract class CardTestCommander3PlayersFFA extends CardTestPlayerAPIImpl @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, 0, 40); + Game game = new CommanderFreeForAll(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ONE, new VancouverMulligan(0), 40); playerA = createPlayer(game, playerA, "PlayerA", deckNameA); playerB = createPlayer(game, playerB, "PlayerB", deckNameB); playerC = createPlayer(game, playerC, "PlayerC", deckNameC); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommanderDuelBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommanderDuelBase.java index d3972b5530..3a9847db68 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommanderDuelBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestCommanderDuelBase.java @@ -7,6 +7,7 @@ import mage.constants.RangeOfInfluence; import mage.game.CommanderDuel; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; /** @@ -23,7 +24,7 @@ public abstract class CardTestCommanderDuelBase extends CardTestPlayerAPIImpl { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new CommanderDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 40); + Game game = new CommanderDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, new VancouverMulligan(0), 40); playerA = createPlayer(game, playerA, "PlayerA", deckNameA); playerB = createPlayer(game, playerB, "PlayerB", deckNameB); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java index 863ac2b256..804e28fef9 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestMultiPlayerBase.java @@ -6,6 +6,7 @@ import mage.constants.RangeOfInfluence; import mage.game.FreeForAll; import mage.game.Game; import mage.game.GameException; +import mage.game.mulligan.VancouverMulligan; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; /** @@ -20,7 +21,7 @@ public abstract class CardTestMultiPlayerBase extends CardTestPlayerAPIImpl { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); + Game game = new FreeForAll(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, new VancouverMulligan(0), 20); // Player order: A -> D -> C -> B playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java index 5c92e59006..6abbbf6dc7 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBase.java @@ -6,6 +6,7 @@ import mage.constants.RangeOfInfluence; import mage.game.Game; import mage.game.GameException; import mage.game.TwoPlayerDuel; +import mage.game.mulligan.VancouverMulligan; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; /** @@ -22,7 +23,7 @@ public abstract class CardTestPlayerBase extends CardTestPlayerAPIImpl { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, new VancouverMulligan(0), 20); playerA = createPlayer(game, playerA, "PlayerA", deckNameA); playerB = createPlayer(game, playerB, "PlayerB", deckNameB); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java index fa1a5241d2..d3da9e21c8 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/CardTestPlayerBaseAI.java @@ -1,18 +1,18 @@ - package org.mage.test.serverside.base; -import java.io.FileNotFoundException; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.game.Game; import mage.game.GameException; import mage.game.TwoPlayerDuel; -import mage.player.ai.ComputerPlayer7; +import mage.game.mulligan.VancouverMulligan; +import org.mage.test.player.TestComputerPlayer7; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.impl.CardTestPlayerAPIImpl; +import java.io.FileNotFoundException; + /** - * * @author LevelX2 */ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @@ -21,7 +21,7 @@ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @Override protected Game createNewGameAndPlayers() throws GameException, FileNotFoundException { - Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, 0, 20); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.LEFT, RangeOfInfluence.ONE, new VancouverMulligan(0), 20); playerA = createPlayer(game, playerA, "PlayerA"); playerB = createPlayer(game, playerB, "PlayerB"); @@ -31,7 +31,7 @@ public abstract class CardTestPlayerBaseAI extends CardTestPlayerAPIImpl { @Override protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { if (name.equals("PlayerA")) { - TestPlayer testPlayer = new TestPlayer(new ComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); + TestPlayer testPlayer = new TestPlayer(new TestComputerPlayer7("PlayerA", RangeOfInfluence.ONE, skill)); testPlayer.setAIPlayer(true); return testPlayer; } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java index 37da99ab42..25bf051210 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/MageTestPlayerBase.java @@ -1,15 +1,7 @@ package org.mage.test.serverside.base; -import java.io.File; -import java.io.FileNotFoundException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Scanner; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import mage.cards.Card; +import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.PhaseStep; @@ -19,7 +11,6 @@ import mage.game.Game; import mage.game.match.MatchType; import mage.game.permanent.PermanentCard; import mage.game.tournament.TournamentType; -import mage.player.ai.ComputerPlayer; import mage.players.Player; import mage.server.game.GameFactory; import mage.server.util.ConfigSettings; @@ -30,8 +21,15 @@ import mage.util.Copier; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.junit.BeforeClass; +import org.mage.test.player.TestComputerPlayer; import org.mage.test.player.TestPlayer; +import java.io.File; +import java.io.FileNotFoundException; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + /** * Base class for all tests. * @@ -54,6 +52,8 @@ public abstract class MageTestPlayerBase { protected Map> commands = new HashMap<>(); + protected static Map loadedDeckCardLists = new HashMap<>(); // test decks buffer + protected TestPlayer playerA; protected TestPlayer playerB; protected TestPlayer playerC; @@ -330,7 +330,13 @@ public abstract class MageTestPlayerBase { } protected TestPlayer createPlayer(String name, RangeOfInfluence rangeOfInfluence) { - return new TestPlayer(new ComputerPlayer(name, rangeOfInfluence)); + return new TestPlayer(new TestComputerPlayer(name, rangeOfInfluence)); } + public void setStrictChooseMode(boolean enable) { + if (playerA != null) playerA.setChooseStrictMode(enable); + if (playerB != null) playerB.setChooseStrictMode(enable); + if (playerC != null) playerC.setChooseStrictMode(enable); + if (playerD != null) playerD.setChooseStrictMode(enable); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index bf2a95d870..c7ecc49a0a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -1,12 +1,12 @@ package org.mage.test.serverside.base.impl; -import mage.MageInt; import mage.Mana; import mage.ObjectColor; import mage.abilities.Ability; import mage.cards.Card; import mage.cards.decks.Deck; -import mage.cards.decks.importer.DeckImporterUtil; +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.importer.DeckImporter; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.cards.repository.CardScanner; @@ -24,8 +24,10 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; import mage.players.ManaPool; import mage.players.Player; +import mage.util.CardUtil; import org.junit.Assert; import org.junit.Before; +import org.mage.test.player.PlayerAction; import org.mage.test.player.TestPlayer; import org.mage.test.serverside.base.CardTestAPI; import org.mage.test.serverside.base.MageTestPlayerBase; @@ -48,13 +50,31 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement // Defines the constant if for activate ability is not target but a ability on the stack to define public static final String NO_TARGET = "NO_TARGET"; + // TODO: add target player param to commands public static final String CHECK_COMMAND_PT = "PT"; + public static final String CHECK_COMMAND_LIFE = "LIFE"; public static final String CHECK_COMMAND_ABILITY = "ABILITY"; public static final String CHECK_COMMAND_PERMANENT_COUNT = "PERMANENT_COUNT"; + public static final String CHECK_COMMAND_EXILE_COUNT = "EXILE_COUNT"; public static final String CHECK_COMMAND_HAND_COUNT = "HAND_COUNT"; + public static final String CHECK_COMMAND_HAND_CARD_COUNT = "HAND_CARD_COUNT"; public static final String CHECK_COMMAND_COLOR = "COLOR"; + public static final String CHECK_COMMAND_TYPE = "TYPE"; public static final String CHECK_COMMAND_SUBTYPE = "SUBTYPE"; public static final String CHECK_COMMAND_MANA_POOL = "MANA_POOL"; + public static final String CHECK_COMMAND_ALIAS_ZONE = "ALIAS_ZONE"; + + // TODO: add target player param to commands + public static final String SHOW_COMMAND_LIBRARY = "LIBRARY"; + public static final String SHOW_COMMAND_HAND = "HAND"; + public static final String SHOW_COMMAND_BATTLEFIELD = "BATTLEFIELD"; + public static final String SHOW_COMMAND_GRAVEYEARD = "GRAVEYARD"; + public static final String SHOW_COMMAND_EXILE = "EXILE"; + public static final String SHOW_COMMAND_AVAILABLE_ABILITIES = "AVAILABLE_ABILITIES"; + public static final String SHOW_COMMAND_ALIASES = "ALIASES"; + + // TODO: add target player param to commands + public static final String ALIAS_COMMAND_ADD = "ADD"; protected GameOptions gameOptions; @@ -64,7 +84,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement protected String deckNameD; protected enum ExpectedType { - TURN_NUMBER, RESULT, LIFE, @@ -165,12 +184,21 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement protected TestPlayer createPlayer(Game game, TestPlayer player, String name, String deckName) throws GameException { player = createNewPlayer(name, game.getRangeOfInfluence()); player.setTestMode(true); + logger.debug("Loading deck..."); - Deck deck = Deck.load(DeckImporterUtil.importDeck(deckName), false, false); + DeckCardLists list; + if (loadedDeckCardLists.containsKey(deckName)) { + list = loadedDeckCardLists.get(deckName); + } else { + list = DeckImporter.importDeckFromFile(deckName); + loadedDeckCardLists.put(deckName, list); + } + Deck deck = Deck.load(list, false, false); logger.debug("Done!"); if (deck.getCards().size() < 40) { throw new IllegalArgumentException("Couldn't load deck, deck size=" + deck.getCards().size()); } + game.loadCards(deck.getCards(), player.getId()); game.loadCards(deck.getSideboard(), player.getId()); game.addPlayer(player, deck); @@ -183,6 +211,27 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement throw new IllegalStateException("Game is not initialized. Use load method to load a test case and initialize a game."); } + // check stop command + int maxTurn = 1; + int maxPhase = 0; + for (Player player : currentGame.getPlayers().values()) { + if (player instanceof TestPlayer) { + TestPlayer testPlayer = (TestPlayer) player; + for (PlayerAction action : testPlayer.getActions()) { + Assert.assertTrue("Wrong turn in action " + action.getTurnNum(), action.getTurnNum() >= 1); + int curTurn = action.getTurnNum(); + int curPhase = action.getStep().getIndex(); + if ((curTurn > maxTurn) || (curTurn == maxTurn && curPhase > maxPhase)) { + maxTurn = curTurn; + maxPhase = curPhase; + } + } + } + } + Assert.assertFalse("Wrong stop command on " + this.stopOnTurn + " / " + this.stopAtStep + " (" + this.stopAtStep.getIndex() + ")" + + " (found actions after stop on " + maxTurn + " / " + maxPhase + ")", + (maxTurn > this.stopOnTurn) || (maxTurn == this.stopOnTurn && maxPhase > this.stopAtStep.getIndex())); + for (Player player : currentGame.getPlayers().values()) { TestPlayer testPlayer = (TestPlayer) player; currentGame.cheat(player.getId(), getCommands(testPlayer)); @@ -201,6 +250,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement logger.debug("Winner: " + currentGame.getWinner()); logger.info("Test has been executed. Execution time: " + (t2 - t1) / 1000000 + " ms"); + // TODO: 01.12.2018, JayDi85 - uncomment and fix MANY broken tests with wrong commands + //assertAllCommandsUsed(); } protected TestPlayer createNewPlayer(String playerName, RangeOfInfluence rangeOfInfluence) { @@ -228,6 +279,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement return player; } + // check commands + private void check(String checkName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) { String res = "check:" + command; for (String param : params) { @@ -237,26 +290,50 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void checkPT(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer power, Integer toughness) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_PT, permanentName, power.toString(), toughness.toString()); } + public void checkLife(String checkName, int turnNum, PhaseStep step, TestPlayer player, Integer life) { + check(checkName, turnNum, step, player, CHECK_COMMAND_LIFE, life.toString()); + } + public void checkAbility(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Class abilityClass, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_ABILITY, permanentName, abilityClass.getName(), mustHave.toString()); } public void checkPermanentCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer count) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_PERMANENT_COUNT, permanentName, count.toString()); } + public void checkExileCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, Integer count) { + //Assert.assertNotEquals("", permanentName); + check(checkName, turnNum, step, player, CHECK_COMMAND_EXILE_COUNT, permanentName, count.toString()); + } + public void checkHandCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, Integer count) { check(checkName, turnNum, step, player, CHECK_COMMAND_HAND_COUNT, count.toString()); } + public void checkHandCardCount(String checkName, int turnNum, PhaseStep step, TestPlayer player, String cardName, Integer count) { + //Assert.assertNotEquals("", cardName); + check(checkName, turnNum, step, player, CHECK_COMMAND_HAND_CARD_COUNT, cardName, count.toString()); + } + public void checkColor(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, String colors, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_COLOR, permanentName, colors, mustHave.toString()); } + public void checkType(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, CardType type, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); + check(checkName, turnNum, step, player, CHECK_COMMAND_TYPE, permanentName, type.toString(), mustHave.toString()); + } + public void checkSubType(String checkName, int turnNum, PhaseStep step, TestPlayer player, String permanentName, SubType subType, Boolean mustHave) { + //Assert.assertNotEquals("", permanentName); check(checkName, turnNum, step, player, CHECK_COMMAND_SUBTYPE, permanentName, subType.toString(), mustHave.toString()); } @@ -264,6 +341,52 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement check(checkName, turnNum, step, player, CHECK_COMMAND_MANA_POOL, colors, amount.toString()); } + public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone) { + checkAliasZone(checkName, turnNum, step, player, alias, zone, true); + } + + public void checkAliasZone(String checkName, int turnNum, PhaseStep step, TestPlayer player, String alias, Zone zone, Boolean mustHave) { + check(checkName, turnNum, step, player, CHECK_COMMAND_ALIAS_ZONE, alias, zone.toString(), mustHave.toString()); + } + + // show commands + + private void show(String showName, int turnNum, PhaseStep step, TestPlayer player, String command, String... params) { + String res = "show:" + command; + for (String param : params) { + res += "@" + param; + } + player.addAction(showName, turnNum, step, res); + } + + public void showLibrary(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_LIBRARY); + } + + public void showHand(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_HAND); + } + + public void showBattlefield(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_BATTLEFIELD); + } + + public void showGraveyard(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_GRAVEYEARD); + } + + public void showExile(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_EXILE); + } + + public void showAvaileableAbilities(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_AVAILABLE_ABILITIES); + } + + public void showAliases(String showName, int turnNum, PhaseStep step, TestPlayer player) { + show(showName, turnNum, step, player, SHOW_COMMAND_ALIASES); + } + /** * Removes all cards from player's library from the game. Usually this * should be used once before initialization to form the library in certain @@ -328,6 +451,19 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void addCard(Zone gameZone, TestPlayer player, String cardName, int count, boolean tapped) { + // aliases for mage objects + String aliasName = ""; + boolean useAliasMultiNames = (count != 1); + if (cardName.contains("@")) { + aliasName = cardName.substring(cardName.indexOf("@") + 1); + cardName = cardName.substring(0, cardName.indexOf("@")); + } + + // one card = one aliase, massive adds can use auto-name + if (!useAliasMultiNames && !aliasName.isEmpty() && player.getAliasByName(aliasName) != null) { + Assert.fail("Can't add card " + cardName + " - alias " + aliasName + " already exists for " + player.getName()); + } + if (gameZone == Zone.BATTLEFIELD) { for (int i = 0; i < count; i++) { CardInfo cardInfo = CardRepository.instance.findCard(cardName); @@ -338,6 +474,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement PermanentCard p = new PermanentCard(card.copy(), player.getId(), currentGame); p.setTapped(tapped); getBattlefieldCards(player).add(p); + + if (!aliasName.isEmpty()) { + player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), p.getId()); + } } } else { if (tapped) { @@ -351,6 +491,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement throw new AssertionError("Couldn't find a card: " + cardName); } cards.add(card); + + if (!aliasName.isEmpty()) { + player.addAlias(player.generateAliasName(aliasName, useAliasMultiNames, i + 1), card.getId()); + } } } } @@ -385,7 +529,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void setLife(TestPlayer player, int life) { - getCommands(player).put(Zone.OUTSIDE, "life:" + String.valueOf(life)); + getCommands(player).put(Zone.OUTSIDE, "life:" + life); } /** @@ -395,8 +539,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void setStopOnTurn(int turn) { - stopOnTurn = turn == -1 ? null : turn; - stopAtStep = PhaseStep.UNTAP; + setStopAt(turn, PhaseStep.UNTAP); } /** @@ -408,7 +551,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void setStopAt(int turn, PhaseStep step) { - stopOnTurn = turn == -1 ? null : turn; + Assert.assertTrue("Wrong turn " + turn, turn >= 1); + stopOnTurn = turn; stopAtStep = step; } @@ -487,6 +631,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertPowerToughness(Player player, String cardName, int power, int toughness, Filter.ComparisonScope scope) throws AssertionError { + //Assert.assertNotEquals("", cardName); int count = 0; int fit = 0; int foundPower = 0; @@ -541,6 +686,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertAbilities(Player player, String cardName, List abilities) throws AssertionError { + //Assert.assertNotEquals("", cardName); int count = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) { @@ -576,6 +722,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @throws AssertionError */ public void assertAbility(Player player, String cardName, Ability ability, boolean mustHave, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int foundCount = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents(player.getId())) { @@ -626,6 +773,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement */ @Override public void assertPermanentCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getControllerId().equals(player.getId())) { @@ -639,6 +787,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement @Override public void assertCommandZoneCount(Player player, String commandZoneObjectName, int count) throws AssertionError { + //Assert.assertNotEquals("", commandZoneObjectName); int actualCount = 0; for (CommandObject commandObject : currentGame.getState().getCommand()) { if (commandObject.getControllerId().equals(player.getId()) && commandObject.getName().equals(commandZoneObjectName)) { @@ -678,6 +827,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void assertCounterCount(Player player, String cardName, CounterType type, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName) && (player == null || permanent.getControllerId().equals(player.getId()))) { @@ -697,11 +847,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertCounterOnExiledCardCount(String cardName, CounterType type, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); Card found = null; if (found == null) { for (Card card : currentGame.getExile().getAllCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { found = card; break; } @@ -731,6 +882,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param mustHave true if creature should have type, false if it should not */ public void assertType(String cardName, CardType type, boolean mustHave) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -753,6 +905,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param subType a subtype to test for */ public void assertType(String cardName, CardType type, SubType subType) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); Assert.assertTrue("(Battlefield) card type not found (" + cardName + ':' + type + ')', found.getCardType().contains(type)); if (subType != null) { @@ -767,6 +920,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param type A type to test for */ public void assertNotType(String cardName, CardType type) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); Assert.assertFalse("(Battlefield) card type found (" + cardName + ':' + type + ')', found.getCardType().contains(type)); } @@ -778,6 +932,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param subType a subtype to test for */ public void assertNotSubtype(String cardName, SubType subType) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = getPermanent(cardName); if (subType != null) { Assert.assertFalse("(Battlefield) card sub-type equal (" + cardName + ':' + subType.getDescription() + ')', found.getSubtype(currentGame).contains(subType)); @@ -793,6 +948,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param mustHave must or not must have that colors */ public void assertColor(Player player, String cardName, ObjectColor searchColors, boolean mustHave) { + //Assert.assertNotEquals("", cardName); Assert.assertNotEquals("must setup colors to search", 0, searchColors.getColorCount()); Permanent card = getPermanent(cardName, player); @@ -827,6 +983,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param tapped Whether the permanent is tapped or not */ public void assertTapped(String cardName, boolean tapped) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -852,6 +1009,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count The amount of this permanents that should be tapped */ public void assertTappedCount(String cardName, boolean tapped, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int tappedAmount = 0; Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { @@ -873,6 +1031,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param attacking Whether the permanent is attacking or not */ public void assertAttacking(String cardName, boolean attacking) throws AssertionError { + //Assert.assertNotEquals("", cardName); Permanent found = null; for (Permanent permanent : currentGame.getBattlefield().getAllActivePermanents()) { if (permanent.getName().equals(cardName)) { @@ -904,17 +1063,18 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertHandCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actual; if (cardName.contains("//")) { // special logic for cheched split cards, because in game logic of card name filtering is different than for test actual = 0; for (Card card : currentGame.getPlayer(player.getId()).getHand().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actual++; } } } else { FilterCard filter = new FilterCard(); - filter.add(new NamePredicate(cardName)); + filter.add(new NamePredicate(cardName, true)); // must find any cards even without names actual = currentGame.getPlayer(player.getId()).getHand().count(filter, player.getId(), currentGame); } Assert.assertEquals("(Hand) Card counts for card " + cardName + " for " + player.getName() + " are not equal ", count, actual); @@ -963,10 +1123,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertExileCount(String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (ExileZone exile : currentGame.getExile().getExileZones()) { for (Card card : exile.getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1002,6 +1163,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertExileCount(Player owner, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (ExileZone exile : currentGame.getExile().getExileZones()) { for (Card card : exile.getCards(currentGame)) { @@ -1021,9 +1183,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertGraveyardCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Card card : player.getGraveyard().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1038,7 +1201,6 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertLibraryCount(Player player, int count) throws AssertionError { - List libraryList = player.getLibrary().getCards(currentGame); int actualCount = libraryList != null && !libraryList.isEmpty() ? libraryList.size() : 0; Assert.assertEquals("(Library " + player.getName() + ") counts are not equal", count, actualCount); @@ -1052,9 +1214,10 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param count Expected count. */ public void assertLibraryCount(Player player, String cardName, int count) throws AssertionError { + //Assert.assertNotEquals("", cardName); int actualCount = 0; for (Card card : player.getLibrary().getCards(currentGame)) { - if (card.getName().equals(cardName)) { + if (CardUtil.haveSameNames(card.getName(), cardName, true)) { actualCount++; } } @@ -1062,15 +1225,27 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement Assert.assertEquals("(Library " + player.getName() + ") Card counts are not equal (" + cardName + ')', count, actualCount); } - /** - * Asserts added actions count. Useful to make sure that all actions were - * executed. - * - * @param player - * @param count - */ - public void assertActionCount(TestPlayer player, int count) { - Assert.assertEquals("Actions left are not equal: ", count, player.getActionCount()); + public void assertActionsCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Actions of " + player.getName() + ") Count are not equal (found [" + + player.getActions().stream().map(PlayerAction::getAction).collect(Collectors.joining(", ")) + + "])", count, player.getActions().size()); + } + + public void assertChoicesCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Choices of " + player.getName() + ") Count are not equal (found " + player.getChoices() + ")", count, player.getChoices().size()); + } + + public void assertTargetsCount(TestPlayer player, int count) throws AssertionError { + Assert.assertEquals("(Targets of " + player.getName() + ") Count are not equal (found " + player.getTargets() + ")", count, player.getTargets().size()); + } + + public void assertAllCommandsUsed() throws AssertionError { + for (Player player : currentGame.getPlayers().values()) { + TestPlayer testPlayer = (TestPlayer) player; + assertActionsCount(testPlayer, 0); + assertChoicesCount(testPlayer, 0); + assertTargetsCount(testPlayer, 0); + } } public void assertActivePlayer(TestPlayer player) { @@ -1111,21 +1286,29 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void playLand(int turnNum, PhaseStep step, TestPlayer player, String cardName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Play " + cardName); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName()); } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, Player target, int manaInPool) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$targetPlayer=" + target.getName() + "$manaInPool=" + manaInPool); } + public void waitStackResolved(int turnNum, PhaseStep step, TestPlayer player) { + player.addAction(turnNum, step, "waitStackResolved"); + } + /** * Rollback the number of given turns: 0 = rollback to the start of the * current turn @@ -1159,11 +1342,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * multiple targets can be seperated by ^ */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "activate:Cast " + cardName + "$target=" + targetName); } public enum StackClause { - WHILE_ON_STACK, WHILE_COPY_ON_STACK, WHILE_NOT_ON_STACK @@ -1198,6 +1381,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement * @param clause */ public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, StackClause clause) { + //Assert.assertNotEquals("", cardName); if (StackClause.WHILE_ON_STACK == clause) { player.addAction(turnNum, step, "activate:Cast " + cardName + '$' + (targetName != null && targetName.startsWith("target") ? targetName : "target=" + targetName) @@ -1210,6 +1394,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void castSpell(int turnNum, PhaseStep step, TestPlayer player, String cardName, String targetName, String spellOnStack, String spellOnTopOfStack) { + //Assert.assertNotEquals("", cardName); String action = "activate:Cast " + cardName + "$target=" + targetName; if (spellOnStack != null && !spellOnStack.isEmpty()) { action += "$spellOnStack=" + spellOnStack; @@ -1225,18 +1410,22 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, Player target) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability + "$targetPlayer=" + target.getName()); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String... targetNames) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't player.addAction(turnNum, step, "activate:" + ability + "$target=" + String.join("^", targetNames)); } public void activateAbility(int turnNum, PhaseStep step, TestPlayer player, String ability, String targetName, String spellOnStack) { + // TODO: it's uses computerPlayer to execute, only ability target will work, but choices and targets commands aren't this.activateAbility(turnNum, step, player, ability, targetName, spellOnStack, StackClause.WHILE_ON_STACK); } @@ -1274,22 +1463,28 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void addCounters(int turnNum, PhaseStep step, TestPlayer player, String cardName, CounterType type, int count) { + //Assert.assertNotEquals("", cardName); player.addAction(turnNum, step, "addCounters:" + cardName + '$' + type.getName() + '$' + count); } public void attack(int turnNum, TestPlayer player, String attacker) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker); } public void attack(int turnNum, TestPlayer player, String attacker, TestPlayer defendingPlayer) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, "attack:" + attacker + "$defendingPlayer=" + defendingPlayer.getName()); } public void attack(int turnNum, TestPlayer player, String attacker, String planeswalker) { + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_ATTACKERS, new StringBuilder("attack:").append(attacker).append("$planeswalker=").append(planeswalker).toString()); } public void block(int turnNum, TestPlayer player, String blocker, String attacker) { + //Assert.assertNotEquals("", blocker); + //Assert.assertNotEquals("", attacker); player.addAction(turnNum, PhaseStep.DECLARE_BLOCKERS, "block:" + blocker + '$' + attacker); } @@ -1383,9 +1578,17 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement } public void assertDamageReceived(Player player, String cardName, int expected) { + //Assert.assertNotEquals("", cardName); Permanent p = getPermanent(cardName, player.getId()); if (p != null) { Assert.assertEquals("Wrong damage received: ", expected, p.getDamage()); } } + + public void waitStackResolved(int turnNum, PhaseStep step) { + if (playerA != null) waitStackResolved(turnNum, step, playerA); + if (playerB != null) waitStackResolved(turnNum, step, playerB); + if (playerC != null) waitStackResolved(turnNum, step, playerC); + if (playerD != null) waitStackResolved(turnNum, step, playerD); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java index e472754c2a..3feddbd4eb 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/deck/DeckValidatorTest.java @@ -59,13 +59,9 @@ public class DeckValidatorTest extends MageTestBase { } @Test - public void testStandardValid() { + public void testStandardDeckCardsAmountValid() { ArrayList deck = new ArrayList<>(); - - deck.add(new CardNameAmount("MPS-AKH", 28, 4)); // Rhonas the Indomitable - deck.add(new CardNameAmount("Built to Smash", 4)); - deck.add(new CardNameAmount("Heroic Intervention", 4)); - deck.add(new CardNameAmount("Mountain", 48)); + deck.add(new CardNameAmount("Mountain", 60)); DeckValidator validator = new Standard(); boolean validationSuccessful = testDeckValid(validator, deck); @@ -73,13 +69,9 @@ public class DeckValidatorTest extends MageTestBase { } @Test - public void testStandardNotValid() { + public void testStandardDeckCardsAmountNotValid() { ArrayList deck = new ArrayList<>(); - - deck.add(new CardNameAmount("MPS-AKH", 28, 4)); // Rhonas the Indomitable - deck.add(new CardNameAmount("Built to Smash", 4)); - deck.add(new CardNameAmount("Heroic Intervention", 4)); - deck.add(new CardNameAmount("Mountain", 47)); + deck.add(new CardNameAmount("Mountain", 59)); ArrayList sideboard = new ArrayList<>(); sideboard.add(new CardNameAmount("Mountain", 16)); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java index 711d329caa..0ba6e9f02b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/rating/GlickoRatingSystemTest.java @@ -1,33 +1,28 @@ - package org.mage.test.serverside.rating; -import org.junit.Assert; import mage.server.rating.GlickoRating; import mage.server.rating.GlickoRatingSystem; +import mage.util.RandomUtil; +import org.junit.Assert; import org.junit.Test; -import java.util.Random; - /** - * * @author Quercitron */ public class GlickoRatingSystemTest { - private final Random random = new Random(); - @Test public void testRatingsAreEqualAfterDraws() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); int count = 1000; for (int i = 0; i < count; i++) { - double startRating = random.nextDouble() * 2500 + 500; - double startRatingDeviation = Math.min(random.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); + double startRating = RandomUtil.nextDouble() * 2500 + 500; + double startRatingDeviation = Math.min(RandomUtil.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); GlickoRating player1 = new GlickoRating(startRating, startRatingDeviation, 1); GlickoRating player2 = new GlickoRating(startRating, startRatingDeviation, 1); - int gamesCount = random.nextInt(50) + 1; + int gamesCount = RandomUtil.nextInt(50) + 1; for (int j = 0; j < gamesCount; j++) { glickoRatingSystem.updateRating(player1, player2, 0.5, j + 2); @@ -43,21 +38,20 @@ public class GlickoRatingSystemTest { int count = 1000; for (int i = 0; i < count; i++) { - double startRating1 = random.nextDouble() * 2500 + 500; - double startRating2 = random.nextDouble() * 2500 + 500; - double startRatingDeviation = Math.min(random.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); + double startRating1 = RandomUtil.nextDouble() * 2500 + 500; + double startRating2 = RandomUtil.nextDouble() * 2500 + 500; + double startRatingDeviation = Math.min(RandomUtil.nextDouble() * 300 + 100, GlickoRatingSystem.BaseRD); GlickoRating player1 = new GlickoRating(startRating1, startRatingDeviation, 1); GlickoRating player2 = new GlickoRating(startRating2, startRatingDeviation, 1); - glickoRatingSystem.updateRating(player1, player2, random.nextDouble(), 1); + glickoRatingSystem.updateRating(player1, player2, RandomUtil.nextDouble(), 1); Assert.assertEquals(player1.getRating() - startRating1, startRating2 - player2.getRating(), 1e-5); Assert.assertEquals(player1.getRatingDeviation(), player2.getRatingDeviation(), 1e-5); } } @Test - public void testExactResult1() - { + public void testExactResult1() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -73,8 +67,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult2() - { + public void testExactResult2() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -90,8 +83,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult3() - { + public void testExactResult3() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 350, 1); @@ -107,8 +99,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult4() - { + public void testExactResult4() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 250, 1); @@ -124,8 +115,7 @@ public class GlickoRatingSystemTest { } @Test - public void testExactResult5() - { + public void testExactResult5() { GlickoRatingSystem glickoRatingSystem = new GlickoRatingSystem(); GlickoRating player1 = new GlickoRating(1500, 100, 1); diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java b/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java index 8a3ba52dd1..f79e7b4b3b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/tournament/SwissPairingMinimalWeightMatchingTest.java @@ -1,21 +1,24 @@ - - package org.mage.test.serverside.tournament; -import java.util.*; - -import mage.game.tournament.*; +import mage.game.tournament.Round; +import mage.game.tournament.TournamentPairing; +import mage.game.tournament.TournamentPlayer; import mage.game.tournament.pairing.RoundPairings; import mage.game.tournament.pairing.SwissPairingMinimalWeightMatching; +import mage.util.RandomUtil; import org.junit.Assert; import org.junit.Test; import org.mage.test.stub.PlayerStub; import org.mage.test.stub.TournamentStub; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + /** - * * @author Quercitron */ public class SwissPairingMinimalWeightMatchingTest { @@ -264,7 +267,6 @@ public class SwissPairingMinimalWeightMatchingTest { } private void SimulateTournament(int playersCount, int roundsCount) { - Random rnd = new Random(); List players = new ArrayList<>(); for (int i = 0; i < playersCount; i++) { @@ -294,7 +296,7 @@ public class SwissPairingMinimalWeightMatchingTest { playedPairs.add(pairing); round.addPairing(pairing); - if (rnd.nextBoolean()) { + if (RandomUtil.nextBoolean()) { pairing.getPlayer1().setPoints(pairing.getPlayer1().getPoints() + 3); } else { pairing.getPlayer2().setPoints(pairing.getPlayer2().getPoints() + 3); diff --git a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java index bfae2666eb..e3347d4ce3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/sets/BoosterGenerationTest.java @@ -33,7 +33,7 @@ public class BoosterGenerationTest extends MageTestBase { CardScanner.scan(); } - private static final List basics = Arrays.asList("Plains", "Island", "Swamp", "Mountain", "Forest"); + private static final List basics = new ArrayList<>(Arrays.asList("Plains", "Island", "Swamp", "Mountain", "Forest")); private void checkOnePartnerBoost() { List booster = Battlebond.getInstance().createBooster(); @@ -64,11 +64,11 @@ public class BoosterGenerationTest extends MageTestBase { @Test public void testFateReforged() { - List tapland = Arrays.asList( + List tapland = new ArrayList<>(Arrays.asList( "Bloodfell Caves", "Blossoming Sands", "Dismal Backwater", "Jungle Hollow", "Rugged Highlands", - "Scoured Barrens", "Swiftwater Cliffs", "Thornwood Falls", "Tranquil Cove", "Wind-Scarred Crag"); - List fetchland = Arrays.asList( - "Bloodstained Mire", "Flooded Strand", "Polluted Delta", "Windswept Heath", "Wooded Foothills"); + "Scoured Barrens", "Swiftwater Cliffs", "Thornwood Falls", "Tranquil Cove", "Wind-Scarred Crag")); + List fetchland = new ArrayList<>(Arrays.asList( + "Bloodstained Mire", "Flooded Strand", "Polluted Delta", "Windswept Heath", "Wooded Foothills")); List booster = FateReforged.getInstance().createBooster(); assertTrue(str(booster), contains(booster, tapland, "FRF") || contains(booster, fetchland, "KTK") @@ -78,13 +78,13 @@ public class BoosterGenerationTest extends MageTestBase { @Test public void testMastersEditionII() { - List snowCoveredLand = Arrays.asList( + List snowCoveredLand = new ArrayList<>(Arrays.asList( "Snow-Covered Plains", "Snow-Covered Island", "Snow-Covered Swamp", "Snow-Covered Mountain", "Snow-Covered Forest" - ); + )); List booster = MastersEditionII.getInstance().createBooster(); assertTrue(str(booster), contains(booster, snowCoveredLand, "ME2")); assertFalse(str(booster), contains(booster, basics, null)); @@ -93,11 +93,11 @@ public class BoosterGenerationTest extends MageTestBase { @Test public void testMastersEditionIV_UrzaSpecialLandsList() { - List needUrzaList = Arrays.asList( + List needUrzaList = new ArrayList<>(Arrays.asList( "Urza's Mine", "Urza's Power Plant", "Urza's Tower" - ); + )); List setOrzaList = MastersEditionIV.getInstance().getSpecialLand(); Assert.assertEquals("Urza special lands must have 4 variation for each of 3 card", 3 * 4, setOrzaList.size()); @@ -117,11 +117,11 @@ public class BoosterGenerationTest extends MageTestBase { public void testMastersEditionIV_UrzaSpecialLandInBoosters() { // ME4 replace all basic lands with special (1 per booster) // https://mtg.gamepedia.com/Masters_Edition_IV - List urzaLand = Arrays.asList( + List urzaLand = new ArrayList<>(Arrays.asList( "Urza's Mine", "Urza's Power Plant", "Urza's Tower" - ); + )); for (int i = 1; i <= 5; i++) { List booster = MastersEditionIV.getInstance().createBooster(); diff --git a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java index 810c068ccf..6fe462512f 100644 --- a/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java +++ b/Mage.Tests/src/test/java/org/mage/test/stub/PlayerStub.java @@ -138,6 +138,11 @@ public class PlayerStub implements Player { return 0; } + @Override + public int damage(int damage, UUID sourceId, Game game) { + return 0; + } + @Override public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) { return 0; @@ -578,25 +583,29 @@ public class PlayerStub implements Player { } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game) { + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game) { return false; } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, boolean triggerEvents) { + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, boolean triggerEvents) { return false; } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId) { + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId) { return false; } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents) { + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, boolean triggerEvents) { return false; } + @Override + public void lookAtAllLibraries(Ability source, Game game) { + } + @Override public boolean canPlayLand() { return false; @@ -633,12 +642,12 @@ public class PlayerStub implements Player { } @Override - public boolean flipCoin(Game game) { + public boolean flipCoin(Ability source, Game game, boolean winnable) { return false; } @Override - public boolean flipCoin(Game game, ArrayList appliedEffects) { + public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList appliedEffects) { return false; } @@ -1083,7 +1092,7 @@ public class PlayerStub implements Player { } @Override - public boolean lookAtFaceDownCard(Card card, Game game) { + public boolean lookAtFaceDownCard(Card card, Game game, int abilitiesToActivate) { return false; } diff --git a/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java new file mode 100644 index 0000000000..13d6915f92 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/testapi/TestAliases.java @@ -0,0 +1,128 @@ +package org.mage.test.testapi; + +import mage.constants.EmptyNames; +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.util.CardUtil; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author JayDi85 + */ + +public class TestAliases extends CardTestPlayerBase { + + @Test + public void test_NamesEquals() { + // empty names for face down cards + Assert.assertTrue(CardUtil.haveEmptyName("")); + Assert.assertTrue(CardUtil.haveEmptyName(EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveEmptyName(" ")); + Assert.assertFalse(CardUtil.haveEmptyName("123")); + Assert.assertFalse(CardUtil.haveEmptyName("Sample Name")); + + // same names (empty names can't be same) + Assert.assertFalse(CardUtil.haveSameNames("", "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), "")); + Assert.assertFalse(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_TOKEN.toString(), EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertTrue(CardUtil.haveSameNames("Name", "Name")); + Assert.assertFalse(CardUtil.haveSameNames("Name", "")); + Assert.assertFalse(CardUtil.haveSameNames("Name", " ")); + Assert.assertFalse(CardUtil.haveSameNames("Name", "123")); + Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString())); + Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2")); + + // ignore mtg rules (empty names must be same) + Assert.assertTrue(CardUtil.haveSameNames("", "", true)); + Assert.assertTrue(CardUtil.haveSameNames(EmptyNames.FACE_DOWN_CREATURE.toString(), EmptyNames.FACE_DOWN_CREATURE.toString(), true)); + Assert.assertTrue(CardUtil.haveSameNames("Name", "Name", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", "", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", " ", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", "123", true)); + Assert.assertFalse(CardUtil.haveSameNames("Name", EmptyNames.FACE_DOWN_CREATURE.toString(), true)); + Assert.assertFalse(CardUtil.haveSameNames("Name1", "Name2", true)); + } + + @Test + public void test_DifferentZones() { + addCard(Zone.LIBRARY, playerA, "Swamp@lib", 1); + addCard(Zone.HAND, playerA, "Swamp@hand", 1); + addCard(Zone.BATTLEFIELD, playerA, "Swamp@battle", 1); + addCard(Zone.GRAVEYARD, playerA, "Swamp@grave", 1); + + showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA); + checkAliasZone("lib", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "lib", Zone.LIBRARY); + checkAliasZone("hand", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "hand", Zone.HAND); + checkAliasZone("battle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "battle", Zone.BATTLEFIELD); + checkAliasZone("grave", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "grave", Zone.GRAVEYARD); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_MultipleNames() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5); + addCard(Zone.BATTLEFIELD, playerA, "Island@isl", 5); + addCard(Zone.BATTLEFIELD, playerB, "Plains", 5); + addCard(Zone.BATTLEFIELD, playerB, "Mountain@mnt", 5); + + checkPermanentCount("Swamp must exists", 1, PhaseStep.UPKEEP, playerA, "Swamp", 5); + checkPermanentCount("Island must exists", 1, PhaseStep.UPKEEP, playerA, "Island", 5); + checkPermanentCount("Plains must exists", 1, PhaseStep.UPKEEP, playerB, "Plains", 5); + checkPermanentCount("Mountain must exists", 1, PhaseStep.UPKEEP, playerB, "Mountain", 5); + // + showAliases("A aliases", 1, PhaseStep.UPKEEP, playerA); + showAliases("B aliases", 1, PhaseStep.UPKEEP, playerB); + // A + checkAliasZone("Swamp must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp", Zone.BATTLEFIELD, false); + checkAliasZone("Swamp.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swamp.1", Zone.BATTLEFIELD, false); + checkAliasZone("Island must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Island", Zone.BATTLEFIELD, false); + checkAliasZone("isl must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl", Zone.BATTLEFIELD, false); + checkAliasZone("isl.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.1", Zone.BATTLEFIELD, true); + checkAliasZone("isl.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.2", Zone.BATTLEFIELD, true); + checkAliasZone("isl.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "isl.5", Zone.BATTLEFIELD, true); + // B + checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains", Zone.BATTLEFIELD, false); + checkAliasZone("Plains.1 must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "Plains.1", Zone.BATTLEFIELD, false); + checkAliasZone("Plains must not", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains", Zone.BATTLEFIELD, false); + checkAliasZone("mnt must not", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt", Zone.BATTLEFIELD, false); + checkAliasZone("mnt.1 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.1", Zone.BATTLEFIELD, true); + checkAliasZone("mnt.2 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.2", Zone.BATTLEFIELD, true); + checkAliasZone("mnt.5 must", 1, PhaseStep.PRECOMBAT_MAIN, playerB, "mnt.5", Zone.BATTLEFIELD, true); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + } + + @Test + public void test_CastTarget() { + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion@lion", 5); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 5); + addCard(Zone.HAND, playerA, "Lightning Bolt", 3); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.1"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.3"); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "@lion.5"); + + showAliases("A aliases", 1, PhaseStep.POSTCOMBAT_MAIN, playerA); + checkAliasZone("1", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.1", Zone.BATTLEFIELD, false); + checkAliasZone("2", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.2", Zone.BATTLEFIELD, true); + checkAliasZone("3", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.3", Zone.BATTLEFIELD, false); + checkAliasZone("4", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.4", Zone.BATTLEFIELD, true); + checkAliasZone("5", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "lion.5", Zone.BATTLEFIELD, false); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + assertAllCommandsUsed(); + + assertGraveyardCount(playerA, "Lightning Bolt", 3); + assertGraveyardCount(playerA, "Silvercoat Lion", 3); + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java index 2f7cf07672..8abdc5abc3 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DeckBuilderTest.java @@ -28,7 +28,7 @@ public class DeckBuilderTest { public void testAllArtifacts() { final List spellCardPool = new ArrayList<>(); final UUID owner = UUID.randomUUID(); - final List allowedColors = Arrays.asList(ColoredManaSymbol.U); + final List allowedColors = new ArrayList<>(Arrays.asList(ColoredManaSymbol.U)); final List setsToUse = new ArrayList<>(); final List landCardPool = null; final RateCallback rateCallback = new RateCallback() { diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java new file mode 100644 index 0000000000..0df089ff4f --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/utils/DeckTestUtils.java @@ -0,0 +1,65 @@ +package org.mage.test.utils; + +import mage.cards.Card; +import mage.cards.Sets; +import mage.cards.decks.Deck; +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.constants.ColoredManaSymbol; +import mage.player.ai.ComputerPlayer; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author JayDi85 + */ +public class DeckTestUtils { + + private static final int DECK_SIZE = 40; + + public static Deck buildRandomDeck(String colors, boolean onlyBasicLands) { + return buildRandomDeck(colors, onlyBasicLands, ""); + } + + public static Deck buildRandomDeck(String colors, boolean onlyBasicLands, String allowedSets) { + + List allowedColors = new ArrayList<>(); + for (int i = 0; i < colors.length(); i++) { + char c = colors.charAt(i); + allowedColors.add(ColoredManaSymbol.lookup(c)); + } + + List allowedList = new ArrayList<>(); + if (allowedSets != null && !allowedSets.isEmpty()) { + String[] codes = allowedSets.split(","); + for (String code : codes) { + if (!code.trim().isEmpty()) { + allowedList.add(code.trim()); + } + } + } + + List cardPool = Sets.generateRandomCardPool(45, allowedColors, onlyBasicLands, allowedList); + return ComputerPlayer.buildDeck(DECK_SIZE, cardPool, allowedColors, onlyBasicLands); + } + + public static DeckCardLists buildRandomDeckAndInitCards(String colors, boolean onlyBasicLands) { + return buildRandomDeckAndInitCards(colors, onlyBasicLands, ""); + } + + public static DeckCardLists buildRandomDeckAndInitCards(String colors, boolean onlyBasicLands, String allowedSets) { + Deck deck = buildRandomDeck(colors, onlyBasicLands, allowedSets); + + DeckCardLists deckList = new DeckCardLists(); + for (Card card : deck.getCards()) { + CardInfo cardInfo = CardRepository.instance.findCard(card.getExpansionSetCode(), card.getCardNumber()); + if (cardInfo != null) { + deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); + } + } + return deckList; + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/ExportJsonGameplayDataTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/ExportJsonGameplayDataTest.java new file mode 100644 index 0000000000..67ef4b6431 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/utils/ExportJsonGameplayDataTest.java @@ -0,0 +1,141 @@ +package org.mage.test.utils; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.Effect; +import mage.cards.*; +import mage.target.Target; +import org.apache.log4j.Logger; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author JayDi85 & ZeldaZach + */ +public class ExportJsonGameplayDataTest { + + private static final Logger logger = Logger.getLogger(ExportJsonGameplayDataTest.class); + private static final boolean MTGJSON_WRITE_TO_FILES = false; + + @Test + @Ignore + /** + * It's export code example for https://github.com/mtgjson/mtgjson4 + */ + public void exportTest() { + List cards = new ArrayList<>(); + Collection sets = Sets.getInstance().values(); + for (ExpansionSet set : sets) { + for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { + cards.add(CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), + setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()))); + } + + JsonObject res = new JsonObject(); + + for (Card card : cards) { + try { + JsonObject resCard = new JsonObject(); + res.add(card.getName(), resCard); + + JsonArray resAbilities = new JsonArray(); + resCard.add("abilities", resAbilities); + for (Ability ability : card.getAbilities()) { + JsonObject resAbility = new JsonObject(); + resAbilities.add(resAbility); + + // basic + resAbility.addProperty("cost", ability.getManaCosts().getText()); + resAbility.addProperty("name", ability.toString()); + resAbility.addProperty("class", ability.getClass().getSimpleName()); + //resAbility.addProperty("rule", ability.getRule()); + + // modes + JsonArray resModes = new JsonArray(); + resAbility.add("modes", resModes); + for (Mode mode : ability.getModes().values()) { + JsonObject resMode = new JsonObject(); + resModes.add(resMode); + + // basic + //resMode.addProperty("name", mode.toString()); + + // effects + JsonArray resEffects = new JsonArray(); + resMode.add("effects", resEffects); + for (Effect effect : mode.getEffects()) { + JsonObject resEffect = new JsonObject(); + resEffects.add(resEffect); + + resEffect.addProperty("class", effect.getClass().getSimpleName()); + resEffect.addProperty("outcome", effect.getOutcome().toString()); + resEffect.addProperty("text", effect.getText(mode)); + } + if (resEffects.size() == 0) { + resMode.remove("effects"); + } + + // targets + JsonArray resTargets = new JsonArray(); + resMode.add("targets", resTargets); + for (Target target : mode.getTargets()) { + JsonObject resTarget = new JsonObject(); + resTargets.add(resTarget); + + resTarget.addProperty("name", target.getTargetName()); + resTarget.addProperty("class", target.getClass().getSimpleName()); + resTarget.addProperty("min", target.getMinNumberOfTargets()); + resTarget.addProperty("max", target.getMaxNumberOfTargets()); + } + if (resTargets.size() == 0) { + resMode.remove("targets"); + } + + if (resMode.get("effects") == null && resMode.get("targets") == null) { + resModes.remove(resMode); + } + } + if (resModes.size() == 0) { + resAbility.remove("modes"); + } + } + } catch (Throwable e) { + logger.error("Inner error for " + card.getName() + ": " + e.getMessage(), e); + break; + } + } + + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + + if (MTGJSON_WRITE_TO_FILES) { + String filePath = System.getProperty("user.dir") + "/json/" + set.getCode() + ".json"; + File outputFile = new File(filePath); + final boolean mkdirs = outputFile.getParentFile().mkdirs(); + try (Writer writer = + new BufferedWriter( + new OutputStreamWriter( + new FileOutputStream(outputFile, false), StandardCharsets.UTF_8 + ) + ) + ) { + writer.write(gson.toJson(res)); + System.out.println("Wrote " + set.getCode() + " to file"); + } catch (Exception e) { + e.printStackTrace(); + } + } else { + //System.out.println(gson.toJson(res)); + } + } + } +} \ No newline at end of file diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTestUtils.java b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTestUtils.java index 04d0e8ccea..37914e1042 100644 --- a/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTestUtils.java +++ b/Mage.Tests/src/test/java/org/mage/test/utils/ManaOptionsTestUtils.java @@ -39,7 +39,7 @@ public class ManaOptionsTestUtils { for(Mana mana: manaList){ String s = mana.toString(); if(list.contains(s)){ - Assert.fail("Founded duplicated mana option " + s + " in " + manaList.toString()); + Assert.fail("Found duplicated mana option " + s + " in " + manaList.toString()); }else{ list.add(s); } diff --git a/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java new file mode 100644 index 0000000000..6667339b6a --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/utils/RandomTest.java @@ -0,0 +1,169 @@ +package org.mage.test.utils; + +import mage.cards.decks.Deck; +import mage.cards.decks.DeckCardLists; +import mage.constants.MultiplayerAttackOption; +import mage.constants.PlanarDieRoll; +import mage.constants.RangeOfInfluence; +import mage.game.Game; +import mage.game.TwoPlayerDuel; +import mage.game.mulligan.VancouverMulligan; +import mage.player.human.HumanPlayer; +import mage.players.Player; +import mage.util.RandomUtil; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author JayDi85 + */ +public class RandomTest { + + @Test + public void test_SeedAndSameResults() { + RandomUtil.setSeed(123); + List listSameA = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listSameA.add(RandomUtil.nextInt()); + } + + RandomUtil.setSeed(321); + List listDifferent = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listDifferent.add(RandomUtil.nextInt()); + } + + RandomUtil.setSeed(123); + List listSameB = new ArrayList<>(); + for (int i = 1; i <= 10; i++) { + listSameB.add(RandomUtil.nextInt()); + } + + Assert.assertEquals("same seed must have same random values", listSameA.stream().mapToInt(Integer::intValue).sum(), listSameB.stream().mapToInt(Integer::intValue).sum()); + Assert.assertNotEquals("different seed must have different random values", listSameA.stream().mapToInt(Integer::intValue).sum(), listDifferent.stream().mapToInt(Integer::intValue).sum()); + } + + @Test + public void test_SeedAndSameRandomDecks() { + RandomUtil.setSeed(123); + DeckCardLists listSameA = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoSameA = listSameA.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + RandomUtil.setSeed(321); + DeckCardLists listDifferent = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoDifferent = listDifferent.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + RandomUtil.setSeed(123); + DeckCardLists listSameB = DeckTestUtils.buildRandomDeckAndInitCards("WGUBR", false, "GRN"); + String infoSameB = listSameB.getCards().stream().map(c -> (c.getSetCode() + "-" + c.getCardName())).collect(Collectors.joining(",")); + + Assert.assertEquals("same seed must have same deck", infoSameA, infoSameB); + Assert.assertNotEquals("different seed must have different deck", infoSameA, infoDifferent); + } + + @Test + @Ignore + public void test_GenerateRandomPng() throws IOException { + String dest = "f:/test/xmage/"; + int height = 512; + int weight = 512; + BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < weight; x++) { + for (int y = 0; y < height; y++) { + image.setRGB(x, y, RandomUtil.nextBoolean() ? Color.white.getRGB() : Color.black.getRGB()); + } + } + ImageIO.write(image, "png", new File(dest + "xmage_random.png")); + } + + @Test + @Ignore + public void test_GenerateRandomDicePng() throws IOException { + String dest = "f:/test/xmage/"; + //RandomUtil.setSeed(123); + Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 50); + + int height = 512; + int weight = 512; + BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < weight; x++) { + for (int y = 0; y < height; y++) { + // roll dice + int diceVal = player.rollDice(game, 12); + int colorMult = Math.floorDiv(255, 12); + + image.setRGB(x, y, new Color(colorMult * diceVal, colorMult * diceVal, colorMult * diceVal).getRGB()); + } + } + ImageIO.write(image, "png", new File(dest + "xmage_random_dice.png")); + } + + @Test + @Ignore + public void test_GenerateRandomPlanarDicePng() throws IOException { + String dest = "f:/test/xmage/"; + //RandomUtil.setSeed(123); + Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 50); + + int height = 512; + int weight = 512; + BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < weight; x++) { + for (int y = 0; y < height; y++) { + // roll planar dice + PlanarDieRoll res = player.rollPlanarDie(game); + image.setRGB(x, y, new Color( + res.equals(PlanarDieRoll.CHAOS_ROLL) ? 255 : 0, + res.equals(PlanarDieRoll.PLANAR_ROLL) ? 255 : 0, + res.equals(PlanarDieRoll.NIL_ROLL) ? 255 : 0 + ).getRGB()); + } + } + ImageIO.write(image, "png", new File(dest + "xmage_random_planar_dice.png")); + } + + @Test + @Ignore + public void test_GenerateRandomLibraryShufflePng() throws IOException { + String dest = "f:/test/xmage/"; + //RandomUtil.setSeed(123); + Player player = new HumanPlayer("random", RangeOfInfluence.ALL, 1); + Game game = new TwoPlayerDuel(MultiplayerAttackOption.MULTIPLE, RangeOfInfluence.ALL, new VancouverMulligan(0), 50); + Deck deck = DeckTestUtils.buildRandomDeck("WGUBR", false, "GRN"); + player.getLibrary().addAll(deck.getCards(), game); + + // multiple cards analyze + for (int i = 0; i < player.getLibrary().size(); i++) { + UUID cardId = player.getLibrary().getCardList().get(i); + //int halfIndex = Math.floorDiv(player.getLibrary().size(), 2); + int colorMult = Math.floorDiv(255, player.getLibrary().size()); + + int height = 512; + int weight = 512; + BufferedImage image = new BufferedImage(weight, height, BufferedImage.TYPE_INT_RGB); + for (int x = 0; x < weight; x++) { + for (int y = 0; y < height; y++) { + // shuffle, search card position and draw + player.getLibrary().shuffle(); + int cardPos = player.getLibrary().getCardPosition(cardId); + //image.setRGB(x, y, cardPos < halfIndex ? Color.white.getRGB() : Color.black.getRGB()); + image.setRGB(x, y, new Color(colorMult * cardPos, colorMult * cardPos, colorMult * cardPos).getRGB()); + } + } + ImageIO.write(image, "png", new File(dest + "xmage_random_shuffle_" + i + ".png")); + } + } +} diff --git a/Mage.Updater/pom.xml b/Mage.Updater/pom.xml index c9ab517c29..b92840266b 100644 --- a/Mage.Updater/pom.xml +++ b/Mage.Updater/pom.xml @@ -5,11 +5,10 @@ mage-root org.mage - 1.4.31 + 1.4.35 4.0.0 - org.mage mage-updater Mage Updater diff --git a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java index d23c0bdf4c..6ca8233d86 100644 --- a/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java +++ b/Mage.Updater/src/main/java/com/magefree/update/helpers/FileHelper.java @@ -68,8 +68,9 @@ public final class FileHelper { for (String filename : files) { File f = new File(filename); if (f.exists()) { - f.delete(); - System.out.println("File has been deleted: " + filename); + if(f.delete()) { + System.out.println("File has been deleted: " + filename); + } } else { System.out.println("ERROR. Couldn't find file to delete: " + filename); } @@ -84,17 +85,14 @@ public final class FileHelper { */ public static void downloadFile(String filename, HttpURLConnection urlConnection) { System.out.println("Downloading " + filename); - InputStream in = null; - FileOutputStream out = null; - try { - in = urlConnection.getInputStream(); + try (InputStream in = urlConnection.getInputStream() ; FileOutputStream out = new FileOutputStream(filename)){ File f = new File(filename); if (!f.exists() && f.getParentFile() != null) { - f.getParentFile().mkdirs(); - System.out.println("Directories have been created: " + f.getParentFile().getPath()); + if(f.getParentFile().mkdirs()) { + System.out.println("Directories have been created: " + f.getParentFile().getPath()); + } } - out = new FileOutputStream(filename); byte[] buf = new byte[4 * 1024]; int bytesRead; @@ -105,19 +103,6 @@ public final class FileHelper { System.out.println("File has been updated: " + filename); } catch (IOException e) { System.out.println("i/o exception - " + e.getMessage()); - } finally { - closeQuietly(in); - closeQuietly(out); - } - } - - public static void closeQuietly(Closeable s) { - if(s != null) { - try { - s.close(); - } catch (Exception e) { - System.out.println("i/o exception - " + e.getMessage()); - } } } } diff --git a/Mage.Verify/pom.xml b/Mage.Verify/pom.xml index 90c41da866..c975c7ee0c 100644 --- a/Mage.Verify/pom.xml +++ b/Mage.Verify/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage-verify @@ -32,7 +32,7 @@ com.fasterxml.jackson.core jackson-databind - 2.6.3 + 2.9.8 @@ -49,7 +49,7 @@ org.mage mage-client - 1.4.31 + 1.4.35 @@ -67,7 +67,7 @@ org.apache.maven.plugins maven-compiler-plugin - diff --git a/Mage.Verify/src/main/java/mage/verify/JsonCard.java b/Mage.Verify/src/main/java/mage/verify/JsonCard.java index a17d1a7b6b..bb85a00e7d 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonCard.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonCard.java @@ -1,40 +1,58 @@ package mage.verify; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import java.util.List; -class JsonCard { - public String layout; - public String name; - public List names; // flip cards - public String manaCost; - public int cmc; - public List colors; - public List colorIdentity; - public String type; - public List supertypes; - public List types; - public List subtypes; - public String text; - public String power; - public String toughness; - public String loyalty; - public String imageName; - public boolean starter; // only available in boxed sets and not in boosters - public int hand; // vanguard - public int life; // vanguard +import static mage.verify.MtgJson.MTGJSON_IGNORE_NEW_PROPERTIES; + +@JsonIgnoreProperties(ignoreUnknown = MTGJSON_IGNORE_NEW_PROPERTIES) +class JsonCard { + // docs: https://mtgjson.com/v4/docs.html - // only available in AllSets.json public String artist; - public String flavor; - public String id; - public int multiverseid; - public String rarity; - public boolean reserved; - public int[] variations; + public String borderColor; + public List colorIdentity; + public List colorIndicator; + public List colors; + public float convertedManaCost; + public float faceConvertedManaCost; + public String flavorText; + public List foreignData; + public String frameVersion; + public boolean hasFoil; + public boolean hasNonFoil; + public boolean isOnlineOnly; + public boolean isOversized; + public boolean isReserved; + public boolean isTimeshifted; + public String layout; + public JsonLegalities legalities; + public String loyalty; + public String manaCost; + public int multiverseId; + public String name; + public List names; public String number; - public String mciNumber; - public String releaseDate; // promos - public String border; + public String originalText; + public String originalType; + public List printings; + public String power; + public String rarity; + public boolean starter; + public String side; + public List rulings; + public List subtypes; + public List supertypes; + public String text; + public String toughness; + public String type; + public List types; + public String uuid; + public List variations; public String watermark; - public boolean timeshifted; + public String tcgplayerProductId; + public String scryfallId; + public boolean isAlternative; + public String frameEffect; } diff --git a/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java b/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java new file mode 100644 index 0000000000..5c85acd664 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonForeignData.java @@ -0,0 +1,15 @@ +package mage.verify; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import static mage.verify.MtgJson.MTGJSON_IGNORE_NEW_PROPERTIES; + +@JsonIgnoreProperties(ignoreUnknown = MTGJSON_IGNORE_NEW_PROPERTIES) +public class JsonForeignData { + public String flavorText; + public String language; + public int multiverseId; + public String name; + public String text; + public String type; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java b/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java new file mode 100644 index 0000000000..b57dd050df --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonLegalities.java @@ -0,0 +1,20 @@ +package mage.verify; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class JsonLegalities { + @JsonProperty("1v1") + public String oneVersusOne; + public String brawl; + public String commander; + public String duel; + public String frontier; + public String future; + public String legacy; + public String modern; + public String penny; + public String pauper; + public String standard; + public String vintage; + public String oldschool; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonMeta.java b/Mage.Verify/src/main/java/mage/verify/JsonMeta.java new file mode 100644 index 0000000000..4d68703479 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonMeta.java @@ -0,0 +1,6 @@ +package mage.verify; + +public class JsonMeta { + public String date; + public String version; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonRuling.java b/Mage.Verify/src/main/java/mage/verify/JsonRuling.java new file mode 100644 index 0000000000..1576700d58 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonRuling.java @@ -0,0 +1,6 @@ +package mage.verify; + +public class JsonRuling { + public String date; + public String text; +} diff --git a/Mage.Verify/src/main/java/mage/verify/JsonSet.java b/Mage.Verify/src/main/java/mage/verify/JsonSet.java index 831721937f..d53d310d04 100644 --- a/Mage.Verify/src/main/java/mage/verify/JsonSet.java +++ b/Mage.Verify/src/main/java/mage/verify/JsonSet.java @@ -1,24 +1,26 @@ package mage.verify; -import java.util.List; -import java.util.Map; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import java.util.List; + +import static mage.verify.MtgJson.MTGJSON_IGNORE_NEW_PROPERTIES; + +@JsonIgnoreProperties(ignoreUnknown = MTGJSON_IGNORE_NEW_PROPERTIES) class JsonSet { - public String name; - public String code; - public String oldCode; - public String gathererCode; - public String magicCardsInfoCode; - public String[] magicRaritiesCodes; - public String[] alternativeNames; - public String releaseDate; - public String border; - public String type; - public List booster; // [String|[String]] - public List cards; + public int baseSetSize; public String block; - public boolean onlineOnly; - public String mkm_id; - public String mkm_name; - public Map translations; + public List boosterV3; // [["rare", "mythic rare"], "uncommon", "uncommon", "uncommon", "common"] + public List cards; + public String code; + public boolean isFoilOnly; + public boolean isOnlineOnly; + public JsonMeta meta; + public String mtgoCode; + public String name; + public String releaseDate; + public List tokens; + public int totalSetSize; + public String type; + public String tcgplayerGroupId; } diff --git a/Mage.Verify/src/main/java/mage/verify/JsonToken.java b/Mage.Verify/src/main/java/mage/verify/JsonToken.java new file mode 100644 index 0000000000..c348485689 --- /dev/null +++ b/Mage.Verify/src/main/java/mage/verify/JsonToken.java @@ -0,0 +1,29 @@ +package mage.verify; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +import java.util.List; + +import static mage.verify.MtgJson.MTGJSON_IGNORE_NEW_PROPERTIES; + +@JsonIgnoreProperties(ignoreUnknown = MTGJSON_IGNORE_NEW_PROPERTIES) +public class JsonToken { + public String artist; + public String borderColor; + public List colorIdentity; + public List colorIndicator; + public List colors; + public String loyalty; + public String name; + public String number; + public String power; + public List reverseRelated; + public String side; + public String text; + public String toughness; + public String type; + public String uuid; + public String watermark; + public boolean isOnlineOnly; + public String scryfallId; +} diff --git a/Mage.Verify/src/main/java/mage/verify/MtgJson.java b/Mage.Verify/src/main/java/mage/verify/MtgJson.java index 1919f8db0f..e6de2c378e 100644 --- a/Mage.Verify/src/main/java/mage/verify/MtgJson.java +++ b/Mage.Verify/src/main/java/mage/verify/MtgJson.java @@ -2,17 +2,19 @@ package mage.verify; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; -import mage.util.StreamUtils; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; +import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.text.Normalizer; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.zip.ZipInputStream; @@ -21,6 +23,8 @@ public final class MtgJson { public static Map mtgJsonToXMageCodes = new HashMap<>(); public static Map xMageToMtgJsonCodes = new HashMap<>(); + public static final boolean MTGJSON_IGNORE_NEW_PROPERTIES = true; // set it to false for full mtgjson checks and research (new fields finds or mtgjson updates) + static { mtgJsonToXMageCodes.put("pWCQ", "WMCQ"); mtgJsonToXMageCodes.put("pSUS", "SUS"); @@ -61,6 +65,29 @@ public final class MtgJson { static { try { cards = loadAllCards(); + + List keysToDelete = new ArrayList<>(); + + // fix names + Map newKeys = new HashMap<>(); + for (String key : cards.keySet()) { + if (key.contains("(")) { + newKeys.put(key.replaceAll("\\(.*\\)", "").trim(), cards.get(key)); + keysToDelete.add(key); + } + } + cards.putAll(newKeys); + cards.keySet().removeAll(keysToDelete); + + // remove wrong data (tokens) + keysToDelete.clear(); + for (Map.Entry record : cards.entrySet()) { + if (record.getValue().layout.equals("token") || record.getValue().layout.equals("double_faced_token")) { + keysToDelete.add(record.getKey()); + } + } + cards.keySet().removeAll(keysToDelete); + addAliases(cards); } catch (IOException e) { throw new RuntimeException(e); @@ -95,7 +122,9 @@ public final class MtgJson { if (stream == null) { File file = new File(filename); if (!file.exists()) { - InputStream download = new URL("http://mtgjson.com/json/" + filename).openStream(); + URLConnection connection = new URL("https://mtgjson.com/json/" + filename).openConnection(); + connection.setRequestProperty("user-agent", "xmage"); + InputStream download = connection.getInputStream(); Files.copy(download, file.toPath(), StandardCopyOption.REPLACE_EXISTING); System.out.println("Downloaded " + filename + " to " + file.getAbsolutePath()); } else { @@ -103,14 +132,9 @@ public final class MtgJson { } stream = new FileInputStream(file); } - ZipInputStream zipInputStream = null; - try { - zipInputStream = new ZipInputStream(stream); + try (ZipInputStream zipInputStream = new ZipInputStream(stream)) { zipInputStream.getNextEntry(); return new ObjectMapper().readValue(zipInputStream, ref); - } finally { - StreamUtils.closeQuietly(zipInputStream); - StreamUtils.closeQuietly(stream); } } @@ -133,6 +157,7 @@ public final class MtgJson { name = name.replace("'", "\""); // for Kongming, "Sleeping Dragon" & Pang Tong, "Young Phoenix" ref = reference.get(name); } + return ref; } diff --git a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java index 34869ff85b..36ce86fb2d 100644 --- a/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java +++ b/Mage.Verify/src/test/java/mage/verify/VerifyCardDataTest.java @@ -1,25 +1,31 @@ package mage.verify; import mage.ObjectColor; +import mage.abilities.keyword.MultikickerAbility; import mage.cards.*; import mage.cards.basiclands.BasicLand; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; +import mage.cards.repository.CardScanner; import mage.constants.CardType; -import mage.constants.Constants; import mage.constants.Rarity; +import mage.constants.SubType; import mage.constants.SuperType; +import mage.game.draft.RateCard; import mage.game.permanent.token.Token; import mage.game.permanent.token.TokenImpl; -import mage.util.CardUtil; +import mage.watchers.Watcher; import org.junit.Assert; import org.junit.Ignore; import org.junit.Test; import org.mage.plugins.card.images.CardDownloadData; -import org.mage.plugins.card.images.DownloadPictures; +import org.mage.plugins.card.images.DownloadPicturesService; import org.reflections.Reflections; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -59,21 +65,30 @@ public class VerifyCardDataTest { skipListCreate("PT"); skipListAddName("PT", "UST", "Garbage Elemental"); skipListAddName("PT", "UST", "Infinity Elemental"); + skipListAddName("PT", "UNH", "Old Fogey"); // color skipListCreate("COLOR"); // cost skipListCreate("COST"); + skipListAddName("COST", "KTK", "Erase"); + skipListAddName("COST", "M13", "Erase"); + skipListAddName("COST", "ULG", "Erase"); + skipListAddName("COST", "H17", "Grimlock, Dinobot Leader"); + skipListAddName("COST", "UST", "Everythingamajig"); // supertype skipListCreate("SUPERTYPE"); // type skipListCreate("TYPE"); + skipListAddName("TYPE", "UNH", "Old Fogey"); + skipListAddName("TYPE", "UST", "capital offense"); // subtype skipListCreate("SUBTYPE"); + skipListAddName("SUBTYPE", "UGL", "Miss Demeanor"); // number skipListCreate("NUMBER"); @@ -82,21 +97,6 @@ public class VerifyCardDataTest { skipListCreate("MISSING_ABILITIES"); } - public static List allCards() { - Collection sets = Sets.getInstance().values(); - List cards = new ArrayList<>(); - for (ExpansionSet set : sets) { - if (set.isCustomSet()) { - continue; - } - for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { - cards.add(CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), - setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()))); - } - } - return cards; - } - private void warn(Card card, String message) { outputMessages.add("Warning: " + message + " for " + card.getExpansionSetCode() + " - " + card.getName() + " - " + card.getCardNumber()); } @@ -107,11 +107,11 @@ public class VerifyCardDataTest { } private int failed = 0; - private ArrayList outputMessages = new ArrayList<>(); + private final ArrayList outputMessages = new ArrayList<>(); @Test public void verifyCards() throws IOException { - for (Card card : allCards()) { + for (Card card : CardScanner.getAllCards()) { Set tokens = findSourceTokens(card.getClass()); if (card.isSplitCard()) { check(((SplitCard) card).getLeftHalfCard(), null); @@ -149,11 +149,11 @@ public class VerifyCardDataTest { String errorType; if (checkCard.getName().equals(prevCard.getName())) { - errorType = " founded DUPLICATED cards" + errorType = " found DUPLICATED cards" + " set (" + set.getCode() + " - " + set.getName() + ")" + " (" + checkCard.getCardNumber() + " - " + checkCard.getName() + ")"; } else { - errorType = " founded TYPOS in card numbers" + errorType = " found TYPOS in card numbers" + " set (" + set.getCode() + " - " + set.getName() + ")" + " (" + prevCard.getCardNumber() + " - " + prevCard.getName() + ")" + " and" @@ -174,7 +174,7 @@ public class VerifyCardDataTest { } if (doubleErrors.size() > 0) { - Assert.fail("DB have duplicated card numbers, founded errors: " + doubleErrors.size()); + Assert.fail("DB has duplicated card numbers, found errors: " + doubleErrors.size()); } } @@ -193,9 +193,12 @@ public class VerifyCardDataTest { if (classesIndex.containsKey(checkCard.getName())) { String needClass = classesIndex.get(checkCard.getName()); if (!needClass.equals(currentClass)) { - // workaround to star wars set with same card names - if (!checkCard.getName().equals("Syndicate Enforcer")) { - errorsList.add("Error: founded wrong class in set " + set.getCode() + " - " + checkCard.getName() + " (" + currentClass + " <> " + needClass + ")"); + // workaround to star wars and unstable set with same card names + if (!checkCard.getName().equals("Syndicate Enforcer") + && !checkCard.getName().equals("Everythingamajig") + && !checkCard.getName().equals("Garbage Elemental") + && !checkCard.getName().equals("Very Cryptic Command")) { + errorsList.add("Error: found wrong class in set " + set.getCode() + " - " + checkCard.getName() + " (" + currentClass + " <> " + needClass + ")"); } } } else { @@ -212,7 +215,7 @@ public class VerifyCardDataTest { System.out.println("Total unique cards: " + classesIndex.size() + ", total non unique cards (reprints): " + totalCards); if (errorsList.size() > 0) { - Assert.fail("DB have wrong card classes, founded errors: " + errorsList.size()); + Assert.fail("DB has wrong card classes, found errors: " + errorsList.size()); } } @@ -230,7 +233,7 @@ public class VerifyCardDataTest { // replace codes for aliases String searchSet = MtgJson.mtgJsonToXMageCodes.getOrDefault(refSet.code, refSet.code); - ExpansionSet mageSet = Sets.findSet(searchSet); + ExpansionSet mageSet = Sets.findSet(searchSet.toUpperCase()); if (mageSet == null) { totalMissingSets = totalMissingSets + 1; totalMissingCards = totalMissingCards + refSet.cards.size(); @@ -352,11 +355,10 @@ public class VerifyCardDataTest { } // TODO: add test to check num cards for rarity (rarityStats > 0 and numRarity > 0) - printMessages(warningsList); printMessages(errorsList); if (errorsList.size() > 0) { - Assert.fail("Founded set errors: " + errorsList.size()); + Assert.fail("Found set errors: " + errorsList.size()); } } @@ -367,7 +369,6 @@ public class VerifyCardDataTest { Collection sets = Sets.getInstance().values(); - // 1. wrong UsesVariousArt settings (set have duplicated card name without that setting -- e.g. cards will have same image) for (ExpansionSet set : sets) { @@ -381,18 +382,59 @@ public class VerifyCardDataTest { // check for (ExpansionSet.SetCardInfo card : set.getSetCardInfo()) { boolean cardHaveDoubleName = (doubleNames.getOrDefault(card.getName(), 0) > 1); - boolean cardHaveVariousSetting = card.getGraphicInfo() == null ? false : card.getGraphicInfo().getUsesVariousArt(); + boolean cardHaveVariousSetting = card.getGraphicInfo() != null && card.getGraphicInfo().getUsesVariousArt(); - if(cardHaveDoubleName && !cardHaveVariousSetting) { + if (cardHaveDoubleName && !cardHaveVariousSetting) { errorsList.add("error, founded double card names, but UsesVariousArt is not true: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); } } } + // 2. all planeswalkers must be legendary + for (ExpansionSet set : sets) { + for (ExpansionSet.SetCardInfo cardInfo : set.getSetCardInfo()) { + Card card = CardImpl.createCard(cardInfo.getCardClass(), new CardSetInfo(cardInfo.getName(), set.getCode(), + cardInfo.getCardNumber(), cardInfo.getRarity(), cardInfo.getGraphicInfo())); + Assert.assertNotNull(card); + + if (card.getCardType().contains(CardType.PLANESWALKER) && !card.getSuperType().contains(SuperType.LEGENDARY)) { + errorsList.add("error, planeswalker must have legendary type: " + set.getCode() + " - " + set.getName() + " - " + card.getName() + " - " + card.getCardNumber()); + } + } + } + printMessages(warningsList); printMessages(errorsList); if (errorsList.size() > 0) { - Assert.fail("Founded card errors: " + errorsList.size()); + Assert.fail("Found card errors: " + errorsList.size()); + } + } + + @Test + @Ignore // TODO: enable it on copy() methods removing + public void checkWatcherCopyMethods() { + + Collection errorsList = new ArrayList<>(); + Collection warningsList = new ArrayList<>(); + + Reflections reflections = new Reflections("mage."); + Set> watcherClassesList = reflections.getSubTypesOf(Watcher.class); + + for (Class watcherClass : watcherClassesList) { + try { + Method m = watcherClass.getMethod("copy"); + if (!m.getGenericReturnType().getTypeName().equals("T")) { + errorsList.add("error, copy() method must be deleted from watcher class: " + watcherClass.getName()); + } + } catch (NoSuchMethodException e) { + errorsList.add("error, can't find copy() method in watcher class: " + watcherClass.getName()); + } + } + + printMessages(warningsList); + printMessages(errorsList); + if (errorsList.size() > 0) { + Assert.fail("Found watcher errors: " + errorsList.size()); } } @@ -420,7 +462,7 @@ public class VerifyCardDataTest { } // tok file's data - ArrayList tokFileTokens = DownloadPictures.getTokenCardUrls(); + ArrayList tokFileTokens = DownloadPicturesService.getTokenCardUrls(); LinkedHashMap tokDataClassesIndex = new LinkedHashMap<>(); LinkedHashMap tokDataNamesIndex = new LinkedHashMap<>(); for (CardDownloadData tokData : tokFileTokens) { @@ -491,7 +533,7 @@ public class VerifyCardDataTest { printMessages(warningsList); printMessages(errorsList); if (errorsList.size() > 0) { - Assert.fail("Founded token errors: " + errorsList.size()); + Assert.fail("Found token errors: " + errorsList.size()); } } @@ -560,6 +602,7 @@ public class VerifyCardDataTest { //checkNumbers(card, ref); // TODO: load data from allsets.json and check it (allcards.json do not have card numbers) checkBasicLands(card, ref); checkMissingAbilities(card, ref); + checkWrongAbilitiesText(card, ref); } private void checkColors(Card card, JsonCard ref) { @@ -567,17 +610,22 @@ public class VerifyCardDataTest { return; } - Collection expected = ref.colors; - ObjectColor color = card.getColor(null); - if (expected == null) { - expected = Collections.emptyList(); + Set expected = new HashSet<>(); + if (ref.colors != null) { + expected.addAll(ref.colors); } + if (card.isFlipCard()) { + expected.addAll(ref.colorIdentity); + } + + ObjectColor color = card.getColor(null); + if (expected.size() != color.getColorCount() - || (color.isBlack() && !expected.contains("Black")) - || (color.isBlue() && !expected.contains("Blue")) - || (color.isGreen() && !expected.contains("Green")) - || (color.isRed() && !expected.contains("Red")) - || (color.isWhite() && !expected.contains("White"))) { + || (color.isBlack() && !expected.contains("B")) + || (color.isBlue() && !expected.contains("U")) + || (color.isGreen() && !expected.contains("G")) + || (color.isRed() && !expected.contains("R")) + || (color.isWhite() && !expected.contains("W"))) { fail(card, "colors", color + " != " + expected); } } @@ -599,7 +647,7 @@ public class VerifyCardDataTest { } } - if (!eqSet(card.getSubtype(null).stream().map(p -> p.toString()).collect(Collectors.toSet()), expected)) { + if (!eqSet(card.getSubtype(null).stream().map(SubType::toString).collect(Collectors.toSet()), expected)) { fail(card, "subtypes", card.getSubtype(null) + " != " + expected); } } @@ -625,7 +673,12 @@ public class VerifyCardDataTest { return; } - // spells have only 1 abilities + // special check: kicker ability must be in rules + if (card.getAbilities().containsClass(MultikickerAbility.class) && card.getRules().stream().noneMatch(rule -> rule.contains("Multikicker"))) { + fail(card, "abilities", "card have Multikicker ability, but missing it in rules text"); + } + + // spells have only 1 ability if (card.isSorcery() || card.isInstant()) { return; } @@ -641,6 +694,144 @@ public class VerifyCardDataTest { } } + private void checkLegalityFormats(Card card, JsonCard ref) { + if (skipListHaveName("LEGALITY", card.getExpansionSetCode(), card.getName())) { + return; + } + + // TODO: add legality checks (by sets and cards, by banned) + } + + private String prepareRule(String cardName, String rule) { + // remove and optimize rule text for analyze + String newRule = rule; + + // remove reminder text + newRule = newRule.replaceAll("(?i)\\(.+\\)", ""); + + // replace special text and symbols + newRule = newRule + .replace("{this}", cardName) + .replace("—", "—"); + + // remove html marks + newRule = newRule + .replace("", "") + .replace("", ""); + + return newRule; + } + + @Test + @Ignore + public void showCardInfo() throws Exception { + // debug only: show direct card info (takes it from class file, not from db repository) + String cardName = "Essence Capture"; + CardScanner.scan(); + CardSetInfo testSet = new CardSetInfo("test", "test", "123", Rarity.COMMON); + CardInfo cardInfo = CardRepository.instance.findCard(cardName); + Card card = CardImpl.createCard(cardInfo.getClassName(), testSet); + card.getRules().stream().forEach(System.out::println); + } + + private void checkWrongAbilitiesText(Card card, JsonCard ref) { + // checks missing or wrong text + if (!card.getExpansionSetCode().equals("WAR")) { + return; + } + + if (ref.text == null || ref.text.isEmpty()) { + return; + } + + String refText = ref.text; + // lands fix + if (refText.startsWith("(") && refText.endsWith(")")) { + refText = refText.substring(1, refText.length() - 1); + } + + String[] refRules = refText.split("[\\$\\\n]"); // ref card's abilities can be splited by \n or $ chars + for (int i = 0; i < refRules.length; i++) { + refRules[i] = prepareRule(card.getName(), refRules[i]); + } + + String[] cardRules = card.getRules().toArray(new String[0]); + for (int i = 0; i < cardRules.length; i++) { + cardRules[i] = prepareRule(card.getName(), cardRules[i]); + } + + for (String cardRule : cardRules) { + boolean isAbilityFounded = false; + for (String refRule : refRules) { + if (cardRule.equals(refRule)) { + isAbilityFounded = true; + break; + } + } + + if (!isAbilityFounded) { + warn(card, "card ability can't be found in ref [" + card.getName() + ": " + cardRule + "]"); + } + } + } + + + /* + for(String rule : card.getRules()) { + rule = rule.replaceAll("(?i).+", ""); // Ignoring reminder text in italic + // TODO: add Equip {3} checks + // TODO: add Raid and other words checks + String[] sl = rule.split(":"); + if (sl.length == 2 && !sl[0].isEmpty()) { + String cardCost = sl[0] + .replace("{this}", card.getName()) + //.replace("", "") + //.replace("", "") + .replace("—", "—"); + String cardAbility = sl[1] + .trim() + .replace("{this}", card.getName()) + //.replace("", "") + //.replace("", "") + .replace("—", "—");; + + boolean found = false; + for (String refRule : refRules) { + refRule = refRule.replaceAll("(?i).+", ""); // Ignoring reminder text in italic + + // fix for ref mana: ref card have xxx instead {T}: Add {xxx}, example: W + if (refRule.length() == 1) { + refRule = "{T}: Add {" + refRule + "}"; + } + refRule = refRule + .trim() + //.replace("", "") + //.replace("", "") + .replace("—", "—"); + + // normal + if (refRule.startsWith(cardCost)) { + found = true; + break; + } + + // ref card have (xxx) instead xxx, example: ({T}: Add {G}.) + // ref card have (xxx) instead xxx, example: ({T}: Add {G}.) + // TODO: delete? + if (refRule.startsWith("(" + cardCost)) { + found = true; + break; + } + } + if (!found) { + fail(card, "abilities", "card ability have cost, but can't find in ref [" + cardCost + ": " + cardAbility + "]"); + } + } + + } + }*/ + + private void checkTypes(Card card, JsonCard ref) { if (skipListHaveName("TYPE", card.getExpansionSetCode(), card.getName())) { return; @@ -690,7 +881,7 @@ public class VerifyCardDataTest { String expected = ref.manaCost; String cost = join(card.getManaCost().getSymbols()); - if (cost != null && cost.isEmpty()) { + if (cost.isEmpty()) { cost = null; } if (cost != null) { @@ -762,4 +953,22 @@ public class VerifyCardDataTest { return result.toString(); } + @Test + public void testCardRatingConsistency() { + // all cards with same name must have same rating (see RateCard.rateCard) + // cards rating must be consistency (same) for card sorting + List cardsList = new ArrayList<>(CardScanner.getAllCards()); + Map cardRates = new HashMap<>(); + for (Card card : cardsList) { + int curRate = RateCard.rateCard(card, null, false); + int prevRate = cardRates.getOrDefault(card.getName(), 0); + if (prevRate == 0) { + cardRates.putIfAbsent(card.getName(), curRate); + } else { + if (curRate != prevRate) { + Assert.fail("Card with same name have different ratings: " + card.getName()); + } + } + } + } } diff --git a/Mage/manifest.mf b/Mage/manifest.mf deleted file mode 100644 index 1574df4a2d..0000000000 --- a/Mage/manifest.mf +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -X-COMMENT: Main-Class will be added automatically by build - diff --git a/Mage/pom.xml b/Mage/pom.xml index d7881372f8..1b972e0326 100644 --- a/Mage/pom.xml +++ b/Mage/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 mage @@ -23,13 +23,17 @@ com.h2database h2 - 1.4.187 + 1.4.197 runtime + + com.google.guava + guava + com.j256.ormlite ormlite-jdbc - 4.48 + 5.1 junit @@ -38,7 +42,7 @@ com.google.protobuf protobuf-java - ${protobuf.version} + 3.7.0-rc1 @@ -55,68 +59,31 @@ - - + - org.apache.maven.plugins - maven-dependency-plugin - ${maven-dependency-plugin.version} + com.github.os72 + protoc-jar-maven-plugin + 3.6.0.1 - copy-protoc - generate-sources - - copy - - - - - com.google.protobuf - protoc - ${protobuf.version} - ${os.detected.classifier} - exe - true - ${project.build.directory} - - - - - - - - - org.apache.maven.plugins - maven-antrun-plugin - ${maven-antrun-plugin.version} - - - exec-protoc - generate-sources - - - - - - - - - - - - - - - - - - - - - - - run - + generate-sources + + run + + + + com.google.protobuf:protoc:3.0.0 + + ${project.basedir}/src/main/proto + + + + java + none + ${project.build.directory}/generated-sources + + + @@ -124,7 +91,7 @@ org.codehaus.mojo build-helper-maven-plugin - ${build-helper-maven-plugin.version} + 1.12 add-classes @@ -139,20 +106,12 @@ - + mage - - - - - kr.motd.maven - os-maven-plugin - ${os-maven-plugin.version} - - + @@ -160,14 +119,6 @@ ${project.basedir}/src/main/proto ${project.build.directory}/generated-sources - - - 1.9.1 - 1.8 - 2.10 - 2.4.2 - 1.4.1.Final - 3.0.0-beta-1 diff --git a/Mage/src/main/java/mage/MageObject.java b/Mage/src/main/java/mage/MageObject.java index b65f172173..7497a44573 100644 --- a/Mage/src/main/java/mage/MageObject.java +++ b/Mage/src/main/java/mage/MageObject.java @@ -64,20 +64,14 @@ public interface MageObject extends MageItem, Serializable { void adjustTargets(Ability ability, Game game); + // memory object copy (not mtg) MageObject copy(); - /** - * Defines that MageObject is a copy of another object - * - * @param isCopy - */ - void setCopy(boolean isCopy); + // copied card info (mtg) + void setCopy(boolean isCopy, MageObject copiedFrom); + + MageObject getCopyFrom(); - /** - * Checks if current MageObject is a copy of another object - * - * @return - */ boolean isCopy(); int getZoneChangeCounter(Game game); @@ -159,13 +153,18 @@ public interface MageObject extends MageItem, Serializable { * @return */ default boolean shareTypes(Card otherCard) { + return this.shareTypes(otherCard, false); + } + + default boolean shareTypes(Card otherCard, boolean permanentOnly) { if (otherCard == null) { throw new IllegalArgumentException("Params can't be null"); } for (CardType type : getCardType()) { - if (otherCard.getCardType().contains(type)) { + if (otherCard.getCardType().contains(type) + && (!permanentOnly || type.isPermanentType())) { return true; } } diff --git a/Mage/src/main/java/mage/MageObjectImpl.java b/Mage/src/main/java/mage/MageObjectImpl.java index 051b958457..7592cb770f 100644 --- a/Mage/src/main/java/mage/MageObjectImpl.java +++ b/Mage/src/main/java/mage/MageObjectImpl.java @@ -1,11 +1,5 @@ - package mage; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -20,16 +14,14 @@ import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.abilities.text.TextPart; import mage.abilities.text.TextPartSubType; import mage.cards.FrameStyle; -import mage.constants.CardType; -import mage.constants.SubLayer; -import mage.constants.SubType; -import mage.constants.SubTypeSet; -import mage.constants.SuperType; +import mage.constants.*; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.*; + public abstract class MageObjectImpl implements MageObject { protected UUID objectId; @@ -48,6 +40,7 @@ public abstract class MageObjectImpl implements MageObject { protected MageInt power; protected MageInt toughness; protected boolean copy; + protected MageObject copyFrom; // copied card INFO (used to call original adjusters) protected List textParts; public MageObjectImpl() { @@ -82,6 +75,7 @@ public abstract class MageObjectImpl implements MageObject { isAllCreatureTypes = object.isAllCreatureTypes; supertype.addAll(object.supertype); this.copy = object.copy; + this.copyFrom = (object.copyFrom != null ? object.copyFrom.copy() : null); textParts = new ArrayList<>(); textParts.addAll(object.textParts); } @@ -263,8 +257,14 @@ public abstract class MageObjectImpl implements MageObject { } @Override - public void setCopy(boolean isCopy) { + public void setCopy(boolean isCopy, MageObject copyFrom) { this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override @@ -322,7 +322,7 @@ public abstract class MageObjectImpl implements MageObject { */ @Override public void removePTCDA() { - for (Iterator iter = this.getAbilities().iterator(); iter.hasNext();) { + for (Iterator iter = this.getAbilities().iterator(); iter.hasNext(); ) { Ability ability = iter.next(); for (Effect effect : ability.getEffects()) { if (effect instanceof ContinuousEffect && ((ContinuousEffect) effect).getSublayer() == SubLayer.CharacteristicDefining_7a) { diff --git a/Mage/src/main/java/mage/MageObjectReference.java b/Mage/src/main/java/mage/MageObjectReference.java index ff72668e40..44f63bebc6 100644 --- a/Mage/src/main/java/mage/MageObjectReference.java +++ b/Mage/src/main/java/mage/MageObjectReference.java @@ -1,7 +1,5 @@ package mage; -import java.io.Serializable; -import java.util.UUID; import mage.cards.Card; import mage.constants.Zone; import mage.game.Game; @@ -10,6 +8,9 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.util.UUID; + /** * A object reference that takes zone changes into account. * @@ -145,4 +146,8 @@ public class MageObjectReference implements Comparable, Ser } return null; } + + public boolean zoneCounterIsCurrent(Game game) { + return game.getState().getZoneChangeCounter(sourceId) == zoneChangeCounter; + } } diff --git a/Mage/src/main/java/mage/ObjectColor.java b/Mage/src/main/java/mage/ObjectColor.java index 3cc60c388e..8f41df79ad 100644 --- a/Mage/src/main/java/mage/ObjectColor.java +++ b/Mage/src/main/java/mage/ObjectColor.java @@ -482,7 +482,7 @@ public class ObjectColor implements Serializable, Copyable, Compara public ColoredManaSymbol getOneColoredManaSymbol() { if (isMulticolored()) { - throw new IllegalStateException("Founded multicolored object, but it's must call with single mana color."); + throw new IllegalStateException("Found multicolor object, but was waiting for simple color."); } if (isBlack()) { diff --git a/Mage/src/main/java/mage/abilities/Ability.java b/Mage/src/main/java/mage/abilities/Ability.java index 9701e1a140..386f8d56c7 100644 --- a/Mage/src/main/java/mage/abilities/Ability.java +++ b/Mage/src/main/java/mage/abilities/Ability.java @@ -1,15 +1,14 @@ package mage.abilities; -import java.io.Serializable; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.costs.Cost; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.Costs; import mage.abilities.costs.mana.ManaCost; import mage.abilities.costs.mana.ManaCosts; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.abilities.hint.Hint; import mage.constants.AbilityType; import mage.constants.AbilityWord; import mage.constants.EffectType; @@ -24,6 +23,10 @@ import mage.target.Targets; import mage.target.targetadjustment.TargetAdjuster; import mage.watchers.Watcher; +import java.io.Serializable; +import java.util.List; +import java.util.UUID; + /** * Practically everything in the game is started from an Ability. This interface * describes what an Ability is composed of at the highest level. @@ -44,10 +47,8 @@ public interface Ability extends Controllable, Serializable { * * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, * mage.game.Game) - * @see - * mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) - * @see - * mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) + * @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) + * @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) */ void newId(); @@ -56,10 +57,8 @@ public interface Ability extends Controllable, Serializable { * * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, * mage.game.Game) - * @see - * mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) - * @see - * mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) + * @see mage.game.GameImpl#addTriggeredAbility(mage.abilities.TriggeredAbility) + * @see mage.game.GameImpl#addDelayedTriggeredAbility(mage.abilities.DelayedTriggeredAbility) */ void newOriginalId(); @@ -143,7 +142,7 @@ public interface Ability extends Controllable, Serializable { /** * TODO Method is unused, keep it around? - * + *

    * Gets all costs that are optional to this ability. These costs can be paid * in addition to other costs to have other effects put into place. * @@ -208,7 +207,6 @@ public interface Ability extends Controllable, Serializable { * * @return The {@link java.util.UUID} of the first target within the targets * list. - * * @see mage.target.Target */ UUID getFirstTarget(); @@ -266,17 +264,15 @@ public interface Ability extends Controllable, Serializable { /** * Activates this ability prompting the controller to pay any mandatory * - * @param game A reference the {@link Game} for which this ability should be - * activated within. + * @param game A reference the {@link Game} for which this ability should be + * activated within. * @param noMana Whether or not {@link ManaCosts} have to be paid. * @return True if this ability was successfully activated. - * * @see mage.players.PlayerImpl#cast(mage.abilities.SpellAbility, * mage.game.Game, boolean) * @see mage.players.PlayerImpl#playAbility(mage.abilities.ActivatedAbility, * mage.game.Game) - * @see - * mage.players.PlayerImpl#triggerAbility(mage.abilities.TriggeredAbility, + * @see mage.players.PlayerImpl#triggerAbility(mage.abilities.TriggeredAbility, * mage.game.Game) */ boolean activate(Game game, boolean noMana); @@ -290,9 +286,7 @@ public interface Ability extends Controllable, Serializable { * * @param game The {@link Game} for which this ability resolves within. * @return Whether or not this ability successfully resolved. - * - * @see - * mage.players.PlayerImpl#playManaAbility(mage.abilities.mana.ManaAbility, + * @see mage.players.PlayerImpl#playManaAbility(mage.abilities.mana.ManaAbility, * mage.game.Game) * @see mage.players.PlayerImpl#specialAction(mage.abilities.SpecialAction, * mage.game.Game) @@ -380,7 +374,7 @@ public interface Ability extends Controllable, Serializable { /** * Sets the value for the ruleAtTheTop attribute - * + *

    * true = show the rule at the top position of the rules * * @param ruleAtTheTop @@ -398,7 +392,7 @@ public interface Ability extends Controllable, Serializable { /** * Sets the value for the worksFaceDown flag - * + *

    * true = the ability works also if the object is face down * * @param worksFaceDown @@ -414,7 +408,7 @@ public interface Ability extends Controllable, Serializable { /** * Sets the value for the ruleVisible attribute - * + *

    * true = rule will be shown for the card / permanent false = rule won't be * shown * @@ -432,7 +426,7 @@ public interface Ability extends Controllable, Serializable { /** * Sets the value for the additional costs rule attribute - * + *

    * true = rule will be shown for the card / permanent false = rule won't be * shown * @@ -451,7 +445,7 @@ public interface Ability extends Controllable, Serializable { * Sets the ability word for the given ability. An ability word is a word * that, in essence, groups, and reminds players of, cards that have a * common functionality and does not imply any particular rules. - * + *

    * --- Not usable yet for rule text generation of triggered abilities --- * * @param abilityWord @@ -479,16 +473,7 @@ public interface Ability extends Controllable, Serializable { boolean activateAlternateOrAdditionalCosts(MageObject sourceObject, boolean noMana, Player controller, Game game); /** - * Sets the object that actually existed while a ability triggerd or an - * ability was activated. - * - * @param mageObject - * @param game - */ - void setSourceObject(MageObject mageObject, Game game); - - /** - * Returns the object that actually existed while a ability triggerd or an + * Returns the object that actually existed while a ability triggered or an * ability was activated. If not set yet, the current object will be * retrieved from the game. * @@ -497,6 +482,8 @@ public interface Ability extends Controllable, Serializable { */ MageObject getSourceObject(Game game); + void setSourceObjectZoneChangeCounter(int zoneChangeCounter); + int getSourceObjectZoneChangeCounter(); /** @@ -520,6 +507,8 @@ public interface Ability extends Controllable, Serializable { */ Permanent getSourcePermanentIfItStillExists(Game game); + Permanent getSourcePermanentOrLKI(Game game); + String getTargetDescription(Targets targets, Game game); void setCanFizzle(boolean canFizzle); @@ -531,4 +520,14 @@ public interface Ability extends Controllable, Serializable { TargetAdjuster getTargetAdjuster(); void adjustTargets(Game game); + + void setCostAdjuster(CostAdjuster costAdjuster); + + CostAdjuster getCostAdjuster(); + + void adjustCosts(Game game); + + List getHints(); + + Ability addHint(Hint hint); } diff --git a/Mage/src/main/java/mage/abilities/AbilityImpl.java b/Mage/src/main/java/mage/abilities/AbilityImpl.java index 6047e07969..e00b004976 100644 --- a/Mage/src/main/java/mage/abilities/AbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/AbilityImpl.java @@ -1,11 +1,6 @@ package mage.abilities; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.UUID; import mage.MageObject; -import mage.MageObjectReference; import mage.Mana; import mage.abilities.costs.*; import mage.abilities.costs.common.PayLifeCost; @@ -15,8 +10,9 @@ import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.mana.DynamicManaEffect; import mage.abilities.effects.common.ManaEffect; +import mage.abilities.effects.mana.DynamicManaEffect; +import mage.abilities.hint.Hint; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.Card; import mage.cards.SplitCard; @@ -38,6 +34,11 @@ import mage.util.ThreadLocalStringBuilder; import mage.watchers.Watcher; import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -67,12 +68,13 @@ public abstract class AbilityImpl implements Ability { protected boolean costModificationActive = true; protected boolean activated = false; protected boolean worksFaceDown = false; - protected MageObject sourceObject; protected int sourceObjectZoneChangeCounter; protected List watchers = new ArrayList<>(); protected List subAbilities = null; protected boolean canFizzle = true; protected TargetAdjuster targetAdjuster = null; + protected CostAdjuster costAdjuster = null; + protected List hints = new ArrayList<>(); public AbilityImpl(AbilityType abilityType, Zone zone) { this.id = UUID.randomUUID(); @@ -116,10 +118,13 @@ public abstract class AbilityImpl implements Ability { this.costModificationActive = ability.costModificationActive; this.worksFaceDown = ability.worksFaceDown; this.abilityWord = ability.abilityWord; - this.sourceObject = ability.sourceObject; this.sourceObjectZoneChangeCounter = ability.sourceObjectZoneChangeCounter; this.canFizzle = ability.canFizzle; this.targetAdjuster = ability.targetAdjuster; + this.costAdjuster = ability.costAdjuster; + for (Hint hint : ability.getHints()) { + this.hints.add(hint.copy()); + } } @Override @@ -131,8 +136,6 @@ public abstract class AbilityImpl implements Ability { public void newId() { if (!(this instanceof MageSingleton)) { this.id = UUID.randomUUID(); -// this.sourceObject = null; -// this.sourceObjectZoneChangeCounter = -1; } getEffects().newId(); } @@ -226,8 +229,10 @@ public abstract class AbilityImpl implements Ability { return false; } - getSourceObject(game); - + MageObject sourceObject = getSourceObject(game); + if (getSourceObjectZoneChangeCounter() == 0) { + setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(getSourceId())); + } if (controller.isTestMode()) { if (!controller.addTargets(this, game)) { return false; @@ -256,7 +261,7 @@ public abstract class AbilityImpl implements Ability { } } if (modes.getAdditionalCost() != null) { - ((OptionalAdditionalModeSourceCosts) modes.getAdditionalCost()).addOptionalAdditionalModeCosts(this, game); + modes.getAdditionalCost().addOptionalAdditionalModeCosts(this, game); } // 20130201 - 601.2b // If the spell has alternative or additional costs that will be paid as it's being cast such @@ -320,11 +325,10 @@ public abstract class AbilityImpl implements Ability { } if (!getTargets().isEmpty()) { Outcome outcome = getEffects().isEmpty() ? Outcome.Detriment : getEffects().get(0).getOutcome(); - if (getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game) == false) { - if ((variableManaCost != null || announceString != null)) { - game.informPlayer(controller, (sourceObject != null ? sourceObject.getIdName() : "") + ": no valid targets"); - } - return false; // when activation of ability is canceled during target selection + // only activated abilities can be canceled by user (not triggered) + if (!getTargets().chooseTargets(outcome, this.controllerId, this, noMana, game, this instanceof ActivatedAbility)) { + // was canceled during targer selection + return false; } } } // end modes @@ -952,9 +956,7 @@ public abstract class AbilityImpl implements Ability { } else if (!object.getAbilities().contains(this)) { // check if it's an ability that is temporary gained to a card Abilities otherAbilities = game.getState().getAllOtherAbilities(this.getSourceId()); - if (otherAbilities == null || !otherAbilities.contains(this)) { - return false; - } + return otherAbilities != null && otherAbilities.contains(this); } } return true; @@ -1160,58 +1162,44 @@ public abstract class AbilityImpl implements Ability { @Override public MageObject getSourceObject(Game game) { - if (sourceObject == null) { - setSourceObject(null, game); - if (sourceObject == null) { - logger.warn("Source object could not be retrieved: " + this.getRule()); - } - } - return sourceObject; + return game.getObject(getSourceId()); } @Override public MageObject getSourceObjectIfItStillExists(Game game) { - MageObject currentObject = game.getObject(getSourceId()); - if (currentObject != null) { - if (sourceObject == null) { - setSourceObject(currentObject, game); - } - MageObjectReference mor = new MageObjectReference(currentObject, game); - if (mor.getZoneChangeCounter() == getSourceObjectZoneChangeCounter()) { - // source object has meanwhile not changed zone - return currentObject; - } + if (getSourceObjectZoneChangeCounter() == 0 + || getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) { + return game.getObject(getSourceId()); } return null; } @Override public Permanent getSourcePermanentIfItStillExists(Game game) { - if (sourceObject == null || !sourceObject.getId().equals(getSourceId())) { - setSourceObject(game.getObject(getSourceId()), game); - } - if (sourceObject instanceof Permanent) { - if (game.getState().getZoneChangeCounter(getSourceId()) == getSourceObjectZoneChangeCounter()) { - return (Permanent) sourceObject; - } + MageObject mageObject = getSourceObjectIfItStillExists(game); + if (mageObject instanceof Permanent) { + return (Permanent) mageObject; } return null; } @Override - public int getSourceObjectZoneChangeCounter() { - return sourceObjectZoneChangeCounter; + public Permanent getSourcePermanentOrLKI(Game game) { + if (getSourceObjectZoneChangeCounter() == 0 + || getSourceObjectZoneChangeCounter() == game.getState().getZoneChangeCounter(getSourceId())) { + return game.getPermanent(getSourceId()); + } + return (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD, getSourceObjectZoneChangeCounter()); } @Override - public void setSourceObject(MageObject sourceObject, Game game) { - if (sourceObject == null) { - this.sourceObject = game.getObject(sourceId); - this.sourceObjectZoneChangeCounter = game.getState().getZoneChangeCounter(sourceId); - } else { - this.sourceObject = sourceObject; - this.sourceObjectZoneChangeCounter = this.sourceObject.getZoneChangeCounter(game); - } + public void setSourceObjectZoneChangeCounter(int sourceObjectZoneChangeCounter) { + this.sourceObjectZoneChangeCounter = sourceObjectZoneChangeCounter; + } + + @Override + public int getSourceObjectZoneChangeCounter() { + return sourceObjectZoneChangeCounter; } @Override @@ -1240,4 +1228,32 @@ public abstract class AbilityImpl implements Ability { targetAdjuster.adjustTargets(this, game); } } + + @Override + public void setCostAdjuster(CostAdjuster costAdjuster) { + this.costAdjuster = costAdjuster; + } + + @Override + public CostAdjuster getCostAdjuster() { + return costAdjuster; + } + + @Override + public void adjustCosts(Game game) { + if (costAdjuster != null) { + costAdjuster.adjustCosts(this, game); + } + } + + @Override + public List getHints() { + return this.hints; + } + + @Override + public Ability addHint(Hint hint) { + this.hints.add(hint); + return this; + } } diff --git a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java index 6b48461d8f..f0ba91bf64 100644 --- a/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/ActivatedAbilityImpl.java @@ -1,4 +1,3 @@ - package mage.abilities; import java.util.UUID; @@ -19,6 +18,7 @@ import mage.constants.TargetController; import mage.constants.TimingRule; import mage.constants.Zone; import mage.game.Game; +import mage.game.command.Commander; import mage.game.command.Emblem; import mage.game.command.Plane; import mage.game.permanent.Permanent; @@ -154,13 +154,19 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa @Override public ActivationStatus canActivate(UUID playerId, Game game) { //20091005 - 602.2 - if (!(hasMoreActivationsThisTurn(game) && (condition == null || condition.apply(game, this)))) { + if (!(hasMoreActivationsThisTurn(game) + && (condition == null + || condition.apply(game, this)))) { return ActivationStatus.getFalse(); } switch (mayActivate) { case ANY: break; - + case ACTIVE: + if (game.getActivePlayerId() != playerId) { + return ActivationStatus.getFalse(); + } + break; case NOT_YOU: if (controlsAbility(playerId, game)) { return ActivationStatus.getFalse(); @@ -198,9 +204,17 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa return ActivationStatus.getFalse(); } //20091005 - 602.5d/602.5e - MageObjectReference permittingObject = game.getContinuousEffects().asThough(sourceId, AsThoughEffectType.ACTIVATE_AS_INSTANT, this, controllerId, game); - if (timing == TimingRule.INSTANT || game.canPlaySorcery(playerId) || null != permittingObject) { - if (costs.canPay(this, sourceId, playerId, game) && canChooseTarget(game)) { + MageObjectReference permittingObject = game.getContinuousEffects() + .asThough(sourceId, + AsThoughEffectType.ACTIVATE_AS_INSTANT, + this, + controllerId, + game); + if (timing == TimingRule.INSTANT + || game.canPlaySorcery(playerId) + || null != permittingObject) { + if (costs.canPay(this, sourceId, playerId, game) + && canChooseTarget(game)) { this.activatorId = playerId; return new ActivationStatus(true, permittingObject); } @@ -219,9 +233,11 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } else { MageObject mageObject = game.getObject(this.sourceId); if (mageObject instanceof Emblem) { - return ((Emblem) mageObject).getControllerId().equals(playerId); + return ((Emblem) mageObject).isControlledBy(playerId); } else if (mageObject instanceof Plane) { - return ((Plane) mageObject).getControllerId().equals(playerId); + return ((Plane) mageObject).isControlledBy(playerId); + } else if (mageObject instanceof Commander) { + return ((Commander) mageObject).isControlledBy(playerId); } else if (game.getState().getZone(this.sourceId) != Zone.BATTLEFIELD) { return ((Card) mageObject).isOwnedBy(playerId); } @@ -297,8 +313,10 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } protected ActivationInfo getActivationInfo(Game game) { - Integer turnNum = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game)); - Integer activationCount = (Integer) game.getState().getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game)); + Integer turnNum = (Integer) game.getState() + .getValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game)); + Integer activationCount = (Integer) game.getState() + .getValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game)); if (turnNum == null || activationCount == null) { return null; } @@ -306,7 +324,9 @@ public abstract class ActivatedAbilityImpl extends AbilityImpl implements Activa } protected void setActivationInfo(ActivationInfo activationInfo, Game game) { - game.getState().setValue(CardUtil.getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum); - game.getState().setValue(CardUtil.getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter); + game.getState().setValue(CardUtil + .getCardZoneString("activationsTurn" + originalId, sourceId, game), activationInfo.turnNum); + game.getState().setValue(CardUtil + .getCardZoneString("activationsCount" + originalId, sourceId, game), activationInfo.activationCounter); } } diff --git a/Mage/src/main/java/mage/abilities/Mode.java b/Mage/src/main/java/mage/abilities/Mode.java index 02e9d9144e..2acae73141 100644 --- a/Mage/src/main/java/mage/abilities/Mode.java +++ b/Mage/src/main/java/mage/abilities/Mode.java @@ -1,14 +1,14 @@ package mage.abilities; -import java.io.Serializable; -import java.util.UUID; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; import mage.target.Target; import mage.target.Targets; +import java.io.Serializable; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class Mode implements Serializable { @@ -53,7 +53,14 @@ public class Mode implements Serializable { } public void addTarget(Target target) { + this.addTarget(target, false); + } + + public void addTarget(Target target, Boolean addChooseHintFromEffect) { targets.add(target); + if (addChooseHintFromEffect) { + target.withChooseHint(this.getEffects().getText(this)); + } } public Effects getEffects() { diff --git a/Mage/src/main/java/mage/abilities/Modes.java b/Mage/src/main/java/mage/abilities/Modes.java index 712dba5b52..c7eb75fbb0 100644 --- a/Mage/src/main/java/mage/abilities/Modes.java +++ b/Mage/src/main/java/mage/abilities/Modes.java @@ -1,13 +1,6 @@ package mage.abilities; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.abilities.costs.OptionalAdditionalModeSourceCosts; import mage.cards.Card; import mage.constants.Outcome; @@ -18,8 +11,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetOpponent; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public class Modes extends LinkedHashMap { @@ -340,25 +334,32 @@ public class Modes extends LinkedHashMap { StringBuilder sb = new StringBuilder(); if (this.getMaxModesFilter() != null) { sb.append("choose one or more. Each mode must target ").append(getMaxModesFilter().getMessage()); - } else if (this.getMinModes() == 1 && this.getMaxModes() == 3) { - sb.append("choose one or more "); + } else if (this.getMinModes() == 0 && this.getMaxModes() == 1) { + sb.append("choose up to one"); + } else if (this.getMinModes() == 1 && this.getMaxModes() > 2) { + sb.append("choose one or more"); } else if (this.getMinModes() == 1 && this.getMaxModes() == 2) { - sb.append("choose one or both "); + sb.append("choose one or both"); } else if (this.getMinModes() == 2 && this.getMaxModes() == 2) { - sb.append("choose two "); + sb.append("choose two"); } else if (this.getMinModes() == 3 && this.getMaxModes() == 3) { - sb.append("choose three "); + sb.append("choose three"); + } else if (this.getMinModes() == 4 && this.getMaxModes() == 4) { + sb.append("choose four"); } else { - sb.append("choose one "); + sb.append("choose one"); } + if (isEachModeOnlyOnce()) { - sb.append("that hasn't been chosen "); + sb.append(" that hasn't been chosen"); } + if (isEachModeMoreThanOnce()) { sb.append(". You may choose the same mode more than once.
    "); } else { - sb.append("—
    "); + sb.append(" —
    "); } + for (Mode mode : this.values()) { sb.append("&bull "); sb.append(mode.getEffects().getTextStartingUpperCase(mode)); diff --git a/Mage/src/main/java/mage/abilities/PlayLandAbility.java b/Mage/src/main/java/mage/abilities/PlayLandAbility.java index 939f28e328..4fc440012e 100644 --- a/Mage/src/main/java/mage/abilities/PlayLandAbility.java +++ b/Mage/src/main/java/mage/abilities/PlayLandAbility.java @@ -1,4 +1,3 @@ - package mage.abilities; import java.util.UUID; @@ -31,7 +30,10 @@ public class PlayLandAbility extends ActivatedAbilityImpl { return ActivationStatus.getFalse(); } //20091005 - 114.2a - return new ActivationStatus(game.isActivePlayer(playerId) && game.getPlayer(playerId).canPlayLand() && game.canPlaySorcery(playerId), permittingObject); + return new ActivationStatus(game.isActivePlayer(playerId) + && game.getPlayer(playerId).canPlayLand() + && game.canPlaySorcery(playerId), + permittingObject); } @Override diff --git a/Mage/src/main/java/mage/abilities/SpellAbility.java b/Mage/src/main/java/mage/abilities/SpellAbility.java index 201d2deb34..d96699bf3b 100644 --- a/Mage/src/main/java/mage/abilities/SpellAbility.java +++ b/Mage/src/main/java/mage/abilities/SpellAbility.java @@ -1,8 +1,5 @@ - package mage.abilities; -import java.util.Optional; -import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.costs.Cost; @@ -12,17 +9,15 @@ import mage.abilities.costs.mana.VariableManaCost; import mage.abilities.keyword.FlashAbility; import mage.cards.Card; import mage.cards.SplitCard; -import mage.constants.AbilityType; -import mage.constants.AsThoughEffectType; -import mage.constants.SpellAbilityCastMode; -import mage.constants.SpellAbilityType; -import mage.constants.TimingRule; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.Optional; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -224,12 +219,16 @@ public class SpellAbility extends ActivatedAbilityImpl { if (event.getType() != GameEvent.EventType.CAST_SPELL) { return null; } + Card card = game.getCard(event.getSourceId()); - Optional ability = card.getAbilities(game).get(event.getTargetId()); - if (ability.isPresent() && ability.get() instanceof SpellAbility) { - return (SpellAbility) ability.get(); + if (card != null) { + Optional ability = card.getAbilities(game).get(event.getTargetId()); + if (ability.isPresent() && ability.get() instanceof SpellAbility) { + return (SpellAbility) ability.get(); + } + return card.getSpellAbility(); } - return card.getSpellAbility(); + return null; } public void setId(UUID idToUse) { diff --git a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java index e341ee74be..55e5bfb9c2 100644 --- a/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java +++ b/Mage/src/main/java/mage/abilities/TriggeredAbilityImpl.java @@ -1,4 +1,3 @@ - package mage.abilities; import java.util.Locale; @@ -45,9 +44,6 @@ public abstract class TriggeredAbilityImpl extends AbilityImpl implements Trigge @Override public void trigger(Game game, UUID controllerId) { //20091005 - 603.4 - if (!(this instanceof DelayedTriggeredAbility)) { - setSourceObject(null, game); - } if (checkInterveningIfClause(game)) { game.addTriggeredAbility(this); } diff --git a/Mage/src/main/java/mage/abilities/abilityword/KinshipAbility.java b/Mage/src/main/java/mage/abilities/abilityword/KinshipAbility.java index f6b952bbfb..6c28ca572f 100644 --- a/Mage/src/main/java/mage/abilities/abilityword/KinshipAbility.java +++ b/Mage/src/main/java/mage/abilities/abilityword/KinshipAbility.java @@ -1,5 +1,3 @@ - - package mage.abilities.abilityword; import mage.abilities.Ability; @@ -21,28 +19,27 @@ import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class KinshipAbility extends TriggeredAbilityImpl { - + public KinshipAbility(Effect kinshipEffect) { - super(Zone.BATTLEFIELD, new KinshipBaseEffect(kinshipEffect), true); + super(Zone.BATTLEFIELD, new KinshipBaseEffect(kinshipEffect), true); } - + public KinshipAbility(final KinshipAbility ability) { - super(ability); + super(ability); } public void addKinshipEffect(Effect kinshipEffect) { - for (Effect effect: this.getEffects()) { + for (Effect effect : this.getEffects()) { if (effect instanceof KinshipBaseEffect) { - ((KinshipBaseEffect) effect).addEffect(kinshipEffect); - break; + ((KinshipBaseEffect) effect).addEffect(kinshipEffect); + break; } - } + } } - + @Override public KinshipAbility copy() { return new KinshipAbility(this); @@ -62,33 +59,33 @@ public class KinshipAbility extends TriggeredAbilityImpl { public String getRule() { return new StringBuilder("Kinship — At the beginning of your upkeep, ").append(super.getRule()).toString(); } - + } class KinshipBaseEffect extends OneShotEffect { - + private final Effects kinshipEffects = new Effects(); - + public KinshipBaseEffect(Effect kinshipEffect) { super(kinshipEffect.getOutcome()); this.kinshipEffects.add(kinshipEffect); this.staticText = "you may look at the top card of your library. If it shares a creature type with {this}, you may reveal it. If you do, "; } - + public KinshipBaseEffect(final KinshipBaseEffect effect) { super(effect); - this.kinshipEffects.addAll(effect.kinshipEffects); + this.kinshipEffects.addAll(effect.kinshipEffects.copy()); } - + public void addEffect(Effect kinshipEffect) { this.kinshipEffects.add(kinshipEffect); } - + @Override public KinshipBaseEffect copy() { return new KinshipBaseEffect(this); } - + @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); @@ -100,22 +97,22 @@ class KinshipBaseEffect extends OneShotEffect { Cards cards = new CardsImpl(card); controller.lookAtCards(sourcePermanent.getName(), cards, game); if (sourcePermanent.shareSubtypes(card, game)) { - if (controller.chooseUse(outcome,new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append('?').toString(), source, game)) { + if (controller.chooseUse(outcome, new StringBuilder("Kinship - Reveal ").append(card.getLogName()).append('?').toString(), source, game)) { controller.revealCards(sourcePermanent.getName(), cards, game); - for (Effect effect: kinshipEffects) { + for (Effect effect : kinshipEffects) { effect.setTargetPointer(new FixedTarget(card.getId())); if (effect.getEffectType() == EffectType.ONESHOT) { effect.apply(game, source); } else { if (effect instanceof ContinuousEffect) { - game.addEffect((ContinuousEffect)effect, source); + game.addEffect((ContinuousEffect) effect, source); } else { throw new UnsupportedOperationException("This kind of effect is not supported"); } } - } + } } - } + } } } return true; @@ -125,7 +122,7 @@ class KinshipBaseEffect extends OneShotEffect { @Override public String getText(Mode mode) { - return new StringBuilder(super.getText(mode)).append(kinshipEffects.getText(mode)).toString(); + return new StringBuilder(super.getText(mode)).append(kinshipEffects.getText(mode)).toString(); } - + } diff --git a/Mage/src/main/java/mage/abilities/common/AttacksFirstTimeTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/AttacksFirstTimeTriggeredAbility.java index 8cef6957df..6c0af59f42 100644 --- a/Mage/src/main/java/mage/abilities/common/AttacksFirstTimeTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/AttacksFirstTimeTriggeredAbility.java @@ -35,7 +35,7 @@ public class AttacksFirstTimeTriggeredAbility extends TriggeredAbilityImpl { if (!event.getSourceId().equals(this.getSourceId())) { return false; } - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); if (watcher == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java index 49d7c0a70e..87ed534a99 100644 --- a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java @@ -70,6 +70,16 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { } } return yours; + case NOT_YOU: + boolean notYours = !event.getPlayerId().equals(this.controllerId); + if (notYours && setTargetPointer) { + if (getTargets().isEmpty()) { + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + } + } + } + return notYours; case OPPONENT: if (game.getPlayer(this.controllerId).hasOpponent(event.getPlayerId(), game)) { if (setTargetPointer && getTargets().isEmpty()) { diff --git a/Mage/src/main/java/mage/abilities/common/ControllerPlaysLandTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ControllerPlaysLandTriggeredAbility.java new file mode 100644 index 0000000000..252203870d --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/ControllerPlaysLandTriggeredAbility.java @@ -0,0 +1,50 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public class ControllerPlaysLandTriggeredAbility extends TriggeredAbilityImpl { + + public ControllerPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) { + super(zone, effect, optional); + } + + public ControllerPlaysLandTriggeredAbility(ControllerPlaysLandTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == EventType.LAND_PLAYED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent land = game.getPermanent(event.getTargetId()); + return land.getControllerId().equals(controllerId); + } + + @Override + public ControllerPlaysLandTriggeredAbility copy() { + return new ControllerPlaysLandTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever you play a land, "; + } +} diff --git a/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java deleted file mode 100644 index ba3e9555d7..0000000000 --- a/Mage/src/main/java/mage/abilities/common/CreatureEntersBattlefieldTriggeredAbility.java +++ /dev/null @@ -1,123 +0,0 @@ - -package mage.abilities.common; - -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; -import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; -import mage.game.Game; -import mage.game.events.EntersTheBattlefieldEvent; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.target.TargetPlayer; -import mage.target.common.TargetCreaturePermanent; - -/** - * - * @author North - */ -public class CreatureEntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl { - - private boolean opponentController; - protected FilterCreaturePermanent filter = new FilterCreaturePermanent(); - - /** - * optional = false
    - * opponentController = false - * - * @param effect - */ - public CreatureEntersBattlefieldTriggeredAbility(Effect effect) { - this(effect, false, false); - } - - /** - * opponentController = false - * - * @param effect - * @param optional - */ - public CreatureEntersBattlefieldTriggeredAbility(Effect effect, boolean optional) { - this(effect, optional, false); - } - - /** - * - * @param effect - * @param optional - * @param opponentController - */ - public CreatureEntersBattlefieldTriggeredAbility(Effect effect, boolean optional, boolean opponentController) { - this(Zone.BATTLEFIELD, effect, optional, opponentController); - - } - - /** - * @param zone - * @param effect - * @param optional - * @param opponentController - */ - public CreatureEntersBattlefieldTriggeredAbility(Zone zone, Effect effect, boolean optional, boolean opponentController) { - this(zone, effect, null, optional, opponentController); - } - - /** - * @param zone - * @param effect - * @param filter filter the triggering creatures - * @param optional - * @param opponentController - */ - public CreatureEntersBattlefieldTriggeredAbility(Zone zone, Effect effect, FilterCreaturePermanent filter, boolean optional, boolean opponentController) { - super(zone, effect, optional); - this.opponentController = opponentController; - if (filter != null) { - this.filter = filter; - } - } - - public CreatureEntersBattlefieldTriggeredAbility(CreatureEntersBattlefieldTriggeredAbility ability) { - super(ability); - this.opponentController = ability.opponentController; - this.filter = ability.filter; - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget(); - if (filter.match(permanent, sourceId, controllerId, game) - && (permanent.isControlledBy(this.controllerId) ^ opponentController)) { - if (!this.getTargets().isEmpty()) { - Target target = this.getTargets().get(0); - if (target instanceof TargetPlayer) { - target.add(permanent.getControllerId(), game); - } - if (target instanceof TargetCreaturePermanent) { - target.add(event.getTargetId(), game); - } - } - return true; - } - return false; - } - - @Override - public String getRule() { - return "Whenever a " + filter.getMessage() + " enters the battlefield under " - + (opponentController ? "an opponent's control, " : "your control, ") - + super.getRule(); - } - - @Override - public CreatureEntersBattlefieldTriggeredAbility copy() { - return new CreatureEntersBattlefieldTriggeredAbility(this); - } -} diff --git a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java index 3045a8fa88..acf69c2ba1 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsCombatDamageToAPlayerTriggeredAbility.java @@ -5,20 +5,20 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.DamagedPlayerEvent; +import mage.game.events.DamagedEvent; import mage.game.events.GameEvent; import mage.players.Player; import mage.target.targetpointer.FixedTarget; /** - * * @author BetaSteward_at_googlemail.com */ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { - protected boolean setTargetPointer; + protected final boolean setTargetPointer; protected String text; protected boolean onlyOpponents; + private boolean orPlaneswalker = false; public DealsCombatDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, false); @@ -47,6 +47,11 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility this.onlyOpponents = ability.onlyOpponents; } + public DealsCombatDamageToAPlayerTriggeredAbility setOrPlaneswalker(boolean orPlaneswalker) { + this.orPlaneswalker = orPlaneswalker; + return this; + } + @Override public DealsCombatDamageToAPlayerTriggeredAbility copy() { return new DealsCombatDamageToAPlayerTriggeredAbility(this); @@ -54,14 +59,15 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER + || (orPlaneswalker && event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER); } @Override public boolean checkTrigger(GameEvent event, Game game) { if (event.getSourceId().equals(getSourceId()) - && ((DamagedPlayerEvent) event).isCombatDamage()) { - if (onlyOpponents) { + && ((DamagedEvent) event).isCombatDamage()) { + if (onlyOpponents && event.getType() == GameEvent.EventType.DAMAGED_PLAYER) { Player controller = game.getPlayer(getControllerId()); if (controller == null || !controller.hasOpponent(event.getPlayerId(), game)) { return false; @@ -81,7 +87,10 @@ public class DealsCombatDamageToAPlayerTriggeredAbility extends TriggeredAbility @Override public String getRule() { if (text == null || text.isEmpty()) { - return "Whenever {this} deals combat damage to " + (onlyOpponents ? "an opponent, " : "a player, ") + super.getRule(); + return "Whenever {this} deals combat damage to " + + (onlyOpponents ? "an opponent" : "a player") + + (orPlaneswalker ? " or planeswalker" : "") + + ", " + super.getRule(); } return text; } diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java index 0b0a41eaa6..4c662d195c 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerAllTriggeredAbility.java @@ -13,7 +13,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImpl { @@ -28,7 +27,11 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp } public DealsDamageToAPlayerAllTriggeredAbility(Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, boolean onlyCombat, boolean affectsDefendingPlayer) { - super(Zone.BATTLEFIELD, effect, optional); + this(Zone.BATTLEFIELD, effect, filter, optional, setTargetPointer, onlyCombat, affectsDefendingPlayer); + } + + public DealsDamageToAPlayerAllTriggeredAbility(Zone zone, Effect effect, FilterPermanent filter, boolean optional, SetTargetPointer setTargetPointer, boolean onlyCombat, boolean affectsDefendingPlayer) { + super(zone, effect, optional); this.setTargetPointer = setTargetPointer; this.filter = filter; this.onlyCombat = onlyCombat; @@ -57,27 +60,25 @@ public class DealsDamageToAPlayerAllTriggeredAbility extends TriggeredAbilityImp public boolean checkTrigger(GameEvent event, Game game) { if (!onlyCombat || ((DamagedPlayerEvent) event).isCombatDamage()) { Permanent permanent = game.getPermanent(event.getSourceId()); - if (permanent != null) { - if (filter.match(permanent, getSourceId(), getControllerId(), game)) { - for (Effect effect : this.getEffects()) { - effect.setValue("damage", event.getAmount()); - effect.setValue("sourceId", event.getSourceId()); - if (affectsDefendingPlayer) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - continue; - } - switch (setTargetPointer) { - case PLAYER: - effect.setTargetPointer(new FixedTarget(permanent.getControllerId())); - break; - case PERMANENT: - effect.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); - break; - } - + if (permanent != null && filter.match(permanent, getSourceId(), getControllerId(), game)) { + for (Effect effect : this.getEffects()) { + effect.setValue("damage", event.getAmount()); + effect.setValue("sourceId", event.getSourceId()); + if (affectsDefendingPlayer) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + continue; } - return true; + switch (setTargetPointer) { + case PLAYER: + effect.setTargetPointer(new FixedTarget(permanent.getControllerId())); + break; + case PERMANENT: + effect.setTargetPointer(new FixedTarget(permanent.getId(), permanent.getZoneChangeCounter(game))); + break; + } + } + return true; } } return false; diff --git a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerTriggeredAbility.java index 2c9c1fc011..289743355a 100644 --- a/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DealsDamageToAPlayerTriggeredAbility.java @@ -2,32 +2,38 @@ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; +import mage.constants.Zone; import mage.game.Game; import mage.game.events.GameEvent; import mage.target.targetpointer.FixedTarget; /** - * * @author jeff */ public class DealsDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { - private boolean setTargetPointer; + private final boolean setTargetPointer; + private final boolean orPlaneswalker; public DealsDamageToAPlayerTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, false); } public DealsDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer) { + this(effect, optional, setTargetPointer, false); + } + + public DealsDamageToAPlayerTriggeredAbility(Effect effect, boolean optional, boolean setTargetPointer, boolean orPlaneswalker) { super(Zone.BATTLEFIELD, effect, optional); this.setTargetPointer = setTargetPointer; + this.orPlaneswalker = orPlaneswalker; } public DealsDamageToAPlayerTriggeredAbility(final DealsDamageToAPlayerTriggeredAbility ability) { super(ability); this.setTargetPointer = ability.setTargetPointer; + this.orPlaneswalker = ability.orPlaneswalker; } @Override @@ -37,7 +43,8 @@ public class DealsDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.DAMAGED_PLAYER; + return event.getType() == GameEvent.EventType.DAMAGED_PLAYER + || (orPlaneswalker && event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER); } @Override @@ -45,8 +52,8 @@ public class DealsDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { if (event.getSourceId().equals(this.sourceId)) { if (setTargetPointer) { for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - effect.setValue("damage", event.getAmount()); + effect.setTargetPointer(new FixedTarget(event.getPlayerId())); + effect.setValue("damage", event.getAmount()); } } return true; @@ -56,7 +63,7 @@ public class DealsDamageToAPlayerTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return "Whenever {this} deals damage to a player, " + super.getRule(); + return "Whenever {this} deals damage to a player" + (orPlaneswalker ? " or planeswalker" : "") + ", " + super.getRule(); } } diff --git a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java index 671945e5f9..a30e474108 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java @@ -30,7 +30,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl { public DiesCreatureTriggeredAbility(Effect effect, boolean optional, boolean another, boolean setTargetPointer) { this(effect, optional, new FilterCreaturePermanent(another ? "another creature" : "a creature")); if (another) { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } this.setTargetPointer = setTargetPointer; } @@ -68,7 +68,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (filter.match(zEvent.getTarget(), sourceId, controllerId, game) && zEvent.getTarget().isCreature()) { if (setTargetPointer) { for (Effect effect : this.getEffects()) { diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java new file mode 100644 index 0000000000..6d43388909 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility.java @@ -0,0 +1,87 @@ + +package mage.abilities.common; + +import mage.MageObject; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; + +/** + * @author noxx + */ +public class DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility extends TriggeredAbilityImpl { + + protected FilterCreatureOrPlaneswalkerPermanent filter; + + public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(Effect effect, boolean optional) { + this(effect, optional, new FilterCreatureOrPlaneswalkerPermanent()); + } + + public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(Effect effect, boolean optional, FilterCreatureOrPlaneswalkerPermanent filter) { + super(Zone.ALL, effect, optional); // Needs "ALL" if the source itself should trigger or multiple (incl. source go to grave) + this.filter = filter; + } + + public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility ability) { + super(ability); + this.filter = ability.filter; + } + + @Override + public DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility copy() { + return new DiesThisOrAnotherCreatureOrPlaneswalkerTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.ZONE_CHANGE; + } + + @Override + public boolean isInUseableZone(Game game, MageObject source, GameEvent event) { + Permanent sourcePermanent = null; + if (game.getState().getZone(getSourceId()) == Zone.BATTLEFIELD) { + sourcePermanent = game.getPermanent(getSourceId()); + } else { + if (game.getShortLivingLKI(getSourceId(), Zone.BATTLEFIELD)) { + sourcePermanent = (Permanent) game.getLastKnownInformation(getSourceId(), Zone.BATTLEFIELD); + } + } + if (sourcePermanent == null) { + return false; + } + return hasSourceObjectAbility(game, sourcePermanent, event); + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + + if (game.getPermanentOrLKIBattlefield(getSourceId()) == null) { + return false; + } + + if (zEvent.isDiesEvent()) { + if (zEvent.getTarget() != null) { + if (zEvent.getTarget().getId().equals(this.getSourceId())) { + return true; + } else { + if (filter.match(zEvent.getTarget(), getSourceId(), getControllerId(), game)) { + return true; + } + } + } + } + return false; + } + + @Override + public String getRule() { + return "Whenever {this} or another " + filter.getMessage() + " dies, " + super.getRule(); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java index 0173c91355..c0d241039d 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesThisOrAnotherCreatureTriggeredAbility.java @@ -66,7 +66,7 @@ public class DiesThisOrAnotherCreatureTriggeredAbility extends TriggeredAbilityI return false; } - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget() != null) { if (zEvent.getTarget().getId().equals(this.getSourceId())) { return true; diff --git a/Mage/src/main/java/mage/abilities/common/EnchantedPlayerAttackedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EnchantedPlayerAttackedTriggeredAbility.java index a6bd906692..6c02743b37 100644 --- a/Mage/src/main/java/mage/abilities/common/EnchantedPlayerAttackedTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EnchantedPlayerAttackedTriggeredAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; @@ -10,7 +9,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author LevelX2 */ public class EnchantedPlayerAttackedTriggeredAbility extends TriggeredAbilityImpl { @@ -35,7 +33,7 @@ public class EnchantedPlayerAttackedTriggeredAbility extends TriggeredAbilityImp Permanent enchantment = game.getPermanentOrLKIBattlefield(getSourceId()); Player controller = game.getPlayer(getControllerId()); if (controller != null && enchantment != null) { - return game.getCombat().getPlayerDefenders(game).contains(enchantment.getAttachedTo()); + return game.getCombat().getPlayerDefenders(game, false).contains(enchantment.getAttachedTo()); } return false; } diff --git a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrDiesSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrDiesSourceTriggeredAbility.java index d0db65728b..1c36a79de9 100644 --- a/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrDiesSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/EntersBattlefieldOrDiesSourceTriggeredAbility.java @@ -43,7 +43,7 @@ public class EntersBattlefieldOrDiesSourceTriggeredAbility extends TriggeredAbil } if (event.getType() == EventType.ZONE_CHANGE && event.getTargetId().equals(this.getSourceId())) { ZoneChangeEvent zEvent = (ZoneChangeEvent)event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/common/FetchLandActivatedAbility.java b/Mage/src/main/java/mage/abilities/common/FetchLandActivatedAbility.java index 40a620f5e8..fa71efebee 100644 --- a/Mage/src/main/java/mage/abilities/common/FetchLandActivatedAbility.java +++ b/Mage/src/main/java/mage/abilities/common/FetchLandActivatedAbility.java @@ -22,6 +22,7 @@ import mage.target.common.TargetCardInLibrary; import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; /** * @@ -51,16 +52,12 @@ public class FetchLandActivatedAbility extends ActivatedAbilityImpl { addEffect(new SearchLibraryPutInPlayEffect(target, false, true, Outcome.PutLandInPlay)); } - public FetchLandActivatedAbility(FetchLandActivatedAbility ability) { + private FetchLandActivatedAbility(FetchLandActivatedAbility ability) { super(ability); } private String subTypeNames(Set subTypes) { - StringBuilder sb = new StringBuilder(); - for (SubType subType: subTypes) { - sb.append(subType.getDescription()).append(" or "); - } - return sb.substring(0, sb.length() - 4); + return subTypes.stream().map(SubType::getDescription).collect(Collectors.joining(" or ")); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java index 09bf317c73..f78e0f9d3e 100644 --- a/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/GainLifeControllerTriggeredAbility.java @@ -9,12 +9,11 @@ import mage.game.events.GameEvent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl { - private boolean setTargetPointer; + private final boolean setTargetPointer; public GainLifeControllerTriggeredAbility(Effect effect, boolean optional) { this(effect, optional, false); @@ -56,7 +55,6 @@ public class GainLifeControllerTriggeredAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Whenever you gain life, ").append(super.getRule()).toString(); + return "Whenever you gain life, " + super.getRule(); } - } diff --git a/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java new file mode 100644 index 0000000000..a7e9205f71 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/GodEternalDiesTriggeredAbility.java @@ -0,0 +1,92 @@ +package mage.abilities.common; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class GodEternalDiesTriggeredAbility extends TriggeredAbilityImpl { + + public GodEternalDiesTriggeredAbility() { + super(Zone.ALL, null, true); + } + + private GodEternalDiesTriggeredAbility(GodEternalDiesTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.ZONE_CHANGE) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + return zEvent.getFromZone() == Zone.BATTLEFIELD + && (zEvent.getToZone() == Zone.GRAVEYARD || zEvent.getToZone() == Zone.EXILED); + } + return false; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getTargetId().equals(this.getSourceId())) { + this.getEffects().clear(); + this.addEffect(new GodEternalEffect(new MageObjectReference(zEvent.getTarget(), game))); + return true; + } + return false; + } + + @Override + public GodEternalDiesTriggeredAbility copy() { + return new GodEternalDiesTriggeredAbility(this); + } + + @Override + public String getRule() { + return "When {this} dies or is put into exile from the battlefield, " + + "you may put it into its owner's library third from the top."; + } +} + +class GodEternalEffect extends OneShotEffect { + + private final MageObjectReference mor; + + GodEternalEffect(MageObjectReference mor) { + super(Outcome.Benefit); + this.mor = mor; + } + + private GodEternalEffect(final GodEternalEffect effect) { + super(effect); + this.mor = effect.mor; + } + + @Override + public GodEternalEffect copy() { + return new GodEternalEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Card card = game.getCard(mor.getSourceId()); + if (card.getZoneChangeCounter(game) - 1 != mor.getZoneChangeCounter()) { + return false; + } + return player.putCardOnTopXOfLibrary(card, game, source, 3); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java index 8757d62401..7ce2028a91 100644 --- a/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/LeavesBattlefieldAllTriggeredAbility.java @@ -40,7 +40,7 @@ public class LeavesBattlefieldAllTriggeredAbility extends TriggeredAbilityImpl { this.setTargetPointer = setTargetPointer; } - public LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) { + private LeavesBattlefieldAllTriggeredAbility(final LeavesBattlefieldAllTriggeredAbility ability) { super(ability); filter = ability.filter; setTargetPointer = ability.setTargetPointer; diff --git a/Mage/src/main/java/mage/abilities/common/OneOrMoreCountersAddedTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OneOrMoreCountersAddedTriggeredAbility.java new file mode 100644 index 0000000000..a0821c4f9f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/OneOrMoreCountersAddedTriggeredAbility.java @@ -0,0 +1,53 @@ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; + +public class OneOrMoreCountersAddedTriggeredAbility extends TriggeredAbilityImpl { + + private final CounterType counterType; + + public OneOrMoreCountersAddedTriggeredAbility(Effect effect) { + this(effect, false); + } + + public OneOrMoreCountersAddedTriggeredAbility(Effect effect, boolean optional) { + this(effect, optional, CounterType.P1P1); + } + + public OneOrMoreCountersAddedTriggeredAbility(Effect effect, boolean optional, CounterType counterType) { + super(Zone.ALL, effect, optional); + this.counterType = counterType; + } + + private OneOrMoreCountersAddedTriggeredAbility(final OneOrMoreCountersAddedTriggeredAbility ability) { + super(ability); + this.counterType = ability.counterType; + } + + @Override + public OneOrMoreCountersAddedTriggeredAbility copy() { + return new OneOrMoreCountersAddedTriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COUNTERS_ADDED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + return event.getData().equals(counterType.getName()) + && event.getAmount() > 0 + && event.getTargetId().equals(this.getSourceId()); + } + + @Override + public String getRule() { + return "Whenever one or more " + counterType.getName() + " counters are put on {this}, " + super.getRule(); + } +} diff --git a/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java new file mode 100644 index 0000000000..7249b6679e --- /dev/null +++ b/Mage/src/main/java/mage/abilities/common/OpponentPlaysLandTriggeredAbility.java @@ -0,0 +1,49 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.common; + +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public class OpponentPlaysLandTriggeredAbility extends TriggeredAbilityImpl { + + public OpponentPlaysLandTriggeredAbility(Zone zone, Effect effect, Boolean optional) { + super(zone, effect, optional); + } + + public OpponentPlaysLandTriggeredAbility(OpponentPlaysLandTriggeredAbility ability) { + super(ability); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.LAND_PLAYED; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + Permanent land = game.getPermanent(event.getTargetId()); + return game.getOpponents(controllerId).contains(land.getControllerId()); + } + + @Override + public OpponentPlaysLandTriggeredAbility copy() { + return new OpponentPlaysLandTriggeredAbility(this); + } + + @Override + public String getRule() { + return "Whenever an opponent plays a land, "; + } +} diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java index df73e1f2ef..5b147df11d 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldAllTriggeredAbility.java @@ -48,8 +48,7 @@ public class PutIntoGraveFromBattlefieldAllTriggeredAbility extends TriggeredAbi @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD - && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (filter.match(zEvent.getTarget(), this.getSourceId(), this.getControllerId(), game)) { if (onlyToControllerGraveyard && !this.isControlledBy(game.getOwnerId(zEvent.getTargetId()))) { return false; diff --git a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java index 2c6fb1139e..0f83feefa2 100644 --- a/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/PutIntoGraveFromBattlefieldSourceTriggeredAbility.java @@ -13,17 +13,21 @@ import mage.game.permanent.Permanent; */ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends TriggeredAbilityImpl { + private boolean onlyToControllerGraveyard; + public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect) { - this(effect, false); + this(effect, false, false); } - public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect, boolean optional) { + public PutIntoGraveFromBattlefieldSourceTriggeredAbility(Effect effect, boolean optional, boolean onlyToControllerGraveyard) { super(Zone.ALL, effect, optional); setLeavesTheBattlefieldTrigger(true); + this.onlyToControllerGraveyard = onlyToControllerGraveyard; } public PutIntoGraveFromBattlefieldSourceTriggeredAbility(final PutIntoGraveFromBattlefieldSourceTriggeredAbility ability) { super(ability); + this.onlyToControllerGraveyard = ability.onlyToControllerGraveyard; } @Override @@ -44,7 +48,7 @@ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends Triggered if (permanent != null && zEvent.getToZone() == Zone.GRAVEYARD && zEvent.getFromZone() == Zone.BATTLEFIELD) { - return true; + return !onlyToControllerGraveyard || this.isControlledBy(game.getOwnerId(zEvent.getTargetId())); } } return false; @@ -52,6 +56,6 @@ public class PutIntoGraveFromBattlefieldSourceTriggeredAbility extends Triggered @Override public String getRule() { - return "When {this} is put into a graveyard from the battlefield, " + super.getRule(); + return "When {this} is put into " + (onlyToControllerGraveyard ? "your" : "a") + " graveyard from the battlefield, " + super.getRule(); } } diff --git a/Mage/src/main/java/mage/abilities/common/SagaAbility.java b/Mage/src/main/java/mage/abilities/common/SagaAbility.java index 954ed8930d..624221c13e 100644 --- a/Mage/src/main/java/mage/abilities/common/SagaAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SagaAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common; import mage.abilities.Ability; @@ -138,7 +137,8 @@ class ChapterTriggeredAbility extends TriggeredAbilityImpl { if (event.getTargetId().equals(getSourceId()) && event.getData().equals(CounterType.LORE.getName())) { int amountAdded = event.getAmount(); int loreCounters = amountAdded; - Permanent sourceSaga = game.getPermanentOrLKIBattlefield(getSourceId()); + //Permanent sourceSaga = game.getPermanentOrLKIBattlefield(getSourceId()); BUG #5393 + Permanent sourceSaga = game.getPermanent(getSourceId()); if (sourceSaga == null) { sourceSaga = game.getPermanentEntering(getSourceId()); } diff --git a/Mage/src/main/java/mage/abilities/common/SimpleStaticAbility.java b/Mage/src/main/java/mage/abilities/common/SimpleStaticAbility.java index 3b608a9cdc..b71bf85dae 100644 --- a/Mage/src/main/java/mage/abilities/common/SimpleStaticAbility.java +++ b/Mage/src/main/java/mage/abilities/common/SimpleStaticAbility.java @@ -2,16 +2,19 @@ package mage.abilities.common; -import mage.constants.Zone; import mage.abilities.StaticAbility; import mage.abilities.effects.Effect; +import mage.constants.Zone; /** - * * @author BetaSteward_at_googlemail.com */ public class SimpleStaticAbility extends StaticAbility { + public SimpleStaticAbility(Effect effect) { + this(Zone.BATTLEFIELD, effect); + } + public SimpleStaticAbility(Zone zone, Effect effect) { super(zone, effect); } diff --git a/Mage/src/main/java/mage/abilities/common/WinsCoinFlipTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/WinsCoinFlipTriggeredAbility.java index 704ff18af2..f80b41a544 100644 --- a/Mage/src/main/java/mage/abilities/common/WinsCoinFlipTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/WinsCoinFlipTriggeredAbility.java @@ -5,10 +5,10 @@ import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; import mage.constants.Zone; import mage.game.Game; +import mage.game.events.CoinFlippedEvent; import mage.game.events.GameEvent; /** - * * @author TheElk801 */ public class WinsCoinFlipTriggeredAbility extends TriggeredAbilityImpl { @@ -33,7 +33,8 @@ public class WinsCoinFlipTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - return event.getFlag(); + CoinFlippedEvent flipEvent = (CoinFlippedEvent) event; + return flipEvent.isWinnable() && (flipEvent.getChosen() == flipEvent.getResult()); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java index 77872721e3..9d97496682 100644 --- a/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/ZoneChangeAllTriggeredAbility.java @@ -1,5 +1,3 @@ - - package mage.abilities.common; import mage.abilities.TriggeredAbilityImpl; @@ -50,8 +48,9 @@ public class ZoneChangeAllTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent)event; - if ((fromZone == null || zEvent.getFromZone() == fromZone) && (toZone == null || zEvent.getToZone() == toZone)) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if ((fromZone == null || fromZone.match(zEvent.getFromZone())) + && (toZone == null || toZone.match(zEvent.getToZone()))) { Permanent perm; if (zEvent.getTarget() != null) { perm = zEvent.getTarget(); diff --git a/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java b/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java index c7c465dd24..8ec64e7760 100644 --- a/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java +++ b/Mage/src/main/java/mage/abilities/common/delayed/OnLeaveReturnExiledToBattlefieldAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.common.delayed; import java.util.LinkedHashSet; diff --git a/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java new file mode 100644 index 0000000000..4bc9f34d73 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AddendumCondition.java @@ -0,0 +1,36 @@ + +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.TurnPhase; +import mage.game.Game; +import mage.game.stack.Spell; + +import java.util.EnumSet; +import java.util.Set; + +/** + * @author LevelX2 + */ + +public enum AddendumCondition implements Condition { + + instance; + private static final Set turnPhases = EnumSet.of( + TurnPhase.PRECOMBAT_MAIN, TurnPhase.POSTCOMBAT_MAIN + ); + + @Override + public boolean apply(Game game, Ability source) { + if (!game.isActivePlayer(source.getControllerId()) || + !turnPhases.contains(game.getTurn().getPhase().getType())) { + return false; + } + if (CastFromEverywhereSourceCondition.instance.apply(game, source)) { + return true; + } + Spell spell = game.getSpell(source.getSourceId()); + return spell != null && !spell.isCopy(); + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/AfterCombatCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AfterCombatCondition.java new file mode 100644 index 0000000000..76bdc4be62 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/AfterCombatCondition.java @@ -0,0 +1,25 @@ + +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.constants.PhaseStep; +import mage.game.Game; + +/** + * @author L_J + */ +public enum AfterCombatCondition implements Condition { + + instance; + @Override + + public boolean apply(Game game, Ability source) { + return game.getStep().getType().isAfter(PhaseStep.END_COMBAT); + } + + @Override + public String toString() { + return "after combat"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedOrBlockedThisCombatSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedOrBlockedThisCombatSourceCondition.java index ef4a90dc6c..17ee4adf33 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackedOrBlockedThisCombatSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttackedOrBlockedThisCombatSourceCondition.java @@ -24,7 +24,7 @@ public enum AttackedOrBlockedThisCombatSourceCondition implements Condition { public boolean apply(Game game, Ability source) { Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (sourceObject != null) { - AttackedOrBlockedThisCombatWatcher watcher = (AttackedOrBlockedThisCombatWatcher) game.getState().getWatchers().get(AttackedOrBlockedThisCombatWatcher.class.getSimpleName()); + AttackedOrBlockedThisCombatWatcher watcher = game.getState().getWatcher(AttackedOrBlockedThisCombatWatcher.class); if (watcher != null) { for (MageObjectReference mor : watcher.getAttackedThisTurnCreatures()) { if (mor.refersTo(sourceObject, game)) { diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java index babbd9580c..026ae5b498 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisStepCondition.java @@ -15,7 +15,7 @@ public enum AttackedThisStepCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerAttackedStepWatcher watcher = (PlayerAttackedStepWatcher) game.getState().getWatchers().get(PlayerAttackedStepWatcher.class.getSimpleName()); + PlayerAttackedStepWatcher watcher = game.getState().getWatcher(PlayerAttackedStepWatcher.class); return watcher != null && watcher.getNumberAttackingCurrentStep(source.getControllerId()) > 0; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnCondition.java index 6341d527a8..5ee7dfb4a8 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnCondition.java @@ -19,7 +19,7 @@ public enum AttackedThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - return !watcher.getAttackedThisTurnCreatures().isEmpty(); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + return watcher != null && !watcher.getAttackedThisTurnCreatures().isEmpty(); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnSourceCondition.java index 58f3719ec7..0bf152ec76 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/AttackedThisTurnSourceCondition.java @@ -18,7 +18,7 @@ public enum AttackedThisTurnSourceCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); return sourcePermanent != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game)); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/BlockedThisTurnSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/BlockedThisTurnSourceCondition.java index d6578996f6..93f37e89a2 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/BlockedThisTurnSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/BlockedThisTurnSourceCondition.java @@ -18,7 +18,7 @@ public enum BlockedThisTurnSourceCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - BlockedThisTurnWatcher watcher = (BlockedThisTurnWatcher) game.getState().getWatchers().get(BlockedThisTurnWatcher.class.getSimpleName()); + BlockedThisTurnWatcher watcher = game.getState().getWatcher(BlockedThisTurnWatcher.class); return sourcePermanent != null && watcher.getBlockedThisTurnCreatures().contains(new MageObjectReference(sourcePermanent, game)); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/CastFromHandSourceCondition.java b/Mage/src/main/java/mage/abilities/condition/common/CastFromHandSourceCondition.java index c813524465..1a584533ec 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/CastFromHandSourceCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/CastFromHandSourceCondition.java @@ -33,7 +33,7 @@ public enum CastFromHandSourceCondition implements Condition { return false; } } - CastFromHandWatcher watcher = (CastFromHandWatcher) game.getState().getWatchers().get(CastFromHandWatcher.class.getSimpleName()); + CastFromHandWatcher watcher = game.getState().getWatcher(CastFromHandWatcher.class); if (watcher != null && watcher.spellWasCastFromHand(source.getSourceId())) { return true; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/ControllerAttackedThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ControllerAttackedThisTurnCondition.java index b327e6e214..d7f732d11a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ControllerAttackedThisTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ControllerAttackedThisTurnCondition.java @@ -15,7 +15,7 @@ public enum ControllerAttackedThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); return source.isControlledBy(game.getActivePlayerId()) && watcher != null && !watcher.getAttackedThisTurnCreatures().isEmpty(); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java b/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java index 4e83de1baf..57e4830640 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DealtDamageToAnOpponent.java @@ -15,7 +15,7 @@ public class DealtDamageToAnOpponent implements Condition { @Override public boolean apply(Game game, Ability source) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { - PlayerDamagedBySourceWatcher watcher = (PlayerDamagedBySourceWatcher) game.getState().getWatchers().get(PlayerDamagedBySourceWatcher.class.getSimpleName(), opponentId); + PlayerDamagedBySourceWatcher watcher = game.getState().getWatcher(PlayerDamagedBySourceWatcher.class, opponentId); if (watcher != null) { if (watcher.hasSourceDoneDamage(source.getSourceId(), game)) { return true; diff --git a/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java b/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java index 3d05017d79..370a2a3020 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/DeliriumCondition.java @@ -1,17 +1,11 @@ - package mage.abilities.condition.common; -import java.util.EnumSet; import mage.abilities.Ability; import mage.abilities.condition.Condition; -import mage.cards.Card; -import mage.constants.CardType; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; import mage.game.Game; -import mage.players.Player; /** - * - * * @author fireshoes */ public enum DeliriumCondition implements Condition { @@ -20,15 +14,7 @@ public enum DeliriumCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - EnumSet foundCardTypes = EnumSet.noneOf(CardType.class); - for (Card card : controller.getGraveyard().getCards(game)) { - foundCardTypes.addAll(card.getCardType()); - } - return foundCardTypes.size() >= 4; - } - return false; + return CardTypesInGraveyardCount.instance.calculate(game, source, null) >= 4; } @Override diff --git a/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java b/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java index 72216794d6..1db22ed9f8 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/HateCondition.java @@ -18,7 +18,7 @@ public enum HateCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - LifeLossOtherFromCombatWatcher watcher = (LifeLossOtherFromCombatWatcher) game.getState().getWatchers().get(LifeLossOtherFromCombatWatcher.class.getSimpleName()); + LifeLossOtherFromCombatWatcher watcher = game.getState().getWatcher(LifeLossOtherFromCombatWatcher.class); return watcher != null && watcher.opponentLostLifeOtherFromCombat(source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java index 44686f489e..2b6d991c54 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LandfallCondition.java @@ -13,7 +13,7 @@ public enum LandfallCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - LandfallWatcher watcher = (LandfallWatcher) game.getState().getWatchers().get(LandfallWatcher.class.getSimpleName()); + LandfallWatcher watcher = game.getState().getWatcher(LandfallWatcher.class); return watcher != null && watcher.landPlayed(source.getControllerId()); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java index 9832cc9109..7025aca0bc 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/LiveLostLastTurnCondition.java @@ -17,9 +17,9 @@ public enum LiveLostLastTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { - return watcher.getLiveLostLastTurn(source.getControllerId()) > 0; + return watcher.getLifeLostLastTurn(source.getControllerId()) > 0; } else { WatcherUtils.logMissingWatcher(game, source, PlayerLostLifeWatcher.class, this.getClass()); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/ManaWasSpentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/ManaWasSpentCondition.java index 5a0737d0a8..d512e91716 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/ManaWasSpentCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/ManaWasSpentCondition.java @@ -30,7 +30,7 @@ public class ManaWasSpentCondition implements Condition { if (source.getAbilityType() == AbilityType.SPELL) { return (source.getManaCostsToPay().getPayment().getColor(coloredManaSymbol) > 0); } - ManaSpentToCastWatcher watcher = (ManaSpentToCastWatcher) game.getState().getWatchers().get(ManaSpentToCastWatcher.class.getSimpleName(), source.getSourceId()); + ManaSpentToCastWatcher watcher = game.getState().getWatcher(ManaSpentToCastWatcher.class, source.getSourceId()); if (watcher != null) { Mana payment = watcher.getAndResetLastPayment(); if (payment != null) { @@ -42,7 +42,7 @@ public class ManaWasSpentCondition implements Condition { @Override public String toString() { - return new StringBuilder("{").append(coloredManaSymbol.toString()).append("} was spent to cast it").toString(); + return "{" + coloredManaSymbol.toString() + "} was spent to cast it"; } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/MorbidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MorbidCondition.java index d095c2b0f5..f6b939cc6e 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/MorbidCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/MorbidCondition.java @@ -16,8 +16,8 @@ public enum MorbidCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - Watcher watcher = game.getState().getWatchers().get(MorbidWatcher.class.getSimpleName()); - return watcher.conditionMet(); + MorbidWatcher watcher = game.getState().getWatcher(MorbidWatcher.class); + return watcher != null && watcher.conditionMet(); } @Override diff --git a/Mage/src/main/java/mage/abilities/condition/common/MyMainPhaseCondition.java b/Mage/src/main/java/mage/abilities/condition/common/MyMainPhaseCondition.java deleted file mode 100644 index ae960029b0..0000000000 --- a/Mage/src/main/java/mage/abilities/condition/common/MyMainPhaseCondition.java +++ /dev/null @@ -1,26 +0,0 @@ - -package mage.abilities.condition.common; - -import java.util.EnumSet; -import java.util.Set; - -import mage.constants.TurnPhase; -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.game.Game; - -/** - * @author LevelX2 - */ - -public enum MyMainPhaseCondition implements Condition { - - instance; - private static final Set turnPhases = EnumSet.of(TurnPhase.PRECOMBAT_MAIN, TurnPhase.POSTCOMBAT_MAIN); - - @Override - public boolean apply(Game game, Ability source) { - return game.isActivePlayer(source.getControllerId()) && - turnPhases.contains(game.getTurn().getPhase().getType()); - } -} diff --git a/Mage/src/main/java/mage/abilities/condition/common/NoSpellsWereCastLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/NoSpellsWereCastLastTurnCondition.java index c43f09ba86..ac1253311a 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/NoSpellsWereCastLastTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/NoSpellsWereCastLastTurnCondition.java @@ -23,7 +23,10 @@ public enum NoSpellsWereCastLastTurnCondition implements Condition { return false; } - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if(watcher == null){ + return false; + } // if any player cast spell, return false for (Integer count : watcher.getAmountOfSpellsCastOnPrevTurn().values()) { if (count > 0) { diff --git a/Mage/src/main/java/mage/abilities/condition/common/OpponentLostLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OpponentLostLifeCondition.java index 75e9107f57..c509ebabc1 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/OpponentLostLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/OpponentLostLifeCondition.java @@ -23,10 +23,10 @@ public class OpponentLostLifeCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int maxLostLive = 0; - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { for (UUID opponentId : game.getOpponents(source.getControllerId())) { - int lostLive = watcher.getLiveLost(opponentId); + int lostLive = watcher.getLifeLost(opponentId); if (lostLive > maxLostLive) { maxLostLive = lostLive; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/OpponentsLostLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/OpponentsLostLifeCondition.java new file mode 100644 index 0000000000..84ae6a0376 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/OpponentsLostLifeCondition.java @@ -0,0 +1,24 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.dynamicvalue.common.OpponentsLostLifeCount; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum OpponentsLostLifeCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + return OpponentsLostLifeCount.instance.calculate(game, source.getControllerId()) > 0; + } + + @Override + public String toString() { + return "opponents lost life"; + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/PlayLandCondition.java b/Mage/src/main/java/mage/abilities/condition/common/PlayLandCondition.java index 121dfec822..cab3b23a32 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/PlayLandCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/PlayLandCondition.java @@ -13,7 +13,7 @@ public enum PlayLandCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayLandWatcher watcher = (PlayLandWatcher) game.getState().getWatchers().get(PlayLandWatcher.class.getSimpleName()); + PlayLandWatcher watcher = game.getState().getWatcher(PlayLandWatcher.class); return watcher != null && watcher.landPlayed(source.getControllerId()); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java index a821a30d30..85dcb3c2d9 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/RaidCondition.java @@ -15,7 +15,7 @@ public enum RaidCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - PlayerAttackedWatcher watcher = (PlayerAttackedWatcher) game.getState().getWatchers().get(PlayerAttackedWatcher.class.getSimpleName()); + PlayerAttackedWatcher watcher = game.getState().getWatcher(PlayerAttackedWatcher.class); return watcher != null && watcher.getNumberOfAttackersCurrentTurn(source.getControllerId()) > 0; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java b/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java index 1c3feabc9e..db68abf028 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/RevoltCondition.java @@ -15,7 +15,7 @@ public enum RevoltCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - RevoltWatcher watcher = (RevoltWatcher) game.getState().getWatchers().get(RevoltWatcher.class.getSimpleName()); + RevoltWatcher watcher = game.getState().getWatcher(RevoltWatcher.class); return watcher != null && watcher.revoltActive(source.getControllerId()); } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceDealtDamageCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceDealtDamageCondition.java index 38bb87a2c2..7a9f111d22 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/SourceDealtDamageCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceDealtDamageCondition.java @@ -24,7 +24,7 @@ public class SourceDealtDamageCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - DamageDoneWatcher watcher = (DamageDoneWatcher) game.getState().getWatchers().get(DamageDoneWatcher.class.getSimpleName()); + DamageDoneWatcher watcher = game.getState().getWatcher(DamageDoneWatcher.class); return watcher != null && watcher.damageDoneBy(source.getSourceId(), source.getSourceObjectZoneChangeCounter(), game) >= value; } diff --git a/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java new file mode 100644 index 0000000000..b4e3697752 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SourceTargetsPermanentCondition.java @@ -0,0 +1,45 @@ +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.filter.FilterPermanent; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.stack.StackObject; +import mage.target.Target; + +import java.util.Iterator; + +/** + * @author TheElk801 + */ +public class SourceTargetsPermanentCondition implements Condition { + + private final FilterPermanent filter; + + public SourceTargetsPermanentCondition(FilterPermanent filter) { + this.filter = filter; + } + + @Override + public boolean apply(Game game, Ability source) { + StackObject sourceSpell = game.getStack().getStackObject(source.getSourceId()); + if (sourceSpell == null) { + return false; + } + Iterator targets = sourceSpell.getStackAbility().getTargets().iterator(); + while (targets.hasNext()) { + Permanent permanent = game.getPermanentOrLKIBattlefield(targets.next().getFirstTarget()); + if (permanent != null && filter.match(permanent, source.getSourceId(), source.getControllerId(), game)) { + return true; + } + } + return false; + } + + @Override + public String toString() { + return "it targets " + filter.getMessage(); + } + +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java new file mode 100644 index 0000000000..8082411944 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/condition/common/SpectacleCondition.java @@ -0,0 +1,33 @@ + +package mage.abilities.condition.common; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.abilities.keyword.SpectacleAbility; +import mage.constants.AbilityType; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author TheElk801 + */ +public enum SpectacleCondition implements Condition { + + instance; + + @Override + public boolean apply(Game game, Ability source) { + if (source.getAbilityType() == AbilityType.TRIGGERED) { + @SuppressWarnings("unchecked") + List spectacleActivations = (ArrayList) game.getState().getValue(SpectacleAbility.SPECTACLE_ACTIVATION_VALUE_KEY + source.getSourceId()); + if (spectacleActivations != null) { + return spectacleActivations.contains(game.getState().getZoneChangeCounter(source.getSourceId()) - 1); + } + return false; + } else { + return source instanceof SpectacleAbility; + } + } +} diff --git a/Mage/src/main/java/mage/abilities/condition/common/TargetAttackedThisTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TargetAttackedThisTurnCondition.java index f81afcc01e..561a3afd29 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TargetAttackedThisTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TargetAttackedThisTurnCondition.java @@ -17,7 +17,7 @@ public enum TargetAttackedThisTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { Permanent creature = game.getPermanentOrLKIBattlefield(source.getTargets().getFirstTarget()); - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); return creature != null && watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(creature, game)); } } diff --git a/Mage/src/main/java/mage/abilities/condition/common/TargetHasCardTypeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TargetHasCardTypeCondition.java index d1f0bb30af..67a02f25c0 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TargetHasCardTypeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TargetHasCardTypeCondition.java @@ -1,8 +1,3 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.abilities.condition.common; import mage.MageObject; diff --git a/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java b/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java index 01f3decbd0..1f905605a4 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/TwoOrMoreSpellsWereCastLastTurnCondition.java @@ -15,7 +15,10 @@ public enum TwoOrMoreSpellsWereCastLastTurnCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); + if(watcher == null){ + return false; + } // if any player cast more than two spells, return true for (Integer count : watcher.getAmountOfSpellsCastOnPrevTurn().values()) { if (count >= 2) { diff --git a/Mage/src/main/java/mage/abilities/condition/common/WatcherCondition.java b/Mage/src/main/java/mage/abilities/condition/common/WatcherCondition.java deleted file mode 100644 index 94d6e45f03..0000000000 --- a/Mage/src/main/java/mage/abilities/condition/common/WatcherCondition.java +++ /dev/null @@ -1,51 +0,0 @@ -package mage.abilities.condition.common; - -import mage.abilities.Ability; -import mage.abilities.condition.Condition; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.watchers.Watcher; - -/** - * - * @author Quercitron - */ -public class WatcherCondition implements Condition { - - private final String watcherKey; - private final WatcherScope watcherScope; - private final String text; - - public WatcherCondition(String watcherKey, WatcherScope watcherScope) { - this(watcherKey, watcherScope, ""); - } - - public WatcherCondition(String watcherKey, WatcherScope watcherScope, String text) { - this.watcherKey = watcherKey; - this.watcherScope = watcherScope; - this.text = text; - } - - @Override - public boolean apply(Game game, Ability source) { - Watcher watcher = null; - switch (watcherScope) { - case GAME: - watcher = game.getState().getWatchers().get(watcherKey); - break; - case PLAYER: - watcher = game.getState().getWatchers().get(watcherKey, source.getControllerId()); - break; - case CARD: - watcher = game.getState().getWatchers().get(watcherKey, source.getSourceId()); - break; - } - return watcher != null && watcher.conditionMet(); - } - - @Override - public String toString() { - return text; - } - -} diff --git a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java index a33a4d9bd0..d8ab429719 100644 --- a/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java +++ b/Mage/src/main/java/mage/abilities/condition/common/YouGainedLifeCondition.java @@ -18,9 +18,9 @@ public class YouGainedLifeCondition extends IntCompareCondition { @Override protected int getInputValue(Game game, Ability source) { int gainedLife = 0; - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getSimpleName()); + PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); if (watcher != null) { - gainedLife = watcher.getLiveGained(source.getControllerId()); + gainedLife = watcher.getLifeGained(source.getControllerId()); } return gainedLife; } diff --git a/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java b/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java new file mode 100644 index 0000000000..7ac35fe979 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/CostAdjuster.java @@ -0,0 +1,12 @@ +package mage.abilities.costs; + +import mage.abilities.Ability; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public interface CostAdjuster { + + void adjustCosts(Ability ability, Game game); +} diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java index 0e085bb160..a2905ea831 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayLifeCost.java @@ -1,18 +1,16 @@ - - package mage.abilities.costs.common; import mage.abilities.Ability; +import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; import mage.game.Game; +import mage.game.events.GameEvent; import java.util.UUID; -import mage.abilities.costs.Cost; /** - * * @author BetaSteward_at_googlemail.com */ public class PayLifeCost extends CostImpl { @@ -36,11 +34,12 @@ public class PayLifeCost extends CostImpl { @Override public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { - //118.4. If a cost or effect allows a player to pay an amount of life greater than 0, + //118.4. If a cost or effect allows a player to pay an amount of life greater than 0, //the player may do so only if their life total is greater than or equal to the - //amount of the payment. If a player pays life, the payment is subtracted from his or + //amount of the payment. If a player pays life, the payment is subtracted from his or //her life total; in other words, the player loses that much life. (Players can always pay 0 life.) int lifeToPayAmount = amount.calculate(game, ability, null); + // Paying 0 life is not considered paying any life. if (lifeToPayAmount > 0 && !game.getPlayer(controllerId).canPayLifeCost()) { return false; } @@ -51,6 +50,9 @@ public class PayLifeCost extends CostImpl { public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { int lifeToPayAmount = amount.calculate(game, ability, null); this.paid = game.getPlayer(controllerId).loseLife(lifeToPayAmount, game, false) == lifeToPayAmount; + if (paid) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIFE_PAID, controllerId, sourceId, controllerId, lifeToPayAmount)); + } return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/PayVariableLifeCost.java b/Mage/src/main/java/mage/abilities/costs/common/PayVariableLifeCost.java index 47cc2a91fb..4da6753e7e 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PayVariableLifeCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PayVariableLifeCost.java @@ -1,5 +1,3 @@ - - package mage.abilities.costs.common; import mage.abilities.Ability; @@ -12,7 +10,6 @@ import mage.players.Player; * * @author LevelX2 */ - public class PayVariableLifeCost extends VariableCostImpl { public PayVariableLifeCost() { @@ -21,7 +18,7 @@ public class PayVariableLifeCost extends VariableCostImpl { public PayVariableLifeCost(boolean additionalCostText) { super("life to pay"); - this.text = new StringBuilder(additionalCostText ? "as an additional cost to cast this spell, pay ":"Pay ") + this.text = new StringBuilder(additionalCostText ? "as an additional cost to cast this spell, pay " : "Pay ") .append(xText).append(' ').append("life").toString(); } @@ -44,7 +41,10 @@ public class PayVariableLifeCost extends VariableCostImpl { int maxValue = 0; Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - maxValue = controller.getLife(); + // Paying 0 life is not considered paying any life, so paying 0 is still allowed + if (game.getPlayer(source.getControllerId()).canPayLifeCost()) { + maxValue = controller.getLife(); + } } return maxValue; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java index 44fa2a8a5e..bd23597969 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/PutCardFromHandOnTopOfLibraryCost.java @@ -5,7 +5,6 @@ */ package mage.abilities.costs.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -16,8 +15,9 @@ import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInHand; +import java.util.UUID; + /** - * * @author jeffwadsworth */ @@ -40,7 +40,7 @@ public class PutCardFromHandOnTopOfLibraryCost extends CostImpl { if (targetCardInHand.canChoose(controllerId, game) && controller.choose(Outcome.PreventDamage, targetCardInHand, sourceId, game)) { card = game.getCard(targetCardInHand.getFirstTarget()); - paid = controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true); + paid = card != null && controller.moveCardToLibraryWithInfo(card, sourceId, game, Zone.HAND, true, true); } return paid; } diff --git a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java index 050cb7959c..51644679b5 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/SacrificeTargetCost.java @@ -1,9 +1,6 @@ package mage.abilities.costs.common; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; @@ -13,21 +10,32 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; +import mage.util.CardUtil; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class SacrificeTargetCost extends CostImpl { - List permanents = new ArrayList<>(); + private final List permanents = new ArrayList<>(); public SacrificeTargetCost(TargetControlledPermanent target) { this.addTarget(target); target.setNotTarget(true); // sacrifice is never targeted + target.setRequired(false); // can be canceled this.text = "sacrifice " - + ((target.getNumberOfTargets() != 1 || (target.getTargetName().startsWith("an") || target.getTargetName().startsWith("a "))) - ? "" : (target.getTargetName().startsWith("artifact") ? "an " : "a ")) + target.getTargetName(); + + ((target.getNumberOfTargets() != 1 + || (target.getTargetName().startsWith("an") + || target.getTargetName().startsWith("a "))) + ? (target.getMinNumberOfTargets() == target.getMaxNumberOfTargets() + && target.getMinNumberOfTargets() > 1 + ? CardUtil.numberToText(target.getNumberOfTargets()) + " " : "") + : (target.getTargetName().startsWith("artifact") ? "an " : "a ")) + + target.getTargetName(); target.setTargetName(target.getTargetName() + " (to sacrifice)"); } @@ -48,6 +56,7 @@ public class SacrificeTargetCost extends CostImpl { if (ability.getAbilityType() == AbilityType.ACTIVATED || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { activator = ((ActivatedAbilityImpl) ability).getActivatorId(); } + // can be cancel by user if (targets.choose(Outcome.Sacrifice, activator, sourceId, game)) { for (UUID targetId : targets.get(0).getTargets()) { Permanent permanent = game.getPermanent(targetId); diff --git a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java index cb79d1df6d..0496b89944 100644 --- a/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java +++ b/Mage/src/main/java/mage/abilities/costs/common/TapTargetCost.java @@ -1,7 +1,5 @@ - package mage.abilities.costs.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; @@ -11,8 +9,9 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetControlledPermanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class TapTargetCost extends CostImpl { @@ -22,6 +21,7 @@ public class TapTargetCost extends CostImpl { public TapTargetCost(TargetControlledPermanent target) { this.target = target; this.target.setNotTarget(true); // costs are never targeted + this.target.setRequired(false); // can be cancel by user this.text = new StringBuilder("Tap ") .append((target.getTargetName().startsWith("a ") || target.getTargetName().startsWith("an ") || target.getTargetName().startsWith("another")) @@ -52,7 +52,7 @@ public class TapTargetCost extends CostImpl { public boolean canPay(Ability ability, UUID sourceId, UUID controllerId, Game game) { return target.canChoose(sourceId, controllerId, game); } - + public TargetControlledPermanent getTarget() { return target; } diff --git a/Mage/src/main/java/mage/abilities/costs/mana/ManaSymbols.java b/Mage/src/main/java/mage/abilities/costs/mana/ManaSymbols.java index 5b7d658b31..877d21c55b 100644 --- a/Mage/src/main/java/mage/abilities/costs/mana/ManaSymbols.java +++ b/Mage/src/main/java/mage/abilities/costs/mana/ManaSymbols.java @@ -6,6 +6,7 @@ import mage.ManaSymbol; import mage.constants.ColoredManaSymbol; import java.util.ArrayList; +import java.util.EnumMap; import java.util.HashMap; import java.util.Map; @@ -16,7 +17,7 @@ import java.util.Map; */ public class ManaSymbols extends ArrayList { - private final static Map coloredManaMap = new HashMap() {{ + private static final Map coloredManaMap = new EnumMap(ColoredManaSymbol.class) {{ put(ColoredManaSymbol.W, ManaSymbol.W); put(ColoredManaSymbol.U, ManaSymbol.U); put(ColoredManaSymbol.B, ManaSymbol.B); @@ -28,23 +29,22 @@ public class ManaSymbols extends ArrayList { * Contains all possible hybrid mana costs (each represents different hybrid mana symbol) * We'll use it for converting from hybrid mana cost to hybrid mana symbol. */ - private final static Map hybridManaMap = new HashMap<>(); + private static final Map hybridManaMap = new EnumMap(ManaSymbol.class) {{ /** * Build map of all possible hybrid mana symbols assigning corresponding instance of hybrid mana cost. */ - static { - hybridManaMap.put(ManaSymbol.HYBRID_BG, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.G)); - hybridManaMap.put(ManaSymbol.HYBRID_BR, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.R)); - hybridManaMap.put(ManaSymbol.HYBRID_GU, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.U)); - hybridManaMap.put(ManaSymbol.HYBRID_GW, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.W)); - hybridManaMap.put(ManaSymbol.HYBRID_RG, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.G)); - hybridManaMap.put(ManaSymbol.HYBRID_RW, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.W)); - hybridManaMap.put(ManaSymbol.HYBRID_UB, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.B)); - hybridManaMap.put(ManaSymbol.HYBRID_UR, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.R)); - hybridManaMap.put(ManaSymbol.HYBRID_WB, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.B)); - hybridManaMap.put(ManaSymbol.HYBRID_WU, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.U)); - } + put(ManaSymbol.HYBRID_BG, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.G)); + put(ManaSymbol.HYBRID_BR, new HybridManaCost(ColoredManaSymbol.B, ColoredManaSymbol.R)); + put(ManaSymbol.HYBRID_GU, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.U)); + put(ManaSymbol.HYBRID_GW, new HybridManaCost(ColoredManaSymbol.G, ColoredManaSymbol.W)); + put(ManaSymbol.HYBRID_RG, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.G)); + put(ManaSymbol.HYBRID_RW, new HybridManaCost(ColoredManaSymbol.R, ColoredManaSymbol.W)); + put(ManaSymbol.HYBRID_UB, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.B)); + put(ManaSymbol.HYBRID_UR, new HybridManaCost(ColoredManaSymbol.U, ColoredManaSymbol.R)); + put(ManaSymbol.HYBRID_WB, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.B)); + put(ManaSymbol.HYBRID_WU, new HybridManaCost(ColoredManaSymbol.W, ColoredManaSymbol.U)); + }}; /** * Extracts mana symbols from {@link ManaCost} using {@link mage.ManaSymbol} as a base class for the mana symbols. diff --git a/Mage/src/main/java/mage/abilities/decorator/ConditionalRestrictionEffect.java b/Mage/src/main/java/mage/abilities/decorator/ConditionalRestrictionEffect.java index f33793ea6b..5f1e6318d5 100644 --- a/Mage/src/main/java/mage/abilities/decorator/ConditionalRestrictionEffect.java +++ b/Mage/src/main/java/mage/abilities/decorator/ConditionalRestrictionEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.decorator; import mage.abilities.Ability; @@ -11,7 +10,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class ConditionalRestrictionEffect extends RestrictionEffect { @@ -86,51 +84,51 @@ public class ConditionalRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { if (conditionState) { - return effect.canAttack(game); + return effect.canAttack(game, canUseChooseDialogs); } else if (otherwiseEffect != null) { - return otherwiseEffect.canAttack(game); + return otherwiseEffect.canAttack(game, canUseChooseDialogs); } return true; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { if (conditionState) { - return effect.canBlock(attacker, blocker, source, game); + return effect.canBlock(attacker, blocker, source, game, canUseChooseDialogs); } else if (otherwiseEffect != null) { - return otherwiseEffect.canBlock(attacker, blocker, source, game); + return otherwiseEffect.canBlock(attacker, blocker, source, game, canUseChooseDialogs); } return true; } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { if (conditionState) { - return effect.canBeBlocked(attacker, blocker, source, game); + return effect.canBeBlocked(attacker, blocker, source, game, canUseChooseDialogs); } else if (otherwiseEffect != null) { - return otherwiseEffect.canBeBlocked(attacker, blocker, source, game); + return otherwiseEffect.canBeBlocked(attacker, blocker, source, game, canUseChooseDialogs); } return true; } @Override - public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { if (conditionState) { - return effect.canBeUntapped(permanent, source, game); + return effect.canBeUntapped(permanent, source, game, canUseChooseDialogs); } else if (otherwiseEffect != null) { - return otherwiseEffect.canBeUntapped(permanent, source, game); + return otherwiseEffect.canBeUntapped(permanent, source, game, canUseChooseDialogs); } return true; } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { if (conditionState) { - return effect.canUseActivatedAbilities(permanent, source, game); + return effect.canUseActivatedAbilities(permanent, source, game, canUseChooseDialogs); } else if (otherwiseEffect != null) { - return otherwiseEffect.canUseActivatedAbilities(permanent, source, game); + return otherwiseEffect.canUseActivatedAbilities(permanent, source, game, canUseChooseDialogs); } return true; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/MultipliedValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/MultipliedValue.java index 55822e15f6..94a8e78487 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/MultipliedValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/MultipliedValue.java @@ -12,21 +12,21 @@ import mage.game.Game; public class MultipliedValue implements DynamicValue { private final DynamicValue value; - private final int multplier; // should be renamed to multiplier but don't want to break your stuff + private final int multiplier; public MultipliedValue(DynamicValue value, int multiplier) { this.value = value.copy(); - this.multplier = multiplier; + this.multiplier = multiplier; } MultipliedValue(final MultipliedValue dynamicValue) { this.value = dynamicValue.value.copy(); - this.multplier = dynamicValue.multplier; + this.multiplier = dynamicValue.multiplier; } @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - return multplier * value.calculate(game, sourceAbility, effect); + return multiplier * value.calculate(game, sourceAbility, effect); } @Override @@ -37,10 +37,10 @@ public class MultipliedValue implements DynamicValue { @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (multplier == 2) { + if (multiplier == 2) { sb.append("twice "); } else { - sb.append(multplier).append(" * "); + sb.append(multiplier).append(" * "); } return sb.append(value.toString()).toString(); } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java index 2dab3cdd79..43529161fe 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttachedPermanentToughnessValue.java @@ -12,29 +12,29 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author MTGfan */ -public class AttachedPermanentToughnessValue implements DynamicValue { - +public enum AttachedPermanentToughnessValue implements DynamicValue { + instance; + @Override public int calculate(Game game, Ability source, Effect effect) { Permanent enchantment = game.getPermanentOrLKIBattlefield(source.getSourceId()); Permanent enchanted = game.getPermanentOrLKIBattlefield(enchantment.getAttachedTo()); return enchanted.getToughness().getValue(); } - + @Override - public AttachedPermanentToughnessValue copy(){ - return new AttachedPermanentToughnessValue(); + public AttachedPermanentToughnessValue copy() { + return AttachedPermanentToughnessValue.instance; } - + @Override public String toString() { return "equal to"; } - - @Override + + @Override public String getMessage() { return "that creature's toughness"; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackedThisTurnOpponentsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackedThisTurnOpponentsCount.java new file mode 100644 index 0000000000..2435fda94a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/AttackedThisTurnOpponentsCount.java @@ -0,0 +1,39 @@ + +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.game.Game; +import mage.watchers.common.PlayersAttackedThisTurnWatcher; + +/** + * @author JayDi85 + */ +public enum AttackedThisTurnOpponentsCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + PlayersAttackedThisTurnWatcher watcher = game.getState().getWatcher(PlayersAttackedThisTurnWatcher.class); + if (watcher != null) { + return watcher.getAttackedOpponentsCount(sourceAbility.getControllerId()); + } + return 0; + } + + @Override + public AttackedThisTurnOpponentsCount copy() { + return AttackedThisTurnOpponentsCount.instance; + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "the number of opponents you attacked this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardTypesInGraveyardCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardTypesInGraveyardCount.java new file mode 100644 index 0000000000..32b2d55318 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardTypesInGraveyardCount.java @@ -0,0 +1,47 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.cards.Card; +import mage.constants.CardType; +import mage.game.Game; +import mage.players.Player; + +import java.util.EnumSet; + +/** + * @author JayDi85 + */ +public enum CardTypesInGraveyardCount implements DynamicValue { + + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + Player controller = game.getPlayer(sourceAbility.getControllerId()); + if (controller != null) { + EnumSet foundCardTypes = EnumSet.noneOf(CardType.class); + for (Card card : controller.getGraveyard().getCards(game)) { + foundCardTypes.addAll(card.getCardType()); + } + return foundCardTypes.size(); + } + return 0; + } + + @Override + public CardTypesInGraveyardCount copy() { + return instance; + } + + @Override + public String toString() { + return "1"; + } + + @Override + public String getMessage() { + return "the number of opponents you attacked this turn"; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllHandsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllHandsCount.java index 7220265e7b..5910f57a6c 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllHandsCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInAllHandsCount.java @@ -1,26 +1,26 @@ package mage.abilities.dynamicvalue.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.game.Game; import mage.players.Player; +import java.util.UUID; + /** - * * @author emerald000 */ -public class CardsInAllHandsCount implements DynamicValue { - +public enum CardsInAllHandsCount implements DynamicValue { + instance; + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { int count = 0; for (UUID playerId : game.getState().getPlayersInRange(sourceAbility.getControllerId(), game)) { Player player = game.getPlayer(playerId); - if (player != null) - { + if (player != null) { count += player.getHand().size(); } } @@ -29,7 +29,7 @@ public class CardsInAllHandsCount implements DynamicValue { @Override public CardsInAllHandsCount copy() { - return new CardsInAllHandsCount(); + return CardsInAllHandsCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerHandCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerHandCount.java index 476057003c..ea8cde0572 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerHandCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInControllerHandCount.java @@ -6,7 +6,8 @@ import mage.abilities.effects.Effect; import mage.game.Game; import mage.players.Player; -public class CardsInControllerHandCount implements DynamicValue { +public enum CardsInControllerHandCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -21,7 +22,7 @@ public class CardsInControllerHandCount implements DynamicValue { @Override public CardsInControllerHandCount copy() { - return new CardsInControllerHandCount(); + return CardsInControllerHandCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetHandCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetHandCount.java index dd7ac467d9..c5e63adb19 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetHandCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetHandCount.java @@ -6,7 +6,8 @@ import mage.abilities.effects.Effect; import mage.game.Game; import mage.players.Player; -public class CardsInTargetHandCount implements DynamicValue { +public enum CardsInTargetHandCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -21,7 +22,7 @@ public class CardsInTargetHandCount implements DynamicValue { @Override public DynamicValue copy() { - return new CardsInTargetHandCount(); + return CardsInTargetHandCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayerHandCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayerHandCount.java index 393f45db14..686f85b959 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayerHandCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CardsInTargetPlayerHandCount.java @@ -7,10 +7,10 @@ import mage.game.Game; import mage.players.Player; /** - * * @author cbrianhill */ -public class CardsInTargetPlayerHandCount implements DynamicValue { +public enum CardsInTargetPlayerHandCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -23,7 +23,7 @@ public class CardsInTargetPlayerHandCount implements DynamicValue { @Override public CardsInTargetPlayerHandCount copy() { - return new CardsInTargetPlayerHandCount(); + return CardsInTargetPlayerHandCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java index 94107fb35c..2663f6a040 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerGotLifeCount.java @@ -33,9 +33,9 @@ public class ControllerGotLifeCount implements DynamicValue, MageSingleton { } public int calculate(Game game, UUID controllerId) { - PlayerGainedLifeWatcher watcher = (PlayerGainedLifeWatcher) game.getState().getWatchers().get(PlayerGainedLifeWatcher.class.getSimpleName()); + PlayerGainedLifeWatcher watcher = game.getState().getWatcher(PlayerGainedLifeWatcher.class); if (watcher != null) { - return watcher.getLiveGained(controllerId); + return watcher.getLifeGained(controllerId); } return 0; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerLifeCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerLifeCount.java index e756e77e3e..512691fd8f 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerLifeCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ControllerLifeCount.java @@ -6,7 +6,8 @@ import mage.abilities.effects.Effect; import mage.game.Game; import mage.players.Player; -public class ControllerLifeCount implements DynamicValue { +public enum ControllerLifeCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -19,7 +20,7 @@ public class ControllerLifeCount implements DynamicValue { @Override public ControllerLifeCount copy() { - return new ControllerLifeCount(); + return ControllerLifeCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java index 806a27fd4c..d5b3fb0b13 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesDiedThisTurnCount.java @@ -10,11 +10,12 @@ import mage.watchers.common.CreaturesDiedWatcher; /** * @author LoneFox */ -public class CreaturesDiedThisTurnCount implements DynamicValue { +public enum CreaturesDiedThisTurnCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - CreaturesDiedWatcher watcher = (CreaturesDiedWatcher) game.getState().getWatchers().get(CreaturesDiedWatcher.class.getSimpleName()); + CreaturesDiedWatcher watcher = game.getState().getWatcher(CreaturesDiedWatcher.class); if (watcher != null) { return watcher.getAmountOfCreaturesDiedThisTurn(); } @@ -23,7 +24,7 @@ public class CreaturesDiedThisTurnCount implements DynamicValue { @Override public CreaturesDiedThisTurnCount copy() { - return new CreaturesDiedThisTurnCount(); + return CreaturesDiedThisTurnCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java new file mode 100644 index 0000000000..16ae508e8f --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/CreaturesYouControlCount.java @@ -0,0 +1,35 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.filter.StaticFilters; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum CreaturesYouControlCount implements DynamicValue { + + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield().count(StaticFilters.FILTER_CONTROLLED_CREATURES, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + } + + @Override + public CreaturesYouControlCount copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "creatures you control"; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/DiscardCostCardConvertedMana.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/DiscardCostCardConvertedMana.java index 145cf7ddaf..03e750bcc3 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/DiscardCostCardConvertedMana.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/DiscardCostCardConvertedMana.java @@ -11,7 +11,8 @@ import mage.game.Game; /** * @author LevelX2 */ -public class DiscardCostCardConvertedMana implements DynamicValue { +public enum DiscardCostCardConvertedMana implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -26,7 +27,7 @@ public class DiscardCostCardConvertedMana implements DynamicValue { @Override public DiscardCostCardConvertedMana copy() { - return new DiscardCostCardConvertedMana(); + return DiscardCostCardConvertedMana.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ExileFromHandCostCardConvertedMana.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ExileFromHandCostCardConvertedMana.java index f13c39c282..48bba82766 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ExileFromHandCostCardConvertedMana.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ExileFromHandCostCardConvertedMana.java @@ -14,10 +14,10 @@ import mage.game.Game; * cost. If no card was exiled the getManaCostsToPay().getX() will be used as * value. * - * * @author LevelX2 */ -public class ExileFromHandCostCardConvertedMana implements DynamicValue { +public enum ExileFromHandCostCardConvertedMana implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -35,7 +35,7 @@ public class ExileFromHandCostCardConvertedMana implements DynamicValue { @Override public ExileFromHandCostCardConvertedMana copy() { - return new ExileFromHandCostCardConvertedMana(); + return ExileFromHandCostCardConvertedMana.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java new file mode 100644 index 0000000000..11fe8edcb2 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GateYouControlCount.java @@ -0,0 +1,43 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.constants.SubType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum GateYouControlCount implements DynamicValue { + + instance; + private static final FilterPermanent filter = new FilterControlledPermanent("Gate you control"); + + static { + filter.add(new SubtypePredicate(SubType.GATE)); + } + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getBattlefield().count(filter, sourceAbility.getSourceId(), sourceAbility.getControllerId(), game); + } + + @Override + public GateYouControlCount copy() { + return instance; + } + + @Override + public String toString() { + return "X"; + } + + @Override + public String getMessage() { + return "gate you control"; + } +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GetXValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GetXValue.java index 07c5eefe0f..84a0302bb4 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GetXValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GetXValue.java @@ -8,14 +8,15 @@ import mage.abilities.effects.Effect; import mage.game.Game; /** - * * @author BetaSteward_at_googlemail.com */ -public class GetXValue implements DynamicValue { +public enum GetXValue implements DynamicValue { + instance; + @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { int amount = 0; - for (VariableCost cost: sourceAbility.getCosts().getVariableCosts()) { + for (VariableCost cost : sourceAbility.getCosts().getVariableCosts()) { amount += cost.getAmount(); } return amount; @@ -23,7 +24,7 @@ public class GetXValue implements DynamicValue { @Override public GetXValue copy() { - return new GetXValue(); + return GetXValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java index a668e5c337..8989267cc2 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestPowerAmongControlledCreaturesValue.java @@ -4,35 +4,31 @@ package mage.abilities.dynamicvalue.common; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; -import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author Styxo */ -public class GreatestPowerAmongControlledCreaturesValue implements DynamicValue { +public enum GreatestPowerAmongControlledCreaturesValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - Player player = game.getPlayer(sourceAbility.getControllerId()); - if (player != null) { - int amount = 0; - for (Permanent p : game.getBattlefield().getActivePermanents(new FilterControlledCreaturePermanent(), sourceAbility.getControllerId(), game)) { - if (p.getPower().getValue() > amount) { - amount = p.getPower().getValue(); - } - } - return amount; + int amount = 0; + for (Permanent p : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, sourceAbility.getControllerId(), game + )) { + amount = Math.max(p.getPower().getValue(), amount); } - return 0; + return amount; } @Override public GreatestPowerAmongControlledCreaturesValue copy() { - return new GreatestPowerAmongControlledCreaturesValue(); + return GreatestPowerAmongControlledCreaturesValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestToughnessAmongControlledCreaturesValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestToughnessAmongControlledCreaturesValue.java new file mode 100644 index 0000000000..2ffddc55f0 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/GreatestToughnessAmongControlledCreaturesValue.java @@ -0,0 +1,43 @@ + +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * @author TheElk801 + */ +public enum GreatestToughnessAmongControlledCreaturesValue implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + int amount = 0; + for (Permanent p : game.getBattlefield().getActivePermanents( + StaticFilters.FILTER_CONTROLLED_CREATURE, sourceAbility.getControllerId(), game + )) { + amount = Math.max(p.getToughness().getValue(), amount); + } + return amount; + } + + @Override + public GreatestToughnessAmongControlledCreaturesValue copy() { + return GreatestToughnessAmongControlledCreaturesValue.instance; + } + + @Override + public String getMessage() { + return "the greatest toughness among creatures you control"; + } + + @Override + public String toString() { + return "X"; + } + +} diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java index 767c185e7a..0ad7fed22b 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaSpentToCastCount.java @@ -10,13 +10,10 @@ import mage.game.Game; import mage.game.stack.Spell; /** - * * @author LevelX2 */ -public class ManaSpentToCastCount implements DynamicValue { - - public ManaSpentToCastCount() { - } +public enum ManaSpentToCastCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability source, Effect effect) { @@ -36,7 +33,7 @@ public class ManaSpentToCastCount implements DynamicValue { @Override public ManaSpentToCastCount copy() { - return new ManaSpentToCastCount(); + return ManaSpentToCastCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaTypeInManaPoolCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaTypeInManaPoolCount.java index 55dc44ddbc..5a2fc33235 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaTypeInManaPoolCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManaTypeInManaPoolCount.java @@ -1,5 +1,6 @@ package mage.abilities.dynamicvalue.common; +import mage.ConditionalMana; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; @@ -29,6 +30,9 @@ public class ManaTypeInManaPoolCount implements DynamicValue { Player player = game.getPlayer(sourceAbility.getControllerId()); if (player != null) { amount = player.getManaPool().get(manaType); + for (ConditionalMana mana : player.getManaPool().getConditionalMana()) { + amount += mana.get(manaType); + } } return amount; } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManacostVariableValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManacostVariableValue.java index e29a7a9a88..bade65f544 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManacostVariableValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ManacostVariableValue.java @@ -5,7 +5,8 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.game.Game; -public class ManacostVariableValue implements DynamicValue { +public enum ManacostVariableValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -14,7 +15,7 @@ public class ManacostVariableValue implements DynamicValue { @Override public ManacostVariableValue copy() { - return new ManacostVariableValue(); + return ManacostVariableValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/MorphManacostVariableValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/MorphManacostVariableValue.java index b3f84b9a60..bc137d87e2 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/MorphManacostVariableValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/MorphManacostVariableValue.java @@ -11,10 +11,10 @@ import mage.abilities.effects.Effect; import mage.game.Game; /** - * * @author LevelX2 */ -public class MorphManacostVariableValue implements DynamicValue { +public enum MorphManacostVariableValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -27,7 +27,7 @@ public class MorphManacostVariableValue implements DynamicValue { @Override public MorphManacostVariableValue copy() { - return new MorphManacostVariableValue(); + return MorphManacostVariableValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/MultikickerCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/MultikickerCount.java index 4d69367763..b4b583c1da 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/MultikickerCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/MultikickerCount.java @@ -9,20 +9,17 @@ import mage.cards.Card; import mage.game.Game; /** - * * @author LevelX2 */ -public class MultikickerCount implements DynamicValue { - - public MultikickerCount() { - } +public enum MultikickerCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability source, Effect effect) { int count = 0; Card card = game.getCard(source.getSourceId()); if (card != null) { - for (Ability ability: card.getAbilities()) { + for (Ability ability : card.getAbilities()) { if (ability instanceof KickerAbility) { count += ((KickerAbility) ability).getKickedCounter(game, source); } @@ -33,7 +30,7 @@ public class MultikickerCount implements DynamicValue { @Override public MultikickerCount copy() { - return new MultikickerCount(); + return MultikickerCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsCount.java new file mode 100644 index 0000000000..d8eee3f627 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsCount.java @@ -0,0 +1,33 @@ +package mage.abilities.dynamicvalue.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.effects.Effect; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum OpponentsCount implements DynamicValue { + instance; + + @Override + public int calculate(Game game, Ability sourceAbility, Effect effect) { + return game.getOpponents(sourceAbility.getControllerId()).size(); + } + + @Override + public OpponentsCount copy() { + return OpponentsCount.instance; + } + + @Override + public String getMessage() { + return "number of opponents you have"; + } + + @Override + public String toString() { + return "1"; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsLostLifeCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsLostLifeCount.java index 1133be57bd..5a566ef04f 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsLostLifeCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsLostLifeCount.java @@ -1,18 +1,19 @@ - package mage.abilities.dynamicvalue.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.game.Game; import mage.watchers.common.PlayerLostLifeWatcher; +import java.util.UUID; + /** - * * @author LevelX2 */ -public class OpponentsLostLifeCount implements DynamicValue { +public enum OpponentsLostLifeCount implements DynamicValue { + + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -20,7 +21,7 @@ public class OpponentsLostLifeCount implements DynamicValue { } public int calculate(Game game, UUID controllerId) { - PlayerLostLifeWatcher watcher = (PlayerLostLifeWatcher) game.getState().getWatchers().get(PlayerLostLifeWatcher.class.getSimpleName()); + PlayerLostLifeWatcher watcher = game.getState().getWatcher(PlayerLostLifeWatcher.class); if (watcher != null) { return watcher.getAllOppLifeLost(controllerId, game); } @@ -29,7 +30,7 @@ public class OpponentsLostLifeCount implements DynamicValue { @Override public OpponentsLostLifeCount copy() { - return new OpponentsLostLifeCount(); + return instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsPoisonCountersCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsPoisonCountersCount.java index 8851841caa..76f16fe6ad 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsPoisonCountersCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/OpponentsPoisonCountersCount.java @@ -10,7 +10,8 @@ import mage.players.Player; import java.util.Set; import java.util.UUID; -public class OpponentsPoisonCountersCount implements DynamicValue { +public enum OpponentsPoisonCountersCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -27,7 +28,7 @@ public class OpponentsPoisonCountersCount implements DynamicValue { @Override public DynamicValue copy() { - return new OpponentsPoisonCountersCount(); + return OpponentsPoisonCountersCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouOwnThatOpponentsControlCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouOwnThatOpponentsControlCount.java index 66c49c9618..3a98ec1d65 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouOwnThatOpponentsControlCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/PermanentsYouOwnThatOpponentsControlCount.java @@ -1,15 +1,17 @@ package mage.abilities.dynamicvalue.common; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.Effect; import mage.game.Game; import mage.game.permanent.Permanent; -public class PermanentsYouOwnThatOpponentsControlCount implements DynamicValue { +import java.util.Set; +import java.util.UUID; + +public enum PermanentsYouOwnThatOpponentsControlCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -28,7 +30,7 @@ public class PermanentsYouOwnThatOpponentsControlCount implements DynamicValue { @Override public PermanentsYouOwnThatOpponentsControlCount copy() { - return new PermanentsYouOwnThatOpponentsControlCount(); + return PermanentsYouOwnThatOpponentsControlCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java index 26c4584099..2b8620a561 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RemovedCountersForCostValue.java @@ -13,10 +13,10 @@ import mage.abilities.effects.Effect; import mage.game.Game; /** - * * @author LevelX2 */ -public class RemovedCountersForCostValue implements DynamicValue { +public enum RemovedCountersForCostValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -35,7 +35,7 @@ public class RemovedCountersForCostValue implements DynamicValue { @Override public RemovedCountersForCostValue copy() { - return new RemovedCountersForCostValue(); + return RemovedCountersForCostValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RevealTargetFromHandCostCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RevealTargetFromHandCostCount.java index b7574ac2f5..f9994726cc 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/RevealTargetFromHandCostCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/RevealTargetFromHandCostCount.java @@ -13,10 +13,10 @@ import mage.abilities.effects.Effect; import mage.game.Game; /** - * * @author emerald000 */ -public class RevealTargetFromHandCostCount implements DynamicValue { +public enum RevealTargetFromHandCostCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -35,7 +35,7 @@ public class RevealTargetFromHandCostCount implements DynamicValue { @Override public RevealTargetFromHandCostCount copy() { - return new RevealTargetFromHandCostCount(); + return RevealTargetFromHandCostCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesPower.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesPower.java index 290a303c88..4cdaed1a82 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesPower.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesPower.java @@ -10,8 +10,8 @@ import mage.game.Game; /** * @author LevelX2 */ -public class SacrificeCostCreaturesPower implements DynamicValue { - +public enum SacrificeCostCreaturesPower implements DynamicValue { +instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { for (Cost cost : sourceAbility.getCosts()) { @@ -26,7 +26,7 @@ public class SacrificeCostCreaturesPower implements DynamicValue { @Override public SacrificeCostCreaturesPower copy() { - return new SacrificeCostCreaturesPower(); + return SacrificeCostCreaturesPower.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesToughness.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesToughness.java index bfc03a261c..514b24f8a3 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesToughness.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SacrificeCostCreaturesToughness.java @@ -10,7 +10,8 @@ import mage.game.Game; /** * @author LevelX2 */ -public class SacrificeCostCreaturesToughness implements DynamicValue { +public enum SacrificeCostCreaturesToughness implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -25,7 +26,7 @@ public class SacrificeCostCreaturesToughness implements DynamicValue { @Override public SacrificeCostCreaturesToughness copy() { - return new SacrificeCostCreaturesToughness(); + return SacrificeCostCreaturesToughness.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/StaticValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/StaticValue.java index 0297eec66a..f5a11f8136 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/StaticValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/StaticValue.java @@ -7,8 +7,9 @@ import mage.game.Game; public class StaticValue implements DynamicValue { - private int value = 0; - private String message; + private final int value; + private final String message; + private static final StaticValue zeroValue = new StaticValue(0); public StaticValue(int value) { this(value, ""); @@ -47,4 +48,8 @@ public class StaticValue implements DynamicValue { public int getValue() { return value; } + + public static StaticValue getZeroValue() { + return zeroValue; + } } diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java index d42cc3f528..6c49909cad 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/SunburstCount.java @@ -10,14 +10,10 @@ import mage.game.stack.Spell; import mage.game.stack.StackObject; /** - * * @author Nicolas */ -public class SunburstCount implements DynamicValue { - - public SunburstCount() { - - } +public enum SunburstCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability source, Effect effect) { @@ -48,7 +44,7 @@ public class SunburstCount implements DynamicValue { @Override public SunburstCount copy() { - return new SunburstCount(); + return SunburstCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetConvertedManaCost.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetConvertedManaCost.java index 7be84e3585..26fe5ed8f5 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetConvertedManaCost.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetConvertedManaCost.java @@ -8,10 +8,10 @@ import mage.cards.Card; import mage.game.Game; /** - * * @author North */ -public class TargetConvertedManaCost implements DynamicValue { +public enum TargetConvertedManaCost implements DynamicValue { + instance; @Override public int calculate(Game game, Ability source, Effect effect) { @@ -24,7 +24,7 @@ public class TargetConvertedManaCost implements DynamicValue { @Override public TargetConvertedManaCost copy() { - return new TargetConvertedManaCost(); + return instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetPermanentPowerCount.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetPermanentPowerCount.java index 814eb19970..ab7e13d4b9 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetPermanentPowerCount.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/TargetPermanentPowerCount.java @@ -9,10 +9,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class TargetPermanentPowerCount implements DynamicValue { +public enum TargetPermanentPowerCount implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { @@ -29,7 +29,7 @@ public class TargetPermanentPowerCount implements DynamicValue { @Override public TargetPermanentPowerCount copy() { - return new TargetPermanentPowerCount(); + return TargetPermanentPowerCount.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ZuberasDiedDynamicValue.java b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ZuberasDiedDynamicValue.java index 85a86a8375..c9310b6311 100644 --- a/Mage/src/main/java/mage/abilities/dynamicvalue/common/ZuberasDiedDynamicValue.java +++ b/Mage/src/main/java/mage/abilities/dynamicvalue/common/ZuberasDiedDynamicValue.java @@ -9,17 +9,21 @@ import mage.watchers.common.ZuberasDiedWatcher; /** * Created by Eric on 9/24/2016. */ -public class ZuberasDiedDynamicValue implements DynamicValue { +public enum ZuberasDiedDynamicValue implements DynamicValue { + instance; @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - ZuberasDiedWatcher watcher = (ZuberasDiedWatcher) game.getState().getWatchers().get(ZuberasDiedWatcher.class.getSimpleName()); - return watcher.zuberasDiedThisTurn; + ZuberasDiedWatcher watcher = game.getState().getWatcher(ZuberasDiedWatcher.class); + if (watcher == null) { + return 0; + } + return watcher.getZuberasDiedThisTurn(); } @Override public ZuberasDiedDynamicValue copy() { - return new ZuberasDiedDynamicValue(); + return ZuberasDiedDynamicValue.instance; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java index dd050ce172..2369835049 100644 --- a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -19,6 +17,8 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetCardInGraveyard; +import java.util.UUID; + /** * Cards with the Aura subtype don't change the zone they are in, if there is no * valid target on the battlefield. Also, when entering the battlefield and it @@ -60,8 +60,13 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { Card card = game.getCard(event.getTargetId()); UUID sourceId = event.getSourceId(); UUID controllerId = event.getPlayerId(); + if (card == null) { + return false; + } + Card firstCardFace = null; if (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null) { + firstCardFace = card; card = card.getSecondCardFace(); if (!card.isEnchantment() || !card.hasSubtype(SubType.AURA, game)) { return false; @@ -126,7 +131,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { enchantCardInGraveyard = target instanceof TargetCardInGraveyard; if (target != null) { target.setNotTarget(true); // always not target because this way it's not handled targeted - target.clearChosen(); // neccessary if e.g. aura is blinked multiple times + target.clearChosen(); // necessary if e.g. aura is blinked multiple times } if (event.getPlayerId() != null) { @@ -149,8 +154,12 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { } Player targetPlayer = game.getPlayer(targetId); if (targetCard != null || targetPermanent != null || targetPlayer != null) { - card = game.getCard(event.getTargetId()); - card.removeFromZone(game, fromZone, sourceId); + if (firstCardFace != null) { + // transforming card. remove first face (original card) from old zone + firstCardFace.removeFromZone(game, fromZone, sourceId); + } else { + card.removeFromZone(game, fromZone, sourceId); + } PermanentCard permanent = new PermanentCard(card, (controllingPlayer == null ? card.getOwnerId() : controllingPlayer.getId()), game); ZoneChangeEvent zoneChangeEvent = new ZoneChangeEvent(permanent, controllerId, fromZone, Zone.BATTLEFIELD); permanent.updateZoneChangeCounter(game, zoneChangeEvent); @@ -184,14 +193,12 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { if (((ZoneChangeEvent) event).getToZone() == Zone.BATTLEFIELD && (((ZoneChangeEvent) event).getFromZone() != Zone.STACK)) { Card card = game.getCard(event.getTargetId()); - if (card != null && (card.isEnchantment() && card.hasSubtype(SubType.AURA, game) + return card != null && (card.isEnchantment() && card.hasSubtype(SubType.AURA, game) || // in case of transformable enchantments (game.getState().getValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + card.getId()) != null - && card.getSecondCardFace() != null - && card.getSecondCardFace().isEnchantment() - && card.getSecondCardFace().hasSubtype(SubType.AURA, game)))) { - return true; - } + && card.getSecondCardFace() != null + && card.getSecondCardFace().isEnchantment() + && card.getSecondCardFace().hasSubtype(SubType.AURA, game))); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index b6a9288166..9ecb8b9185 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -1,10 +1,5 @@ - package mage.abilities.effects; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.constants.DependencyType; @@ -13,8 +8,12 @@ import mage.constants.Layer; import mage.constants.SubLayer; import mage.game.Game; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public interface ContinuousEffect extends Effect { @@ -59,6 +58,14 @@ public interface ContinuousEffect extends Effect { void addDependedToType(DependencyType dependencyType); + void setStartingTurnNum(Game game, UUID startingController); + + int getStartingTurnNum(); + + int getNextStartingControllerTurnNum(); + + UUID getStartingController(); + @Override void newId(); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index f908f16fd9..dc72e9d494 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -1,12 +1,5 @@ - package mage.abilities.effects; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.MageSingleton; @@ -14,16 +7,12 @@ import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.DomainValue; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; -import mage.constants.AbilityType; -import mage.constants.DependencyType; -import mage.constants.Duration; -import mage.constants.EffectType; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; +import mage.constants.*; import mage.game.Game; import mage.players.Player; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ @@ -50,8 +39,9 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu protected boolean characterDefining = false; // until your next turn - protected int startingTurn; - protected UUID startingControllerId; + private int startingTurnNum; + private int yourNextTurnNum; + private UUID startingControllerId; public ContinuousEffectImpl(Duration duration, Outcome outcome) { super(outcome); @@ -79,7 +69,8 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.affectedObjectsSet = effect.affectedObjectsSet; this.affectedObjectList.addAll(effect.affectedObjectList); this.temporary = effect.temporary; - this.startingTurn = effect.startingTurn; + this.startingTurnNum = effect.startingTurnNum; + this.yourNextTurnNum = effect.yourNextTurnNum; this.startingControllerId = effect.startingControllerId; this.dependencyTypes = effect.dependencyTypes; this.dependendToTypes = effect.dependendToTypes; @@ -170,17 +161,44 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu this.affectedObjectsSet = true; } } - startingTurn = game.getTurnNum(); - startingControllerId = source.getControllerId(); + setStartingTurnNum(game, source.getControllerId()); + } + + @Override + public void setStartingTurnNum(Game game, UUID startingController) { + this.startingControllerId = startingController; + this.startingTurnNum = game.getTurnNum(); + this.yourNextTurnNum = game.isActivePlayer(startingControllerId) ? startingTurnNum + 2 : startingTurnNum + 1; + } + + public int getStartingTurnNum() { + return this.startingTurnNum; + } + + public int getNextStartingControllerTurnNum() { + return this.yourNextTurnNum; + } + + public UUID getStartingController() { + return this.startingControllerId; } @Override public boolean isInactive(Ability source, Game game) { - if (duration == Duration.UntilYourNextTurn) { + if (duration == Duration.UntilYourNextTurn || duration == Duration.UntilEndOfYourNextTurn) { Player player = game.getPlayer(startingControllerId); if (player != null) { if (player.isInGame()) { - return game.isActivePlayer(startingControllerId) && game.getTurnNum() != startingTurn; + boolean canDelete = false; + switch (duration) { + case UntilYourNextTurn: + canDelete = game.getTurnNum() >= yourNextTurnNum; + break; + case UntilEndOfYourNextTurn: + canDelete = (game.getTurnNum() > yourNextTurnNum) + || (game.getTurnNum() == yourNextTurnNum && game.getStep().getType().isAfter(PhaseStep.END_TURN)); + } + return canDelete; } return player.hasReachedNextTurnAfterLeaving(); } diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index ce14ca33b4..5f1bad6e5b 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -494,7 +494,11 @@ public class ContinuousEffects implements Serializable { if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof SplitCardHalf) { idToCheck = ((SplitCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId(); } else { - idToCheck = objectId; + if (game.getObject(objectId) instanceof SplitCardHalf) { + idToCheck = ((SplitCardHalf) game.getObject(objectId)).getParentCard().getId(); + } else { + idToCheck = objectId; + } } for (AsThoughEffect effect : asThoughEffectsList) { Set abilities = asThoughEffectsMap.get(type).getAbility(effect.getId()); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java index 7b1c66c19c..524a1eaa9a 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectsList.java @@ -1,9 +1,9 @@ - package mage.abilities.effects; import mage.abilities.Ability; import mage.abilities.MageSingleton; import mage.constants.Duration; +import mage.constants.Zone; import mage.game.Game; import org.apache.log4j.Logger; @@ -103,9 +103,15 @@ public class ContinuousEffectsList extends ArrayList break; case Custom: case UntilYourNextTurn: + case UntilEndOfYourNextTurn: if (effect.isInactive(ability, game)) { it.remove(); } + break; + case UntilSourceLeavesBattlefield: + if (Zone.BATTLEFIELD != game.getState().getZone(ability.getSourceId())) { + it.remove(); + } } } } diff --git a/Mage/src/main/java/mage/abilities/effects/Effect.java b/Mage/src/main/java/mage/abilities/effects/Effect.java index f956b7bf7d..07312ebdf1 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effect.java +++ b/Mage/src/main/java/mage/abilities/effects/Effect.java @@ -1,8 +1,5 @@ - package mage.abilities.effects; -import java.io.Serializable; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.constants.EffectType; @@ -10,8 +7,10 @@ import mage.constants.Outcome; import mage.game.Game; import mage.target.targetpointer.TargetPointer; +import java.io.Serializable; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public interface Effect extends Serializable { @@ -64,4 +63,7 @@ public interface Effect extends Serializable { Effect copy(); + Effect concatBy(String concatPrefix); + + String getConcatPrefix(); } diff --git a/Mage/src/main/java/mage/abilities/effects/EffectImpl.java b/Mage/src/main/java/mage/abilities/effects/EffectImpl.java index f640ec9aad..65e0bbada8 100644 --- a/Mage/src/main/java/mage/abilities/effects/EffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/EffectImpl.java @@ -1,9 +1,5 @@ - package mage.abilities.effects; -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; import mage.abilities.MageSingleton; import mage.abilities.Mode; import mage.constants.EffectType; @@ -11,8 +7,11 @@ import mage.constants.Outcome; import mage.target.targetpointer.FirstTargetPointer; import mage.target.targetpointer.TargetPointer; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public abstract class EffectImpl implements Effect { @@ -23,7 +22,7 @@ public abstract class EffectImpl implements Effect { protected TargetPointer targetPointer = FirstTargetPointer.getInstance(); protected String staticText = ""; protected Map values; - protected boolean applyEffectsAfter = false; + protected String concatPrefix = ""; // combines multiple effects in text rule public EffectImpl(Outcome outcome) { this.id = UUID.randomUUID(); @@ -36,6 +35,7 @@ public abstract class EffectImpl implements Effect { this.staticText = effect.staticText; this.effectType = effect.effectType; this.targetPointer = effect.targetPointer.copy(); + this.concatPrefix = effect.concatPrefix; if (effect.values != null) { values = new HashMap<>(); Map map = effect.values; @@ -43,7 +43,6 @@ public abstract class EffectImpl implements Effect { values.put(entry.getKey(), entry.getValue()); } } - this.applyEffectsAfter = effect.applyEffectsAfter; } @Override @@ -112,4 +111,15 @@ public abstract class EffectImpl implements Effect { } return values.get(key); } + + @Override + public Effect concatBy(String concatPrefix) { + this.concatPrefix = concatPrefix; + return this; + } + + @Override + public String getConcatPrefix() { + return this.concatPrefix; + } } diff --git a/Mage/src/main/java/mage/abilities/effects/Effects.java b/Mage/src/main/java/mage/abilities/effects/Effects.java index cb32b8471a..df2661806b 100644 --- a/Mage/src/main/java/mage/abilities/effects/Effects.java +++ b/Mage/src/main/java/mage/abilities/effects/Effects.java @@ -1,16 +1,15 @@ - package mage.abilities.effects; +import mage.abilities.Mode; +import mage.constants.Outcome; +import mage.target.targetpointer.TargetPointer; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import mage.abilities.Mode; -import mage.constants.Outcome; -import mage.target.targetpointer.TargetPointer; /** - * * @author BetaSteward_at_googlemail.com */ public class Effects extends ArrayList { @@ -43,11 +42,25 @@ public class Effects extends ArrayList { public String getText(Mode mode) { StringBuilder sbText = new StringBuilder(); String lastRule = null; + int effectNum = 0; for (Effect effect : this) { String endString = ""; String nextRule = effect.getText(mode); + + // ignore empty rules + if (nextRule == null || nextRule.isEmpty()) { + continue; + } + effectNum++; + + // concat effects (default: each effect with a new sentence) + String concatPrefix = effect.getConcatPrefix(); + if (effectNum > 1 && !concatPrefix.isEmpty() && !concatPrefix.equals(".")) { + nextRule = concatPrefix + " " + nextRule; + } + if (nextRule != null) { - if (nextRule.startsWith("and ") || nextRule.startsWith("with ")) { + if (nextRule.startsWith("and ") || nextRule.startsWith("with ") || nextRule.startsWith("then ")) { endString = " "; } else if (nextRule.startsWith(",") || nextRule.startsWith(" ")) { endString = ""; @@ -63,6 +76,7 @@ public class Effects extends ArrayList { } lastRule = nextRule; } + if (lastRule != null && lastRule.length() > 3 && !lastRule.endsWith(".") && !lastRule.endsWith("\"") @@ -71,6 +85,7 @@ public class Effects extends ArrayList { && !lastRule.endsWith("
    ")) { sbText.append('.'); } + return sbText.toString(); } diff --git a/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java b/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java new file mode 100644 index 0000000000..81c1e19e28 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/PreventDamageAndRemoveCountersEffect.java @@ -0,0 +1,60 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects; + +import mage.abilities.Ability; +import mage.constants.Duration; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; + +/** + * + * @author antoni-g + */ +public class PreventDamageAndRemoveCountersEffect extends PreventionEffectImpl { + + public PreventDamageAndRemoveCountersEffect() { + super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false); + staticText = "If damage would be dealt to {this}, prevent that damage and remove that many +1/+1 counters from it"; + } + + public PreventDamageAndRemoveCountersEffect(final PreventDamageAndRemoveCountersEffect effect) { + super(effect); + } + + @Override + public PreventDamageAndRemoveCountersEffect copy() { + return new PreventDamageAndRemoveCountersEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + int damage = event.getAmount(); + preventDamageAction(event, source, game); + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent != null) { + permanent.removeCounters(CounterType.P1P1.createInstance(damage), game); //MTG ruling (this) loses counters even if the damage isn't prevented + } + return false; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (super.applies(event, source, game)) { + if (event.getTargetId().equals(source.getSourceId())) { + return true; + } + } + return false; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java b/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java index afea25b950..262d7ab3be 100644 --- a/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/RedirectionEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects; import mage.MageObject; @@ -47,6 +46,7 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl { this.redirectTarget = effect.redirectTarget; this.amountToRedirect = effect.amountToRedirect; this.usageType = effect.usageType; + this.applyEffectsCounter = effect.applyEffectsCounter; } @Override @@ -80,6 +80,7 @@ public abstract class RedirectionEffect extends ReplacementEffectImpl { if (applyEffectsCounter > 0) { if (applyEffectsCounter < game.getState().getApplyEffectsCounter()) { this.discard(); + return false; } } else { applyEffectsCounter = game.getState().getApplyEffectsCounter(); diff --git a/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java b/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java index b1dc7e3a9e..14cf8b38b4 100644 --- a/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/RestrictionEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects; -import java.util.UUID; import mage.abilities.Ability; import mage.constants.Duration; import mage.constants.EffectType; @@ -9,8 +7,9 @@ import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public abstract class RestrictionEffect extends ContinuousEffectImpl { @@ -35,27 +34,44 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { public abstract boolean applies(Permanent permanent, Ability source, Game game); - public boolean canAttack(Game game) { + // canUseChooseDialogs -- restrict checks can be called by rules engine and by card info engine, + // last one uses for info only and can't use dialogs, e.g. canUseChooseDialogs = false + + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return true; } - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + /** + * @param attacker + * @param defenderId id of planeswalker or player to attack, can be empty for general checks + * @param source + * @param game + * @return + */ + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + /** + * @param attacker can be empty for general checks + * @param blocker + * @param source + * @param game + * @return + */ + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canBlockCheckAfter(Ability source, Game game) { + public boolean canBlockCheckAfter(Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return true; } @@ -68,19 +84,19 @@ public abstract class RestrictionEffect extends ContinuousEffectImpl { * @return true = block is ok false = block is not valid (human: back to * defining blockers, AI: remove blocker) */ - public boolean canBeBlockedCheckAfter(Permanent attacker, Ability source, Game game) { + public boolean canBeBlockedCheckAfter(Permanent attacker, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return true; } - public boolean canTransform(Permanent permanent, Ability source, Game game) { + public boolean canTransform(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CantAttackBlockTransformAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CantAttackBlockTransformAttachedEffect.java index 6428f841a5..ab4726fa42 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CantAttackBlockTransformAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CantAttackBlockTransformAttachedEffect.java @@ -12,7 +12,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author halljared */ public class CantAttackBlockTransformAttachedEffect extends RestrictionEffect { @@ -30,25 +29,23 @@ public class CantAttackBlockTransformAttachedEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { - if (permanent.getId().equals(enchantment.getAttachedTo())) { - return true; - } + return permanent.getId().equals(enchantment.getAttachedTo()); } return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canTransform(Permanent permanent, Ability source, Game game) { + public boolean canTransform(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java index 86edae8d1f..79aea129af 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseACardNameEffect.java @@ -13,7 +13,6 @@ import mage.players.Player; import mage.util.CardUtil; /** - * * @author LevelX2 */ public class ChooseACardNameEffect extends OneShotEffect { @@ -92,11 +91,11 @@ public class ChooseACardNameEffect extends OneShotEffect { if (controller.choose(Outcome.Detriment, cardChoice, game)) { String cardName = cardChoice.getChoice(); if (!game.isSimulation()) { - game.informPlayers(sourceObject.getLogName() + ", named card: [" + cardName + ']'); + game.informPlayers(sourceObject.getLogName() + ", chosen name: [" + cardName + ']'); } game.getState().setValue(source.getSourceId().toString() + INFO_KEY, cardName); if (sourceObject instanceof Permanent) { - ((Permanent) sourceObject).addInfo(INFO_KEY, CardUtil.addToolTipMarkTags("Named card: " + cardName), game); + ((Permanent) sourceObject).addInfo(INFO_KEY, CardUtil.addToolTipMarkTags("Chosen name: " + cardName), game); } return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java index 7964752d8c..a078a57c80 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseLandTypeEffect.java @@ -5,7 +5,6 @@ */ package mage.abilities.effects.common; -import java.util.stream.Collectors; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; @@ -18,8 +17,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.util.CardUtil; +import java.util.stream.Collectors; + /** - * * @author fireshoes */ public class ChooseLandTypeEffect extends OneShotEffect { @@ -43,7 +43,7 @@ public class ChooseLandTypeEffect extends OneShotEffect { if (controller != null && mageObject != null) { Choice typeChoice = new ChoiceImpl(true); typeChoice.setMessage("Choose land type"); - typeChoice.setChoices(SubType.getLandTypes(false).stream().map(SubType::toString).collect(Collectors.toSet())); + typeChoice.setChoices(SubType.getLandTypes().stream().map(SubType::toString).collect(Collectors.toSet())); if (controller.choose(outcome, typeChoice, game)) { if (!game.isSimulation()) { game.informPlayers(mageObject.getName() + ": " + controller.getLogName() + " has chosen " + typeChoice.getChoice()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ChooseModeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ChooseModeEffect.java index c58092acb3..5189e93f9a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ChooseModeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ChooseModeEffect.java @@ -19,7 +19,7 @@ import mage.players.Player; */ public class ChooseModeEffect extends OneShotEffect { - protected final List modes = new ArrayList(); + protected final List modes = new ArrayList<>(); protected final String choiceMessage; public ChooseModeEffect(String choiceMessage, String... modes) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java index 9dd49c7ea6..72b22fc266 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CipherEffect.java @@ -1,7 +1,6 @@ package mage.abilities.effects.common; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -20,11 +19,13 @@ import mage.players.Player; import mage.target.common.TargetControlledCreaturePermanent; import mage.target.targetpointer.FixedTarget; +import java.util.UUID; + /** * FAQ 2013/01/11 - * + *

    * 702.97. Cipher - * + *

    * 702.97a Cipher appears on some instants and sorceries. It represents two * static abilities, one that functions while the spell is on the stack and one * that functions while the card with cipher is in the exile zone. "Cipher" @@ -33,17 +34,17 @@ import mage.target.targetpointer.FixedTarget; * that creature, that creature has 'Whenever this creature deals combat damage * to a player, you may copy this card and you may cast the copy without paying * its mana cost.'" - * + *

    * 702.97b The term "encoded" describes the relationship between the card with * cipher while in the exile zone and the creature chosen when the spell * represented by that card resolves. - * + *

    * 702.97c The card with cipher remains encoded on the chosen creature as long * as the card with cipher remains exiled and the creature remains on the * battlefield. The card remains encoded on that object even if it changes * controller or stops being a creature, as long as it remains on the * battlefield. - * + *

    * TODO: Implement Cipher as two static abilities concerning the rules. * * @author LevelX2 @@ -114,20 +115,13 @@ class CipherStoreEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); Card cipherCard = game.getCard(cipherCardId); - if (cipherCard != null) { + if (cipherCard != null && controller != null) { Card copyCard = game.copyCard(cipherCard, source, controller.getId()); SpellAbility ability = copyCard.getSpellAbility(); // remove the cipher effect from the copy - Effect cipherEffect = null; - for (Effect effect : ability.getEffects()) { - if (effect instanceof CipherEffect) { - cipherEffect = effect; - } - } - ability.getEffects().remove(cipherEffect); - if (ability instanceof SpellAbility) { - controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); - } + ability.getEffects().removeIf(effect -> effect instanceof CipherEffect); + controller.cast(ability, game, true, new MageObjectReference(source.getSourceObject(game), game)); + } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java index b582f29130..d75fda572e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -16,7 +15,6 @@ import mage.util.functions.ApplyToPermanent; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class CopyEffect extends ContinuousEffectImpl { @@ -90,7 +88,13 @@ public class CopyEffect extends ContinuousEffectImpl { } protected boolean copyToPermanent(Permanent permanent, Game game, Ability source) { - permanent.setCopy(true); + if (copyFromObject.getCopyFrom() != null) { + // copy from temp blueprints (they are already copies) + permanent.setCopy(true, copyFromObject.getCopyFrom()); + } else { + // copy object to object + permanent.setCopy(true, copyFromObject); + } permanent.setName(copyFromObject.getName()); permanent.getColor(game).setColor(copyFromObject.getColor(game)); permanent.getManaCost().clear(); @@ -118,8 +122,12 @@ public class CopyEffect extends ContinuousEffectImpl { permanent.addAbility(ability, getSourceId(), game, false); // no new Id so consumed replacement effects are known while new continuousEffects.apply happen. } } - permanent.getPower().setValue(copyFromObject.getPower().getValue()); - permanent.getToughness().setValue(copyFromObject.getToughness().getValue()); + + // Primal Clay example: + // If a creature that’s already on the battlefield becomes a copy of this creature, it copies the power, toughness, + // and abilities that were chosen for this creature as it entered the battlefield. (2018-03-16) + permanent.getPower().setValue(copyFromObject.getPower().getBaseValueModified()); + permanent.getToughness().setValue(copyFromObject.getToughness().getBaseValueModified()); if (copyFromObject instanceof Permanent) { Permanent targetPermanent = (Permanent) copyFromObject; permanent.setTransformed(targetPermanent.isTransformed()); diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java index d74258916f..c8aeb347db 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyPermanentEffect.java @@ -1,12 +1,12 @@ package mage.abilities.effects.common; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.SpellAbility; import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; +import mage.abilities.keyword.EnchantAbility; import mage.constants.Outcome; import mage.constants.SubType; import mage.filter.FilterPermanent; @@ -20,8 +20,9 @@ import mage.target.TargetPermanent; import mage.util.functions.ApplyToPermanent; import mage.util.functions.EmptyApplyToPermanent; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class CopyPermanentEffect extends OneShotEffect { @@ -59,7 +60,9 @@ public class CopyPermanentEffect extends OneShotEffect { super(effect); this.filter = effect.filter.copy(); this.applier = effect.applier; - this.bluePrintPermanent = effect.bluePrintPermanent; + if (effect.bluePrintPermanent != null) { + this.bluePrintPermanent = effect.bluePrintPermanent.copy(); + } this.useTargetOfAbility = effect.useTargetOfAbility; } @@ -84,42 +87,70 @@ public class CopyPermanentEffect extends OneShotEffect { } if (copyFromPermanent != null) { bluePrintPermanent = game.copyPermanent(copyFromPermanent, sourcePermanent.getId(), source, applier); - - //if object is a copy of an aura, it needs to attach - if (bluePrintPermanent.hasSubtype(SubType.AURA, game)){ + if (bluePrintPermanent == null) { + return false; + } + + // if object is a copy of an aura, it needs to attach again for new target + if (bluePrintPermanent.hasSubtype(SubType.AURA, game)) { //copied from mage.cards.c.CopyEnchantment.java - Target target = bluePrintPermanent.getSpellAbility().getTargets().get(0); + + // permanent can be attached (Estrid's Mask) or enchant (Utopia Sprawl) + // TODO: fix Animate Dead -- it's can't be copied (can't retarget) Outcome auraOutcome = Outcome.BoostCreature; + Target auraTarget = null; + + // attach - search effect in spell ability (example: cast Utopia Sprawl, cast Estrid's Invocation on it) for (Ability ability : bluePrintPermanent.getAbilities()) { if (ability instanceof SpellAbility) { for (Effect effect : ability.getEffects()) { if (effect instanceof AttachEffect) { - auraOutcome = effect.getOutcome(); + if (bluePrintPermanent.getSpellAbility().getTargets().size() > 0) { + auraTarget = bluePrintPermanent.getSpellAbility().getTargets().get(0); + auraOutcome = effect.getOutcome(); + } } } } } - - /*if this is a copy of a copy, the copy's target has been - *copied and needs to be cleared - */ - { - UUID targetId = target.getFirstTarget(); - if(targetId != null) - target.remove(targetId); + + // enchant - search in all abilities (example: cast Estrid's Invocation on enchanted creature by Estrid, the Masked second ability, cast Estrid's Invocation on it) + if (auraTarget == null) { + for (Ability ability : bluePrintPermanent.getAbilities()) { + if (ability instanceof EnchantAbility) { + if (ability.getTargets().size() > 0) { // Animate Dead don't have targets + auraTarget = ability.getTargets().get(0); + for (Effect effect : ability.getEffects()) { + // first outcome + auraOutcome = effect.getOutcome(); + } + } + } + } } - - target.setNotTarget(true); - if (controller.choose(auraOutcome, target, source.getSourceId(), game)) { - UUID targetId = target.getFirstTarget(); - Permanent targetPermanent = game.getPermanent(targetId); - Player targetPlayer = game.getPlayer(targetId); - if (targetPermanent != null) { - targetPermanent.addAttachment(sourcePermanent.getId(), game); - } else if (targetPlayer != null) { - targetPlayer.addAttachment(sourcePermanent.getId(), game); - } else { - return false; + + /* if this is a copy of a copy, the copy's target has been + * copied and needs to be cleared + */ + if (auraTarget != null) { + // clear selected target + if (auraTarget.getFirstTarget() != null) { + auraTarget.remove(auraTarget.getFirstTarget()); + } + + // select new target + auraTarget.setNotTarget(true); + if (controller.choose(auraOutcome, auraTarget, source.getSourceId(), game)) { + UUID targetId = auraTarget.getFirstTarget(); + Permanent targetPermanent = game.getPermanent(targetId); + Player targetPlayer = game.getPlayer(targetId); + if (targetPermanent != null) { + targetPermanent.addAttachment(sourcePermanent.getId(), game); + } else if (targetPlayer != null) { + targetPlayer.addAttachment(sourcePermanent.getId(), game); + } else { + return false; + } } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java index 040be4c85d..c3a4879b4d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CopyTargetSpellEffect.java @@ -1,8 +1,8 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.Zone; @@ -13,12 +13,12 @@ import mage.players.Player; /** * @author BetaSteward_at_googlemail.com - * */ public class CopyTargetSpellEffect extends OneShotEffect { private final boolean useController; private final boolean useLKI; + private String copyThatSpellName = "that spell"; public CopyTargetSpellEffect() { this(false); @@ -38,6 +38,12 @@ public class CopyTargetSpellEffect extends OneShotEffect { super(effect); this.useLKI = effect.useLKI; this.useController = effect.useController; + this.copyThatSpellName = effect.copyThatSpellName; + } + + public Effect withSpellName(String copyThatSpellName) { + this.copyThatSpellName = copyThatSpellName; + return this; } @Override @@ -79,7 +85,14 @@ public class CopyTargetSpellEffect extends OneShotEffect { return staticText; } StringBuilder sb = new StringBuilder(); - sb.append("copy target ").append(mode.getTargets().get(0).getTargetName()).append(". You may choose new targets for the copy"); + sb.append("copy "); + if (!mode.getTargets().isEmpty()) { + sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + } else { + sb.append(copyThatSpellName); + } + sb.append(". You may choose new targets for the copy"); + return sb.toString(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java index 092c8ec92c..8f90639c3b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenCopyTargetEffect.java @@ -1,8 +1,5 @@ package mage.abilities.effects.common; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.ObjectColor; import mage.abilities.Ability; @@ -14,11 +11,7 @@ import mage.abilities.effects.OneShotEffect; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.HasteAbility; import mage.cards.Card; -import mage.constants.CardType; -import mage.constants.Outcome; -import mage.constants.SubType; -import mage.constants.SuperType; -import mage.constants.Zone; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.EmptyToken; @@ -27,8 +20,11 @@ import mage.util.CardUtil; import mage.util.functions.ApplyToPermanent; import mage.util.functions.EmptyApplyToPermanent; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public class CreateTokenCopyTargetEffect extends OneShotEffect { @@ -73,12 +69,11 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { } /** - * - * @param playerId null the token is controlled/owned by the controller of - * the source ability + * @param playerId null the token is controlled/owned by the controller of + * the source ability * @param additionalCardType the token gains this card type in addition - * @param hasHaste the token gains haste - * @param number number of tokens to put into play + * @param hasHaste the token gains haste + * @param number number of tokens to put into play * @param tapped * @param attacking */ @@ -165,7 +160,7 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect { copyFrom = game.getCard(getTargetPointer().getFirst(game, source)); } - if (permanent == null && copyFrom == null) { + if (copyFrom == null) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenTargetEffect.java index 2d37250007..15bc8d25af 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/CreateTokenTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/CreateTokenTargetEffect.java @@ -69,7 +69,14 @@ public class CreateTokenTargetEffect extends OneShotEffect { return staticText; } StringBuilder sb = new StringBuilder(); - sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + + if (mode.getTargets().isEmpty()) { + sb.append("target player"); + } + else { + sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + } + sb.append(" creates "); if (amount.toString().equals("1")) { sb.append("a "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java index 5aa4b5c5b9..626b7225cb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DamageTargetEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; @@ -14,8 +12,9 @@ import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com * @author North */ @@ -161,11 +160,15 @@ public class DamageTargetEffect extends OneShotEffect { if (!targetDescription.isEmpty()) { sb.append(targetDescription); } else { - String targetName = mode.getTargets().get(0).getTargetName(); - if (targetName.contains("any")) { - sb.append(targetName); + if (!mode.getTargets().isEmpty()) { + String targetName = mode.getTargets().get(0).getTargetName(); + if (targetName.contains("any")) { + sb.append(targetName); + } else { + sb.append("target ").append(targetName); + } } else { - sb.append("target ").append(targetName); + sb.append("that target"); } } if (!message.isEmpty()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java index a2ef730ccd..cc767a1a60 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyAllNamedPermanentsEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -11,9 +9,9 @@ import mage.filter.predicate.mageobject.NamePredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.util.CardUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class DestroyAllNamedPermanentsEffect extends OneShotEffect { @@ -38,12 +36,12 @@ public class DestroyAllNamedPermanentsEffect extends OneShotEffect { return false; } FilterPermanent filter = new FilterPermanent(); - if (targetPermanent.getName().isEmpty()) { + if (CardUtil.haveEmptyName(targetPermanent)) { filter.add(new PermanentIdPredicate(targetPermanent.getId())); // if no name (face down creature) only the creature itself is selected } else { filter.add(new NamePredicate(targetPermanent.getName())); } - for (Permanent perm: game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + for (Permanent perm : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { perm.destroy(source.getSourceId(), game, false); } return true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroySourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroySourceEffect.java index 1c2262f414..6ce1a75c8c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroySourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroySourceEffect.java @@ -38,7 +38,9 @@ public class DestroySourceEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = source.getSourcePermanentIfItStillExists(game); - if (permanent != null) { + if (permanent != null + && permanent.isPhasedIn() + && !permanent.isPhasedOutIndirectly()) { permanent.destroy(source.getSourceId(), game, noRegen); return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetEffect.java index 6c86bed0a1..6ac8f7ab1c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DestroyTargetEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -13,8 +11,9 @@ import mage.target.targetpointer.FirstTargetPointer; import mage.target.targetpointer.SecondTargetPointer; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class DestroyTargetEffect extends OneShotEffect { @@ -27,14 +26,18 @@ public class DestroyTargetEffect extends OneShotEffect { } public DestroyTargetEffect(String ruleText) { - this(false); - staticText = ruleText; + this(ruleText, false); } public DestroyTargetEffect(boolean noRegen) { this(noRegen, false); } + public DestroyTargetEffect(String ruleText, boolean noRegen) { + this(noRegen, false); + staticText = ruleText; + } + public DestroyTargetEffect(boolean noRegen, boolean multitargetHandling) { super(Outcome.DestroyPermanent); this.noRegen = noRegen; @@ -55,11 +58,15 @@ public class DestroyTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { int affectedTargets = 0; - if (multitargetHandling && source.getTargets().size() > 1 && targetPointer instanceof FirstTargetPointer) { // Decimate + if (multitargetHandling + && source.getTargets().size() > 1 + && targetPointer instanceof FirstTargetPointer) { // Decimate for (Target target : source.getTargets()) { for (UUID permanentId : target.getTargets()) { Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { + if (permanent != null + && permanent.isPhasedIn() + && !permanent.isPhasedOutIndirectly()) { permanent.destroy(source.getSourceId(), game, noRegen); affectedTargets++; } @@ -68,7 +75,9 @@ public class DestroyTargetEffect extends OneShotEffect { } else { for (UUID permanentId : targetPointer.getTargets(game, source)) { Permanent permanent = game.getPermanent(permanentId); - if (permanent != null) { + if (permanent != null + && permanent.isPhasedIn() + && !permanent.isPhasedOutIndirectly()) { permanent.destroy(source.getSourceId(), game, noRegen); affectedTargets++; } @@ -100,7 +109,12 @@ public class DestroyTargetEffect extends OneShotEffect { } sb.append(targetName); } else { - sb.append("Destroy ").append(CardUtil.numberToText(target.getNumberOfTargets())).append(" target ").append(target.getTargetName()); + if (target.getMaxNumberOfTargets() == target.getMinNumberOfTargets()) { + sb.append("destroy ").append(CardUtil.numberToText(target.getNumberOfTargets())); + } else { + sb.append("destroy up to ").append(CardUtil.numberToText(target.getMaxNumberOfTargets())); + } + sb.append(" target ").append(target.getTargetName()); } } if (noRegen) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java index 410568577f..99c5c5b07b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainAllEffect.java @@ -1,9 +1,5 @@ - package mage.abilities.effects.common; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.RestrictionEffect; @@ -16,8 +12,11 @@ import mage.game.permanent.Permanent; import mage.game.turn.Step; import mage.target.targetpointer.FixedTarget; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public class DetainAllEffect extends OneShotEffect { @@ -110,17 +109,17 @@ class DetainAllRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java index 57b2a4c89f..b4e169e807 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DetainTargetEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -16,8 +14,9 @@ import mage.target.Target; import mage.target.common.TargetCreaturePermanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * @author LevelX2 */ // @@ -137,17 +136,17 @@ class DetainRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java index 1bf91e308d..2394b15275 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DevourEffect.java @@ -41,7 +41,7 @@ public class DevourEffect extends ReplacementEffectImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures to devour"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } private final DevourFactor devourFactor; diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java index 845fe9e5a4..5a8c7f408d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoIfCostPaid.java @@ -1,6 +1,5 @@ package mage.abilities.effects.common; -import java.util.Locale; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -14,6 +13,8 @@ import mage.game.Game; import mage.players.Player; import mage.util.CardUtil; +import java.util.Locale; + public class DoIfCostPaid extends OneShotEffect { protected Effects executingEffects = new Effects(); @@ -27,9 +28,10 @@ public class DoIfCostPaid extends OneShotEffect { } public DoIfCostPaid(Effect effect, Effect effect2, Cost cost) { - this(effect,effect2,cost,true); + this(effect, effect2, cost, true); } - public DoIfCostPaid(Effect effect, Effect effect2, Cost cost,boolean optional) { + + public DoIfCostPaid(Effect effect, Effect effect2, Cost cost, boolean optional) { this(effect, cost, null, optional); this.otherwiseEffects.add(effect2); } @@ -62,6 +64,14 @@ public class DoIfCostPaid extends OneShotEffect { return this; } + public Effects getExecutingEffects() { + return this.executingEffects; + } + + public Effects getOtherwiseEffects() { + return this.otherwiseEffects; + } + @Override public boolean apply(Game game, Ability source) { Player player = getPayingPlayer(game, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java index 4c2208e00c..8368248a15 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DoUnlessAnyPlayerPaysEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import java.util.UUID; @@ -6,6 +5,8 @@ import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; @@ -22,15 +23,22 @@ import mage.util.CardUtil; public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { protected Effects executingEffects = new Effects(); - private final Cost cost; + protected Cost cost; private String chooseUseText; + protected DynamicValue genericMana; + + public DoUnlessAnyPlayerPaysEffect(Effect effect, DynamicValue genericMana) { + super(Outcome.Detriment); + this.genericMana = genericMana; + this.executingEffects.add(effect); + } public DoUnlessAnyPlayerPaysEffect(Effect effect, Cost cost) { this(effect, cost, null); } public DoUnlessAnyPlayerPaysEffect(Effect effect, Cost cost, String chooseUseText) { - super(Outcome.Benefit); + super(Outcome.Neutral); this.executingEffects.add(effect); this.cost = cost; this.chooseUseText = chooseUseText; @@ -38,8 +46,13 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { public DoUnlessAnyPlayerPaysEffect(final DoUnlessAnyPlayerPaysEffect effect) { super(effect); + if (effect.cost != null) { + this.cost = effect.cost.copy(); + } + if (effect.genericMana != null) { + this.genericMana = effect.genericMana.copy(); + } this.executingEffects = effect.executingEffects.copy(); - this.cost = effect.cost.copy(); this.chooseUseText = effect.chooseUseText; } @@ -51,11 +64,18 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller != null && sourceObject != null) { + Cost costToPay; + if (controller != null + && sourceObject != null) { + if (cost != null) { + costToPay = cost.copy(); + } else { + costToPay = new GenericManaCost(genericMana.calculate(game, source, this)); + } String message; if (chooseUseText == null) { String effectText = executingEffects.getText(source.getModes().getMode()); - message = "Pay " + cost.getText() + " to prevent (" + effectText.substring(0, effectText.length() - 1) + ")?"; + message = "Pay " + costToPay.getText() + " to prevent (" + effectText.substring(0, effectText.length() - 1) + ")?"; } else { message = chooseUseText; } @@ -65,9 +85,10 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { // check if any player is willing to pay for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null && cost.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { - cost.clearPaid(); - if (cost.pay(source, game, source.getSourceId(), player.getId(), false, null)) { + if (player != null + && costToPay.canPay(source, source.getSourceId(), player.getId(), game) && player.chooseUse(Outcome.Detriment, message, source, game)) { + costToPay.clearPaid(); + if (costToPay.pay(source, game, source.getSourceId(), player.getId(), false, null)) { if (!game.isSimulation()) { game.informPlayers(player.getLogName() + " pays the cost to prevent the effect"); } @@ -100,8 +121,18 @@ public class DoUnlessAnyPlayerPaysEffect extends OneShotEffect { if (!staticText.isEmpty()) { return staticText; } + StringBuilder sb = new StringBuilder(); + if (cost != null) { + sb.append(cost.getText()); + } else { + sb.append("{X}"); + } + if (genericMana != null && !genericMana.getMessage().isEmpty()) { + sb.append(", where X is "); + sb.append(genericMana.getMessage()); + } String effectsText = executingEffects.getText(mode); - return effectsText.substring(0, effectsText.length() - 1) + " unless any player pays " + cost.getText(); + return effectsText.substring(0, effectsText.length() - 1) + " unless any player pays " + sb.toString(); } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java index 49d5651cbf..41200f26f0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersNextUntapStepTargetEffect.java @@ -32,7 +32,6 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR * Attention: This effect won't work with targets controlled by different * controllers If this is needed, the validForTurnNum has to be saved per * controller. - * */ public DontUntapInControllersNextUntapStepTargetEffect() { this(""); @@ -43,10 +42,9 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR } /** - * - * @param targetName used as target text for the generated rule text + * @param targetName used as target text for the generated rule text * @param onlyIfControlledByPlayer the effect only works if the permanent is - * controlled by that controller, null = it works for all players + * controlled by that controller, null = it works for all players */ public DontUntapInControllersNextUntapStepTargetEffect(String targetName, UUID onlyIfControlledByPlayer) { this(targetName, false, onlyIfControlledByPlayer); @@ -116,7 +114,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR } } } - + if (allHandled) { discard(); } @@ -149,8 +147,7 @@ public class DontUntapInControllersNextUntapStepTargetEffect extends ContinuousR } else return targetName + " doesn't untap during its controller's next " + (twoSteps ? "two " : "") + "untap step" + (twoSteps ? "s" : ""); } else { - return "target " + (mode == null ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next " + (twoSteps ? "two " : "") + "untap step" + (twoSteps ? "s" : ""); + return "target " + (mode == null || mode.getTargets().isEmpty() ? "creature" : mode.getTargets().get(0).getTargetName()) + " doesn't untap during its controller's next " + (twoSteps ? "two " : "") + "untap step" + (twoSteps ? "s" : ""); } } - -} +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java index 9371f56249..c0e7b28f54 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DontUntapInControllersUntapStepEnchantedEffect.java @@ -19,7 +19,7 @@ public class DontUntapInControllersUntapStepEnchantedEffect extends ContinuousRu } public DontUntapInControllersUntapStepEnchantedEffect(String description) { - super(Duration.WhileOnBattlefield, Outcome.Detriment, false, true); + super(Duration.WhileOnBattlefield, Outcome.Removal, false, true); staticText = "Enchanted " + description + " doesn't untap during its controller's untap step"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/DrawCardSourceControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/DrawCardSourceControllerEffect.java index b2e79fcd0e..c56a4f28b8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/DrawCardSourceControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/DrawCardSourceControllerEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -17,20 +16,32 @@ import mage.util.CardUtil; public class DrawCardSourceControllerEffect extends OneShotEffect { protected DynamicValue amount; + protected String whoDrawCard = ""; public DrawCardSourceControllerEffect(int amount) { - this(new StaticValue(amount)); + this(amount, ""); + } + + public DrawCardSourceControllerEffect(int amount, String whoDrawCard) { + this(new StaticValue(amount), whoDrawCard); } public DrawCardSourceControllerEffect(DynamicValue amount) { + this(amount, ""); + } + + public DrawCardSourceControllerEffect(DynamicValue amount, String whoDrawCard) { super(Outcome.DrawCard); this.amount = amount.copy(); + this.whoDrawCard = whoDrawCard; setText(); } public DrawCardSourceControllerEffect(final DrawCardSourceControllerEffect effect) { super(effect); this.amount = effect.amount.copy(); + this.whoDrawCard = effect.whoDrawCard; + setText(); } @Override @@ -51,8 +62,8 @@ public class DrawCardSourceControllerEffect extends OneShotEffect { private void setText() { StringBuilder sb = new StringBuilder(); boolean oneCard = (amount instanceof StaticValue && amount.calculate(null, null, this) == 1) - || amount instanceof PermanentsOnBattlefieldCount || amount.toString().equals("1"); - sb.append("draw ").append(oneCard ? "a" : CardUtil.numberToText(amount.toString())).append(" card"); + || amount instanceof PermanentsOnBattlefieldCount || amount.toString().equals("1") || amount.toString().equals("a"); + sb.append(whoDrawCard.isEmpty() ? "" : whoDrawCard + " ").append("draw ").append(oneCard ? "a" : CardUtil.numberToText(amount.toString())).append(" card"); if (!oneCard) { sb.append('s'); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileAndGainLifeEqualPowerTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileAndGainLifeEqualPowerTargetEffect.java index 8126896e21..efa3ecd82d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileAndGainLifeEqualPowerTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileAndGainLifeEqualPowerTargetEffect.java @@ -14,7 +14,7 @@ import mage.players.Player; public class ExileAndGainLifeEqualPowerTargetEffect extends OneShotEffect { public ExileAndGainLifeEqualPowerTargetEffect() { - super(Outcome.GainLife); + super(Outcome.Removal); staticText = "Exile target creature. Its controller gains life equal to its power"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java index 0810053005..f828e713ef 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileSpellEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -12,7 +11,6 @@ import mage.game.stack.Spell; import mage.players.Player; /** - * * @author BetaSteward_at_googlemail.com */ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { @@ -38,7 +36,7 @@ public class ExileSpellEffect extends OneShotEffect implements MageSingleton { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { Spell spell = game.getStack().getSpell(source.getId()); - if (spell != null && !spell.isCopiedSpell()) { + if (spell != null && !spell.isCopy()) { Card spellCard = spell.getCard(); if (spellCard != null) { controller.moveCards(spellCard, Zone.EXILED, source, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java index d7798ace28..0d1285a3f9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import java.util.LinkedHashSet; @@ -93,7 +92,8 @@ public class ExileTargetEffect extends OneShotEffect { for (Target target : source.getTargets()) { for (UUID targetId : target.getTargets()) { Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { + if (permanent != null + && permanent.isPhasedIn()) { Zone currentZone = game.getState().getZone(permanent.getId()); if (currentZone != Zone.EXILED && (onlyFromZone == null || onlyFromZone == Zone.BATTLEFIELD)) { toExile.add(permanent); @@ -117,7 +117,8 @@ public class ExileTargetEffect extends OneShotEffect { } else { for (UUID targetId : getTargetPointer().getTargets(game, source)) { Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { + if (permanent != null + && permanent.isPhasedIn()) { Zone currentZone = game.getState().getZone(permanent.getId()); if (currentZone != Zone.EXILED && (onlyFromZone == null || onlyFromZone == Zone.BATTLEFIELD)) { toExile.add(permanent); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileUntilSourceLeavesEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileUntilSourceLeavesEffect.java index 496096af91..bd54104237 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ExileUntilSourceLeavesEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileUntilSourceLeavesEffect.java @@ -19,7 +19,7 @@ import mage.util.CardUtil; public class ExileUntilSourceLeavesEffect extends OneShotEffect { public ExileUntilSourceLeavesEffect(String targetName) { - super(Outcome.Benefit); + super(Outcome.Removal); this.staticText = "exile target " + targetName + " an opponent controls until {this} leaves the battlefield"; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/FightTargetsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FightTargetsEffect.java index c0fd2f1ca5..db8b80f874 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/FightTargetsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/FightTargetsEffect.java @@ -1,6 +1,6 @@ - package mage.abilities.effects.common; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.OneShotEffect; @@ -32,35 +32,58 @@ public class FightTargetsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Card card = game.getCard(source.getSourceId()); if (card != null) { - // only if both targets are legal the effect will be applied - if (source.getTargets().get(0).isLegal(source, game) && source.getTargets().get(1).isLegal(source, game)) { - Permanent creature1 = game.getPermanent(source.getTargets().get(0).getFirstTarget()); - Permanent creature2 = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - // 20110930 - 701.10 - if (creature1 != null && creature2 != null) { - if (creature1.isCreature() && creature2.isCreature()) { - return creature1.fight(creature2, source, game); - } + UUID target1Id = null; + UUID target2Id = null; + // first target is in target pointer, second target is a normal target + if (source.getTargets().size() < 2) { + if (!source.getTargets().get(0).isLegal(source, game)) { + return false; + } + target1Id = getTargetPointer().getFirst(game, source); + target2Id = source.getTargets().getFirstTarget(); + if (target1Id == target2Id) { + return false; + } + // two normal targets available, only if both targets are legal the effect will be applied + } else if (source.getTargets().get(0).isLegal(source, game) && source.getTargets().get(1).isLegal(source, game)) { + target1Id = source.getTargets().get(0).getFirstTarget(); + target2Id = source.getTargets().get(1).getFirstTarget(); + } + Permanent creature1 = game.getPermanent(target1Id); + Permanent creature2 = game.getPermanent(target2Id); + // 20110930 - 701.10 + if (creature1 != null && creature2 != null) { + if (creature1.isCreature() && creature2.isCreature()) { + return creature1.fight(creature2, source, game); } } - if (!game.isSimulation()) { - game.informPlayers(card.getName() + " has been fizzled."); - } + } + if (!game.isSimulation()) { + game.informPlayers(card.getName() + " has been fizzled."); } return false; } @Override - public FightTargetsEffect copy() { + public FightTargetsEffect + copy() { return new FightTargetsEffect(this); + } @Override - public String getText(Mode mode) { - if (staticText != null && !staticText.isEmpty()) { + public String + getText(Mode mode + ) { + if (staticText + != null && !staticText + .isEmpty()) { return staticText; + } - return "Target " + mode.getTargets().get(0).getTargetName() + " fights another target " + mode.getTargets().get(1).getTargetName(); + return "Target " + mode + .getTargets().get(0).getTargetName() + " fights another target " + mode + .getTargets().get(1).getTargetName(); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java index 6e7abd8d26..32b1b7940d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/FlipCoinEffect.java @@ -60,7 +60,7 @@ public class FlipCoinEffect extends OneShotEffect { MageObject mageObject = game.getObject(source.getSourceId()); if (controller != null && mageObject != null) { boolean result = true; - for (Effect effect : controller.flipCoin(game) ? executingEffectsWon : executingEffectsLost) { + for (Effect effect : controller.flipCoin(source, game, true) ? executingEffectsWon : executingEffectsLost) { effect.setTargetPointer(this.targetPointer); if (effect instanceof OneShotEffect) { result &= effect.apply(game, source); diff --git a/Mage/src/main/java/mage/abilities/effects/common/FlipUntilLoseEffect.java b/Mage/src/main/java/mage/abilities/effects/common/FlipUntilLoseEffect.java index 365e6b3a6a..6d1abe14fd 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/FlipUntilLoseEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/FlipUntilLoseEffect.java @@ -34,7 +34,7 @@ public class FlipUntilLoseEffect extends OneShotEffect { return false; } while (true) { - if (!player.flipCoin(game)) { + if (!player.flipCoin(source, game, true)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java index 58fb0c2cf3..a99b93a6f3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/GetEmblemTargetPlayerEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.MageObject; @@ -10,8 +9,9 @@ import mage.game.Game; import mage.game.command.Emblem; import mage.players.Player; +import java.util.stream.Collectors; + /** - * * @author LevelX2 */ public class GetEmblemTargetPlayerEffect extends OneShotEffect { @@ -53,6 +53,6 @@ public class GetEmblemTargetPlayerEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "Target " + mode.getTargets().get(0).getTargetName() + " gets an emblem with \"" + emblem.getAbilities().getRules(null) + '"'; + return "Target " + mode.getTargets().get(0).getTargetName() + " gets an emblem with \"" + emblem.getAbilities().getRules(null).stream().collect(Collectors.joining("; ")) + "\""; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetEffect.java index dc7a672668..f46fa4dc76 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/LoseLifeTargetEffect.java @@ -1,6 +1,6 @@ - package mage.abilities.effects.common; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; @@ -39,12 +39,15 @@ public class LoseLifeTargetEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player != null) { - player.loseLife(amount.calculate(game, source, this), game, false); - return true; + boolean applied = false; + for (UUID playerId : targetPointer.getTargets(game, source)) { + Player player = game.getPlayer(playerId); + if (player != null + && player.loseLife(amount.calculate(game, source, this), game, false) > 0) { + applied = true; + } } - return false; + return applied; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java index 4ce396a9a4..59ef2da86e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/MayTapOrUntapTargetEffect.java @@ -14,7 +14,7 @@ import mage.players.Player; public class MayTapOrUntapTargetEffect extends OneShotEffect { public MayTapOrUntapTargetEffect() { - super(Outcome.Benefit); + super(Outcome.AIDontUseIt); } public MayTapOrUntapTargetEffect(final MayTapOrUntapTargetEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java index a74f8d7962..59b4cbdf40 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PopulateEffect.java @@ -34,7 +34,7 @@ public class PopulateEffect extends OneShotEffect { private static final FilterPermanent filter = new FilterPermanent("token for populate"); static { - filter.add(new TokenPredicate()); + filter.add(TokenPredicate.instance); filter.add(new ControllerPredicate(TargetController.YOU)); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java index 5c857c93c2..51cbe53711 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventAllNonCombatDamageToAllEffect.java @@ -2,34 +2,38 @@ package mage.abilities.effects.common; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.PreventionEffectImpl; -import mage.filter.FilterInPlay; +import mage.constants.Duration; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.DamageEvent; import mage.game.events.GameEvent; import mage.game.permanent.Permanent; -import mage.players.Player; /** - * * @author jeffwadsworth */ public class PreventAllNonCombatDamageToAllEffect extends PreventionEffectImpl { protected final FilterPermanent filter; + private final boolean andToYou; public PreventAllNonCombatDamageToAllEffect(Duration duration, FilterPermanent filter) { - super(duration, Integer.MAX_VALUE, false); - this.filter = filter; - staticText = "Prevent all non combat damage that would be dealt to " + filter.getMessage() + ' ' + duration.toString(); + this(duration, filter, false); } - public PreventAllNonCombatDamageToAllEffect(final PreventAllNonCombatDamageToAllEffect effect) { + public PreventAllNonCombatDamageToAllEffect(Duration duration, FilterPermanent filter, boolean andToYou) { + super(duration, Integer.MAX_VALUE, false); + this.filter = filter; + this.andToYou = andToYou; + staticText = "Prevent all non combat damage that would be dealt to " + (andToYou ? "you and " : "") + filter.getMessage() + ' ' + duration.toString(); + } + + private PreventAllNonCombatDamageToAllEffect(final PreventAllNonCombatDamageToAllEffect effect) { super(effect); this.filter = effect.filter.copy(); + this.andToYou = effect.andToYou; } @Override @@ -45,6 +49,7 @@ public class PreventAllNonCombatDamageToAllEffect extends PreventionEffectImpl { if (permanent != null) { return filter.match(permanent, source.getSourceId(), source.getControllerId(), game); } + return andToYou && source.getControllerId().equals(event.getTargetId()); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java index b72b54d01c..0e832aeac6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PreventDamageToTargetMultiAmountEffect.java @@ -6,6 +6,7 @@ import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.PreventionEffectImpl; import mage.constants.Duration; import mage.game.Game; @@ -27,6 +28,10 @@ public class PreventDamageToTargetMultiAmountEffect extends PreventionEffectImpl super(duration, amount, false); } + public PreventDamageToTargetMultiAmountEffect(Duration duration, int amount, boolean onlyCombat, boolean consumable, DynamicValue dynamicValue) { + super(duration, amount, onlyCombat, consumable, dynamicValue); + } + public PreventDamageToTargetMultiAmountEffect(final PreventDamageToTargetMultiAmountEffect effect) { super(effect); } @@ -100,12 +105,15 @@ public class PreventDamageToTargetMultiAmountEffect extends PreventionEffectImpl @Override public String getText(Mode mode) { StringBuilder sb = new StringBuilder(); - sb.append("prevent the next ").append(amountToPrevent).append(" damage that would be dealt "); - if (duration == Duration.EndOfTurn) { - sb.append("this turn "); + if (staticText.isEmpty()) { + sb.append("prevent the next ").append(amountToPrevent).append(" damage that would be dealt "); + if (duration == Duration.EndOfTurn) { + sb.append("this turn "); + } + sb.append("to any number of targets, divided as you choose"); + return sb.toString(); } - sb.append("to any number of targets, divided as you choose"); - return sb.toString(); + return staticText; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/PutLibraryIntoGraveTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/PutLibraryIntoGraveTargetEffect.java index 01aee794ef..f1158cb434 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/PutLibraryIntoGraveTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/PutLibraryIntoGraveTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -13,7 +12,6 @@ import mage.players.Player; import mage.util.CardUtil; /** - * * @author BetaSteward_at_googlemail.com */ public class PutLibraryIntoGraveTargetEffect extends OneShotEffect { @@ -61,7 +59,12 @@ public class PutLibraryIntoGraveTargetEffect extends OneShotEffect { StringBuilder sb = new StringBuilder(); String message = amount.getMessage(); - sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + if (!mode.getTargets().isEmpty()) { + sb.append("target ").append(mode.getTargets().get(0).getTargetName()); + } else { + sb.append("that target"); + } + sb.append(" puts the top "); if (message.isEmpty()) { if (amount.toString().equals("1")) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/RecruiterEffect.java b/Mage/src/main/java/mage/abilities/effects/common/RecruiterEffect.java index e7723c6d08..1327e85549 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/RecruiterEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/RecruiterEffect.java @@ -41,7 +41,7 @@ public class RecruiterEffect extends OneShotEffect { if (controller != null) { TargetCardInLibrary targetCards = new TargetCardInLibrary(0, Integer.MAX_VALUE, filter); Cards cards = new CardsImpl(); - if (controller.searchLibrary(targetCards, game)) { + if (controller.searchLibrary(targetCards, source, game)) { cards.addAll(targetCards.getTargets()); } controller.revealCards(staticText, cards, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReplaceOpponentCardsInHandWithSelectedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReplaceOpponentCardsInHandWithSelectedEffect.java index 5635316fee..af77e9b1c3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReplaceOpponentCardsInHandWithSelectedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReplaceOpponentCardsInHandWithSelectedEffect.java @@ -44,7 +44,7 @@ public class ReplaceOpponentCardsInHandWithSelectedEffect extends OneShotEffect TargetCardInLibrary target = new TargetCardInLibrary(searchLibraryForNum, searchLibraryForNum, new FilterCard()); - controller.searchLibrary(target, game, targetOpponent.getId()); + controller.searchLibrary(target, source, game, targetOpponent.getId()); for (UUID cardId : target.getTargets()) { Card targetCard = game.getCard(cardId); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java index 9a1190329d..363c97fc4a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromGraveyardToBattlefieldTargetEffect.java @@ -65,19 +65,24 @@ public class ReturnFromGraveyardToBattlefieldTargetEffect extends OneShotEffect return staticText; } StringBuilder sb = new StringBuilder(); - Target target = mode.getTargets().get(0); - sb.append("return "); - if (target.getMaxNumberOfTargets() > 1) { - if (target.getMaxNumberOfTargets() != target.getNumberOfTargets()) { - sb.append("up to "); + + if (mode.getTargets().isEmpty()) { + sb.append("return target creature to the battlefield"); + } else { + Target target = mode.getTargets().get(0); + sb.append("return "); + if (target.getMaxNumberOfTargets() > 1) { + if (target.getMaxNumberOfTargets() != target.getNumberOfTargets()) { + sb.append("up to "); + } + sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(' '); + } + sb.append("target ").append(mode.getTargets().get(0).getTargetName()).append(" to the battlefield"); + if (tapped) { + sb.append(" tapped"); } - sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(' '); - } - sb.append("target ").append(mode.getTargets().get(0).getTargetName()).append(" to the battlefield"); - if (tapped) { - sb.append(" tapped"); } sb.append(" under your control"); return sb.toString(); } -} +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java index 175c92dfbb..cf5006a114 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeEffect.java @@ -1,6 +1,6 @@ - package mage.abilities.effects.common; +import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; @@ -46,34 +46,33 @@ public class SacrificeEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(targetPointer.getFirst(game, source)); - if (player == null) { - return false; - } - - FilterPermanent newFilter = filter.copy(); // filter can be static, so it's important to copy here - newFilter.add(new ControllerIdPredicate(player.getId())); - - int amount = count.calculate(game, source, this); - int realCount = game.getBattlefield().countAll(newFilter, player.getId(), game); - amount = Math.min(amount, realCount); - - Target target = new TargetPermanent(amount, amount, newFilter, true); - - if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { - while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { - player.chooseTarget(Outcome.Sacrifice, target, source, game); - } - - for (int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent(target.getTargets().get(idx)); - - if (permanent != null) { - permanent.sacrifice(source.getSourceId(), game); + boolean applied = false; + for (UUID playerId : targetPointer.getTargets(game, source)) { + Player player = game.getPlayer(playerId); + if (player != null) { + FilterPermanent newFilter = filter.copy(); // filter can be static, so it's important to copy here + newFilter.add(new ControllerIdPredicate(player.getId())); + int amount = count.calculate(game, source, this); + int realCount = game.getBattlefield().countAll(newFilter, player.getId(), game); + amount = Math.min(amount, realCount); + Target target = new TargetPermanent(amount, amount, newFilter, true); + if (amount > 0 && target.canChoose(source.getSourceId(), player.getId(), game)) { + while (!target.isChosen() + && target.canChoose(player.getId(), game) + && player.canRespond()) { + player.chooseTarget(Outcome.Sacrifice, target, source, game); + } + for (int idx = 0; idx < target.getTargets().size(); idx++) { + Permanent permanent = game.getPermanent(target.getTargets().get(idx)); + if (permanent != null + && permanent.sacrifice(source.getSourceId(), game)) { + applied = true; + } + } } } } - return true; + return applied; } public void setAmount(DynamicValue amount) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java index b4e9339de4..806acf2a7e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceEffect.java @@ -1,13 +1,12 @@ - package mage.abilities.effects.common; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; +import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.stack.Spell; /** * @@ -34,11 +33,9 @@ public class SacrificeSourceEffect extends OneShotEffect { MageObject sourceObject = source.getSourceObjectIfItStillExists(game); if (sourceObject == null) { // Check if the effect was installed by the spell the source was cast by (e.g. Necromancy), if not don't sacrifice the permanent - if (source.getSourceObject(game) instanceof Spell) { + if (game.getState().getZone(source.getSourceId()).equals(Zone.BATTLEFIELD) + && source.getSourceObjectZoneChangeCounter() + 1 == game.getState().getZoneChangeCounter(source.getSourceId())) { sourceObject = game.getPermanent(source.getSourceId()); - if (sourceObject != null && sourceObject.getZoneChangeCounter(game) > source.getSourceObjectZoneChangeCounter() + 1) { - return false; - } } } if (sourceObject instanceof Permanent) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java index 75cb98bcbb..bd4597a719 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SacrificeSourceUnlessPaysEffect.java @@ -4,6 +4,8 @@ import java.util.Locale; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.OneShotEffect; import mage.constants.Outcome; import mage.constants.Zone; @@ -18,19 +20,33 @@ import mage.util.CardUtil; public class SacrificeSourceUnlessPaysEffect extends OneShotEffect { protected Cost cost; + protected DynamicValue genericMana; public SacrificeSourceUnlessPaysEffect(Cost cost) { super(Outcome.Sacrifice); this.cost = cost; } + public SacrificeSourceUnlessPaysEffect(DynamicValue genericMana) { + super(Outcome.Detriment); + this.genericMana = genericMana; + } + public SacrificeSourceUnlessPaysEffect(final SacrificeSourceUnlessPaysEffect effect) { super(effect); - this.cost = effect.cost.copy(); + if (effect.cost != null) { + this.cost = effect.cost.copy(); + } + if (effect.genericMana != null) { + this.genericMana = effect.genericMana.copy(); + } } @Override public boolean apply(Game game, Ability source) { + if (genericMana != null) { + cost = new GenericManaCost(genericMana.calculate(game, source, this)); + } Player controller = game.getPlayer(source.getControllerId()); Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (controller != null && sourcePermanent != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/SkipCombatStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SkipCombatStepEffect.java new file mode 100644 index 0000000000..4d72fe19fd --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/SkipCombatStepEffect.java @@ -0,0 +1,55 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author jeffwadsworth + */ + +public class SkipCombatStepEffect extends ReplacementEffectImpl { + + public SkipCombatStepEffect(Duration duration) { + super(duration, Outcome.Detriment); + staticText = "that player skips their next combat phase"; + } + + public SkipCombatStepEffect(final SkipCombatStepEffect effect) { + super(effect); + } + + @Override + public SkipCombatStepEffect copy() { + return new SkipCombatStepEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.COMBAT_PHASE; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getPlayerId().equals(targetPointer.getFirst(game, source)); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/SkipNextDrawStepTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SkipNextDrawStepTargetEffect.java new file mode 100644 index 0000000000..e0d819beaf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/SkipNextDrawStepTargetEffect.java @@ -0,0 +1,55 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common; + +import mage.abilities.Ability; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; +import mage.game.events.GameEvent; + +/** + * + * @author jeffwadsworth + */ + +public class SkipNextDrawStepTargetEffect extends ReplacementEffectImpl { + + public SkipNextDrawStepTargetEffect() { + super(Duration.OneUse, Outcome.Detriment); + staticText = "Target player skips their next draw step"; + } + + public SkipNextDrawStepTargetEffect(final SkipNextDrawStepTargetEffect effect) { + super(effect); + } + + @Override + public SkipNextDrawStepTargetEffect copy() { + return new SkipNextDrawStepTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return true; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DRAW_STEP; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getPlayerId().equals(source.getFirstTarget()); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java index dbe05cd6b7..2a74938f66 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/SkipUntapOptionalSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common; import mage.abilities.Ability; @@ -10,7 +9,6 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author LevelX2 */ public class SkipUntapOptionalSourceEffect extends RestrictionEffect { @@ -32,9 +30,15 @@ public class SkipUntapOptionalSourceEffect extends RestrictionEffect { } @Override - public boolean canBeUntapped(Permanent permanent, Ability source, Game game) { + public boolean canBeUntapped(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { Player player = game.getPlayer(permanent.getControllerId()); - return player != null && player.chooseUse(Outcome.Benefit, "Untap " + permanent.getLogName() + '?', source, game); + if (canUseChooseDialogs) { + // calls on untap step + return player != null && player.chooseUse(Outcome.Benefit, "Untap " + permanent.getLogName() + '?', source, game); + } else { + // calcs on get cards info + return true; + } } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java index 9364751220..421b2c2bc9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapAllTargetPlayerControlsEffect.java @@ -51,6 +51,9 @@ public class TapAllTargetPlayerControlsEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - return "tap all " + filter.toString() + " target " + mode.getTargets().get(0).getTargetName() + " controls"; + + return "tap all " + filter.toString() + " target " + + (mode.getTargets().isEmpty() ? "player" : mode.getTargets().get(0).getTargetName()) + + " controls"; } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapEnchantedEffect.java index 40ea264ac5..462f09c412 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapEnchantedEffect.java @@ -1,10 +1,8 @@ - - package mage.abilities.effects.common; -import mage.constants.Outcome; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -15,17 +13,17 @@ import mage.game.permanent.Permanent; public class TapEnchantedEffect extends OneShotEffect { public TapEnchantedEffect() { - super(Outcome.Tap); - staticText = "tap enchanted creature"; - } + super(Outcome.Tap); + staticText = "tap enchanted creature"; + } public TapEnchantedEffect(final TapEnchantedEffect effect) { - super(effect); + super(effect); } @Override public boolean apply(Game game, Ability source) { - Permanent permanent = (Permanent) source.getSourceObject(game); + Permanent permanent = source.getSourcePermanentIfItStillExists(game); if (permanent != null) { Permanent attach = game.getPermanent(permanent.getAttachedTo()); if (attach != null) { @@ -41,4 +39,4 @@ public class TapEnchantedEffect extends OneShotEffect { return new TapEnchantedEffect(this); } - } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java index 29d10627a7..e3aa5c5c56 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/TapTargetEffect.java @@ -54,6 +54,10 @@ public class TapTargetEffect extends OneShotEffect { return "tap " + staticText; } + if (mode.getTargets().isEmpty()) { + return "tap target permanent"; + } + Target target = mode.getTargets().get(0); if (target.getMaxNumberOfTargets() > 1) { if (target.getMaxNumberOfTargets() == target.getNumberOfTargets()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java index 78834f82ae..385ff814ec 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapAllThatAttackedEffect.java @@ -36,9 +36,9 @@ public class UntapAllThatAttackedEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Watcher watcher = game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); - if (watcher instanceof AttackedThisTurnWatcher) { - Set attackedThisTurn = ((AttackedThisTurnWatcher) watcher).getAttackedThisTurnCreatures(); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + if (watcher != null) { + Set attackedThisTurn = watcher.getAttackedThisTurnCreatures(); for (MageObjectReference mor : attackedThisTurn) { Permanent permanent = mor.getPermanent(game); if (permanent != null && permanent.isCreature()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java index ccc695b67b..05540aeb2c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapLandsEffect.java @@ -20,7 +20,7 @@ public class UntapLandsEffect extends OneShotEffect { private static final FilterLandPermanent filter = new FilterLandPermanent("untapped lands"); static { - filter.add(new TappedPredicate()); + filter.add(TappedPredicate.instance); } private final int amount; private final boolean upTo; diff --git a/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java index 838996d2b8..d474f15cc8 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/UntapTargetEffect.java @@ -65,8 +65,12 @@ public class UntapTargetEffect extends OneShotEffect { if (staticText != null && !staticText.isEmpty()) { return staticText; } - Target target = mode.getTargets().get(0); + if (mode.getTargets().isEmpty()) { + return "untap target permanent"; + } + + Target target = mode.getTargets().get(0); StringBuilder sb = new StringBuilder(); sb.append("untap "); if (target.getNumberOfTargets() == 0) { @@ -84,4 +88,4 @@ public class UntapTargetEffect extends OneShotEffect { return sb.toString(); } -} +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java index b4c4ec8f1d..43e14562a2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleAllEffect.java @@ -60,7 +60,7 @@ public class AttacksIfAbleAllEffect extends RequirementEffect { if (eachCombat) { return true; } - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); return watcher != null && !watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game)); } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleSourceEffect.java index 44b4356b8e..bf62c5c642 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/AttacksIfAbleSourceEffect.java @@ -47,7 +47,7 @@ public class AttacksIfAbleSourceEffect extends RequirementEffect { if (eachCombat) { return true; } - AttackedThisTurnWatcher watcher = (AttackedThisTurnWatcher) game.getState().getWatchers().get(AttackedThisTurnWatcher.class.getSimpleName()); + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); return watcher != null && !watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game)); } return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java index 6ee0830377..d3b865179d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackAsThoughItDidntHaveDefenderAllEffect.java @@ -7,7 +7,7 @@ import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.FilterPermanent; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.permanent.Permanent; @@ -21,7 +21,7 @@ public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffec private final FilterPermanent filter; public CanAttackAsThoughItDidntHaveDefenderAllEffect(Duration duration) { - this(duration, new FilterCreaturePermanent()); + this(duration, StaticFilters.FILTER_PERMANENT_CREATURE); } public CanAttackAsThoughItDidntHaveDefenderAllEffect(Duration duration, FilterPermanent filter) { @@ -30,7 +30,7 @@ public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffec this.staticText = getText(); } - public CanAttackAsThoughItDidntHaveDefenderAllEffect(final CanAttackAsThoughItDidntHaveDefenderAllEffect effect) { + private CanAttackAsThoughItDidntHaveDefenderAllEffect(final CanAttackAsThoughItDidntHaveDefenderAllEffect effect) { super(effect); this.filter = effect.filter.copy(); } @@ -48,7 +48,8 @@ public class CanAttackAsThoughItDidntHaveDefenderAllEffect extends AsThoughEffec @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Permanent permanent = game.getPermanent(objectId); - return permanent != null && filter.match(permanent, game); + return permanent != null + && filter.match(permanent, source.getSourceId(), source.getControllerId(), game); } private String getText() { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java index 7c5f54daf0..711ad88eba 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanAttackOnlyAloneEffect.java @@ -12,7 +12,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CanAttackOnlyAloneEffect extends RestrictionEffect { @@ -32,7 +31,7 @@ public class CanAttackOnlyAloneEffect extends RestrictionEffect { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return numberOfAttackers == 1; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java index 2e01519ec2..ecb95414c9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingAttachedEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -31,7 +29,10 @@ public class CanBlockOnlyFlyingAttachedEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.getAbilities().contains(FlyingAbility.getInstance()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java index b703fc64c5..c39e9d3188 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CanBlockOnlyFlyingEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ @@ -32,7 +29,10 @@ public class CanBlockOnlyFlyingEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.getAbilities().contains(FlyingAbility.getInstance()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneAttachedEffect.java index dbd3766b02..cf3a354dcc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneAttachedEffect.java @@ -13,7 +13,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackAloneAttachedEffect extends RestrictionEffect { @@ -33,7 +32,7 @@ public class CantAttackAloneAttachedEffect extends RestrictionEffect { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return numberOfAttackers > 1; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneSourceEffect.java index 5aa33b59e3..9f8f27f5ce 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAloneSourceEffect.java @@ -12,7 +12,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackAloneSourceEffect extends RestrictionEffect { @@ -32,7 +31,7 @@ public class CantAttackAloneSourceEffect extends RestrictionEffect { } @Override - public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game) { + public boolean canAttackCheckAfter(int numberOfAttackers, Ability source, Game game, boolean canUseChooseDialogs) { return numberOfAttackers > 1; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java index 73326c41a7..40339821a3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerAllEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -30,7 +28,7 @@ public class CantAttackAnyPlayerAllEffect extends RestrictionEffect { sb.append(' ').append(duration.toString()); } } - staticText = sb.toString(); + staticText = sb.toString(); } public CantAttackAnyPlayerAllEffect(final CantAttackAnyPlayerAllEffect effect) { @@ -44,7 +42,7 @@ public class CantAttackAnyPlayerAllEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerSourceEffect.java index ea135f6e95..0a4365b39f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAnyPlayerSourceEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +8,7 @@ import mage.game.permanent.Permanent; /** * The source of this effect can't attack any opponent - * + * * @author BetaSteward_at_googlemail.com */ public class CantAttackAnyPlayerSourceEffect extends RestrictionEffect { @@ -29,7 +27,7 @@ public class CantAttackAnyPlayerSourceEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAttachedEffect.java index 0b39ca6dca..3b726f3ca0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackAttachedEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ @@ -31,7 +28,7 @@ public class CantAttackAttachedEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java index f6c9d06fb4..7e4db0db57 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAllEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackBlockAllEffect extends RestrictionEffect { @@ -42,12 +40,12 @@ public class CantAttackBlockAllEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAttachedEffect.java index 082c2a9632..883e89d76d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockAttachedEffect.java @@ -1,10 +1,10 @@ - package mage.abilities.effects.common.combat; -import mage.constants.AttachmentType; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; +import mage.constants.AttachmentType; +import mage.constants.Duration; +import mage.constants.Outcome; import mage.game.Game; import mage.game.permanent.Permanent; @@ -14,7 +14,7 @@ import mage.game.permanent.Permanent; public class CantAttackBlockAttachedEffect extends RestrictionEffect { public CantAttackBlockAttachedEffect(AttachmentType attachmentType) { - super(Duration.WhileOnBattlefield); + super(Duration.WhileOnBattlefield, Outcome.Removal); this.staticText = attachmentType.verb() + " creature can't attack or block"; } @@ -30,12 +30,12 @@ public class CantAttackBlockAttachedEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java index f572dab3a5..a1f25df21d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockTargetEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +7,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ @@ -30,12 +27,12 @@ public class CantAttackBlockTargetEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockUnlessConditionSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockUnlessConditionSourceEffect.java index 0cdbd5da37..2f035c6f9a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockUnlessConditionSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackBlockUnlessConditionSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackBlockUnlessConditionSourceEffect extends RestrictionEffect { @@ -33,12 +31,12 @@ public class CantAttackBlockUnlessConditionSourceEffect extends RestrictionEffec } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerAttachedEffect.java index 09e122ede9..605da5354c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackControllerAttachedEffect.java @@ -1,8 +1,5 @@ - - package mage.abilities.effects.common.combat; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.AttachmentType; @@ -10,9 +7,10 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author LevelX2 */ @@ -33,7 +31,11 @@ public class CantAttackControllerAttachedEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + if (defenderId.equals(source.getControllerId())) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackIfDefenderControlsPermanent.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackIfDefenderControlsPermanent.java index e813b23e8b..21f0fece9a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackIfDefenderControlsPermanent.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackIfDefenderControlsPermanent.java @@ -1,8 +1,5 @@ - - package mage.abilities.effects.common.combat; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; @@ -11,8 +8,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author BursegSardaukar */ @@ -37,7 +35,11 @@ public class CantAttackIfDefenderControlsPermanent extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + UUID defendingPlayerId; Player player = game.getPlayer(defenderId); if (player == null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java index ce43782e8a..d47f577799 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackSourceEffect.java @@ -1,15 +1,12 @@ - - package mage.abilities.effects.common.combat; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author BetaSteward_at_googlemail.com & L_J */ public class CantAttackSourceEffect extends RestrictionEffect { @@ -29,7 +26,7 @@ public class CantAttackSourceEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackTargetEffect.java index 641e804152..c0148d71d5 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackTargetEffect.java @@ -1,5 +1,3 @@ - - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackTargetEffect extends RestrictionEffect { @@ -29,7 +26,7 @@ public class CantAttackTargetEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @@ -40,11 +37,11 @@ public class CantAttackTargetEffect extends RestrictionEffect { @Override public String getText(Mode mode) { - if(staticText != null && !staticText.isEmpty()) { + if (staticText != null && !staticText.isEmpty()) { return staticText; } String text = "target " + mode.getTargets().get(0).getTargetName() + " can't attack"; - if(this.duration == Duration.EndOfTurn) { + if (this.duration == Duration.EndOfTurn) { text += " this turn"; } return text; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackUnlessDefenderControllsPermanent.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackUnlessDefenderControllsPermanent.java index 91a597aaa2..f783c08a55 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackUnlessDefenderControllsPermanent.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackUnlessDefenderControllsPermanent.java @@ -1,8 +1,5 @@ - - package mage.abilities.effects.common.combat; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; @@ -11,8 +8,9 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.UUID; + /** - * * @author LevelX2 */ @@ -37,7 +35,11 @@ public class CantAttackUnlessDefenderControllsPermanent extends RestrictionEffec } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + UUID defendingPlayerId; Player player = game.getPlayer(defenderId); if (player == null) { @@ -50,10 +52,7 @@ public class CantAttackUnlessDefenderControllsPermanent extends RestrictionEffec } else { defendingPlayerId = defenderId; } - if (defendingPlayerId != null && game.getBattlefield().countAll(filter, defendingPlayerId, game) == 0) { - return false; - } - return true; + return defendingPlayerId == null || game.getBattlefield().countAll(filter, defendingPlayerId, game) != 0; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java index 1fc2dd1d2a..b47fd8d748 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouAllEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -13,7 +12,6 @@ import mage.game.permanent.Permanent; import java.util.UUID; /** - * * @author LevelX2 */ public class CantAttackYouAllEffect extends RestrictionEffect { @@ -35,7 +33,7 @@ public class CantAttackYouAllEffect extends RestrictionEffect { this.alsoPlaneswalker = alsoPlaneswalker; staticText = filterAttacker.getMessage() + " can't attack you" + (alsoPlaneswalker ? " or a planeswalker you control" : "") - + (duration == Duration.UntilYourNextTurn ? " until your next turn" : ""); + + (duration == Duration.UntilYourNextTurn || duration == Duration.UntilEndOfYourNextTurn ? " " + duration.toString() : ""); } CantAttackYouAllEffect(final CantAttackYouAllEffect effect) { @@ -50,7 +48,10 @@ public class CantAttackYouAllEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } if (alsoPlaneswalker) { Permanent planeswalker = game.getPermanent(defenderId); if (planeswalker != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouEffect.java index 7214238747..cdd9e6b0b2 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouEffect.java @@ -1,15 +1,14 @@ - package mage.abilities.effects.common.combat; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author TheElk801 */ public class CantAttackYouEffect extends RestrictionEffect { @@ -33,7 +32,10 @@ public class CantAttackYouEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } return !defenderId.equals(source.getControllerId()); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java index b603326ddf..7bc79625d7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouOrPlaneswalkerAllEffect.java @@ -1,7 +1,5 @@ - package mage.abilities.effects.common.combat; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; @@ -10,8 +8,9 @@ import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.UUID; + /** - * * @author fireshoes */ public class CantAttackYouOrPlaneswalkerAllEffect extends RestrictionEffect { @@ -39,7 +38,11 @@ public class CantAttackYouOrPlaneswalkerAllEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + if (defenderId.equals(source.getControllerId())) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java index 0eef90ee66..ca59b00414 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantAttackYouUnlessPayManaAllEffect.java @@ -12,7 +12,6 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEffectImpl { @@ -37,7 +36,7 @@ public class CantAttackYouUnlessPayManaAllEffect extends PayCostToAttackBlockEff + (payAlsoForAttackingPlaneswalker ? "or a planeswalker you control " : "") + "unless their controller pays " + (manaCosts == null ? "" : manaCosts.getText()) - + " for each creature he or she controls that's attacking you"; + + " for each creature they controls that's attacking you"; } public CantAttackYouUnlessPayManaAllEffect(final CantAttackYouUnlessPayManaAllEffect effect) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java index 8d88c0fd80..1894ad25e0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAllEffect.java @@ -1,15 +1,13 @@ - package mage.abilities.effects.common.combat; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ public class CantBeBlockedAllEffect extends RestrictionEffect { @@ -37,7 +35,7 @@ public class CantBeBlockedAllEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAttachedEffect.java index 6fc49b43cd..dfe28e5b50 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedAttachedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ public class CantBeBlockedAttachedEffect extends RestrictionEffect { @@ -29,7 +27,7 @@ public class CantBeBlockedAttachedEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java index 9e901b02d9..67930d2c52 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBeBlockedByAllSourceEffect extends RestrictionEffect { @@ -36,7 +34,7 @@ public class CantBeBlockedByAllSourceEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java index 7ac30077d0..1448aacf27 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByAllTargetEffect.java @@ -1,16 +1,15 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.Duration; -import static mage.constants.Duration.EndOfTurn; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; +import static mage.constants.Duration.EndOfTurn; + /** - * * @author LevelX2 */ public class CantBeBlockedByAllTargetEffect extends RestrictionEffect { @@ -38,7 +37,7 @@ public class CantBeBlockedByAllTargetEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java index 30d2965464..bb0bbc9ffb 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAllEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ @@ -23,7 +21,7 @@ public class CantBeBlockedByCreaturesAllEffect extends RestrictionEffect { this.filterCreatures = filterCreatures; this.filterBlockedBy = filterBlockedBy; staticText = new StringBuilder(filterCreatures.getMessage()).append(" can't be blocked ") - .append(filterBlockedBy.getMessage().startsWith("except by") ? "":"by ").append(filterBlockedBy.getMessage()).toString(); + .append(filterBlockedBy.getMessage().startsWith("except by") ? "" : "by ").append(filterBlockedBy.getMessage()).toString(); } public CantBeBlockedByCreaturesAllEffect(final CantBeBlockedByCreaturesAllEffect effect) { @@ -38,7 +36,7 @@ public class CantBeBlockedByCreaturesAllEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filterBlockedBy.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java index 52c339e183..83259e873b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesAttachedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -36,7 +35,7 @@ public class CantBeBlockedByCreaturesAttachedEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java index 4c25091625..1f9cb72844 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBeBlockedByCreaturesSourceEffect extends RestrictionEffect { @@ -19,8 +17,8 @@ public class CantBeBlockedByCreaturesSourceEffect extends RestrictionEffect { public CantBeBlockedByCreaturesSourceEffect(FilterCreaturePermanent filter, Duration duration) { super(duration); this.filter = filter; - staticText = new StringBuilder("{this} can't be blocked ") - .append(filter.getMessage().startsWith("except by") ? "" : "by ").append(filter.getMessage()).toString(); + staticText = "{this} can't be blocked " + (duration == Duration.EndOfTurn ? "this turn " : "") + + (filter.getMessage().startsWith("except by") ? "" : "by ") + filter.getMessage(); } public CantBeBlockedByCreaturesSourceEffect(final CantBeBlockedByCreaturesSourceEffect effect) { @@ -34,7 +32,7 @@ public class CantBeBlockedByCreaturesSourceEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithGreaterPowerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithGreaterPowerEffect.java index c2194a8015..96774ecc3e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithGreaterPowerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithGreaterPowerEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -8,7 +7,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBeBlockedByCreaturesWithGreaterPowerEffect extends RestrictionEffect { @@ -28,7 +26,7 @@ public class CantBeBlockedByCreaturesWithGreaterPowerEffect extends RestrictionE } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getPower().getValue() <= attacker.getPower().getValue(); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithLessPowerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithLessPowerEffect.java index c60bf27c7e..4bb2102dc3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithLessPowerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByCreaturesWithLessPowerEffect.java @@ -1,14 +1,12 @@ - package mage.abilities.effects.common.combat; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ public class CantBeBlockedByCreaturesWithLessPowerEffect extends RestrictionEffect { @@ -28,7 +26,7 @@ public class CantBeBlockedByCreaturesWithLessPowerEffect extends RestrictionEffe } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return (blocker.getPower().getValue() >= attacker.getPower().getValue()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByTargetSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByTargetSourceEffect.java index cd3c25ed91..112e1b0dd7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByTargetSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedByTargetSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +9,6 @@ import mage.game.permanent.Permanent; import mage.target.Target; /** - * * @author LevelX2 */ @@ -18,7 +16,7 @@ public class CantBeBlockedByTargetSourceEffect extends RestrictionEffect { /** * Target creature(s) cant block the source creature - * + * * @param duration */ @@ -36,7 +34,7 @@ public class CantBeBlockedByTargetSourceEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !this.getTargetPointer().getTargets(game, source).contains(blocker.getId()); } @@ -52,7 +50,7 @@ public class CantBeBlockedByTargetSourceEffect extends RestrictionEffect { } StringBuilder sb = new StringBuilder(); Target target = mode.getTargets().get(0); - if(target.getNumberOfTargets() > 1){ + if (target.getNumberOfTargets() > 1) { if (target.getNumberOfTargets() < target.getMaxNumberOfTargets()) { sb.append("Up to"); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedSourceEffect.java index 04e7af34c2..f9b65a97fc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -8,7 +7,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ public class CantBeBlockedSourceEffect extends RestrictionEffect { @@ -16,6 +14,7 @@ public class CantBeBlockedSourceEffect extends RestrictionEffect { public CantBeBlockedSourceEffect() { this(Duration.WhileOnBattlefield); } + public CantBeBlockedSourceEffect(Duration duration) { super(duration); this.staticText = "{this} can't be blocked"; @@ -34,7 +33,7 @@ public class CantBeBlockedSourceEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java index 15d43ec0ea..0d2a648f54 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBeBlockedTargetEffect.java @@ -13,7 +13,6 @@ import mage.target.Target; import mage.util.CardUtil; /** - * * @author North */ public class CantBeBlockedTargetEffect extends RestrictionEffect { @@ -47,7 +46,7 @@ public class CantBeBlockedTargetEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return !filter.match(blocker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockActivateAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockActivateAttachedEffect.java index 41f313bd43..53e9a16e0d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockActivateAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockActivateAttachedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -8,7 +7,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public class CantBlockActivateAttachedEffect extends RestrictionEffect { @@ -26,20 +24,18 @@ public class CantBlockActivateAttachedEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { - if (permanent.getId().equals(enchantment.getAttachedTo())) { - return true; - } + return permanent.getId().equals(enchantment.getAttachedTo()); } return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java index 605aa5ef49..a75abc4900 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAllEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -10,7 +9,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBlockAllEffect extends RestrictionEffect { @@ -33,7 +31,7 @@ public class CantBlockAllEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java index d4e7176eeb..c3a680b771 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttachedEffect.java @@ -1,18 +1,17 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; import mage.constants.AttachmentType; import mage.constants.Duration; -import static mage.constants.Duration.EndOfTurn; import mage.filter.common.FilterCreaturePermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; +import static mage.constants.Duration.EndOfTurn; + /** - * * @author North */ public class CantBlockAttachedEffect extends RestrictionEffect { @@ -69,7 +68,10 @@ public class CantBlockAttachedEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttackActivateAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttackActivateAttachedEffect.java index e49b50d326..cc9906fe9b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttackActivateAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockAttackActivateAttachedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -8,7 +7,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBlockAttackActivateAttachedEffect extends RestrictionEffect { @@ -26,25 +24,23 @@ public class CantBlockAttackActivateAttachedEffect extends RestrictionEffect { public boolean applies(Permanent permanent, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); if (enchantment != null && enchantment.getAttachedTo() != null) { - if (permanent.getId().equals(enchantment.getAttachedTo())) { - return true; - } + return permanent.getId().equals(enchantment.getAttachedTo()); } return false; } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game) { + public boolean canUseActivatedAbilities(Permanent permanent, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java index 9667983168..0d888e8cab 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockCreaturesSourceEffect.java @@ -36,7 +36,10 @@ public class CantBlockCreaturesSourceEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return !filter.match(attacker, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockSourceEffect.java index 86e11eecfc..81d4735b0d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockSourceEffect.java @@ -1,15 +1,12 @@ - - package mage.abilities.effects.common.combat; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author BetaSteward_at_googlemail.com */ public class CantBlockSourceEffect extends RestrictionEffect { @@ -32,7 +29,7 @@ public class CantBlockSourceEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockTargetEffect.java index cb15d4d9bd..9a97d0cb11 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -11,7 +10,6 @@ import mage.target.Target; import mage.util.CardUtil; /** - * * @author North */ public class CantBlockTargetEffect extends RestrictionEffect { @@ -30,7 +28,7 @@ public class CantBlockTargetEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java index 52b86813cd..cba3316d96 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/CantBlockUnlessYouControlSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.combat; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class CantBlockUnlessYouControlSourceEffect extends RestrictionEffect { @@ -33,7 +31,7 @@ public class CantBlockUnlessYouControlSourceEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java index 5c713db1f6..d8806469c3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByAllTargetEffect.java @@ -19,9 +19,9 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect { public MustBeBlockedByAllTargetEffect(Duration duration) { super(duration); - staticText = new StringBuilder("All creatures able to block target creature ") - .append(this.getDuration() == Duration.EndOfTurn ? "this turn ":"") - .append("do so").toString(); + staticText = "All creatures able to block target creature " + + (this.getDuration() == Duration.EndOfTurn ? "this turn " : "") + + "do so"; } public MustBeBlockedByAllTargetEffect(final MustBeBlockedByAllTargetEffect effect) { @@ -33,7 +33,7 @@ public class MustBeBlockedByAllTargetEffect extends RequirementEffect { Permanent attackingCreature = game.getPermanent(this.getTargetPointer().getFirst(game, source)); if (attackingCreature != null && attackingCreature.isAttacking()) { if (source.getAbilityType() != AbilityType.STATIC) { - BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher blockedAttackerWatcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attackingCreature, permanent, game)) { // has already blocked this turn, so no need to do again return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java index 81fba0f3d3..d56b0e8b0e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/combat/MustBeBlockedByTargetSourceEffect.java @@ -36,7 +36,7 @@ public class MustBeBlockedByTargetSourceEffect extends RequirementEffect { if (blocker != null && blocker.canBlock(source.getSourceId(), game)) { Permanent attacker = (Permanent) source.getSourceObjectIfItStillExists(game); if (attacker != null) { - BlockedAttackerWatcher blockedAttackerWatcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher blockedAttackerWatcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (blockedAttackerWatcher != null && blockedAttackerWatcher.creatureHasBlockedAttacker(attacker, blocker, game)) { // has already blocked this turn, so no need to do again return false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java index fc1ab81355..ebf958615d 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandEnchantedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -78,7 +77,7 @@ public class BecomesBasicLandEnchantedEffect extends ContinuousEffectImpl { break; case TypeChangingEffects_4: // subtypes are all removed by changing the subtype to a land type. - permanent.getSubtype(game).removeAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).removeAll(SubType.getLandTypes()); permanent.getSubtype(game).addAll(landTypes); break; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java index 86fa19b7ce..23de1a78d9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesBasicLandTargetEffect.java @@ -1,10 +1,5 @@ - package mage.abilities.effects.common.continuous; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.mana.*; @@ -15,6 +10,11 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + /** * http://mtgsalvation.gamepedia.com/Land_changers * @@ -116,7 +116,7 @@ public class BecomesBasicLandTargetEffect extends ContinuousEffectImpl { // So the ability removing has to be done before Layer 6 land.removeAllAbilities(source.getSourceId(), game); // 305.7 - land.getSubtype(game).removeAll(SubType.getLandTypes(false)); + land.getSubtype(game).removeAll(SubType.getLandTypes()); land.getSubtype(game).addAll(landTypes); } else { landTypesToAdd.clear(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedEffect.java index 23f00727a2..2a74032610 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -73,7 +72,7 @@ public class BecomesCreatureAttachedEffect extends ContinuousEffectImpl { case ALL: case ALL_BUT_COLOR: case ABILITIES_SUBTYPE: - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); break; } for (SubType t : token.getSubtype(game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect.java index d127b40943..16b27519ee 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.MageObjectReference; @@ -7,7 +6,6 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.Token; /** @@ -71,7 +69,7 @@ public class BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect extends Co case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { for (SuperType superType : token.getSuperType()) { - permanentAttachedTo.addSuperType(superType); + permanentAttachedTo.addSuperType(superType); } // card type @@ -90,7 +88,7 @@ public class BecomesCreatureAttachedWithActivatedAbilityOrSpellEffect extends Co case ALL: case ALL_BUT_COLOR: case ABILITIES_SUBTYPE_AND_PT: - permanentAttachedTo.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanentAttachedTo.getSubtype(game).retainAll(SubType.getLandTypes()); break; } for (SubType subType : token.getSubtype(game)) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java index ba868a521f..09a34e730b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.MageObjectReference; @@ -31,8 +30,9 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements } public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness) { - this(token, theyAreStillType,duration,losePreviousTypes,characterDefining,power,toughness,false); + this(token, theyAreStillType, duration, losePreviousTypes, characterDefining, power, toughness, false); } + public BecomesCreatureSourceEffect(Token token, String theyAreStillType, Duration duration, boolean losePreviousTypes, boolean characterDefining, DynamicValue power, DynamicValue toughness, boolean loseAbilities) { super(duration, Outcome.BecomeCreature); this.characterDefining = characterDefining; @@ -40,7 +40,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements this.theyAreStillType = theyAreStillType; this.losePreviousTypes = losePreviousTypes; this.power = power; - this.toughness = toughness;this.loseAbilities=loseAbilities; + this.toughness = toughness; + this.loseAbilities = loseAbilities; setText(); this.addDependencyType(DependencyType.BecomeCreature); @@ -50,7 +51,8 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements super(effect); this.token = effect.token.copy(); this.theyAreStillType = effect.theyAreStillType; - this.losePreviousTypes = effect.losePreviousTypes;this.loseAbilities=effect.loseAbilities; + this.losePreviousTypes = effect.losePreviousTypes; + this.loseAbilities = effect.loseAbilities; if (effect.power != null) { this.power = effect.power.copy(); } @@ -92,7 +94,7 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements } if (theyAreStillType != null && theyAreStillType.isEmpty() || theyAreStillType == null && permanent.isLand()) { - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); } if (!token.getSubtype(game).isEmpty()) { permanent.getSubtype(game).addAll(token.getSubtype(game)); @@ -111,8 +113,9 @@ public class BecomesCreatureSourceEffect extends ContinuousEffectImpl implements case AbilityAddingRemovingEffects_6: if (sublayer == SubLayer.NA) { - if(loseAbilities){ - permanent.removeAllAbilities(source.getSourceId(), game);} + if (loseAbilities) { + permanent.removeAllAbilities(source.getSourceId(), game); + } for (Ability ability : token.getAbilities()) { permanent.addAbility(ability, source.getSourceId(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java index d386d9c691..97d55d1aa0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -7,7 +6,6 @@ import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.game.permanent.token.TokenImpl; import mage.game.permanent.token.Token; import mage.target.Target; import mage.util.CardUtil; @@ -22,26 +20,34 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl { protected Token token; protected boolean loseAllAbilities; protected boolean addStillALandText; + protected boolean loseName; + + + public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) { + this(token, loseAllAbilities, stillALand, duration, false); + } /** - * * @param token * @param loseAllAbilities loses all subtypes and colors - * @param stillALand add rule text, "it's still a land" + * @param stillALand add rule text, "it's still a land" + * @param loseName permanent lose name and get's it from token * @param duration */ - public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration) { + public BecomesCreatureTargetEffect(Token token, boolean loseAllAbilities, boolean stillALand, Duration duration, boolean loseName) { super(duration, Outcome.BecomeCreature); this.token = token; this.loseAllAbilities = loseAllAbilities; this.addStillALandText = stillALand; + this.loseName = loseName; } public BecomesCreatureTargetEffect(final BecomesCreatureTargetEffect effect) { super(effect); - token = effect.token.copy(); + this.token = effect.token.copy(); this.loseAllAbilities = effect.loseAllAbilities; this.addStillALandText = effect.addStillALandText; + this.loseName = effect.loseName; } @Override @@ -56,10 +62,17 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(permanentId); if (permanent != null) { switch (layer) { + case TextChangingEffects_3: + if (sublayer == SubLayer.NA) { + if (loseName) { + permanent.setName(token.getName()); + } + } + break; case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { if (loseAllAbilities) { - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); permanent.getSubtype(game).addAll(token.getSubtype(game)); } else { if (!token.getSubtype(game).isEmpty()) { @@ -128,7 +141,11 @@ public class BecomesCreatureTargetEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return layer == Layer.PTChangingEffects_7 || layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.ColorChangingEffects_5 || layer == Layer.TypeChangingEffects_4; + return layer == Layer.PTChangingEffects_7 + || layer == Layer.AbilityAddingRemovingEffects_6 + || layer == Layer.ColorChangingEffects_5 + || layer == Layer.TypeChangingEffects_4 + || layer == Layer.TextChangingEffects_3; } @Override diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTypeTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTypeTargetEffect.java index e5a140ff81..839f691d21 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTypeTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesCreatureTypeTargetEffect.java @@ -15,7 +15,6 @@ import mage.util.SubTypeList; import java.util.UUID; /** - * * @author LevelX2 */ public class BecomesCreatureTypeTargetEffect extends ContinuousEffectImpl { @@ -73,7 +72,7 @@ public class BecomesCreatureTypeTargetEffect extends ContinuousEffectImpl { switch (layer) { case TypeChangingEffects_4: if (loseOther) { - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); permanent.getSubtype(game).addAll(subtypes); } else { for (SubType subtype : subtypes) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesEnchantmentSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesEnchantmentSourceEffect.java new file mode 100644 index 0000000000..e16f3d033a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesEnchantmentSourceEffect.java @@ -0,0 +1,79 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.abilities.effects.common.continuous; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.CardType; +import mage.constants.DependencyType; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.game.Game; +import mage.game.permanent.Permanent; + +/** + * + * @author jeffwadsworth + */ +public class BecomesEnchantmentSourceEffect extends ContinuousEffectImpl implements SourceEffect { + + public BecomesEnchantmentSourceEffect() { + super(Duration.Custom, Outcome.AddAbility); + staticText = "{this} becomes an Enchantment"; + dependencyTypes.add(DependencyType.EnchantmentAddingRemoving); + + } + + public BecomesEnchantmentSourceEffect(final BecomesEnchantmentSourceEffect effect) { + super(effect); + } + + @Override + public BecomesEnchantmentSourceEffect copy() { + return new BecomesEnchantmentSourceEffect(this); + } + + @Override + public void init(Ability source, Game game) { + super.init(source, game); + affectedObjectList.add(new MageObjectReference(source.getSourceId(), game)); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + Permanent permanent = affectedObjectList.get(0).getPermanent(game); + if (permanent != null) { + switch (layer) { + case TypeChangingEffects_4: + if (sublayer == SubLayer.NA) { + permanent.getCardType().clear(); + permanent.getSubtype(game).clear(); + if (!permanent.getCardType().contains(CardType.ENCHANTMENT)) { + permanent.getCardType().add(CardType.ENCHANTMENT); + } + } + break; + } + return true; + } + this.discard(); + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return Layer.TypeChangingEffects_4 == layer; + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java index 3bc5c7a936..97f506cbf3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BecomesSubtypeAllEffect.java @@ -70,7 +70,7 @@ public class BecomesSubtypeAllEffect extends ContinuousEffectImpl { switch (layer) { case TypeChangingEffects_4: if (loseOther) { - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); permanent.getSubtype(game).addAll(subtypes); } else { for (SubType subtype : subtypes) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostTargetEffect.java index 59e56db5fb..9254999b2b 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/BoostTargetEffect.java @@ -1,8 +1,6 @@ package mage.abilities.effects.common.continuous; -import java.util.Locale; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.dynamicvalue.DynamicValue; @@ -17,8 +15,10 @@ import mage.game.permanent.Permanent; import mage.target.Target; import mage.util.CardUtil; +import java.util.Locale; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class BoostTargetEffect extends ContinuousEffectImpl { @@ -27,6 +27,10 @@ public class BoostTargetEffect extends ContinuousEffectImpl { private DynamicValue toughness; private boolean lockedIn; + public BoostTargetEffect(int power, int toughness) { + this(power, toughness, Duration.EndOfTurn); + } + public BoostTargetEffect(int power, int toughness, Duration duration) { this(new StaticValue(power), new StaticValue(toughness), duration, false); } @@ -39,8 +43,8 @@ public class BoostTargetEffect extends ContinuousEffectImpl { * @param power * @param toughness * @param duration - * @param lockedIn if true, power and toughness will be calculated only - * once, when the ability resolves + * @param lockedIn if true, power and toughness will be calculated only + * once, when the ability resolves */ public BoostTargetEffect(DynamicValue power, DynamicValue toughness, Duration duration, boolean lockedIn) { super(duration, Layer.PTChangingEffects_7, SubLayer.ModifyPT_7c, isCanKill(toughness) ? Outcome.UnboostCreature : Outcome.BoostCreature); @@ -95,7 +99,7 @@ public class BoostTargetEffect extends ContinuousEffectImpl { Target target = mode.getTargets().get(0); StringBuilder sb = new StringBuilder(); if (target.getMaxNumberOfTargets() > 1) { - if (target.getNumberOfTargets() < target.getNumberOfTargets()) { + if (target.getNumberOfTargets() < target.getMaxNumberOfTargets()) { sb.append("up to "); } sb.append(CardUtil.numberToText(target.getMaxNumberOfTargets())).append(" target ").append(target.getTargetName()).append(" get "); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/CantCastMoreThanOneSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/CantCastMoreThanOneSpellEffect.java index e20ec58717..4901a687ec 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/CantCastMoreThanOneSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/CantCastMoreThanOneSpellEffect.java @@ -69,7 +69,7 @@ public class CantCastMoreThanOneSpellEffect extends ContinuousRuleModifyingEffec return false; } } - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); return watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(event.getPlayerId()) > 0; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/ControlEnchantedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/ControlEnchantedEffect.java index 44074e0028..3b8d579a0c 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/ControlEnchantedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/ControlEnchantedEffect.java @@ -35,13 +35,17 @@ public class ControlEnchantedEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { Permanent enchantment = game.getPermanent(source.getSourceId()); - if (enchantment != null && enchantment.getAttachedTo() != null) { + if (enchantment != null + && enchantment.getAttachedTo() != null) { Permanent permanent = game.getPermanent(enchantment.getAttachedTo()); if (permanent != null) { switch (layer) { case ControlChangingEffects_2: if (sublayer == SubLayer.NA) { permanent.changeControllerId(enchantment.getControllerId(), game); + permanent.getAbilities().forEach((ability) -> { + ability.setControllerId(enchantment.getControllerId()); + }); } break; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java index 034f7a273e..fb52506093 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityAttachedEffect.java @@ -70,7 +70,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { public void init(Ability source, Game game) { super.init(source, game); if (affectedObjectsSet) { - Permanent equipment = game.getPermanent(source.getSourceId()); + Permanent equipment = game.getPermanentOrLKIBattlefield(source.getSourceId()); if (equipment != null && equipment.getAttachedTo() != null) { this.setTargetPointer(new FixedTarget(equipment.getAttachedTo(), game.getState().getZoneChangeCounter(equipment.getAttachedTo()))); } @@ -107,7 +107,7 @@ public class GainAbilityAttachedEffect extends ContinuousEffectImpl { } else { sb.append("gains "); } - sb.append(ability.getRule()); + sb.append('"' + ability.getRule("this creature") + '"'); if (!duration.toString().isEmpty()) { sb.append(' ').append(duration.toString()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java index 881e319024..ba4747be4e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainAbilityTargetEffect.java @@ -1,24 +1,18 @@ - package mage.abilities.effects.common.continuous; -import java.util.Locale; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.effects.ContinuousEffectImpl; import mage.cards.Card; -import mage.constants.DependencyType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.Target; +import java.util.Locale; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class GainAbilityTargetEffect extends ContinuousEffectImpl { @@ -88,9 +82,7 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl { return true; } if (durationPhaseStep != null && durationPhaseStep == game.getPhase().getStep().getType()) { - if (!sameStep && game.isActivePlayer(durationPlayerId) || game.getPlayer(durationPlayerId).hasReachedNextTurnAfterLeaving()) { - return true; - } + return !sameStep && game.isActivePlayer(durationPlayerId) || game.getPlayer(durationPlayerId).hasReachedNextTurnAfterLeaving(); } else { sameStep = false; } @@ -137,21 +129,26 @@ public class GainAbilityTargetEffect extends ContinuousEffectImpl { return staticText; } StringBuilder sb = new StringBuilder(); - Target target = mode.getTargets().get(0); - if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) { - sb.append("any number of target ").append(target.getTargetName()).append(" gain "); - } else if (target.getMaxNumberOfTargets() > 1) { - if (target.getNumberOfTargets() < target.getMaxNumberOfTargets()) { - sb.append("up to "); - } - sb.append(target.getMaxNumberOfTargets()).append(" target ").append(target.getTargetName()).append(" gain "); - } else { - if (!target.getTargetName().toUpperCase(Locale.ENGLISH).startsWith("ANOTHER")) { - sb.append("target "); - } - sb.append(target.getTargetName()).append(" gains "); + if (mode.getTargets().size() > 0) { + Target target = mode.getTargets().get(0); + if (target.getMaxNumberOfTargets() == Integer.MAX_VALUE) { + sb.append("any number of target ").append(target.getTargetName()).append(" gain "); + } else if (target.getMaxNumberOfTargets() > 1) { + if (target.getNumberOfTargets() < target.getMaxNumberOfTargets()) { + sb.append("up to "); + } + sb.append(target.getMaxNumberOfTargets()).append(" target ").append(target.getTargetName()).append(" gain "); + } else { + if (!target.getTargetName().toUpperCase(Locale.ENGLISH).startsWith("ANOTHER")) { + sb.append("target "); + } + sb.append(target.getTargetName()).append(" gains "); + } + } else { + sb.append("gains "); } + sb.append(ability.getRule()); if (durationPhaseStep != null) { sb.append(" until your next ").append(durationPhaseStep.toString().toLowerCase(Locale.ENGLISH)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java index 993134026f..129c58657a 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/GainControlTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import java.util.UUID; @@ -98,12 +97,14 @@ public class GainControlTargetEffect extends ContinuousEffectImpl { } } } - if (!targetStillExists) { - // no valid target exists, effect can be discarded + // no valid target exists and the controller is no longer in the game, effect can be discarded + if (!targetStillExists + || !controller.isInGame()) { discard(); } return true; } + discard(); // controller no longer exists return false; } @@ -112,6 +113,11 @@ public class GainControlTargetEffect extends ContinuousEffectImpl { if (!staticText.isEmpty()) { return staticText; } + + if (mode.getTargets().isEmpty()) { + return "gain control of target permanent"; + } + Target target = mode.getTargets().get(0); StringBuilder sb = new StringBuilder("gain control of "); if (target.getMaxNumberOfTargets() > 1) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LookAtTopCardOfLibraryAnyTimeEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LookAtTopCardOfLibraryAnyTimeEffect.java new file mode 100644 index 0000000000..52a614f100 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LookAtTopCardOfLibraryAnyTimeEffect.java @@ -0,0 +1,50 @@ +package mage.abilities.effects.common.continuous; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.cards.Card; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.game.Game; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class LookAtTopCardOfLibraryAnyTimeEffect extends ContinuousEffectImpl { + + public LookAtTopCardOfLibraryAnyTimeEffect() { + super(Duration.WhileOnBattlefield, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); + staticText = "You may look at the top card of your library any time."; + } + + private LookAtTopCardOfLibraryAnyTimeEffect(final LookAtTopCardOfLibraryAnyTimeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return true; + } + Card topCard = controller.getLibrary().getFromTop(game); + if (topCard == null) { + return true; + } + MageObject obj = source.getSourceObject(game); + if (obj == null) { + return true; + } + controller.lookAtCards("Top card of " + obj.getIdName() + " controller's library", topCard, game); + return true; + } + + @Override + public LookAtTopCardOfLibraryAnyTimeEffect copy() { + return new LookAtTopCardOfLibraryAnyTimeEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllCreatureTypesTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllCreatureTypesTargetEffect.java index 1385a7b930..e913d661ab 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllCreatureTypesTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseAllCreatureTypesTargetEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -9,7 +8,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author emerald000 */ public class LoseAllCreatureTypesTargetEffect extends ContinuousEffectImpl { @@ -32,7 +30,7 @@ public class LoseAllCreatureTypesTargetEffect extends ContinuousEffectImpl { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); if (permanent != null) { permanent.setIsAllCreatureTypes(false); - return permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + return permanent.getSubtype(game).retainAll(SubType.getLandTypes()); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseArtifactTypeTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseArtifactTypeTargetEffect.java index ac44c271aa..edff38e966 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseArtifactTypeTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseArtifactTypeTargetEffect.java @@ -1,21 +1,17 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.effects.ContinuousEffectImpl; import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; -import mage.util.CardUtil; import java.util.UUID; /** - * * @author noahg */ -public class LoseArtifactTypeTargetEffect extends ContinuousEffectImpl{ +public class LoseArtifactTypeTargetEffect extends ContinuousEffectImpl { public LoseArtifactTypeTargetEffect(Duration duration) { super(duration, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.Neutral); @@ -53,7 +49,7 @@ public class LoseArtifactTypeTargetEffect extends ContinuousEffectImpl{ case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { permanent.getCardType().remove(CardType.ARTIFACT); - permanent.getSubtype(game).removeAll(SubType.getArtifactTypes(false)); + permanent.getSubtype(game).removeAll(SubType.getArtifactTypes()); } break; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseCreatureTypeSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseCreatureTypeSourceEffect.java index 1af8b2d87d..02405a9d04 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseCreatureTypeSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/LoseCreatureTypeSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; @@ -10,7 +9,6 @@ import mage.game.permanent.Permanent; import mage.util.CardUtil; /** - * * @author LevelX2 */ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implements SourceEffect { @@ -65,7 +63,7 @@ public class LoseCreatureTypeSourceEffect extends ContinuousEffectImpl implement case TypeChangingEffects_4: if (sublayer == SubLayer.NA) { permanent.getCardType().remove(CardType.CREATURE); - permanent.getSubtype(game).retainAll(SubType.getLandTypes(false)); + permanent.getSubtype(game).retainAll(SubType.getLandTypes()); if (permanent.isAttacking() || permanent.getBlocking() > 0) { permanent.removeFromCombat(game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetCardSubtypeAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetCardSubtypeAttachedEffect.java index 2afd1c3abd..05da896fff 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/SetCardSubtypeAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/SetCardSubtypeAttachedEffect.java @@ -1,14 +1,8 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; -import mage.constants.AttachmentType; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.SubLayer; -import mage.constants.SubType; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; import mage.util.SubTypeList; @@ -54,7 +48,7 @@ public class SetCardSubtypeAttachedEffect extends ContinuousEffectImpl { if (equipment != null && equipment.getAttachedTo() != null) { Permanent target = game.getPermanent(equipment.getAttachedTo()); if (target != null) { - target.getSubtype(game).retainAll(SubType.getLandTypes(false)); + target.getSubtype(game).retainAll(SubType.getLandTypes()); target.getSubtype(game).addAll(setSubtypes); } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java index 76999b4f19..0b8c11b397 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapAllDuringEachOtherPlayersUntapStepEffect.java @@ -1,20 +1,14 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.RestrictionEffect; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; +import mage.constants.*; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEffectImpl { @@ -49,7 +43,7 @@ public class UntapAllDuringEachOtherPlayersUntapStepEffect extends ContinuousEff for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, source.getControllerId(), game)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, source, game); + untap &= effect.canBeUntapped(permanent, source, game, true); } if (untap) { permanent.untap(game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java index d1ede8e3a3..1ea738d7b3 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/UntapSourceDuringEachOtherPlayersUntapStepEffect.java @@ -1,19 +1,13 @@ - package mage.abilities.effects.common.continuous; import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.RestrictionEffect; -import mage.constants.Duration; -import mage.constants.Layer; -import mage.constants.Outcome; -import mage.constants.PhaseStep; -import mage.constants.SubLayer; +import mage.constants.*; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author fireshoes */ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends ContinuousEffectImpl { @@ -43,11 +37,11 @@ public class UntapSourceDuringEachOtherPlayersUntapStepEffect extends Continuous && game.getStep() != null && game.getStep().getType() == PhaseStep.UNTAP) { game.getState().setValue(source.getSourceId() + "applied", true); - Permanent permanent = (Permanent) game.getPermanent(source.getSourceId()); + Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, source, game); + untap &= effect.canBeUntapped(permanent, source, game, true); } if (untap) { permanent.untap(game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java index 91bb40fba5..90e19e1c13 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/CastWithoutPayingManaCostEffect.java @@ -3,10 +3,13 @@ package mage.abilities.effects.common.cost; import mage.MageObjectReference; import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.cards.Card; import mage.constants.ComparisonType; import mage.constants.Outcome; +import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; @@ -25,23 +28,23 @@ import org.apache.log4j.Logger; */ public class CastWithoutPayingManaCostEffect extends OneShotEffect { - private final FilterNonlandCard filter; - private final int manaCost; + private final DynamicValue manaCost; /** * @param maxCost Maximum converted mana cost for this effect to apply to */ public CastWithoutPayingManaCostEffect(int maxCost) { + this(new StaticValue(maxCost)); + } + + public CastWithoutPayingManaCostEffect(DynamicValue maxCost) { super(Outcome.PlayForFree); - filter = new FilterNonlandCard("card with converted mana cost " + maxCost + " or less from your hand"); - filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, maxCost + 1)); this.manaCost = maxCost; this.staticText = "you may cast a card with converted mana cost " + maxCost + " or less from your hand without paying its mana cost"; } public CastWithoutPayingManaCostEffect(final CastWithoutPayingManaCostEffect effect) { super(effect); - this.filter = effect.filter.copy(); this.manaCost = effect.manaCost; } @@ -52,11 +55,14 @@ public class CastWithoutPayingManaCostEffect extends OneShotEffect { if (controller == null) { return false; } + int cmc = manaCost.calculate(game, source, this); + FilterCard filter = new FilterNonlandCard("card with converted mana cost " + cmc + " or less from your hand"); + filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, cmc + 1)); Target target = new TargetCardInHand(filter); if (target.canChoose(source.getSourceId(), controller.getId(), game) - && controller.chooseUse(outcome, "Cast a card with converted mana cost " + manaCost - + " or less from your hand without paying its mana cost?", source, game)) { + && controller.chooseUse(outcome, "Cast a card with converted mana cost " + cmc + + " or less from your hand without paying its mana cost?", source, game)) { Card cardToCast = null; boolean cancel = false; while (controller.canRespond() && !cancel) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java index 32a056f599..4e62811543 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.cost; import mage.abilities.Ability; @@ -13,14 +12,17 @@ import mage.game.Game; import mage.util.CardUtil; /** - * * @author LevelX2 */ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl { private final int amount; private ManaCosts manaCostsToReduce = null; - private final Condition condition; + private Condition condition; + + public SpellCostReductionSourceEffect(ManaCosts manaCostsToReduce) { + this(manaCostsToReduce, null); + } public SpellCostReductionSourceEffect(ManaCosts manaCostsToReduce, Condition condition) { super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); @@ -33,19 +35,28 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl { for (String manaSymbol : manaCostsToReduce.getSymbols()) { sb.append(manaSymbol); } - sb.append(" less to if ").append(this.condition.toString()); + sb.append(" less"); + if (this.condition != null) { + sb.append(" to if ").append(this.condition.toString()); + } + this.staticText = sb.toString(); } + public SpellCostReductionSourceEffect(int amount) { + this(amount, null); + } + public SpellCostReductionSourceEffect(int amount, Condition condition) { super(Duration.WhileOnBattlefield, Outcome.Benefit, CostModificationType.REDUCE_COST); this.amount = amount; this.condition = condition; StringBuilder sb = new StringBuilder(); - sb.append("{this} costs {") - .append(amount).append("} less to cast ") - .append((this.condition.toString().startsWith("if ") ? "" : "if ")) - .append(this.condition.toString()); + sb.append("{this} costs {").append(amount).append("} less to cast"); + if (this.condition != null) { + sb.append(" ").append(this.condition.toString().startsWith("if ") ? "" : "if "); + sb.append(this.condition.toString()); + } this.staticText = sb.toString(); } @@ -69,7 +80,7 @@ public class SpellCostReductionSourceEffect extends CostModificationEffectImpl { @Override public boolean applies(Ability abilityToModify, Ability source, Game game) { if (abilityToModify.getSourceId().equals(source.getSourceId()) && (abilityToModify instanceof SpellAbility)) { - return condition.apply(game, source); + return condition == null || condition.apply(game, source); } return false; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java new file mode 100644 index 0000000000..4391755fa3 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/cost/SpellCostReductionSourceForOpponentsEffect.java @@ -0,0 +1,52 @@ +package mage.abilities.effects.common.cost; + +import mage.Mana; +import mage.abilities.Ability; +import mage.abilities.SpellAbility; +import mage.constants.CostModificationType; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.game.Game; + +public class SpellCostReductionSourceForOpponentsEffect extends CostModificationEffectImpl { + + public SpellCostReductionSourceForOpponentsEffect() { + this("undaunted (This spell costs {1} less to cast for each opponent.)"); + } + + public SpellCostReductionSourceForOpponentsEffect(String newStaticText) { + super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); + staticText = newStaticText; + } + + public SpellCostReductionSourceForOpponentsEffect(final SpellCostReductionSourceForOpponentsEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source, Ability abilityToModify) { + SpellAbility spellAbility = (SpellAbility) abilityToModify; + Mana mana = spellAbility.getManaCostsToPay().getMana(); + if (mana.getGeneric() > 0) { + int count = game.getOpponents(source.getControllerId()).size(); + int newCount = mana.getGeneric() - count; + if (newCount < 0) { + newCount = 0; + } + mana.setGeneric(newCount); + spellAbility.getManaCostsToPay().load(mana.toString()); + return true; + } + return false; + } + + @Override + public boolean applies(Ability abilityToModify, Ability source, Game game) { + return abilityToModify instanceof SpellAbility && abilityToModify.getSourceId().equals(source.getSourceId()); + } + + @Override + public SpellCostReductionSourceForOpponentsEffect copy() { + return new SpellCostReductionSourceForOpponentsEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java index afc03b0b89..0687972d50 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersAttachedEffect.java @@ -23,7 +23,7 @@ public class AddCountersAttachedEffect extends OneShotEffect { private String textEnchanted; public AddCountersAttachedEffect(Counter counter, String textEnchanted) { - this(counter, new StaticValue(0), textEnchanted); + this(counter, new StaticValue(1), textEnchanted); } /** @@ -56,8 +56,12 @@ public class AddCountersAttachedEffect extends OneShotEffect { Permanent attachedTo = game.getPermanent(permanent.getAttachedTo()); if (attachedTo != null && counter != null) { Counter newCounter = counter.copy(); - newCounter.add(amount.calculate(game, source, this)); - attachedTo.addCounters(newCounter, source, game); + int countersToAdd = amount.calculate(game, source, this); + if (countersToAdd > 0) { + countersToAdd--; + newCounter.add(countersToAdd); + attachedTo.addCounters(newCounter, source, game); + } } return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java index e50680a73c..4c717eb6e4 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/AddCountersTargetEffect.java @@ -1,8 +1,5 @@ - package mage.abilities.effects.common.counter; -import java.util.Locale; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.Mode; @@ -19,8 +16,10 @@ import mage.players.Player; import mage.target.Target; import mage.util.CardUtil; +import java.util.Locale; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class AddCountersTargetEffect extends OneShotEffect { @@ -121,8 +120,8 @@ public class AddCountersTargetEffect extends OneShotEffect { } sb.append(" on "); - if (!mode.getTargets().isEmpty()) { - Target target = mode.getTargets().get(0); + Target target = mode.getTargets().getEffectTarget(this.targetPointer); + if (target != null) { if (target.getNumberOfTargets() == 0) { sb.append("up to "); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java index 30fec0a1cb..005e6c0712 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/ProliferateEffect.java @@ -1,16 +1,7 @@ - package mage.abilities.effects.common.counter; -import java.io.Serializable; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; -import mage.choices.Choice; -import mage.choices.ChoiceImpl; import mage.constants.Outcome; import mage.counters.Counter; import mage.game.Game; @@ -19,14 +10,30 @@ import mage.players.Player; import mage.target.Target; import mage.target.common.TargetPermanentOrPlayerWithCounter; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + /** * @author nantuko */ public class ProliferateEffect extends OneShotEffect { public ProliferateEffect() { + this("", true); + } + + public ProliferateEffect(boolean showAbilityHint) { + this("", showAbilityHint); + } + + public ProliferateEffect(String afterText, boolean showAbilityHint) { super(Outcome.Benefit); - staticText = "Proliferate. (You choose any number of permanents and/or players with counters on them, then give each another counter of a kind already there.)"; + staticText = "proliferate" + afterText; + if (showAbilityHint) { + staticText += ". (You choose any number of permanents and/or players with counters on them, then give each another counter of each kind already there.)"; + } } public ProliferateEffect(ProliferateEffect effect) { @@ -36,6 +43,7 @@ public class ProliferateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + Counter newCounter = null; if (controller == null) { return false; } @@ -48,60 +56,30 @@ public class ProliferateEffect extends OneShotEffect { Permanent permanent = game.getPermanent(chosen); if (permanent != null) { if (!permanent.getCounters(game).isEmpty()) { - if (permanent.getCounters(game).size() == 1) { - for (Counter counter : permanent.getCounters(game).values()) { - Counter newCounter = new Counter(counter.getName()); - permanent.addCounters(newCounter, source, game); - } - } else { - Choice choice = new ChoiceImpl(true); - Set choices = new HashSet<>(); - for (Counter counter : permanent.getCounters(game).values()) { - choices.add(counter.getName()); - } - choice.setChoices(choices); - choice.setMessage("Choose a counter to proliferate (" + permanent.getIdName() + ')'); - if (controller.choose(Outcome.Benefit, choice, game)) { - for (Counter counter : permanent.getCounters(game).values()) { - if (counter.getName().equals(choice.getChoice())) { - Counter newCounter = new Counter(counter.getName()); - permanent.addCounters(newCounter, source, game); - break; - } - } - } else { - return false; - } + for (Counter counter : permanent.getCounters(game).values()) { + newCounter = new Counter(counter.getName()); + permanent.addCounters(newCounter, source, game); + } + if (newCounter != null) { + game.informPlayers(permanent.getName() + + " had 1 " + + newCounter.getName() + + " counter added to it."); } } } else { Player player = game.getPlayer(chosen); if (player != null) { if (!player.getCounters().isEmpty()) { - if (player.getCounters().size() == 1) { - for (Counter counter : player.getCounters().values()) { - Counter newCounter = new Counter(counter.getName()); - player.addCounters(newCounter, game); - } - } else { - Choice choice = new ChoiceImpl(true); - Set choices = new HashSet<>(); - for (Counter counter : player.getCounters().values()) { - choices.add(counter.getName()); - } - choice.setChoices(choices); - choice.setMessage("Choose a counter to proliferate (" + player.getLogName() + ')'); - if (controller.choose(Outcome.Benefit, choice, game)) { - for (Counter counter : player.getCounters().values()) { - if (counter.getName().equals(choice.getChoice())) { - Counter newCounter = new Counter(counter.getName()); - player.addCounters(newCounter, game); - break; - } - } - } else { - return false; - } + for (Counter counter : player.getCounters().values()) { + newCounter = new Counter(counter.getName()); + player.addCounters(newCounter, game); + } + if (newCounter != null) { + game.informPlayers(player.getName() + + " had 1 " + + newCounter.getName() + + " counter added to them."); } } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java index 4cd077f158..6345058e2f 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/counter/RemoveCounterSourceEffect.java @@ -1,4 +1,3 @@ - package mage.abilities.effects.common.counter; import mage.abilities.Ability; diff --git a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java index 5e8ddbdac5..ad8a25bbde 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/discard/DiscardCardYouChooseTargetEffect.java @@ -1,8 +1,5 @@ - package mage.abilities.effects.common.discard; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.StaticValue; @@ -20,8 +17,10 @@ import mage.target.TargetCard; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; +import java.util.List; +import java.util.UUID; + /** - * * @author noxx */ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { @@ -98,7 +97,6 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(targetPointer.getFirst(game, source)); Player controller = game.getPlayer(source.getControllerId()); - Card sourceCard = game.getCard(source.getSourceId()); if (player != null && controller != null) { if (revealAllCards) { this.numberCardsToReveal = new StaticValue(player.getHand().size()); @@ -125,6 +123,7 @@ public class DiscardCardYouChooseTargetEffect extends OneShotEffect { revealedCards.addAll(player.getHand()); } + Card sourceCard = game.getCard(source.getSourceId()); player.revealCards(sourceCard != null ? sourceCard.getIdName() + " (" + sourceCard.getZoneChangeCounter(game) + ')' : "Discard", revealedCards, game); boolean result = true; diff --git a/Mage/src/main/java/mage/abilities/effects/common/replacement/DealtDamageToCreatureBySourceDies.java b/Mage/src/main/java/mage/abilities/effects/common/replacement/DealtDamageToCreatureBySourceDies.java index 673acae848..0c974f4021 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/replacement/DealtDamageToCreatureBySourceDies.java +++ b/Mage/src/main/java/mage/abilities/effects/common/replacement/DealtDamageToCreatureBySourceDies.java @@ -63,7 +63,7 @@ public class DealtDamageToCreatureBySourceDies extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zce = (ZoneChangeEvent) event; if (zce.isDiesEvent()) { - DamagedByWatcher watcher = (DamagedByWatcher) game.getState().getWatchers().get(DamagedByWatcher.class.getSimpleName(), source.getSourceId()); + DamagedByWatcher watcher = game.getState().getWatcher(DamagedByWatcher.class, source.getSourceId()); if (watcher != null) { return watcher.wasDamaged(zce.getTarget(), game); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyIfYouHaveCastAnotherSpellEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyIfYouHaveCastAnotherSpellEffect.java index 7126808c81..e3de9c3cf7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyIfYouHaveCastAnotherSpellEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CastOnlyIfYouHaveCastAnotherSpellEffect.java @@ -32,7 +32,7 @@ public class CastOnlyIfYouHaveCastAnotherSpellEffect extends ContinuousRuleModif @Override public boolean applies(GameEvent event, Ability source, Game game) { if (event.getSourceId().equals(source.getSourceId())) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null && watcher.getAmountOfSpellsPlayerCastOnCurrentTurn(source.getControllerId()) == 0) { return true; } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CombatDamageByToughnessEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CombatDamageByToughnessEffect.java new file mode 100644 index 0000000000..a72ec5c1e6 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/CombatDamageByToughnessEffect.java @@ -0,0 +1,62 @@ + +package mage.abilities.effects.common.ruleModifying; + +import mage.abilities.Ability; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.constants.Duration; +import mage.constants.Layer; +import mage.constants.Outcome; +import mage.constants.SubLayer; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.ControllerIdPredicate; +import mage.game.Game; + +/** + * @author TheElk801 + */ +public class CombatDamageByToughnessEffect extends ContinuousEffectImpl { + + private final FilterCreaturePermanent filter; + private final boolean onlyControlled; + + public CombatDamageByToughnessEffect(FilterCreaturePermanent filter, boolean onlyControlled) { + super(Duration.WhileOnBattlefield, Outcome.Detriment); + this.filter = filter; + this.onlyControlled = onlyControlled; + staticText = "Each " + filter.getMessage() + (onlyControlled ? " you control" : "") + + " assigns combat damage equal to its toughness rather than its power"; + } + + private CombatDamageByToughnessEffect(final CombatDamageByToughnessEffect effect) { + super(effect); + this.filter = effect.filter; + this.onlyControlled = effect.onlyControlled; + } + + @Override + public CombatDamageByToughnessEffect copy() { + return new CombatDamageByToughnessEffect(this); + } + + @Override + public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { + // Change the rule + FilterCreaturePermanent filterPermanent = filter.copy(); + if (onlyControlled) { + filterPermanent.add(new ControllerIdPredicate(source.getControllerId())); + } + game.getCombat().setUseToughnessForDamage(true); + game.getCombat().addUseToughnessForDamageFilter(filterPermanent); + return true; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.RulesEffects; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java index 944262e9ac..e02f7003b7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/TargetsHaveToTargetPermanentIfAbleEffect.java @@ -5,8 +5,6 @@ */ package mage.abilities.effects.common.ruleModifying; -import java.util.List; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.ActivatedAbility; @@ -14,6 +12,7 @@ import mage.abilities.SpellAbility; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.constants.Duration; import mage.constants.Outcome; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.events.GameEvent; @@ -22,11 +21,14 @@ import mage.game.stack.StackObject; import mage.players.Player; import mage.target.Target; +import java.util.List; +import java.util.UUID; + /** * 6/8/2016 If a spell or ability's targets are changed, or if a copy of a spell * or ability is put onto the stack and has new targets chosen, it doesn't have * to target a Flagbearer. - * + *

    * 3/16/2017 A Flagbearer only requires targeting of itself when choosing targets * as a result of casting a spell or activating an ability. Notably, triggered * abilities are exempt from this targeting restriction (in addition to the note @@ -37,15 +39,22 @@ import mage.target.Target; public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModifyingEffectImpl { private final FilterPermanent filter; + private static final FilterPermanent flagbearerFilter = new FilterPermanent(SubType.FLAGBEARER, "one Flagbearer"); + + public TargetsHaveToTargetPermanentIfAbleEffect() { + this(flagbearerFilter); + } public TargetsHaveToTargetPermanentIfAbleEffect(FilterPermanent filter) { super(Duration.WhileOnBattlefield, Outcome.Detriment); this.filter = filter; - staticText = "While choosing targets as part of casting a spell or activating an ability, your opponents must choose at least " + this.filter.getMessage() + " on the battlefield if able"; + staticText = "While an opponent is choosing targets as part of casting a spell they control " + + "or activating an ability they control, that player must choose at least " + + this.filter.getMessage() + " on the battlefield if able"; } - public TargetsHaveToTargetPermanentIfAbleEffect(final TargetsHaveToTargetPermanentIfAbleEffect effect) { + private TargetsHaveToTargetPermanentIfAbleEffect(final TargetsHaveToTargetPermanentIfAbleEffect effect) { super(effect); this.filter = effect.filter; } @@ -83,7 +92,11 @@ public class TargetsHaveToTargetPermanentIfAbleEffect extends ContinuousRuleModi Ability stackAbility = stackObject.getStackAbility(); // Ensure that this ability is activated or a cast spell, because Flag Bearer effects don't require triggered abilities to choose a Standard Bearer if (!(stackAbility instanceof ActivatedAbility) && - !(stackAbility instanceof SpellAbility)) { + !(stackAbility instanceof SpellAbility)) { + return false; + } + // Also check that targeting player controls the ability + if (!stackAbility.isControlledBy(targetingPlayer.getId())) { return false; } Ability ability = (Ability) getValue("targetAbility"); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutInHandEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutInHandEffect.java index 7f1d990bb2..e23b92b1dc 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutInHandEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutInHandEffect.java @@ -34,7 +34,7 @@ public class SearchLibraryGraveyardPutInHandEffect extends OneShotEffect { super(Outcome.Benefit); this.filter = filter; this.forceToSearchBoth = forceToSearchBoth; - staticText = (youMay ? "You may" : "") + "search your library and" + (forceToSearchBoth ? "" : "/or") + " graveyard for a card named " + filter.getMessage() + staticText = (youMay ? "You may" : "") + " search your library and" + (forceToSearchBoth ? "" : "/or") + " graveyard for a card named " + filter.getMessage() + ", reveal it, and put it into your hand. " + (forceToSearchBoth ? "Then shuffle your library" : "If you search your library this way, shuffle it"); } @@ -59,7 +59,7 @@ public class SearchLibraryGraveyardPutInHandEffect extends OneShotEffect { if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + '?', source, game)) { TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); target.clearChosen(); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { cardFound = game.getCard(target.getFirstTarget()); } diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java new file mode 100644 index 0000000000..627244f47b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java @@ -0,0 +1,91 @@ +package mage.abilities.effects.common.search; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author Styxo + */ +public class SearchLibraryGraveyardPutOntoBattlefieldEffect extends OneShotEffect { + + private FilterCard filter; + private boolean forceToSearchBoth; + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter) { + this(filter, false); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth) { + this(filter, forceToSearchBoth, false); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth, boolean youMay) { + super(Outcome.Benefit); + this.filter = filter; + this.forceToSearchBoth = forceToSearchBoth; + staticText = (youMay ? "You may" : "") + " search your library and" + (forceToSearchBoth ? "" : "/or") + " graveyard for a card named " + filter.getMessage() + + ", reveal it, and put it into your hand. " + (forceToSearchBoth ? "Then shuffle your library" : "If you search your library this way, shuffle it"); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(final SearchLibraryGraveyardPutOntoBattlefieldEffect effect) { + super(effect); + this.filter = effect.filter; + this.forceToSearchBoth = effect.forceToSearchBoth; + + } + + @Override + public SearchLibraryGraveyardPutOntoBattlefieldEffect copy() { + return new SearchLibraryGraveyardPutOntoBattlefieldEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + Card cardFound = null; + if (controller != null && sourceObject != null) { + if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + '?', source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); + target.clearChosen(); + if (controller.searchLibrary(target, source, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + controller.shuffleLibrary(source, game); + } + + if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a card named " + filter.getMessage() + '?', source, game)) { + TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, filter); + target.clearChosen(); + if (controller.choose(outcome, controller.getGraveyard(), target, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + } + + if (cardFound != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game); + controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game); + } + + return true; + } + + return false; + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java new file mode 100644 index 0000000000..09754429ba --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java @@ -0,0 +1,87 @@ +package mage.abilities.effects.common.search; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.constants.ComparisonType; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author antoni-g + */ +public class SearchLibraryGraveyardWithLessCMCPutIntoPlay extends OneShotEffect { + + private final FilterCard filter; + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay() { + this(new FilterCard()); + } + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay(FilterCard filter) { + super(Outcome.PutCreatureInPlay); + this.filter = filter; + staticText = "Search your library or graveyard for a " + filter.getMessage() + " with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; + } + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay(final SearchLibraryGraveyardWithLessCMCPutIntoPlay effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public SearchLibraryGraveyardWithLessCMCPutIntoPlay copy() { + return new SearchLibraryGraveyardWithLessCMCPutIntoPlay(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + Card cardFound = null; + if (controller != null && sourceObject != null) { + // create x cost filter + FilterCard advancedFilter = filter.copy(); // never change static objects so copy the object here before + advancedFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); + + if (controller.chooseUse(outcome, "Search your library for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(advancedFilter); + target.clearChosen(); + if (controller.searchLibrary(target, source, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + controller.shuffleLibrary(source, game); + } + + if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) { + TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, advancedFilter); + target.clearChosen(); + if (controller.choose(outcome, controller.getGraveyard(), target, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + } + + if (cardFound != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game); + controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game); + } + + return true; + } + return false; + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandEffect.java index 23a1f43d8b..788c3e3754 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandEffect.java @@ -63,7 +63,7 @@ public class SearchLibraryPutInHandEffect extends SearchEffect { return false; } target.clearChosen(); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); for (UUID cardId : target.getTargets()) { diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java index 87e8ed12f5..86bd7d7337 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInHandOrOnBattlefieldEffect.java @@ -66,7 +66,7 @@ public class SearchLibraryPutInHandOrOnBattlefieldEffect extends SearchEffect { return false; } target.clearChosen(); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards cards = new CardsImpl(); boolean askToPutOntoBf = false; diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java index c519f1736e..940931dfac 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayEffect.java @@ -62,7 +62,7 @@ public class SearchLibraryPutInPlayEffect extends SearchEffect { if (player == null) { return false; } - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, tapped, false, false, null); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java index 507223d1f6..e2877c9fc6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutInPlayTargetPlayerEffect.java @@ -70,7 +70,7 @@ public class SearchLibraryPutInPlayTargetPlayerEffect extends SearchEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(getTargetPointer().getFirst(game, source)); if (player != null) { - if (player.searchLibrary(target, game)) { + if (player.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { player.moveCards(new CardsImpl(target.getTargets()).getCards(game), Zone.BATTLEFIELD, source, game, tapped, false, ownerIsController, null); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java index 0766baf14e..d9923a55b0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryPutOnLibraryEffect.java @@ -50,7 +50,7 @@ public class SearchLibraryPutOnLibraryEffect extends SearchEffect { if (controller == null || sourceObject == null) { return false; } - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { Cards foundCards = new CardsImpl(target.getTargets()); if (reveal && !foundCards.isEmpty()) { controller.revealCards(sourceObject.getIdName(), foundCards, game); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java index 61d5e9e2cf..c116004e5e 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryWithLessCMCPutInPlayEffect.java @@ -43,7 +43,7 @@ public class SearchLibraryWithLessCMCPutInPlayEffect extends OneShotEffect { FilterCard advancedFilter = filter.copy(); // never change static objects so copy the object here before advancedFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); TargetCardInLibrary target = new TargetCardInLibrary(advancedFilter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Card card = controller.getLibrary().getCard(target.getFirstTarget(), game); if (card != null) { diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java new file mode 100644 index 0000000000..ed29b59aea --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AdaptEffect.java @@ -0,0 +1,56 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.constants.Outcome; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.util.CardUtil; + +/** + * @author TheElk801 + */ +public class AdaptEffect extends OneShotEffect { + + private final int adaptNumber; + + public AdaptEffect(int adaptNumber) { + super(Outcome.BoostCreature); + this.adaptNumber = adaptNumber; + staticText = "Adapt " + adaptNumber + + " (If this creature has no +1/+1 counters on it, put " + + CardUtil.numberToText(adaptNumber) + " +1/+1 counter" + + (adaptNumber > 1 ? "s" : "") + " on it.)"; + } + + private AdaptEffect(final AdaptEffect effect) { + super(effect); + this.adaptNumber = effect.adaptNumber; + } + + @Override + public AdaptEffect copy() { + return new AdaptEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; + } + GameEvent event = new GameEvent( + GameEvent.EventType.ADAPT, source.getSourceId(), source.getSourceId(), + source.getControllerId(), adaptNumber, false + ); + if (game.replaceEvent(event)) { + return false; + } + if (permanent.getCounters(game).getCount(CounterType.P1P1) == 0 || event.getFlag()) { + permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount()), source, game); + } + return true; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java new file mode 100644 index 0000000000..ff46aaa66b --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/keyword/AmassEffect.java @@ -0,0 +1,91 @@ +package mage.abilities.effects.keyword; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.abilities.dynamicvalue.common.StaticValue; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.game.permanent.token.ZombieArmyToken; +import mage.players.Player; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class AmassEffect extends OneShotEffect { + + private static final FilterPermanent filter = new FilterControlledPermanent("Army you control"); + + static { + filter.add(new SubtypePredicate(SubType.ARMY)); + } + + private final DynamicValue amassNumber; + private UUID amassedCreatureId = null; + + public AmassEffect(int amassNumber) { + this(new StaticValue(amassNumber)); + staticText = "amass " + amassNumber + ". (Put " + CardUtil.numberToText(amassNumber) + + " +1/+1 counter" + (amassNumber > 1 ? "s " : " ") + + "on an Army you control. If you don’t control one, " + + "create a 0/0 black Zombie Army creature token first.)"; + } + + public AmassEffect(DynamicValue amassNumber) { + super(Outcome.BoostCreature); + this.amassNumber = amassNumber; + staticText = "amass X, where X is the number of " + amassNumber.getMessage() + ". (Put X +1/+1 counters" + + "on an Army you control. If you don’t control one, " + + "create a 0/0 black Zombie Army creature token first.)"; + } + + private AmassEffect(final AmassEffect effect) { + super(effect); + this.amassNumber = effect.amassNumber; + } + + @Override + public AmassEffect copy() { + return new AmassEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int xValue = amassNumber.calculate(game, source, this); + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + if (!game.getBattlefield().contains(filter, source.getControllerId(), 1, game)) { + new CreateTokenEffect(new ZombieArmyToken()).apply(game, source); + } + Target target = new TargetPermanent(filter); + target.setNotTarget(true); + if (!player.choose(outcome, target, source.getSourceId(), game)) { + return false; + } + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent == null) { + return false; + } + permanent.addCounters(CounterType.P1P1.createInstance(xValue), source, game); + this.amassedCreatureId = permanent.getId(); + return true; + } + + public UUID getAmassedCreatureId() { + return amassedCreatureId; + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/keyword/EchoEffect.java b/Mage/src/main/java/mage/abilities/effects/keyword/EchoEffect.java index e2d20da03b..15978c837b 100644 --- a/Mage/src/main/java/mage/abilities/effects/keyword/EchoEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/keyword/EchoEffect.java @@ -80,6 +80,12 @@ public class EchoEffect extends OneShotEffect { @Override public String getText(Mode mode) { StringBuilder sb = new StringBuilder("sacrifice {this} unless you "); + + if (cost == null) { + sb.append("pay this permanent's mana cost"); + return sb.toString(); + } + String costText = cost.getText(); if (costText.toLowerCase(Locale.ENGLISH).startsWith("discard")) { sb.append(costText.substring(0, 1).toLowerCase(Locale.ENGLISH)); diff --git a/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java b/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java index dc03549ea0..42f5af2737 100644 --- a/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/mana/AddManaOfAnyColorEffect.java @@ -70,12 +70,14 @@ public class AddManaOfAnyColorEffect extends BasicManaEffect { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { String mes = String.format("Select color of %d mana to add it", this.amount); - ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId())); - if (controller.choose(outcome, choice, game)) { - if (choice.getColor() != null) { - Mana mana = choice.getMana(amount); - mana.setFlag(setFlag); - return mana; + if (mes != null) { + ChoiceColor choice = new ChoiceColor(true, mes, game.getObject(source.getSourceId())); + if (controller.choose(outcome, choice, game)) { + if (choice.getColor() != null) { + Mana mana = choice.getMana(amount); + mana.setFlag(setFlag); + return mana; + } } } } diff --git a/Mage/src/main/java/mage/abilities/hint/ConditionHint.java b/Mage/src/main/java/mage/abilities/hint/ConditionHint.java new file mode 100644 index 0000000000..4df8b1cf59 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/ConditionHint.java @@ -0,0 +1,59 @@ +package mage.abilities.hint; + +import mage.abilities.Ability; +import mage.abilities.condition.Condition; +import mage.game.Game; + +import java.awt.*; + +/** + * @author JayDi85 + */ +public class ConditionHint implements Hint { + + private Condition condition; + private String trueText; + private Color trueColor; + private String falseText; + private Color falseColor; + private Boolean useIcons; + + public ConditionHint(Condition condition, String textWithIcons) { + this(condition, textWithIcons, null, textWithIcons, null, true); + } + + public ConditionHint(Condition condition, String trueText, Color trueColor, String falseText, Color falseColor, Boolean useIcons) { + this.condition = condition; + this.trueText = trueText; + this.trueColor = trueColor; + this.falseText = falseText; + this.falseColor = falseColor; + this.useIcons = useIcons; + } + + private ConditionHint(final ConditionHint hint) { + this.condition = hint.condition; + this.trueText = hint.trueText; + this.trueColor = hint.trueColor; + this.falseText = hint.falseText; + this.falseColor = hint.falseColor; + this.useIcons = hint.useIcons; + } + + @Override + public String getText(Game game, Ability ability) { + String icon; + if (condition.apply(game, ability)) { + icon = this.useIcons ? HintUtils.HINT_ICON_GOOD : null; + return HintUtils.prepareText(this.trueText, this.trueColor, icon); + } else { + icon = this.useIcons ? HintUtils.HINT_ICON_BAD : null; + return HintUtils.prepareText(this.falseText, this.falseColor, icon); + } + } + + @Override + public Hint copy() { + return new ConditionHint(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/Hint.java b/Mage/src/main/java/mage/abilities/hint/Hint.java new file mode 100644 index 0000000000..71a0ef8cbc --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/Hint.java @@ -0,0 +1,16 @@ +package mage.abilities.hint; + +import mage.abilities.Ability; +import mage.game.Game; + +import java.io.Serializable; + +/** + * @author JayDi85 + */ +public interface Hint extends Serializable { + + String getText(Game game, Ability ability); + + Hint copy(); +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/hint/HintUtils.java b/Mage/src/main/java/mage/abilities/hint/HintUtils.java new file mode 100644 index 0000000000..4fc94befaf --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/HintUtils.java @@ -0,0 +1,56 @@ +package mage.abilities.hint; + +import java.awt.*; +import java.util.HashSet; +import java.util.List; + +/** + * @author JayDi85 + */ +public class HintUtils { + + public static final boolean ABILITY_HINTS_ENABLE = true; + public static final boolean RESTRICT_HINTS_ENABLE = true; + + // icons changes to real files on client side (see mana icons replacement) + public static final String HINT_ICON_GOOD = "ICON_GOOD"; + public static final String HINT_ICON_BAD = "ICON_BAD"; + public static final String HINT_ICON_RESTRICT = "ICON_RESTRICT"; + + // + public static final String HINT_START_MARK = "
    "; // workaround to find hint text in rules list and shows it in html + + public static String prepareText(String text, Color color) { + return prepareText(text, color, null); + } + + public static String prepareText(String text, Color color, String icon) { + String res; + + // text + if (text != null && color != null) { + String hex = String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()); + res = String.format("%s", hex, text); + } else { + res = text; + } + + // icon + if (res != null && icon != null) { + res = icon + res; + } + + return res; + } + + public static void appendHints(List destList, List newHints) { + // append only unique hints + HashSet used = new HashSet<>(); + for (String s : newHints) { + if (!used.contains(s)) { + destList.add(s); + used.add(s); + } + } + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/StaticHint.java b/Mage/src/main/java/mage/abilities/hint/StaticHint.java new file mode 100644 index 0000000000..848b09ac56 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/StaticHint.java @@ -0,0 +1,36 @@ +package mage.abilities.hint; + +import mage.abilities.Ability; +import mage.game.Game; + +import java.awt.*; + +/** + * @author JayDi85 + */ +public class StaticHint implements Hint { + + private String text; + + public StaticHint(String text) { + this(text, null); + } + + public StaticHint(String text, Color color) { + this.text = HintUtils.prepareText(text, color); + } + + private StaticHint(final StaticHint hint) { + this.text = hint.text; + } + + @Override + public String getText(Game game, Ability ability) { + return text; + } + + @Override + public Hint copy() { + return new StaticHint(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/ValueHint.java b/Mage/src/main/java/mage/abilities/hint/ValueHint.java new file mode 100644 index 0000000000..49c03d7c91 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/ValueHint.java @@ -0,0 +1,34 @@ +package mage.abilities.hint; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.DynamicValue; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public class ValueHint implements Hint { + + private String name; + private DynamicValue value; + + public ValueHint(String name, DynamicValue value) { + this.name = name; + this.value = value; + } + + private ValueHint(final ValueHint hint) { + this.name = hint.name; + this.value = hint.value.copy(); + } + + @Override + public String getText(Game game, Ability ability) { + return name + ": " + value.calculate(game, ability, null); + } + + @Override + public Hint copy() { + return new ValueHint(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/CitysBlessingHint.java b/Mage/src/main/java/mage/abilities/hint/common/CitysBlessingHint.java new file mode 100644 index 0000000000..80708eaa51 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/CitysBlessingHint.java @@ -0,0 +1,26 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.condition.common.CitysBlessingCondition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum CitysBlessingHint implements Hint { + + instance; + private static final ConditionHint hint = new ConditionHint(CitysBlessingCondition.instance, "You have city's blessing"); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/CreaturesYouControlHint.java b/Mage/src/main/java/mage/abilities/hint/common/CreaturesYouControlHint.java new file mode 100644 index 0000000000..f596d3c590 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/CreaturesYouControlHint.java @@ -0,0 +1,26 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum CreaturesYouControlHint implements Hint { + + instance; + private static final Hint hint = new ValueHint("Creatures you control", CreaturesYouControlCount.instance); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/DeliriumHint.java b/Mage/src/main/java/mage/abilities/hint/common/DeliriumHint.java new file mode 100644 index 0000000000..824f4e4597 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/DeliriumHint.java @@ -0,0 +1,27 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.condition.common.DeliriumCondition; +import mage.abilities.dynamicvalue.common.CardTypesInGraveyardCount; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum DeliriumHint implements Hint { + + instance; + private static final ConditionHint hint = new ConditionHint(DeliriumCondition.instance, "4+ card types in your graveyard"); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability) + " (current: " + CardTypesInGraveyardCount.instance.calculate(game, ability, null) + ")"; + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/FerociousHint.java b/Mage/src/main/java/mage/abilities/hint/common/FerociousHint.java new file mode 100644 index 0000000000..a934da23e7 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/FerociousHint.java @@ -0,0 +1,26 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.condition.common.FerociousCondition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum FerociousHint implements Hint { + + instance; + private static final ConditionHint hint = new ConditionHint(FerociousCondition.instance, "You control a creature with power 4+"); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/GateYouControlHint.java b/Mage/src/main/java/mage/abilities/hint/common/GateYouControlHint.java new file mode 100644 index 0000000000..5a2498624a --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/GateYouControlHint.java @@ -0,0 +1,27 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.dynamicvalue.common.GateYouControlCount; +import mage.abilities.hint.Hint; +import mage.abilities.hint.ValueHint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum GateYouControlHint implements Hint { + + instance; + + private static final Hint hint = new ValueHint("Gate you control", GateYouControlCount.instance); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/hint/common/SpectacleHint.java b/Mage/src/main/java/mage/abilities/hint/common/SpectacleHint.java new file mode 100644 index 0000000000..81d7d3afa6 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/hint/common/SpectacleHint.java @@ -0,0 +1,26 @@ +package mage.abilities.hint.common; + +import mage.abilities.Ability; +import mage.abilities.condition.common.OpponentsLostLifeCondition; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.game.Game; + +/** + * @author JayDi85 + */ +public enum SpectacleHint implements Hint { + + instance; + private static final ConditionHint hint = new ConditionHint(OpponentsLostLifeCondition.instance, "Opponents lost life this turn"); + + @Override + public String getText(Game game, Ability ability) { + return hint.getText(game, ability); + } + + @Override + public Hint copy() { + return instance; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/AdaptAbility.java b/Mage/src/main/java/mage/abilities/keyword/AdaptAbility.java new file mode 100644 index 0000000000..65d037d8c1 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/AdaptAbility.java @@ -0,0 +1,27 @@ + + +package mage.abilities.keyword; + +import mage.abilities.ActivatedAbilityImpl; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.keyword.AdaptEffect; +import mage.constants.Zone; + +/** + * @author TheElk801 + */ +public class AdaptAbility extends ActivatedAbilityImpl { + + public AdaptAbility(int adaptNumber, String manaCost) { + super(Zone.BATTLEFIELD, new AdaptEffect(adaptNumber), new ManaCostsImpl(manaCost)); + } + + private AdaptAbility(final AdaptAbility ability) { + super(ability); + } + + @Override + public AdaptAbility copy() { + return new AdaptAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java b/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java new file mode 100644 index 0000000000..2fa1c7ecf3 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/AfterlifeAbility.java @@ -0,0 +1,35 @@ +package mage.abilities.keyword; + +import mage.abilities.common.DiesTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.game.permanent.token.WhiteBlackSpiritToken; +import mage.util.CardUtil; + +public class AfterlifeAbility extends DiesTriggeredAbility { + + private final int tokenCount; + + public AfterlifeAbility(int tokenCount) { + super(new CreateTokenEffect(new WhiteBlackSpiritToken(), tokenCount), false); + this.tokenCount = tokenCount; + } + + public AfterlifeAbility(final AfterlifeAbility ability) { + super(ability); + this.tokenCount = ability.tokenCount; + } + + @Override + public String getRule() { + return "Afterlife " + tokenCount + " (When this creature dies, create " + + CardUtil.numberToText(tokenCount, "a") + + " 1/1 white and black Spirit creature token" + + (tokenCount > 1 ? "s" : "") + + " with flying.)"; + } + + @Override + public AfterlifeAbility copy() { + return new AfterlifeAbility(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java b/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java new file mode 100644 index 0000000000..528cc744df --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/BandsWithOtherAbility.java @@ -0,0 +1,79 @@ + +package mage.abilities.keyword; + +import mage.abilities.StaticAbility; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; + +/** + * + * @author L_J + */ +public class BandsWithOtherAbility extends StaticAbility { + + private SubType subtype; + private SuperType supertype; + private String bandingName; + + public BandsWithOtherAbility() { + this(null, null, null); + } + + public BandsWithOtherAbility(SubType subtype) { + this(subtype, null, null); + } + + public BandsWithOtherAbility(SuperType supertype) { + this(null, supertype, null); + } + + public BandsWithOtherAbility(String bandingName) { + this(null, null, bandingName); + } + + public BandsWithOtherAbility(SubType subtype, SuperType supertype, String bandingName) { + super(Zone.ALL, null); + this.subtype = subtype; + this.supertype = supertype; + this.bandingName = bandingName; + } + + public BandsWithOtherAbility(BandsWithOtherAbility ability) { + super(ability); + this.subtype = ability.subtype; + this.supertype = ability.supertype; + this.bandingName = ability.bandingName; + } + + @Override + public BandsWithOtherAbility copy() { + return new BandsWithOtherAbility(this); + } + + public SubType getSubtype() { + return subtype; + } + + public SuperType getSupertype() { + return supertype; + } + + public String getName() { + return bandingName; + } + + @Override + public String getRule() { + StringBuilder sb = new StringBuilder("bands with other"); + if (subtype != null) { + return sb.append(' ').append(subtype.getDescription()).append('s').toString(); + } else if (supertype != null) { + return sb.append(' ').append(supertype.toString()).append(" creatures").toString(); + } else if (bandingName != null) { + return sb.append(" creatures named ").append(bandingName).toString(); + } + return "all \"" + sb.toString() + "\" abilities"; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java b/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java index 873e0c82c9..885301b7a5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BloodthirstAbility.java @@ -69,15 +69,15 @@ class BloodthirstEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); if (player != null) { - BloodthirstWatcher watcher = (BloodthirstWatcher) game.getState().getWatchers().get(BloodthirstWatcher.class.getSimpleName(), source.getControllerId()); + BloodthirstWatcher watcher = game.getState().getWatcher(BloodthirstWatcher.class, source.getControllerId()); if (watcher != null && watcher.conditionMet()) { Permanent permanent = game.getPermanentEntering(source.getSourceId()); if (permanent != null) { ArrayList appliedEffects = (ArrayList) this.getValue("appliedEffects"); // the basic event is the EntersBattlefieldEvent, so use already applied replacement effects from that event permanent.addCounters(CounterType.P1P1.createInstance(amount), source, game, appliedEffects); } + return true; } - return true; } return false; } diff --git a/Mage/src/main/java/mage/abilities/keyword/BountyAbility.java b/Mage/src/main/java/mage/abilities/keyword/BountyAbility.java index e41e160ec7..0879c6608b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BountyAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BountyAbility.java @@ -19,23 +19,23 @@ import mage.filter.predicate.permanent.CounterPredicate; */ public class BountyAbility extends DiesCreatureTriggeredAbility { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature an opponent controls with a bounty counter on it"); + private static final FilterCreaturePermanent bountyCounterFilter = new FilterCreaturePermanent("creature an opponent controls with a bounty counter on it"); static { - filter.add(new ControllerPredicate(TargetController.OPPONENT)); - filter.add(new CounterPredicate(CounterType.BOUNTY)); + bountyCounterFilter.add(new ControllerPredicate(TargetController.OPPONENT)); + bountyCounterFilter.add(new CounterPredicate(CounterType.BOUNTY)); } public BountyAbility(Effect effect) { - super(effect, false, filter); + super(effect, false, bountyCounterFilter); } public BountyAbility(Effect effect, boolean optional) { - super(effect, optional, filter); + super(effect, optional, bountyCounterFilter); } public BountyAbility(Effect effect, boolean optional, boolean setTargetPointer) { - super(effect, optional, filter, setTargetPointer); + super(effect, optional, bountyCounterFilter, setTargetPointer); } public BountyAbility(final BountyAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/BuybackAbility.java b/Mage/src/main/java/mage/abilities/keyword/BuybackAbility.java index a889f8dd79..4cc80bd106 100644 --- a/Mage/src/main/java/mage/abilities/keyword/BuybackAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/BuybackAbility.java @@ -51,7 +51,7 @@ public class BuybackAbility extends StaticAbility implements OptionalAdditionalS public BuybackAbility(Cost cost) { super(Zone.STACK, new BuybackEffect()); - this.buybackCost = new OptionalAdditionalCostImpl(keywordText, "-", reminderTextCost, cost); + this.buybackCost = new OptionalAdditionalCostImpl(keywordText, "—", reminderTextCost, cost); setRuleAtTheTop(true); } diff --git a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java index 3292aa3a36..3f44a43db9 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CascadeAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.MageObjectReference; @@ -21,7 +20,7 @@ import mage.players.Player; public class CascadeAbility extends TriggeredAbilityImpl { //20091005 - 702.82 - private final static String REMINDERTEXT = " (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less." + private static final String REMINDERTEXT = " (When you cast this spell, exile cards from the top of your library until you exile a nonland card that costs less." + " You may cast it without paying its mana cost. Put the exiled cards on the bottom in a random order.)"; private boolean withReminder; @@ -84,7 +83,11 @@ class CascadeEffect extends OneShotEffect { return false; } ExileZone exile = game.getExile().createZone(source.getSourceId(), controller.getName() + " Cascade"); - int sourceCost = game.getCard(source.getSourceId()).getConvertedManaCost(); + card = game.getCard(source.getSourceId()); + if (card == null) { + return false; + } + int sourceCost = card.getConvertedManaCost(); do { card = controller.getLibrary().getFromTop(game); if (card == null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java index 28331ab692..b073f23f6f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ChampionAbility.java @@ -99,7 +99,7 @@ public class ChampionAbility extends StaticAbility { if (requiresCreature) { filter.add(new CardTypePredicate(CardType.CREATURE)); } - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); // When this permanent enters the battlefield, sacrifice it unless you exile another [object] you control. Ability ability1 = new EntersBattlefieldTriggeredAbility( diff --git a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java index 30778d34e2..9854465661 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConspireAbility.java @@ -55,7 +55,7 @@ public class ConspireAbility extends StaticAbility implements OptionalAdditional protected static final String CONSPIRE_ACTIVATION_KEY = "ConspireActivation"; static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); filter.add(new SharesColorWithSourcePredicate()); filter.add(new CardTypePredicate(CardType.CREATURE)); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java index afba2dcd99..19a50c3e32 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ConvokeAbility.java @@ -69,7 +69,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana private static final FilterCreaturePermanent filterUntapped = new FilterCreaturePermanent(); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } public ConvokeAbility() { @@ -96,7 +96,7 @@ public class ConvokeAbility extends SimpleStaticAbility implements AlternateMana specialAction.setSourceId(source.getSourceId()); // create filter for possible creatures to tap FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); if (unpaid.getMana().getGeneric() == 0) { List colorPredicates = new ArrayList<>(); if (unpaid.getMana().getBlack() > 0) { diff --git a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java index c4d9502957..8f91103ef5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/CrewAbility.java @@ -1,12 +1,12 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.Cost; import mage.abilities.costs.CostImpl; import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect; +import mage.abilities.hint.HintUtils; import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; @@ -20,6 +20,10 @@ import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; +import java.awt.*; +import java.util.Objects; +import java.util.UUID; + /** * @author emerald000 */ @@ -54,7 +58,7 @@ class CrewCost extends CostImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("untapped creature you control"); static { - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); } private final int value; @@ -70,7 +74,24 @@ class CrewCost extends CostImpl { @Override public boolean pay(Ability ability, Game game, UUID sourceId, UUID controllerId, boolean noMana, Cost costToPay) { - Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true); + Target target = new TargetControlledCreaturePermanent(0, Integer.MAX_VALUE, filter, true) { + @Override + public String getMessage() { + // shows selected power + int selectedPower = this.targets.entrySet().stream() + .map(entry -> (game.getPermanent(entry.getKey()))) + .filter(Objects::nonNull) + .mapToInt(p -> (p.getPower().getValue())) + .sum(); + String extraInfo = "(selected power " + selectedPower + " of " + value + ")"; + if (selectedPower >= value) { + extraInfo = HintUtils.prepareText(extraInfo, Color.GREEN); + } + return super.getMessage() + " " + extraInfo; + } + }; + + // can cancel if (target.choose(Outcome.Tap, controllerId, sourceId, game)) { int sumPower = 0; for (UUID targetId : target.getTargets()) { @@ -88,7 +109,10 @@ class CrewCost extends CostImpl { game.fireEvent(GameEvent.getEvent(GameEvent.EventType.CREWED_VEHICLE, targetId, sourceId, controllerId)); } } + } else { + return false; } + return paid; } diff --git a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java index 68055acec9..2855262cdb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/DelveAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.util.List; import mage.Mana; import mage.abilities.Ability; import mage.abilities.SpecialAction; @@ -24,6 +22,8 @@ import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; import mage.util.CardUtil; +import java.util.List; + /** * 702.65. Delve 702.65a Delve is a static ability that functions while the * spell with delve is on the stack. “Delve” means “For each generic mana in @@ -31,7 +31,7 @@ import mage.util.CardUtil; * pay that mana.” The delve ability isn't an additional or alternative cost and * applies only after the total cost of the spell with delve is determined. * 702.65b Multiple instances of delve on the same spell are redundant. - * + *

    * The rules for delve have changed slightly since it was last in an expansion. * Previously, delve reduced the cost to cast a spell. Under the current rules, * you exile cards from your graveyard at the same time you pay the spell's @@ -45,7 +45,7 @@ import mage.util.CardUtil; * it can be used in conjunction with alternative costs. * * @author LevelX2 - * + *

    * TODO: Change card exiling to a way to pay mana costs, now it's maybe not * possible to pay costs from effects that increase the mana costs. */ @@ -83,7 +83,8 @@ public class DelveAbility extends SimpleStaticAbility implements AlternateManaPa unpaidAmount = 1; } specialAction.addCost(new ExileFromGraveCost(new TargetCardInYourGraveyard( - 0, Math.min(controller.getGraveyard().size(), unpaidAmount), new FilterCard(), true))); + 0, Math.min(controller.getGraveyard().size(), unpaidAmount), + new FilterCard("cards to exile for delve's pay from your graveyard"), true))); if (specialAction.canActivate(source.getControllerId(), game).canActivate()) { game.getState().getSpecialActions().add(specialAction); } diff --git a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java index 6495c39cec..ccb08800bb 100644 --- a/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/EquipAbility.java @@ -1,17 +1,12 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.ActivatedAbilityImpl; import mage.abilities.costs.Cost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.EquipEffect; -import mage.abilities.effects.common.AttachEffect; import mage.constants.Outcome; -import mage.constants.SubType; import mage.constants.TimingRule; import mage.constants.Zone; -import mage.game.Game; -import mage.game.permanent.Permanent; import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; @@ -45,7 +40,7 @@ public class EquipAbility extends ActivatedAbilityImpl { @Override public String getRule() { - return "Equip " + costs.getText() + manaCosts.getText() + " (" + manaCosts.getText() + ": Attach to target creature you control. Equip only as a sorcery.)"; + return "Equip " + costs.getText() + manaCosts.getText() + " (" + manaCosts.getText() + ": Attach to target creature you control. Equip only as a sorcery.)"; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java b/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java index 7dac00d4bd..18f10b4289 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ExertAbility.java @@ -109,7 +109,7 @@ class ExertReplacementEffect extends ReplacementEffectImpl { if (creature != null && controller != null) { if (exertOnlyOncePerTurn) { MageObjectReference creatureReference = new MageObjectReference(creature.getId(), creature.getZoneChangeCounter(game), game); - ExertedThisTurnWatcher watcher = (ExertedThisTurnWatcher) game.getState().getWatchers().get(ExertedThisTurnWatcher.class.getSimpleName()); + ExertedThisTurnWatcher watcher = game.getState().getWatcher(ExertedThisTurnWatcher.class); if (watcher != null && watcher.getExertedThisTurnCreatures().contains(creatureReference)) { return false; } @@ -145,7 +145,7 @@ class ExertedThisTurnWatcher extends Watcher { private final Set exertedThisTurnCreatures; public ExertedThisTurnWatcher() { - super(ExertedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); exertedThisTurnCreatures = new HashSet<>(); } diff --git a/Mage/src/main/java/mage/abilities/keyword/FadingAbility.java b/Mage/src/main/java/mage/abilities/keyword/FadingAbility.java index 9bc38f8a20..08f6943a42 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FadingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FadingAbility.java @@ -23,12 +23,18 @@ public class FadingAbility extends EntersBattlefieldAbility { private String ruleText; public FadingAbility(int fadeCounter, Card card) { + this(fadeCounter, card, false); + } + + public FadingAbility(int fadeCounter, Card card, boolean shortRuleText) { super(new AddCountersSourceEffect(CounterType.FADE.createInstance(fadeCounter)), "with"); Ability ability = new BeginningOfUpkeepTriggeredAbility(new FadingEffect(), TargetController.YOU, false); ability.setRuleVisible(false); addSubAbility(ability); - ruleText = "Fading " + fadeCounter + " (This permanent enters the battlefield with " + fadeCounter + " fade counters on it." - + " At the beginning of your upkeep, remove a fade counter from this permanent. If you can't, sacrifice the permanent."; + ruleText = "Fading " + fadeCounter + + (shortRuleText ? "" + : " (This permanent enters the battlefield with " + fadeCounter + " fade counters on it." + + " At the beginning of your upkeep, remove a fade counter from this permanent. If you can't, sacrifice the permanent."); } public FadingAbility(final FadingAbility ability) { diff --git a/Mage/src/main/java/mage/abilities/keyword/FearAbility.java b/Mage/src/main/java/mage/abilities/keyword/FearAbility.java index e774280597..e380accd37 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FearAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FearAbility.java @@ -1,18 +1,16 @@ - package mage.abilities.keyword; -import mage.constants.Duration; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; import mage.abilities.effects.RestrictionEffect; +import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; import java.io.ObjectStreamException; /** - * * @author Loki */ public class FearAbility extends EvasionAbility implements MageSingleton { @@ -59,7 +57,7 @@ class FearEffect extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.isArtifact() || blocker.getColor(game).isBlack(); } diff --git a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java index b07f6dbd32..ba192daadf 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlashbackAbility.java @@ -134,7 +134,7 @@ public class FlashbackAbility extends SpellAbility { public String getRule() { StringBuilder sbRule = new StringBuilder("Flashback"); if (!costs.isEmpty()) { - sbRule.append(" - "); + sbRule.append("—"); } else { sbRule.append(' '); } diff --git a/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java b/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java index ddc5aa9cfd..3550730f0b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/FlyingAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.io.ObjectStreamException; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; @@ -12,8 +10,9 @@ import mage.constants.SubType; import mage.game.Game; import mage.game.permanent.Permanent; +import java.io.ObjectStreamException; + /** - * * @author BetaSteward_at_googlemail.com */ public class FlyingAbility extends EvasionAbility implements MageSingleton { @@ -60,7 +59,7 @@ class FlyingEffect extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().containsKey(FlyingAbility.getInstance().getId()) || blocker.getAbilities().containsKey(ReachAbility.getInstance().getId()) || (null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_DRAGON, source, blocker.getControllerId(), game) diff --git a/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java b/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java index 01eb83de3b..ab4823303e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/GravestormAbility.java @@ -74,20 +74,22 @@ class GravestormEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { MageObjectReference spellRef = (MageObjectReference) this.getValue("GravestormSpellRef"); if (spellRef != null) { - GravestormWatcher watcher = (GravestormWatcher) game.getState().getWatchers().get(GravestormWatcher.class.getSimpleName()); - int gravestormCount = watcher.getGravestormCount(); - if (gravestormCount > 0) { - Spell spell = (Spell) this.getValue("GravestormSpell"); - if (spell != null) { - if (!game.isSimulation()) { - game.informPlayers("Gravestorm: " + spell.getName() + " will be copied " + gravestormCount + " time" + (gravestormCount > 1 ? "s" : "")); - } - for (int i = 0; i < gravestormCount; i++) { - spell.createCopyOnStack(game, source, source.getControllerId(), true); + GravestormWatcher watcher = game.getState().getWatcher(GravestormWatcher.class); + if(watcher != null) { + int gravestormCount = watcher.getGravestormCount(); + if (gravestormCount > 0) { + Spell spell = (Spell) this.getValue("GravestormSpell"); + if (spell != null) { + if (!game.isSimulation()) { + game.informPlayers("Gravestorm: " + spell.getName() + " will be copied " + gravestormCount + " time" + (gravestormCount > 1 ? "s" : "")); + } + for (int i = 0; i < gravestormCount; i++) { + spell.createCopyOnStack(game, source, source.getControllerId(), true); + } } } + return true; } - return true; } return false; } diff --git a/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java b/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java index 9e08681fb9..71297bc893 100644 --- a/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/HauntAbility.java @@ -110,8 +110,8 @@ public class HauntAbility extends TriggeredAbilityImpl { class HauntExileAbility extends ZoneChangeTriggeredAbility { - private final static String RULE_TEXT_CREATURE = "Haunt (When this creature dies, exile it haunting target creature.)"; - private final static String RULE_TEXT_SPELL = "Haunt (When this spell card is put into a graveyard after resolving, exile it haunting target creature.)"; + private static final String RULE_TEXT_CREATURE = "Haunt (When this creature dies, exile it haunting target creature.)"; + private static final String RULE_TEXT_SPELL = "Haunt (When this spell card is put into a graveyard after resolving, exile it haunting target creature.)"; private boolean creatureHaunt; diff --git a/Mage/src/main/java/mage/abilities/keyword/HeroicAbility.java b/Mage/src/main/java/mage/abilities/keyword/HeroicAbility.java index b14c2c0a1f..a13febfc0e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/HeroicAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/HeroicAbility.java @@ -1,7 +1,6 @@ package mage.abilities.keyword; -import java.util.UUID; import mage.abilities.Mode; import mage.abilities.SpellAbility; import mage.abilities.TriggeredAbilityImpl; @@ -12,24 +11,33 @@ import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.target.Target; +import java.util.UUID; + /** * Heroic * - * * @author LevelX2 */ public class HeroicAbility extends TriggeredAbilityImpl { + private final boolean isHeroic; + public HeroicAbility(Effect effect) { this(effect, false); } public HeroicAbility(Effect effect, boolean optional) { + this(effect, optional, true); + } + + public HeroicAbility(Effect effect, boolean optional, boolean isHeroic) { super(Zone.BATTLEFIELD, effect, optional); + this.isHeroic = isHeroic; } public HeroicAbility(final HeroicAbility ability) { super(ability); + this.isHeroic = ability.isHeroic; } @Override @@ -77,6 +85,6 @@ public class HeroicAbility extends TriggeredAbilityImpl { @Override public String getRule() { - return new StringBuilder("Heroic — Whenever you cast a spell that targets {this}, ").append(super.getRule()).toString(); + return (isHeroic ? "Heroic — " : "") + "Whenever you cast a spell that targets {this}, " + super.getRule(); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java b/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java new file mode 100644 index 0000000000..88fd558921 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/HexproofFromMonocoloredAbility.java @@ -0,0 +1,44 @@ +package mage.abilities.keyword; + +import mage.abilities.MageSingleton; +import mage.abilities.common.SimpleStaticAbility; +import mage.constants.Zone; + +import java.io.ObjectStreamException; + +/** + * Hexproof from Monocolored (This creature or player can't be the target of monocolored + * spells or abilities your opponents control.) + * + * @author TheElk801 + */ +public class HexproofFromMonocoloredAbility extends SimpleStaticAbility implements MageSingleton { + + private static final HexproofFromMonocoloredAbility instance; + + static { + instance = new HexproofFromMonocoloredAbility(); + } + + private Object readResolve() throws ObjectStreamException { + return instance; + } + + public static HexproofFromMonocoloredAbility getInstance() { + return instance; + } + + private HexproofFromMonocoloredAbility() { + super(Zone.BATTLEFIELD, null); + } + + @Override + public HexproofFromMonocoloredAbility copy() { + return instance; + } + + @Override + public String getRule() { + return "hexproof from monocolored (This creature can't be the target of monocolored spells or abilities your opponents control.)"; + } +} diff --git a/Mage/src/main/java/mage/abilities/keyword/HorsemanshipAbility.java b/Mage/src/main/java/mage/abilities/keyword/HorsemanshipAbility.java index a7f515966e..73b2ce7a35 100644 --- a/Mage/src/main/java/mage/abilities/keyword/HorsemanshipAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/HorsemanshipAbility.java @@ -1,8 +1,5 @@ - - package mage.abilities.keyword; -import java.io.ObjectStreamException; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; @@ -11,13 +8,14 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.io.ObjectStreamException; + /** - * * @author LevelX2 */ public class HorsemanshipAbility extends EvasionAbility implements MageSingleton { - private static final HorsemanshipAbility instance = new HorsemanshipAbility(); + private static final HorsemanshipAbility instance = new HorsemanshipAbility(); private Object readResolve() throws ObjectStreamException { return instance; @@ -59,7 +57,7 @@ class Horsemanship extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().containsKey(HorsemanshipAbility.getInstance().getId()); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java b/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java index f3a9f36d65..7418145817 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ImproviseAbility.java @@ -37,7 +37,7 @@ public class ImproviseAbility extends SimpleStaticAbility implements AlternateMa private static final FilterArtifactPermanent filterUntapped = new FilterArtifactPermanent(); static { - filterUntapped.add(Predicates.not(new TappedPredicate())); + filterUntapped.add(Predicates.not(TappedPredicate.instance)); } public ImproviseAbility() { @@ -64,7 +64,7 @@ public class ImproviseAbility extends SimpleStaticAbility implements AlternateMa specialAction.setSourceId(source.getSourceId()); // create filter for possible artifacts to tap FilterControlledArtifactPermanent filter = new FilterControlledArtifactPermanent(); - filter.add(Predicates.not(new TappedPredicate())); + filter.add(Predicates.not(TappedPredicate.instance)); Target target = new TargetControlledPermanent(1, unpaid.getMana().getGeneric(), filter, true); target.setTargetName("artifact to Improvise"); specialAction.addTarget(target); diff --git a/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java b/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java index c8dd8b4791..f48cc7327b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/IntimidateAbility.java @@ -10,18 +10,15 @@ import mage.game.permanent.Permanent; /** * 702.13. Intimidate # - * - * 702.13a Intimidate is an evasion ability. - * - * 702.13b A creature with intimidate can't be blocked except by artifact creatures - * and/or creatures that share a color with it. (See rule 509, "Declare Blockers Step.") # - * - * 702.13c Multiple instances of intimidate on the same creature are redundant. - * - * - * + *

    + * 702.13a Intimidate is an evasion ability. + *

    + * 702.13b A creature with intimidate can't be blocked except by artifact creatures + * and/or creatures that share a color with it. (See rule 509, "Declare Blockers Step.") # + *

    + * 702.13c Multiple instances of intimidate on the same creature are redundant. */ -public class IntimidateAbility extends EvasionAbility implements MageSingleton { +public class IntimidateAbility extends EvasionAbility implements MageSingleton { private static final IntimidateAbility instance = new IntimidateAbility(); public static IntimidateAbility getInstance() { @@ -58,7 +55,7 @@ class IntimidateEffect extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { boolean result = false; if (blocker.isArtifact() && (blocker.isCreature())) { result = true; diff --git a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java index 77a5e0fc74..dc4c59aee1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/LandwalkAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -11,7 +10,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author BetaSteward_at_googlemail.com */ public class LandwalkAbility extends EvasionAbility { @@ -60,7 +58,7 @@ class LandwalkEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { if (game.getBattlefield().contains(filter, blocker.getControllerId(), 1, game) && null == game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_LANDWALK, source, blocker.getControllerId(), game)) { switch (filter.getMessage()) { diff --git a/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java b/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java index 0ca8676bbb..061c000e83 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MeleeAbility.java @@ -1,10 +1,8 @@ package mage.abilities.keyword; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; +import java.util.*; + import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.dynamicvalue.DynamicValue; @@ -45,10 +43,10 @@ public class MeleeAbility extends AttacksTriggeredAbility { class MeleeWatcher extends Watcher { - private HashMap> playersAttacked = new HashMap<>(0); + private Map> playersAttacked = new HashMap<>(0); MeleeWatcher() { - super("MeleeWatcher", WatcherScope.GAME); + super(WatcherScope.GAME); } MeleeWatcher(final MeleeWatcher watcher) { @@ -88,7 +86,7 @@ class MeleeDynamicValue implements DynamicValue { @Override public int calculate(Game game, Ability sourceAbility, Effect effect) { - MeleeWatcher watcher = (MeleeWatcher) game.getState().getWatchers().get(MeleeWatcher.class.getSimpleName()); + MeleeWatcher watcher = game.getState().getWatcher(MeleeWatcher.class); if (watcher != null) { if (!valueChecked) { this.lockedInValue = watcher.getNumberOfAttackedPlayers(sourceAbility.getControllerId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java index bd579657da..e7fbee0fb7 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MentorAbility.java @@ -13,7 +13,6 @@ import mage.game.permanent.Permanent; import mage.target.common.TargetCreaturePermanent; /** - * * @author TheElk801 */ public class MentorAbility extends AttacksTriggeredAbility { @@ -21,8 +20,8 @@ public class MentorAbility extends AttacksTriggeredAbility { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("attacking creature with lesser power"); static { - filter.add(new AttackingPredicate()); - filter.add(new MentorAbilityPredicate()); + filter.add(AttackingPredicate.instance); + filter.add(MentorAbilityPredicate.instance); } public MentorAbility() { @@ -46,7 +45,8 @@ public class MentorAbility extends AttacksTriggeredAbility { } -class MentorAbilityPredicate implements ObjectSourcePlayerPredicate> { +enum MentorAbilityPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override public boolean apply(ObjectSourcePlayer input, Game game) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java b/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java index 250992d472..2592e16aa9 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ModularAbility.java @@ -93,7 +93,7 @@ public class ModularAbility extends DiesTriggeredAbility { public String getRule() { StringBuilder sb = new StringBuilder("Modular"); if (sunburst) { - sb.append("-Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); + sb.append("—Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it. When it dies, you may put its +1/+1 counters on target artifact creature.)"); } else { sb.append(' ').append(amount).append(" (This enters the battlefield with ") .append(CardUtil.numberToText(amount, "a")) diff --git a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java index 6a1b3c449e..66ba57de9e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/MorphAbility.java @@ -108,7 +108,8 @@ public class MorphAbility extends StaticAbility implements AlternativeSourceCost name = ABILITY_KEYWORD; for (Cost cost : morphCosts) { if (!(cost instanceof ManaCosts)) { - sb.append("- "); + sb.setLength(sb.length() - 1); + sb.append("—"); break; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java index 5737f0b50b..e63ae4d5a2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/NinjutsuAbility.java @@ -47,7 +47,7 @@ public class NinjutsuAbility extends ActivatedAbilityImpl { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("unblocked attacker you control"); static { - filter.add(new UnblockedPredicate()); + filter.add(UnblockedPredicate.instance); } /** @@ -199,8 +199,8 @@ class RevealNinjutsuCardCost extends CostImpl { for (CommandObject coj : game.getState().getCommand()) { if (coj != null && coj.getId().equals(ability.getSourceId())) { card = game.getCard(ability.getSourceId()); + break; } - break; } } if (card != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java index 6ce501563f..c6c26c43cd 100644 --- a/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/OfferingAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.SpellAbility; @@ -19,18 +17,19 @@ import mage.target.Target; import mage.target.common.TargetControlledCreaturePermanent; import mage.util.CardUtil; +import java.util.UUID; + /** - * * 702.46. Offering # 702.46a Offering is a static ability of a card that * functions in any zone from which the card can be cast. "[Subtype] offering" * means "You may cast this card any time you could cast an instant by * sacrificing a [subtype] permanent. If you do, the total cost to cast this * card is reduced by the sacrificed permanent's mana cost." # - * + *

    * 702.46b The permanent is sacrificed at the same time the spell is announced * (see rule 601.2a). The total cost of the spell is reduced by the sacrificed * permanent's mana cost (see rule 601.2e). # - * + *

    * 702.46c Generic mana in the sacrificed permanent's mana cost reduces generic * mana in the total cost to cast the card with offering. Colored mana in the * sacrificed permanent's mana cost reduces mana of the same color in the total @@ -39,7 +38,6 @@ import mage.util.CardUtil; * cost of the card with offering, or is in excess of the card's colored mana * cost, reduces that much generic mana in the total cost. # * - * * @author LevelX2 */ public class OfferingAbility extends StaticAbility { @@ -47,7 +45,6 @@ public class OfferingAbility extends StaticAbility { private FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent(); /** - * * @param subtype name of the subtype that can be offered */ public OfferingAbility(SubType subtype) { @@ -107,7 +104,7 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { public boolean applies(UUID sourceId, Ability affectedAbility, Ability source, Game game, UUID playerId) { if (sourceId.equals(source.getSourceId())) { Card card = game.getCard(sourceId); - if (!card.isOwnedBy(source.getControllerId())) { + if (card == null || !card.isOwnedBy(source.getControllerId())) { return false; } // because can activate is always called twice, result from first call will be used @@ -129,6 +126,9 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { } FilterControlledCreaturePermanent filter = ((OfferingAbility) source).getFilter(); Card spellToCast = game.getCard(source.getSourceId()); + if (spellToCast == null) { + return false; + } Player player = game.getPlayer(source.getControllerId()); if (player != null && !CardUtil.isCheckPlayableMode(affectedAbility) && player.chooseUse(Outcome.Benefit, "Offer a " + filter.getMessage() + " to cast " + spellToCast.getName() + '?', source, game)) { @@ -146,7 +146,6 @@ class OfferingAsThoughEffect extends AsThoughEffectImpl { game.getState().setValue("offering_ok_" + card.getId(), true); game.getState().setValue("offering_Id_" + card.getId(), activationId); return true; - } } else { game.getState().setValue("offering_" + card.getId(), true); @@ -201,7 +200,7 @@ class OfferingCostReductionEffect extends CostModificationEffectImpl { Card card = game.getCard(source.getSourceId()); if (card != null) { Object object = game.getState().getValue("offering_Id_" + card.getId()); - if (object != null && ((UUID) object).equals(this.activationId) && offeredPermanent.getPermanent(game) != null) { + if (object != null && object.equals(this.activationId) && offeredPermanent.getPermanent(game) != null) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/PartnerWithAbility.java b/Mage/src/main/java/mage/abilities/keyword/PartnerWithAbility.java index 43bea447a7..a9f9a82ec0 100644 --- a/Mage/src/main/java/mage/abilities/keyword/PartnerWithAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/PartnerWithAbility.java @@ -116,7 +116,7 @@ class PartnersWithSearchEffect extends OneShotEffect { filter.add(new NamePredicate(partnerName)); TargetCardInLibrary target = new TargetCardInLibrary(filter); if (player.chooseUse(Outcome.Benefit, "Search your library for a card named " + partnerName + " and put it into your hand?", source, game)) { - player.searchLibrary(target, game); + player.searchLibrary(target, source, game); for (UUID cardId : target.getTargets()) { Card card = player.getLibrary().getCard(cardId, game); if (card != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java index 3bc23ba84f..3e3ff1ca3c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProwlAbility.java @@ -92,7 +92,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost public boolean askToActivateAlternativeCosts(Ability ability, Game game) { if (ability instanceof SpellAbility) { Player player = game.getPlayer(controllerId); - ProwlWatcher prowlWatcher = (ProwlWatcher) game.getState().getWatchers().get(ProwlWatcher.class.getSimpleName()); + ProwlWatcher prowlWatcher = game.getState().getWatcher(ProwlWatcher.class); Card card = game.getCard(ability.getSourceId()); if (player == null || prowlWatcher == null || card == null) { throw new IllegalArgumentException("Params can't be null"); @@ -108,7 +108,7 @@ public class ProwlAbility extends StaticAbility implements AlternativeSourceCost this.resetProwl(); for (AlternativeCost2 prowlCost : prowlCosts) { if (prowlCost.canPay(ability, sourceId, controllerId, game) - && player.chooseUse(Outcome.Benefit, new StringBuilder("Cast for ").append(PROWL_KEYWORD).append(" cost ").append(prowlCost.getText(true)).append(" ?").toString(), ability, game)) { + && player.chooseUse(Outcome.Benefit, "Cast for " + PROWL_KEYWORD + " cost " + prowlCost.getText(true) + " ?", ability, game)) { prowlCost.activate(); ability.getManaCostsToPay().clear(); ability.getCosts().clear(); diff --git a/Mage/src/main/java/mage/abilities/keyword/RampageAbility.java b/Mage/src/main/java/mage/abilities/keyword/RampageAbility.java index 2359c92a3c..00b7bf47be 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RampageAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RampageAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -19,9 +18,15 @@ public class RampageAbility extends BecomesBlockedTriggeredAbility { private final String rule; public RampageAbility(int amount) { + this(amount, false); + } + + public RampageAbility(int amount, boolean shortRuleText) { super(null, false); - rule = "rampage " + amount + " (Whenever this creature becomes blocked, it gets +" - + amount + "/+" + amount + " until end of turn for each creature blocking it beyond the first.)"; + rule = "rampage " + amount + + (shortRuleText ? "" + : " (Whenever this creature becomes blocked, it gets +" + + amount + "/+" + amount + " until end of turn for each creature blocking it beyond the first.)"); RampageValue rv = new RampageValue(amount); this.addEffect(new BoostSourceEffect(rv, rv, Duration.EndOfTurn, true)); } diff --git a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java index 885d0a3b66..6afa7afdf0 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReboundAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.abilities.DelayedTriggeredAbility; @@ -21,6 +19,8 @@ import mage.game.events.ZoneChangeEvent; import mage.game.stack.Spell; import mage.players.Player; +import java.util.UUID; + /** * This ability has no effect by default and will always return false on the * call to apply. This is because of how the {@link ReboundEffect} works. It @@ -93,7 +93,7 @@ class ReboundCastFromHandReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Spell sourceSpell = game.getStack().getSpell(source.getSourceId()); - if (sourceSpell != null && sourceSpell.isCopiedSpell()) { + if (sourceSpell != null && sourceSpell.isCopy()) { return false; } else { Card sourceCard = game.getCard(source.getSourceId()); diff --git a/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java b/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java index c6bac07f93..25f309b6b5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/RecoverAbility.java @@ -48,7 +48,7 @@ public class RecoverAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { if (zEvent.getTarget().isOwnedBy(getControllerId()) && zEvent.getTarget().isCreature() && !zEvent.getTarget().getId().equals(getSourceId())) { diff --git a/Mage/src/main/java/mage/abilities/keyword/ReinforceAbility.java b/Mage/src/main/java/mage/abilities/keyword/ReinforceAbility.java index df70c1df60..96e54314c3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ReinforceAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ReinforceAbility.java @@ -43,7 +43,7 @@ public class ReinforceAbility extends SimpleActivatedAbility { @Override public String getRule() { StringBuilder sb = new StringBuilder("Reinforce "); - sb.append(count.toString()).append(" - "); + sb.append(count.toString()).append("—"); sb.append(cost.getText()); sb.append(" (").append(cost.getText()).append(", Discard this card: Put "); if (count.toString().equals("1")) { diff --git a/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java b/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java new file mode 100644 index 0000000000..fe667a08ce --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/RiotAbility.java @@ -0,0 +1,94 @@ + +package mage.abilities.keyword; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.counters.CounterType; +import mage.game.Game; +import mage.game.events.EntersTheBattlefieldEvent; +import mage.game.events.GameEvent; +import mage.game.events.GameEvent.EventType; +import mage.game.permanent.Permanent; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public class RiotAbility extends SimpleStaticAbility { + + public RiotAbility() { + super(Zone.ALL, new RiotReplacementEffect()); + } + + private RiotAbility(final RiotAbility ability) { + super(ability); + } + + @Override + public RiotAbility copy() { + return new RiotAbility(this); + } + + @Override + public String getRule() { + return "Riot (This creature enters the battlefield with your choice of a +1/+1 counter or haste.)"; + } +} + +class RiotReplacementEffect extends ReplacementEffectImpl { + + RiotReplacementEffect() { + super(Duration.EndOfGame, Outcome.Detriment); + } + + private RiotReplacementEffect(final RiotReplacementEffect effect) { + super(effect); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == EventType.ENTERS_THE_BATTLEFIELD; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + return event.getTargetId().equals(source.getSourceId()); + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Permanent creature = ((EntersTheBattlefieldEvent) event).getTarget(); + Player controller = game.getPlayer(source.getControllerId()); + if (creature != null && controller != null) { + if (controller.chooseUse(outcome, "Have " + creature.getLogName() + " enter the battlefield with a +1/+1 counter on it or with haste?", null, "+1/+1 counter", "Haste", source, game)) { + game.informPlayers(controller.getLogName() + " choose to put a +1/+1 counter on " + creature.getName()); + creature.addCounters(CounterType.P1P1.createInstance(), source, game, event.getAppliedEffects()); + } else { + game.addEffect(new GainAbilitySourceEffect(HasteAbility.getInstance(), Duration.Custom), source); + } + } + return false; + } + + @Override + public String getText(Mode mode) { + return staticText; + } + + @Override + public RiotReplacementEffect copy() { + return new RiotReplacementEffect(this); + } + +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java b/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java index 6188b91b59..ed1689c4e1 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ShadowAbility.java @@ -1,6 +1,5 @@ package mage.abilities.keyword; -import java.io.ObjectStreamException; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; @@ -10,6 +9,8 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.io.ObjectStreamException; + /** * "Shadow" keyword * @@ -59,12 +60,15 @@ class ShadowEffect extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.getAbilities().containsKey(ShadowAbility.getInstance().getId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().containsKey(ShadowAbility.getInstance().getId()) || null != game.getContinuousEffects().asThough(blocker.getId(), AsThoughEffectType.BLOCK_SHADOW, source, blocker.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/abilities/keyword/SkulkAbility.java b/Mage/src/main/java/mage/abilities/keyword/SkulkAbility.java index 2378f0a9db..db30ccb96a 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SkulkAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SkulkAbility.java @@ -14,7 +14,6 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ public class SkulkAbility extends StaticAbility { @@ -56,7 +55,7 @@ class SkulkEffect extends RestrictionEffect { } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getPower().getValue() <= attacker.getPower().getValue(); } diff --git a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java index da422af6d8..db7dc45be6 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SoulbondAbility.java @@ -112,7 +112,7 @@ class SoulboundEntersSelfEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another not paired creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.not(new PairedPredicate())); } @@ -168,12 +168,12 @@ class SoulboundEntersSelfEffect extends OneShotEffect { */ class SoulbondEntersOtherAbility extends EntersBattlefieldAllTriggeredAbility { - private final static FilterCreaturePermanent soulbondFilter = new FilterCreaturePermanent(); + private static final FilterCreaturePermanent soulbondFilter = new FilterCreaturePermanent(); static { soulbondFilter.add(Predicates.not(new PairedPredicate())); soulbondFilter.add(new ControllerPredicate(TargetController.YOU)); - soulbondFilter.add(new AnotherPredicate()); + soulbondFilter.add(AnotherPredicate.instance); } public SoulbondEntersOtherAbility() { @@ -214,7 +214,7 @@ class SoulboundEntersOtherEffect extends OneShotEffect { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another not paired creature you control"); static { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.add(Predicates.not(new PairedPredicate())); } diff --git a/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java index 9a15056e04..ed9223756e 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SpaceflightAbility.java @@ -1,7 +1,5 @@ - package mage.abilities.keyword; -import java.io.ObjectStreamException; import mage.abilities.Ability; import mage.abilities.EvasionAbility; import mage.abilities.MageSingleton; @@ -10,8 +8,9 @@ import mage.constants.Duration; import mage.game.Game; import mage.game.permanent.Permanent; +import java.io.ObjectStreamException; + /** - * * @author Styxo */ public class SpaceflightAbility extends EvasionAbility implements MageSingleton { @@ -58,12 +57,15 @@ class SpaceFlightEffect extends RestrictionEffect implements MageSingleton { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { + if (attacker == null) { + return true; + } return attacker.getAbilities().containsKey(SpaceflightAbility.getInstance().getId()); } @Override - public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBeBlocked(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return blocker.getAbilities().containsKey(SpaceflightAbility.getInstance().getId()) || blocker.getAbilities().containsKey(CanBlockSpaceflightAbility.getInstance().getId()); } diff --git a/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java new file mode 100644 index 0000000000..5845fdeeb6 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/keyword/SpectacleAbility.java @@ -0,0 +1,80 @@ +package mage.abilities.keyword; + +import mage.abilities.SpellAbility; +import mage.abilities.costs.mana.ManaCost; +import mage.abilities.dynamicvalue.common.OpponentsLostLifeCount; +import mage.abilities.hint.common.SpectacleHint; +import mage.cards.Card; +import mage.constants.SpellAbilityType; +import mage.constants.Zone; +import mage.game.Game; + +import java.util.ArrayList; +import java.util.UUID; + +/** + * @author TheElk801 + */ +public class SpectacleAbility extends SpellAbility { + + public static final String SPECTACLE_ACTIVATION_VALUE_KEY = "spectacleActivation"; + + private String rule; + + public SpectacleAbility(Card card, ManaCost spectacleCosts) { + super(spectacleCosts, card.getName() + " with spectacle", Zone.HAND, SpellAbilityType.BASE_ALTERNATE); + this.getCosts().addAll(card.getSpellAbility().getCosts().copy()); + this.getEffects().addAll(card.getSpellAbility().getEffects().copy()); + this.getTargets().addAll(card.getSpellAbility().getTargets().copy()); + this.spellAbilityType = SpellAbilityType.BASE_ALTERNATE; + this.timing = card.getSpellAbility().getTiming(); + this.setRuleAtTheTop(true); + this.rule = "Spectacle " + spectacleCosts.getText() + + " (You may cast this spell for its spectacle cost rather than its mana cost if an opponent lost life this turn.)"; + this.addHint(SpectacleHint.instance); + } + + public SpectacleAbility(final SpectacleAbility ability) { + super(ability); + this.rule = ability.rule; + } + + @Override + public ActivationStatus canActivate(UUID playerId, Game game) { + if (OpponentsLostLifeCount.instance.calculate(game, playerId) > 0) { + return super.canActivate(playerId, game); + } + return ActivationStatus.getFalse(); + } + + @Override + @SuppressWarnings("unchecked") + public boolean activate(Game game, boolean noMana) { + if (super.activate(game, noMana)) { + ArrayList spectacleActivations = (ArrayList) game.getState().getValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId()); + if (spectacleActivations == null) { + spectacleActivations = new ArrayList<>(); // zoneChangeCounter + game.getState().setValue(SPECTACLE_ACTIVATION_VALUE_KEY + getSourceId(), spectacleActivations); + } + spectacleActivations.add(game.getState().getZoneChangeCounter(getSourceId())); + return true; + } + return false; + } + + @Override + public SpectacleAbility copy() { + return new SpectacleAbility(this); + } + + @Override + public String getRule(boolean all) { + return getRule(); + } + + @Override + public String getRule() { + return rule; + } + +} diff --git a/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java b/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java index f2880befeb..c6a604730c 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SpliceOntoArcaneAbility.java @@ -112,7 +112,7 @@ public class SpliceOntoArcaneAbility extends SimpleStaticAbility { @Override public String getRule() { StringBuilder sb = new StringBuilder(); - sb.append(KEYWORD_TEXT).append(nonManaCosts ? "-" : " "); + sb.append(KEYWORD_TEXT).append(nonManaCosts ? "—" : " "); sb.append(spliceCosts.getText()).append(nonManaCosts ? ". " : " "); sb.append("(As you cast an Arcane spell, you may reveal this card from your hand and pay its splice cost. If you do, add this card's effects to that spell.)"); return sb.toString(); diff --git a/Mage/src/main/java/mage/abilities/keyword/SplitSecondAbility.java b/Mage/src/main/java/mage/abilities/keyword/SplitSecondAbility.java index aebf6928c8..55e5823ea5 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SplitSecondAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SplitSecondAbility.java @@ -69,7 +69,7 @@ class SplitSecondEffect extends ContinuousRuleModifyingEffectImpl { } if (event.getType() == GameEvent.EventType.ACTIVATE_ABILITY) { Optional ability = game.getAbility(event.getTargetId(), event.getSourceId()); - if (ability != null && !(ability.get() instanceof ActivatedManaAbilityImpl)) { + if (ability.isPresent() && !(ability.get() instanceof ActivatedManaAbilityImpl)) { return true; } } diff --git a/Mage/src/main/java/mage/abilities/keyword/StormAbility.java b/Mage/src/main/java/mage/abilities/keyword/StormAbility.java index 45b99a4ab6..001c1add9b 100644 --- a/Mage/src/main/java/mage/abilities/keyword/StormAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/StormAbility.java @@ -74,7 +74,7 @@ class StormEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { MageObjectReference spellRef = (MageObjectReference) this.getValue("StormSpellRef"); if (spellRef != null) { - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { int stormCount = watcher.getSpellOrder(spellRef, game) - 1; if (stormCount > 0) { @@ -89,7 +89,7 @@ class StormEffect extends OneShotEffect { } } } else { - Logger.getLogger(StormEffect.class).fatal("CastSpellLastTurnWatcher not found. game = " + game == null ? "NULL" : game.getGameType().toString()); + Logger.getLogger(StormEffect.class).fatal("CastSpellLastTurnWatcher not found. game = " +game.getGameType().toString()); } return true; } diff --git a/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java b/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java index e5aabcfe01..aa03cf9579 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SunburstAbility.java @@ -22,8 +22,8 @@ import mage.players.Player; */ public class SunburstAbility extends EntersBattlefieldAbility { - private final static String ruleCreature = "Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; - private final static String ruleNonCreature = "Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; + private static final String ruleCreature = "Sunburst (This enters the battlefield with a +1/+1 counter on it for each color of mana spent to cast it.)"; + private static final String ruleNonCreature = "Sunburst (This enters the battlefield with a charge counter on it for each color of mana spent to cast it.)"; private boolean isCreature; public SunburstAbility(Card card) { @@ -50,7 +50,7 @@ public class SunburstAbility extends EntersBattlefieldAbility { class SunburstEffect extends OneShotEffect { - private static final DynamicValue amount = new SunburstCount(); + private static final DynamicValue amount = SunburstCount.instance; public SunburstEffect() { super(Outcome.Benefit); diff --git a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java index 9e74163a2f..4b4d591f88 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SupportAbility.java @@ -24,7 +24,7 @@ public class SupportAbility extends EntersBattlefieldTriggeredAbility { if (!card.isInstant() && !card.isSorcery()) { FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures"); if (card.isCreature()) { - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); filter.setMessage("other target creatures"); } addTarget(new TargetCreaturePermanent(0, amount, filter, false)); diff --git a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java index a94231fb4b..0e4c28b540 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SurgeAbility.java @@ -42,7 +42,7 @@ public class SurgeAbility extends SpellAbility { @Override public ActivationStatus canActivate(UUID playerId, Game game) { // check if controller or teammate has already cast a spell this turn - CastSpellLastTurnWatcher watcher = (CastSpellLastTurnWatcher) game.getState().getWatchers().get(CastSpellLastTurnWatcher.class.getSimpleName()); + CastSpellLastTurnWatcher watcher = game.getState().getWatcher(CastSpellLastTurnWatcher.class); if (watcher != null) { Player player = game.getPlayer(playerId); if (player != null) { diff --git a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java index 7c4d3afdc4..f1e16d47bf 100644 --- a/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/SuspendAbility.java @@ -140,7 +140,7 @@ public class SuspendAbility extends SpecialAction { } StringBuilder sb = new StringBuilder("Suspend "); if (cost != null) { - sb.append(suspend == Integer.MAX_VALUE ? "X" : suspend).append(" - ").append(cost.getText()).append(suspend == Integer.MAX_VALUE ? ". X can't be 0" : ""); + sb.append(suspend == Integer.MAX_VALUE ? "X" : suspend).append("—").append(cost.getText()).append(suspend == Integer.MAX_VALUE ? ". X can't be 0" : ""); if (!shortRule) { sb.append(" (Rather than cast this card from your hand, pay ") .append(cost.getText()) diff --git a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java index e616e86298..8408cd0fc3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransformAbility.java @@ -18,7 +18,7 @@ public class TransformAbility extends SimpleStaticAbility { public static final String NO_SPELLS_TRANSFORM_RULE = "At the beginning of each upkeep, if no spells were cast last turn, transform {this}."; public static final String TWO_OR_MORE_SPELLS_TRANSFORM_RULE = "At the beginning of each upkeep, if a player cast two or more spells last turn, transform {this}."; - // this state value controlls if a permanent enters the battlefield already transformed + // this state value controls if a permanent enters the battlefield already transformed public static final String VALUE_KEY_ENTER_TRANSFORMED = "EnterTransformed"; public TransformAbility() { diff --git a/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java b/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java index f0143e4f0f..7a4c9770b2 100644 --- a/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/TransmuteAbility.java @@ -80,7 +80,7 @@ class TransmuteEffect extends OneShotEffect { FilterCard filter = new FilterCard("card with converted mana cost " + sourceObject.getConvertedManaCost()); filter.add(new ConvertedManaCostPredicate(ComparisonType.EQUAL_TO, sourceObject.getConvertedManaCost())); TargetCardInLibrary target = new TargetCardInLibrary(1, filter); - if (controller.searchLibrary(target, game)) { + if (controller.searchLibrary(target, source, game)) { if (!target.getTargets().isEmpty()) { Cards revealed = new CardsImpl(target.getTargets()); controller.revealCards(sourceObject.getIdName(), revealed, game); diff --git a/Mage/src/main/java/mage/abilities/keyword/UndauntedAbility.java b/Mage/src/main/java/mage/abilities/keyword/UndauntedAbility.java index 857d47133b..52061608d3 100644 --- a/Mage/src/main/java/mage/abilities/keyword/UndauntedAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/UndauntedAbility.java @@ -5,25 +5,17 @@ */ package mage.abilities.keyword; -import mage.Mana; -import mage.abilities.Ability; -import mage.abilities.SpellAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.cost.CostModificationEffectImpl; -import mage.constants.CostModificationType; -import mage.constants.Duration; -import mage.constants.Outcome; +import mage.abilities.effects.common.cost.SpellCostReductionSourceForOpponentsEffect; import mage.constants.Zone; -import mage.game.Game; /** - * * @author LevelX2 */ public class UndauntedAbility extends SimpleStaticAbility { public UndauntedAbility() { - super(Zone.ALL, new UndauntedEffect()); + super(Zone.ALL, new SpellCostReductionSourceForOpponentsEffect("undaunted (This spell costs {1} less to cast for each opponent.)")); setRuleAtTheTop(true); } @@ -36,43 +28,4 @@ public class UndauntedAbility extends SimpleStaticAbility { return new UndauntedAbility(this); } -} - -class UndauntedEffect extends CostModificationEffectImpl { - - public UndauntedEffect() { - super(Duration.Custom, Outcome.Benefit, CostModificationType.REDUCE_COST); - staticText = "undaunted (This spell costs {1} less to cast for each opponent.)"; - } - - public UndauntedEffect(final UndauntedEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source, Ability abilityToModify) { - SpellAbility spellAbility = (SpellAbility) abilityToModify; - Mana mana = spellAbility.getManaCostsToPay().getMana(); - if (mana.getGeneric() > 0) { - int count = game.getOpponents(source.getControllerId()).size(); - int newCount = mana.getGeneric() - count; - if (newCount < 0) { - newCount = 0; - } - mana.setGeneric(newCount); - spellAbility.getManaCostsToPay().load(mana.toString()); - return true; - } - return false; - } - - @Override - public boolean applies(Ability abilityToModify, Ability source, Game game) { - return abilityToModify instanceof SpellAbility && abilityToModify.getSourceId().equals(source.getSourceId()); - } - - @Override - public UndauntedEffect copy() { - return new UndauntedEffect(this); - } -} +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/abilities/keyword/UnearthAbility.java b/Mage/src/main/java/mage/abilities/keyword/UnearthAbility.java index 31e6d3424e..ef3dad3208 100644 --- a/Mage/src/main/java/mage/abilities/keyword/UnearthAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/UnearthAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -19,19 +18,17 @@ import mage.game.events.GameEvent.EventType; import mage.game.events.ZoneChangeEvent; /** - * * @author BetaSteward_at_googlemail.com - * - * + *

    + *

    * 702.82. Unearth - * + *

    * 702.82a Unearth is an activated ability that functions while the card with * unearth is in a graveyard. "Unearth [cost]" means "[Cost]: Return this card * from your graveyard to the battlefield. It gains haste. Exile it at the * beginning of the next end step. If it would leave the battlefield, exile it * instead of putting it anywhere else. Activate this ability only any time you * could cast a sorcery." - * */ public class UnearthAbility extends ActivatedAbilityImpl { @@ -111,7 +108,7 @@ class UnearthLeavesBattlefieldEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - return EventType.ZONE_CHANGE == event.getType(); + return event.getType() == EventType.ZONE_CHANGE; } @Override diff --git a/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java b/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java index 271f8db3ff..8e7da9419f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/UnleashAbility.java @@ -1,4 +1,3 @@ - package mage.abilities.keyword; import mage.abilities.Ability; @@ -110,15 +109,13 @@ class UnleashRestrictionEffect extends RestrictionEffect { @Override public boolean applies(Permanent permanent, Ability source, Game game) { if (permanent != null && permanent.getId().equals(source.getSourceId())) { - if (permanent.getCounters(game).getCount(CounterType.P1P1) > 0) { - return true; - } + return permanent.getCounters(game).getCount(CounterType.P1P1) > 0; } return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java index 086a90ff43..288e48b195 100644 --- a/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java +++ b/Mage/src/main/java/mage/abilities/mana/AnyColorLandsProduceManaAbility.java @@ -1,8 +1,6 @@ package mage.abilities.mana; -import java.util.ArrayList; -import java.util.List; import mage.Mana; import mage.abilities.Abilities; import mage.abilities.Ability; @@ -20,8 +18,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; +import java.util.ArrayList; +import java.util.List; + /** - * * @author LevelX2 */ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl { @@ -31,7 +31,11 @@ public class AnyColorLandsProduceManaAbility extends ActivatedManaAbilityImpl { } public AnyColorLandsProduceManaAbility(TargetController targetController, boolean onlyColors) { - super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController, onlyColors), new TapSourceCost()); + this(targetController, onlyColors, null); + } + + public AnyColorLandsProduceManaAbility(TargetController targetController, boolean onlyColors, FilterPermanent filter) { + super(Zone.BATTLEFIELD, new AnyColorLandsProduceManaEffect(targetController, onlyColors, filter), new TapSourceCost()); } public AnyColorLandsProduceManaAbility(final AnyColorLandsProduceManaAbility ability) { @@ -62,16 +66,21 @@ class AnyColorLandsProduceManaEffect extends ManaEffect { private boolean inManaTypeCalculation = false; - public AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors) { + AnyColorLandsProduceManaEffect(TargetController targetController, boolean onlyColors, FilterPermanent filter) { super(); - filter = new FilterLandPermanent(); + if (filter == null) { + this.filter = new FilterLandPermanent(); + } else { + this.filter = filter.copy(); + } this.onlyColors = onlyColors; - filter.add(new ControllerPredicate(targetController)); + this.filter.add(new ControllerPredicate(targetController)); String text = targetController == TargetController.OPPONENT ? "an opponent controls" : "you control"; - staticText = "Add one mana of any " + (this.onlyColors ? "color" : "type") + " that a land " + text + " could produce"; + staticText = "Add one mana of any " + (this.onlyColors ? "color" : "type") + " that a " + + (filter == null ? "land " : filter.getMessage() + " ") + text + " could produce"; } - public AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { + private AnyColorLandsProduceManaEffect(final AnyColorLandsProduceManaEffect effect) { super(effect); this.filter = effect.filter.copy(); this.onlyColors = effect.onlyColors; diff --git a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java index ebd11af1fb..0a4a17cb4c 100644 --- a/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/meta/OrTriggeredAbility.java @@ -1,6 +1,8 @@ package mage.abilities.meta; -import mage.MageObject; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; import mage.abilities.TriggeredAbility; import mage.abilities.TriggeredAbilityImpl; import mage.abilities.effects.Effect; @@ -9,14 +11,13 @@ import mage.game.Game; import mage.game.events.GameEvent; import mage.watchers.Watcher; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** - * A triggered ability that combines several others and triggers whenever one or more of them would. The abilities - * passed in should have null as their effect, and should have their own targets set if necessary. All other information - * will be passed in from changes to this Ability. Note: this does NOT work with abilities that have intervening if clauses. + * A triggered ability that combines several others and triggers whenever one or + * more of them would. The abilities passed in should have null as their effect, + * and should have their own targets set if necessary. All other information + * will be passed in from changes to this Ability. Note: this does NOT work with + * abilities that have intervening if clauses. + * * @author noahg */ public class OrTriggeredAbility extends TriggeredAbilityImpl { @@ -43,19 +44,17 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { public OrTriggeredAbility(OrTriggeredAbility ability) { super(ability); this.triggeredAbilities = new TriggeredAbility[ability.triggeredAbilities.length]; - for (int i = 0; i < this.triggeredAbilities.length; i++){ + for (int i = 0; i < this.triggeredAbilities.length; i++) { this.triggeredAbilities[i] = ability.triggeredAbilities[i].copy(); } this.triggeringAbilities = new ArrayList<>(ability.triggeringAbilities); this.ruleTrigger = ability.ruleTrigger; } - @Override public boolean checkEventType(GameEvent event, Game game) { for (TriggeredAbility ability : triggeredAbilities) { - if (ability.checkEventType(event, game)){ - System.out.println("Correct event type (" + event.getType() + ")"); + if (ability.checkEventType(event, game)) { return true; } } @@ -68,11 +67,9 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { for (int i = 0; i < triggeredAbilities.length; i++) { TriggeredAbility ability = triggeredAbilities[i]; if (ability.checkEventType(event, game) && ability.checkTrigger(event, game)) { - System.out.println("Triggered from " + ability.getRule()); triggeringAbilities.add(i); toRet = true; } - System.out.println("Checked " + ability.getRule()); } return toRet; } @@ -101,7 +98,6 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { return sb.toString() + super.getRule(); } - @Override public void setControllerId(UUID controllerId) { super.setControllerId(controllerId); @@ -126,11 +122,4 @@ public class OrTriggeredAbility extends TriggeredAbilityImpl { } } - @Override - public void setSourceObject(MageObject sourceObject, Game game) { - super.setSourceObject(sourceObject, game); - for (TriggeredAbility ability : triggeredAbilities) { - ability.setSourceObject(sourceObject, game); - } - } } diff --git a/Mage/src/main/java/mage/cards/CardGraphicInfo.java b/Mage/src/main/java/mage/cards/CardGraphicInfo.java index ae9aee3dbb..d0c4ae0641 100644 --- a/Mage/src/main/java/mage/cards/CardGraphicInfo.java +++ b/Mage/src/main/java/mage/cards/CardGraphicInfo.java @@ -2,7 +2,9 @@ package mage.cards; import mage.ObjectColor; -public final class CardGraphicInfo { +import java.io.Serializable; + +public final class CardGraphicInfo implements Serializable { private final ObjectColor frameColor; private final FrameStyle frameStyle; @@ -29,4 +31,14 @@ public final class CardGraphicInfo { public boolean getUsesVariousArt() { return this.useVariousArt; } + + private CardGraphicInfo(final CardGraphicInfo info) { + this.frameColor = info.frameColor != null ? info.frameColor.copy() : null; + this.frameStyle = info.frameStyle; + this.useVariousArt = info.useVariousArt; + } + + public CardGraphicInfo copy() { + return new CardGraphicInfo(this); + } } diff --git a/Mage/src/main/java/mage/cards/CardImpl.java b/Mage/src/main/java/mage/cards/CardImpl.java index 8b19cf5d3f..1bb7efb4e4 100644 --- a/Mage/src/main/java/mage/cards/CardImpl.java +++ b/Mage/src/main/java/mage/cards/CardImpl.java @@ -1,10 +1,13 @@ package mage.cards; +import com.google.common.collect.ImmutableList; import mage.MageObject; import mage.MageObjectImpl; import mage.Mana; import mage.ObjectColor; import mage.abilities.*; +import mage.abilities.hint.Hint; +import mage.abilities.hint.HintUtils; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.cards.repository.PluginClassloaderRegistery; import mage.constants.*; @@ -222,11 +225,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { game.getState().getCardState(objectId).addInfo(key, value); } - protected static final ArrayList rulesError = new ArrayList() { - { - add("Exception occurred in rules generation"); - } - }; + protected static final List rulesError = ImmutableList.of("Exception occurred in rules generation"); @Override public List getRules() { @@ -243,6 +242,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { try { List rules = getRules(); if (game != null) { + // debug state CardState cardState = game.getState().getCardState(objectId); if (cardState != null) { for (String data : cardState.getInfo().values()) { @@ -252,6 +252,27 @@ public abstract class CardImpl extends MageObjectImpl implements Card { rules.add(ability.getRule()); } } + + // ability hints + List abilityHints = new ArrayList<>(); + if (HintUtils.ABILITY_HINTS_ENABLE) { + for (Ability ability : abilities) { + for (Hint hint : ability.getHints()) { + String s = hint.getText(game, ability); + if (s != null && !s.isEmpty()) { + abilityHints.add(s); + } + } + } + } + + // restrict hints only for permanents, not cards + + // total hints + if (!abilityHints.isEmpty()) { + rules.add(HintUtils.HINT_START_MARK); + HintUtils.appendHints(rules, abilityHints); + } } return rules; } catch (Exception e) { @@ -327,9 +348,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card { return spellAbility; } -// @Override -// public void adjustCosts(Ability ability, Game game) { -// } + @Override + public void adjustCosts(Ability ability, Game game) { + ability.adjustCosts(game); + } + @Override public void adjustTargets(Ability ability, Game game) { ability.adjustTargets(game); @@ -360,9 +383,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { public List getMana() { List mana = new ArrayList<>(); for (ActivatedManaAbilityImpl ability : this.abilities.getActivatedManaAbilities(Zone.BATTLEFIELD)) { - for (Mana netMana : ability.getNetMana(null)) { - mana.add(netMana); - } + mana.addAll(ability.getNetMana(null)); } return mana; } @@ -486,7 +507,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } } if (lkiObject != null) { - removed = game.getState().getCommand().remove((CommandObject) lkiObject); + removed = game.getState().getCommand().remove(lkiObject); } break; case OUTSIDE: @@ -591,7 +612,6 @@ public abstract class CardImpl extends MageObjectImpl implements Card { } List cardInfo = Sets.findSet(expansionSetCode).findCardInfoByClass(secondSideCardClazz); - assert cardInfo.size() == 1; // should find 1 second side card if (cardInfo.isEmpty()) { return null; } @@ -700,6 +720,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public void removeCounters(String name, int amount, Game game) { + int finalAmount = 0; for (int i = 0; i < amount; i++) { if (!getCounters(game).removeCounter(name, 1)) { break; @@ -707,7 +728,12 @@ public abstract class CardImpl extends MageObjectImpl implements Card { GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTER_REMOVED, objectId, getControllerOrOwner()); event.setData(name); game.fireEvent(event); + finalAmount++; } + GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTERS_REMOVED, objectId, getControllerOrOwner()); + event.setData(name); + event.setAmount(finalAmount); + game.fireEvent(event); } @Override @@ -720,7 +746,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card { @Override public String getLogName() { if (name.isEmpty()) { - return GameLog.getNeutralColoredText("face down card"); + return GameLog.getNeutralColoredText(EmptyNames.FACE_DOWN_CREATURE.toString()); } else { return GameLog.getColoredObjectIdName(this); } diff --git a/Mage/src/main/java/mage/cards/CardSetInfo.java b/Mage/src/main/java/mage/cards/CardSetInfo.java index c6a8ee07e4..447175b38a 100644 --- a/Mage/src/main/java/mage/cards/CardSetInfo.java +++ b/Mage/src/main/java/mage/cards/CardSetInfo.java @@ -1,10 +1,11 @@ package mage.cards; import mage.constants.Rarity; +import mage.util.Copyable; import java.io.Serializable; -public final class CardSetInfo implements Serializable { +public final class CardSetInfo implements Serializable, Copyable { private final String name; private final String cardNumber; @@ -43,4 +44,17 @@ public final class CardSetInfo implements Serializable { public CardGraphicInfo getGraphicInfo() { return this.graphicInfo; } + + private CardSetInfo(final CardSetInfo info) { + this.name = info.name; + this.expansionSetCode = info.expansionSetCode; + this.cardNumber = info.cardNumber; + this.rarity = info.rarity; + this.graphicInfo = info.getGraphicInfo() != null ? info.getGraphicInfo().copy() : null; + } + + @Override + public CardSetInfo copy() { + return new CardSetInfo(this); + } } diff --git a/Mage/src/main/java/mage/cards/CardsImpl.java b/Mage/src/main/java/mage/cards/CardsImpl.java index 50492310d8..14c7537bf9 100644 --- a/Mage/src/main/java/mage/cards/CardsImpl.java +++ b/Mage/src/main/java/mage/cards/CardsImpl.java @@ -155,7 +155,9 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl List cards = new ArrayList<>(); for (UUID cardId : this) { Card card = game.getCard(cardId); - cards.add(card.getName()); + if (card != null) { + cards.add(card.getName()); + } } Collections.sort(cards); for (String name : cards) { @@ -183,7 +185,9 @@ public class CardsImpl extends LinkedHashSet implements Cards, Serializabl Map cards = new HashMap<>(); for (UUID cardId : this) { Card card = game.getCard(cardId); - cards.putIfAbsent(card.getName(), card); + if (card != null) { + cards.putIfAbsent(card.getName(), card); + } } return cards.values(); } diff --git a/Mage/src/main/java/mage/cards/ExpansionSet.java b/Mage/src/main/java/mage/cards/ExpansionSet.java index 488b32b044..ba8ac8073f 100644 --- a/Mage/src/main/java/mage/cards/ExpansionSet.java +++ b/Mage/src/main/java/mage/cards/ExpansionSet.java @@ -1,31 +1,29 @@ - package mage.cards; import mage.ObjectColor; +import mage.abilities.Ability; +import mage.abilities.keyword.PartnerWithAbility; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; -import mage.abilities.Ability; import mage.constants.Rarity; import mage.constants.SetType; import mage.util.CardUtil; import mage.util.RandomUtil; +import org.apache.log4j.Logger; import java.io.Serializable; import java.util.*; import java.util.stream.Collectors; -import mage.abilities.keyword.PartnerWithAbility; -import org.apache.log4j.Logger; - /** * @author BetaSteward_at_googlemail.com */ public abstract class ExpansionSet implements Serializable { private static final Logger logger = Logger.getLogger(ExpansionSet.class); - public final static CardGraphicInfo NON_FULL_USE_VARIOUS = new CardGraphicInfo(null, true); - public final static CardGraphicInfo FULL_ART_BFZ_VARIOUS = new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true); + public static final CardGraphicInfo NON_FULL_USE_VARIOUS = new CardGraphicInfo(null, true); + public static final CardGraphicInfo FULL_ART_BFZ_VARIOUS = new CardGraphicInfo(FrameStyle.BFZ_FULL_ART_BASIC, true); public class SetCardInfo implements Serializable { @@ -108,6 +106,7 @@ public abstract class ExpansionSet implements Serializable { protected boolean hasPartnerMechanic = false; protected boolean needsLegendCreature = false; + protected boolean needsPlaneswalker = false; protected boolean validateBoosterColors = true; protected double rejectMissingColorProbability = 0.8; protected double rejectSameColorUncommonsProbability = 0.8; @@ -256,9 +255,10 @@ public abstract class ExpansionSet implements Serializable { } if (needsLegendCreature) { - if (booster.stream().noneMatch(card -> card.isLegendary() && card.isCreature())) { - return false; - } + return booster.stream().anyMatch(card -> card.isLegendary() && card.isCreature()); + } + if (needsPlaneswalker) { + return booster.stream().filter(card -> card.isPlaneswalker()).count() == 1; } // TODO: add partner check @@ -312,9 +312,7 @@ public abstract class ExpansionSet implements Serializable { // check that we don't have 3 or more uncommons/rares of the same color if (magicColors.stream().anyMatch(color -> uncommonWeight.get(color) >= 180)) { // reject only part of the boosters - if (RandomUtil.nextDouble() < rejectSameColorUncommonsProbability) { - return false; - } + return !(RandomUtil.nextDouble() < rejectSameColorUncommonsProbability); } return true; @@ -606,10 +604,6 @@ public abstract class ExpansionSet implements Serializable { return new ArrayList<>(); } - public boolean isCustomSet() { - return setType == SetType.CUSTOM_SET; - } - public void removeSavedCards() { savedCards.clear(); } diff --git a/Mage/src/main/java/mage/cards/Sets.java b/Mage/src/main/java/mage/cards/Sets.java index f68db60abe..1c3bde2f14 100644 --- a/Mage/src/main/java/mage/cards/Sets.java +++ b/Mage/src/main/java/mage/cards/Sets.java @@ -1,10 +1,6 @@ - package mage.cards; import mage.Mana; -import mage.cards.decks.DeckCardInfo; -import mage.cards.decks.DeckCardLayout; -import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardCriteria; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; @@ -17,12 +13,9 @@ import mage.util.RandomUtil; import org.apache.log4j.Logger; import org.junit.Assert; -import java.io.FileNotFoundException; -import java.io.PrintWriter; import java.util.*; /** - * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class Sets extends HashMap { @@ -53,15 +46,11 @@ public class Sets extends HashMap { throw new IllegalArgumentException("Set code " + set.getCode() + " already exists."); } this.put(set.getCode(), set); - if (set.isCustomSet()) { + if (set.getSetType().isCustomSet()) { customSets.add(set.getCode()); } } - public static boolean isCustomSet(String setCode) { - return getInstance().customSets.contains(setCode); - } - /** * Generates card pool of cardsCount cards that have manacost of allowed * colors. @@ -75,6 +64,10 @@ public class Sets extends HashMap { } public static List generateRandomCardPool(int cardsCount, List allowedColors, boolean onlyBasicLands) { + return generateRandomCardPool(cardsCount, allowedColors, onlyBasicLands, null); + } + + public static List generateRandomCardPool(int cardsCount, List allowedColors, boolean onlyBasicLands, List allowedSets) { CardCriteria criteria = new CardCriteria(); if (onlyBasicLands) { @@ -94,6 +87,12 @@ public class Sets extends HashMap { criteria.colorless(false); // colorless is not allowed for gen } + if (allowedSets != null && allowedSets.size() > 0) { + for (String code : allowedSets) { + criteria.setCodes(code); + } + } + FilterMana manaNeed = new FilterMana(); for (ColoredManaSymbol color : allowedColors) { switch (color) { @@ -120,6 +119,9 @@ public class Sets extends HashMap { } } List cards = CardRepository.instance.findCards(criteria); + if (cards.isEmpty()) { + throw new IllegalStateException("Can't find cards for chosen colors to generate deck: " + allowedColors); + } int count = 0; int tries = 0; @@ -137,21 +139,43 @@ public class Sets extends HashMap { // discard not needed color by mana produce Assert.assertEquals("only basic lands allow, but found " + card.getName(), 1, card.getMana().size()); for (Mana manaLand : card.getMana()) { - if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { cardManaOK = false; } - if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { cardManaOK = false; } - if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { cardManaOK = false; } - if (manaLand.getRed() > 0 && !manaNeed.isRed()) { cardManaOK = false; } - if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { cardManaOK = false; } - if (manaLand.getColorless() > 0) { cardManaOK = false; } // ignore colorless land (wastes) + if (manaLand.getWhite() > 0 && !manaNeed.isWhite()) { + cardManaOK = false; + } + if (manaLand.getBlue() > 0 && !manaNeed.isBlue()) { + cardManaOK = false; + } + if (manaLand.getBlack() > 0 && !manaNeed.isBlack()) { + cardManaOK = false; + } + if (manaLand.getRed() > 0 && !manaNeed.isRed()) { + cardManaOK = false; + } + if (manaLand.getGreen() > 0 && !manaNeed.isGreen()) { + cardManaOK = false; + } + if (manaLand.getColorless() > 0) { + cardManaOK = false; + } // ignore colorless land (wastes) } } else { // cards // discard any card that have not needed color - if (manaCard.isWhite() && !manaNeed.isWhite()) { cardManaOK = false; } - if (manaCard.isBlue() && !manaNeed.isBlue()) { cardManaOK = false; } - if (manaCard.isBlack() && !manaNeed.isBlack()) { cardManaOK = false; } - if (manaCard.isRed() && !manaNeed.isRed()) { cardManaOK = false; } - if (manaCard.isGreen() && !manaNeed.isGreen()) { cardManaOK = false; } + if (manaCard.isWhite() && !manaNeed.isWhite()) { + cardManaOK = false; + } + if (manaCard.isBlue() && !manaNeed.isBlue()) { + cardManaOK = false; + } + if (manaCard.isBlack() && !manaNeed.isBlack()) { + cardManaOK = false; + } + if (manaCard.isRed() && !manaNeed.isRed()) { + cardManaOK = false; + } + if (manaCard.isGreen() && !manaNeed.isGreen()) { + cardManaOK = false; + } } if (cardManaOK) { @@ -176,73 +200,4 @@ public class Sets extends HashMap { return null; } - public static void saveDeck(String file, DeckCardLists deck) throws FileNotFoundException { - Map deckCards = new HashMap<>(); - Map sideboard = new HashMap<>(); - try (PrintWriter out = new PrintWriter(file)) { - if (deck.getName() != null && !deck.getName().isEmpty()) { - out.println("NAME:" + deck.getName()); - } - if (deck.getAuthor() != null && !deck.getAuthor().isEmpty()) { - out.println("AUTHOR:" + deck.getAuthor()); - } - for (DeckCardInfo deckCardInfo : deck.getCards()) { - if (deckCards.containsKey(deckCardInfo.getCardKey())) { - deckCards.put(deckCardInfo.getCardKey(), deckCards.get(deckCardInfo.getCardKey()).increaseQuantity()); - } else { - deckCards.put(deckCardInfo.getCardKey(), deckCardInfo); - } - } - - for (DeckCardInfo deckCardInfo : deck.getSideboard()) { - if (sideboard.containsKey(deckCardInfo.getCardKey())) { - sideboard.put(deckCardInfo.getCardKey(), sideboard.get(deckCardInfo.getCardKey()).increaseQuantity()); - } else { - sideboard.put(deckCardInfo.getCardKey(), deckCardInfo); - } - } - - // Write out all of the cards - for (Entry entry : deckCards.entrySet()) { - out.printf("%d [%s:%s] %s%n", entry.getValue().getQuantity(), entry.getValue().getSetCode(), entry.getValue().getCardNum(), entry.getValue().getCardName()); - } - for (Entry entry : sideboard.entrySet()) { - out.printf("SB: %d [%s:%s] %s%n", entry.getValue().getQuantity(), entry.getValue().getSetCode(), entry.getValue().getCardNum(), entry.getValue().getCardName()); - } - - // Write out the layout - out.print("LAYOUT MAIN:"); - writeCardLayout(out, deck.getCardLayout()); - out.print("\n"); - out.print("LAYOUT SIDEBOARD:"); - writeCardLayout(out, deck.getSideboardLayout()); - out.print("\n"); - } - } - - private static void writeCardLayout(PrintWriter out, DeckCardLayout layout) { - if (layout == null) { - return; - } - List>> cardGrid = layout.getCards(); - int height = cardGrid.size(); - int width = (height > 0) ? cardGrid.get(0).size() : 0; - out.print("(" + height + ',' + width + ')'); - out.print(layout.getSettings()); - out.print("|"); - for (List> row : cardGrid) { - for (List stack : row) { - out.print("("); - for (int i = 0; i < stack.size(); ++i) { - DeckCardInfo info = stack.get(i); - out.printf("[%s:%s]", info.getSetCode(), info.getCardNum()); - if (i != stack.size() - 1) { - out.print(","); - } - } - out.print(")"); - } - } - } - } diff --git a/Mage/src/main/java/mage/cards/SplitCard.java b/Mage/src/main/java/mage/cards/SplitCard.java index b8102f7ae4..a602c2a663 100644 --- a/Mage/src/main/java/mage/cards/SplitCard.java +++ b/Mage/src/main/java/mage/cards/SplitCard.java @@ -1,9 +1,6 @@ - package mage.cards; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; import mage.abilities.Ability; @@ -13,8 +10,11 @@ import mage.constants.SpellAbilityType; import mage.constants.Zone; import mage.game.Game; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class SplitCard extends CardImpl { @@ -58,10 +58,10 @@ public abstract class SplitCard extends CardImpl { } @Override - public void setCopy(boolean isCopy) { - super.setCopy(isCopy); - leftHalfCard.setCopy(isCopy); - rightHalfCard.setCopy(isCopy); + public void setCopy(boolean isCopy, MageObject copiedFrom) { + super.setCopy(isCopy, copiedFrom); + leftHalfCard.setCopy(isCopy, copiedFrom); + rightHalfCard.setCopy(isCopy, copiedFrom); } @Override diff --git a/Mage/src/main/java/mage/cards/decks/Constructed.java b/Mage/src/main/java/mage/cards/decks/Constructed.java index 23410c32b5..aaa95e435b 100644 --- a/Mage/src/main/java/mage/cards/decks/Constructed.java +++ b/Mage/src/main/java/mage/cards/decks/Constructed.java @@ -1,26 +1,28 @@ - package mage.cards.decks; -import java.util.*; -import java.util.Map.Entry; import mage.cards.Card; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.Rarity; import org.apache.log4j.Logger; +import java.util.*; +import java.util.Map.Entry; + /** - * * @author BetaSteward_at_googlemail.com */ public class Constructed extends DeckValidator { private static final Logger logger = Logger.getLogger(DeckValidator.class); - protected static final List anyNumberCardsAllowed = new ArrayList<>(Arrays.asList("Relentless Rats", "Shadowborn Apostle", "Rat Colony")); - protected static final List basicLandNames = new ArrayList<>( - Arrays.asList("Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest", - "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains")); + protected static final List anyNumberCardsAllowed = new ArrayList<>(Arrays.asList( + "Relentless Rats", "Shadowborn Apostle", "Rat Colony", "Persistent Petitioners" + )); + protected static final List basicLandNames = new ArrayList<>(Arrays.asList( + "Forest", "Island", "Mountain", "Swamp", "Plains", "Wastes", "Snow-Covered Forest", + "Snow-Covered Island", "Snow-Covered Mountain", "Snow-Covered Swamp", "Snow-Covered Plains" + )); protected List banned = new ArrayList<>(); protected List restricted = new ArrayList<>(); protected List setCodes = new ArrayList<>(); @@ -38,12 +40,22 @@ public class Constructed extends DeckValidator { return setCodes; } + @Override + public int getDeckMinSize() { + return 60; + } + + @Override + public int getSideboardMinSize() { + return 0; + } + @Override public boolean validate(Deck deck) { boolean valid = true; //20091005 - 100.2a - if (deck.getCards().size() < 60) { - invalid.put("Deck", "Must contain at least 60 cards: has only " + deck.getCards().size() + " cards"); + if (deck.getCards().size() < getDeckMinSize()) { + invalid.put("Deck", "Must contain at least " + getDeckMinSize() + " cards: has only " + deck.getCards().size() + " cards"); valid = false; } //20130713 - 100.4a diff --git a/Mage/src/main/java/mage/cards/decks/DeckFileFilter.java b/Mage/src/main/java/mage/cards/decks/DeckFileFilter.java new file mode 100644 index 0000000000..d7ca6415ed --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/DeckFileFilter.java @@ -0,0 +1,40 @@ +package mage.cards.decks; + +import javax.swing.filechooser.FileFilter; +import java.io.File; +import java.util.Locale; + +/** + * @author JayDi85 + */ +public class DeckFileFilter extends FileFilter { + + private final String ext; + private final String description; + + public DeckFileFilter(String ext, String description) { + this.ext = ext.toLowerCase(Locale.ENGLISH); + this.description = description; + } + + @Override + public boolean accept(File f) { + if (f.isDirectory()) { + return true; + } + + String fileExt = null; + String s = f.getName(); + int i = s.lastIndexOf('.'); + + if (i > 0 && i < s.length() - 1) { + fileExt = s.substring(i + 1).toLowerCase(Locale.ENGLISH); + } + return (fileExt != null) && fileExt.equals(this.ext); + } + + @Override + public String getDescription() { + return description; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/cards/decks/DeckFormats.java b/Mage/src/main/java/mage/cards/decks/DeckFormats.java new file mode 100644 index 0000000000..8100bb909b --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/DeckFormats.java @@ -0,0 +1,119 @@ +package mage.cards.decks; + +import mage.cards.decks.exporter.DeckExporter; +import mage.cards.decks.exporter.MtgArenaDeckExporter; +import mage.cards.decks.exporter.MtgOnlineDeckExporter; +import mage.cards.decks.exporter.XmageDeckExporter; + +import javax.swing.filechooser.FileFilter; +import java.io.*; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.Optional; + +public enum DeckFormats { + + XMAGE(new XmageDeckExporter()), + MTG_ONLINE(new MtgOnlineDeckExporter()), + MTG_ARENA(new MtgArenaDeckExporter()); + + private final DeckExporter exporter; + + DeckFormats(DeckExporter exporter) { + this.exporter = exporter; + } + + public DeckExporter getExporter() { + return exporter; + } + + public static Optional getFormatForExtension(String filename) { + String exp = getExtension(filename).orElse(""); + for (DeckFormats df : values()) { + if (!exp.isEmpty() && df.getExporter().getDefaultFileExt().equals(exp)) { + return Optional.of(df); + } + } + return Optional.empty(); + } + + public static Optional getExtension(String filename) { + int i = filename.lastIndexOf('.'); + if (i > 0 && i < filename.length() - 1) { + return Optional.of(filename.substring(i + 1).toLowerCase(Locale.ENGLISH)); + } else { + return Optional.empty(); + } + } + + public static Optional getFormatForFilter(FileFilter filter) { + for (DeckFormats df : values()) { + if (df.getExporter().getFileFilter().equals(filter)) { + return Optional.of(df); + } + } + return Optional.empty(); + } + + public static String getDefaultFileExtForFilter(FileFilter filter) { + return getFormatForFilter(filter) + .map(df -> df.getExporter().getDefaultFileExt()) + .orElse(""); + } + + public static List getFileFilters() { + List res = new ArrayList<>(); + for (DeckFormats df : values()) { + res.add(df.getExporter().getFileFilter()); + } + return res; + } + + public static void writeDeck(String file, DeckCardLists deck) throws IOException { + writeDeck(new File(file), deck); + } + + public static void writeDeck(String file, DeckCardLists deck, DeckFormats format) throws IOException { + writeDeck(new File(file), deck, format); + } + + public static void writeDeck(String file, DeckCardLists deck, DeckExporter exporter) throws IOException { + writeDeck(new File(file), deck, exporter); + } + + public static void writeDeck(File file, DeckCardLists deck) throws IOException { + DeckFormats format = DeckFormats.getFormatForExtension(file.getName()).orElseGet(() -> { + throw new IllegalArgumentException("Could not determine deck export format."); + }); + writeDeck(file, deck, format); + } + + public static void writeDeck(File file, DeckCardLists deck, DeckFormats format) throws IOException { + writeDeck(file, deck, format.getExporter()); + } + + public static void writeDeck(File file, DeckCardLists deck, DeckExporter exporter) throws IOException { + try (FileOutputStream out = new FileOutputStream(file)) { + writeDeck(out, deck, exporter); + } + } + + public static void writeDeck(OutputStream out, DeckCardLists deck, DeckFormats format) { + writeDeck(new PrintWriter(out), deck, format); + } + + public static void writeDeck(OutputStream out, DeckCardLists deck, DeckExporter exporter) { + writeDeck(new PrintWriter(out), deck, exporter); + } + + public static void writeDeck(PrintWriter out, DeckCardLists deck, DeckFormats format) { + writeDeck(out, deck, format.getExporter()); + } + + public static void writeDeck(PrintWriter out, DeckCardLists deck, DeckExporter exporter) { + exporter.writeDeck(out, deck); + out.flush(); + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/DeckFormatsTest.java b/Mage/src/main/java/mage/cards/decks/DeckFormatsTest.java new file mode 100644 index 0000000000..2b0e71e502 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/DeckFormatsTest.java @@ -0,0 +1,45 @@ +package mage.cards.decks; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author JayDi85 + */ +public class DeckFormatsTest { + + @Test + public void test_FormatsExt() { + Map extList = new HashMap<>(); + for (DeckFormats df : DeckFormats.values()) { + // 1. must be unique + if (extList.containsKey(df.getExporter().getDefaultFileExt())) { + Assert.fail("Default ext must be unique for each format: " + df.getExporter().getDescription()); + } else { + extList.putIfAbsent(df.getExporter().getDefaultFileExt(), df); + } + // 2. must work with files + String fileName = "C:\\xmage\\deck" + "." + df.getExporter().getDefaultFileExt(); + Assert.assertTrue("Must support lower ext: " + df.getExporter().getDescription(), DeckFormats.getFormatForExtension(fileName.toLowerCase()).isPresent()); + Assert.assertTrue("Must support upper ext: " + df.getExporter().getDescription(), DeckFormats.getFormatForExtension(fileName.toUpperCase()).isPresent()); + } + + // 3. wrong ext + Assert.assertFalse("Must not find empty ext", DeckFormats.getFormatForExtension("deck").isPresent()); + Assert.assertFalse("Must not find . ext", DeckFormats.getFormatForExtension("deck.").isPresent()); + Assert.assertFalse("Must not find unknown ext", DeckFormats.getFormatForExtension("deck.xxx").isPresent()); + + // 3. double ext + String fileName = "C:\\xmage\\deck" + + "." + DeckFormats.XMAGE.getExporter().getDefaultFileExt() + + "." + DeckFormats.MTG_ONLINE.getExporter().getDefaultFileExt(); + Assert.assertEquals("Must find mtgo", DeckFormats.getFormatForExtension(fileName).get(), DeckFormats.MTG_ONLINE); + fileName = "C:\\xmage\\deck" + + "." + DeckFormats.MTG_ONLINE.getExporter().getDefaultFileExt() + + "." + DeckFormats.XMAGE.getExporter().getDefaultFileExt(); + Assert.assertEquals("Must find xmage", DeckFormats.getFormatForExtension(fileName).get(), DeckFormats.XMAGE); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/cards/decks/DeckValidator.java b/Mage/src/main/java/mage/cards/decks/DeckValidator.java index d307890508..506fd6310b 100644 --- a/Mage/src/main/java/mage/cards/decks/DeckValidator.java +++ b/Mage/src/main/java/mage/cards/decks/DeckValidator.java @@ -1,14 +1,13 @@ - package mage.cards.decks; +import mage.cards.Card; + import java.io.Serializable; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import mage.cards.Card; /** - * * @author BetaSteward_at_googlemail.com */ public abstract class DeckValidator implements Serializable { @@ -32,11 +31,10 @@ public abstract class DeckValidator implements Serializable { } protected void countCards(Map counts, Collection cards) { - for (Card card: cards) { + for (Card card : cards) { if (counts.containsKey(card.getName())) { counts.put(card.getName(), counts.get(card.getName()) + 1); - } - else { + } else { counts.put(card.getName(), 1); } } @@ -45,4 +43,8 @@ public abstract class DeckValidator implements Serializable { public int getEdhPowerLevel(Deck deck) { return 0; } + + public abstract int getDeckMinSize(); + + public abstract int getSideboardMinSize(); } diff --git a/Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java b/Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java similarity index 86% rename from Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java rename to Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java index bdaabc92a5..b65ec5925b 100644 --- a/Mage.Server/src/main/java/mage/server/game/DeckValidatorFactory.java +++ b/Mage/src/main/java/mage/cards/decks/DeckValidatorFactory.java @@ -1,8 +1,5 @@ +package mage.cards.decks; - -package mage.server.game; - -import mage.cards.decks.DeckValidator; import org.apache.log4j.Logger; import java.lang.reflect.Constructor; @@ -11,7 +8,6 @@ import java.util.Map; import java.util.Set; /** - * * @author BetaSteward_at_googlemail.com */ public enum DeckValidatorFactory { @@ -21,16 +17,12 @@ public enum DeckValidatorFactory { private final Map deckTypes = new LinkedHashMap<>(); - - - private DeckValidatorFactory() {} - public DeckValidator createDeckValidator(String deckType) { DeckValidator validator; try { Constructor con = deckTypes.get(deckType).getConstructor(); - validator = (DeckValidator)con.newInstance(); + validator = (DeckValidator) con.newInstance(); } catch (Exception ex) { logger.fatal("DeckValidatorFactory error", ex); return null; diff --git a/Mage/src/main/java/mage/cards/decks/DnDDeckTargetListener.java b/Mage/src/main/java/mage/cards/decks/DnDDeckTargetListener.java new file mode 100644 index 0000000000..5865df3894 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/DnDDeckTargetListener.java @@ -0,0 +1,116 @@ +package mage.cards.decks; + +import org.apache.log4j.Logger; + +import javax.swing.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.UnsupportedFlavorException; +import java.awt.dnd.DropTargetAdapter; +import java.awt.dnd.DropTargetDragEvent; +import java.awt.dnd.DropTargetDropEvent; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.List; + +public class DnDDeckTargetListener extends DropTargetAdapter { + + private static final transient Logger logger = Logger.getLogger(DnDDeckTargetListener.class); + private static final DataFlavor fileFlavor = DataFlavor.javaFileListFlavor; + private static final DataFlavor plainTextFlavor = DataFlavor.stringFlavor; + + private boolean isCopyOrMove(int dropAction) { + return (dropAction & TransferHandler.COPY_OR_MOVE) != 0; + } + + private boolean isCopyAction(int dropAction) { + return (dropAction & TransferHandler.COPY) != 0; + } + + private boolean isMoveAction(int dropAction) { + return (dropAction & TransferHandler.MOVE) != 0; + } + + private boolean isAcceptable(DropTargetDragEvent dtde) { + boolean copyOrMove = isCopyOrMove(dtde.getDropAction()); + boolean flavorSupported = dtde.isDataFlavorSupported(plainTextFlavor) || dtde.isDataFlavorSupported(fileFlavor); + return copyOrMove && flavorSupported; + } + + private boolean isAcceptable(DropTargetDropEvent dtde) { + boolean copyOrMove = isCopyOrMove(dtde.getDropAction()); + boolean flavorSupported = dtde.isDataFlavorSupported(plainTextFlavor) || dtde.isDataFlavorSupported(fileFlavor); + return copyOrMove && flavorSupported; + } + + @Override + public void dragEnter(DropTargetDragEvent dtde) { + if (isAcceptable(dtde)) { + dtde.acceptDrag(TransferHandler.COPY); + } else { + dtde.rejectDrag(); + } + } + + @Override + public void dragOver(DropTargetDragEvent dtde) { + if (isAcceptable(dtde)) { + dtde.acceptDrag(TransferHandler.COPY); + } else { + dtde.rejectDrag(); + } + } + + @Override + public void dropActionChanged(DropTargetDragEvent dtde) { + if (isAcceptable(dtde)) { + dtde.acceptDrag(TransferHandler.COPY); + } else { + dtde.rejectDrag(); + } + } + + @Override + public void drop(DropTargetDropEvent dtde) { + if (isAcceptable(dtde)) { + dtde.acceptDrop(TransferHandler.COPY); + } else { + dtde.rejectDrop(); + dtde.dropComplete(false); + return; + } + + boolean move = isMoveAction(dtde.getDropAction()); + + try { + if (dtde.isDataFlavorSupported(fileFlavor)) { + List files = (List) dtde.getTransferable().getTransferData(fileFlavor); + dtde.dropComplete(handleFilesDrop(move, files)); + } else if (dtde.isDataFlavorSupported(plainTextFlavor)) { + String text = (String) dtde.getTransferable().getTransferData(plainTextFlavor); + try { + dtde.dropComplete(handleUriDrop(move, new URI(text))); + } catch (URISyntaxException e) { + dtde.dropComplete(handlePlainTextDrop(move, text)); + } + } + } catch (UnsupportedFlavorException | IOException e) { + logger.error("Unsupported drag and drop data", e); + dtde.dropComplete(false); + } + } + + protected boolean handlePlainTextDrop(boolean move, String text) { + return false; + } + + protected boolean handleUriDrop(boolean move, URI uri) { + return false; + } + + protected boolean handleFilesDrop(boolean move, List files) { + return false; + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/exporter/DeckExporter.java b/Mage/src/main/java/mage/cards/decks/exporter/DeckExporter.java new file mode 100644 index 0000000000..d9a4b8ab40 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/exporter/DeckExporter.java @@ -0,0 +1,33 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckFormats; + +import javax.swing.filechooser.FileFilter; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; + +public abstract class DeckExporter { + + public void writeDeck(String file, DeckCardLists deck) throws IOException { + DeckFormats.writeDeck(file, deck, this); + } + + public void writeDeck(File file, DeckCardLists deck) throws IOException { + DeckFormats.writeDeck(file, deck, this); + } + + public void writeDeck(OutputStream out, DeckCardLists deck) { + DeckFormats.writeDeck(out, deck, this); + } + + public abstract void writeDeck(PrintWriter out, DeckCardLists deck); + + public abstract FileFilter getFileFilter(); + + public abstract String getDefaultFileExt(); + + public abstract String getDescription(); +} diff --git a/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporter.java b/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporter.java new file mode 100644 index 0000000000..220637ecff --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporter.java @@ -0,0 +1,75 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckFileFilter; + +import javax.swing.filechooser.FileFilter; +import java.io.PrintWriter; +import java.util.*; + +/** + * @author JayDi85 + */ +public class MtgArenaDeckExporter extends DeckExporter { + + private final String ext = "mtga"; + private final String description = "MTG Arena's deck format (*.mtga)"; + private final FileFilter fileFilter = new DeckFileFilter(ext, description); + + @Override + public void writeDeck(PrintWriter out, DeckCardLists deck) { + Map amount = new HashMap<>(); + List deckMain = prepareCardsList(deck.getCards(), amount, "M@"); + List deckSideboard = prepareCardsList(deck.getSideboard(), amount, "S@"); + + printCards(out, deckMain, amount, "M@"); + if (deckSideboard.size() > 0) { + out.println(); + printCards(out, deckSideboard, amount, "S@"); + } + } + + private List prepareCardsList(List sourceCards, Map amount, String prefix) { + List res = new ArrayList<>(); + for (DeckCardInfo card : sourceCards) { + String name = card.getCardName() + " (" + card.getSetCode().toUpperCase(Locale.ENGLISH) + ") " + card.getCardNum(); + String code = prefix + name; + int curAmount = amount.getOrDefault(code, 0); + if (curAmount == 0) { + res.add(name); + } + amount.put(code, curAmount + card.getQuantity()); + } + return res; + } + + private void printCards(PrintWriter out, List deck, Map amount, String prefix) { + if (deck.size() == 0) return; + + boolean firstCard = true; + for (String name : deck) { + if (!firstCard) out.println(); + out.print(amount.get(prefix + name)); + out.print(' '); + out.print(name); + firstCard = false; + } + out.println(); + } + + @Override + public FileFilter getFileFilter() { + return fileFilter; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getDefaultFileExt() { + return ext; + } +} diff --git a/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporterTest.java b/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporterTest.java new file mode 100644 index 0000000000..773a0d19a3 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/exporter/MtgArenaDeckExporterTest.java @@ -0,0 +1,38 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +/** + * @author JayDi85 + */ +public class MtgArenaDeckExporterTest { + + @Test + public void writeDeck() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeckCardLists deck = new DeckCardLists(); + deck.getCards().add(new DeckCardInfo("Forest", "1", "RNA", 2)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 3)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 5)); // must combine + deck.getCards().add(new DeckCardInfo("Mountain", "3", "RNA", 1)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 2)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 5)); // must combine + deck.getSideboard().add(new DeckCardInfo("Mountain", "2", "RNA", 3)); + DeckExporter exporter = new MtgArenaDeckExporter(); + exporter.writeDeck(baos, deck); + assertEquals("2 Forest (RNA) 1" + System.lineSeparator() + + "8 Plains (RNA) 2" + System.lineSeparator() + + "1 Mountain (RNA) 3" + System.lineSeparator() + + System.lineSeparator() + + "7 Island (RNA) 1" + System.lineSeparator() + + "3 Mountain (RNA) 2" + System.lineSeparator(), + baos.toString()); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/cards/decks/exporter/MtgOnlineDeckExporter.java b/Mage/src/main/java/mage/cards/decks/exporter/MtgOnlineDeckExporter.java new file mode 100644 index 0000000000..5cf545b911 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/exporter/MtgOnlineDeckExporter.java @@ -0,0 +1,74 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckFileFilter; + +import javax.swing.filechooser.FileFilter; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MtgOnlineDeckExporter extends DeckExporter { + + private final String ext = "dek"; + private final String description = "MTG Online's deck format (*.dek)"; + private final FileFilter fileFilter = new DeckFileFilter(ext, description); + + @Override + public void writeDeck(PrintWriter out, DeckCardLists deck) { + Map amount = new HashMap<>(); + List deckMain = prepareCardsList(deck.getCards(), amount, "M@"); + List deckSideboard = prepareCardsList(deck.getSideboard(), amount, "S@"); + + printCards(out, deckMain, amount, "M@"); + if (deckSideboard.size() > 0) { + out.println(); + printCards(out, deckSideboard, amount, "S@"); + } + } + + private List prepareCardsList(List sourceCards, Map amount, String prefix) { + List res = new ArrayList<>(); + for (DeckCardInfo card : sourceCards) { + String code = prefix + card.getCardName(); + int curAmount = amount.getOrDefault(code, 0); + if (curAmount == 0) { + res.add(card.getCardName()); + } + amount.put(code, curAmount + card.getQuantity()); + } + return res; + } + + private void printCards(PrintWriter out, List deck, Map amount, String prefix) { + if (deck.size() == 0) return; + + boolean firstCard = true; + for (String name : deck) { + if (!firstCard) out.println(); + out.print(amount.get(prefix + name)); + out.print(' '); + out.print(name); + firstCard = false; + } + out.println(); + } + + @Override + public FileFilter getFileFilter() { + return fileFilter; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getDefaultFileExt() { + return ext; + } +} diff --git a/Mage/src/main/java/mage/cards/decks/exporter/XmageDeckExporter.java b/Mage/src/main/java/mage/cards/decks/exporter/XmageDeckExporter.java new file mode 100644 index 0000000000..c3e18fe023 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/exporter/XmageDeckExporter.java @@ -0,0 +1,113 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLayout; +import mage.cards.decks.DeckCardLists; +import mage.cards.decks.DeckFileFilter; + +import javax.swing.filechooser.FileFilter; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class XmageDeckExporter extends DeckExporter { + + private final String ext = "dck"; + private final String description = "XMage's deck format (*.dck)"; + private final FileFilter fileFilter = new DeckFileFilter(ext, description); + + @Override + public void writeDeck(PrintWriter out, DeckCardLists deck) { + List deckMain = new ArrayList<>(); + List deckSideboard = new ArrayList<>(); + Map amount = new HashMap<>(); + + // info + if (deck.getName() != null && !deck.getName().isEmpty()) { + out.println("NAME:" + deck.getName()); + } + if (deck.getAuthor() != null && !deck.getAuthor().isEmpty()) { + out.println("AUTHOR:" + deck.getAuthor()); + } + + // main + for (DeckCardInfo card : deck.getCards()) { + String code = "M@" + card.getCardKey(); + int curAmount = amount.getOrDefault(code, 0); + if (curAmount == 0) { + deckMain.add(card); + } + amount.put(code, curAmount + card.getQuantity()); + } + // sideboard + for (DeckCardInfo card : deck.getSideboard()) { + String code = "S@" + card.getCardKey(); + int curAmount = amount.getOrDefault(code, 0); + if (curAmount == 0) { + deckSideboard.add(card); + } + amount.put(code, curAmount + card.getQuantity()); + } + + // cards print + for (DeckCardInfo card : deckMain) { + out.printf("%d [%s:%s] %s%n", amount.get("M@" + card.getCardKey()), card.getSetCode(), card.getCardNum(), card.getCardName()); + } + for (DeckCardInfo card : deckSideboard) { + out.printf("SB: %d [%s:%s] %s%n", amount.get("S@" + card.getCardKey()), card.getSetCode(), card.getCardNum(), card.getCardName()); + } + + // layout print + if (deck.getCardLayout() != null) { + out.print("LAYOUT MAIN:"); + writeCardLayout(out, deck.getCardLayout()); + out.println(""); + out.print("LAYOUT SIDEBOARD:"); + writeCardLayout(out, deck.getSideboardLayout()); + out.println(""); + } + } + + private static void writeCardLayout(PrintWriter out, DeckCardLayout layout) { + if (layout == null) { + return; + } + List>> cardGrid = layout.getCards(); + int height = cardGrid.size(); + int width = (height > 0) ? cardGrid.get(0).size() : 0; + out.print("(" + height + ',' + width + ')'); + out.print(layout.getSettings()); + out.print("|"); + for (List> row : cardGrid) { + for (List stack : row) { + out.print("("); + for (int i = 0; i < stack.size(); ++i) { + DeckCardInfo info = stack.get(i); + out.printf("[%s:%s]", info.getSetCode(), info.getCardNum()); + if (i != stack.size() - 1) { + out.print(","); + } + } + out.print(")"); + } + } + } + + @Override + public FileFilter getFileFilter() { + return fileFilter; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getDefaultFileExt() { + return ext; + } +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/CardLookup.java b/Mage/src/main/java/mage/cards/decks/importer/CardLookup.java new file mode 100644 index 0000000000..2a7aa1ae3e --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/CardLookup.java @@ -0,0 +1,22 @@ +package mage.cards.decks.importer; + +import java.util.List; +import java.util.Optional; + +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; + +public class CardLookup { + + public static final CardLookup instance = new CardLookup(); + + public Optional lookupCardInfo(String name) { + return Optional.ofNullable(CardRepository.instance.findPreferedCoreExpansionCard(name, true)); + } + + public List lookupCardInfo(CardCriteria criteria) { + return CardRepository.instance.findCards(criteria); + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java new file mode 100644 index 0000000000..a79a6beeb5 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/CodDeckImporter.java @@ -0,0 +1,74 @@ +package mage.cards.decks.importer; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardInfo; + +public class CodDeckImporter extends XmlDeckImporter { + + @Override + public DeckCardLists importDeck(String filename, StringBuilder errorMessages) { + try { + Document doc = getXmlDocument(filename); + DeckCardLists decklist = new DeckCardLists(); + + List mainCards = getNodes(doc, "/cockatrice_deck/zone[@name='main']/card"); + decklist.setCards(mainCards.stream() + .flatMap(toDeckCardInfo(getCardLookup(), errorMessages)) + .collect(Collectors.toList())); + + List sideboardCards = getNodes(doc, "/cockatrice_deck/zone[@name='side']/card"); + decklist.setSideboard(sideboardCards.stream() + .flatMap(toDeckCardInfo(getCardLookup(), errorMessages)) + .collect(Collectors.toList())); + + getNodes(doc, "/cockatrice_deck/deckname") + .forEach(n -> decklist.setName(n.getTextContent().trim())); + + return decklist; + } catch (Exception e) { + logger.error("Error loading deck", e); + errorMessages.append("There was an error loading the deck."); + return new DeckCardLists(); + } + } + + private static int getQuantityFromNode(Node node) { + Node numberNode = node.getAttributes().getNamedItem("number"); + if (numberNode == null) { + return 1; + } + try { + return Math.min(100, Math.max(1, Integer.parseInt(numberNode.getNodeValue()))); + } catch (NumberFormatException e) { + return 1; + } + } + + private static Function> toDeckCardInfo(CardLookup lookup, StringBuilder errors) { + return node -> { + String name = node.getAttributes().getNamedItem("name").getNodeValue().trim(); + Optional cardInfo = lookup.lookupCardInfo(name); + if (cardInfo.isPresent()) { + CardInfo info = cardInfo.get(); + return Collections.nCopies( + getQuantityFromNode(node), + new DeckCardInfo(info.getName(), info.getCardNumber(), info.getSetCode())).stream(); + } else { + errors.append("Could not find card: '").append(name).append("'\n"); + return Stream.empty(); + } + }; + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java index fee59b3b4d..63788634ca 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DckDeckImporter.java @@ -15,7 +15,7 @@ import mage.cards.repository.CardRepository; * * @author North */ -public class DckDeckImporter extends DeckImporter { +public class DckDeckImporter extends PlainTextDeckImporter { private static final Pattern pattern = Pattern.compile("(SB:)?\\s*(\\d*)\\s*\\[([^]:]+):([^]:]+)\\]\\s*(.*)\\s*$"); @@ -56,7 +56,7 @@ public class DckDeckImporter extends DeckImporter { CardInfo foundedCard = CardRepository.instance.findCard(setCode, cardNum); boolean wasOutdated = false; if ((foundedCard != null) && !foundedCard.getName().equals(cardName)){ - sbMessage.append("Line ").append(lineCount).append(": ").append("founded outdated card number or name, will try to replace: ").append(line).append('\n'); + sbMessage.append("Line ").append(lineCount).append(": ").append("found outdated card number or name, will try to replace: ").append(line).append('\n'); wasOutdated = true; foundedCard = null; } diff --git a/Mage/src/main/java/mage/cards/decks/importer/DecDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DecDeckImporter.java index cf2c83a0c5..5ab07af1de 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DecDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DecDeckImporter.java @@ -1,6 +1,8 @@ package mage.cards.decks.importer; +import java.util.Optional; + import mage.cards.decks.DeckCardInfo; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; @@ -10,7 +12,7 @@ import mage.cards.repository.CardRepository; * * @author BetaSteward_at_googlemail.com */ -public class DecDeckImporter extends DeckImporter { +public class DecDeckImporter extends PlainTextDeckImporter { @Override protected void readLine(String line, DeckCardLists deckList) { @@ -29,10 +31,11 @@ public class DecDeckImporter extends DeckImporter { String lineName = line.substring(delim).trim(); try { int num = Integer.parseInt(lineNum); - CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true); - if (cardInfo == null) { + Optional cardLookup = getCardLookup().lookupCardInfo(lineName); + if (!cardLookup.isPresent()) { sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n'); } else { + CardInfo cardInfo = cardLookup.get(); for (int i = 0; i < num; i++) { if (!sideboard) { deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); diff --git a/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java index 1957cd7058..b7ba7f8059 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DeckImporter.java @@ -1,74 +1,91 @@ - - package mage.cards.decks.importer; -import mage.cards.decks.DeckCardLists; import org.apache.log4j.Logger; - import java.io.File; +import java.util.Locale; +import java.util.Optional; import java.util.Scanner; -/** - * - * @author BetaSteward_at_googlemail.com - */ + +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardInfo; +import mage.cards.repository.CardRepository; + public abstract class DeckImporter { - private static final Logger logger = Logger.getLogger(DeckImporter.class); + protected static final Logger logger = Logger.getLogger(DeckImporter.class); - protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats - protected int lineCount; + private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "}; + public static DeckImporter getDeckImporter(String file) { + if (file == null) { + return null; + } if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) { + return new DecDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) { + return new MWSDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) { + return new TxtDeckImporter(haveSideboardSection(file)); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) { + return new DckDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) { + return new DekDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("cod")) { + return new CodDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("o8d")) { + return new O8dDeckImporter(); + } else if (file.toLowerCase(Locale.ENGLISH).endsWith("draft")) { + return new DraftLogImporter(); + } else { + return null; + } + } - /** - * - * @param file file to import - * @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0) - * @return decks list - */ - public DeckCardLists importDeck(String file, StringBuilder errorMessages) { - File f = new File(file); - DeckCardLists deckList = new DeckCardLists(); - if (!f.exists()) { - logger.warn("Deckfile " + file + " not found."); - return deckList; + public static DeckCardLists importDeckFromFile(String file) { + return importDeckFromFile(file, new StringBuilder()); + } + + public static DeckCardLists importDeckFromFile(String file, StringBuilder errorMessages) { + DeckImporter deckImporter = getDeckImporter(file); + if (deckImporter != null) { + return deckImporter.importDeck(file, errorMessages); + } else { + return new DeckCardLists(); + } + } + + public abstract DeckCardLists importDeck(String file, StringBuilder errorMessages); + + public DeckCardLists importDeck(String file) { + return importDeck(file, new StringBuilder()); + } + + public CardLookup getCardLookup() { + return CardLookup.instance; + } + + private static boolean haveSideboardSection(String file) { + // search for sideboard section: + // or //sideboard + // or SB: 1 card name -- special deckstats.net + + File f = new File(file); + try (Scanner scanner = new Scanner(f)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH); + + for (String mark : SIDEBOARD_MARKS) { + if (line.startsWith(mark)) { + return true; + } } - lineCount = 0; - - sbMessage.setLength(0); - try { - try (Scanner scanner = new Scanner(f)) { - while (scanner.hasNextLine()) { - String line = scanner.nextLine().trim(); - lineCount++; - readLine(line, deckList); - } - - if (sbMessage.length() > 0) { - if(errorMessages != null) { - // normal output for user - errorMessages.append(sbMessage); - }else{ - // fatal error - logger.fatal(sbMessage); - } - } - } catch (Exception ex) { - logger.fatal(null, ex); - } - } catch (Exception ex) { - logger.fatal(null, ex); - } - return deckList; + } + } catch (Exception e) { + // ignore error, deckimporter will process it } - public DeckCardLists importDeck(String file) { - return importDeck(file, null); - } + // not found + return false; + } - public String getErrors(){ - return sbMessage.toString(); - } - - protected abstract void readLine(String line, DeckCardLists deckList); } diff --git a/Mage/src/main/java/mage/cards/decks/importer/DeckImporterUtil.java b/Mage/src/main/java/mage/cards/decks/importer/DeckImporterUtil.java deleted file mode 100644 index a0e90dc526..0000000000 --- a/Mage/src/main/java/mage/cards/decks/importer/DeckImporterUtil.java +++ /dev/null @@ -1,69 +0,0 @@ - -package mage.cards.decks.importer; - -import java.io.File; -import java.util.Locale; -import java.util.Scanner; -import mage.cards.decks.DeckCardLists; - -/** - * - * @author North - */ -public final class DeckImporterUtil { - - private static final String[] SIDEBOARD_MARKS = new String[]{"//sideboard", "sb: "}; - - public static boolean haveSideboardSection(String file) { - // search for sideboard section: - // or //sideboard - // or SB: 1 card name -- special deckstats.net - - File f = new File(file); - try (Scanner scanner = new Scanner(f)) { - while (scanner.hasNextLine()) { - String line = scanner.nextLine().trim().toLowerCase(Locale.ENGLISH); - - for (String mark : SIDEBOARD_MARKS) { - if (line.startsWith(mark)) { - return true; - } - } - } - } catch (Exception e) { - // ignore error, deckimporter will process it - } - - // not found - return false; - } - - public static DeckImporter getDeckImporter(String file) { - if (file.toLowerCase(Locale.ENGLISH).endsWith("dec")) { - return new DecDeckImporter(); - } else if (file.toLowerCase(Locale.ENGLISH).endsWith("mwdeck")) { - return new MWSDeckImporter(); - } else if (file.toLowerCase(Locale.ENGLISH).endsWith("txt")) { - return new TxtDeckImporter(haveSideboardSection(file)); - } else if (file.toLowerCase(Locale.ENGLISH).endsWith("dck")) { - return new DckDeckImporter(); - } else if (file.toLowerCase(Locale.ENGLISH).endsWith("dek")) { - return new DekDeckImporter(); - } else { - return null; - } - } - - public static DeckCardLists importDeck(String file, StringBuilder errorMessages) { - DeckImporter deckImporter = getDeckImporter(file); - if (deckImporter != null) { - return deckImporter.importDeck(file, errorMessages); - } else { - return new DeckCardLists(); - } - } - - public static DeckCardLists importDeck(String file) { - return importDeck(file, null); - } -} diff --git a/Mage/src/main/java/mage/cards/decks/importer/DekDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DekDeckImporter.java index 7e6efc577a..2672ff9d3e 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/DekDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/DekDeckImporter.java @@ -8,7 +8,7 @@ import mage.cards.repository.CardRepository; /** * Created by royk on 11-Sep-16. */ -public class DekDeckImporter extends DeckImporter { +public class DekDeckImporter extends PlainTextDeckImporter { @Override protected void readLine(String line, DeckCardLists deckList) { diff --git a/Mage/src/main/java/mage/cards/decks/importer/DraftLogImporter.java b/Mage/src/main/java/mage/cards/decks/importer/DraftLogImporter.java new file mode 100644 index 0000000000..5914165f1c --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/DraftLogImporter.java @@ -0,0 +1,46 @@ +package mage.cards.decks.importer; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; + +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class DraftLogImporter extends PlainTextDeckImporter { + + private static Pattern SET_PATTERN = Pattern.compile("------ (\\p{Alnum}+) ------$"); + private static Pattern PICK_PATTERN = Pattern.compile("--> (.+)$"); + + private String currentSet = null; + + @Override + protected void readLine(String line, DeckCardLists deckList) { + Matcher setMatcher = SET_PATTERN.matcher(line); + if (setMatcher.matches()) { + currentSet = setMatcher.group(1); + return; + } + + Matcher pickMatcher = PICK_PATTERN.matcher(line); + if (pickMatcher.matches()) { + String name = pickMatcher.group(1); + List cards = getCardLookup().lookupCardInfo(new CardCriteria().setCodes(currentSet).name(name)); + CardInfo card = null; + if (!cards.isEmpty()) { + card = cards.get(0); + } else { + card = getCardLookup().lookupCardInfo(name).orElse(null); + } + + if (card != null) { + deckList.getCards().add(new DeckCardInfo(card.getName(), card.getCardNumber(), card.getSetCode())); + } else { + sbMessage.append("couldn't find: \"").append(name).append("\"\n"); + } + } + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/MWSDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/MWSDeckImporter.java index bb5c066218..7c23d28c60 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/MWSDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/MWSDeckImporter.java @@ -14,7 +14,7 @@ import mage.util.RandomUtil; * * @author BetaSteward_at_googlemail.com */ -public class MWSDeckImporter extends DeckImporter { +public class MWSDeckImporter extends PlainTextDeckImporter { @Override protected void readLine(String line, DeckCardLists deckList) { @@ -43,13 +43,13 @@ public class MWSDeckImporter extends DeckImporter { CardCriteria criteria = new CardCriteria(); criteria.name(lineName); criteria.setCodes(setCode); - List cards = CardRepository.instance.findCards(criteria); + List cards = getCardLookup().lookupCardInfo(criteria); if (!cards.isEmpty()) { cardInfo = cards.get(RandomUtil.nextInt(cards.size())); } } if (cardInfo == null) { - cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true); + cardInfo = getCardLookup().lookupCardInfo(lineName).orElse(null); } if (cardInfo == null) { diff --git a/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java new file mode 100644 index 0000000000..cefc64e961 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/O8dDeckImporter.java @@ -0,0 +1,71 @@ +package mage.cards.decks.importer; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardInfo; + +public class O8dDeckImporter extends XmlDeckImporter { + + @Override + public DeckCardLists importDeck(String filename, StringBuilder errorMessages) { + try { + Document doc = getXmlDocument(filename); + DeckCardLists decklist = new DeckCardLists(); + + List mainCards = getNodes(doc, "/deck/section[@name='Main']/card"); + decklist.setCards(mainCards.stream() + .flatMap(toDeckCardInfo(getCardLookup(), errorMessages)) + .collect(Collectors.toList())); + + List sideboardCards = getNodes(doc, "/deck/section[@name='Sideboard']/card"); + decklist.setSideboard(sideboardCards.stream() + .flatMap(toDeckCardInfo(getCardLookup(), errorMessages)) + .collect(Collectors.toList())); + + return decklist; + } catch (Exception e) { + logger.error("Error loading deck", e); + errorMessages.append("There was an error loading the deck."); + return new DeckCardLists(); + } + } + + private static int getQuantityFromNode(Node node) { + Node numberNode = node.getAttributes().getNamedItem("qty"); + if (numberNode == null) { + return 1; + } + try { + return Math.min(100, Math.max(1, Integer.parseInt(numberNode.getNodeValue()))); + } catch (NumberFormatException e) { + return 1; + } + } + + private static Function> toDeckCardInfo(CardLookup lookup, StringBuilder errors) { + return node -> { + String name = node.getTextContent(); + Optional cardInfo = lookup.lookupCardInfo(name); + if (cardInfo.isPresent()) { + CardInfo info = cardInfo.get(); + return Collections.nCopies( + getQuantityFromNode(node), + new DeckCardInfo(info.getName(), info.getCardNumber(), info.getSetCode())).stream(); + } else { + errors.append("Could not find card: '").append(name).append("'\n"); + return Stream.empty(); + } + }; + } + +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java new file mode 100644 index 0000000000..c9d99d3aae --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/PlainTextDeckImporter.java @@ -0,0 +1,67 @@ + + +package mage.cards.decks.importer; + +import java.io.File; +import java.util.Scanner; + +import mage.cards.decks.DeckCardLists; + +/** + * + * @author BetaSteward_at_googlemail.com + */ +public abstract class PlainTextDeckImporter extends DeckImporter { + + protected StringBuilder sbMessage = new StringBuilder(); //TODO we should stop using this not garbage collectable StringBuilder. It just bloats + protected int lineCount; + + + /** + * + * @param file file to import + * @param errorMessages you can setup output messages to showup to user (set null for fatal exception on messages.count > 0) + * @return decks list + */ + public DeckCardLists importDeck(String file, StringBuilder errorMessages) { + File f = new File(file); + DeckCardLists deckList = new DeckCardLists(); + if (!f.exists()) { + logger.warn("Deckfile " + file + " not found."); + return deckList; + } + lineCount = 0; + + sbMessage.setLength(0); + try { + try (Scanner scanner = new Scanner(f)) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine().trim(); + lineCount++; + readLine(line, deckList); + } + + if (sbMessage.length() > 0) { + if(errorMessages != null) { + // normal output for user + errorMessages.append(sbMessage); + }else{ + // fatal error + logger.fatal(sbMessage); + } + } + } catch (Exception ex) { + logger.fatal(null, ex); + } + } catch (Exception ex) { + logger.fatal(null, ex); + } + return deckList; + } + + public DeckCardLists importDeck(String file) { + return importDeck(file, null); + } + + protected abstract void readLine(String line, DeckCardLists deckList); +} diff --git a/Mage/src/main/java/mage/cards/decks/importer/TxtDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/TxtDeckImporter.java index 4d593610ff..2941efcd6b 100644 --- a/Mage/src/main/java/mage/cards/decks/importer/TxtDeckImporter.java +++ b/Mage/src/main/java/mage/cards/decks/importer/TxtDeckImporter.java @@ -1,28 +1,27 @@ - package mage.cards.decks.importer; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Locale; -import java.util.Set; import mage.cards.decks.DeckCardInfo; import mage.cards.decks.DeckCardLists; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Locale; +import java.util.Set; + /** - * * @author BetaSteward_at_googlemail.com */ -public class TxtDeckImporter extends DeckImporter { +public class TxtDeckImporter extends PlainTextDeckImporter { private static final String[] SET_VALUES = new String[]{"lands", "creatures", "planeswalkers", "other spells", "sideboard cards", - "Instant", "Land", "Enchantment", "Artifact", "Sorcery", "Planeswalker", "Creature"}; + "Instant", "Land", "Enchantment", "Artifact", "Sorcery", "Planeswalker", "Creature"}; private static final Set IGNORE_NAMES = new HashSet<>(Arrays.asList(SET_VALUES)); private boolean sideboard = false; private boolean switchSideboardByEmptyLine = true; // all cards after first empty line will be sideboard (like mtgo format) - private int nonEmptyLinesTotal = 0; + private boolean wasCardLines = false; public TxtDeckImporter(boolean haveSideboardSection) { if (haveSideboardSection) { @@ -56,19 +55,17 @@ public class TxtDeckImporter extends DeckImporter { } // switch sideboard by empty line - if (switchSideboardByEmptyLine && line.isEmpty() && nonEmptyLinesTotal > 0) { + if (switchSideboardByEmptyLine && line.isEmpty() && wasCardLines) { if (!sideboard) { sideboard = true; } else { - sbMessage.append("Found empty line at ").append(lineCount).append(", but sideboard already used. Use //sideboard switcher OR one empty line to devide your cards.").append('\n'); + sbMessage.append("Found empty line at ").append(lineCount).append(", but sideboard already used. Use //sideboard switcher OR use only one empty line to devide your cards.").append('\n'); } // skip empty line return; } - nonEmptyLinesTotal++; - // single line sideboard card from deckstats.net // SB: 3 Carnage Tyrant boolean singleLineSideBoard = false; @@ -82,8 +79,36 @@ public class TxtDeckImporter extends DeckImporter { if (delim < 0) { return; } + String lineNum = line.substring(0, delim).trim(); - String lineName = line.substring(delim).replace("'", "\'").trim(); + if (IGNORE_NAMES.contains(lineNum)) { + return; + } + + // amount + int cardAmount = 0; + boolean haveCardAmout; + try { + cardAmount = Integer.parseInt(lineNum.replaceAll("\\D+", "")); + if ((cardAmount <= 0) || (cardAmount >= 100)) { + sbMessage.append("Invalid number (too small or too big): ").append(lineNum).append(" at line ").append(lineCount).append('\n'); + return; + } + haveCardAmout = true; + } catch (NumberFormatException nfe) { + haveCardAmout = false; + //sbMessage.append("Invalid number: ").append(lineNum).append(" at line ").append(lineCount).append('\n'); + //return; + } + + String lineName; + if (haveCardAmout) { + lineName = line.substring(delim).trim(); + } else { + lineName = line.trim(); + cardAmount = 1; + } + lineName = lineName .replace("&", "//") .replace("Æ", "Ae") @@ -97,33 +122,25 @@ public class TxtDeckImporter extends DeckImporter { if (lineName.contains("//") && !lineName.contains(" // ")) { lineName = lineName.replace("//", " // "); } - if (lineName.contains(" / ")) { - lineName = lineName.replace(" / ", " // "); - } - if (IGNORE_NAMES.contains(lineName) || IGNORE_NAMES.contains(lineNum)) { + lineName = lineName.replaceFirst("(?<=[^/])\\s*/\\s*(?=[^/])", " // "); + + if (IGNORE_NAMES.contains(lineName)) { return; } - try { - int num = Integer.parseInt(lineNum.replaceAll("\\D+", "")); - if ((num < 0) || (num > 100)) { - sbMessage.append("Invalid number (too small or too big): ").append(lineNum).append(" at line ").append(lineCount).append('\n'); - return; - } - CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true); - if (cardInfo == null) { - sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n'); - } else { - for (int i = 0; i < num; i++) { - if (!sideboard && !singleLineSideBoard) { - deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); - } else { - deckList.getSideboard().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); - } + wasCardLines = true; + + CardInfo cardInfo = CardRepository.instance.findPreferedCoreExpansionCard(lineName, true); + if (cardInfo == null) { + sbMessage.append("Could not find card: '").append(lineName).append("' at line ").append(lineCount).append('\n'); + } else { + for (int i = 0; i < cardAmount; i++) { + if (!sideboard && !singleLineSideBoard) { + deckList.getCards().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); + } else { + deckList.getSideboard().add(new DeckCardInfo(cardInfo.getName(), cardInfo.getCardNumber(), cardInfo.getSetCode())); } } - } catch (NumberFormatException nfe) { - sbMessage.append("Invalid number: ").append(lineNum).append(" at line ").append(lineCount).append('\n'); } } } diff --git a/Mage/src/main/java/mage/cards/decks/importer/XmlDeckImporter.java b/Mage/src/main/java/mage/cards/decks/importer/XmlDeckImporter.java new file mode 100644 index 0000000000..8a88799656 --- /dev/null +++ b/Mage/src/main/java/mage/cards/decks/importer/XmlDeckImporter.java @@ -0,0 +1,52 @@ +package mage.cards.decks.importer; + +import static javax.xml.xpath.XPathConstants.NODESET; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +public abstract class XmlDeckImporter extends DeckImporter { + + private XPathFactory xpathFactory = XPathFactory.newInstance(); + private DocumentBuilder builder = getDocumentBuilder(); + + protected List getNodes(Document doc, String xpathExpression) throws XPathExpressionException { + NodeList nodes = (NodeList) xpathFactory.newXPath().evaluate(xpathExpression, doc, NODESET); + ArrayList list = new ArrayList<>(); + for (int i = 0; i < nodes.getLength(); i++) { + list.add(nodes.item(i)); + } + return list; + } + + private DocumentBuilder getDocumentBuilder() { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + return factory.newDocumentBuilder(); + } catch (ParserConfigurationException e) { + throw new RuntimeException(); + } + } + + protected Document getXmlDocument(String filename) throws IOException { + try { + return builder.parse(new File(filename)); + } catch (SAXException e) { + throw new IOException(e); + } + } + +} diff --git a/Mage/src/main/java/mage/cards/repository/CardCriteria.java b/Mage/src/main/java/mage/cards/repository/CardCriteria.java index 6e72fcde25..85882512b2 100644 --- a/Mage/src/main/java/mage/cards/repository/CardCriteria.java +++ b/Mage/src/main/java/mage/cards/repository/CardCriteria.java @@ -309,4 +309,97 @@ public class CardCriteria { qb.orderBy(sortBy, true); } } + + public String getName() { + return name; + } + + public String getNameExact() { + return nameExact; + } + + public String getRules() { + return rules; + } + + public List getSetCodes() { + return setCodes; + } + + public List getTypes() { + return types; + } + + public List getNotTypes() { + return notTypes; + } + + public List getSupertypes() { + return supertypes; + } + + public List getNotSupertypes() { + return notSupertypes; + } + + public List getSubtypes() { + return subtypes; + } + + public List getRarities() { + return rarities; + } + + public Boolean getDoubleFaced() { + return doubleFaced; + } + + public boolean isBlack() { + return black; + } + + public boolean isBlue() { + return blue; + } + + public boolean isGreen() { + return green; + } + + public boolean isRed() { + return red; + } + + public boolean isWhite() { + return white; + } + + public boolean isColorless() { + return colorless; + } + + public Integer getConvertedManaCost() { + return convertedManaCost; + } + + public String getSortBy() { + return sortBy; + } + + public Long getStart() { + return start; + } + + public Long getCount() { + return count; + } + + public int getMinCardNumber() { + return minCardNumber; + } + + public int getMaxCardNumber() { + return maxCardNumber; + } + } diff --git a/Mage/src/main/java/mage/cards/repository/CardInfo.java b/Mage/src/main/java/mage/cards/repository/CardInfo.java index 2563d4e307..e33bafe158 100644 --- a/Mage/src/main/java/mage/cards/repository/CardInfo.java +++ b/Mage/src/main/java/mage/cards/repository/CardInfo.java @@ -301,7 +301,7 @@ public class CardInfo { return sl; } for (String s : subtypes.split(SEPARATOR)) { - sl.add(s); + sl.add(SubType.fromString(s)); } return sl; } diff --git a/Mage/src/main/java/mage/cards/repository/CardRepository.java b/Mage/src/main/java/mage/cards/repository/CardRepository.java index 229b6351a2..e54d6e4812 100644 --- a/Mage/src/main/java/mage/cards/repository/CardRepository.java +++ b/Mage/src/main/java/mage/cards/repository/CardRepository.java @@ -10,31 +10,35 @@ import com.j256.ormlite.stmt.Where; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.DatabaseConnection; import com.j256.ormlite.table.TableUtils; -import java.io.File; -import java.sql.SQLException; -import java.util.*; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.SetType; import mage.constants.SuperType; +import mage.game.events.Listener; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.File; +import java.sql.SQLException; +import java.util.*; + /** - * @author North + * @author North, JayDi85 */ public enum CardRepository { instance; + private static final Logger logger = Logger.getLogger(CardRepository.class); + private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE"; private static final String VERSION_ENTITY_NAME = "card"; // raise this if db structure was changed private static final long CARD_DB_VERSION = 51; // raise this if new cards were added to the server - private static final long CARD_CONTENT_VERSION = 122; + private static final long CARD_CONTENT_VERSION = 222; private Dao cardDao; private Set classNames; + private RepositoryEventSource eventSource = new RepositoryEventSource(); CardRepository() { File file = new File("db"); @@ -43,35 +47,54 @@ public enum CardRepository { } try { ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); - boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, CARD_DB_VERSION); - if (obsolete) { + boolean isObsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, CARD_DB_VERSION); + boolean isNewBuild = RepositoryUtil.isNewBuildRun(connectionSource, VERSION_ENTITY_NAME, CardRepository.class); // recreate db on new build + if (isObsolete || isNewBuild) { + //System.out.println("Local cards db is outdated, cleaning..."); TableUtils.dropTable(connectionSource, CardInfo.class, true); } TableUtils.createTableIfNotExists(connectionSource, CardInfo.class); cardDao = DaoManager.createDao(connectionSource, CardInfo.class); + + eventSource.fireRepositoryDbLoaded(); } catch (SQLException ex) { Logger.getLogger(CardRepository.class).error("Error creating card repository - ", ex); } } - public void addCards(final List cards) { + public void subscribe(Listener listener) { + eventSource.addListener(listener); + } + + public void saveCards(final List newCards, long newContentVersion) { try { cardDao.callBatchTasks(() -> { - try { - for (CardInfo card : cards) { - cardDao.create(card); - if (classNames != null) { - classNames.add(card.getClassName()); + // add + if (newCards != null && !newCards.isEmpty()) { + logger.info("DB: need to add " + newCards.size() + " new cards"); + try { + for (CardInfo card : newCards) { + cardDao.create(card); + if (classNames != null) { + classNames.add(card.getClassName()); + } } + } catch (SQLException ex) { + Logger.getLogger(CardRepository.class).error("Error adding cards to DB - ", ex); } - } catch (SQLException ex) { - Logger.getLogger(CardRepository.class).error("Error adding cards to DB - ", ex); } + + // no card updates + return null; }); + + setContentVersion(newContentVersion); + eventSource.fireRepositoryDbUpdated(); } catch (Exception ex) { + // } } @@ -305,7 +328,9 @@ public enum CardRepository { public CardInfo findCard(String setCode, String cardNumber) { try { QueryBuilder queryBuilder = cardDao.queryBuilder(); - queryBuilder.limit(1L).where().eq("setCode", new SelectArg(setCode)).and().eq("cardNumber", cardNumber).and().eq("nightCard", false); + queryBuilder.limit(1L).where().eq("setCode", new SelectArg(setCode)) + .and().eq("cardNumber", new SelectArg(cardNumber)) + .and().eq("nightCard", new SelectArg(false)); List result = cardDao.query(queryBuilder.prepare()); if (!result.isEmpty()) { return result.get(0); @@ -381,8 +406,7 @@ public enum CardRepository { return cardinfo; } - if ((set.getType() == SetType.EXPANSION || set.getType() == SetType.CORE) - && (lastExpansionDate == null || set.getReleaseDate().after(lastExpansionDate))) { + if (set.getType().isStandardLegal() && (lastExpansionDate == null || set.getReleaseDate().after(lastExpansionDate))) { cardToUse = cardinfo; lastExpansionDate = set.getReleaseDate(); } @@ -480,12 +504,10 @@ public enum CardRepository { public void closeDB() { try { if (cardDao != null && cardDao.getConnectionSource() != null) { - DatabaseConnection conn = cardDao.getConnectionSource().getReadWriteConnection(); + DatabaseConnection conn = cardDao.getConnectionSource().getReadWriteConnection(cardDao.getTableName()); conn.executeStatement("shutdown compact", 0); } - } catch (SQLException ex) { - } } diff --git a/Mage/src/main/java/mage/cards/repository/CardScanner.java b/Mage/src/main/java/mage/cards/repository/CardScanner.java index c098a939a5..6660c6da84 100644 --- a/Mage/src/main/java/mage/cards/repository/CardScanner.java +++ b/Mage/src/main/java/mage/cards/repository/CardScanner.java @@ -1,13 +1,13 @@ - package mage.cards.repository; -import java.util.ArrayList; -import java.util.List; import mage.cards.*; import org.apache.log4j.Logger; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + /** - * * @author North */ public final class CardScanner { @@ -27,14 +27,15 @@ public final class CardScanner { scanned = true; List cardsToAdd = new ArrayList<>(); - int setsUpdatedCount = 0; - int setsAddedCount = 0; + List setsToAdd = new ArrayList<>(); + List setsToUpdate = new ArrayList<>(); + // check sets for (ExpansionSet set : Sets.getInstance().values()) { ExpansionInfo expansionInfo = ExpansionRepository.instance.getSetByCode(set.getCode()); if (expansionInfo == null) { - setsAddedCount += 1; - ExpansionRepository.instance.add(new ExpansionInfo(set)); + // need add + setsToAdd.add(new ExpansionInfo(set)); } else if (!expansionInfo.name.equals(set.getName()) || !expansionInfo.code.equals(set.getCode()) || (expansionInfo.blockName == null ? set.getBlockName() != null : !expansionInfo.blockName.equals(set.getBlockName())) @@ -42,22 +43,17 @@ public final class CardScanner { || expansionInfo.type != set.getSetType() || expansionInfo.boosters != set.hasBoosters() || expansionInfo.basicLands != set.hasBasicLands()) { - setsUpdatedCount += 1; - ExpansionRepository.instance.update(expansionInfo); + // need update + setsToUpdate.add(expansionInfo); } } - ExpansionRepository.instance.setContentVersion(ExpansionRepository.instance.getContentVersionConstant()); - - if (setsAddedCount > 0) { - logger.info("DB: need to add " + setsUpdatedCount + " new sets"); - } - if (setsUpdatedCount > 0) { - logger.info("DB: need to update " + setsUpdatedCount + " sets"); - } + ExpansionRepository.instance.saveSets(setsToAdd, setsToUpdate, ExpansionRepository.instance.getContentVersionConstant()); + // check cards (only add mode, without updates) for (ExpansionSet set : Sets.getInstance().values()) { for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { if (CardRepository.instance.findCard(set.getCode(), setInfo.getCardNumber()) == null) { + // need add Card card = CardImpl.createCard( setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()), @@ -73,11 +69,25 @@ public final class CardScanner { } } } + CardRepository.instance.saveCards(cardsToAdd, CardRepository.instance.getContentVersionConstant()); + } - if (!cardsToAdd.isEmpty()) { - logger.info("DB: need to add " + cardsToAdd.size() + " new cards"); - CardRepository.instance.addCards(cardsToAdd); + public static List getAllCards() { + return getAllCards(true); + } + + public static List getAllCards(boolean ignoreCustomSets) { + Collection sets = Sets.getInstance().values(); + List cards = new ArrayList<>(); + for (ExpansionSet set : sets) { + if (ignoreCustomSets && set.getSetType().isCustomSet()) { + continue; + } + for (ExpansionSet.SetCardInfo setInfo : set.getSetCardInfo()) { + cards.add(CardImpl.createCard(setInfo.getCardClass(), new CardSetInfo(setInfo.getName(), set.getCode(), + setInfo.getCardNumber(), setInfo.getRarity(), setInfo.getGraphicInfo()))); + } } - CardRepository.instance.setContentVersion(CardRepository.instance.getContentVersionConstant()); + return cards; } } diff --git a/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java b/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java new file mode 100644 index 0000000000..9914b5246f --- /dev/null +++ b/Mage/src/main/java/mage/cards/repository/DatabaseBuild.java @@ -0,0 +1,33 @@ +package mage.cards.repository; + +import com.j256.ormlite.field.DatabaseField; +import com.j256.ormlite.table.DatabaseTable; + +/** + * @author JayDi85 + */ +@DatabaseTable(tableName = "build") +public class DatabaseBuild { + + @DatabaseField + protected String entity; + + @DatabaseField(columnName = "last_build") + protected String lastBuild; + + public String getEntity() { + return entity; + } + + public void setEntity(String entity) { + this.entity = entity; + } + + public String getLastBuild() { + return lastBuild; + } + + public void setLastBuild(String lastBuild) { + this.lastBuild = lastBuild; + } +} diff --git a/Mage/src/main/java/mage/cards/repository/ExpansionInfo.java b/Mage/src/main/java/mage/cards/repository/ExpansionInfo.java index 572e5ef3d1..8b17210ea5 100644 --- a/Mage/src/main/java/mage/cards/repository/ExpansionInfo.java +++ b/Mage/src/main/java/mage/cards/repository/ExpansionInfo.java @@ -3,12 +3,12 @@ package mage.cards.repository; import com.j256.ormlite.field.DataType; import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.table.DatabaseTable; -import java.util.Date; import mage.cards.ExpansionSet; import mage.constants.SetType; +import java.util.Date; + /** - * * @author North */ @DatabaseTable(tableName = "expansion") @@ -16,11 +16,11 @@ public class ExpansionInfo { @DatabaseField(unique = true) protected String name; - @DatabaseField(id = true,unique = true) + @DatabaseField(id = true, unique = true) protected String code; @DatabaseField protected String blockName; - @DatabaseField + @DatabaseField(dataType = DataType.DATE_STRING, format = "yyyy-MM-dd HH:mm:ss") protected Date releaseDate; @DatabaseField(dataType = DataType.ENUM_STRING) protected SetType type; @@ -74,5 +74,4 @@ public class ExpansionInfo { public String toString() { return name; } - } diff --git a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java index 4ed44d2966..6370e4cbfc 100644 --- a/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java +++ b/Mage/src/main/java/mage/cards/repository/ExpansionRepository.java @@ -8,17 +8,18 @@ import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; +import mage.game.events.Listener; +import org.apache.log4j.Logger; + import java.io.File; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import org.apache.log4j.Logger; /** - * - * @author North + * @author North, JayDi85 */ public enum ExpansionRepository { @@ -29,9 +30,11 @@ public enum ExpansionRepository { private static final String JDBC_URL = "jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE"; private static final String VERSION_ENTITY_NAME = "expansion"; private static final long EXPANSION_DB_VERSION = 5; - private static final long EXPANSION_CONTENT_VERSION = 17; + private static final long EXPANSION_CONTENT_VERSION = 18; private Dao expansionDao; + private RepositoryEventSource eventSource = new RepositoryEventSource(); + public boolean instanceInitialized = false; ExpansionRepository() { File file = new File("db"); @@ -40,32 +43,63 @@ public enum ExpansionRepository { } try { ConnectionSource connectionSource = new JdbcConnectionSource(JDBC_URL); - boolean obsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, EXPANSION_DB_VERSION); - if (obsolete) { + boolean isObsolete = RepositoryUtil.isDatabaseObsolete(connectionSource, VERSION_ENTITY_NAME, EXPANSION_DB_VERSION); + boolean isNewBuild = RepositoryUtil.isNewBuildRun(connectionSource, VERSION_ENTITY_NAME, ExpansionRepository.class); // recreate db on new build + if (isObsolete || isNewBuild) { + //System.out.println("Local sets db is outdated, cleaning..."); TableUtils.dropTable(connectionSource, ExpansionInfo.class, true); } TableUtils.createTableIfNotExists(connectionSource, ExpansionInfo.class); expansionDao = DaoManager.createDao(connectionSource, ExpansionInfo.class); + instanceInitialized = true; + + eventSource.fireRepositoryDbLoaded(); } catch (SQLException ex) { ex.printStackTrace(); } + } - public void add(ExpansionInfo expansion) { - try { - expansionDao.create(expansion); - } catch (SQLException ex) { - logger.error(ex); - } + public void subscribe(Listener listener) { + eventSource.addListener(listener); } - public void update(ExpansionInfo expansion) { + public void saveSets(final List newSets, final List updatedSets, long newContentVersion) { try { - expansionDao.update(expansion); - } catch (SQLException ex) { - logger.error(ex); + expansionDao.callBatchTasks(() -> { + // add + if (newSets != null && !newSets.isEmpty()) { + logger.info("DB: need to add " + newSets.size() + " new sets"); + try { + for (ExpansionInfo exp : newSets) { + expansionDao.create(exp); + } + } catch (SQLException ex) { + Logger.getLogger(CardRepository.class).error("Error adding expansions to DB - ", ex); + } + } + + // update + if (updatedSets != null && !updatedSets.isEmpty()) { + logger.info("DB: need to update " + updatedSets.size() + " sets"); + try { + for (ExpansionInfo exp : updatedSets) { + expansionDao.update(exp); + } + } catch (SQLException ex) { + Logger.getLogger(CardRepository.class).error("Error adding expansions to DB - ", ex); + } + } + + return null; + }); + + setContentVersion(newContentVersion); + eventSource.fireRepositoryDbUpdated(); + } catch (Exception ex) { + // } } @@ -89,9 +123,9 @@ public enum ExpansionRepository { // only with boosters and cards GenericRawResults setsList = expansionDao.queryRaw( "select * from expansion e " - + " where e.boosters = 1 " - + " and exists(select (1) from card c where c.setcode = e.code) " - + " order by e.releasedate desc", + + " where e.boosters = 1 " + + " and exists(select (1) from card c where c.setcode = e.code) " + + " order by e.releasedate desc", expansionDao.getRawRowMapper()); List resList = new ArrayList<>(); diff --git a/Mage/src/main/java/mage/cards/repository/RepositoryEvent.java b/Mage/src/main/java/mage/cards/repository/RepositoryEvent.java new file mode 100644 index 0000000000..2056f74719 --- /dev/null +++ b/Mage/src/main/java/mage/cards/repository/RepositoryEvent.java @@ -0,0 +1,27 @@ +package mage.cards.repository; + +import mage.game.events.ExternalEvent; + +import java.io.Serializable; +import java.util.EventObject; + +/** + * @author JayDi85 + */ +public class RepositoryEvent extends EventObject implements ExternalEvent, Serializable { + + public enum RepositoryEventType { + DB_LOADED, DB_UPDATED + } + + private RepositoryEventType eventType; + + public RepositoryEvent(RepositoryEventType eventType) { + super(eventType); + this.eventType = eventType; + } + + public RepositoryEventType getEventType() { + return eventType; + } +} diff --git a/Mage/src/main/java/mage/cards/repository/RepositoryEventSource.java b/Mage/src/main/java/mage/cards/repository/RepositoryEventSource.java new file mode 100644 index 0000000000..33dda83d60 --- /dev/null +++ b/Mage/src/main/java/mage/cards/repository/RepositoryEventSource.java @@ -0,0 +1,34 @@ +package mage.cards.repository; + +import mage.game.events.EventDispatcher; +import mage.game.events.EventSource; +import mage.game.events.Listener; + +import java.io.Serializable; + +/** + * @author JayDi85 + */ +public class RepositoryEventSource implements EventSource, Serializable { + + protected final EventDispatcher dispatcher = new EventDispatcher() { + }; + + @Override + public void addListener(Listener listener) { + dispatcher.addListener(listener); + } + + @Override + public void removeAllListener() { + dispatcher.removeAllListener(); + } + + public void fireRepositoryDbLoaded() { + dispatcher.fireEvent(new RepositoryEvent(RepositoryEvent.RepositoryEventType.DB_LOADED)); + } + + public void fireRepositoryDbUpdated() { + dispatcher.fireEvent(new RepositoryEvent(RepositoryEvent.RepositoryEventType.DB_UPDATED)); + } +} diff --git a/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java b/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java index 15f4921f59..07086fa0f4 100644 --- a/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java +++ b/Mage/src/main/java/mage/cards/repository/RepositoryUtil.java @@ -7,21 +7,34 @@ import com.j256.ormlite.stmt.QueryBuilder; import com.j256.ormlite.stmt.SelectArg; import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.table.TableUtils; +import mage.util.JarVersion; +import org.apache.log4j.Logger; + import java.sql.SQLException; import java.util.List; /** - * - * @author North + * @author North, JayDi85 */ public final class RepositoryUtil { + private static final Logger logger = Logger.getLogger(RepositoryUtil.class); + public static final boolean CARD_DB_RECREATE_BY_CLIENT_SIDE = true; // re-creates db from client (best performance) or downloads from server on connects (can be slow) + + public static void bootstrapLocalDb() { + // call local db to init all sets and cards repository (need for correct updates cycle, not on random request) + logger.info("Loading database..."); + ExpansionRepository.instance.getContentVersionConstant(); + CardRepository.instance.getContentVersionConstant(); + } + public static boolean isDatabaseObsolete(ConnectionSource connectionSource, String entityName, long version) throws SQLException { TableUtils.createTableIfNotExists(connectionSource, DatabaseVersion.class); Dao dbVersionDao = DaoManager.createDao(connectionSource, DatabaseVersion.class); QueryBuilder queryBuilder = dbVersionDao.queryBuilder(); - queryBuilder.where().eq("entity", new SelectArg(entityName)).and().eq("version", version); + queryBuilder.where().eq("entity", new SelectArg(entityName)) + .and().eq("version", new SelectArg(version)); List dbVersions = dbVersionDao.query(queryBuilder.prepare()); if (dbVersions.isEmpty()) { @@ -33,6 +46,31 @@ public final class RepositoryUtil { return dbVersions.isEmpty(); } + public static boolean isNewBuildRun(ConnectionSource connectionSource, String entityName, Class clazz) throws SQLException { + // build time checks only for releases, not runtime (e.g. IDE debug) + // that's check uses for cards db cleanup on new version/build + String currentBuild = JarVersion.getBuildTime(clazz); + if (!JarVersion.isBuildTimeOk(currentBuild)) { + return false; + } + + TableUtils.createTableIfNotExists(connectionSource, DatabaseBuild.class); + Dao dbBuildDao = DaoManager.createDao(connectionSource, DatabaseBuild.class); + + QueryBuilder queryBuilder = dbBuildDao.queryBuilder(); + queryBuilder.where().eq("entity", new SelectArg(entityName)) + .and().eq("last_build", new SelectArg(currentBuild)); + List dbBuilds = dbBuildDao.query(queryBuilder.prepare()); + + if (dbBuilds.isEmpty()) { + DatabaseBuild dbBuild = new DatabaseBuild(); + dbBuild.setEntity(entityName); + dbBuild.setLastBuild(currentBuild); + dbBuildDao.create(dbBuild); + } + return dbBuilds.isEmpty(); + } + public static void updateVersion(ConnectionSource connectionSource, String entityName, long version) throws SQLException { TableUtils.createTableIfNotExists(connectionSource, DatabaseVersion.class); Dao dbVersionDao = DaoManager.createDao(connectionSource, DatabaseVersion.class); @@ -66,4 +104,9 @@ public final class RepositoryUtil { } } + public static boolean isDatabaseEmpty() { + return ExpansionRepository.instance.getSetByCode("GRN") == null + || CardRepository.instance.findCard("Island") == null; + } + } diff --git a/Mage/src/main/java/mage/choices/ChoiceColor.java b/Mage/src/main/java/mage/choices/ChoiceColor.java index 9847e9fd51..6673b4e804 100644 --- a/Mage/src/main/java/mage/choices/ChoiceColor.java +++ b/Mage/src/main/java/mage/choices/ChoiceColor.java @@ -1,4 +1,3 @@ - package mage.choices; import mage.MageObject; @@ -8,14 +7,13 @@ import mage.ObjectColor; import java.util.ArrayList; /** - * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class ChoiceColor extends ChoiceImpl { - private static final ArrayList colorChoices = getBaseColors(); + private static final ArrayList colorChoices = getBaseColors(); - public static ArrayList getBaseColors(){ + public static ArrayList getBaseColors() { ArrayList arr = new ArrayList<>(); arr.add("Green"); arr.add("Blue"); @@ -33,15 +31,15 @@ public class ChoiceColor extends ChoiceImpl { this(required, "Choose color"); } - public ChoiceColor(boolean required, String chooseMessage){ + public ChoiceColor(boolean required, String chooseMessage) { this(required, chooseMessage, ""); } - public ChoiceColor(boolean required, String chooseMessage, MageObject source){ + public ChoiceColor(boolean required, String chooseMessage, MageObject source) { this(required, chooseMessage, source.getIdName()); } - public ChoiceColor(boolean required, String chooseMessage, String chooseSubMessage){ + public ChoiceColor(boolean required, String chooseMessage, String chooseSubMessage) { super(required); this.choices.addAll(colorChoices); @@ -59,6 +57,10 @@ public class ChoiceColor extends ChoiceImpl { return new ChoiceColor(this); } + public void removeColorFromChoices(String colorName) { + this.choices.remove(colorName); + } + public ObjectColor getColor() { if (choice == null) { return null; diff --git a/Mage/src/main/java/mage/choices/ChoiceCreatureType.java b/Mage/src/main/java/mage/choices/ChoiceCreatureType.java index 7ffbab8829..c17b5ac9e4 100644 --- a/Mage/src/main/java/mage/choices/ChoiceCreatureType.java +++ b/Mage/src/main/java/mage/choices/ChoiceCreatureType.java @@ -22,11 +22,11 @@ public class ChoiceCreatureType extends ChoiceImpl { this(true, chooseMessage, source); } - public ChoiceCreatureType(boolean required, String chooseMessage, MageObject source){ + public ChoiceCreatureType(boolean required, String chooseMessage, MageObject source) { super(required); - this.setChoices(SubType.getCreatureTypes(false).stream().map(SubType::toString).collect(Collectors.toCollection(LinkedHashSet::new))); + this.setChoices(SubType.getCreatureTypes().stream().map(SubType::toString).collect(Collectors.toCollection(LinkedHashSet::new))); this.setMessage(chooseMessage); - if(source != null) { + if (source != null) { this.setSubMessage(source.getIdName()); } this.setSearchEnabled(true); diff --git a/Mage/src/main/java/mage/choices/ChoiceImpl.java b/Mage/src/main/java/mage/choices/ChoiceImpl.java index 0c8718f290..66ea9d37c1 100644 --- a/Mage/src/main/java/mage/choices/ChoiceImpl.java +++ b/Mage/src/main/java/mage/choices/ChoiceImpl.java @@ -1,12 +1,11 @@ - - package mage.choices; +import mage.util.RandomUtil; + import java.io.Serializable; import java.util.*; /** - * * @author BetaSteward_at_googlemail.com, JayDi85 */ public class ChoiceImpl implements Choice, Serializable { @@ -22,7 +21,6 @@ public class ChoiceImpl implements Choice, Serializable { protected String subMessage; protected boolean searchEnabled = true; // enable for all windows by default protected String searchText; - private static Random rnd = new Random(); public ChoiceImpl() { this(false); @@ -69,10 +67,14 @@ public class ChoiceImpl implements Choice, Serializable { } @Override - public String getSubMessage(){ return subMessage; } + public String getSubMessage() { + return subMessage; + } @Override - public void setSubMessage(String subMessage){ this.subMessage = subMessage; } + public void setSubMessage(String subMessage) { + this.subMessage = subMessage; + } @Override public Set getChoices() { @@ -124,9 +126,9 @@ public class ChoiceImpl implements Choice, Serializable { @Override public String getChoiceValue() { - if ((keyChoices != null) && (keyChoices.containsKey(choiceKey))){ + if ((keyChoices != null) && (keyChoices.containsKey(choiceKey))) { return keyChoices.get(choiceKey); - }else{ + } else { return null; } } @@ -147,67 +149,67 @@ public class ChoiceImpl implements Choice, Serializable { } @Override - public boolean isSearchEnabled(){ + public boolean isSearchEnabled() { return this.searchEnabled; - }; + } @Override - public void setSearchEnabled(boolean isEnabled){ + public void setSearchEnabled(boolean isEnabled) { this.searchEnabled = isEnabled; - }; + } @Override - public void setSearchText(String searchText){ + public void setSearchText(String searchText) { this.searchText = searchText; - }; + } @Override - public String getSearchText(){ + public String getSearchText() { return this.searchText; - }; + } @Override - public boolean isSortEnabled(){ + public boolean isSortEnabled() { return (this.sortData != null) && !this.sortData.isEmpty(); - }; + } @Override - public void setSortData(Map sortData){ + public void setSortData(Map sortData) { this.sortData = sortData; - }; + } @Override - public Map getSortData(){ + public Map getSortData() { return this.sortData; - }; + } @Override public void setRandomChoice() { - if(this.isKeyChoice()){ + if (this.isKeyChoice()) { // key mode String[] vals = this.getKeyChoices().keySet().toArray(new String[0]); - if(vals.length > 0) { - int choiceNum = rnd.nextInt(vals.length); + if (vals.length > 0) { + int choiceNum = RandomUtil.nextInt(vals.length); this.setChoiceByKey(vals[choiceNum]); } } else { // string mode String[] vals = this.getChoices().toArray(new String[0]); - if(vals.length > 0) { - int choiceNum = rnd.nextInt(vals.length); + if (vals.length > 0) { + int choiceNum = RandomUtil.nextInt(vals.length); this.setChoice(vals[choiceNum]); } } } @Override - public boolean setChoiceByAnswers(List answers, boolean removeSelectAnswerFromList){ + public boolean setChoiceByAnswers(List answers, boolean removeSelectAnswerFromList) { // select by answers - if(this.isKeyChoice()){ + if (this.isKeyChoice()) { // keys mode for (String needChoice : answers) { - for (Map.Entry currentChoice: this.getKeyChoices().entrySet()) { + for (Map.Entry currentChoice : this.getKeyChoices().entrySet()) { if (currentChoice.getKey().equals(needChoice)) { this.setChoiceByKey(needChoice); answers.remove(needChoice); diff --git a/Mage/src/main/java/mage/choices/ChoiceLandType.java b/Mage/src/main/java/mage/choices/ChoiceLandType.java index edb20740e7..12cca314a6 100644 --- a/Mage/src/main/java/mage/choices/ChoiceLandType.java +++ b/Mage/src/main/java/mage/choices/ChoiceLandType.java @@ -1,5 +1,3 @@ - - package mage.choices; import mage.constants.SubType; @@ -13,7 +11,7 @@ public class ChoiceLandType extends ChoiceImpl { public ChoiceLandType() { super(true); - this.setChoices(SubType.getLandTypes(false).stream().map(SubType::toString).collect(Collectors.toSet())); + this.setChoices(SubType.getLandTypes().stream().map(SubType::toString).collect(Collectors.toSet())); this.message = "Choose a land type"; } diff --git a/Mage/src/main/java/mage/constants/AbilityWord.java b/Mage/src/main/java/mage/constants/AbilityWord.java index 408e590c66..898cc8ea6c 100644 --- a/Mage/src/main/java/mage/constants/AbilityWord.java +++ b/Mage/src/main/java/mage/constants/AbilityWord.java @@ -7,6 +7,7 @@ package mage.constants; */ public enum AbilityWord { + ADDENDUM("Addendum"), BATTALION("Battalion"), BLOODRUSH("Bloodrush"), CHANNEL("Channel"), diff --git a/Mage/src/main/java/mage/constants/CardType.java b/Mage/src/main/java/mage/constants/CardType.java index d060f5aa04..54fb252ac5 100644 --- a/Mage/src/main/java/mage/constants/CardType.java +++ b/Mage/src/main/java/mage/constants/CardType.java @@ -31,6 +31,16 @@ public enum CardType { return text; } + public static CardType fromString(String value) { + for (CardType ct : CardType.values()) { + if (ct.toString().equals(value)) { + return ct; + } + } + + throw new IllegalArgumentException("Can't find card type enum value: " + value); + } + public boolean isPermanentType() { return permanentType; } diff --git a/Mage/src/main/java/mage/constants/Duration.java b/Mage/src/main/java/mage/constants/Duration.java index e23951b8e1..0ec5060ed0 100644 --- a/Mage/src/main/java/mage/constants/Duration.java +++ b/Mage/src/main/java/mage/constants/Duration.java @@ -1,7 +1,6 @@ package mage.constants; /** - * * @author North */ public enum Duration { @@ -12,6 +11,8 @@ public enum Duration { WhileInGraveyard("", false), EndOfTurn("until end of turn", true), UntilYourNextTurn("until your next turn", true), + UntilEndOfYourNextTurn("until the end of your next turn", true), + UntilSourceLeavesBattlefield("until {source} leaves the battlefield", true), // supported for continuous layered effects EndOfCombat("until end of combat", true), EndOfStep("until end of phase step", true), Custom("", true); diff --git a/Mage/src/main/java/mage/constants/EmptyNames.java b/Mage/src/main/java/mage/constants/EmptyNames.java new file mode 100644 index 0000000000..998e75714a --- /dev/null +++ b/Mage/src/main/java/mage/constants/EmptyNames.java @@ -0,0 +1,24 @@ +package mage.constants; + +/** + * + * @author JayDi85 + */ +public enum EmptyNames { + + // TODO: make names for that cards and enable Assert.assertNotEquals("", permanentName); for assertXXX tests + // TODO: replace all getName().equals to haveSameNames and haveEmptyName + FACE_DOWN_CREATURE(""), // "Face down creature" + FACE_DOWN_TOKEN(""); // "Face down token" + + private final String cardName; + + EmptyNames(String cardName) { + this.cardName = cardName; + } + + @Override + public String toString() { + return cardName; + } +} diff --git a/Mage/src/main/java/mage/constants/SetType.java b/Mage/src/main/java/mage/constants/SetType.java index ed23a233bb..c1d2922230 100644 --- a/Mage/src/main/java/mage/constants/SetType.java +++ b/Mage/src/main/java/mage/constants/SetType.java @@ -1,7 +1,6 @@ package mage.constants; /** - * * @author North */ public enum SetType { @@ -10,6 +9,7 @@ public enum SetType { MAGIC_ONLINE("Magic Online"), SUPPLEMENTAL("Supplemental"), SUPPLEMENTAL_STANDARD_LEGAL("Standard Legal Supplemental"), + SUPPLEMENTAL_MODERN_LEGAL("Modern Legal Supplemental"), PROMOTIONAL("Promotional"), JOKESET("Joke Set"), CUSTOM_SET("Unofficial Set"); @@ -24,4 +24,27 @@ public enum SetType { public String toString() { return text; } + + public boolean isCustomSet() { + return this == SetType.CUSTOM_SET; + } + + public boolean isJokeSet() { + return this == SetType.JOKESET; + } + + public boolean isEternalLegal() { + // any official sets except un-sets + return this != SetType.CUSTOM_SET && this != SetType.JOKESET; + } + + public boolean isStandardLegal() { + // any official sets that was in standard + return this == SetType.CORE || this == SetType.EXPANSION || this == SetType.SUPPLEMENTAL_STANDARD_LEGAL; + } + + public boolean isModernLegal() { + // any official sets that was in modern (standard + Modern Horizons) + return this.isStandardLegal() || this == SetType.SUPPLEMENTAL_MODERN_LEGAL; + } } diff --git a/Mage/src/main/java/mage/constants/SubType.java b/Mage/src/main/java/mage/constants/SubType.java index 5f61eef8ec..00387a9761 100644 --- a/Mage/src/main/java/mage/constants/SubType.java +++ b/Mage/src/main/java/mage/constants/SubType.java @@ -53,6 +53,7 @@ public enum SubType { ARCHER("Archer", SubTypeSet.CreatureType), ARCHON("Archon", SubTypeSet.CreatureType), ARTIFICER("Artificer", SubTypeSet.CreatureType), + ARMY("Army", SubTypeSet.CreatureType), ARTIFICIER("Artificier", SubTypeSet.CreatureType, true), ASSASSIN("Assassin", SubTypeSet.CreatureType), ASSEMBLY_WORKER("Assembly-Worker", SubTypeSet.CreatureType), @@ -200,6 +201,7 @@ public enum SubType { KOR("Kor", SubTypeSet.CreatureType), KRAKEN("Kraken", SubTypeSet.CreatureType), // L + LADYOFPROPERETIQUETTE("Lady of Proper Etiquette", SubTypeSet.CreatureType, true), // Unglued LAMIA("Lamia", SubTypeSet.CreatureType), LAMMASU("Lammasu", SubTypeSet.CreatureType), LEECH("Leech", SubTypeSet.CreatureType), @@ -313,6 +315,7 @@ public enum SubType { SPIDER("Spider", SubTypeSet.CreatureType), SPIKE("Spike", SubTypeSet.CreatureType), SPIRIT("Spirit", SubTypeSet.CreatureType), + SPLINTER("Splinter", SubTypeSet.CreatureType), SPLITTER("Splitter", SubTypeSet.CreatureType), SPONGE("Sponge", SubTypeSet.CreatureType), SQUID("Squid", SubTypeSet.CreatureType), @@ -378,6 +381,7 @@ public enum SubType { CHANDRA("Chandra", SubTypeSet.PlaneswalkerType), DACK("Dack", SubTypeSet.PlaneswalkerType), DARETTI("Daretti", SubTypeSet.PlaneswalkerType), + DAVRIEL("Davriel", SubTypeSet.PlaneswalkerType), DOMRI("Domri", SubTypeSet.PlaneswalkerType), DOOKU("Dooku", SubTypeSet.PlaneswalkerType, true), // Star Wars DOVIN("Dovin", SubTypeSet.PlaneswalkerType), @@ -389,6 +393,7 @@ public enum SubType { HUATLI("Huatli", SubTypeSet.PlaneswalkerType), JACE("Jace", SubTypeSet.PlaneswalkerType), KARN("Karn", SubTypeSet.PlaneswalkerType), + KASMINA("Kasmina", SubTypeSet.PlaneswalkerType), KAYA("Kaya", SubTypeSet.PlaneswalkerType), KIORA("Kiora", SubTypeSet.PlaneswalkerType), KOTH("Koth", SubTypeSet.PlaneswalkerType), @@ -403,13 +408,16 @@ public enum SubType { SAHEELI("Saheeli", SubTypeSet.PlaneswalkerType), SAMUT("Samut", SubTypeSet.PlaneswalkerType), SARKHAN("Sarkhan", SubTypeSet.PlaneswalkerType), + SERRA("Serra", SubTypeSet.PlaneswalkerType), SIDIOUS("Sidious", SubTypeSet.PlaneswalkerType, true), // Star Wars SORIN("Sorin", SubTypeSet.PlaneswalkerType), TAMIYO("Tamiyo", SubTypeSet.PlaneswalkerType), TEFERI("Teferi", SubTypeSet.PlaneswalkerType), + TEYO("Teyo", SubTypeSet.PlaneswalkerType), TEZZERET("Tezzeret", SubTypeSet.PlaneswalkerType), TIBALT("Tibalt", SubTypeSet.PlaneswalkerType), UGIN("Ugin", SubTypeSet.PlaneswalkerType), + URZA("Urza", SubTypeSet.PlaneswalkerType, true), // Unstable VENSER("Venser", SubTypeSet.PlaneswalkerType), VIVIEN("Vivien", SubTypeSet.PlaneswalkerType), VRASKA("Vraska", SubTypeSet.PlaneswalkerType), @@ -469,48 +477,47 @@ public enum SubType { return subTypeSet; } - public static Set getArtifactTypes(boolean withCustomSets) { + public static Set getArtifactTypes() { Set subTypes = EnumSet.noneOf(SubType.class); for (SubType subType : values()) { - if (subType.getSubTypeSet() == SubTypeSet.ArtifactType && (withCustomSets || !subType.customSet)) { + if (subType.getSubTypeSet() == SubTypeSet.ArtifactType) { subTypes.add(subType); } } return subTypes; } - public static Set getPlaneswalkerTypes(boolean withCustomSets) { + public static Set getPlaneswalkerTypes() { Set subTypes = EnumSet.noneOf(SubType.class); for (SubType subType : values()) { - if (subType.getSubTypeSet() == SubTypeSet.PlaneswalkerType && (withCustomSets || !subType.customSet)) { + if (subType.getSubTypeSet() == SubTypeSet.PlaneswalkerType) { subTypes.add(subType); } } return subTypes; } - public static Set getCreatureTypes(boolean customSet) { + public static Set getCreatureTypes() { Set subTypes = EnumSet.noneOf(SubType.class); - for (SubType s : values()) { - if (s.customSet == customSet && s.getSubTypeSet() == SubTypeSet.CreatureType) { - subTypes.add(s); + for (SubType subType : values()) { + if (subType.getSubTypeSet() == SubTypeSet.CreatureType) { + subTypes.add(subType); } } return subTypes; } - public static Set getBasicLands(boolean customSet) { + public static Set getBasicLands() { return Arrays.stream(values()) .filter(p -> p.getSubTypeSet() == SubTypeSet.BasicLandType) - .filter(s -> s.customSet == customSet) .collect(Collectors.toSet()); } - public static SubTypeList getLandTypes(boolean customSet) { + public static SubTypeList getLandTypes() { SubTypeList landTypes = new SubTypeList(); - for (SubType s : values()) { - if (s.getSubTypeSet() == SubTypeSet.BasicLandType || s.getSubTypeSet() == SubTypeSet.NonBasicLandType) { - landTypes.add(s); + for (SubType subType : values()) { + if (subType.getSubTypeSet() == SubTypeSet.BasicLandType || subType.getSubTypeSet() == SubTypeSet.NonBasicLandType) { + landTypes.add(subType); } } return landTypes; diff --git a/Mage/src/main/java/mage/counters/CounterType.java b/Mage/src/main/java/mage/counters/CounterType.java index fd2eb77912..89ce5320cc 100644 --- a/Mage/src/main/java/mage/counters/CounterType.java +++ b/Mage/src/main/java/mage/counters/CounterType.java @@ -9,6 +9,7 @@ public enum CounterType { AGE("age"), AIM("aim"), + ARROW("arrow"), ARROWHEAD("arrowhead"), AWAKENING("awakening"), BLAZE("blaze"), @@ -51,6 +52,7 @@ public enum CounterType { FUSE("fuse"), GEM("gem"), GLOBE("globe"), + GLYPH("glyph"), GOLD("gold"), GROWTH("growth"), HATCHLING("hatchling"), @@ -73,12 +75,14 @@ public enum CounterType { LOYALTY("loyalty"), MANIFESTATION("manifestation"), MANNEQUIN("mannequin"), + MATRIX("matrix"), M1M1(new BoostCounter(-1, -1).name), M2M1(new BoostCounter(-2, -1).name), M2M2(new BoostCounter(-2, -2).name), MINE("mine"), MINING("mining"), MIRE("mire"), + MUSIC("music"), MUSTER("muster"), NET("net"), OMEN("omen"), @@ -90,15 +94,18 @@ public enum CounterType { P2P2(new BoostCounter(2, 2).name), PAGE("page"), PAIN("pain"), + PARALYZATION("paralyzation"), PETAL("petal"), PETRIFICATION("petrification"), PHYLACTERY("phylactery"), + PIN("pin"), PLAGUE("plague"), PLOT("plot"), POLYP("polyp"), POISON("poison"), PRESSURE("pressure"), PREY("prey"), + PUPA("pupa"), REPAIR("repair"), RUST("rust"), QUEST("quest"), @@ -107,6 +114,7 @@ public enum CounterType { SHELL("shell"), SHIELD("shield"), SHRED("shred"), + SLEEP("sleep"), SLIME("slime"), SLUMBER("slumber"), SOOT("soot"), @@ -126,6 +134,9 @@ public enum CounterType { VELOCITY("velocity"), VERSE("verse"), VITALITY("vitality"), + VORTEX("vortex"), + WAGE("wage"), + WINCH("winch"), WIND("wind"), WISH("wish"); diff --git a/Mage/src/main/java/mage/designations/CitysBlessing.java b/Mage/src/main/java/mage/designations/CitysBlessing.java index ca5aaa7476..9e803a6b67 100644 --- a/Mage/src/main/java/mage/designations/CitysBlessing.java +++ b/Mage/src/main/java/mage/designations/CitysBlessing.java @@ -1,8 +1,6 @@ - package mage.designations; /** - * * @author LevelX2 */ public class CitysBlessing extends Designation { @@ -10,4 +8,13 @@ public class CitysBlessing extends Designation { public CitysBlessing() { super(DesignationType.CITYS_BLESSING, "RIX"); } + + private CitysBlessing(final CitysBlessing card) { + super(card); + } + + @Override + public CitysBlessing copy() { + return new CitysBlessing(this); + } } diff --git a/Mage/src/main/java/mage/designations/Designation.java b/Mage/src/main/java/mage/designations/Designation.java index 44d7ba62ab..3554e68c50 100644 --- a/Mage/src/main/java/mage/designations/Designation.java +++ b/Mage/src/main/java/mage/designations/Designation.java @@ -1,14 +1,5 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.designations; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -28,14 +19,18 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class Designation implements MageObject { private static EnumSet emptySet = EnumSet.noneOf(CardType.class); - private static List emptyList = new ArrayList(); + private static List emptyList = new ArrayList<>(); private static ObjectColor emptyColor = new ObjectColor(); private static ManaCostsImpl emptyCost = new ManaCostsImpl(); @@ -43,6 +38,8 @@ public abstract class Designation implements MageObject { private DesignationType designationType; private UUID id; private FrameStyle frameStyle; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage; private final boolean unique; // can a designation be added multiple times (false) or only once to an object (true) @@ -65,6 +62,8 @@ public abstract class Designation implements MageObject { this.name = designation.name; this.designationType = designation.designationType; this.frameStyle = designation.frameStyle; + this.copy = designation.copy; + this.copyFrom = (designation.copyFrom != null ? designation.copyFrom.copy() : null); this.abilites = designation.abilites.copy(); this.unique = designation.unique; } @@ -78,6 +77,22 @@ public abstract class Designation implements MageObject { this.id = UUID.randomUUID(); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -198,20 +213,6 @@ public abstract class Designation implements MageObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - - @Override - public Designation copy() { - return this; - } - @Override public int getZoneChangeCounter(Game game) { return 1; // Emblems can't move zones until now so return always 1 @@ -232,7 +233,6 @@ public abstract class Designation implements MageObject { } /** - * * @param game * @param controllerId */ diff --git a/Mage/src/main/java/mage/designations/Monarch.java b/Mage/src/main/java/mage/designations/Monarch.java index 0281b3c459..d178838970 100644 --- a/Mage/src/main/java/mage/designations/Monarch.java +++ b/Mage/src/main/java/mage/designations/Monarch.java @@ -1,4 +1,3 @@ - package mage.designations; import mage.MageObject; @@ -15,7 +14,6 @@ import mage.game.permanent.Permanent; import mage.target.targetpointer.FixedTarget; /** - * * @author LevelX2 */ public class Monarch extends Designation { @@ -25,6 +23,15 @@ public class Monarch extends Designation { addAbility(new MonarchDrawTriggeredAbility()); addAbility(new MonarchDealsCombatDamageToAPlayerTriggeredAbility()); } + + private Monarch(final Monarch monarch) { + super(monarch); + } + + @Override + public Monarch copy() { + return new Monarch(this); + } } // At the beginning of the monarch's end step, that player draws a card diff --git a/Mage/src/main/java/mage/filter/Filter.java b/Mage/src/main/java/mage/filter/Filter.java index 7da73e2776..3f839a0f64 100644 --- a/Mage/src/main/java/mage/filter/Filter.java +++ b/Mage/src/main/java/mage/filter/Filter.java @@ -2,6 +2,7 @@ package mage.filter; import java.io.Serializable; +import java.util.List; import mage.filter.predicate.Predicate; import mage.game.Game; @@ -28,4 +29,5 @@ public interface Filter extends Serializable { Filter copy(); + List> getPredicates(); } diff --git a/Mage/src/main/java/mage/filter/FilterImpl.java b/Mage/src/main/java/mage/filter/FilterImpl.java index cf1c847b7b..192b574d92 100644 --- a/Mage/src/main/java/mage/filter/FilterImpl.java +++ b/Mage/src/main/java/mage/filter/FilterImpl.java @@ -75,4 +75,8 @@ public abstract class FilterImpl implements Filter { this.lockedFilter = lockedFilter; } + public List> getPredicates() { + return predicates; + } + } diff --git a/Mage/src/main/java/mage/filter/FilterPlayer.java b/Mage/src/main/java/mage/filter/FilterPlayer.java index 907dfb3434..8f085ddd67 100644 --- a/Mage/src/main/java/mage/filter/FilterPlayer.java +++ b/Mage/src/main/java/mage/filter/FilterPlayer.java @@ -44,12 +44,12 @@ public class FilterPlayer extends FilterImpl { return object instanceof Player; } - public boolean match(Player player, UUID sourceId, UUID playerId, Game game) { - if (!this.match(player, game)) { + public boolean match(Player checkPlayer, UUID sourceId, UUID sourceControllerId, Game game) { + if (!this.match(checkPlayer, game)) { return false; } - return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(player, sourceId, playerId), game); + return Predicates.and(extraPredicates).apply(new ObjectSourcePlayer(checkPlayer, sourceId, sourceControllerId), game); } @Override diff --git a/Mage/src/main/java/mage/filter/StaticFilters.java b/Mage/src/main/java/mage/filter/StaticFilters.java index 0fcf903c4c..dba8893667 100644 --- a/Mage/src/main/java/mage/filter/StaticFilters.java +++ b/Mage/src/main/java/mage/filter/StaticFilters.java @@ -23,7 +23,7 @@ import mage.filter.predicate.permanent.TokenPredicate; /** * A class that holds Filter objects that may not be modified without copying * before. This prevents the creation of thousands of filter objects. - * + *

    * Because the filters are used application wide they may not be modified. * NEVER!!!!! But it's possible, so be careful! * @@ -42,6 +42,7 @@ public final class StaticFilters { static { FILTER_ENCHANTMENT_PERMANENT.setLockedFilter(true); } + public static final FilterCard FILTER_CARD = new FilterCard("card"); static { @@ -84,6 +85,12 @@ public final class StaticFilters { FILTER_CARD_CREATURE_YOUR_GRAVEYARD.setLockedFilter(true); } + public static final FilterCreatureCard FILTER_CARD_CREATURES_YOUR_GRAVEYARD = new FilterCreatureCard("creature cards from your graveyard"); + + static { + FILTER_CARD_CREATURES_YOUR_GRAVEYARD.setLockedFilter(true); + } + public static final FilterCard FILTER_CARD_FROM_YOUR_GRAVEYARD = new FilterCard("card from your graveyard"); static { @@ -119,6 +126,7 @@ public final class StaticFilters { static { FILTER_CARD_NON_LAND.setLockedFilter(true); } + public static final FilterNonlandCard FILTER_CARD_A_NON_LAND = new FilterNonlandCard("a nonland card"); static { @@ -143,6 +151,12 @@ public final class StaticFilters { FILTER_PERMANENTS.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT = new FilterArtifactPermanent("artifact"); + + static { + FILTER_PERMANENT_ARTIFACT.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_AN = new FilterArtifactPermanent("an artifact"); static { @@ -154,11 +168,13 @@ public final class StaticFilters { static { FILTER_PERMANENT_ARTIFACT_OR_ENCHANTMENT.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_ARTIFACT_CREATURE_PERMANENT = new FilterArtifactCreaturePermanent(); static { FILTER_ARTIFACT_CREATURE_PERMANENT.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_OR_CREATURE = new FilterPermanent("artifact or creature"); static { @@ -168,6 +184,7 @@ public final class StaticFilters { )); FILTER_PERMANENT_ARTIFACT_OR_CREATURE.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT = new FilterPermanent("artifact, creature, or enchantment"); static { @@ -178,6 +195,7 @@ public final class StaticFilters { )); FILTER_PERMANENT_ARTIFACT_CREATURE_OR_ENCHANTMENT.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_ARTIFACT_CREATURE_ENCHANTMENT_OR_LAND = new FilterPermanent("artifact, creature, enchantment, or land"); static { @@ -195,16 +213,19 @@ public final class StaticFilters { static { FILTER_CONTROLLED_PERMANENT.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_ARTIFACT = new FilterControlledArtifactPermanent(); static { FILTER_CONTROLLED_PERMANENT_ARTIFACT.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN = new FilterControlledArtifactPermanent("an artifact"); static { FILTER_CONTROLLED_PERMANENT_ARTIFACT_AN.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE = new FilterControlledPermanent("artifact or creature you control"); static { @@ -214,6 +235,7 @@ public final class StaticFilters { )); FILTER_CONTROLLED_PERMANENT_ARTIFACT_OR_CREATURE.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_LAND = new FilterControlledLandPermanent(); static { @@ -232,12 +254,14 @@ public final class StaticFilters { FILTER_OPPONENTS_PERMANENT.add(new ControllerPredicate(TargetController.OPPONENT)); FILTER_OPPONENTS_PERMANENT.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_OPPONENTS_PERMANENT_CREATURE = new FilterCreaturePermanent("creature an opponent controls"); static { FILTER_OPPONENTS_PERMANENT_CREATURE.add(new ControllerPredicate(TargetController.OPPONENT)); FILTER_OPPONENTS_PERMANENT_CREATURE.setLockedFilter(true); } + public static final FilterPermanent FILTER_OPPONENTS_PERMANENT_ARTIFACT = new FilterPermanent("artifact an opponent controls"); static { @@ -245,6 +269,7 @@ public final class StaticFilters { FILTER_OPPONENTS_PERMANENT_ARTIFACT.add(new CardTypePredicate(CardType.ARTIFACT)); FILTER_OPPONENTS_PERMANENT_ARTIFACT.setLockedFilter(true); } + public static final FilterPermanent FILTER_OPPONENTS_PERMANENT_ARTIFACT_OR_CREATURE = new FilterPermanent("artifact or creature an opponent controls"); static { @@ -280,12 +305,14 @@ public final class StaticFilters { static { FILTER_CONTROLLED_A_CREATURE.setLockedFilter(true); } + public static final FilterControlledCreaturePermanent FILTER_CONTROLLED_ANOTHER_CREATURE = new FilterControlledCreaturePermanent("another creature"); static { - FILTER_CONTROLLED_ANOTHER_CREATURE.add(new AnotherPredicate()); + FILTER_CONTROLLED_ANOTHER_CREATURE.add(AnotherPredicate.instance); FILTER_CONTROLLED_ANOTHER_CREATURE.setLockedFilter(true); } + public static final FilterControlledPermanent FILTER_CONTROLLED_PERMANENT_NON_LAND = new FilterControlledPermanent("nonland permanent"); static { @@ -294,6 +321,7 @@ public final class StaticFilters { ); FILTER_CONTROLLED_PERMANENT_NON_LAND.setLockedFilter(true); } + public static final FilterLandPermanent FILTER_LAND = new FilterLandPermanent(); static { @@ -331,6 +359,12 @@ public final class StaticFilters { FILTER_PERMANENT_CREATURE.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_A = new FilterCreaturePermanent("a creature"); + + static { + FILTER_PERMANENT_CREATURE_A.setLockedFilter(true); + } + public static final FilterPermanent FILTER_PERMANENT_CREATURE_OR_PLANESWALKER_A = new FilterPermanent("a creature or planeswalker"); static { @@ -344,56 +378,70 @@ public final class StaticFilters { static { FILTER_PERMANENT_A_CREATURE.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_CONTROLLED = new FilterCreaturePermanent("creature you control"); static { FILTER_PERMANENT_CREATURE_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); FILTER_PERMANENT_CREATURE_CONTROLLED.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES = new FilterCreaturePermanent("creatures"); static { FILTER_PERMANENT_CREATURES.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURES_CONTROLLED = new FilterCreaturePermanent("creatures you control"); static { FILTER_PERMANENT_CREATURES_CONTROLLED.add(new ControllerPredicate(TargetController.YOU)); FILTER_PERMANENT_CREATURES_CONTROLLED.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_GOBLINS = new FilterCreaturePermanent(SubType.GOBLIN, "Goblin creatures"); static { FILTER_PERMANENT_CREATURE_GOBLINS.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_PERMANENT_CREATURE_SLIVERS = new FilterCreaturePermanent(SubType.SLIVER, "all Sliver creatures"); static { FILTER_PERMANENT_CREATURE_SLIVERS.setLockedFilter(true); } + public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKER = new FilterPlaneswalkerPermanent(); static { FILTER_PERMANENT_PLANESWALKER.setLockedFilter(true); } - public static final FilterPermanent FILTER_PERMANENT_NON_LAND = new FilterNonlandPermanent(); + public static final FilterPlaneswalkerPermanent FILTER_PERMANENT_PLANESWALKERS = new FilterPlaneswalkerPermanent("planeswalkers"); + + static { + FILTER_PERMANENT_PLANESWALKERS.setLockedFilter(true); + } + + public static final FilterNonlandPermanent FILTER_PERMANENT_NON_LAND = new FilterNonlandPermanent(); static { FILTER_PERMANENT_NON_LAND.setLockedFilter(true); } - public static final FilterPermanent FILTER_PERMANENTS_NON_LAND = new FilterNonlandPermanent("nonland permanents"); + public static final FilterNonlandPermanent FILTER_PERMANENTS_NON_LAND = new FilterNonlandPermanent("nonland permanents"); static { FILTER_PERMANENTS_NON_LAND.setLockedFilter(true); } + public static final FilterStackObject FILTER_SPELL_OR_ABILITY_OPPONENTS = new FilterStackObject("spell or ability and opponent controls"); static { FILTER_SPELL_OR_ABILITY_OPPONENTS.add(new ControllerPredicate(TargetController.OPPONENT)); FILTER_SPELL_OR_ABILITY_OPPONENTS.setLockedFilter(true); } + public static final FilterStackObject FILTER_SPELL_OR_ABILITY = new FilterStackObject(); static { @@ -405,17 +453,25 @@ public final class StaticFilters { static { FILTER_SPELL_A_CREATURE.setLockedFilter(true); } + public static final FilterCreatureSpell FILTER_SPELL_CREATURE = new FilterCreatureSpell("creature spell"); static { FILTER_SPELL_CREATURE.setLockedFilter(true); } + public static final FilterSpell FILTER_SPELL_NON_CREATURE = (FilterSpell) new FilterSpell("noncreature spell").add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); static { FILTER_SPELL_NON_CREATURE.setLockedFilter(true); } + public static final FilterSpell FILTER_SPELL_A_NON_CREATURE = (FilterSpell) new FilterSpell("a noncreature spell").add(Predicates.not(new CardTypePredicate(CardType.CREATURE))); + + static { + FILTER_SPELL_A_NON_CREATURE.setLockedFilter(true); + } + public static final FilterSpell FILTER_SPELL = new FilterSpell(); static { @@ -431,7 +487,7 @@ public final class StaticFilters { public static final FilterSpell FILTER_SPELL_A_MULTICOLORED = new FilterSpell("a multicolored spell"); static { - FILTER_SPELL_A_MULTICOLORED.add(new MulticoloredPredicate()); + FILTER_SPELL_A_MULTICOLORED.add(MulticoloredPredicate.instance); FILTER_SPELL_A_MULTICOLORED.setLockedFilter(true); } @@ -444,6 +500,7 @@ public final class StaticFilters { )); FILTER_SPELL_AN_INSTANT_OR_SORCERY.setLockedFilter(true); } + public static final FilterSpell FILTER_SPELL_INSTANT_OR_SORCERY = new FilterSpell("instant or sorcery spell"); static { @@ -463,17 +520,18 @@ public final class StaticFilters { )); FILTER_SPELLS_INSTANT_OR_SORCERY.setLockedFilter(true); } + public static final FilterCreaturePermanent FILTER_CREATURE_TOKENS = new FilterCreaturePermanent("creature tokens"); static { - FILTER_CREATURE_TOKENS.add(new TokenPredicate()); + FILTER_CREATURE_TOKENS.add(TokenPredicate.instance); FILTER_CREATURE_TOKENS.setLockedFilter(true); } public static final FilterCreaturePermanent FILTER_ATTACKING_CREATURES = new FilterCreaturePermanent("attacking creatures"); static { - FILTER_ATTACKING_CREATURES.add(new AttackingPredicate()); + FILTER_ATTACKING_CREATURES.add(AttackingPredicate.instance); FILTER_ATTACKING_CREATURES.setLockedFilter(true); } @@ -484,6 +542,7 @@ public final class StaticFilters { FILTER_PERMANENT_AURA.add(new SubtypePredicate(SubType.AURA)); FILTER_PERMANENT_AURA.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_EQUIPMENT = new FilterPermanent(); static { @@ -491,6 +550,7 @@ public final class StaticFilters { FILTER_PERMANENT_EQUIPMENT.add(new SubtypePredicate(SubType.EQUIPMENT)); FILTER_PERMANENT_EQUIPMENT.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_FORTIFICATION = new FilterPermanent(); static { @@ -498,6 +558,7 @@ public final class StaticFilters { FILTER_PERMANENT_FORTIFICATION.add(new SubtypePredicate(SubType.FORTIFICATION)); FILTER_PERMANENT_FORTIFICATION.setLockedFilter(true); } + public static final FilterPermanent FILTER_PERMANENT_LEGENDARY = new FilterPermanent(); static { diff --git a/Mage/src/main/java/mage/filter/common/FilterAttackingCreature.java b/Mage/src/main/java/mage/filter/common/FilterAttackingCreature.java index 90d1271aec..ac3564f19f 100644 --- a/Mage/src/main/java/mage/filter/common/FilterAttackingCreature.java +++ b/Mage/src/main/java/mage/filter/common/FilterAttackingCreature.java @@ -16,7 +16,7 @@ public class FilterAttackingCreature extends FilterCreaturePermanent { public FilterAttackingCreature(String name) { super(name); - this.add(new AttackingPredicate()); + this.add(AttackingPredicate.instance); } public FilterAttackingCreature(final FilterAttackingCreature filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterAttackingOrBlockingCreature.java b/Mage/src/main/java/mage/filter/common/FilterAttackingOrBlockingCreature.java index aaaa446e1c..2cb8bbfe23 100644 --- a/Mage/src/main/java/mage/filter/common/FilterAttackingOrBlockingCreature.java +++ b/Mage/src/main/java/mage/filter/common/FilterAttackingOrBlockingCreature.java @@ -19,8 +19,8 @@ public class FilterAttackingOrBlockingCreature extends FilterCreaturePermanent { public FilterAttackingOrBlockingCreature(String name) { super(name); this.add(Predicates.or( - new AttackingPredicate(), - new BlockingPredicate())); + AttackingPredicate.instance, + BlockingPredicate.instance)); } public FilterAttackingOrBlockingCreature(final FilterAttackingOrBlockingCreature filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterBlockingCreature.java b/Mage/src/main/java/mage/filter/common/FilterBlockingCreature.java index 9a285ba6c6..660b9abf15 100644 --- a/Mage/src/main/java/mage/filter/common/FilterBlockingCreature.java +++ b/Mage/src/main/java/mage/filter/common/FilterBlockingCreature.java @@ -15,7 +15,7 @@ public class FilterBlockingCreature extends FilterCreaturePermanent { public FilterBlockingCreature(String name) { super(name); - this.add(new BlockingPredicate()); + this.add(BlockingPredicate.instance); } public FilterBlockingCreature(final FilterBlockingCreature filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterControlledPlaneswalkerPermanent.java b/Mage/src/main/java/mage/filter/common/FilterControlledPlaneswalkerPermanent.java index 9cbee3044f..ef474acf32 100644 --- a/Mage/src/main/java/mage/filter/common/FilterControlledPlaneswalkerPermanent.java +++ b/Mage/src/main/java/mage/filter/common/FilterControlledPlaneswalkerPermanent.java @@ -6,7 +6,6 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; /** - * * @author LevelX2 */ public class FilterControlledPlaneswalkerPermanent extends FilterControlledPermanent { @@ -15,6 +14,10 @@ public class FilterControlledPlaneswalkerPermanent extends FilterControlledPerma this("planeswalker you control"); } + public FilterControlledPlaneswalkerPermanent(SubType subType) { + this(subType, "a " + subType + " planeswalker"); + } + public FilterControlledPlaneswalkerPermanent(SubType subType, String name) { super(name); this.add(new CardTypePredicate(CardType.PLANESWALKER)); diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java index d6e1555303..4657174caa 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureAttackingYou.java @@ -1,5 +1,5 @@ -package mage.target.common; +package mage.filter.common; import java.util.UUID; import mage.filter.common.FilterAttackingCreature; diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java index 112685b0dd..68b75d7926 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureForAttack.java @@ -25,9 +25,9 @@ public class FilterCreatureForAttack extends FilterCreaturePermanent { public FilterCreatureForAttack(String name) { super(name); - this.add(Predicates.not(new AttackingPredicate())); - this.add(Predicates.not(new BlockingPredicate())); - this.add(Predicates.not(new TappedPredicate())); + this.add(Predicates.not(AttackingPredicate.instance)); + this.add(Predicates.not(BlockingPredicate.instance)); + this.add(Predicates.not(TappedPredicate.instance)); this.add(Predicates.not(new AbilityPredicate(DefenderAbility.class))); this.add(new CanTapPredicate()); } diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombat.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombat.java index 5b418ce182..dc94c1fa32 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombat.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombat.java @@ -18,7 +18,7 @@ public class FilterCreatureForCombat extends FilterCreatureForCombatBase { public FilterCreatureForCombat(String name) { super(name); - this.add(Predicates.not(new TappedPredicate())); + this.add(Predicates.not(TappedPredicate.instance)); } public FilterCreatureForCombat(final FilterCreatureForCombat filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBase.java b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBase.java index 195d4cefcb..a5daa73e32 100644 --- a/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBase.java +++ b/Mage/src/main/java/mage/filter/common/FilterCreatureForCombatBase.java @@ -22,7 +22,7 @@ public class FilterCreatureForCombatBase extends FilterCreaturePermanent { public FilterCreatureForCombatBase(String name) { super(name); - this.add(Predicates.not(new AttackingPredicate())); + this.add(Predicates.not(AttackingPredicate.instance)); this.add(new PhasedInPredicate()); this.add(new CanBlockPredicate()); } diff --git a/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java b/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java index fc843f163c..eb3f7cf1c1 100644 --- a/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java +++ b/Mage/src/main/java/mage/filter/common/FilterHistoricCard.java @@ -20,7 +20,7 @@ public class FilterHistoricCard extends FilterCard { public FilterHistoricCard(String name) { super(name); - this.add(new HistoricPredicate()); + this.add(HistoricPredicate.instance); } public FilterHistoricCard(final FilterHistoricCard filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java b/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java index d6b59a6cc7..13ccb99ea1 100644 --- a/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java +++ b/Mage/src/main/java/mage/filter/common/FilterHistoricSpell.java @@ -16,7 +16,7 @@ public class FilterHistoricSpell extends FilterSpell { public FilterHistoricSpell(String name) { super(name); - this.add(new HistoricPredicate()); + this.add(HistoricPredicate.instance); } public FilterHistoricSpell(final FilterHistoricSpell filter) { diff --git a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java index f587236ac4..601bb952bc 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java +++ b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerOrPlayer.java @@ -47,6 +47,14 @@ public class FilterPlaneswalkerOrPlayer extends FilterImpl { this.playerFilter = filter.playerFilter.copy(); } + public FilterPlaneswalkerPermanent getFilterPermanent() { + return this.planeswalkerFilter; + } + + public FilterPlayer getFilterPlayer() { + return this.playerFilter; + } + @Override public boolean checkObjectClass(Object object) { return true; diff --git a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java index 0fef222e96..8149b208bf 100644 --- a/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java +++ b/Mage/src/main/java/mage/filter/common/FilterPlaneswalkerPermanent.java @@ -3,11 +3,12 @@ package mage.filter.common; import mage.constants.CardType; +import mage.constants.SubType; import mage.filter.FilterPermanent; import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; /** - * * @author BetaSteward_at_googlemail.com */ public class FilterPlaneswalkerPermanent extends FilterPermanent { @@ -16,6 +17,11 @@ public class FilterPlaneswalkerPermanent extends FilterPermanent { this("planeswalker"); } + public FilterPlaneswalkerPermanent(SubType subType) { + this(subType.getDescription() + " planeswalker"); + this.add(new SubtypePredicate(subType)); + } + public FilterPlaneswalkerPermanent(String name) { super(name); this.add(new CardTypePredicate(CardType.PLANESWALKER)); diff --git a/Mage/src/main/java/mage/filter/common/FilterUntappedCreature.java b/Mage/src/main/java/mage/filter/common/FilterUntappedCreature.java index 13f1ee652a..ebf7c43da1 100644 --- a/Mage/src/main/java/mage/filter/common/FilterUntappedCreature.java +++ b/Mage/src/main/java/mage/filter/common/FilterUntappedCreature.java @@ -17,7 +17,7 @@ public class FilterUntappedCreature extends FilterCreaturePermanent { public FilterUntappedCreature(String name) { super(name); - this.add(Predicates.not(new TappedPredicate())); + this.add(Predicates.not(TappedPredicate.instance)); } public FilterUntappedCreature(final FilterUntappedCreature filter) { diff --git a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java index aa73a7d466..671c8abf0c 100644 --- a/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java +++ b/Mage/src/main/java/mage/filter/predicate/ObjectSourcePlayer.java @@ -12,8 +12,8 @@ public class ObjectSourcePlayer extends ObjectPlayer { protected final UUID sourceId; - public ObjectSourcePlayer(T object, UUID sourceId, UUID playerId) { - super(object, playerId); + public ObjectSourcePlayer(T object, UUID sourceId, UUID sourceControllerId) { + super(object, sourceControllerId); this.sourceId = sourceId; } diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/ColorlessPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/ColorlessPredicate.java index 3dcf34b34d..0eee39d882 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/ColorlessPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/ColorlessPredicate.java @@ -6,10 +6,10 @@ import mage.filter.predicate.Predicate; import mage.game.Game; /** - * * @author North */ -public class ColorlessPredicate implements Predicate { +public enum ColorlessPredicate implements Predicate { + instance; @Override public boolean apply(MageObject input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/HistoricPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/HistoricPredicate.java index fa862b16b8..39d0a7c15f 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/HistoricPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/HistoricPredicate.java @@ -10,10 +10,10 @@ import mage.filter.predicate.Predicate; import mage.game.Game; /** - * * @author LevelX2 */ -public class HistoricPredicate implements Predicate { +public enum HistoricPredicate implements Predicate { + instance; @Override public boolean apply(MageObject input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/MonocoloredPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/MonocoloredPredicate.java index 66d98053ec..50172d93ad 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/MonocoloredPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/MonocoloredPredicate.java @@ -6,10 +6,10 @@ import mage.filter.predicate.Predicate; import mage.game.Game; /** - * * @author LevelX2 */ -public class MonocoloredPredicate implements Predicate { +public enum MonocoloredPredicate implements Predicate { + instance; @Override public boolean apply(MageObject input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java index f159866611..58a5937d74 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/MulticoloredPredicate.java @@ -8,10 +8,10 @@ import mage.filter.predicate.Predicate; import mage.game.Game; /** - * * @author jeffwadsworth */ -public class MulticoloredPredicate implements Predicate { +public enum MulticoloredPredicate implements Predicate { + instance; @Override public boolean apply(MageObject input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java index 65ac53f8d4..b80f7766a7 100644 --- a/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/mageobject/NamePredicate.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.mageobject; import mage.MageObject; @@ -7,17 +6,23 @@ import mage.constants.SpellAbilityType; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.stack.Spell; +import mage.util.CardUtil; /** - * * @author North */ public class NamePredicate implements Predicate { private final String name; + private final Boolean ignoreMtgRuleForEmptyNames; // NamePredicate uses at test and checks, it's must ignore that rules (empty names is not equals in mtg) public NamePredicate(String name) { + this(name, false); + } + + public NamePredicate(String name, Boolean ignoreMtgRuleForEmptyNames) { this.name = name; + this.ignoreMtgRuleForEmptyNames = ignoreMtgRuleForEmptyNames; } @Override @@ -25,17 +30,20 @@ public class NamePredicate implements Predicate { // If a player names a card, the player may name either half of a split card, but not both. // A split card has the chosen name if one of its two names matches the chosen name. if (input instanceof SplitCard) { - return name.equals(((SplitCard)input).getLeftHalfCard().getName()) || name.equals(((SplitCard)input).getRightHalfCard().getName()); - } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED){ - SplitCard card = (SplitCard) ((Spell)input).getCard(); - return name.equals(card.getLeftHalfCard().getName()) || name.equals(card.getRightHalfCard().getName()); + return CardUtil.haveSameNames(name, ((SplitCard) input).getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(name, ((SplitCard) input).getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames); + } else if (input instanceof Spell && ((Spell) input).getSpellAbility().getSpellAbilityType() == SpellAbilityType.SPLIT_FUSED) { + SplitCard card = (SplitCard) ((Spell) input).getCard(); + return CardUtil.haveSameNames(name, card.getLeftHalfCard().getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(name, card.getRightHalfCard().getName(), this.ignoreMtgRuleForEmptyNames); } else { if (name.contains(" // ")) { String leftName = name.substring(0, name.indexOf(" // ")); String rightName = name.substring(name.indexOf(" // ") + 4, name.length()); - return leftName.equals(input.getName()) || rightName.equals(input.getName()); + return CardUtil.haveSameNames(leftName, input.getName(), this.ignoreMtgRuleForEmptyNames) || + CardUtil.haveSameNames(rightName, input.getName(), this.ignoreMtgRuleForEmptyNames); } else { - return name.equals(input.getName()); + return CardUtil.haveSameNames(name, input.getName(), this.ignoreMtgRuleForEmptyNames); } } } diff --git a/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java b/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java index 54e8e55853..54d3c490ed 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java +++ b/Mage/src/main/java/mage/filter/predicate/other/AuraCardCanAttachToPermanentId.java @@ -1,4 +1,3 @@ - package mage.filter.predicate.other; import java.util.UUID; @@ -14,7 +13,6 @@ import mage.target.Target; * @author jeffwadsworth */ // Use this predicate if a aura card comes into play attached to a permanent without targeting - public class AuraCardCanAttachToPermanentId implements Predicate { private final UUID toBeCheckedPermanentId; @@ -27,10 +25,14 @@ public class AuraCardCanAttachToPermanentId implements Predicate { public boolean apply(Card input, Game game) { final Permanent permanent = game.getPermanent(toBeCheckedPermanentId); Filter filter; - for (Target target : input.getSpellAbility().getTargets()) { - filter = target.getFilter(); - if (filter.match(permanent, game)) { - return true; + if (permanent != null + && input != null + && input.isEnchantment()) { + for (Target target : input.getSpellAbility().getTargets()) { + filter = target.getFilter(); + if (filter.match(permanent, game)) { + return true; + } } } return false; @@ -40,4 +42,4 @@ public class AuraCardCanAttachToPermanentId implements Predicate { public String toString() { return "AuraCardCanAttachToPermanentId(" + toBeCheckedPermanentId + ')'; } -} \ No newline at end of file +} diff --git a/Mage/src/main/java/mage/filter/predicate/other/AuraPermanentCanAttachToPermanentId.java b/Mage/src/main/java/mage/filter/predicate/other/AuraPermanentCanAttachToPermanentId.java index 5e22dfd714..a52633c2b5 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/AuraPermanentCanAttachToPermanentId.java +++ b/Mage/src/main/java/mage/filter/predicate/other/AuraPermanentCanAttachToPermanentId.java @@ -26,10 +26,12 @@ public class AuraPermanentCanAttachToPermanentId implements Predicate public boolean apply(Permanent input, Game game) { final Permanent permanent = game.getPermanent(toBeCheckedPermanentId); Filter filter; - for (Target target : input.getSpellAbility().getTargets()) { - filter = target.getFilter(); - if (filter.match(permanent, game)) { - return true; + if(input.getSpellAbility() != null && input.getSpellAbility().getTargets() != null) { + for (Target target : input.getSpellAbility().getTargets()) { + filter = target.getFilter(); + if (filter.match(permanent, game)) { + return true; + } } } return false; diff --git a/Mage/src/main/java/mage/filter/predicate/other/FaceDownPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/FaceDownPredicate.java index 1253e4fb1e..c6079cf9d4 100644 --- a/Mage/src/main/java/mage/filter/predicate/other/FaceDownPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/other/FaceDownPredicate.java @@ -6,10 +6,10 @@ import mage.filter.predicate.Predicate; import mage.game.Game; /** - * * @author North */ -public class FaceDownPredicate implements Predicate { +public enum FaceDownPredicate implements Predicate { + instance; @Override public boolean apply(Card input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java new file mode 100644 index 0000000000..08433ae089 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/TargetsOnlyOnePlayerPredicate.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; + +/** + * + * @author jeffwadsworth + */ +public class TargetsOnlyOnePlayerPredicate implements ObjectSourcePlayerPredicate> { + + public TargetsOnlyOnePlayerPredicate() { + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if (object != null) { + for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + if (target.getTargets().size() == 1) { // only one player targeted + Player player = game.getPlayer(target.getFirstTarget()); + return player != null; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets only one player"; + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java b/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java new file mode 100644 index 0000000000..af8f556bc4 --- /dev/null +++ b/Mage/src/main/java/mage/filter/predicate/other/TargetsPlayerPredicate.java @@ -0,0 +1,48 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package mage.filter.predicate.other; + +import java.util.UUID; +import mage.MageObject; +import mage.abilities.Mode; +import mage.filter.predicate.ObjectSourcePlayer; +import mage.filter.predicate.ObjectSourcePlayerPredicate; +import mage.game.Game; +import mage.game.stack.StackObject; +import mage.players.Player; +import mage.target.Target; + +/** + * + * @author jeffwadsworth + */ +public class TargetsPlayerPredicate implements ObjectSourcePlayerPredicate> { + + public TargetsPlayerPredicate() { + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + StackObject object = game.getStack().getStackObject(input.getObject().getId()); + if (object != null) { + for (UUID modeId : object.getStackAbility().getModes().getSelectedModes()) { + Mode mode = object.getStackAbility().getModes().get(modeId); + for (Target target : mode.getTargets()) { + for (UUID targetId : target.getTargets()) { + Player player = game.getPlayer(targetId); + return player != null; + } + } + } + } + return false; + } + + @Override + public String toString() { + return "that targets a player"; + } +} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherPredicate.java index 19d9bdd2a4..c8d9671388 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/AnotherPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/AnotherPredicate.java @@ -7,10 +7,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class AnotherPredicate implements ObjectSourcePlayerPredicate> { +public enum AnotherPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override public boolean apply(ObjectSourcePlayer input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/AttackingPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/AttackingPredicate.java index 871661f0bc..899967ab45 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/AttackingPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/AttackingPredicate.java @@ -6,10 +6,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class AttackingPredicate implements Predicate { +public enum AttackingPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/BlockedByIdPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/BlockedByIdPredicate.java index b1ba27d400..135281a0e1 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/BlockedByIdPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/BlockedByIdPredicate.java @@ -28,7 +28,7 @@ public class BlockedByIdPredicate implements Predicate { } // Check if the blockerId was blocked before, if it does no longer exists now but so the target attacking is still valid Permanent blocker = game.getPermanentOrLKIBattlefield(blockerId); if (blocker != null) { - BlockedAttackerWatcher watcher = (BlockedAttackerWatcher) game.getState().getWatchers().get(BlockedAttackerWatcher.class.getSimpleName()); + BlockedAttackerWatcher watcher = game.getState().getWatcher(BlockedAttackerWatcher.class); if (watcher != null) { return watcher.creatureHasBlockedAttacker(input, blocker, game); } diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/BlockedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/BlockedPredicate.java index 1e0ef1f468..97fd2a2f54 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/BlockedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/BlockedPredicate.java @@ -6,10 +6,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class BlockedPredicate implements Predicate { +public enum BlockedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/BlockingPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/BlockingPredicate.java index 3360109111..cf2c3f7c55 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/BlockingPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/BlockingPredicate.java @@ -6,10 +6,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class BlockingPredicate implements Predicate { +public enum BlockingPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java index 8be4989a9f..58bc4269b2 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CommanderPredicate.java @@ -11,10 +11,10 @@ import mage.game.permanent.Permanent; import mage.players.Player; /** - * * @author LevelX2 */ -public class CommanderPredicate implements Predicate { +public enum CommanderPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/CounterAnyPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/CounterAnyPredicate.java index 71065e54e3..228f1dd628 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/CounterAnyPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/CounterAnyPredicate.java @@ -1,19 +1,15 @@ package mage.filter.predicate.permanent; -import mage.counters.Counter; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author LevelX2 */ -public class CounterAnyPredicate implements Predicate { - - public CounterAnyPredicate() { - } +public enum CounterAnyPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/DamagedPlayerThisTurnPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/DamagedPlayerThisTurnPredicate.java index 17807a0ea3..191e58133a 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/DamagedPlayerThisTurnPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/DamagedPlayerThisTurnPredicate.java @@ -28,14 +28,14 @@ public class DamagedPlayerThisTurnPredicate implements ObjectPlayerPredicate> { +public enum DefendingPlayerControlsPredicate implements ObjectSourcePlayerPredicate> { + instance; @Override public boolean apply(ObjectSourcePlayer input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/EnchantedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/EnchantedPredicate.java index c548735dc5..71491195df 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/EnchantedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/EnchantedPredicate.java @@ -1,19 +1,18 @@ package mage.filter.predicate.permanent; -import java.util.Objects; -import java.util.UUID; - import mage.MageObject; import mage.filter.predicate.Predicate; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.Objects; + /** - * * @author LevelX2 */ -public class EnchantedPredicate implements Predicate { +public enum EnchantedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { @@ -26,6 +25,6 @@ public class EnchantedPredicate implements Predicate { @Override public String toString() { - return "Enchanted" ; + return "Enchanted"; } } diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java index cb0b266d9e..c92c414594 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/EquippedPredicate.java @@ -15,7 +15,8 @@ import java.util.Objects; /** * @author LevelX2 */ -public class EquippedPredicate implements Predicate { +public enum EquippedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/TappedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/TappedPredicate.java index fb3319ac46..2b4d720d9c 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/TappedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/TappedPredicate.java @@ -6,10 +6,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author North */ -public class TappedPredicate implements Predicate { +public enum TappedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/TokenPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/TokenPredicate.java index 61afd03d76..97e8f49f5e 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/TokenPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/TokenPredicate.java @@ -7,10 +7,10 @@ import mage.game.permanent.Permanent; import mage.game.permanent.PermanentToken; /** - * * @author North */ -public class TokenPredicate implements Predicate { +public enum TokenPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/TransformedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/TransformedPredicate.java index 8cbcf132be..9479bcf814 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/TransformedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/TransformedPredicate.java @@ -6,10 +6,10 @@ import mage.game.Game; import mage.game.permanent.Permanent; /** - * * @author Saga */ -public class TransformedPredicate implements Predicate { +public enum TransformedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { @@ -18,6 +18,6 @@ public class TransformedPredicate implements Predicate { @Override public String toString() { - return "Transformed" ; + return "Transformed"; } } \ No newline at end of file diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/UnblockedPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/UnblockedPredicate.java index 4b164bc4ae..2bcff6037f 100644 --- a/Mage/src/main/java/mage/filter/predicate/permanent/UnblockedPredicate.java +++ b/Mage/src/main/java/mage/filter/predicate/permanent/UnblockedPredicate.java @@ -13,7 +13,8 @@ import mage.game.turn.Step; * * @author LevelX2 */ -public class UnblockedPredicate implements Predicate { +public enum UnblockedPredicate implements Predicate { + instance; @Override public boolean apply(Permanent input, Game game) { diff --git a/Mage/src/main/java/mage/game/Controllable.java b/Mage/src/main/java/mage/game/Controllable.java index 025b8f3720..ac7507e508 100644 --- a/Mage/src/main/java/mage/game/Controllable.java +++ b/Mage/src/main/java/mage/game/Controllable.java @@ -12,6 +12,9 @@ public interface Controllable { UUID getId(); default boolean isControlledBy(UUID controllerID){ + if(getControllerId() == null){ + return false; + } return getControllerId().equals(controllerID); } } diff --git a/Mage/src/main/java/mage/game/Exile.java b/Mage/src/main/java/mage/game/Exile.java index 3fc2a7ab7b..a8a4474e40 100644 --- a/Mage/src/main/java/mage/game/Exile.java +++ b/Mage/src/main/java/mage/game/Exile.java @@ -1,19 +1,15 @@ - package mage.game; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.UUID; import mage.cards.Card; +import mage.filter.FilterCard; import mage.util.Copyable; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; + /** - * * @author BetaSteward_at_googlemail.com */ public class Exile implements Serializable, Copyable { @@ -70,6 +66,11 @@ public class Exile implements Serializable, Copyable { return null; } + public List getCards(FilterCard filter, Game game) { + List allCards = getAllCards(game); + return allCards.stream().filter(card -> filter.match(card, game)).collect(Collectors.toList()); + } + public List getAllCards(Game game) { List cards = new ArrayList<>(); for (ExileZone exile : exileZones.values()) { @@ -106,4 +107,17 @@ public class Exile implements Serializable, Copyable { exile.clear(); } } + + public void cleanupEndOfTurnZones(Game game) { + // moves cards from outdated zone to main exile zone + ExileZone mainZone = getExileZone(PERMANENT); + for (ExileZone zone : exileZones.values()) { + if (zone.isCleanupOnEndTurn()) { + for (Card card : zone.getCards(game)) { + mainZone.add(card); + zone.remove(card); + } + } + } + } } diff --git a/Mage/src/main/java/mage/game/ExileZone.java b/Mage/src/main/java/mage/game/ExileZone.java index 2b9395ee12..451d2bb249 100644 --- a/Mage/src/main/java/mage/game/ExileZone.java +++ b/Mage/src/main/java/mage/game/ExileZone.java @@ -1,13 +1,10 @@ - - package mage.game; -import java.util.UUID; - import mage.cards.CardsImpl; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class ExileZone extends CardsImpl { @@ -15,16 +12,22 @@ public class ExileZone extends CardsImpl { private UUID id; private String name; private boolean hidden; + private boolean cleanupOnEndTurn = false; // moved cards from that zone to default on end of turn (to cleanup exile windows) public ExileZone(UUID id, String name) { this(id, name, false); } public ExileZone(UUID id, String name, boolean hidden) { + this(id, name, false, false); + } + + public ExileZone(UUID id, String name, boolean hidden, boolean cleanupOnEndTurn) { super(); this.id = id; this.name = name; this.hidden = hidden; + this.cleanupOnEndTurn = cleanupOnEndTurn; } public ExileZone(final ExileZone zone) { @@ -32,6 +35,7 @@ public class ExileZone extends CardsImpl { this.id = zone.id; this.name = zone.name; this.hidden = zone.hidden; + this.cleanupOnEndTurn = zone.cleanupOnEndTurn; } public UUID getId() { @@ -46,6 +50,14 @@ public class ExileZone extends CardsImpl { return hidden; } + public boolean isCleanupOnEndTurn() { + return cleanupOnEndTurn; + } + + public void setCleanupOnEndTurn(boolean cleanupOnEndTurn) { + this.cleanupOnEndTurn = cleanupOnEndTurn; + } + @Override public ExileZone copy() { return new ExileZone(this); diff --git a/Mage/src/main/java/mage/game/Game.java b/Mage/src/main/java/mage/game/Game.java index 8ab4089a44..17342a8fb7 100644 --- a/Mage/src/main/java/mage/game/Game.java +++ b/Mage/src/main/java/mage/game/Game.java @@ -1,10 +1,5 @@ - package mage.game; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; - import mage.MageItem; import mage.MageObject; import mage.abilities.Ability; @@ -30,7 +25,9 @@ import mage.game.events.GameEvent; import mage.game.events.Listener; import mage.game.events.PlayerQueryEvent; import mage.game.events.TableEvent; +import mage.game.match.Match; import mage.game.match.MatchType; +import mage.game.mulligan.Mulligan; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; @@ -45,6 +42,10 @@ import mage.players.Players; import mage.util.MessageToClient; import mage.util.functions.ApplyToPermanent; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + public interface Game extends MageItem, Serializable { MatchType getGameType(); @@ -98,6 +99,7 @@ public interface Game extends MageItem, Serializable { Map> getLKI(); + // Result must be checked for null. Possible errors search pattern: (\S*) = game.getCard.+\n(?!.+\1 != null) Card getCard(UUID cardId); Optional getAbility(UUID abilityId, UUID sourceId); @@ -106,6 +108,7 @@ public interface Game extends MageItem, Serializable { void addPlayer(Player player, Deck deck); + // Result must be checked for null. Possible errors search pattern: (\S*) = game.getPlayer.+\n(?!.+\1 != null) Player getPlayer(UUID playerId); Player getPlayerOrPlaneswalkerController(UUID playerId); @@ -130,8 +133,8 @@ public interface Game extends MageItem, Serializable { } - default boolean isActivePlayer(UUID playerId){ - return getActivePlayerId().equals(playerId); + default boolean isActivePlayer(UUID playerId) { + return getActivePlayerId() != null && getActivePlayerId().equals(playerId); } /** @@ -294,9 +297,9 @@ public interface Game extends MageItem, Serializable { /** * Creates and fires an damage prevention event * - * @param damageEvent damage event that will be replaced (instanceof check - * will be done) - * @param source ability that's the source of the prevention effect + * @param damageEvent damage event that will be replaced (instanceof check + * will be done) + * @param source ability that's the source of the prevention effect * @param game * @param amountToPrevent max preventable amount * @return true prevention was successfull / false prevention was replaced @@ -306,12 +309,12 @@ public interface Game extends MageItem, Serializable { /** * Creates and fires an damage prevention event * - * @param event damage event that will be replaced (instanceof check will be - * done) - * @param source ability that's the source of the prevention effect + * @param event damage event that will be replaced (instanceof check will be + * done) + * @param source ability that's the source of the prevention effect * @param game * @param preventAllDamage true if there is no limit to the damage that can - * be prevented + * be prevented * @return true prevention was successfull / false prevention was replaced */ PreventionEffectData preventDamage(GameEvent event, Ability source, Game game, boolean preventAllDamage); @@ -471,4 +474,7 @@ public interface Game extends MageItem, Serializable { int damagePlayerOrPlaneswalker(UUID playerOrWalker, int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable); int damagePlayerOrPlaneswalker(UUID playerOrWalker, int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List appliedEffects); + + Mulligan getMulligan(); + } diff --git a/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java b/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java index 03b905bcc0..ab7408114a 100644 --- a/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCanadianHighlanderImpl.java @@ -1,20 +1,18 @@ package mage.game; -import java.util.*; import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; -import mage.players.Player; + +import java.util.UUID; public abstract class GameCanadianHighlanderImpl extends GameImpl { - protected boolean startingPlayerSkipsDraw = true; - protected Map usedMulligans = new LinkedHashMap<>(); - - public GameCanadianHighlanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, 0, startLife); + public GameCanadianHighlanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public GameCanadianHighlanderImpl(final GameCanadianHighlanderImpl game) { @@ -27,110 +25,4 @@ public abstract class GameCanadianHighlanderImpl extends GameImpl { state.getTurnMods().add(new TurnMod(startingPlayerId, PhaseStep.DRAW)); } - private String getNextMulligan(String mulligan) { - switch (mulligan) { - case "7": - return "6a"; - case "6a": - return "6b"; - case "6b": - return "5a"; - case "5a": - return "5b"; - case "5b": - return "4a"; - case "4a": - return "4b"; - case "4b": - return "3a"; - case "3a": - return "3b"; - case "3b": - return "2a"; - case "2a": - return "2b"; - case "2b": - return "1a"; - case "1a": - return "1b"; - } - return "0"; - } - - private int getNextMulliganNum(String mulligan) { - switch (mulligan) { - case "7": - return 6; - case "6a": - return 6; - case "6b": - return 5; - case "5a": - return 5; - case "5b": - return 4; - case "4a": - return 4; - case "4b": - return 3; - case "3a": - return 3; - case "3b": - return 2; - case "2a": - return 2; - case "2b": - return 1; - case "1a": - return 1; - } - return 0; - } - - @Override - public int mulliganDownTo(UUID playerId) { - Player player = getPlayer(playerId); - int deduction = 1; - int numToMulliganTo = -1; - if (usedMulligans != null) { - String mulliganCode = "7"; - if (usedMulligans.containsKey(player.getId())) { - mulliganCode = usedMulligans.get(player.getId()); - } - numToMulliganTo = getNextMulliganNum(mulliganCode); - } - if (numToMulliganTo == -1) { - return player.getHand().size() - deduction; - } - return numToMulliganTo; - } - - @Override - public void mulligan(UUID playerId) { - Player player = getPlayer(playerId); - int numCards = player.getHand().size(); - int numToMulliganTo = numCards; - player.getLibrary().addAll(player.getHand().getCards(this), this); - player.getHand().clear(); - player.shuffleLibrary(null, this); - if (usedMulligans != null) { - String mulliganCode = "7"; - if (usedMulligans.containsKey(player.getId())) { - mulliganCode = usedMulligans.get(player.getId()); - } - numToMulliganTo = getNextMulliganNum(mulliganCode); - usedMulligans.put(player.getId(), getNextMulligan(mulliganCode)); - } - fireInformEvent(new StringBuilder(player.getLogName()) - .append(" mulligans to ") - .append(Integer.toString(numToMulliganTo)) - .append(numToMulliganTo == 1 ? " card" : " cards").toString()); - player.drawCards(numToMulliganTo, this); - } - - @Override - public void endMulligan(UUID playerId) { - super.endMulligan(playerId); - } - } diff --git a/Mage/src/main/java/mage/game/GameCommanderImpl.java b/Mage/src/main/java/mage/game/GameCommanderImpl.java index f6c2e6779d..96de6b8306 100644 --- a/Mage/src/main/java/mage/game/GameCommanderImpl.java +++ b/Mage/src/main/java/mage/game/GameCommanderImpl.java @@ -1,8 +1,5 @@ - package mage.game; -import java.util.Map; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.InfoEffect; @@ -13,10 +10,14 @@ import mage.constants.MultiplayerAttackOption; import mage.constants.PhaseStep; import mage.constants.RangeOfInfluence; import mage.constants.Zone; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; import mage.watchers.common.CommanderInfoWatcher; +import java.util.Map; +import java.util.UUID; + public abstract class GameCommanderImpl extends GameImpl { // private final Map mulliganedCards = new HashMap<>(); @@ -25,8 +26,8 @@ public abstract class GameCommanderImpl extends GameImpl { protected boolean alsoLibrary; // replace commander going to library protected boolean startingPlayerSkipsDraw = true; - public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public GameCommanderImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public GameCommanderImpl(final GameCommanderImpl game) { @@ -44,18 +45,20 @@ public abstract class GameCommanderImpl extends GameImpl { for (UUID playerId : state.getPlayerList(startingPlayerId)) { Player player = getPlayer(playerId); if (player != null) { - while (!player.getSideboard().isEmpty()) { - Card commander = this.getCard(player.getSideboard().iterator().next()); - if (commander != null) { - player.addCommanderId(commander.getId()); - commander.moveToZone(Zone.COMMAND, null, this, true); - commander.getAbilities().setControllerId(player.getId()); - ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary)); - ability.addEffect(new CommanderCostModification(commander.getId())); - getState().setValue(commander.getId() + "_castCount", 0); - CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage); - getState().getWatchers().add(watcher); - watcher.addCardInfoToCommander(this); + if (player.getSideboard().isEmpty()) { // needed for restart game of e.g. Karn Liberated + for (UUID commanderId : player.getCommandersIds()) { + Card commander = this.getCard(commanderId); + if (commander != null) { + initCommander(commander, ability, player); + } + } + } else { + while (!player.getSideboard().isEmpty()) { + Card commander = this.getCard(player.getSideboard().iterator().next()); + if (commander != null) { + player.addCommanderId(commander.getId()); + initCommander(commander, ability, player); + } } } } @@ -67,6 +70,17 @@ public abstract class GameCommanderImpl extends GameImpl { } } + private void initCommander(Card commander, Ability ability, Player player) { + commander.moveToZone(Zone.COMMAND, null, this, true); + commander.getAbilities().setControllerId(player.getId()); + ability.addEffect(new CommanderReplacementEffect(commander.getId(), alsoHand, alsoLibrary)); + ability.addEffect(new CommanderCostModification(commander.getId())); + getState().setValue(commander.getId() + "_castCount", 0); + CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), checkCommanderDamage); + getState().addWatcher(watcher); + watcher.addCardInfoToCommander(this); + } + //20130711 /*903.8. The Commander variant uses an alternate mulligan rule. * Each time a player takes a mulligan, rather than shuffling their entire hand of cards into their library, that player exiles any number of cards from their hand face down. @@ -155,7 +169,7 @@ public abstract class GameCommanderImpl extends GameImpl { protected boolean checkStateBasedActions() { for (Player player : getPlayers().values()) { for (UUID commanderId : player.getCommandersIds()) { - CommanderInfoWatcher damageWatcher = (CommanderInfoWatcher) getState().getWatchers().get(CommanderInfoWatcher.class.getSimpleName(), commanderId); + CommanderInfoWatcher damageWatcher = getState().getWatcher(CommanderInfoWatcher.class, commanderId); if (damageWatcher == null) { continue; } diff --git a/Mage/src/main/java/mage/game/GameImpl.java b/Mage/src/main/java/mage/game/GameImpl.java index e745c75e12..8d2589f68f 100644 --- a/Mage/src/main/java/mage/game/GameImpl.java +++ b/Mage/src/main/java/mage/game/GameImpl.java @@ -1,9 +1,5 @@ package mage.game; -import java.io.IOException; -import java.io.Serializable; -import java.util.*; -import java.util.Map.Entry; import mage.MageException; import mage.MageObject; import mage.abilities.*; @@ -44,6 +40,8 @@ import mage.game.command.Emblem; import mage.game.command.Plane; import mage.game.events.*; import mage.game.events.TableEvent.EventType; +import mage.game.mulligan.LondonMulligan; +import mage.game.mulligan.Mulligan; import mage.game.permanent.Battlefield; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; @@ -65,10 +63,14 @@ import mage.util.GameLog; import mage.util.MessageToClient; import mage.util.RandomUtil; import mage.util.functions.ApplyToPermanent; -import mage.watchers.Watchers; import mage.watchers.common.*; import org.apache.log4j.Logger; +import java.io.IOException; +import java.io.Serializable; +import java.util.*; +import java.util.Map.Entry; + public abstract class GameImpl implements Game, Serializable { private static final int ROLLBACK_TURNS_MAX = 4; @@ -108,15 +110,12 @@ public abstract class GameImpl implements Game, Serializable { protected UUID winnerId; protected RangeOfInfluence range; - protected int freeMulligans; - protected Map usedFreeMulligans = new LinkedHashMap<>(); + protected Mulligan mulligan; + protected MultiplayerAttackOption attackOption; protected GameOptions gameOptions; protected String startMessage; - public static volatile int copyCount = 0; - public static volatile long copyTime = 0; - // private final transient LinkedList actions; private Player scorePlayer; // private int score = 0; @@ -142,27 +141,24 @@ public abstract class GameImpl implements Game, Serializable { // used to proceed player conceding requests private final LinkedList concedingPlayers = new LinkedList<>(); // used to handle asynchronous request of a player to leave the game - public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { + public GameImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { this.id = UUID.randomUUID(); this.range = range; - this.freeMulligans = freeMulligans; + this.mulligan = mulligan; this.attackOption = attackOption; this.state = new GameState(); this.startLife = startLife; this.executingRollback = false; + initGameDefaultWatchers(); } public GameImpl(final GameImpl game) { - long t1 = 0; - if (logger.isDebugEnabled()) { - t1 = System.currentTimeMillis(); - } this.id = game.id; this.ready = game.ready; this.startingPlayerId = game.startingPlayerId; this.winnerId = game.winnerId; this.range = game.range; - this.freeMulligans = game.freeMulligans; + this.mulligan = game.getMulligan().copy(); this.attackOption = game.attackOption; this.state = game.state.copy(); this.gameCards = game.gameCards; @@ -172,10 +168,7 @@ public abstract class GameImpl implements Game, Serializable { this.lkiExtended.putAll(game.lkiExtended); this.shortLivingLKI.putAll(game.shortLivingLKI); this.permanentsEntering.putAll(game.permanentsEntering); - if (logger.isDebugEnabled()) { - copyCount++; - copyTime += (System.currentTimeMillis() - t1); - } + this.stateCheckRequired = game.stateCheckRequired; this.scorePlayer = game.scorePlayer; this.scopeRelevant = game.scopeRelevant; @@ -259,6 +252,7 @@ public abstract class GameImpl implements Game, Serializable { public void addPlayer(Player player, Deck deck) { player.useDeck(deck, this); state.addPlayer(player); + initPlayerDefaultWatchers(player.getId()); } @Override @@ -504,7 +498,7 @@ public abstract class GameImpl implements Game, Serializable { return Optional.empty(); } -// @Override + // @Override // public Zone getZone(UUID objectId) { // return state.getZone(objectId); // } @@ -532,7 +526,7 @@ public abstract class GameImpl implements Game, Serializable { } } -// /** + // /** // * Starts check if game is over or if playerId is given let the player // * concede. // * @@ -966,66 +960,9 @@ public abstract class GameImpl implements Game, Serializable { } //20091005 - 103.4 - List keepPlayers = new ArrayList<>(); - List mulliganPlayers = new ArrayList<>(); - do { - mulliganPlayers.clear(); - for (UUID playerId : state.getPlayerList(startingPlayerId)) { - if (!keepPlayers.contains(playerId)) { - Player player = getPlayer(playerId); - boolean keep = true; - while (true) { - if (player.getHand().isEmpty()) { - break; - } - GameEvent event = new GameEvent(GameEvent.EventType.CAN_TAKE_MULLIGAN, null, null, playerId); - if (!replaceEvent(event)) { - fireEvent(event); - getState().setChoosingPlayerId(playerId); - if (player.chooseMulligan(this)) { - keep = false; - } - break; - } - } - if (keep) { - endMulligan(player.getId()); - keepPlayers.add(playerId); - fireInformEvent(player.getLogName() + " keeps hand"); - } else { - mulliganPlayers.add(playerId); - fireInformEvent(player.getLogName() + " decides to take mulligan"); - } - } - } - for (UUID mulliganPlayerId : mulliganPlayers) { - mulligan(mulliganPlayerId); - } - saveState(false); - } while (!mulliganPlayers.isEmpty()); - // new scry rule - for (UUID playerId : state.getPlayerList(startingPlayerId)) { - Player player = getPlayer(playerId); - if (player != null && player.getHand().size() < startingHandSize) { - player.scry(1, null, this); - } - } + mulligan.executeMulliganPhase(this, startingHandSize); getState().setChoosingPlayerId(null); - state.getWatchers().reset(); // watcher objects from cards are reused during match so reset all card watchers already added - Watchers watchers = state.getWatchers(); - // add default watchers - for (UUID playerId : state.getPlayerList(startingPlayerId)) { - watchers.add(new PlayerDamagedBySourceWatcher(playerId)); - watchers.add(new BloodthirstWatcher(playerId)); - } - watchers.add(new MorbidWatcher()); - watchers.add(new CastSpellLastTurnWatcher()); - watchers.add(new CastSpellYourLastTurnWatcher()); - watchers.add(new PlayerLostLifeWatcher()); - watchers.add(new PlayerLostLifeNonCombatWatcher()); - watchers.add(new BlockedAttackerWatcher()); - watchers.add(new DamageDoneWatcher()); - watchers.add(new PlanarRollWatcher()); + state.resetWatchers(); // watcher objects from cards are reused during match so reset all card watchers already added //20100716 - 103.5 for (UUID playerId : state.getPlayerList(startingPlayerId)) { @@ -1074,6 +1011,24 @@ public abstract class GameImpl implements Game, Serializable { } } + + public void initGameDefaultWatchers() { + getState().addWatcher(new MorbidWatcher()); + getState().addWatcher(new CastSpellLastTurnWatcher()); + getState().addWatcher(new CastSpellYourLastTurnWatcher()); + getState().addWatcher(new PlayerLostLifeWatcher()); + getState().addWatcher(new PlayerLostLifeNonCombatWatcher()); + getState().addWatcher(new BlockedAttackerWatcher()); + getState().addWatcher(new DamageDoneWatcher()); + getState().addWatcher(new PlanarRollWatcher()); + getState().addWatcher(new PlayersAttackedThisTurnWatcher()); + } + + public void initPlayerDefaultWatchers(UUID playerId) { + getState().addWatcher(new PlayerDamagedBySourceWatcher(playerId)); + getState().addWatcher(new BloodthirstWatcher(playerId)); + } + protected void sendStartMessage(Player choosingPlayer, Player startingPlayer) { StringBuilder message = new StringBuilder(); if (choosingPlayer != null) { @@ -1116,7 +1071,7 @@ public abstract class GameImpl implements Game, Serializable { for (Player player : getPlayers().values()) { player.endOfTurn(this); } - state.getWatchers().reset(); + state.resetWatchers(); } protected UUID pickChoosingPlayer() { @@ -1163,51 +1118,17 @@ public abstract class GameImpl implements Game, Serializable { @Override public int mulliganDownTo(UUID playerId) { - Player player = getPlayer(playerId); - int deduction = 1; - if (freeMulligans > 0) { - if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { - int used = usedFreeMulligans.get(player.getId()); - if (used < freeMulligans) { - deduction = 0; - } - } else { - deduction = 0; - } - } - return player.getHand().size() - deduction; + return mulligan.mulliganDownTo(this, playerId); } @Override public void endMulligan(UUID playerId) { + mulligan.endMulligan(this, playerId); } @Override public void mulligan(UUID playerId) { - Player player = getPlayer(playerId); - int numCards = player.getHand().size(); - player.getLibrary().addAll(player.getHand().getCards(this), this); - player.getHand().clear(); - player.shuffleLibrary(null, this); - int deduction = 1; - if (freeMulligans > 0) { - if (usedFreeMulligans.containsKey(player.getId())) { - int used = usedFreeMulligans.get(player.getId()); - if (used < freeMulligans) { - deduction = 0; - usedFreeMulligans.put(player.getId(), used + 1); - } - } else { - deduction = 0; - usedFreeMulligans.put(player.getId(), 1); - } - } - fireInformEvent(new StringBuilder(player.getLogName()) - .append(" mulligans") - .append(deduction == 0 ? " for free and draws " : " down to ") - .append(Integer.toString(numCards - deduction)) - .append(numCards - deduction == 1 ? " card" : " cards").toString()); - player.drawCards(numCards - deduction, this); + mulligan.mulligan(this, playerId); } @Override @@ -1527,7 +1448,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void addEffect(ContinuousEffect continuousEffect, Ability source) { Ability newAbility = source.copy(); - newAbility.setSourceObject(null, this); // Update the source object to the currently existing Object + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId())); ContinuousEffect newEffect = continuousEffect.copy(); newEffect.newId(); @@ -1542,10 +1463,9 @@ public abstract class GameImpl implements Game, Serializable { } /** - * * @param emblem * @param sourceObject - * @param toPlayerId controller and owner of the emblem + * @param toPlayerId controller and owner of the emblem */ @Override public void addEmblem(Emblem emblem, MageObject sourceObject, UUID toPlayerId) { @@ -1561,11 +1481,10 @@ public abstract class GameImpl implements Game, Serializable { } /** - * * @param plane * @param sourceObject - * @param toPlayerId controller and owner of the plane (may only be one per - * game..) + * @param toPlayerId controller and owner of the plane (may only be one per + * game..) * @return boolean - whether the plane was added successfully or not */ @Override @@ -1637,6 +1556,7 @@ public abstract class GameImpl implements Game, Serializable { if (newBluePrint == null) { newBluePrint = copyFromPermanent.copy(); newBluePrint.reset(this); + //getState().addCard(permanent); if (copyFromPermanent.isMorphed() || copyFromPermanent.isManifested()) { MorphAbility.setPermanentToFaceDownCreature(newBluePrint); @@ -1650,6 +1570,9 @@ public abstract class GameImpl implements Game, Serializable { applier.apply(this, newBluePrint, source, copyToPermanentId); } + // save original copy link (handle copy of copies too) + newBluePrint.setCopy(true, (copyFromPermanent.getCopyFrom() != null ? copyFromPermanent.getCopyFrom() : copyFromPermanent)); + CopyEffect newEffect = new CopyEffect(duration, newBluePrint, copyToPermanentId); newEffect.newId(); newEffect.setApplier(applier); @@ -1698,11 +1621,17 @@ public abstract class GameImpl implements Game, Serializable { if (ability instanceof TriggeredManaAbility || ability instanceof DelayedTriggeredManaAbility) { // 20110715 - 605.4 Ability manaAbiltiy = ability.copy(); + if (manaAbiltiy.getSourceObjectZoneChangeCounter() == 0) { + manaAbiltiy.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId())); + } manaAbiltiy.activate(this, false); manaAbiltiy.resolve(this); } else { TriggeredAbility newAbility = ability.copy(); newAbility.newId(); + if (newAbility.getSourceObjectZoneChangeCounter() == 0) { + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(ability.getSourceId())); + } state.addTriggeredAbility(newAbility); } } @@ -1711,10 +1640,10 @@ public abstract class GameImpl implements Game, Serializable { public UUID addDelayedTriggeredAbility(DelayedTriggeredAbility delayedAbility, Ability source) { delayedAbility.setSourceId(source.getSourceId()); delayedAbility.setControllerId(source.getControllerId()); - delayedAbility.setSourceObject(source.getSourceObject(this), this); // return addDelayedTriggeredAbility(delayedAbility); DelayedTriggeredAbility newAbility = delayedAbility.copy(); newAbility.newId(); + newAbility.setSourceObjectZoneChangeCounter(getState().getZoneChangeCounter(source.getSourceId())); newAbility.initOnAdding(this); // ability.init is called as the ability triggeres not now. // If a FixedTarget pointer is already set from the effect setting up this delayed ability @@ -1784,7 +1713,7 @@ public abstract class GameImpl implements Game, Serializable { break; } // triggered abilities that don't use the stack have to be executed first (e.g. Banisher Priest Return exiled creature - for (Iterator it = abilities.iterator(); it.hasNext();) { + for (Iterator it = abilities.iterator(); it.hasNext(); ) { TriggeredAbility triggeredAbility = it.next(); if (!triggeredAbility.isUsesStack()) { state.removeTriggeredAbility(triggeredAbility); @@ -1969,7 +1898,7 @@ public abstract class GameImpl implements Game, Serializable { if ((ability instanceof SpellAbility) && SpellAbilityType.BASE_ALTERNATE == ((SpellAbility) ability).getSpellAbilityType() && !ability.getTargets().isEmpty()) { - spellAbility = (SpellAbility) ability; + spellAbility = ability; break; } } @@ -2519,7 +2448,7 @@ public abstract class GameImpl implements Game, Serializable { } //20100423 - 800.4a Set toOutside = new HashSet<>(); - for (Iterator it = getBattlefield().getAllPermanents().iterator(); it.hasNext();) { + for (Iterator it = getBattlefield().getAllPermanents().iterator(); it.hasNext(); ) { Permanent perm = it.next(); if (perm.isOwnedBy(playerId)) { if (perm.getAttachedTo() != null) { @@ -2562,7 +2491,7 @@ public abstract class GameImpl implements Game, Serializable { player.moveCards(toOutside, Zone.OUTSIDE, null, this); // triggered abilities that don't use the stack have to be executed List abilities = state.getTriggered(player.getId()); - for (Iterator it = abilities.iterator(); it.hasNext();) { + for (Iterator it = abilities.iterator(); it.hasNext(); ) { TriggeredAbility triggeredAbility = it.next(); if (!triggeredAbility.isUsesStack()) { state.removeTriggeredAbility(triggeredAbility); @@ -2582,7 +2511,7 @@ public abstract class GameImpl implements Game, Serializable { // Remove cards from the player in all exile zones for (ExileZone exile : this.getExile().getExileZones()) { - for (Iterator it = exile.iterator(); it.hasNext();) { + for (Iterator it = exile.iterator(); it.hasNext(); ) { Card card = this.getCard(it.next()); if (card != null && card.isOwnedBy(playerId)) { it.remove(); @@ -2592,9 +2521,9 @@ public abstract class GameImpl implements Game, Serializable { //Remove all commander/emblems/plane the player controls boolean addPlaneAgain = false; - for (Iterator it = this.getState().getCommand().iterator(); it.hasNext();) { + for (Iterator it = this.getState().getCommand().iterator(); it.hasNext(); ) { CommandObject obj = it.next(); - if (obj.getControllerId().equals(playerId)) { + if (obj.isControlledBy(playerId)) { if (obj instanceof Emblem) { ((Emblem) obj).discardEffects();// This may not be the best fix but it works } @@ -2728,7 +2657,7 @@ public abstract class GameImpl implements Game, Serializable { } if (!game.isSimulation()) { StringBuilder message = new StringBuilder(preventionSource.getLogName()).append(": Prevented "); - message.append(Integer.toString(result.getPreventedDamage())).append(" damage from ").append(damageSource.getLogName()); + message.append(result.getPreventedDamage()).append(" damage from ").append(damageSource.getLogName()); if (!targetName.isEmpty()) { message.append(" to ").append(targetName); } @@ -2763,7 +2692,7 @@ public abstract class GameImpl implements Game, Serializable { * Gets last known information about object in the zone. At the moment * doesn't take into account zone (it is expected that it doesn't really * matter, if not, then Map> should be used instead). - * + *

    * Can return null. * * @param objectId @@ -3118,7 +3047,7 @@ public abstract class GameImpl implements Game, Serializable { public void saveRollBackGameState() { if (gameOptions.rollbackTurnsAllowed) { int toDelete = getTurnNum() - ROLLBACK_TURNS_MAX; - if (toDelete > 0 && gameStatesRollBack.containsKey(toDelete)) { + if (toDelete > 0) { gameStatesRollBack.remove(toDelete); } gameStatesRollBack.put(getTurnNum(), state.copy()); @@ -3170,9 +3099,7 @@ public abstract class GameImpl implements Game, Serializable { @Override public void setEnterWithCounters(UUID sourceId, Counters counters) { if (counters == null) { - if (enterWithCounters.containsKey(sourceId)) { - enterWithCounters.remove(sourceId); - } + enterWithCounters.remove(sourceId); return; } enterWithCounters.put(sourceId, counters); @@ -3237,4 +3164,10 @@ public abstract class GameImpl implements Game, Serializable { } return 0; } + + @Override + public Mulligan getMulligan() { + return mulligan; + } + } diff --git a/Mage/src/main/java/mage/game/GameState.java b/Mage/src/main/java/mage/game/GameState.java index e18fc41b72..1c71d6c6f2 100644 --- a/Mage/src/main/java/mage/game/GameState.java +++ b/Mage/src/main/java/mage/game/GameState.java @@ -1,8 +1,5 @@ package mage.game; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; import mage.MageObject; import mage.abilities.*; import mage.abilities.effects.ContinuousEffect; @@ -35,15 +32,17 @@ import mage.util.ThreadLocalStringBuilder; import mage.watchers.Watcher; import mage.watchers.Watchers; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + /** - * * @author BetaSteward_at_googlemail.com - * + *

    * since at any time the game state may be copied and restored you cannot rely * on any object maintaining it's instance it then becomes necessary to only * refer to objects by their ids since these will always remain constant * throughout its lifetime - * */ public class GameState implements Serializable, Copyable { @@ -532,8 +531,16 @@ public class GameState implements Serializable, Copyable { return this.turnMods; } - public Watchers getWatchers() { - return this.watchers; + public T getWatcher(Class watcherClass) { + return watcherClass.cast(watchers.get(watcherClass.getSimpleName())); + } + + public T getWatcher(Class watcherClass, UUID uuid) { + return watcherClass.cast(watchers.get(watcherClass.getSimpleName(), uuid.toString())); + } + + public T getWatcher(Class watcherClass, String prefix) { + return watcherClass.cast(watchers.get(watcherClass.getSimpleName(), prefix)); } public SpecialActions getSpecialActions() { @@ -572,6 +579,7 @@ public class GameState implements Serializable, Copyable { public void removeEotEffects(Game game) { effects.removeEndOfTurnEffects(); delayed.removeEndOfTurnAbilities(); + exile.cleanupEndOfTurnZones(game); game.applyEffects(); } @@ -590,6 +598,7 @@ public class GameState implements Serializable, Copyable { // public void addMessage(String message) { // this.messages.add(message); // } + /** * Returns a list of all players of the game ignoring range or if a player * has lost or left the game. @@ -758,12 +767,14 @@ public class GameState implements Serializable, Copyable { } for (Map.Entry> entry : eventsByKey.entrySet()) { Set movedCards = new LinkedHashSet<>(); - for (Iterator it = entry.getValue().iterator(); it.hasNext();) { + for (Iterator it = entry.getValue().iterator(); it.hasNext(); ) { GameEvent event = it.next(); ZoneChangeEvent castEvent = (ZoneChangeEvent) event; UUID targetId = castEvent.getTargetId(); Card card = game.getCard(targetId); - movedCards.add(card); + if (card != null) { + movedCards.add(card); + } } ZoneChangeData eventData = entry.getKey(); if (!movedCards.isEmpty()) { @@ -943,7 +954,7 @@ public class GameState implements Serializable, Copyable { /** * Other abilities are used to implement some special kind of continuous * effects that give abilities to non permanents. - * + *

    * Crucible of Worlds - You may play land cards from your graveyard. Past in * Flames - Each instant and sorcery card in your graveyard gains flashback * until end of turn. The flashback cost is equal to its mana cost. Varolz, @@ -984,7 +995,7 @@ public class GameState implements Serializable, Copyable { * @param attachedTo * @param ability * @param copyAbility copies non MageSingleton abilities before adding to - * state + * state */ public void addOtherAbility(Card attachedTo, Ability ability, boolean copyAbility) { Ability newAbility; @@ -1104,6 +1115,10 @@ public class GameState implements Serializable, Copyable { this.watchers.add(watcher); } + public void resetWatchers() { + this.watchers.reset(); + } + public int getZoneChangeCounter(UUID objectId) { return zoneChangeCounter.getOrDefault(objectId, 1); } @@ -1134,7 +1149,7 @@ public class GameState implements Serializable, Copyable { Card copiedCard = cardToCopy.copy(); copiedCard.assignNewId(); copiedCard.setOwnerId(source.getControllerId()); - copiedCard.setCopy(true); + copiedCard.setCopy(true, cardToCopy); copiedCards.put(copiedCard.getId(), copiedCard); addCard(copiedCard); if (copiedCard.isSplitCard()) { diff --git a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java index 768fe8efd8..78c7fdb0ec 100644 --- a/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java +++ b/Mage/src/main/java/mage/game/GameTinyLeadersImpl.java @@ -16,6 +16,7 @@ import mage.cards.CardSetInfo; import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.*; +import mage.game.mulligan.Mulligan; import mage.game.turn.TurnMod; import mage.players.Player; import mage.watchers.common.CommanderInfoWatcher; @@ -30,8 +31,8 @@ public abstract class GameTinyLeadersImpl extends GameImpl { protected boolean alsoLibrary; // replace also commander going to library protected boolean startingPlayerSkipsDraw = true; - public GameTinyLeadersImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, int freeMulligans, int startLife) { - super(attackOption, range, freeMulligans, startLife); + public GameTinyLeadersImpl(MultiplayerAttackOption attackOption, RangeOfInfluence range, Mulligan mulligan, int startLife) { + super(attackOption, range, mulligan, startLife); } public GameTinyLeadersImpl(final GameTinyLeadersImpl game) { @@ -60,7 +61,7 @@ public abstract class GameTinyLeadersImpl extends GameImpl { // ability.addEffect(new CommanderManaReplacementEffect(player.getId(), CardUtil.getColorIdentity(commander))); getState().setValue(commander.getId() + "_castCount", 0); CommanderInfoWatcher watcher = new CommanderInfoWatcher(commander.getId(), false); - getState().getWatchers().add(watcher); + getState().addWatcher(watcher); watcher.addCardInfoToCommander(this); } else { throw new UnknownError("Commander card could not be created. Name: [" + player.getMatchPlayer().getDeck().getName() + ']'); diff --git a/Mage/src/main/java/mage/game/Table.java b/Mage/src/main/java/mage/game/Table.java index 5b6f223021..eba4df35c6 100644 --- a/Mage/src/main/java/mage/game/Table.java +++ b/Mage/src/main/java/mage/game/Table.java @@ -298,8 +298,8 @@ public class Table implements Serializable { .setGameType(this.getGameType()) .setDeckType(this.getDeckType()) .setControllerName(this.getControllerName()) - .setStartTimeMs(this.getStartTime().getTime()) - .setEndTimeMs(this.getEndTime().getTime()) + .setStartTimeMs(this.getStartTime() != null ? this.getStartTime().getTime() : 0L) + .setEndTimeMs(this.getEndTime() != null ? this.getEndTime().getTime() : 0L) .build(); } } diff --git a/Mage/src/main/java/mage/game/combat/Combat.java b/Mage/src/main/java/mage/game/combat/Combat.java index 5b56d49347..990147a783 100644 --- a/Mage/src/main/java/mage/game/combat/Combat.java +++ b/Mage/src/main/java/mage/game/combat/Combat.java @@ -1,4 +1,3 @@ - package mage.game.combat; import mage.MageObject; @@ -6,6 +5,7 @@ import mage.abilities.Ability; import mage.abilities.effects.RequirementEffect; import mage.abilities.effects.RestrictionEffect; import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.special.JohanVigilanceAbility; import mage.constants.Outcome; @@ -14,8 +14,12 @@ import mage.filter.StaticFilters; import mage.filter.common.FilterControlledCreaturePermanent; import mage.filter.common.FilterCreatureForCombatBlock; import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.mageobject.NamePredicate; +import mage.filter.predicate.mageobject.SubtypePredicate; +import mage.filter.predicate.mageobject.SupertypePredicate; import mage.filter.predicate.permanent.AttackingSameNotBandedPredicate; import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.Game; @@ -103,8 +107,8 @@ public class Combat implements Serializable, Copyable { } /** - * Get all possible defender (players and plainwalkers) That does not mean - * neccessarly mean that they are really attacked + * Get all possible defender (players and planeswalkers) That does not mean + * necessarily mean that they are really attacked * * @return */ @@ -246,11 +250,14 @@ public class Combat implements Serializable, Copyable { game.getCombat().checkAttackRequirements(player, game); boolean firstTime = true; do { - if (!firstTime || !game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) { + if (!firstTime + || !game.getPlayer(game.getActivePlayerId()).getAvailableAttackers(game).isEmpty()) { player.selectAttackers(game, attackingPlayerId); } firstTime = false; - if (game.isPaused() || game.checkIfGameIsOver() || game.executingRollback()) { + if (game.isPaused() + || game.checkIfGameIsOver() + || game.executingRollback()) { return; } // because of possible undo during declare attackers it's neccassary to call here the methods with "game.getCombat()." to get the current combat object!!! @@ -268,7 +275,7 @@ public class Combat implements Serializable, Copyable { Permanent attackingPermanent = game.getPermanent(attacker); if (attackingPermanent != null) { attackingPermanent.setTapped(false); - attackingPermanent.tap(game); // to tap with event finally here is needed to prevent abusing of Vampire Envoy like cards + attackingPermanent.tap(true, game); // to tap with event finally here is needed to prevent abusing of Vampire Envoy like cards } } handleBanding(attacker, game); @@ -291,55 +298,125 @@ public class Combat implements Serializable, Copyable { private void handleBanding(UUID creatureId, Game game) { Player player = game.getPlayer(attackingPlayerId); Permanent attacker = game.getPermanent(creatureId); - if (attacker != null && player != null) { + if (attacker != null + && player != null) { CombatGroup combatGroup = findGroup(attacker.getId()); - if (combatGroup != null && attacker.getAbilities().containsKey(BandingAbility.getInstance().getId()) && attacker.getBandedCards().isEmpty() && getAttackers().size() > 1) { - boolean isBanded = false; - FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature to band with " + attacker.getLogName()); - filter.add(Predicates.not(new PermanentIdPredicate(creatureId))); - filter.add(new AttackingSameNotBandedPredicate(combatGroup.getDefenderId())); // creature that isn't already banded, and is attacking the same player or planeswalker - while (player.canRespond()) { - TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); - target.setRequired(false); - if (!target.canChoose(attackingPlayerId, game) - || game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, attackingPlayerId, attackingPlayerId)) - || !player.chooseUse(Outcome.Benefit, "Do you wish to " + (isBanded ? "band " + attacker.getLogName() + " with another " : "form a band with " + attacker.getLogName() + " and an ") + "attacking creature?", null, game)) { - break; - } - if (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) { - isBanded = true; - for (UUID targetId : target.getTargets()) { - Permanent permanent = game.getPermanent(targetId); - if (permanent != null) { - - for (UUID bandedId : attacker.getBandedCards()) { - permanent.addBandedCard(bandedId); - Permanent banded = game.getPermanent(bandedId); - if (banded != null) { - banded.addBandedCard(targetId); - } - } - permanent.addBandedCard(creatureId); - attacker.addBandedCard(targetId); - if (!permanent.getAbilities().containsKey(BandingAbility.getInstance().getId())) { - filter.add(new AbilityPredicate(BandingAbility.class)); - } - } - - } + if (combatGroup != null + && attacker.getBandedCards().isEmpty() + && getAttackers().size() > 1) { + boolean canBand = attacker.getAbilities().containsKey(BandingAbility.getInstance().getId()); + List bandsWithOther = new ArrayList<>(); + for (Ability ability : attacker.getAbilities()) { + if (ability.getClass().equals(BandsWithOtherAbility.class)) { + bandsWithOther.add(ability); } } - if (isBanded) { - StringBuilder sb = new StringBuilder(player.getLogName()).append(" formed a band with ").append((attacker.getBandedCards().size() + 1) + " creatures: "); - sb.append(attacker.getLogName()); - for (UUID id : attacker.getBandedCards()) { - sb.append(", "); - Permanent permanent = game.getPermanent(id); - if (permanent != null) { - sb.append(permanent.getLogName()); + boolean canBandWithOther = !bandsWithOther.isEmpty(); + if (canBand || canBandWithOther) { + boolean isBanded = false; + FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("attacking creature to band with " + attacker.getLogName()); + filter.add(Predicates.not(new PermanentIdPredicate(creatureId))); + filter.add(new AttackingSameNotBandedPredicate(combatGroup.getDefenderId())); // creature that isn't already banded, and is attacking the same player or planeswalker + List> predicates = new ArrayList<>(); + if (!canBand + && canBandWithOther) { + for (Ability ab : bandsWithOther) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + predicates.add(new SubtypePredicate(ability.getSubtype())); + } + if (ability.getSupertype() != null) { + predicates.add(new SupertypePredicate(ability.getSupertype())); + } + if (ability.getName() != null) { + predicates.add(new NamePredicate(ability.getName())); + } + } + filter.add(Predicates.or(predicates)); + } + while (player.canRespond()) { + TargetControlledPermanent target = new TargetControlledPermanent(1, 1, filter, true); + target.setRequired(false); + canBand &= target.canChoose(attackingPlayerId, game); + canBandWithOther &= target.canChoose(attackingPlayerId, game); + if (game.replaceEvent(GameEvent.getEvent(GameEvent.EventType.DECLARING_ATTACKERS, attackingPlayerId, attackingPlayerId)) + || (!canBand && !canBandWithOther) + || !player.chooseUse(Outcome.Benefit, + "Do you wish to " + (isBanded ? "band " + attacker.getLogName() + + " with another " : "form a band with " + attacker.getLogName() + " and an ") + + "attacking creature?", null, game)) { + break; + } + + if (canBand && canBandWithOther) { + if (player.chooseUse(Outcome.Detriment, "Choose type of banding ability to apply:", + attacker.getLogName(), "Banding", "Bands with other", null, game)) { + canBandWithOther = false; + } else { + canBand = false; + for (Ability ab : bandsWithOther) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + predicates.add(new SubtypePredicate(ability.getSubtype())); + } + if (ability.getSupertype() != null) { + predicates.add(new SupertypePredicate(ability.getSupertype())); + } + if (ability.getName() != null) { + predicates.add(new NamePredicate(ability.getName())); + } + } + filter.add(Predicates.or(predicates)); + } + } + + if (target.choose(Outcome.Benefit, attackingPlayerId, null, game)) { + isBanded = true; + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + + for (UUID bandedId : attacker.getBandedCards()) { + permanent.addBandedCard(bandedId); + Permanent banded = game.getPermanent(bandedId); + if (banded != null) { + banded.addBandedCard(targetId); + } + } + permanent.addBandedCard(creatureId); + attacker.addBandedCard(targetId); + if (canBand) { + if (!permanent.getAbilities().containsKey(BandingAbility.getInstance().getId())) { + filter.add(new AbilityPredicate(BandingAbility.class)); + canBandWithOther = false; + } + } else if (canBandWithOther) { + List> newPredicates = new ArrayList<>(); + for (Predicate predicate : predicates) { + if (predicate.apply(permanent, game)) { + newPredicates.add(predicate); + } + } + filter.add(Predicates.or(newPredicates)); + canBand = false; + } + } + + } } } - game.informPlayers(sb.toString()); + if (isBanded) { + StringBuilder sb = new StringBuilder(player.getLogName()).append(" formed a band with ").append((attacker.getBandedCards().size() + 1) + " creatures: "); + sb.append(attacker.getLogName()); + for (UUID id : attacker.getBandedCards()) { + sb.append(", "); + Permanent permanent = game.getPermanent(id); + if (permanent != null) { + sb.append(permanent.getLogName()); + } + } + game.informPlayers(sb.toString()); + } } } } @@ -387,11 +464,15 @@ public class Combat implements Serializable, Copyable { if (defenders.size() == 1) { player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); } else { - TargetDefender target = new TargetDefender(defenders, creature.getId()); - target.setRequired(true); - target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack"); - if (player.chooseTarget(Outcome.Damage, target, null, game)) { - player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); + if (!player.isHuman()) { // computer only for multiple defenders + player.declareAttacker(creature.getId(), defenders.iterator().next(), game, false); + } else { // human players only for multiple defenders + TargetDefender target = new TargetDefender(defenders, creature.getId()); + target.setRequired(true); + target.setTargetName("planeswalker or player for " + creature.getLogName() + " to attack"); + if (player.chooseTarget(Outcome.Damage, target, null, game)) { + player.declareAttacker(creature.getId(), target.getFirstTarget(), game, false); + } } } } else { @@ -439,9 +520,10 @@ public class Combat implements Serializable, Copyable { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canAttackCheckAfter(numberAttackers, ability, game)) { + if (!effect.canAttackCheckAfter(numberAttackers, ability, game, true)) { MageObject sourceObject = ability.getSourceObject(game); if (attackingPlayer.isHuman()) { + attackingPlayer.resetPlayerPassedActions(); game.informPlayer(attackingPlayer, attackingCreature.getIdName() + " can't attack this way (" + (sourceObject == null ? "null" : sourceObject.getIdName()) + ')'); return false; } else { @@ -482,7 +564,7 @@ public class Combat implements Serializable, Copyable { /** * Handle the blocker selection process * - * @param blockController player that controlls how to block, if null the + * @param blockController player that controls how to block, if null the * defender is the controller * @param game */ @@ -671,8 +753,8 @@ public class Combat implements Serializable, Copyable { * creature can't block unless a player pays a cost, that player is not * required to pay that cost, even if blocking with that creature would * increase the number of requirements being obeyed. - * - * + *

    + *

    * Example: A player controls one creature that "blocks if able" and another * creature with no abilities. An effect states "Creatures can't be blocked * except by two or more creatures." Having only the first creature block @@ -775,9 +857,8 @@ public class Combat implements Serializable, Copyable { // if creature can block more attackers, inform human player or set blocks for AI player if (mayBlock) { if (controller.isHuman()) { - if (!game.isSimulation()) { - game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName()); - } + controller.resetPlayerPassedActions(); + game.informPlayer(controller, "Creature should block all attackers it's able to this turn: " + creature.getIdName()); } else { Player defender = game.getPlayer(creature.getControllerId()); if (defender != null) { @@ -866,9 +947,8 @@ public class Combat implements Serializable, Copyable { // if creature can block, inform human player or set block for AI player if (mayBlock) { if (controller.isHuman()) { - if (!game.isSimulation()) { - game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName()); - } + controller.resetPlayerPassedActions(); + game.informPlayer(controller, "Creature should block this turn: " + creature.getIdName()); } else { Player defender = game.getPlayer(creature.getControllerId()); if (defender != null) { @@ -920,6 +1000,7 @@ public class Combat implements Serializable, Copyable { possibleBlockerId, toBeBlockedCreatureId, mustBeBlockedByAtLeastX, game); if (blockRequiredMessage != null) { // message means not required removeBlocker(possibleBlockerId, game); + controller.resetPlayerPassedActions(); game.informPlayer(controller, blockRequiredMessage + " Existing block removed. It's a requirement to block " + toBeBlockedCreature.getIdName() + '.'); return false; } @@ -964,21 +1045,6 @@ public class Combat implements Serializable, Copyable { // ignore creatures controlled by other players continue; } - -// // check if creature has to pay a cost to block so it's not mandatory to block -// boolean removedAttacker = false; -// for (Iterator iterator = entry.getValue().iterator(); iterator.hasNext();) { -// UUID possibleAttackerId = iterator.next(); -// if (game.getContinuousEffects().checkIfThereArePayCostToAttackBlockEffects( -// GameEvent.getEvent(GameEvent.EventType.DECLARE_BLOCKER, possibleAttackerId, creatureForcedToBlock.getId(), creatureForcedToBlock.getControllerId()), game)) { -// // has cost to block to pay so remove this attacker -// iterator.remove(); -// removedAttacker = true; -// } -// } -// if (removedAttacker && entry.getValue().isEmpty()) { -// continue; -// } // creature does not block -> not allowed // Check if blocker is really able to block one or more attackers (maybe not if the attacker has menace) - if not continue with the next forced blocker // TODO: Probably there is some potential to abuse the check if forced blockers are assigned to differnt attackers with e.g. menace. @@ -1029,7 +1095,8 @@ public class Combat implements Serializable, Copyable { } } if (sb.length() > 0) { - if (!game.isSimulation()) { + if (controller.isHuman()) { + controller.resetPlayerPassedActions(); sb.insert(0, "Some creatures are forced to block certain attacker(s):\n"); sb.append("\nPlease block with each of these creatures an appropriate attacker."); game.informPlayer(controller, sb.toString()); @@ -1112,8 +1179,9 @@ public class Combat implements Serializable, Copyable { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(blockingCreature, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canBlockCheckAfter(ability, game)) { + if (!effect.canBlockCheckAfter(ability, game, true)) { if (controller.isHuman()) { + controller.resetPlayerPassedActions(); game.informPlayer(controller, blockingCreature.getLogName() + " can't block this way."); return false; } else { @@ -1132,8 +1200,9 @@ public class Combat implements Serializable, Copyable { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(attackingCreature, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canBeBlockedCheckAfter(attackingCreature, ability, game)) { + if (!effect.canBeBlockedCheckAfter(attackingCreature, ability, game, true)) { if (controller.isHuman()) { + controller.resetPlayerPassedActions(); game.informPlayer(controller, attackingCreature.getLogName() + " can't be blocked this way."); return false; } else { @@ -1274,11 +1343,12 @@ public class Combat implements Serializable, Copyable { } if (defenderAttackedBy.size() >= defendingPlayer.getMaxAttackedBy()) { Player attackingPlayer = game.getPlayer(game.getControllerId(attackerId)); - if (attackingPlayer != null && !game.isSimulation()) { - game.informPlayer(attackingPlayer, "No more than " + - CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()) + - " creatures can attack " + - defendingPlayer.getLogName()); + if (attackingPlayer != null && attackingPlayer.isHuman()) { + attackingPlayer.resetPlayerPassedActions(); + game.informPlayer(attackingPlayer, "No more than " + + CardUtil.numberToText(defendingPlayer.getMaxAttackedBy()) + + " creatures can attack " + + defendingPlayer.getLogName()); } return false; } @@ -1469,6 +1539,18 @@ public class Combat implements Serializable, Copyable { return false; } + public boolean isPlaneswalkerAttacked(UUID defenderId, Game game) { + for (CombatGroup group : groups) { + if (group.defenderIsPlaneswalker) { + Permanent permanent = game.getPermanent(group.getDefenderId()); + if (permanent.isControlledBy(defenderId)) { + return true; + } + } + } + return false; + } + /** * @param attackerId * @return uuid of defending player or planeswalker @@ -1512,8 +1594,15 @@ public class Combat implements Serializable, Copyable { } public Set getPlayerDefenders(Game game) { + return getPlayerDefenders(game, true); + } + + public Set getPlayerDefenders(Game game, boolean includePlaneswalkers) { Set playerDefenders = new HashSet<>(); for (CombatGroup group : groups) { + if (group.defenderIsPlaneswalker && !includePlaneswalkers) { + continue; + } if (group.defenderIsPlaneswalker) { Permanent permanent = game.getPermanent(group.getDefenderId()); if (permanent != null) { diff --git a/Mage/src/main/java/mage/game/combat/CombatGroup.java b/Mage/src/main/java/mage/game/combat/CombatGroup.java index e357b6df97..be2f139af6 100644 --- a/Mage/src/main/java/mage/game/combat/CombatGroup.java +++ b/Mage/src/main/java/mage/game/combat/CombatGroup.java @@ -5,10 +5,12 @@ import java.io.Serializable; import java.util.*; import java.util.stream.Stream; +import mage.abilities.Ability; import mage.abilities.common.ControllerAssignCombatDamageToBlockersAbility; import mage.abilities.common.ControllerDivideCombatDamageAbility; import mage.abilities.common.DamageAsThoughNotBlockedAbility; import mage.abilities.keyword.BandingAbility; +import mage.abilities.keyword.BandsWithOtherAbility; import mage.abilities.keyword.CantBlockAloneAbility; import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DoubleStrikeAbility; @@ -110,6 +112,56 @@ public class CombatGroup implements Serializable, Copyable { return perm.getAbilities().containsKey(BandingAbility.getInstance().getId()); } + private boolean appliesBandsWithOther(List creatureIds, Game game) { + for (UUID creatureId : creatureIds) { + Permanent perm = game.getPermanent(creatureId); + if (perm != null && perm.getBandedCards() != null) { + for (Ability ab : perm.getAbilities()) { + if (ab.getClass().equals(BandsWithOtherAbility.class)) { + BandsWithOtherAbility ability = (BandsWithOtherAbility) ab; + if (ability.getSubtype() != null) { + if (perm.hasSubtype(ability.getSubtype(), game)) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.hasSubtype(ability.getSubtype(), game)) { + return true; + } + } + } + } + } + if (ability.getSupertype() != null) { + if (perm.getSuperType().contains(ability.getSupertype())) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.getSuperType().contains(ability.getSupertype())) { + return true; + } + } + } + } + } + if (ability.getName() != null) { + if (perm.getName().equals(ability.getName())) { + for (UUID bandedId : creatureIds) { + if (!bandedId.equals(creatureId)) { + Permanent banded = game.getPermanent(bandedId); + if (banded != null && banded.getName().equals(ability.getName())) { + return true; + } + } + } + } + } + } + } + } + } + return false; + } + public void assignDamageToBlockers(boolean first, Game game) { if (!attackers.isEmpty() && (!first || hasFirstOrDoubleStrike(game))) { Permanent attacker = game.getPermanent(attackers.get(0)); @@ -837,6 +889,9 @@ public class CombatGroup implements Serializable, Copyable { } } } + if (appliesBandsWithOther(attackers, game)) { // 702.21k - both a [quality] creature with “bands with other [quality]” and another [quality] creature (...) + return true; + } return false; } @@ -855,6 +910,9 @@ public class CombatGroup implements Serializable, Copyable { } } } + if (appliesBandsWithOther(blockers, game)) { // 702.21j - both a [quality] creature with “bands with other [quality]” and another [quality] creature (...) + return true; + } for (Permanent defensiveFormation : game.getBattlefield().getAllActivePermanents(defendingPlayerId)) { if (defensiveFormation.getAbilities().containsKey(ControllerAssignCombatDamageToBlockersAbility.getInstance().getId())) { return true; diff --git a/Mage/src/main/java/mage/game/command/CommandObject.java b/Mage/src/main/java/mage/game/command/CommandObject.java index b537d823ea..2a376c6b3f 100644 --- a/Mage/src/main/java/mage/game/command/CommandObject.java +++ b/Mage/src/main/java/mage/game/command/CommandObject.java @@ -3,17 +3,16 @@ package mage.game.command; import java.util.UUID; import mage.MageObject; +import mage.game.Controllable; /** * * @author Viserion, nantuko */ -public interface CommandObject extends MageObject { +public interface CommandObject extends MageObject, Controllable { UUID getSourceId(); - UUID getControllerId(); - void assignNewId(); MageObject getSourceObject(); diff --git a/Mage/src/main/java/mage/game/command/Commander.java b/Mage/src/main/java/mage/game/command/Commander.java index 966133e5dd..7163f8683e 100644 --- a/Mage/src/main/java/mage/game/command/Commander.java +++ b/Mage/src/main/java/mage/game/command/Commander.java @@ -1,10 +1,7 @@ - package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; +import mage.MageObject; import mage.ObjectColor; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; @@ -24,9 +21,15 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + public class Commander implements CommandObject { private final Card sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private final Abilities abilities = new AbilitiesImpl<>(); public Commander(Card card) { @@ -40,8 +43,10 @@ public class Commander implements CommandObject { } } - private Commander(Commander copy) { - this.sourceObject = copy.sourceObject; + private Commander(final Commander commander) { + this.sourceObject = commander.sourceObject; + this.copy = commander.copy; + this.copyFrom = (commander.copyFrom != null ? commander.copyFrom.copy() : null); } @Override @@ -68,6 +73,22 @@ public class Commander implements CommandObject { return new Commander(this); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return sourceObject.getName(); @@ -170,15 +191,6 @@ public class Commander implements CommandObject { public void adjustTargets(Ability ability, Game game) { } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public UUID getId() { return sourceObject.getId(); diff --git a/Mage/src/main/java/mage/game/command/Emblem.java b/Mage/src/main/java/mage/game/command/Emblem.java index 898a5aeb56..7a4a8896aa 100644 --- a/Mage/src/main/java/mage/game/command/Emblem.java +++ b/Mage/src/main/java/mage/game/command/Emblem.java @@ -1,9 +1,5 @@ - package mage.game.command; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -26,6 +22,10 @@ import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** * @author nantuko */ @@ -39,6 +39,8 @@ public class Emblem implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -53,6 +55,8 @@ public class Emblem implements CommandObject { this.frameStyle = emblem.frameStyle; this.controllerId = emblem.controllerId; this.sourceObject = emblem.sourceObject; + this.copy = emblem.copy; + this.copyFrom = (emblem.copyFrom != null ? emblem.copyFrom : null); this.abilites = emblem.abilites.copy(); this.expansionSetCodeForImage = emblem.expansionSetCodeForImage; } @@ -102,6 +106,22 @@ public class Emblem implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -205,15 +225,6 @@ public class Emblem implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Emblem copy() { return new Emblem(this); diff --git a/Mage/src/main/java/mage/game/command/Plane.java b/Mage/src/main/java/mage/game/command/Plane.java index b6a3768c29..d06d5b355b 100644 --- a/Mage/src/main/java/mage/game/command/Plane.java +++ b/Mage/src/main/java/mage/game/command/Plane.java @@ -1,12 +1,5 @@ - package mage.game.command; -import static java.lang.Math.log; -import java.lang.reflect.Constructor; -import java.util.EnumSet; -import java.util.List; -import java.util.Random; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; @@ -28,8 +21,14 @@ import mage.constants.SuperType; import mage.game.Game; import mage.game.events.ZoneChangeEvent; import mage.util.GameLog; +import mage.util.RandomUtil; import mage.util.SubTypeList; +import java.lang.reflect.Constructor; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** * @author spjspj */ @@ -43,6 +42,8 @@ public class Plane implements CommandObject { private UUID id; private UUID controllerId; private MageObject sourceObject; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private FrameStyle frameStyle; private Abilities abilites = new AbilitiesImpl<>(); private String expansionSetCodeForImage = ""; @@ -58,6 +59,8 @@ public class Plane implements CommandObject { this.frameStyle = plane.frameStyle; this.controllerId = plane.controllerId; this.sourceObject = plane.sourceObject; + this.copy = plane.copy; + this.copyFrom = (plane.copyFrom != null ? plane.copyFrom.copy() : null); this.abilites = plane.abilites.copy(); this.expansionSetCodeForImage = plane.expansionSetCodeForImage; } @@ -107,6 +110,22 @@ public class Plane implements CommandObject { this.abilites.setControllerId(controllerId); } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -210,15 +229,6 @@ public class Plane implements CommandObject { return this.id; } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public Plane copy() { return new Plane(this); @@ -279,7 +289,7 @@ public class Plane implements CommandObject { } public static Plane getRandomPlane() { - int pick = new Random().nextInt(Planes.values().length); + int pick = RandomUtil.nextInt(Planes.values().length); String planeName = Planes.values()[pick].toString(); planeName = "mage.game.command.planes." + planeName; try { @@ -289,7 +299,7 @@ public class Plane implements CommandObject { if (plane instanceof Plane) { return (Plane) plane; } - } catch (Exception ex) { + } catch (Exception ex) { } return null; } diff --git a/Mage/src/main/java/mage/game/command/emblems/AurraSingBaneOfJediEmblem.java b/Mage/src/main/java/mage/game/command/emblems/AurraSingBaneOfJediEmblem.java index 8917e9a01f..30763b68c2 100644 --- a/Mage/src/main/java/mage/game/command/emblems/AurraSingBaneOfJediEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/AurraSingBaneOfJediEmblem.java @@ -18,7 +18,7 @@ public final class AurraSingBaneOfJediEmblem extends Emblem { private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a nontoken creature you control"); static { - filter.add(Predicates.not(new TokenPredicate())); + filter.add(Predicates.not(TokenPredicate.instance)); } // Whenever a nontoken creature you control leaves the battlefied, discard a card. diff --git a/Mage/src/main/java/mage/game/command/emblems/DomriChaosBringerEmblem.java b/Mage/src/main/java/mage/game/command/emblems/DomriChaosBringerEmblem.java new file mode 100644 index 0000000000..fc35e32c1a --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/DomriChaosBringerEmblem.java @@ -0,0 +1,24 @@ +package mage.game.command.emblems; + +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.effects.common.CreateTokenEffect; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.game.command.Emblem; +import mage.game.permanent.token.RedGreenBeastToken; + +/** + * @author TheElk801 + */ +public final class DomriChaosBringerEmblem extends Emblem { + + // -8: You get an emblem with "At the beginning of each end step, create a 4/4 red and green Beast creature token with trample." + public DomriChaosBringerEmblem() { + this.setName("Emblem Domri"); + this.setExpansionSetCodeForImage("RNA"); + this.getAbilities().add(new BeginningOfEndStepTriggeredAbility( + Zone.COMMAND, new CreateTokenEffect(new RedGreenBeastToken()), + TargetController.ANY, null, false + )); + } +} diff --git a/Mage/src/main/java/mage/game/command/emblems/ElspethKnightErrantEmblem.java b/Mage/src/main/java/mage/game/command/emblems/ElspethKnightErrantEmblem.java index 1789969181..b6b292b238 100644 --- a/Mage/src/main/java/mage/game/command/emblems/ElspethKnightErrantEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/ElspethKnightErrantEmblem.java @@ -14,7 +14,6 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.game.command.Emblem; /** - * * @author spjspj */ public final class ElspethKnightErrantEmblem extends Emblem { @@ -28,7 +27,7 @@ public final class ElspethKnightErrantEmblem extends Emblem { new CardTypePredicate(CardType.ENCHANTMENT), new CardTypePredicate(CardType.LAND))); Effect effect = new GainAbilityAllEffect(IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, filter, false); - effect.setText("Artifacts, creatures, enchantments, and lands you control are indestructible"); + effect.setText("Artifacts, creatures, enchantments, and lands you control have indestructible"); this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, effect)); this.setExpansionSetCodeForImage("MMA"); } diff --git a/Mage/src/main/java/mage/game/command/emblems/GarrukApexPredatorEmblem.java b/Mage/src/main/java/mage/game/command/emblems/GarrukApexPredatorEmblem.java index 63bae300ec..71d2200e31 100644 --- a/Mage/src/main/java/mage/game/command/emblems/GarrukApexPredatorEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/GarrukApexPredatorEmblem.java @@ -1,4 +1,3 @@ - package mage.game.command.emblems; import mage.abilities.Ability; @@ -13,7 +12,6 @@ import mage.constants.Zone; import mage.game.command.Emblem; /** - * * @author spjspj */ public final class GarrukApexPredatorEmblem extends Emblem { @@ -25,12 +23,12 @@ public final class GarrukApexPredatorEmblem extends Emblem { public GarrukApexPredatorEmblem() { setName("Emblem Garruk"); + Effect effect = new BoostTargetEffect(5, 5, Duration.EndOfTurn); effect.setText("it gets +5/+5"); Ability ability = new AttackedByCreatureTriggeredAbility(Zone.COMMAND, effect, false, SetTargetPointer.PERMANENT); - effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn, - "and gains trample until end of turn"); - ability.addEffect(effect); + effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn); + ability.addEffect(effect.concatBy("and")); this.getAbilities().add(ability); } } diff --git a/Mage/src/main/java/mage/game/command/emblems/JaceUnravelerOfSecretsEmblem.java b/Mage/src/main/java/mage/game/command/emblems/JaceUnravelerOfSecretsEmblem.java index 0ae65c4043..4c5cec028c 100644 --- a/Mage/src/main/java/mage/game/command/emblems/JaceUnravelerOfSecretsEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/JaceUnravelerOfSecretsEmblem.java @@ -51,7 +51,7 @@ class JaceUnravelerOfSecretsTriggeredAbility extends SpellCastOpponentTriggeredA @Override public boolean checkTrigger(GameEvent event, Game game) { if (super.checkTrigger(event, game)) { - SpellsCastWatcher watcher = (SpellsCastWatcher) game.getState().getWatchers().get(SpellsCastWatcher.class.getSimpleName()); + SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class); if (watcher != null) { List spells = watcher.getSpellsCastThisTurn(event.getPlayerId()); if (spells != null && spells.size() == 1) { diff --git a/Mage/src/main/java/mage/game/command/emblems/JayaBallardEmblem.java b/Mage/src/main/java/mage/game/command/emblems/JayaBallardEmblem.java index 45f0b291d7..0de0f51a96 100644 --- a/Mage/src/main/java/mage/game/command/emblems/JayaBallardEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/JayaBallardEmblem.java @@ -64,10 +64,12 @@ class JayaBallardCastFromGraveyardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Card card = game.getCard(objectId); - if (card != null) { - return (affectedControllerId.equals(source.getControllerId()) - && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game) - && Zone.GRAVEYARD.equals(game.getState().getZone(card.getId()))); + if (card != null + && affectedControllerId.equals(source.getControllerId()) + && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game) + && Zone.GRAVEYARD.equals(game.getState().getZone(card.getId()))) { + game.getState().setValue("JayaBallard", card); + return true; } return false; } @@ -98,7 +100,7 @@ class JayaBallardReplacementEffect extends ReplacementEffectImpl { public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { - Card card = game.getCard(getTargetPointer().getFirst(game, source)); + Card card = (Card) game.getState().getValue("JayaBallard"); if (card != null) { controller.moveCardToExileWithInfo(card, null, "", source.getSourceId(), game, Zone.STACK, true); return true; @@ -116,11 +118,13 @@ class JayaBallardReplacementEffect extends ReplacementEffectImpl { public boolean applies(GameEvent event, Ability source, Game game) { if (Zone.GRAVEYARD == ((ZoneChangeEvent) event).getToZone()) { Card card = game.getCard(event.getSourceId()); - if (card != null && (card.isInstant() || card.isSorcery())) { - // TODO: Find a way to check, that the spell from graveyard was really cast by the ability of the emblem. - // currently every spell cast from graveyard will be exiled. - CastFromGraveyardWatcher watcher = (CastFromGraveyardWatcher) game.getState().getWatchers().get(CastFromGraveyardWatcher.class.getSimpleName()); - return watcher != null && watcher.spellWasCastFromGraveyard(event.getTargetId(), game.getState().getZoneChangeCounter(event.getTargetId())); + if (card != null + && (card.isInstant() + || card.isSorcery())) { + CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); + return watcher != null + && watcher.spellWasCastFromGraveyard(event.getTargetId(), + game.getState().getZoneChangeCounter(event.getTargetId())); } } return false; diff --git a/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java b/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java index 272a96ba41..007aeeb625 100644 --- a/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/MomirEmblem.java @@ -1,7 +1,5 @@ - package mage.game.command.emblems; -import java.util.List; import mage.abilities.Ability; import mage.abilities.common.LimitedTimesPerTurnActivatedAbility; import mage.abilities.costs.common.DiscardCardCost; @@ -15,7 +13,6 @@ import mage.cards.repository.CardInfo; import mage.cards.repository.CardRepository; import mage.constants.CardType; import mage.constants.Outcome; -import mage.constants.SetType; import mage.constants.TimingRule; import mage.constants.Zone; import mage.game.Game; @@ -24,8 +21,9 @@ import mage.game.permanent.token.EmptyToken; import mage.util.CardUtil; import mage.util.RandomUtil; +import java.util.List; + /** - * * @author spjspj */ public final class MomirEmblem extends Emblem { @@ -69,22 +67,30 @@ class MomirEffect extends OneShotEffect { game.informPlayers("No random creature card with converted mana cost of " + value + " was found."); return false; } - EmptyToken token = new EmptyToken(); // search for a non custom set creature - while (token.getName().isEmpty() && !options.isEmpty()) { + + // search for a random non custom set creature + EmptyToken token = null; + while (!options.isEmpty()) { int index = RandomUtil.nextInt(options.size()); ExpansionSet expansionSet = Sets.findSet(options.get(index).getSetCode()); - if (expansionSet == null || expansionSet.getSetType() == SetType.CUSTOM_SET) { + if (expansionSet == null || !expansionSet.getSetType().isEternalLegal()) { options.remove(index); } else { Card card = options.get(index).getCard(); if (card != null) { + token = new EmptyToken(); CardUtil.copyTo(token).from(card); + break; } else { options.remove(index); } } } - token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false); - return true; + if (token != null) { + token.putOntoBattlefield(1, game, source.getSourceId(), source.getControllerId(), false, false); + return true; + } + + return false; } } diff --git a/Mage/src/main/java/mage/game/command/emblems/NissaWhoShakesTheWorldEmblem.java b/Mage/src/main/java/mage/game/command/emblems/NissaWhoShakesTheWorldEmblem.java new file mode 100644 index 0000000000..e00b2a2480 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/NissaWhoShakesTheWorldEmblem.java @@ -0,0 +1,28 @@ + +package mage.game.command.emblems; + +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.GainAbilityAllEffect; +import mage.abilities.keyword.IndestructibleAbility; +import mage.constants.Duration; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.command.Emblem; + +/** + * @author TheElk801 + */ +public final class NissaWhoShakesTheWorldEmblem extends Emblem { + + public NissaWhoShakesTheWorldEmblem() { + this.setName("Emblem Nissa"); + this.getAbilities().add(new SimpleStaticAbility( + Zone.COMMAND, + new GainAbilityAllEffect( + IndestructibleAbility.getInstance(), Duration.WhileOnBattlefield, + StaticFilters.FILTER_CONTROLLED_PERMANENT_LAND, false + ) + )); + this.setExpansionSetCodeForImage("WAR"); + } +} diff --git a/Mage/src/main/java/mage/game/command/emblems/ObNixilisOfTheBlackOathEmblem.java b/Mage/src/main/java/mage/game/command/emblems/ObNixilisOfTheBlackOathEmblem.java index c324972d06..4131d1b323 100644 --- a/Mage/src/main/java/mage/game/command/emblems/ObNixilisOfTheBlackOathEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/ObNixilisOfTheBlackOathEmblem.java @@ -24,7 +24,7 @@ public final class ObNixilisOfTheBlackOathEmblem extends Emblem { // You get an emblem with "{1}{B}, Sacrifice a creature: You gain X life and draw X cards, where X is the sacrificed creature's power." public ObNixilisOfTheBlackOathEmblem() { this.setName("Emblem Nixilis"); - DynamicValue xValue = new SacrificeCostCreaturesPower(); + DynamicValue xValue = SacrificeCostCreaturesPower.instance; Effect effect = new GainLifeEffect(xValue); effect.setText("You gain X life"); Ability ability = new SimpleActivatedAbility(Zone.COMMAND, effect, new ManaCostsImpl("{1}{B}")); diff --git a/Mage/src/main/java/mage/game/command/emblems/RowanKenrithEmblem.java b/Mage/src/main/java/mage/game/command/emblems/RowanKenrithEmblem.java index c3f33d114b..2f08b15ed7 100644 --- a/Mage/src/main/java/mage/game/command/emblems/RowanKenrithEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/RowanKenrithEmblem.java @@ -2,7 +2,6 @@ package mage.game.command.emblems; import mage.abilities.Ability; import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.mana.ActivatedManaAbilityImpl; import mage.constants.Outcome; @@ -10,7 +9,6 @@ import mage.constants.Zone; import mage.game.Game; import mage.game.command.Emblem; import mage.game.events.GameEvent; -import mage.game.permanent.Permanent; import mage.game.stack.StackAbility; import mage.players.Player; @@ -51,9 +49,9 @@ class RowanKenrithEmblemTriggeredAbility extends TriggeredAbilityImpl { public boolean checkTrigger(GameEvent event, Game game) { if (event.getPlayerId().equals(getControllerId())) { StackAbility stackAbility = (StackAbility) game.getStack().getStackObject(event.getSourceId()); - if (stackAbility != null && !(stackAbility.getStackAbility() instanceof ActivatedManaAbilityImpl)) { - Effect effect = this.getEffects().get(0); - effect.setValue("stackAbility", stackAbility); + if (stackAbility != null + && !(stackAbility.getStackAbility() instanceof ActivatedManaAbilityImpl)) { + game.getState().setValue("rowanStackAbility", stackAbility); return true; } } @@ -88,12 +86,12 @@ class RowanKenrithEmblemEffect extends OneShotEffect { if (player == null) { return false; } - StackAbility ability = (StackAbility) getValue("stackAbility"); + StackAbility ability = (StackAbility) game.getState().getValue("rowanStackAbility"); Player controller = game.getPlayer(source.getControllerId()); - Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (ability != null && controller != null && sourcePermanent != null) { + if (ability != null + && controller != null) { ability.createCopyOnStack(game, source, source.getControllerId(), true); - game.informPlayers(sourcePermanent.getIdName() + ": " + controller.getLogName() + " copied activated ability"); + game.informPlayers(source.getSourceObjectIfItStillExists(game).getName() + " : " + controller.getLogName() + " copied activated ability"); return true; } return false; diff --git a/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java b/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java new file mode 100644 index 0000000000..1d0ad23d58 --- /dev/null +++ b/Mage/src/main/java/mage/game/command/emblems/SerraTheBenevolentEmblem.java @@ -0,0 +1,73 @@ +package mage.game.command.emblems; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.ReplacementEffectImpl; +import mage.constants.Duration; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.command.Emblem; +import mage.game.events.GameEvent; +import mage.players.Player; + +/** + * @author TheElk801 + */ +public final class SerraTheBenevolentEmblem extends Emblem { + + // -6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead." + public SerraTheBenevolentEmblem() { + this.setName("Emblem Serra"); + this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new SerraTheBenevolentEmblemEffect())); + } +} + +class SerraTheBenevolentEmblemEffect extends ReplacementEffectImpl { + + SerraTheBenevolentEmblemEffect() { + super(Duration.Custom, Outcome.Benefit); + staticText = "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead"; + } + + private SerraTheBenevolentEmblemEffect(final SerraTheBenevolentEmblemEffect effect) { + super(effect); + } + + @Override + public SerraTheBenevolentEmblemEffect copy() { + return new SerraTheBenevolentEmblemEffect(this); + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGE_CAUSES_LIFE_LOSS; + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + if (source.isControlledBy(event.getPlayerId())) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null + && (controller.getLife() - event.getAmount()) < 1 + && game.getBattlefield().count( + StaticFilters.FILTER_CONTROLLED_CREATURE, + source.getSourceId(), event.getPlayerId(), game) > 0 + ) { + event.setAmount(controller.getLife() - 1); + } + } + return false; + } + + @Override + public boolean apply(Game game, Ability source) { + return false; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + return false; + } +} diff --git a/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java b/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java index f7c2fac333..018943ecab 100644 --- a/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/VraskaGolgariQueenEmblem.java @@ -3,11 +3,11 @@ package mage.game.command.emblems; import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility; import mage.abilities.effects.common.LoseGameTargetPlayerEffect; import mage.constants.SetTargetPointer; +import mage.constants.Zone; import mage.filter.StaticFilters; import mage.game.command.Emblem; /** - * * @author TheElk801 */ public final class VraskaGolgariQueenEmblem extends Emblem { @@ -17,9 +17,9 @@ public final class VraskaGolgariQueenEmblem extends Emblem { this.setName("Emblem Vraska"); this.setExpansionSetCodeForImage("GRN"); this.getAbilities().add(new DealsDamageToAPlayerAllTriggeredAbility( - new LoseGameTargetPlayerEffect(), + Zone.COMMAND, new LoseGameTargetPlayerEffect(), StaticFilters.FILTER_CONTROLLED_A_CREATURE, - false, SetTargetPointer.PLAYER, true + false, SetTargetPointer.NONE, true, true )); } } diff --git a/Mage/src/main/java/mage/game/command/emblems/WillKenrithEmblem.java b/Mage/src/main/java/mage/game/command/emblems/WillKenrithEmblem.java index 9a0f1bbbe6..9e171194f2 100644 --- a/Mage/src/main/java/mage/game/command/emblems/WillKenrithEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/WillKenrithEmblem.java @@ -1,4 +1,3 @@ - package mage.game.command.emblems; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -8,7 +7,6 @@ import mage.filter.StaticFilters; import mage.game.command.Emblem; /** - * * @author TheElk801 */ public final class WillKenrithEmblem extends Emblem { @@ -18,9 +16,8 @@ public final class WillKenrithEmblem extends Emblem { this.setName("Emblem Will Kenrith"); this.getAbilities().add(new SpellCastControllerTriggeredAbility( Zone.COMMAND, - new CopyTargetSpellEffect(true) - .setText("copy that spell. You may choose new targets for the copy"), - StaticFilters.FILTER_SPELL_INSTANT_OR_SORCERY, + new CopyTargetSpellEffect(true).withSpellName("it"), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false, true )); diff --git a/Mage/src/main/java/mage/game/command/planes/AgyremPlane.java b/Mage/src/main/java/mage/game/command/planes/AgyremPlane.java index df6166cc6e..e879dd6054 100644 --- a/Mage/src/main/java/mage/game/command/planes/AgyremPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/AgyremPlane.java @@ -1,9 +1,5 @@ - package mage.game.command.planes; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.ObjectColor; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -33,8 +29,11 @@ import mage.target.Target; import mage.target.targetpointer.FixedTarget; import mage.watchers.common.PlanarRollWatcher; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author spjspj */ public class AgyremPlane extends Plane { @@ -151,7 +150,11 @@ class AgyremRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { + if (defenderId == null) { + return true; + } + Plane cPlane = game.getState().getCurrentPlane(); if (cPlane != null && cPlane.getName().equalsIgnoreCase("Plane - Agyrem")) { return !defenderId.equals(source.getControllerId()); diff --git a/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java b/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java index 784207f8c1..0b5da1d1e4 100644 --- a/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/AkoumPlane.java @@ -35,7 +35,7 @@ public class AkoumPlane extends Plane { private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creature that isn't enchanted"); static { - filter.add(Predicates.not(new EnchantedPredicate())); + filter.add(Predicates.not(EnchantedPredicate.instance)); filterCard.add(new CardTypePredicate(CardType.ENCHANTMENT)); } diff --git a/Mage/src/main/java/mage/game/command/planes/AstralArenaPlane.java b/Mage/src/main/java/mage/game/command/planes/AstralArenaPlane.java index 7c7bf12635..15260c05f5 100644 --- a/Mage/src/main/java/mage/game/command/planes/AstralArenaPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/AstralArenaPlane.java @@ -1,9 +1,5 @@ - package mage.game.command.planes; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -24,8 +20,11 @@ import mage.target.Target; import mage.watchers.common.AttackedThisTurnWatcher; import mage.watchers.common.PlanarRollWatcher; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + /** - * * @author spjspj */ public class AstralArenaPlane extends Plane { @@ -81,15 +80,11 @@ class AstralArenaAttackRestrictionEffect extends RestrictionEffect { if (cPlane == null) { return false; } - if (!cPlane.getName().equalsIgnoreCase("Plane - Astral Arena")) { - return false; - } - - return true; + return cPlane.getName().equalsIgnoreCase("Plane - Astral Arena"); } @Override - public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game) { + public boolean canAttack(Permanent attacker, UUID defenderId, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getAttackers().isEmpty(); } } @@ -116,14 +111,11 @@ class AstralArenaBlockRestrictionEffect extends RestrictionEffect { if (cPlane == null) { return false; } - if (!cPlane.getName().equalsIgnoreCase("Plane - Astral Arena")) { - return false; - } - return true; + return cPlane.getName().equalsIgnoreCase("Plane - Astral Arena"); } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return game.getCombat().getBlockers().isEmpty(); } } diff --git a/Mage/src/main/java/mage/game/command/planes/BantPlane.java b/Mage/src/main/java/mage/game/command/planes/BantPlane.java index a1187a748f..5ea0fc27e6 100644 --- a/Mage/src/main/java/mage/game/command/planes/BantPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/BantPlane.java @@ -107,7 +107,7 @@ class PlanarDieRollCostIncreasingEffect extends CostModificationEffectImpl { public boolean apply(Game game, Ability source, Ability abilityToModify) { Player activePlayer = game.getPlayer(game.getActivePlayerId()); if (activePlayer != null) { - PlanarRollWatcher watcher = (PlanarRollWatcher) game.getState().getWatchers().get(PlanarRollWatcher.class.getSimpleName()); + PlanarRollWatcher watcher = game.getState().getWatcher(PlanarRollWatcher.class); int rolledCounter = 0; if (watcher != null) { rolledCounter = watcher.getNumberTimesPlanarDieRolled(activePlayer.getId()); diff --git a/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java b/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java index bf125dadf4..04fb098a1f 100644 --- a/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/FeedingGroundsPlane.java @@ -53,7 +53,7 @@ public class FeedingGroundsPlane extends Plane { this.getAbilities().add(ability); // Active player can roll the planar die: Whenever you roll {CHAOS}, target red or green creature gets X +1/+1 counters - Effect chaosEffect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), new TargetConvertedManaCost()); + Effect chaosEffect = new AddCountersTargetEffect(CounterType.P1P1.createInstance(), TargetConvertedManaCost.instance); Target chaosTarget = new TargetCreaturePermanent(1, 1, filter, false); List chaosEffects = new ArrayList(); diff --git a/Mage/src/main/java/mage/game/command/planes/FieldsOfSummerPlane.java b/Mage/src/main/java/mage/game/command/planes/FieldsOfSummerPlane.java index b767e9281b..f8444d6fc8 100644 --- a/Mage/src/main/java/mage/game/command/planes/FieldsOfSummerPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/FieldsOfSummerPlane.java @@ -32,7 +32,7 @@ import mage.watchers.common.PlanarRollWatcher; */ public class FieldsOfSummerPlane extends Plane { - private final static FilterSpell filter = new FilterSpell("a spell"); + private static final FilterSpell filter = new FilterSpell("a spell"); public FieldsOfSummerPlane() { this.setName("Plane - Fields of Summer"); diff --git a/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java b/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java index abb010d4dc..06cb2d410e 100644 --- a/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/HedronFieldsOfAgadeemPlane.java @@ -1,8 +1,5 @@ - package mage.game.command.planes; -import java.util.ArrayList; -import java.util.List; import mage.abilities.Ability; import mage.abilities.common.ActivateIfConditionActivatedAbility; import mage.abilities.common.SimpleStaticAbility; @@ -21,12 +18,14 @@ import mage.filter.predicate.mageobject.PowerPredicate; import mage.game.Game; import mage.game.command.Plane; import mage.game.permanent.Permanent; +import mage.game.permanent.token.EldraziAnnihilatorToken; import mage.target.Target; import mage.watchers.common.PlanarRollWatcher; -import mage.game.permanent.token.EldraziAnnihilatorToken; + +import java.util.ArrayList; +import java.util.List; /** - * * @author spjspj */ public class HedronFieldsOfAgadeemPlane extends Plane { @@ -80,12 +79,12 @@ class HedronFieldsOfAgadeemRestrictionEffect extends RestrictionEffect { } @Override - public boolean canAttack(Game game) { + public boolean canAttack(Game game, boolean canUseChooseDialogs) { return false; } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java b/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java index a1bdad2eec..e1accd02cb 100644 --- a/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java +++ b/Mage/src/main/java/mage/game/command/planes/TazeemPlane.java @@ -1,8 +1,5 @@ - package mage.game.command.planes; -import java.util.ArrayList; -import java.util.List; import mage.abilities.Ability; import mage.abilities.Mode; import mage.abilities.common.ActivateIfConditionActivatedAbility; @@ -25,8 +22,10 @@ import mage.game.permanent.Permanent; import mage.target.Target; import mage.watchers.common.PlanarRollWatcher; +import java.util.ArrayList; +import java.util.List; + /** - * * @author spjspj */ public class TazeemPlane extends Plane { @@ -83,7 +82,7 @@ class TazeemCantBlockAllEffect extends RestrictionEffect { } @Override - public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game) { + public boolean canBlock(Permanent attacker, Permanent blocker, Ability source, Game game, boolean canUseChooseDialogs) { return false; } diff --git a/Mage/src/main/java/mage/game/draft/DraftCube.java b/Mage/src/main/java/mage/game/draft/DraftCube.java index 439a5c6a6d..7854940ccb 100644 --- a/Mage/src/main/java/mage/game/draft/DraftCube.java +++ b/Mage/src/main/java/mage/game/draft/DraftCube.java @@ -46,6 +46,7 @@ public abstract class DraftCube { private static final Logger logger = Logger.getLogger(DraftCube.class); private final String name; + private final String code; private static final int boosterSize = 15; protected List cubeCards = new ArrayList<>(); @@ -53,12 +54,17 @@ public abstract class DraftCube { public DraftCube(String name) { this.name = name; + this.code = getClass().getSimpleName(); } public String getName() { return name; } + public String getCode() { + return code; + } + public List getCubeCards() { return cubeCards; } diff --git a/Mage/src/main/java/mage/game/draft/DraftImpl.java b/Mage/src/main/java/mage/game/draft/DraftImpl.java index 35efc14431..5ef5a2330e 100644 --- a/Mage/src/main/java/mage/game/draft/DraftImpl.java +++ b/Mage/src/main/java/mage/game/draft/DraftImpl.java @@ -147,7 +147,8 @@ public abstract class DraftImpl implements Draft { @Override public void autoPick(UUID playerId) { - this.addPick(playerId, players.get(playerId).getBooster().get(0).getId(), null); + List booster = players.get(playerId).getBooster(); + this.addPick(playerId, booster.get(booster.size()-1).getId(), null); } protected void passLeft() { diff --git a/Mage/src/main/java/mage/game/draft/RateCard.java b/Mage/src/main/java/mage/game/draft/RateCard.java new file mode 100644 index 0000000000..aa83b50052 --- /dev/null +++ b/Mage/src/main/java/mage/game/draft/RateCard.java @@ -0,0 +1,408 @@ +package mage.game.draft; + +import mage.abilities.Ability; +import mage.abilities.Mode; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.*; +import mage.abilities.effects.common.continuous.BoostEnchantedEffect; +import mage.abilities.effects.common.continuous.BoostTargetEffect; +import mage.cards.Card; +import mage.cards.repository.CardScanner; +import mage.constants.ColoredManaSymbol; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.target.Target; +import mage.target.TargetPermanent; +import mage.target.common.TargetAttackingCreature; +import mage.target.common.TargetAttackingOrBlockingCreature; +import mage.target.common.TargetCreaturePermanent; +import mage.target.common.TargetPlayerOrPlaneswalker; +import org.apache.log4j.Logger; + +import java.io.InputStream; +import java.util.*; + +/** + * Class responsible for reading ratings from resources and rating given cards. + * Based on card relative ratings from resources and card parameters. + * + * @author nantuko + */ +public final class RateCard { + + public static final boolean PRELOAD_CARD_RATINGS_ON_STARTUP = false; // warning, rating and card classes preloading can cause lags for users with low memory + + private static Map baseRatings = new HashMap<>(); + private static final Map rated = new HashMap<>(); + private static boolean isLoaded = false; + + /** + * Rating that is given for new cards. + * Ratings are in [1,10] range, so setting it high will make new cards appear more often. + * nowadays, cards that are more rare are more powerful, lets trust that and play the shiny cards. + */ + private static final int DEFAULT_NOT_RATED_CARD_RATING = 40; + private static final int DEFAULT_NOT_RATED_UNCOMMON_RATING = 60; + private static final int DEFAULT_NOT_RATED_RARE_RATING = 75; + private static final int DEFAULT_NOT_RATED_MYTHIC_RATING = 90; + + private static String RATINGS_DIR = "/ratings/"; + private static String RATINGS_SET_LIST = RATINGS_DIR + "setsWithRatings.csv"; + + private static final Logger log = Logger.getLogger(RateCard.class); + + /** + * Hide constructor. + */ + private RateCard() { + } + + public static void bootstrapCardsAndRatings() { + // preload cards and ratings + log.info("Loading cards and rating..."); + List cards = CardScanner.getAllCards(false); + for (Card card : cards) { + RateCard.rateCard(card, null); + } + } + + /** + * Get absolute score of the card. + * Depends on type, manacost, rating. + * If allowedColors is null then the rating is retrieved from the cache + * + * @param card + * @param allowedColors + * @return + */ + public static int rateCard(Card card, List allowedColors) { + return rateCard(card, allowedColors, true); + } + + public static int rateCard(Card card, List allowedColors, boolean useCache) { + if (card == null) { + return 0; + } + + if (useCache && allowedColors == null && rated.containsKey(card.getName())) { + int rate = rated.get(card.getName()); + return rate; + } + + int type; + if (card.isPlaneswalker()) { + type = 15; + } else if (card.isCreature()) { + type = 10; + } else if (card.getSubtype(null).contains(SubType.EQUIPMENT)) { + type = 8; + } else if (card.getSubtype(null).contains(SubType.AURA)) { + type = 5; + } else if (card.isInstant()) { + type = 7; + } else { + type = 6; + } + int score = getBaseCardScore(card) + 2 * type + getManaCostScore(card, allowedColors) + + 40 * isRemoval(card); + + if (useCache && allowedColors == null) + rated.put(card.getName(), score); + + return score; + } + + private static int isRemoval(Card card) { + if (card.isEnchantment() || card.isInstant() || card.isSorcery()) { + + for (Ability ability : card.getAbilities()) { + for (Effect effect : ability.getEffects()) { + if (isEffectRemoval(card, ability, effect) == 1) { + return 1; + } + } + for (Mode mode : ability.getModes().values()) { + for (Effect effect : mode.getEffects()) { + if (isEffectRemoval(card, ability, effect) == 1) { + return 1; + } + } + } + } + + } + return 0; + } + + private static int isEffectRemoval(Card card, Ability ability, Effect effect) { + if (effect.getOutcome() == Outcome.Removal) { + log.debug("Found removal: " + card.getName()); + return 1; + } + //static List removalEffects =[BoostTargetEffect,BoostEnchantedEffect] + if (effect instanceof BoostTargetEffect || effect instanceof BoostEnchantedEffect) { + String text = effect.getText(null); + if (text.contains("/-")) { + // toughness reducer, aka removal + return 1; + } + } + if (effect instanceof FightTargetsEffect || effect instanceof DamageWithPowerTargetEffect) { + return 1; + } + if (effect.getOutcome() == Outcome.Damage || effect instanceof DamageTargetEffect) { + for (Target target : ability.getTargets()) { + if (!(target instanceof TargetPlayerOrPlaneswalker)) { + log.debug("Found damage dealer: " + card.getName()); + return 1; + } + } + } + if (effect.getOutcome() == Outcome.DestroyPermanent || + effect instanceof DestroyTargetEffect || + effect instanceof ExileTargetEffect || + effect instanceof ExileUntilSourceLeavesEffect) { + for (Target target : ability.getTargets()) { + if (target instanceof TargetCreaturePermanent || + target instanceof TargetAttackingCreature || + target instanceof TargetAttackingOrBlockingCreature || + target instanceof TargetPermanent) { + log.debug("Found destroyer/exiler: " + card.getName()); + return 1; + } + } + } + return 0; + } + + + /** + * Return rating of the card. + * + * @param card Card to rate. + * @return Rating number from [1:100]. + */ + public static int getBaseCardScore(Card card) { + // same card name must have same rating + + // ratings from files + // lazy loading on first request + prepareAndLoadRatings(); + + // ratings from card rarity + // some cards can have different rarity -- it's will be used from first set + int newRating; + switch (card.getRarity()) { + case COMMON: + newRating = DEFAULT_NOT_RATED_CARD_RATING; + break; + case UNCOMMON: + newRating = DEFAULT_NOT_RATED_UNCOMMON_RATING; + break; + case RARE: + newRating = DEFAULT_NOT_RATED_RARE_RATING; + break; + case MYTHIC: + newRating = DEFAULT_NOT_RATED_MYTHIC_RATING; + break; + default: + newRating = DEFAULT_NOT_RATED_CARD_RATING; + break; + } + + int oldRating = baseRatings.getOrDefault(card.getName(), 0); + if (oldRating != 0 && oldRating != newRating) { + //log.info("card have different rating by sets: " + card.getName() + " (" + oldRating + " <> " + newRating + ")"); + } + + if (oldRating != 0) { + return oldRating; + } else { + baseRatings.put(card.getName(), newRating); + return newRating; + } + } + + /** + * reads the list of sets that have ratings csv files and read each file + */ + public synchronized static void prepareAndLoadRatings() { + if (isLoaded) { + return; + } + + // load sets list + List setsToLoad = new LinkedList<>(); + try { + InputStream is = RateCard.class.getResourceAsStream(RATINGS_SET_LIST); + Scanner scanner = new Scanner(is); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (!line.substring(0, 1).equals("#")) { + setsToLoad.add(line); + } + } + } catch (Throwable e) { + log.error("Failed to read ratings sets list file: " + RATINGS_SET_LIST, e); + } + + // load set data + String rateFile = ""; + try { + for (String code : setsToLoad) { + //log.info("Reading ratings for the set " + code); + rateFile = RATINGS_DIR + code + ".csv"; + readFromFile(rateFile); + } + } catch (Exception e) { + log.error("Failed to read ratings set file: " + rateFile, e); + } + + isLoaded = true; + } + + /** + * reads ratings from the file + */ + private synchronized static void readFromFile(String path) { + // card must get max rating from multiple cards + Integer min = Integer.MAX_VALUE, max = 0; + Map thisFileRatings = new HashMap<>(); + + // load + InputStream is = RateCard.class.getResourceAsStream(path); + Scanner scanner = new Scanner(is); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + String[] s = line.split(":"); + if (s.length == 2) { + Integer rating = Integer.parseInt(s[1].trim()); + String name = s[0].trim(); + if (rating > max) { + max = rating; + } + if (rating < min) { + min = rating; + } + thisFileRatings.put(name, rating); + } + } + + // normalize for the file to [1..100] + for (Map.Entry ratingByName : thisFileRatings.entrySet()) { + int r = ratingByName.getValue(); + String name = ratingByName.getKey(); + int newRating = (int) (100.0f * (r - min) / (max - min)); + int oldRating = baseRatings.getOrDefault(name, 0); + if (newRating > oldRating) { + baseRatings.put(name, newRating); + } + } + } + + private static final int[] SINGLE_PENALTY = {0, 1, 1, 3, 6, 9}; + private static final int MULTICOLOR_BONUS = 15; + + /** + * Get manacost score. + * Depends on chosen colors. Returns negative score for those cards that doesn't fit allowed colors. + * If allowed colors are not chosen, then score based on converted cost is returned with penalty for heavy colored cards. + * gives bonus to multicolor cards that fit within allowed colors and if allowed colors is <5 + * + * @param card + * @param allowedColors Can be null. + * @return + */ + private static int getManaCostScore(Card card, List allowedColors) { + int converted = card.getManaCost().convertedManaCost(); + if (allowedColors == null) { + int colorPenalty = 0; + for (String symbol : card.getManaCost().getSymbols()) { + if (isColoredMana(symbol)) { + colorPenalty++; + } + } + return 2 * (converted - colorPenalty + 1); + } + final Map singleCount = new HashMap<>(); + int maxSingleCount = 0; + for (String symbol : card.getManaCost().getSymbols()) { + int count = 0; + symbol = symbol.replace("{", "").replace("}", ""); + if (isColoredMana(symbol)) { + for (ColoredManaSymbol allowed : allowedColors) { + if (allowed.toString().equals(symbol)) { + count++; + } + } + if (count == 0) { + return -100; + } + Integer typeCount = singleCount.get(symbol); + if (typeCount == null) { + typeCount = 0; + } + typeCount += 1; + singleCount.put(symbol, typeCount); + maxSingleCount = Math.max(maxSingleCount, typeCount); + } + } + if (maxSingleCount > 5) + maxSingleCount = 5; + + int rate = 2 * converted + 3 * (10 - SINGLE_PENALTY[maxSingleCount]); + if (singleCount.size() > 1 && singleCount.size() < 5) { + rate += MULTICOLOR_BONUS; + } + return rate; + } + + /** + * Determines whether mana symbol is color. + * + * @param symbol + * @return + */ + public static boolean isColoredMana(String symbol) { + String s = symbol; + if (s.length() > 1) { + s = s.replace("{", "").replace("}", ""); + } + if (s.length() > 1) { + return false; + } + return s.equals("W") || s.equals("G") || s.equals("U") || s.equals("B") || s.equals("R"); + } + + /** + * Return number of color mana symbols in manacost. + * + * @param card + * @return + */ + public static int getColorManaCount(Card card) { + int count = 0; + for (String symbol : card.getManaCost().getSymbols()) { + if (isColoredMana(symbol)) { + count++; + } + } + return count; + } + + /** + * Return number of different color mana symbols in manacost. + * + * @param card + * @return + */ + public static int getDifferentColorManaCount(Card card) { + Set symbols = new HashSet<>(); + for (String symbol : card.getManaCost().getSymbols()) { + if (isColoredMana(symbol)) { + symbols.add(symbol); + } + } + return symbols.size(); + } +} diff --git a/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java b/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java index b2aecbd1d8..da3fd7d8da 100644 --- a/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java +++ b/Mage/src/main/java/mage/game/draft/RichManBoosterDraft.java @@ -6,6 +6,7 @@ import java.util.Objects; import java.util.UUID; import mage.cards.Card; import mage.cards.ExpansionSet; +import org.apache.log4j.Logger; /** * @@ -13,7 +14,10 @@ import mage.cards.ExpansionSet; */ public class RichManBoosterDraft extends DraftImpl { - protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25}; + private static final Logger logger = Logger.getLogger(RichManBoosterDraft.class); + + //protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25}; + protected int[] richManTimes = {70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}; public RichManBoosterDraft(DraftOptions options, List sets) { super(options, sets); diff --git a/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java b/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java index 1c097da3b9..082d82deb5 100644 --- a/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java +++ b/Mage/src/main/java/mage/game/draft/RichManCubeBoosterDraft.java @@ -13,7 +13,8 @@ import mage.game.draft.DraftCube.CardIdentity; */ public class RichManCubeBoosterDraft extends DraftImpl { - protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25}; + //protected int[] richManTimes = {75, 70, 65, 60, 55, 50, 45, 40, 35, 35, 35, 35, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25}; + protected int[] richManTimes = {70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40}; protected final Map cardsInCube = new LinkedHashMap<>(); public RichManCubeBoosterDraft(DraftOptions options, List sets) { diff --git a/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java b/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java new file mode 100644 index 0000000000..b7dad08225 --- /dev/null +++ b/Mage/src/main/java/mage/game/events/CoinFlippedEvent.java @@ -0,0 +1,41 @@ +package mage.game.events; + +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + **/ +public class CoinFlippedEvent extends GameEvent { + private final boolean result; + private final boolean chosen; + private final boolean winnable; + + CoinFlippedEvent(UUID playerId, UUID sourceId, boolean result, boolean chosen, boolean winnable) { + super(EventType.COIN_FLIPPED, playerId, sourceId, playerId); + this.result = result; + this.chosen = chosen; + this.winnable = winnable; + } + + public boolean getResult() { + return result; + } + + public String getResultName() { + return CardUtil.booleanToFlipName(result); + } + + public boolean getChosen() { + return chosen; + } + + public String getChosenName() { + return CardUtil.booleanToFlipName(chosen); + } + + public boolean isWinnable() { + return winnable; + } +} diff --git a/Mage/src/main/java/mage/game/events/FlipCoinEvent.java b/Mage/src/main/java/mage/game/events/FlipCoinEvent.java new file mode 100644 index 0000000000..3dc799ad4e --- /dev/null +++ b/Mage/src/main/java/mage/game/events/FlipCoinEvent.java @@ -0,0 +1,58 @@ +package mage.game.events; + +import mage.util.CardUtil; + +import java.util.UUID; + +/** + * @author TheElk801 + **/ +public class FlipCoinEvent extends GameEvent { + private boolean result; + private final boolean chosen; + private final boolean winnable; + private int flipCount = 1; + + public FlipCoinEvent(UUID playerId, UUID sourceId, boolean result, boolean chosen, boolean winnable) { + super(EventType.FLIP_COIN, playerId, sourceId, playerId); + this.result = result; + this.chosen = chosen; + this.winnable = winnable; + } + + public boolean getResult() { + return result; + } + + public String getResultName() { + return CardUtil.booleanToFlipName(result); + } + + public void setResult(boolean result) { + this.result = result; + } + + public boolean getChosen() { + return chosen; + } + + public String getChosenName() { + return CardUtil.booleanToFlipName(chosen); + } + + public boolean isWinnable() { + return winnable; + } + + public int getFlipCount() { + return flipCount; + } + + public void setFlipCount(int flipCount) { + this.flipCount = flipCount; + } + + public CoinFlippedEvent getFlippedEvent() { + return new CoinFlippedEvent(playerId, sourceId, result, chosen, winnable); + } +} diff --git a/Mage/src/main/java/mage/game/events/GameEvent.java b/Mage/src/main/java/mage/game/events/GameEvent.java index eeb746ce95..2d20ce98a0 100644 --- a/Mage/src/main/java/mage/game/events/GameEvent.java +++ b/Mage/src/main/java/mage/game/events/GameEvent.java @@ -1,14 +1,14 @@ package mage.game.events; +import mage.MageObjectReference; +import mage.constants.Zone; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; -import mage.MageObjectReference; -import mage.constants.Zone; /** - * * @author BetaSteward_at_googlemail.com */ public class GameEvent implements Serializable { @@ -221,6 +221,7 @@ public class GameEvent implements Serializable { PLANESWALK, PLANESWALKED, PAID_CUMULATIVE_UPKEEP, DIDNT_PAY_CUMULATIVE_UPKEEP, + LIFE_PAID, //permanent events ENTERS_THE_BATTLEFIELD_SELF, /* 616.1a If any of the replacement and/or prevention effects are self-replacement effects (see rule 614.15), one of them must be chosen. If not, proceed to rule 616.1b. */ @@ -232,6 +233,7 @@ public class GameEvent implements Serializable { FLIP, FLIPPED, UNFLIP, UNFLIPPED, TRANSFORM, TRANSFORMED, + ADAPT, BECOMES_MONSTROUS, BECOMES_EXERTED, /* BECOMES_EXERTED @@ -290,7 +292,7 @@ public class GameEvent implements Serializable { UNATTACH, UNATTACHED, ADD_COUNTER, COUNTER_ADDED, ADD_COUNTERS, COUNTERS_ADDED, - COUNTER_REMOVED, + COUNTER_REMOVED, COUNTERS_REMOVED, LOSE_CONTROL, /* LOST_CONTROL targetId id of the creature that lost control @@ -383,12 +385,12 @@ public class GameEvent implements Serializable { } private GameEvent(EventType type, UUID customEventType, - UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { + UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag) { this(type, customEventType, targetId, sourceId, playerId, amount, flag, null); } private GameEvent(EventType type, UUID customEventType, - UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) { + UUID targetId, UUID sourceId, UUID playerId, int amount, boolean flag, MageObjectReference reference) { this.type = type; this.customEventType = customEventType; this.targetId = targetId; @@ -466,7 +468,7 @@ public class GameEvent implements Serializable { /** * used to store which replacement effects were already applied to an event * or or any modified events that may replace it - * + *

    * 614.5. A replacement effect doesn't invoke itself repeatedly; it gets * only one opportunity to affect an event or any modified events that may * replace it. Example: A player controls two permanents, each with an diff --git a/Mage/src/main/java/mage/game/match/MatchImpl.java b/Mage/src/main/java/mage/game/match/MatchImpl.java index 660d073ce9..668ef67670 100644 --- a/Mage/src/main/java/mage/game/match/MatchImpl.java +++ b/Mage/src/main/java/mage/game/match/MatchImpl.java @@ -1,11 +1,5 @@ - package mage.game.match; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.UUID; import mage.cards.decks.Deck; import mage.game.Game; import mage.game.GameException; @@ -21,8 +15,9 @@ import mage.util.DateFormat; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.util.*; + /** - * * @author BetaSteward_at_googlemail.com */ public abstract class MatchImpl implements Match { @@ -394,7 +389,9 @@ public abstract class MatchImpl implements Match { // Check if the cards included in the deck are the same as in the original deck validDeck = (player.getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode()); if (validDeck == false) { - deck.getCards().clear(); // Clear the deck so the player cheating looses the game + // clear the deck so the player cheating looses the game + deck.getCards().clear(); + deck.getSideboard().clear(); } player.updateDeck(deck); } @@ -421,6 +418,8 @@ public abstract class MatchImpl implements Match { if (options.getRange() != null) { sb.append(" Range: ").append(options.getRange().toString()).append("
    "); } + sb.append(" Mulligan type: ").append(options.getMulliganType().toString()).append("
    "); + sb.append(" Free mulligans: ").append(options.getFreeMulligans()).append("
    "); sb.append("
    ").append("Match is ").append(this.getOptions().isRated() ? "" : "not ").append("rated
    "); sb.append("You have to win ").append(this.getWinsNeeded()).append(this.getWinsNeeded() == 1 ? " game" : " games").append(" to win the complete match
    "); sb.append("
    Game has started

    "); diff --git a/Mage/src/main/java/mage/game/match/MatchOptions.java b/Mage/src/main/java/mage/game/match/MatchOptions.java index 02e6808416..0fd193193e 100644 --- a/Mage/src/main/java/mage/game/match/MatchOptions.java +++ b/Mage/src/main/java/mage/game/match/MatchOptions.java @@ -5,6 +5,7 @@ import mage.constants.MatchTimeLimit; import mage.constants.MultiplayerAttackOption; import mage.constants.RangeOfInfluence; import mage.constants.SkillLevel; +import mage.game.mulligan.MulliganType; import mage.game.result.ResultProtos; import mage.players.PlayerType; @@ -37,6 +38,7 @@ public class MatchOptions implements Serializable { protected boolean spectatorsAllowed; protected boolean planeChase; protected int quitRatio; + protected int minimumRating; protected int edhPowerLevel; protected boolean rated; protected int numSeatsForMatch; @@ -46,6 +48,7 @@ public class MatchOptions implements Serializable { * Time each player has during the game to play using his\her priority. */ protected MatchTimeLimit matchTimeLimit; // 0 = no priorityTime handling + protected MulliganType mulliganType; /*public MatchOptions(String name, String gameType) { this.name = name; @@ -205,6 +208,10 @@ public class MatchOptions implements Serializable { this.quitRatio = quitRatio; } + public int getMinimumRating() { return minimumRating; } + + public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; } + public int getEdhPowerLevel() { return edhPowerLevel; } @@ -252,4 +259,16 @@ public class MatchOptions implements Serializable { return builder.build(); } + + public void setMullgianType(MulliganType mulliganType) { + this.mulliganType = mulliganType; + } + + public MulliganType getMulliganType() { + if (mulliganType == null) { + return MulliganType.GAME_DEFAULT; + } + return mulliganType; + } + } diff --git a/Mage/src/main/java/mage/game/match/MatchPlayer.java b/Mage/src/main/java/mage/game/match/MatchPlayer.java index 5d1b9ca18e..e7b876ceb6 100644 --- a/Mage/src/main/java/mage/game/match/MatchPlayer.java +++ b/Mage/src/main/java/mage/game/match/MatchPlayer.java @@ -1,13 +1,13 @@ - package mage.game.match; -import java.io.Serializable; import mage.cards.Card; import mage.cards.decks.Deck; +import mage.cards.decks.DeckValidator; import mage.players.Player; +import java.io.Serializable; + /** - * * @author BetaSteward_at_googlemail.com */ public class MatchPlayer implements Serializable { @@ -78,9 +78,9 @@ public class MatchPlayer implements Serializable { this.deck = deck; } - public Deck generateDeck() { - //TODO: improve this - while (deck.getCards().size() < 40 && !deck.getSideboard().isEmpty()) { + public Deck generateDeck(DeckValidator deckValidator) { + // auto complete deck + while (deck.getCards().size() < deckValidator.getDeckMinSize() && !deck.getSideboard().isEmpty()) { Card card = deck.getSideboard().iterator().next(); deck.getCards().add(card); deck.getSideboard().remove(card); diff --git a/Mage/src/main/java/mage/game/mulligan/CanadianHighlanderMulligan.java b/Mage/src/main/java/mage/game/mulligan/CanadianHighlanderMulligan.java new file mode 100644 index 0000000000..320f39897c --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/CanadianHighlanderMulligan.java @@ -0,0 +1,124 @@ +package mage.game.mulligan; + +import mage.game.Game; +import mage.players.Player; + +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +public class CanadianHighlanderMulligan extends VancouverMulligan { + + protected Map usedMulligans = new LinkedHashMap<>(); + + public CanadianHighlanderMulligan(int freeMulligans) { + super(freeMulligans); + } + + @Override + public CanadianHighlanderMulligan copy() { + return new CanadianHighlanderMulligan(getFreeMulligans()); + } + + private String getNextMulligan(String mulligan) { + switch (mulligan) { + case "7": + return "6a"; + case "6a": + return "6b"; + case "6b": + return "5a"; + case "5a": + return "5b"; + case "5b": + return "4a"; + case "4a": + return "4b"; + case "4b": + return "3a"; + case "3a": + return "3b"; + case "3b": + return "2a"; + case "2a": + return "2b"; + case "2b": + return "1a"; + case "1a": + return "1b"; + } + return "0"; + } + + private int getNextMulliganNum(String mulligan) { + switch (mulligan) { + case "7": + return 6; + case "6a": + return 6; + case "6b": + return 5; + case "5a": + return 5; + case "5b": + return 4; + case "4a": + return 4; + case "4b": + return 3; + case "3a": + return 3; + case "3b": + return 2; + case "2a": + return 2; + case "2b": + return 1; + case "1a": + return 1; + } + return 0; + } + + @Override + public int mulliganDownTo(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int deduction = 1; + int numToMulliganTo = -1; + if (usedMulligans != null) { + String mulliganCode = "7"; + if (usedMulligans.containsKey(player.getId())) { + mulliganCode = usedMulligans.get(player.getId()); + } + numToMulliganTo = getNextMulliganNum(mulliganCode); + } + if (numToMulliganTo == -1) { + return player.getHand().size() - deduction; + } + return numToMulliganTo; + } + + @Override + public void mulligan(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int numCards = player.getHand().size(); + int numToMulliganTo = numCards; + player.getLibrary().addAll(player.getHand().getCards(game), game); + player.getHand().clear(); + player.shuffleLibrary(null, game); + if (usedMulligans != null) { + String mulliganCode = "7"; + if (usedMulligans.containsKey(player.getId())) { + mulliganCode = usedMulligans.get(player.getId()); + } + numToMulliganTo = getNextMulliganNum(mulliganCode); + usedMulligans.put(player.getId(), getNextMulligan(mulliganCode)); + } + game.fireInformEvent(new StringBuilder(player.getLogName()) + .append(" mulligans to ") + .append(Integer.toString(numToMulliganTo)) + .append(numToMulliganTo == 1 ? " card" : " cards").toString()); + player.drawCards(numToMulliganTo, game); + } + +} diff --git a/Mage/src/main/java/mage/game/mulligan/LondonMulligan.java b/Mage/src/main/java/mage/game/mulligan/LondonMulligan.java new file mode 100644 index 0000000000..5c9e85a4d6 --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/LondonMulligan.java @@ -0,0 +1,131 @@ +package mage.game.mulligan; + +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class LondonMulligan extends Mulligan { + + protected Map startingHandSizes = new HashMap<>(); + protected Map openingHandSizes = new HashMap<>(); + + public LondonMulligan(int freeMulligans) { + super(freeMulligans); + } + + @Override + public void executeMulliganPhase(Game game, int startingHandSize) { + /* + * 103.4. Each player draws a number of cards equal to their starting hand size, which is normally + * seven. (Some effects can modify a player’s starting hand size.) A player who is dissatisfied with + * their initial hand may take a mulligan. First, the starting player declares whether they will + * take a mulligan. Then each other player in turn order does the same. Once each player has made a + * declaration, all players who decided to take mulligans do so at the same time. To take a mulligan, + * a player shuffles the cards in their hand back into their library, draws a new hand of cards equal + * to their starting hand size, then puts a number of those cards onto the bottom of their library in + * any order equal to the number of times that player has taken a mulligan. Once a player chooses not + * to take a mulligan, the remaining cards become the player’s opening hand, and that player may not + * take any further mulligans. This process is then repeated until no player takes a mulligan. A + * player can’t take a number of mulligans greater their starting hand size. + * + * https://magic.wizards.com/en/articles/archive/competitive-gaming/mythic-championship-ii-format-and-london-test-2019-02-21 + */ + + for (UUID playerId : game.getState().getPlayerList(game.getStartingPlayerId())) { + openingHandSizes.put(playerId, startingHandSize); + startingHandSizes.put(playerId, startingHandSize); + } + + super.executeMulliganPhase(game, startingHandSize); + } + + @Override + public int mulliganDownTo(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int deduction = 1; + if (freeMulligans > 0) { + if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { + int used = usedFreeMulligans.get(player.getId()); + if (used < freeMulligans) { + deduction = 0; + } + } else { + deduction = 0; + } + } + return openingHandSizes.get(playerId) - deduction; + } + + @Override + public boolean canTakeMulligan(Game game, Player player) { + return super.canTakeMulligan(game, player) && openingHandSizes.get(player.getId()) > 0; + } + + @Override + public void mulligan(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int numCards = startingHandSizes.get(player.getId()); + player.getLibrary().addAll(player.getHand().getCards(game), game); + player.getHand().clear(); + player.shuffleLibrary(null, game); + int deduction = 1; + if (freeMulligans > 0) { + if (usedFreeMulligans.containsKey(player.getId())) { + int used = usedFreeMulligans.get(player.getId()); + if (used < freeMulligans) { + deduction = 0; + usedFreeMulligans.put(player.getId(), used + 1); + } + } else { + deduction = 0; + usedFreeMulligans.put(player.getId(), 1); + } + } + openingHandSizes.put(playerId, openingHandSizes.get(playerId) - deduction); + if (deduction == 0) { + game.fireInformEvent(new StringBuilder(player.getLogName()) + .append(" mulligans for free.") + .toString()); + } else { + game.fireInformEvent(new StringBuilder(player.getLogName()) + .append(" mulligans") + .append(" down to ") + .append((numCards - deduction)) + .append(numCards - deduction == 1 ? " card" : " cards").toString()); + } + player.drawCards(numCards, game); + + int handSize = openingHandSizes.get(player.getId()); + if (player.getHand().size() > handSize) { + int cardsToDiscard = player.getHand().size() - handSize; + Cards cards = new CardsImpl(); + cards.addAll(player.getHand()); + TargetCard target = new TargetCard(cardsToDiscard, cardsToDiscard, Zone.HAND, + new FilterCard("cards to PUT on the BOTTOM of your library (Discard for Mulligan)")); + player.chooseTarget(Outcome.Neutral, cards, target, null, game); + player.putCardsOnBottomOfLibrary(new CardsImpl(target.getTargets()), game, null, true); + cards.removeAll(target.getTargets()); + } + } + + @Override + public void endMulligan(Game game, UUID playerId) {} + + @Override + public LondonMulligan copy() { + LondonMulligan mulligan = new LondonMulligan(getFreeMulligans()); + mulligan.openingHandSizes.putAll(openingHandSizes); + mulligan.startingHandSizes.putAll(startingHandSizes); + return mulligan; + } + +} diff --git a/Mage/src/main/java/mage/game/mulligan/Mulligan.java b/Mage/src/main/java/mage/game/mulligan/Mulligan.java new file mode 100644 index 0000000000..43abf6c284 --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/Mulligan.java @@ -0,0 +1,87 @@ +package mage.game.mulligan; + +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.Player; + +import java.util.*; + +public abstract class Mulligan { + + protected final int freeMulligans; + protected final Map usedFreeMulligans = new HashMap<>(); + + public Mulligan(int freeMulligans) { + this.freeMulligans = freeMulligans; + } + + public void executeMulliganPhase(Game game, int startingHandSize) { + /* + * 103.4. Each player draws a number of cards equal to their starting hand size, + * which is normally seven. (Some effects can modify a player’s starting hand size.) + * A player who is dissatisfied with their initial hand may take a mulligan. First + * the starting player declares whether they will take a mulligan. Then each other + * player in turn order does the same. Once each player has made a declaration, all + * players who decided to take mulligans do so at the same time. To take a mulligan, + * a player shuffles their hand back into their library, then draws a new hand of one + * fewer cards than they had before. If a player kept their hand of cards, those cards + * become the player’s opening hand, and that player may not take any further mulligans. + * This process is then repeated until no player takes a mulligan. (Note that if a + * player’s hand size reaches zero cards, that player must keep that hand.) + */ + List keepPlayers = new ArrayList<>(); + List mulliganPlayers = new ArrayList<>(); + do { + mulliganPlayers.clear(); + for (UUID playerId : game.getState().getPlayerList(game.getStartingPlayerId())) { + if (!keepPlayers.contains(playerId)) { + Player player = game.getPlayer(playerId); + boolean keep = true; + while (true) { + if (!canTakeMulligan(game, player)) { + break; + } + GameEvent event = new GameEvent(GameEvent.EventType.CAN_TAKE_MULLIGAN, null, null, playerId); + if (!game.replaceEvent(event)) { + game.fireEvent(event); + game.getState().setChoosingPlayerId(playerId); + if (player.chooseMulligan(game)) { + keep = false; + } + break; + } + } + if (keep) { + game.endMulligan(player.getId()); + keepPlayers.add(playerId); + game.fireInformEvent(player.getLogName() + " keeps hand"); + } else { + mulliganPlayers.add(playerId); + game.fireInformEvent(player.getLogName() + " decides to take mulligan"); + } + } + } + for (UUID mulliganPlayerId : mulliganPlayers) { + mulligan(game, mulliganPlayerId); + } + game.saveState(false); + } while (!mulliganPlayers.isEmpty()); + } + + public abstract int mulliganDownTo(Game game, UUID playerId); + + public abstract void mulligan(Game game, UUID playerId); + + public abstract void endMulligan(Game game, UUID playerId); + + public abstract Mulligan copy(); + + public boolean canTakeMulligan(Game game, Player player) { + return !player.getHand().isEmpty(); + } + + public int getFreeMulligans() { + return freeMulligans; + } + +} diff --git a/Mage/src/main/java/mage/game/mulligan/MulliganType.java b/Mage/src/main/java/mage/game/mulligan/MulliganType.java new file mode 100644 index 0000000000..568abff45e --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/MulliganType.java @@ -0,0 +1,59 @@ +package mage.game.mulligan; + +import java.util.Locale; + +public enum MulliganType { + + GAME_DEFAULT("Game Default"), + VANCOUVER("Vancouver"), + PARIS("Paris"), + LONDON("London"), + CANADIAN_HIGHLANDER("Canadian Highlander"); + + private final String displayName; + + MulliganType(String displayName) { + this.displayName = displayName; + } + + public Mulligan getMulligan(int freeMulligans) { + switch (this) { + case PARIS: + return new ParisMulligan(freeMulligans); + case CANADIAN_HIGHLANDER: + return new CanadianHighlanderMulligan(freeMulligans); + case LONDON: + return new LondonMulligan(freeMulligans); + default: + case VANCOUVER: + return new VancouverMulligan(freeMulligans); + } + } + + @Override + public String toString() { + return displayName; + } + + public static MulliganType valueByName(String name) { + String search = (name != null ? name : "").toUpperCase(Locale.ENGLISH); + + MulliganType res = GAME_DEFAULT; + for (MulliganType m : values()) { + if (m.displayName.toUpperCase(Locale.ENGLISH).equals(search)) { + res = m; + break; + } + } + return res; + } + + + public MulliganType orDefault(MulliganType defaultMulligan) { + if (this == GAME_DEFAULT) { + return defaultMulligan; + } + return this; + } + +} diff --git a/Mage/src/main/java/mage/game/mulligan/ParisMulligan.java b/Mage/src/main/java/mage/game/mulligan/ParisMulligan.java new file mode 100644 index 0000000000..89ed63c087 --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/ParisMulligan.java @@ -0,0 +1,67 @@ +package mage.game.mulligan; + +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +public class ParisMulligan extends Mulligan { + + public ParisMulligan(int freeMulligans) { + super(freeMulligans); + } + + @Override + public int mulliganDownTo(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int deduction = 1; + if (freeMulligans > 0) { + if (usedFreeMulligans != null && usedFreeMulligans.containsKey(player.getId())) { + int used = usedFreeMulligans.get(player.getId()); + if (used < freeMulligans) { + deduction = 0; + } + } else { + deduction = 0; + } + } + return player.getHand().size() - deduction; + } + + @Override + public void mulligan(Game game, UUID playerId) { + Player player = game.getPlayer(playerId); + int numCards = player.getHand().size(); + player.getLibrary().addAll(player.getHand().getCards(game), game); + player.getHand().clear(); + player.shuffleLibrary(null, game); + int deduction = 1; + if (freeMulligans > 0) { + if (usedFreeMulligans.containsKey(player.getId())) { + int used = usedFreeMulligans.get(player.getId()); + if (used < freeMulligans) { + deduction = 0; + usedFreeMulligans.put(player.getId(), used + 1); + } + } else { + deduction = 0; + usedFreeMulligans.put(player.getId(), 1); + } + } + game.fireInformEvent(new StringBuilder(player.getLogName()) + .append(" mulligans") + .append(deduction == 0 ? " for free and draws " : " down to ") + .append((numCards - deduction)) + .append(numCards - deduction == 1 ? " card" : " cards").toString()); + player.drawCards(numCards - deduction, game); + } + + @Override + public void endMulligan(Game game, UUID playerId) {} + + @Override + public ParisMulligan copy() { + return new ParisMulligan(getFreeMulligans()); + } + +} diff --git a/Mage/src/main/java/mage/game/mulligan/VancouverMulligan.java b/Mage/src/main/java/mage/game/mulligan/VancouverMulligan.java new file mode 100644 index 0000000000..9a131224d9 --- /dev/null +++ b/Mage/src/main/java/mage/game/mulligan/VancouverMulligan.java @@ -0,0 +1,36 @@ +package mage.game.mulligan; + +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +public class VancouverMulligan extends ParisMulligan { + + public VancouverMulligan(int freeMulligans) { + super(freeMulligans); + } + + @Override + public void executeMulliganPhase(Game game, int startingHandSize) { + super.executeMulliganPhase(game, startingHandSize); + /* + * 103.4 (scry rule) - After all players have kept an opening hand, each player in + * turn order whose hand contains fewer cards than that player’s starting hand size + * may look at the top card of their library. If a player does, that player may put + * that card on the bottom of their library. + */ + for (UUID playerId : game.getState().getPlayerList(game.getStartingPlayerId())) { + Player player = game.getPlayer(playerId); + if (player != null && player.getHand().size() < startingHandSize) { + player.scry(1, null, game); + } + } + } + + @Override + public VancouverMulligan copy() { + return new VancouverMulligan(getFreeMulligans()); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/Battlefield.java b/Mage/src/main/java/mage/game/permanent/Battlefield.java index c9df6b058c..a4445c6c64 100644 --- a/Mage/src/main/java/mage/game/permanent/Battlefield.java +++ b/Mage/src/main/java/mage/game/permanent/Battlefield.java @@ -6,6 +6,7 @@ import mage.constants.CardType; import mage.constants.RangeOfInfluence; import mage.filter.FilterPermanent; import mage.game.Game; +import mage.players.Player; import java.io.Serializable; import java.util.*; @@ -297,7 +298,11 @@ public class Battlefield implements Serializable { .filter(perm -> perm.isPhasedIn() && filter.match(perm, sourceId, sourcePlayerId, game)) .collect(Collectors.toList()); } else { - Set range = game.getPlayer(sourcePlayerId).getInRange(); + Player player = game.getPlayer(sourcePlayerId); + if(player == null){ + return Collections.emptyList(); + } + Set range = player.getInRange(); return field.values() .stream() .filter(perm -> perm.isPhasedIn() && range.contains(perm.getControllerId()) diff --git a/Mage/src/main/java/mage/game/permanent/Permanent.java b/Mage/src/main/java/mage/game/permanent/Permanent.java index 1e17d0e8a9..8ebdc1f648 100644 --- a/Mage/src/main/java/mage/game/permanent/Permanent.java +++ b/Mage/src/main/java/mage/game/permanent/Permanent.java @@ -1,9 +1,6 @@ package mage.game.permanent; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.MageObjectReference; import mage.abilities.Ability; @@ -14,6 +11,10 @@ import mage.game.Controllable; import mage.game.Game; import mage.game.GameState; +import java.util.List; +import java.util.Set; +import java.util.UUID; + public interface Permanent extends Card, Controllable { void setControllerId(UUID controllerId); @@ -24,6 +25,8 @@ public interface Permanent extends Card, Controllable { boolean tap(Game game); + boolean tap(boolean forCombat, Game game); + /** * use tap(game) *

    @@ -106,6 +109,8 @@ public interface Permanent extends Card, Controllable { int getDamage(); + int damage(int damage, UUID sourceId, Game game); + int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable); int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable, List appliedEffects); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentCard.java b/Mage/src/main/java/mage/game/permanent/PermanentCard.java index eef8105555..f6436ee451 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentCard.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentCard.java @@ -21,6 +21,8 @@ public class PermanentCard extends PermanentImpl { protected int maxLevelCounters; // A copy of the origin card that was cast (this is not the original card, so it's possible to chnage some attribute to this blueprint to change attributes to the permanent if it enters the battlefield with e.g. a subtype) protected Card card; + // A copy of original card that was used for copy and create current permanent (used in copy effects and special commands like adjustTargets) + protected Card copiedFromCard; // the number this permanent instance had protected int zoneChangeCounter; @@ -153,7 +155,13 @@ public class PermanentCard extends PermanentImpl { if (this.isTransformed() && card.getSecondCardFace() != null) { card.getSecondCardFace().adjustTargets(ability, game); } else { - card.adjustTargets(ability, game); + if (this.isCopy()) { + // if COPIED card have adjuster then it's must be called instead own -- see OathOfLieges tests + // raise null error on wrong copy + this.getCopyFrom().adjustTargets(ability, game); + } else { + card.adjustTargets(ability, game); + } } } diff --git a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java index 776f0b775d..a76df41f43 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentImpl.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentImpl.java @@ -1,4 +1,3 @@ - package mage.game.permanent; import mage.MageObject; @@ -9,6 +8,8 @@ import mage.abilities.Ability; import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.Effect; import mage.abilities.effects.RestrictionEffect; +import mage.abilities.hint.Hint; +import mage.abilities.hint.HintUtils; import mage.abilities.keyword.*; import mage.abilities.text.TextPart; import mage.cards.Card; @@ -44,12 +45,13 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { private static final Logger logger = Logger.getLogger(PermanentImpl.class); - public class MarkedDamageInfo { + static class MarkedDamageInfo { public MarkedDamageInfo(Counter counter, MageObject sourceObject) { this.counter = counter; this.sourceObject = sourceObject; } + Counter counter; MageObject sourceObject; } @@ -164,7 +166,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public String toString() { StringBuilder sb = threadLocalBuilder.get(); - sb.append(this.name).append('-').append(this.expansionSetCode); + sb.append(this.getName()).append('-').append(this.expansionSetCode); if (copy) { sb.append(" [Copy]"); } @@ -195,10 +197,23 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } + @Override + public String getName() { + if (name.isEmpty()) { + if (faceDown) { + return EmptyNames.FACE_DOWN_CREATURE.toString(); + } else { + return ""; + } + } else { + return name; + } + } + @Override public String getValue(GameState state) { StringBuilder sb = threadLocalBuilder.get(); - sb.append(controllerId).append(name).append(tapped).append(damage); + sb.append(controllerId).append(getName()).append(tapped).append(damage); sb.append(subtype).append(supertype).append(power.getValue()).append(toughness.getValue()); sb.append(abilities.getValue()); for (Counter counter : getCounters(state).values()) { @@ -223,17 +238,83 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public List getRules(Game game) { try { List rules = getRules(); + + // info if (info != null) { for (String data : info.values()) { rules.add(data); } } + + // ability hints + List abilityHints = new ArrayList<>(); + if (HintUtils.ABILITY_HINTS_ENABLE) { + for (Ability ability : abilities) { + for (Hint hint : ability.getHints()) { + String s = hint.getText(game, ability); + if (s != null && !s.isEmpty()) { + abilityHints.add(s); + } + } + } + } + + // restrict hints + List restrictHints = new ArrayList<>(); + if (HintUtils.RESTRICT_HINTS_ENABLE) { + for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { + for (Ability ability : entry.getValue()) { + if (!entry.getKey().applies(this, ability, game)) { + continue; + } + + if (!entry.getKey().canAttack(game, false) || !entry.getKey().canAttack(this, null, ability, game, false)) { + restrictHints.add(HintUtils.prepareText("Can't attack" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT)); + } + + if (!entry.getKey().canBlock(null, this, ability, game, false)) { + restrictHints.add(HintUtils.prepareText("Can't block" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT)); + } + + if (!entry.getKey().canBeUntapped(this, ability, game, false)) { + restrictHints.add(HintUtils.prepareText("Can't untapped" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT)); + } + + if (!entry.getKey().canUseActivatedAbilities(this, ability, game, false)) { + restrictHints.add(HintUtils.prepareText("Can't use activated abilities" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT)); + } + + if (!entry.getKey().canTransform(this, ability, game, false)) { + restrictHints.add(HintUtils.prepareText("Can't transform" + addSourceObjectName(game, ability), null, HintUtils.HINT_ICON_RESTRICT)); + } + } + } + restrictHints.sort(String::compareTo); + } + + // total hints + if (!abilityHints.isEmpty() || !restrictHints.isEmpty()) { + rules.add(HintUtils.HINT_START_MARK); + HintUtils.appendHints(rules, abilityHints); + HintUtils.appendHints(rules, restrictHints); + } + return rules; } catch (Exception e) { return rulesError; } } + private String addSourceObjectName(Game game, Ability ability) { + if (ability != null) { + MageObject object = game.getObject(ability.getSourceId()); + if (object != null) { + return " (" + object.getIdName() + ")"; + } + } + return ""; + } + @Override public Abilities getAbilities() { return abilities; @@ -245,7 +326,6 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } /** - * * @param ability * @param game */ @@ -378,11 +458,16 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { @Override public boolean tap(Game game) { + return tap(false, game); + } + + @Override + public boolean tap(boolean forCombat, Game game) { //20091005 - 701.15a if (!tapped) { if (!replaceEvent(EventType.TAP, game)) { this.tapped = true; - fireEvent(EventType.TAPPED, game); + game.fireEvent(new GameEvent(EventType.TAPPED, objectId, ownerId, controllerId, 0, forCombat)); return true; } } @@ -460,7 +545,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { public boolean phaseIn(Game game, boolean onlyDirect) { if (!phasedIn) { if (!replaceEvent(EventType.PHASE_IN, game) - && ((onlyDirect && !indirectPhase) || (!onlyDirect))) { + && (!onlyDirect || !indirectPhase)) { this.phasedIn = true; this.indirectPhase = false; if (!game.isSimulation()) { @@ -665,7 +750,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { this.attachedTo = attachToObjectId; this.attachedToZoneChangeCounter = game.getState().getZoneChangeCounter(attachToObjectId); for (Ability ability : this.getAbilities()) { - for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext();) { + for (Iterator ite = ability.getEffects(game, EffectType.CONTINUOUS).iterator(); ite.hasNext(); ) { ContinuousEffect effect = (ContinuousEffect) ite.next(); game.getContinuousEffects().setOrder(effect); // It's important to update the timestamp of the copied effect in ContinuousEffects because it does the action @@ -699,6 +784,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { return this.damage; } + @Override + public int damage(int damage, UUID sourceId, Game game) { + return damage(damage, sourceId, game, true, false, false, null); + } + @Override public int damage(int damage, UUID sourceId, Game game, boolean combat, boolean preventable) { return damage(damage, sourceId, game, preventable, combat, false, null); @@ -715,8 +805,8 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { * @param game * @param preventable * @param combat - * @param markDamage If true, damage will be dealt later in applyDamage - * method + * @param markDamage If true, damage will be dealt later in applyDamage + * method * @return */ private int damage(int damageAmount, UUID sourceId, Game game, boolean preventable, boolean combat, boolean markDamage, List appliedEffects) { @@ -746,7 +836,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { sourceControllerId = ((Card) source).getOwnerId(); } else if (source instanceof CommandObject) { sourceControllerId = ((CommandObject) source).getControllerId(); - sourceAbilities = ((CommandObject) source).getAbilities(); + sourceAbilities = source.getAbilities(); } else { source = null; } @@ -934,14 +1024,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { } } + if (abilities.containsKey(HexproofFromMonocoloredAbility.getInstance().getId())) { + if (game.getPlayer(this.getControllerId()).hasOpponent(sourceControllerId, game) + && null == game.getContinuousEffects().asThough(this.getId(), AsThoughEffectType.HEXPROOF, null, sourceControllerId, game) + && !source.getColor(game).isColorless() && !source.getColor(game).isMulticolored()) { + return false; + } + } + if (hasProtectionFrom(source, game)) { return false; } // needed to get the correct possible targets if target rule modification effects are active // e.g. Fiendslayer Paladin tried to target with Ultimate Price - if (game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(EventType.TARGET, this.getId(), source.getId(), sourceControllerId), null, game, true)) { - return false; - } + return !game.getContinuousEffects().preventedByRuleModification(GameEvent.getEvent(EventType.TARGET, this.getId(), source.getId(), sourceControllerId), null, game, true); } return true; @@ -1094,11 +1190,11 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { private boolean canAttackCheckRestrictionEffects(UUID defenderId, Game game) { //20101001 - 508.1c for (Map.Entry> effectEntry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { - if (!effectEntry.getKey().canAttack(game)) { + if (!effectEntry.getKey().canAttack(game, true)) { return false; } for (Ability ability : effectEntry.getValue()) { - if (!effectEntry.getKey().canAttack(this, defenderId, ability, game)) { + if (!effectEntry.getKey().canAttack(this, defenderId, ability, game, true)) { return false; } } @@ -1123,7 +1219,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { // check blocker restrictions for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { for (Ability ability : entry.getValue()) { - if (!entry.getKey().canBlock(attacker, this, ability, game)) { + if (!entry.getKey().canBlock(attacker, this, ability, game, true)) { return false; } } @@ -1131,7 +1227,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { // check also attacker's restriction effects for (Map.Entry> restrictionEntry : game.getContinuousEffects().getApplicableRestrictionEffects(attacker, game).entrySet()) { for (Ability ability : restrictionEntry.getValue()) { - if (!restrictionEntry.getKey().canBeBlocked(attacker, this, ability, game)) { + if (!restrictionEntry.getKey().canBeBlocked(attacker, this, ability, game, true)) { return false; } } @@ -1149,7 +1245,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canBlock(null, this, ability, game)) { + if (!effect.canBlock(null, this, ability, game, true)) { return false; } } @@ -1170,7 +1266,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canUseActivatedAbilities(this, ability, game)) { + if (!effect.canUseActivatedAbilities(this, ability, game, true)) { return false; } } @@ -1184,7 +1280,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { for (Map.Entry> entry : game.getContinuousEffects().getApplicableRestrictionEffects(this, game).entrySet()) { RestrictionEffect effect = entry.getKey(); for (Ability ability : entry.getValue()) { - if (!effect.canTransform(this, ability, game)) { + if (!effect.canTransform(this, ability, game, true)) { return false; } } @@ -1441,20 +1537,20 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { //If an object leaves the zone it's in, all attached permanents become unattached //note that this code doesn't actually detach anything, and is a bit of a bandaid public void detachAllAttachments(Game game) { - for(UUID attachmentId : getAttachments()) { + for (UUID attachmentId : getAttachments()) { Permanent attachment = game.getPermanent(attachmentId); Card attachmentCard = game.getCard(attachmentId); - if(attachment != null && attachmentCard != null) { + if (attachment != null && attachmentCard != null) { //make bestow cards and licids into creatures //aura test to stop bludgeon brawl shenanigans from using this code //consider adding code to handle that case? - if(attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { + if (attachment.hasSubtype(SubType.AURA, game) && attachmentCard.isCreature()) { BestowAbility.becomeCreature(attachment, game); } } } } - + @Override public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List appliedEffects) { Zone fromZone = game.getState().getZone(objectId); @@ -1480,7 +1576,7 @@ public abstract class PermanentImpl extends CardImpl implements Permanent { Zone fromZone = game.getState().getZone(objectId); ZoneChangeEvent event = new ZoneChangeEvent(this, sourceId, ownerId, fromZone, Zone.EXILED, appliedEffects); ZoneChangeInfo.Exile info = new ZoneChangeInfo.Exile(event, exileId, name); - + boolean successfullyMoved = ZonesHandler.moveCard(info, game); //20180810 - 701.3d detachAllAttachments(game); diff --git a/Mage/src/main/java/mage/game/permanent/PermanentToken.java b/Mage/src/main/java/mage/game/permanent/PermanentToken.java index bb04a3916d..ba809c2056 100644 --- a/Mage/src/main/java/mage/game/permanent/PermanentToken.java +++ b/Mage/src/main/java/mage/game/permanent/PermanentToken.java @@ -1,15 +1,15 @@ - package mage.game.permanent; -import java.util.UUID; import mage.MageObject; import mage.abilities.Ability; import mage.abilities.costs.mana.ManaCost; +import mage.constants.EmptyNames; import mage.game.Game; import mage.game.permanent.token.Token; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class PermanentToken extends PermanentImpl { @@ -42,6 +42,15 @@ public class PermanentToken extends PermanentImpl { this.toughness.resetToBaseValue(); } + @Override + public String getName() { + if (name.isEmpty()) { + return EmptyNames.FACE_DOWN_TOKEN.toString(); + } else { + return name; + } + } + private void copyFromToken(Token token, Game game, boolean reset) { this.name = token.getName(); this.abilities.clear(); diff --git a/Mage/src/main/java/mage/game/permanent/token/AngelToken.java b/Mage/src/main/java/mage/game/permanent/token/AngelToken.java index 04f1ee9fbc..960758bc3d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/AngelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/AngelToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class AngelToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CFX", "GTC", "ISD", "M14", "ORI", "SOI", "ZEN", "C15", "MM3")); diff --git a/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java new file mode 100644 index 0000000000..5f7b407718 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/AssassinToken2.java @@ -0,0 +1,78 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.TriggeredAbilityImpl; +import mage.abilities.effects.Effect; +import mage.abilities.effects.common.DestroyTargetEffect; +import mage.abilities.keyword.DeathtouchAbility; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.target.targetpointer.FixedTarget; + +/** + * @author TheElk801 + */ +public final class AssassinToken2 extends TokenImpl { + + public AssassinToken2() { + super("Assassin", "1/1 black Assassin creature token with deathtouch and \"Whenever this creature deals damage to a planeswalker, destroy that planeswalker.\""); + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.ASSASSIN); + power = new MageInt(1); + toughness = new MageInt(1); + addAbility(DeathtouchAbility.getInstance()); + addAbility(new AssassinToken2TriggeredAbility()); + + setOriginalExpansionSetCode("WAR"); + } + + private AssassinToken2(final AssassinToken2 token) { + super(token); + } + + public AssassinToken2 copy() { + return new AssassinToken2(this); + } +} + +class AssassinToken2TriggeredAbility extends TriggeredAbilityImpl { + + AssassinToken2TriggeredAbility() { + super(Zone.BATTLEFIELD, null); + } + + private AssassinToken2TriggeredAbility(final AssassinToken2TriggeredAbility effect) { + super(effect); + } + + @Override + public AssassinToken2TriggeredAbility copy() { + return new AssassinToken2TriggeredAbility(this); + } + + @Override + public boolean checkEventType(GameEvent event, Game game) { + return event.getType() == GameEvent.EventType.DAMAGED_PLANESWALKER; + } + + @Override + public boolean checkTrigger(GameEvent event, Game game) { + if (event.getSourceId().equals(getSourceId())) { + Effect effect = new DestroyTargetEffect(); + effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); + this.getEffects().clear(); + this.addEffect(effect); + return true; + } + return false; + } + + @Override + public String getRule() { + return "Whenever this creature deals damage to a planeswalker, destroy that planeswalker."; + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/game/permanent/token/BatToken.java b/Mage/src/main/java/mage/game/permanent/token/BatToken.java index d87677d013..6e22ffb8ce 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BatToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class BatToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("MMA", "C17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken.java index 3ab4664bb5..ed845d62cc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class BeastToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "LRW", "M15", "M14", "DDL", "M13", "M12", "DD3GVL", "NPH", "M11", "M10", "EVE", "MM3", "CMA", "E01")); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java b/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java index d65062a55e..a65f361af9 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/BeastToken2.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class BeastToken2 extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ZEN", "C14", "DDD", "C15", "DD3GVL", "MM3", "CMA", "E01")); diff --git a/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java b/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java deleted file mode 100644 index 199457fcc2..0000000000 --- a/Mage/src/main/java/mage/game/permanent/token/BeckonApparitionToken.java +++ /dev/null @@ -1,34 +0,0 @@ - - -package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; -import mage.abilities.keyword.FlyingAbility; - -/** - * - * @author spjspj - */ -public final class BeckonApparitionToken extends TokenImpl { - - public BeckonApparitionToken() { - super("Spirit", "1/1 white and black Spirit creature token with flying"); - this.setOriginalExpansionSetCode("GTC"); - cardType.add(CardType.CREATURE); - color.setWhite(true); - color.setBlack(true); - subtype.add(SubType.SPIRIT); - power = new MageInt(1); - toughness = new MageInt(1); - this.addAbility(FlyingAbility.getInstance()); - } - public BeckonApparitionToken(final BeckonApparitionToken token) { - super(token); - } - - public BeckonApparitionToken copy() { - return new BeckonApparitionToken(this); - } - -} diff --git a/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java b/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java index 378dbfc769..10da78ae2d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BelzenlokClericToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class BelzenlokClericToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java b/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java index 81883c03a1..214b4f07d6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BelzenlokDemonToken.java @@ -29,7 +29,7 @@ import mage.players.Player; */ public final class BelzenlokDemonToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } @@ -72,7 +72,7 @@ class BelzenlokDemonTokenEffect extends OneShotEffect { static { filter.add(new CardTypePredicate(CardType.CREATURE)); - filter.add(new AnotherPredicate()); + filter.add(AnotherPredicate.instance); } BelzenlokDemonTokenEffect() { diff --git a/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java b/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java new file mode 100644 index 0000000000..3f25f1635e --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/BiogenicOozeToken.java @@ -0,0 +1,26 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class BiogenicOozeToken extends TokenImpl { + + public BiogenicOozeToken() { + super("Ooze", "2/2 green Ooze creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.OOZE); + color.setGreen(true); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + setOriginalExpansionSetCode("RNA"); + } + + public BiogenicOozeToken(final BiogenicOozeToken token) { + super(token); + } + + public BiogenicOozeToken copy() { + return new BiogenicOozeToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java index 33de29d06f..5ac97bf621 100644 --- a/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/BrudicladTelchorMyrToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class BrudicladTelchorMyrToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C18")); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatToken.java b/Mage/src/main/java/mage/game/permanent/token/CatToken.java index 36dd3f2660..bfc82b3969 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class CatToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("SOM", "M13", "M14", "C14", "C15", "C17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java index f6b6dff1ea..63b4f4c6dd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CatWarriorToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class CatWarriorToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("PLC", "C17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java b/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java index a9984358df..30c1e3baa1 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CentaurToken.java @@ -1,31 +1,32 @@ - - package mage.game.permanent.token; +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.util.RandomUtil; + import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; -import mage.util.RandomUtil; /** - * * @author LevelX2 */ public final class CentaurToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("RTR", "MM3")); + tokenImageSets.addAll(Arrays.asList("RTR", "MM3", "RNA")); } public CentaurToken() { super("Centaur", "3/3 green Centaur creature token"); cardType.add(CardType.CREATURE); - setTokenType(RandomUtil.nextInt(2) +1); // randomly take image 1 or 2 + availableImageSetCodes = tokenImageSets; + if (getOriginalExpansionSetCode() != null && getOriginalExpansionSetCode().equals("RNA")) { + setTokenType(RandomUtil.nextInt(2) + 1); // randomly take image 1 or 2 + } color.setGreen(true); subtype.add(SubType.CENTAUR); power = new MageInt(3); diff --git a/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java b/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java index b7e87b1550..ad35700571 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ChainersTormentNightmareToken.java @@ -14,7 +14,7 @@ import mage.MageInt; */ public final class ChainersTormentNightmareToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java b/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java index c6d7aa94a4..c9948238f5 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ClueArtifactToken.java @@ -20,7 +20,7 @@ import java.util.List; */ public final class ClueArtifactToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("SOI", "EDM")); diff --git a/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java b/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java index 1bd425c21c..edbd8a3076 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DeathtouchRatToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class DeathtouchRatToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C17")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/DevilToken.java b/Mage/src/main/java/mage/game/permanent/token/DevilToken.java index 874435a0d1..bb7da534fe 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DevilToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DevilToken.java @@ -21,6 +21,7 @@ public final class DevilToken extends TokenImpl { public DevilToken() { super("Devil", "1/1 red Devil creature with \"When this creature dies, it deals 1 damage to any target.\""); availableImageSetCodes.addAll(Collections.singletonList("SOI")); + availableImageSetCodes.addAll(Collections.singletonList("WAR")); cardType.add(CardType.CREATURE); subtype.add(SubType.DEVIL); color.setRed(true); diff --git a/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java b/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java index 7cec19c091..1fdaffe7b7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DokaiWeaverofLifeToken.java @@ -19,7 +19,7 @@ import mage.filter.common.FilterControlledPermanent; */ public final class DokaiWeaverofLifeToken extends TokenImpl { - final static FilterControlledPermanent filterLands = new FilterControlledLandPermanent("lands you control"); + static final FilterControlledPermanent filterLands = new FilterControlledLandPermanent("lands you control"); public DokaiWeaverofLifeToken() { super("Elemental", "X/X green Elemental creature token, where X is the number of lands you control"); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonToken.java b/Mage/src/main/java/mage/game/permanent/token/DragonToken.java index c190d3bdfb..babf74f8df 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonToken.java @@ -1,25 +1,23 @@ - - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.MageInt; import mage.abilities.keyword.FlyingAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author BetaSteward_at_googlemail.com */ public final class DragonToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA", "MM3", "C17")); + tokenImageSets.addAll(Arrays.asList("DTK", "MMA", "ALA", "MM3", "C17", "WAR")); } public DragonToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java b/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java index 77f5516b95..a5436d7f7c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonToken2.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class DragonToken2 extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("WWK", "10E", "BFZ", "C15", "CN2", "CMA")); diff --git a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java index ca4518c18b..13d468195d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java +++ b/Mage/src/main/java/mage/game/permanent/token/DragonTokenGold.java @@ -16,7 +16,7 @@ import mage.constants.SubType; */ public final class DragonTokenGold extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("UST","H17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java index 093abb0561..467f16a0b3 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EdgarMarkovToken.java @@ -14,7 +14,7 @@ import mage.MageInt; */ public final class EdgarMarkovToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C17")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java index e6c531d8ed..95f042f15b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziHorrorToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class EldraziHorrorToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Collections.singletonList("EMN")); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java index d6c551d4c2..7b5c526790 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziScionToken.java @@ -20,7 +20,7 @@ import mage.util.RandomUtil; */ public final class EldraziScionToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("BFZ", "OGW")); diff --git a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java index e6ebe54a1c..dbbc9dcbda 100644 --- a/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/EldraziSpawnToken.java @@ -20,7 +20,7 @@ import mage.util.RandomUtil; */ public final class EldraziSpawnToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ROE", "MM2", "DDP", "C17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java index 8622dd3dab..88637b7b67 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalShamanToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class ElementalShamanToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C15", "DD3JVC", "DD2", "LRW")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ElementalToken.java index 0befcb97ec..5369b5bff6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElementalToken.java @@ -16,7 +16,7 @@ import mage.constants.SubType; */ public final class ElementalToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("OGW", "CON", "DIS")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java index ef74c81e01..3bdeb7a095 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElephantToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class ElephantToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "CNS", "DDD", "MM2", "WWK", "OGW", "C15", "DD3GVL", "MM3", "CMA")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ElfToken.java b/Mage/src/main/java/mage/game/permanent/token/ElfToken.java index e995729730..baad518b72 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ElfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ElfToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class ElfToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "SHM", "EVG", "LRW", "ORI")); diff --git a/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java b/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java index 974355b47f..a5b324e663 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FaerieRogueToken.java @@ -17,7 +17,7 @@ import mage.abilities.keyword.FlyingAbility; */ public final class FaerieRogueToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("SHM", "MOR", "MMA", "MM2")); diff --git a/Mage/src/main/java/mage/game/permanent/token/FreyaliseLlanowarsFuryToken.java b/Mage/src/main/java/mage/game/permanent/token/FreyaliseLlanowarsFuryToken.java index 4bf277ec07..2f2c3b25ed 100644 --- a/Mage/src/main/java/mage/game/permanent/token/FreyaliseLlanowarsFuryToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FreyaliseLlanowarsFuryToken.java @@ -16,7 +16,7 @@ import mage.abilities.mana.GreenManaAbility; */ public final class FreyaliseLlanowarsFuryToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "CMA")); diff --git a/Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java similarity index 59% rename from Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java rename to Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java index 0f3b2c7dd9..5a11a15633 100644 --- a/Mage/src/main/java/mage/game/permanent/token/RapidHybridizationToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/FrogLizardToken.java @@ -1,19 +1,16 @@ - - package mage.game.permanent.token; + +import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; -import mage.MageInt; /** - * * @author spjspj */ -public final class RapidHybridizationToken extends TokenImpl { +public final class FrogLizardToken extends TokenImpl { - public RapidHybridizationToken() { + public FrogLizardToken() { super("Frog Lizard", "3/3 green Frog Lizard creature token"); - this.setOriginalExpansionSetCode("GTC"); cardType.add(CardType.CREATURE); color.setGreen(true); @@ -25,11 +22,11 @@ public final class RapidHybridizationToken extends TokenImpl { toughness = new MageInt(3); } - public RapidHybridizationToken(final RapidHybridizationToken token) { + public FrogLizardToken(final FrogLizardToken token) { super(token); } - public RapidHybridizationToken copy() { - return new RapidHybridizationToken(this); + public FrogLizardToken copy() { + return new FrogLizardToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/GermToken.java b/Mage/src/main/java/mage/game/permanent/token/GermToken.java index aa122e3048..7b8ed218af 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GermToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GermToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; */ public final class GermToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("NPH", "MBS", "SOM", "EMA", "C16")); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java index 7c923be38a..d2d509018c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoatToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoatToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class GoatToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("EVE", "M13", "M14", "C14")); diff --git a/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java b/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java index e59b7f70df..e78dee90ab 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoblinToken.java @@ -1,26 +1,25 @@ - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.MageInt; import mage.abilities.keyword.HasteAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author North */ public final class GoblinToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("10E", "ALA", "SOM", "M10", "NPH", "M13", "RTR", "MMA", "M15", "C14", "KTK", "EVG", "DTK", "ORI", "DDG", "DDN", "DD3EVG", "MM2", - "MM3", "EMA", "C16", "DOM")); + "MM3", "EMA", "C16", "DOM", "ANA", "RNA", "WAR")); } public GoblinToken(boolean withHaste) { diff --git a/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java b/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java new file mode 100644 index 0000000000..37e965bdbb --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/GodEternalOketraToken.java @@ -0,0 +1,33 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class GodEternalOketraToken extends TokenImpl { + + public GodEternalOketraToken() { + super("Zombie Warrior", "4/4 black Zombie Warrior creature token with vigilance"); + setOriginalExpansionSetCode("WAR"); // default + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.ZOMBIE); + subtype.add(SubType.WARRIOR); + power = new MageInt(4); + toughness = new MageInt(4); + addAbility(VigilanceAbility.getInstance()); + } + + private GodEternalOketraToken(final GodEternalOketraToken token) { + super(token); + } + + @Override + public GodEternalOketraToken copy() { + return new GodEternalOketraToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/GoldToken.java b/Mage/src/main/java/mage/game/permanent/token/GoldToken.java index 87db9f0acc..65f263911b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GoldToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GoldToken.java @@ -17,7 +17,7 @@ import mage.constants.Zone; */ public final class GoldToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("BNG", "C17")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/GolemToken.java b/Mage/src/main/java/mage/game/permanent/token/GolemToken.java index 46945073d0..7f51a49c45 100644 --- a/Mage/src/main/java/mage/game/permanent/token/GolemToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/GolemToken.java @@ -15,7 +15,7 @@ import mage.MageInt; */ public final class GolemToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("MM2", "NPH", "SOM", "MM3")); diff --git a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java index 83524c1f95..b1509f116b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HumanToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HumanToken.java @@ -1,14 +1,12 @@ - - package mage.game.permanent.token; -import java.util.Arrays; +import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; -import mage.MageInt; + +import java.util.Arrays; /** - * * @author LoneFox */ public final class HumanToken extends TokenImpl { @@ -20,7 +18,7 @@ public final class HumanToken extends TokenImpl { subtype.add(SubType.HUMAN); power = new MageInt(1); toughness = new MageInt(1); - availableImageSetCodes.addAll(Arrays.asList("DKA", "AVR", "FNMP")); + availableImageSetCodes.addAll(Arrays.asList("DKA", "AVR", "FNMP", "RNA")); } public HumanToken(final HumanToken token) { @@ -28,7 +26,7 @@ public final class HumanToken extends TokenImpl { } @Override - public HumanToken copy() { + public HumanToken copy() { return new HumanToken(this); } diff --git a/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java b/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java index 66fdb89a16..63fbd6c793 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HuntedCentaurToken.java @@ -16,7 +16,7 @@ import mage.abilities.keyword.ProtectionAbility; */ public final class HuntedCentaurToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("RTR", "MM3")); diff --git a/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java index ccc227663e..f0751efe80 100644 --- a/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/HuntedDragonKnightToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class HuntedDragonKnightToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15")); diff --git a/Mage/src/main/java/mage/game/permanent/token/InsectToken.java b/Mage/src/main/java/mage/game/permanent/token/InsectToken.java index 24ccf81e3c..8b2fa6e4bf 100644 --- a/Mage/src/main/java/mage/game/permanent/token/InsectToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/InsectToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class InsectToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("M10", "MM2", "SOI")); diff --git a/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java b/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java index 39eae8e0d3..aa9ca68498 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KalonianTwingroveTreefolkWarriorToken.java @@ -18,7 +18,7 @@ import mage.filter.predicate.mageobject.SubtypePredicate; */ public final class KalonianTwingroveTreefolkWarriorToken extends TokenImpl { - final static FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); + static final FilterControlledPermanent filterLands = new FilterControlledPermanent("Forests you control"); static { filterLands.add(new SubtypePredicate(SubType.FOREST)); diff --git a/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java b/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java index 7c558f7c31..faa2d6a54b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KarnConstructToken.java @@ -29,7 +29,7 @@ public final class KarnConstructToken extends TokenImpl { filter.add(new CardTypePredicate(CardType.ARTIFACT)); } - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java index 5f1946ff76..cb6a989684 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KaroxBladewingDragonToken.java @@ -15,7 +15,7 @@ import mage.constants.SuperType; */ public final class KaroxBladewingDragonToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java index 3006cb62d6..e69e3735b0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/KnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/KnightToken.java @@ -15,7 +15,7 @@ import mage.util.RandomUtil; */ public final class KnightToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ORI", "RTR", "C15", "CMA", "DOM")); diff --git a/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java b/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java index d62053a100..69cc8040ab 100644 --- a/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/LeafdrakeRoostDrakeToken.java @@ -15,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; */ public final class LeafdrakeRoostDrakeToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C13", "CMA")); diff --git a/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java b/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java index db390f1d50..c8d839e692 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MaritLageToken.java @@ -1,21 +1,21 @@ package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; + import mage.MageInt; import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.IndestructibleAbility; +import mage.constants.CardType; +import mage.constants.SubType; import mage.constants.SuperType; /** - * * @author spjspj */ public final class MaritLageToken extends TokenImpl { public MaritLageToken() { - super("Marit Lage", "legendary 20/20 black Avatar creature token with flying and indestructible named Marit Lage"); + super("Marit Lage", "Marit Lage, a legendary 20/20 black Avatar creature token with flying and indestructible"); this.setOriginalExpansionSetCode("CSP"); cardType.add(CardType.CREATURE); subtype.add(SubType.AVATAR); diff --git a/Mage/src/main/java/mage/game/permanent/token/MaskToken.java b/Mage/src/main/java/mage/game/permanent/token/MaskToken.java index 662ee9e060..fd1619f995 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MaskToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MaskToken.java @@ -10,7 +10,6 @@ import mage.constants.SubType; import mage.target.TargetPermanent; /** - * * @author TheElk801 */ public final class MaskToken extends TokenImpl { @@ -18,8 +17,8 @@ public final class MaskToken extends TokenImpl { public MaskToken() { super( "Mask", "white Aura enchantment token named Mask " - + "attached to another target permanent. " - + "The token has enchant permanent and totem armor." + + "attached to another target permanent. " + + "The token has enchant permanent and totem armor." ); cardType.add(CardType.ENCHANTMENT); color.setWhite(true); @@ -31,6 +30,7 @@ public final class MaskToken extends TokenImpl { ability.addEffect(new AttachEffect(Outcome.BoostCreature)); this.addAbility(ability); + // Totem armor this.addAbility(new TotemArmorAbility()); } diff --git a/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java b/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java new file mode 100644 index 0000000000..c2d50814b8 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/MesmerizingBenthidToken.java @@ -0,0 +1,36 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.common.BlocksTriggeredAbility; +import mage.abilities.effects.common.DontUntapInControllersNextUntapStepTargetEffect; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class MesmerizingBenthidToken extends TokenImpl { + + public MesmerizingBenthidToken() { + super("Illusion", "0/2 blue Illusion creature token with \"Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step.\""); + cardType.add(CardType.CREATURE); + color.setBlue(true); + setOriginalExpansionSetCode("RNA"); + + subtype.add(SubType.ILLUSION); + power = new MageInt(0); + toughness = new MageInt(2); + this.addAbility(new BlocksTriggeredAbility( + new DontUntapInControllersNextUntapStepTargetEffect("that creature"), + false, true + )); + } + + private MesmerizingBenthidToken(final MesmerizingBenthidToken token) { + super(token); + } + + public MesmerizingBenthidToken copy() { + return new MesmerizingBenthidToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java index f3df80a3d7..9077c7f15c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/MyrToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/MyrToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class MyrToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "MM2", "NPH", "SOM")); diff --git a/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java b/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java index ca21913063..383605fd5c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/OviyaPashiriSageLifecrafterToken.java @@ -13,7 +13,7 @@ import mage.util.RandomUtil; */ public final class OviyaPashiriSageLifecrafterToken extends TokenImpl { - final static FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("creatures you control"); + static final FilterControlledCreaturePermanent filterCreature = new FilterControlledCreaturePermanent("creatures you control"); public OviyaPashiriSageLifecrafterToken() { this(1); diff --git a/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java b/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java new file mode 100644 index 0000000000..5405ab5235 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/PlanewideCelebrationToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author TheElk801 + */ +public final class PlanewideCelebrationToken extends TokenImpl { + + public PlanewideCelebrationToken() { + super("Citizen", "2/2 Citizen creature token that's all colors"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + color.setBlue(true); + color.setBlack(true); + color.setRed(true); + color.setGreen(true); + + subtype.add(SubType.CITIZEN); + power = new MageInt(2); + toughness = new MageInt(2); + } + + public PlanewideCelebrationToken(final PlanewideCelebrationToken token) { + super(token); + } + + public PlanewideCelebrationToken copy() { + return new PlanewideCelebrationToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/PlantToken.java b/Mage/src/main/java/mage/game/permanent/token/PlantToken.java index a3b6ebe09d..962b0c657a 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PlantToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PlantToken.java @@ -11,7 +11,7 @@ import mage.constants.SubType; public final class PlantToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("WWK", "DDP", "OGW")); diff --git a/Mage/src/main/java/mage/game/permanent/token/PrismToken.java b/Mage/src/main/java/mage/game/permanent/token/PrismToken.java index fc4275add2..8f0336ee67 100644 --- a/Mage/src/main/java/mage/game/permanent/token/PrismToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/PrismToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class PrismToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Collections.singletonList("VIS")); diff --git a/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java b/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java new file mode 100644 index 0000000000..55a29a38b3 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/RedGreenBeastToken.java @@ -0,0 +1,33 @@ + +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.TrampleAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class RedGreenBeastToken extends TokenImpl { + + public RedGreenBeastToken() { + super("Beast", "4/4 red and green Beast creature token with trample"); + cardType.add(CardType.CREATURE); + color.setRed(true); + color.setGreen(true); + subtype.add(SubType.BEAST); + power = new MageInt(4); + toughness = new MageInt(4); + + this.addAbility(TrampleAbility.getInstance()); + } + + private RedGreenBeastToken(final RedGreenBeastToken token) { + super(token); + } + + public RedGreenBeastToken copy() { + return new RedGreenBeastToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/RevelOfTheFallenGodSatyrToken.java b/Mage/src/main/java/mage/game/permanent/token/RevelOfTheFallenGodSatyrToken.java deleted file mode 100644 index 231f7f3a14..0000000000 --- a/Mage/src/main/java/mage/game/permanent/token/RevelOfTheFallenGodSatyrToken.java +++ /dev/null @@ -1,35 +0,0 @@ - -package mage.game.permanent.token; - -import mage.constants.CardType; -import mage.constants.SubType; -import mage.MageInt; -import mage.ObjectColor; -import mage.abilities.keyword.HasteAbility; - -/** - * - * @author spjspj - */ -public final class RevelOfTheFallenGodSatyrToken extends TokenImpl { - - public RevelOfTheFallenGodSatyrToken() { - super("Satyr", "2/2 red and green Satyr creature tokens with haste"); - this.setOriginalExpansionSetCode("THS"); - cardType.add(CardType.CREATURE); - color.setColor(ObjectColor.RED); - color.setColor(ObjectColor.GREEN); - subtype.add(SubType.SATYR); - power = new MageInt(2); - toughness = new MageInt(2); - addAbility(HasteAbility.getInstance()); - } - - public RevelOfTheFallenGodSatyrToken(final RevelOfTheFallenGodSatyrToken token) { - super(token); - } - - public RevelOfTheFallenGodSatyrToken copy() { - return new RevelOfTheFallenGodSatyrToken(this); - } -} diff --git a/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java b/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java index fb52d5ed7f..a653c0ddbc 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SaprolingToken.java @@ -16,7 +16,7 @@ import mage.util.RandomUtil; */ public final class SaprolingToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList( diff --git a/Mage/src/main/java/mage/game/permanent/token/ServoToken.java b/Mage/src/main/java/mage/game/permanent/token/ServoToken.java index 2a72c0a805..43fc61957d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ServoToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ServoToken.java @@ -15,10 +15,11 @@ import mage.util.RandomUtil; */ public final class ServoToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Collections.singletonList("KLD")); + tokenImageSets.addAll(Collections.singletonList("WAR")); } public ServoToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java b/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java index 2916047a75..88ccc6b506 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SnakeToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class SnakeToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ZEN", "KTK", "MM2", "C15")); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java b/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java index 719e32a1f5..781374b86b 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierToken.java @@ -15,7 +15,7 @@ import mage.util.RandomUtil; */ public final class SoldierToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("10E", "M15", "C14", "ORI", "ALA", "DDF", "THS", "M12", "M13", "MM2", "MMA", "RTR", diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java b/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java index 8c1ad0188c..59fe7b1231 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierTokenWithHaste.java @@ -16,7 +16,7 @@ import mage.abilities.keyword.HasteAbility; */ public final class SoldierTokenWithHaste extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("GTC", "MM3")); diff --git a/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java b/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java new file mode 100644 index 0000000000..34a79a9df8 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/SoldierVigilanceToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class SoldierVigilanceToken extends TokenImpl { + + public SoldierVigilanceToken() { + super("Soldier", "2/2 white Soldier creature token with vigilance"); + + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.SOLDIER); + power = new MageInt(2); + toughness = new MageInt(2); + addAbility(VigilanceAbility.getInstance()); + + setOriginalExpansionSetCode("WAR"); + } + + private SoldierVigilanceToken(final SoldierVigilanceToken token) { + super(token); + } + + @Override + public SoldierVigilanceToken copy() { + return new SoldierVigilanceToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java index 84f2150481..f1e69fe3b0 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiderToken.java @@ -19,7 +19,7 @@ import mage.constants.SubType; */ public final class SpiderToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("ISD", "EMN", "C15", "SHM")); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java index 5a1f7c4dbf..8264a002ee 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritToken.java @@ -13,7 +13,7 @@ import mage.constants.SubType; */ public final class SpiritToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("CHK", "EMA", "C16")); diff --git a/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java b/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java index 5b856ddeda..0b46fd648c 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SpiritWhiteToken.java @@ -1,23 +1,24 @@ - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.MageInt; import mage.abilities.keyword.FlyingAbility; import mage.constants.CardType; import mage.constants.SubType; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * @author nantuko */ public final class SpiritWhiteToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", "SOI", "EMA", "C16", "MM3", "CMA", "E01")); + tokenImageSets.addAll(Arrays.asList("AVR", "C14", "CNS", "DDC", "DDK", "FRF", "ISD", "KTK", "M15", "MM2", "SHM", + "SOI", "EMA", "C16", "MM3", "CMA", "E01", "ANA", "RNA")); } public SpiritWhiteToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java b/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java new file mode 100644 index 0000000000..bc5bfdcbca --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/SplinterToken.java @@ -0,0 +1,35 @@ + +package mage.game.permanent.token; + +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; +import mage.abilities.keyword.CumulativeUpkeepAbility; +import mage.abilities.keyword.FlyingAbility; + +/** + * + * @author L_J + */ +public final class SplinterToken extends TokenImpl { + + public SplinterToken() { + super("Splinter", "1/1 green Splinter creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPLINTER); + color.setGreen(true); + power = new MageInt(1); + toughness = new MageInt(1); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(new CumulativeUpkeepAbility(new ManaCostsImpl("{G}"))); + } + + public SplinterToken(final SplinterToken token) { + super(token); + } + + public SplinterToken copy() { + return new SplinterToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java b/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java index 632b4a0742..9fbee3b13f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/SquirrelToken.java @@ -14,7 +14,7 @@ import mage.constants.SubType; */ public final class SquirrelToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Collections.singletonList("CNS")); diff --git a/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java new file mode 100644 index 0000000000..3e2b867fb3 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/StarfishToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * + * @author spike + */ +public final class StarfishToken extends TokenImpl { + + public StarfishToken() { + this(null, 0); + } + + public StarfishToken(String setCode, int tokenType) { + super("Starfish", "0/1 blue Starfish creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.STARFISH); + color.setBlue(true); + power = new MageInt(0); + toughness = new MageInt(1); + } + + public StarfishToken(final StarfishToken token) { + super(token); + } + + @Override + public StarfishToken copy() { + return new StarfishToken(this); + } +} \ No newline at end of file diff --git a/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java b/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java new file mode 100644 index 0000000000..251ec6ca7d --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/TeyoToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.DefenderAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class TeyoToken extends TokenImpl { + + public TeyoToken() { + super("Wall", "0/3 white Wall creature token with defender"); + cardType.add(CardType.CREATURE); + color.setWhite(true); + subtype.add(SubType.WALL); + power = new MageInt(0); + toughness = new MageInt(3); + addAbility(DefenderAbility.getInstance()); + + setOriginalExpansionSetCode("WAR"); + } + + public TeyoToken(final TeyoToken token) { + super(token); + } + + public TeyoToken copy() { + return new TeyoToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java b/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java index e39bc6107c..d2a6c00ffd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThopterColorlessToken.java @@ -16,7 +16,7 @@ import mage.util.RandomUtil; */ public final class ThopterColorlessToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("MBS", "ORI", "KLD")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java b/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java index cda4a66341..a417cea721 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ThrullToken.java @@ -15,7 +15,7 @@ import mage.constants.SubType; */ public final class ThrullToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Collections.singletonList("MM2")); diff --git a/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java index f7a02d4dd3..38bd95ccd7 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TitaniaProtectorOfArgothElementalToken.java @@ -15,7 +15,7 @@ import mage.ObjectColor; */ public final class TitaniaProtectorOfArgothElementalToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C14", "CMA")); diff --git a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java index 86ba65c2c7..222b063c81 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java +++ b/Mage/src/main/java/mage/game/permanent/token/TokenImpl.java @@ -1,9 +1,5 @@ package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.UUID; import mage.MageObject; import mage.MageObjectImpl; import mage.abilities.Ability; @@ -18,6 +14,11 @@ import mage.game.permanent.PermanentToken; import mage.players.Player; import mage.util.RandomUtil; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + public abstract class TokenImpl extends MageObjectImpl implements Token { protected String description; @@ -241,6 +242,8 @@ public abstract class TokenImpl extends MageObjectImpl implements Token { @Override public void setOriginalExpansionSetCode(String originalExpansionSetCode) { + // TODO: remove original set code at all... token image must be takes by card source or by latest set (on null source) + // TODO: if set have same tokens then selects it by random this.originalExpansionSetCode = originalExpansionSetCode; setTokenDescriptor(); } diff --git a/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java b/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java index aba3940cb6..204dd81471 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/TreasureToken.java @@ -1,9 +1,5 @@ - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; import mage.abilities.Ability; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.TapSourceCost; @@ -13,16 +9,19 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author TheElk801 */ public final class TreasureToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("XLN")); + tokenImageSets.addAll(Arrays.asList("XLN", "RNA")); } public TreasureToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java b/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java new file mode 100644 index 0000000000..8bbb0002e2 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/UginTheIneffableToken.java @@ -0,0 +1,29 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class UginTheIneffableToken extends TokenImpl { + + public UginTheIneffableToken() { + super("Spirit", "2/2 colorless Spirit creature token"); + setExpansionSetCodeForImage("WAR"); // default + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPIRIT); + power = new MageInt(2); + toughness = new MageInt(2); + } + + private UginTheIneffableToken(final UginTheIneffableToken token) { + super(token); + } + + @Override + public UginTheIneffableToken copy() { + return new UginTheIneffableToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java index 4c4672101d..98bedc8bf6 100644 --- a/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/UtvaraHellkiteDragonToken.java @@ -15,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; */ public final class UtvaraHellkiteDragonToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C17")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java index 6bf1df172e..9b10f6d21d 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ValdukElementalToken.java @@ -16,7 +16,7 @@ import mage.abilities.keyword.TrampleAbility; */ public final class ValdukElementalToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java b/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java index 94fa0a262b..cf5134219e 100644 --- a/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/VoiceOfResurgenceToken.java @@ -1,18 +1,15 @@ - package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.dynamicvalue.common.CreaturesYouControlCount; import mage.abilities.effects.common.continuous.SetPowerToughnessSourceEffect; +import mage.constants.CardType; import mage.constants.Duration; +import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.common.FilterControlledCreaturePermanent; /** - * * @author spjspj */ public final class VoiceOfResurgenceToken extends TokenImpl { @@ -28,8 +25,9 @@ public final class VoiceOfResurgenceToken extends TokenImpl { power = new MageInt(0); toughness = new MageInt(0); + // This creature's power and toughness are each equal to the number of creatures you control. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SetPowerToughnessSourceEffect( - new PermanentsOnBattlefieldCount(new FilterControlledCreaturePermanent()), Duration.EndOfGame))); + CreaturesYouControlCount.instance, Duration.EndOfGame))); } public VoiceOfResurgenceToken(final VoiceOfResurgenceToken token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/VojaFriendToElvesToken.java b/Mage/src/main/java/mage/game/permanent/token/VojaFriendToElvesToken.java new file mode 100644 index 0000000000..cb8c66b133 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/VojaFriendToElvesToken.java @@ -0,0 +1,35 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; + +/** + * @author TheElk801 + */ +public final class VojaFriendToElvesToken extends TokenImpl { + + public VojaFriendToElvesToken() { + super("Voja, Friend to Elves", "Voja, Friend to Elves, a legendary 3/3 green and white Wolf creature token"); + this.cardType.add(CardType.CREATURE); + addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.WOLF); + + this.color.setGreen(true); + this.color.setWhite(true); + this.power = new MageInt(3); + this.toughness = new MageInt(3); + + setOriginalExpansionSetCode("WAR"); + } + + private VojaFriendToElvesToken(final VojaFriendToElvesToken token) { + super(token); + } + + public VojaFriendToElvesToken copy() { + return new VojaFriendToElvesToken(this); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java b/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java new file mode 100644 index 0000000000..45542d6ae0 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WardenSphinxToken.java @@ -0,0 +1,34 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.abilities.keyword.FlyingAbility; +import mage.abilities.keyword.VigilanceAbility; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author JayDi85 + */ +public final class WardenSphinxToken extends TokenImpl { + + public WardenSphinxToken() { + super("Sphinx", "4/4 white and blue Sphinx creature token with flying and vigilance"); + this.setOriginalExpansionSetCode("RNA"); + color.setWhite(true); + color.setBlue(true); + cardType.add(CardType.CREATURE); + subtype.add(SubType.SPHINX); + power = new MageInt(4); + toughness = new MageInt(4); + this.addAbility(FlyingAbility.getInstance()); + this.addAbility(VigilanceAbility.getInstance()); + } + + public WardenSphinxToken(final WardenSphinxToken token) { + super(token); + } + + public WardenSphinxToken copy() { + return new WardenSphinxToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java b/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java index 0856aece60..77dc8c07af 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WasitoraCatDragonToken.java @@ -15,7 +15,7 @@ import mage.abilities.keyword.FlyingAbility; */ public final class WasitoraCatDragonToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("C17")); diff --git a/Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java similarity index 67% rename from Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java rename to Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java index 19ccedcc36..7bf6156883 100644 --- a/Mage/src/main/java/mage/game/permanent/token/TeysaEnvoyOfGhostsToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WhiteBlackSpiritToken.java @@ -1,18 +1,18 @@ package mage.game.permanent.token; -import mage.constants.CardType; -import mage.constants.SubType; + import mage.MageInt; import mage.abilities.keyword.FlyingAbility; +import mage.constants.CardType; +import mage.constants.SubType; /** - * * @author spjspj */ -public final class TeysaEnvoyOfGhostsToken extends TokenImpl { +public final class WhiteBlackSpiritToken extends TokenImpl { - public TeysaEnvoyOfGhostsToken() { + public WhiteBlackSpiritToken() { super("Spirit", "1/1 white and black Spirit creature token with flying"); cardType.add(CardType.CREATURE); color.setWhite(true); @@ -23,11 +23,11 @@ public final class TeysaEnvoyOfGhostsToken extends TokenImpl { this.addAbility(FlyingAbility.getInstance()); } - public TeysaEnvoyOfGhostsToken(final TeysaEnvoyOfGhostsToken token) { + public WhiteBlackSpiritToken(final WhiteBlackSpiritToken token) { super(token); } - public TeysaEnvoyOfGhostsToken copy() { - return new TeysaEnvoyOfGhostsToken(this); + public WhiteBlackSpiritToken copy() { + return new WhiteBlackSpiritToken(this); } } diff --git a/Mage/src/main/java/mage/game/permanent/token/WizardToken.java b/Mage/src/main/java/mage/game/permanent/token/WizardToken.java new file mode 100644 index 0000000000..ecc864261f --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WizardToken.java @@ -0,0 +1,31 @@ +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +public final class WizardToken extends TokenImpl { + + public WizardToken() { + this("WAR"); + } + + public WizardToken(String setCode) { + super("Wizard", "2/2 blue Wizard creature token"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WIZARD); + color.setBlue(true); + power = new MageInt(2); + toughness = new MageInt(2); + + setOriginalExpansionSetCode(setCode); + } + + private WizardToken(final WizardToken token) { + super(token); + } + + public WizardToken copy() { + return new WizardToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/WolfToken.java b/Mage/src/main/java/mage/game/permanent/token/WolfToken.java index 90333794a1..8f1a88da77 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WolfToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/WolfToken.java @@ -15,10 +15,10 @@ import mage.constants.SubType; */ public final class WolfToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { - tokenImageSets.addAll(Arrays.asList("BNG", "C14", "CNS", "FNMP", "ISD", "LRW", "M10", "M14", "MM2", "SHM", "SOM", "ZEN", "SOI", "C15", "M15")); + tokenImageSets.addAll(Arrays.asList("BNG", "C14", "CNS", "FNMP", "ISD", "LRW", "M10", "M14", "MM2", "SHM", "SOM", "ZEN", "SOI", "C15", "M15", "WAR")); } public WolfToken() { diff --git a/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java b/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java new file mode 100644 index 0000000000..af156cd597 --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/WolvesOfTheHuntToken.java @@ -0,0 +1,32 @@ + +package mage.game.permanent.token; + +import mage.constants.CardType; +import mage.constants.SubType; +import mage.MageInt; +import mage.abilities.keyword.BandsWithOtherAbility; + +/** + * + * @author L_J + */ +public final class WolvesOfTheHuntToken extends TokenImpl { + + public WolvesOfTheHuntToken() { + super("Wolves of the Hunt", "1/1 green Wolf creature token named Wolves of the Hunt"); + cardType.add(CardType.CREATURE); + subtype.add(SubType.WOLF); + color.setGreen(true); + power = new MageInt(1); + toughness = new MageInt(1); + this.addAbility(new BandsWithOtherAbility("Wolves of the Hunt")); + } + + public WolvesOfTheHuntToken(final WolvesOfTheHuntToken token) { + super(token); + } + + public WolvesOfTheHuntToken copy() { + return new WolvesOfTheHuntToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/Wurm1Token.java b/Mage/src/main/java/mage/game/permanent/token/Wurm1Token.java index da2bc1764c..85d0116826 100644 --- a/Mage/src/main/java/mage/game/permanent/token/Wurm1Token.java +++ b/Mage/src/main/java/mage/game/permanent/token/Wurm1Token.java @@ -1,4 +1,3 @@ - package mage.game.permanent.token; import mage.constants.CardType; @@ -24,6 +23,8 @@ public final class Wurm1Token extends TokenImpl { power = new MageInt(3); toughness = new MageInt(3); this.addAbility(DeathtouchAbility.getInstance()); + + setTokenType(1); // for image } public Wurm1Token(final Wurm1Token token) { diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmToken2.java b/Mage/src/main/java/mage/game/permanent/token/WurmToken2.java index 63aca026ce..598e85a5a4 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmToken2.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmToken2.java @@ -16,7 +16,7 @@ import mage.abilities.keyword.TrampleAbility; */ public final class WurmToken2 extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("RTR", "MM3")); diff --git a/Mage/src/main/java/mage/game/permanent/token/WurmToken3.java b/Mage/src/main/java/mage/game/permanent/token/WurmToken3.java index f30e990cbc..31425bb2bd 100644 --- a/Mage/src/main/java/mage/game/permanent/token/WurmToken3.java +++ b/Mage/src/main/java/mage/game/permanent/token/WurmToken3.java @@ -15,7 +15,7 @@ import mage.MageInt; */ public final class WurmToken3 extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("AKH")); diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java new file mode 100644 index 0000000000..86fe1a490d --- /dev/null +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieArmyToken.java @@ -0,0 +1,32 @@ + +package mage.game.permanent.token; + +import mage.MageInt; +import mage.constants.CardType; +import mage.constants.SubType; + +/** + * @author TheElk801 + */ +public final class ZombieArmyToken extends TokenImpl { + + public ZombieArmyToken() { + super("Zombie Army", "0/0 black Zombie Army creature token"); + setExpansionSetCodeForImage("WAR"); // default + cardType.add(CardType.CREATURE); + color.setBlack(true); + subtype.add(SubType.ZOMBIE); + subtype.add(SubType.ARMY); + power = new MageInt(0); + toughness = new MageInt(0); + } + + private ZombieArmyToken(final ZombieArmyToken token) { + super(token); + } + + @Override + public ZombieArmyToken copy() { + return new ZombieArmyToken(this); + } +} diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java index 7869f2ae18..4927f61524 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieKnightToken.java @@ -12,7 +12,7 @@ import mage.constants.SubType; public final class ZombieKnightToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("DOM")); } diff --git a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java index d0080034f4..397005e22f 100644 --- a/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/ZombieToken.java @@ -1,26 +1,24 @@ - package mage.game.permanent.token; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - import mage.MageInt; import mage.constants.CardType; import mage.constants.SubType; import mage.util.RandomUtil; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** - * * @author BetaSteward_at_googlemail.com */ public final class ZombieToken extends TokenImpl { - final static private List tokenImageSets = new ArrayList<>(); + static final private List tokenImageSets = new ArrayList<>(); static { tokenImageSets.addAll(Arrays.asList("10E", "M10", "M11", "M12", "M13", "M14", "M15", "MBS", "ALA", "ISD", "C14", "C15", "C16", "C17", "CNS", - "MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01")); + "MMA", "BNG", "KTK", "DTK", "ORI", "OGW", "SOI", "EMN", "EMA", "MM3", "AKH", "CMA", "E01", "RNA", "WAR")); } public ZombieToken() { diff --git a/Mage/src/main/java/mage/game/stack/Spell.java b/Mage/src/main/java/mage/game/stack/Spell.java index 281a6485dd..984535269d 100644 --- a/Mage/src/main/java/mage/game/stack/Spell.java +++ b/Mage/src/main/java/mage/game/stack/Spell.java @@ -1,10 +1,5 @@ - package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.Mana; @@ -39,8 +34,12 @@ import mage.players.Player; import mage.util.GameLog; import mage.util.SubTypeList; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class Spell extends StackObjImpl implements Card { @@ -63,7 +62,8 @@ public class Spell extends StackObjImpl implements Card { private final UUID id; private UUID controllerId; - private boolean copiedSpell; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private boolean faceDown; private boolean countered; private boolean resolving = false; @@ -118,7 +118,8 @@ public class Spell extends StackObjImpl implements Card { this.frameStyle = spell.frameStyle; this.controllerId = spell.controllerId; - this.copiedSpell = spell.copiedSpell; + this.copy = spell.copy; + this.copyFrom = (spell.copyFrom != null ? spell.copyFrom.copy() : null); this.faceDown = spell.faceDown; this.countered = spell.countered; this.resolving = spell.resolving; @@ -155,7 +156,7 @@ public class Spell extends StackObjImpl implements Card { public String getActivatedMessage(Game game) { StringBuilder sb = new StringBuilder(); - if (isCopiedSpell()) { + if (isCopy()) { sb.append(" copies "); } else { sb.append(" casts "); @@ -362,7 +363,7 @@ public class Spell extends StackObjImpl implements Card { @Override public void counter(UUID sourceId, Game game, Zone zone, boolean owner, ZoneDetail zoneDetail) { this.countered = true; - if (!isCopiedSpell()) { + if (!isCopy()) { Player player = game.getPlayer(game.getControllerId(sourceId)); if (player == null) { player = game.getPlayer(getControllerId()); @@ -706,7 +707,7 @@ public class Spell extends StackObjImpl implements Card { newAbility.newId(); copy.addSpellAbility(newAbility); } - copy.setCopy(true); + copy.setCopy(true, this); copy.setControllerId(newController); return copy; } @@ -740,7 +741,7 @@ public class Spell extends StackObjImpl implements Card { // 706.10a If a copy of a spell is in a zone other than the stack, it ceases to exist. // If a copy of a card is in any zone other than the stack or the battlefield, it ceases to exist. // These are state-based actions. See rule 704. - if (this.isCopiedSpell() && zone != Zone.STACK) { + if (this.isCopy() && zone != Zone.STACK) { return true; } return card.moveToZone(zone, sourceId, game, flag, appliedEffects); @@ -753,7 +754,7 @@ public class Spell extends StackObjImpl implements Card { @Override public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List appliedEffects) { - if (this.isCopiedSpell()) { + if (this.isCopy()) { game.getStack().remove(this, game); return true; } @@ -835,26 +836,24 @@ public class Spell extends StackObjImpl implements Card { // do nothing } - public void setCopiedSpell(boolean isCopied) { - this.copiedSpell = isCopied; - } - - public boolean isCopiedSpell() { - return this.copiedSpell; - } - public Zone getFromZone() { return this.fromZone; } @Override - public void setCopy(boolean isCopy) { - setCopiedSpell(isCopy); + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); } @Override public boolean isCopy() { - return isCopiedSpell(); + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; } @Override @@ -990,6 +989,7 @@ public class Spell extends StackObjImpl implements Card { @Override public StackObject createCopyOnStack(Game game, Ability source, UUID newControllerId, boolean chooseNewTargets) { Spell copy = this.copySpell(newControllerId); + game.getState().setZone(copy.getId(), Zone.STACK); // required for targeting ex: Nivmagus Elemental game.getStack().push(copy); if (chooseNewTargets) { copy.chooseNewTargets(game, newControllerId); diff --git a/Mage/src/main/java/mage/game/stack/StackAbility.java b/Mage/src/main/java/mage/game/stack/StackAbility.java index 4c7259ed7d..295c229e4a 100644 --- a/Mage/src/main/java/mage/game/stack/StackAbility.java +++ b/Mage/src/main/java/mage/game/stack/StackAbility.java @@ -1,14 +1,11 @@ package mage.game.stack; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.ObjectColor; import mage.abilities.*; import mage.abilities.costs.Cost; +import mage.abilities.costs.CostAdjuster; import mage.abilities.costs.Costs; import mage.abilities.costs.CostsImpl; import mage.abilities.costs.mana.ManaCost; @@ -16,6 +13,7 @@ import mage.abilities.costs.mana.ManaCosts; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.Effect; import mage.abilities.effects.Effects; +import mage.abilities.hint.Hint; import mage.abilities.text.TextPart; import mage.cards.Card; import mage.cards.FrameStyle; @@ -32,8 +30,12 @@ import mage.util.GameLog; import mage.util.SubTypeList; import mage.watchers.Watcher; +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public class StackAbility extends StackObjImpl implements Ability { @@ -47,9 +49,12 @@ public class StackAbility extends StackObjImpl implements Ability { private final Ability ability; private UUID controllerId; + private boolean copy; + private MageObject copyFrom; // copied card INFO (used to call original adjusters) private String name; private String expansionSetCode; private TargetAdjuster targetAdjuster = null; + private CostAdjuster costAdjuster = null; public StackAbility(Ability ability, UUID controllerId) { this.ability = ability; @@ -60,10 +65,13 @@ public class StackAbility extends StackObjImpl implements Ability { public StackAbility(final StackAbility stackAbility) { this.ability = stackAbility.ability.copy(); this.controllerId = stackAbility.controllerId; + this.copy = stackAbility.copy; + this.copyFrom = (stackAbility.copyFrom != null ? stackAbility.copyFrom.copy() : null); this.name = stackAbility.name; this.expansionSetCode = stackAbility.expansionSetCode; this.targetAdjuster = stackAbility.targetAdjuster; this.targetChanged = stackAbility.targetChanged; + this.costAdjuster = stackAbility.costAdjuster; } @Override @@ -104,6 +112,22 @@ public class StackAbility extends StackObjImpl implements Ability { } } + @Override + public void setCopy(boolean isCopy, MageObject copyFrom) { + this.copy = isCopy; + this.copyFrom = (copyFrom != null ? copyFrom.copy() : null); + } + + @Override + public boolean isCopy() { + return this.copy; + } + + @Override + public MageObject getCopyFrom() { + return this.copyFrom; + } + @Override public String getName() { return name; @@ -150,9 +174,7 @@ public class StackAbility extends StackObjImpl implements Ability { @Override public Abilities getAbilities() { - Abilities abilities = new AbilitiesImpl<>(); - abilities.add(ability); - return abilities; + return new AbilitiesImpl<>(ability); } @Override @@ -408,15 +430,6 @@ public class StackAbility extends StackObjImpl implements Ability { throw new UnsupportedOperationException("Not supported."); } - @Override - public void setCopy(boolean isCopy) { - } - - @Override - public boolean isCopy() { - return false; - } - @Override public boolean getRuleAtTheTop() { return this.ability.getRuleAtTheTop(); @@ -518,14 +531,19 @@ public class StackAbility extends StackObjImpl implements Ability { return this.ability.getSourcePermanentIfItStillExists(game); } + @Override + public void setSourceObjectZoneChangeCounter(int zoneChangeCounter) { + ability.setSourceObjectZoneChangeCounter(zoneChangeCounter); + } + @Override public int getSourceObjectZoneChangeCounter() { return ability.getSourceObjectZoneChangeCounter(); } @Override - public void setSourceObject(MageObject sourceObject, Game game) { - throw new UnsupportedOperationException("Not supported."); + public Permanent getSourcePermanentOrLKI(Game game) { + return ability.getSourcePermanentOrLKI(game); } @Override @@ -569,7 +587,7 @@ public class StackAbility extends StackObjImpl implements Ability { Outcome outcome = newAbility.getEffects().isEmpty() ? Outcome.Detriment : newAbility.getEffects().get(0).getOutcome(); if (controller.chooseUse(outcome, "Choose new targets?", source, game)) { newAbility.getTargets().clearChosen(); - newAbility.getTargets().chooseTargets(outcome, newControllerId, newAbility, false, game); + newAbility.getTargets().chooseTargets(outcome, newControllerId, newAbility, false, game, false); } } game.fireEvent(new GameEvent(GameEvent.EventType.COPIED_STACKOBJECT, newStackAbility.getId(), this.getId(), newControllerId)); @@ -611,4 +629,32 @@ public class StackAbility extends StackObjImpl implements Ability { targetAdjuster.adjustTargets(this, game); } } + + @Override + public void setCostAdjuster(CostAdjuster costAdjuster) { + this.costAdjuster = costAdjuster; + } + + @Override + public CostAdjuster getCostAdjuster() { + return costAdjuster; + } + + @Override + public void adjustCosts(Game game) { + if (costAdjuster != null) { + costAdjuster.adjustCosts(this, game); + } + } + + @Override + public List getHints() { + return this.ability.getHints(); + } + + @Override + public Ability addHint(Hint hint) { + // only abilities supports addhint + return null; + } } diff --git a/Mage/src/main/java/mage/game/stack/StackObjImpl.java b/Mage/src/main/java/mage/game/stack/StackObjImpl.java index 12d49f5749..8af461dfdb 100644 --- a/Mage/src/main/java/mage/game/stack/StackObjImpl.java +++ b/Mage/src/main/java/mage/game/stack/StackObjImpl.java @@ -1,12 +1,5 @@ -/* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. - */ package mage.game.stack; -import java.util.Set; -import java.util.UUID; import mage.MageObject; import mage.abilities.Abilities; import mage.abilities.AbilitiesImpl; @@ -21,8 +14,10 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetAmount; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public abstract class StackObjImpl implements StackObject { @@ -44,47 +39,47 @@ public abstract class StackObjImpl implements StackObject { * 114.6. Some effects allow a player to change the target(s) of a spell or * ability, and other effects allow a player to choose new targets for a * spell or ability. - * + *

    * 114.6a If an effect allows a player to "change the target(s)" of a spell * or ability, each target can be changed only to another legal target. If a * target can't be changed to another legal target, the original target is * unchanged, even if the original target is itself illegal by then. If all * the targets aren't changed to other legal targets, none of them are * changed. - * + *

    * 114.6b If an effect allows a player to "change a target" of a spell or * ability, the process described in rule 114.6a is followed, except that * only one of those targets may be changed (rather than all of them or none * of them). - * + *

    * 114.6c If an effect allows a player to "change any targets" of a spell or * ability, the process described in rule 114.6a is followed, except that * any number of those targets may be changed (rather than all of them or * none of them). - * + *

    * 114.6d If an effect allows a player to "choose new targets" for a spell * or ability, the player may leave any number of the targets unchanged, * even if those targets would be illegal. If the player chooses to change * some or all of the targets, the new targets must be legal and must not * cause any unchanged targets to become illegal. - * + *

    * 114.6e When changing targets or choosing new targets for a spell or * ability, only the final set of targets is evaluated to determine whether * the change is legal. - * + *

    * Example: Arc Trail is a sorcery that reads "Arc Trail deals 2 damage to * any target and 1 damage to another target creature or player." The * current targets of Arc Trail are Runeclaw Bear and Llanowar Elves, in * that order. You cast Redirect, an instant that reads "You may choose new * targets for target spell," targeting Arc Trail. You can change the first * target to Llanowar Elves and change the second target to Runeclaw Bear. - * + *

    * 114.7. Modal spells and abilities may have different targeting * requirements for each mode. An effect that allows a player to change the * target(s) of a modal spell or ability, or to choose new targets for a * modal spell or ability, doesn't allow that player to change its mode. * (See rule 700.2.) - * + *

    * 706.10c Some effects copy a spell or ability and state that its * controller may choose new targets for the copy. The player may leave any * number of the targets unchanged, even if those targets would be illegal. @@ -94,13 +89,13 @@ public abstract class StackObjImpl implements StackObject { * * @param game * @param targetControllerId - player that can/has to change the target of - * the spell - * @param forceChange - does only work for targets with maximum of one - * targetId - * @param onlyOneTarget - 114.6b one target must be changed to another - * target - * @param filterNewTarget restriction for the new target, if null nothing is - * cheched + * the spell + * @param forceChange - does only work for targets with maximum of one + * targetId + * @param onlyOneTarget - 114.6b one target must be changed to another + * target + * @param filterNewTarget restriction for the new target, if null nothing is + * cheched * @return */ @Override @@ -163,10 +158,15 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); for (UUID targetId : target.getTargets()) { String targetNames = getNamesOftargets(targetId, game); + String targetAmount = ""; + if (target.getTargetAmount(targetId) > 0) { + targetAmount = " (amount: " + target.getTargetAmount(targetId) + ")"; + } // change the target? Outcome outcome = mode.getEffects().isEmpty() ? Outcome.Detriment : mode.getEffects().get(0).getOutcome(); + if (targetNames != null - && (forceChange || targetController.chooseUse(outcome, "Change this target: " + targetNames + '?', ability, game))) { + && (forceChange || targetController.chooseUse(outcome, "Change this target: " + targetNames + targetAmount + '?', ability, game))) { Set possibleTargets = target.possibleTargets(this.getSourceId(), getControllerId(), game); // choose exactly one other target - already targeted objects are not counted if (forceChange && possibleTargets != null && possibleTargets.size() > 1) { // controller of spell must be used (e.g. TargetOpponent) @@ -179,7 +179,8 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); newTarget.chooseTarget(outcome, getControllerId(), ability, game); - // check target restriction + + // check target restriction TODO: add multiple target checks if (newTarget.getFirstTarget() != null && filterNewTarget != null) { Permanent newTargetPermanent = game.getPermanent(newTarget.getFirstTarget()); if (newTargetPermanent == null || !filterNewTarget.match(newTargetPermanent, game)) { @@ -187,7 +188,13 @@ public abstract class StackObjImpl implements StackObject { newTarget.clearChosen(); } } - } while (targetController.canRespond() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1)); + + // workaround to stop infinite AI choose (remove after chooseTarget can be called with extra filter to disable some ids) + if (iteration > 10) { + break; + } + } + while (targetController.canRespond() && (targetId.equals(newTarget.getFirstTarget()) || newTarget.getTargets().size() != 1)); // choose a new target } else { // build a target definition with exactly one possible target to select that replaces old target diff --git a/Mage/src/main/java/mage/game/tournament/LimitedOptions.java b/Mage/src/main/java/mage/game/tournament/LimitedOptions.java index c8199d9200..0151beed80 100644 --- a/Mage/src/main/java/mage/game/tournament/LimitedOptions.java +++ b/Mage/src/main/java/mage/game/tournament/LimitedOptions.java @@ -1,15 +1,13 @@ - - package mage.game.tournament; +import mage.cards.decks.Deck; +import mage.game.draft.DraftCube; + import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import mage.cards.decks.Deck; -import mage.game.draft.DraftCube; /** - * * @author BetaSteward_at_googlemail.com */ public class LimitedOptions implements Serializable { @@ -20,6 +18,7 @@ public class LimitedOptions implements Serializable { protected DraftCube draftCube; protected int numberBoosters; protected boolean isRandom; + protected boolean isRichMan; protected Deck cubeFromDeck = null; public List getSetCodes() { @@ -66,11 +65,19 @@ public class LimitedOptions implements Serializable { this.numberBoosters = numberBoosters; } - public boolean getIsRandom(){ + public boolean getIsRandom() { return isRandom; } - public void setIsRandom(boolean isRandom){ + + public void setIsRandom(boolean isRandom) { this.isRandom = isRandom; } + public boolean getIsRichMan() { + return isRichMan; + } + + public void setIsRichMan(boolean isRichMan) { + this.isRichMan = isRichMan; + } } diff --git a/Mage/src/main/java/mage/game/tournament/TournamentOptions.java b/Mage/src/main/java/mage/game/tournament/TournamentOptions.java index 2b042d19a1..c81294ce3e 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentOptions.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentOptions.java @@ -24,6 +24,7 @@ public class TournamentOptions implements Serializable { protected int numberRounds; protected String password; protected int quitRatio; + protected int minimumRating; public TournamentOptions(String name, String matchType, int numSeats) { this.name = name; @@ -98,4 +99,8 @@ public class TournamentOptions implements Serializable { public void setQuitRatio(int quitRatio) { this.quitRatio = quitRatio; } + + public int getMinimumRating() { return minimumRating; } + + public void setMinimumRating(int minimumRating) { this.minimumRating = minimumRating; } } diff --git a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java index 6072015d4d..18b063822b 100644 --- a/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java +++ b/Mage/src/main/java/mage/game/tournament/TournamentPlayer.java @@ -1,7 +1,5 @@ - package mage.game.tournament; -import java.util.Set; import mage.cards.decks.Deck; import mage.constants.TournamentPlayerState; import mage.game.result.ResultProtos.TourneyPlayerProto; @@ -10,8 +8,9 @@ import mage.players.Player; import mage.players.PlayerType; import mage.util.TournamentUtil; +import java.util.Set; + /** - * * @author BetaSteward_at_googlemail.com */ public class TournamentPlayer { @@ -93,7 +92,9 @@ public class TournamentPlayer { // Check if the cards included in the deck are the same as in the original deck boolean validDeck = (getDeck().getDeckCompleteHashCode() == deck.getDeckCompleteHashCode()); if (validDeck == false) { - deck.getCards().clear(); // Clear the deck so the player cheating looses the game + // Clear the deck so the player cheating looses the game + deck.getCards().clear(); + deck.getSideboard().clear(); } this.deck = deck; return validDeck; @@ -177,7 +178,6 @@ public class TournamentPlayer { /** * Free resources no longer needed if tournament has ended - * */ public void cleanUpOnTournamentEnd() { this.deck = null; diff --git a/Mage/src/main/java/mage/game/tournament/pairing/SwissPairingMinimalWeightMatching.java b/Mage/src/main/java/mage/game/tournament/pairing/SwissPairingMinimalWeightMatching.java index 8a3add5718..4be6d8f9ff 100644 --- a/Mage/src/main/java/mage/game/tournament/pairing/SwissPairingMinimalWeightMatching.java +++ b/Mage/src/main/java/mage/game/tournament/pairing/SwissPairingMinimalWeightMatching.java @@ -9,7 +9,6 @@ import mage.game.tournament.TournamentPlayer; import java.util.*; /** - * * @author Quercitron */ @@ -23,7 +22,7 @@ public class SwissPairingMinimalWeightMatching { private final int playersCount; - List swissPlayers; + private List swissPlayers; // number of vertexes in graph private final int n; @@ -37,8 +36,8 @@ public class SwissPairingMinimalWeightMatching { swissPlayers = new ArrayList<>(); for (TournamentPlayer tournamentPlayer : players) { PlayerInfo swissPlayer = new PlayerInfo(); - swissPlayer.tournamentPlayer = tournamentPlayer; - swissPlayer.points = tournamentPlayer.getPoints(); + swissPlayer.setTournamentPlayer(tournamentPlayer); + swissPlayer.setPoints(tournamentPlayer.getPoints()); swissPlayers.add(swissPlayer); } @@ -46,8 +45,8 @@ public class SwissPairingMinimalWeightMatching { Collections.shuffle(swissPlayers); Map map = new HashMap<>(); for (int i = 0; i < playersCount; i++) { - swissPlayers.get(i).id = i; - map.put(swissPlayers.get(i).tournamentPlayer, i); + swissPlayers.get(i).setId(i); + map.put(swissPlayers.get(i).getTournamentPlayer(), i); } // calculate Tie Breaker points -- Sum of Opponents' Scores (SOS) @@ -62,10 +61,10 @@ public class SwissPairingMinimalWeightMatching { // a player could have left the tournament, so we should check if id is not null if (id1 != null) { - swissPlayers.get(id1).sosPoints += player2.getPoints(); + swissPlayers.get(id1).setSosPoints(swissPlayers.get(id1).getSosPoints() + player2.getPoints()); } if (id2 != null) { - swissPlayers.get(id2).sosPoints += player1.getPoints(); + swissPlayers.get(id2).setSosPoints(swissPlayers.get(id2).getSosPoints() + player1.getPoints()); } // todo: sos points for byes? maybe add player points? } @@ -73,18 +72,18 @@ public class SwissPairingMinimalWeightMatching { // sort by points and then by sos points swissPlayers.sort((p1, p2) -> { - int result = p2.points - p1.points; + int result = p2.getPoints() - p1.getPoints(); if (result != 0) { return result; } - return p2.sosPoints - p1.sosPoints; + return p2.getSosPoints() - p1.getSosPoints(); }); // order could be changed, update ids and mapping map.clear(); for (int i = 0; i < playersCount; i++) { - swissPlayers.get(i).id = i; - map.put(swissPlayers.get(i).tournamentPlayer, i); + swissPlayers.get(i).setId(i); + map.put(swissPlayers.get(i).getTournamentPlayer(), i); } // count ties and matches between players @@ -125,18 +124,18 @@ public class SwissPairingMinimalWeightMatching { for (int i = 0; i < playersCount; i++) { for (int j = 0; j < i; j++) { w[i][j] = Math.abs(i - j) + - pointsDiffMultiplier * Math.abs(swissPlayers.get(i).points - swissPlayers.get(j).points); + pointsDiffMultiplier * Math.abs(swissPlayers.get(i).getPoints() - swissPlayers.get(j).getPoints()); w[j][i] = w[i][j]; } } } else { for (int i = 0; i < playersCount; i++) { PlayerInfo player = swissPlayers.get(i); - for (int p = player.points; p >= 0; p--) { + for (int p = player.getPoints(); p >= 0; p--) { int first = -1; int last = -1; for (int j = 0; j < playersCount; j++) { - if (swissPlayers.get(j).points == p) { + if (swissPlayers.get(j).getPoints() == p) { if (first < 0) { first = j; } @@ -146,8 +145,8 @@ public class SwissPairingMinimalWeightMatching { if (first < 0) { continue; } - int self = (p == player.points ? i : first - 1); - int diff = pointsDiffMultiplier * (player.points - p); + int self = (p == player.getPoints() ? i : first - 1); + int diff = pointsDiffMultiplier * (player.getPoints() - p); for (int j = Math.max(first, i); j <= last; j++) { w[i][j] = Math.abs(j - (last + first - self)) + diff; w[j][i] = w[i][j]; @@ -168,7 +167,7 @@ public class SwissPairingMinimalWeightMatching { // try to avoid giving the same person multiple byes if (n > playersCount) { for (int i = 0; i < playersCount; i++) { - w[i][n - 1] = 10 * (swissPlayers.get(i).points - swissPlayers.get(playersCount - 1).points) + (playersCount - i - 1); + w[i][n - 1] = 10 * (swissPlayers.get(i).getPoints() - swissPlayers.get(playersCount - 1).getPoints()) + (playersCount - i - 1); w[i][n - 1] += byes[i] * 2000; w[n - 1][i] = w[i][n - 1]; } @@ -195,9 +194,9 @@ public class SwissPairingMinimalWeightMatching { List pairings = new ArrayList<>(); List playerByes = new ArrayList<>(); - Map map = new HashMap<>(); + Map map = new HashMap<>(); for (PlayerInfo player : swissPlayers) { - map.put(player.id, player.tournamentPlayer); + map.put(player.getId(), player.getTournamentPlayer()); } if (n > playersCount) { @@ -218,15 +217,15 @@ public class SwissPairingMinimalWeightMatching { return new RoundPairings(pairings, playerByes); } - boolean[] used; + private boolean[] used; // current pairs - int[] pairs; + private int[] pairs; // current weight - int weight; + private int weight; - int[] result; - int minCost; + private int[] result; + private int minCost; // backtrack all possible pairings and choose one with minimal weight private void makePairings(int t) { @@ -262,13 +261,45 @@ public class SwissPairingMinimalWeightMatching { } static class PlayerInfo { - public int id; + private int id; - public TournamentPlayer tournamentPlayer; + private TournamentPlayer tournamentPlayer; - public int points; + private int points; - public int sosPoints; + private int sosPoints; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public TournamentPlayer getTournamentPlayer() { + return tournamentPlayer; + } + + public void setTournamentPlayer(TournamentPlayer tournamentPlayer) { + this.tournamentPlayer = tournamentPlayer; + } + + public int getPoints() { + return points; + } + + public void setPoints(int points) { + this.points = points; + } + + public int getSosPoints() { + return sosPoints; + } + + public void setSosPoints(int sosPoints) { + this.sosPoints = sosPoints; + } } } diff --git a/Mage/src/main/java/mage/players/Library.java b/Mage/src/main/java/mage/players/Library.java index 3c896d5b83..3f930f781f 100644 --- a/Mage/src/main/java/mage/players/Library.java +++ b/Mage/src/main/java/mage/players/Library.java @@ -1,15 +1,15 @@ - package mage.players; -import java.io.Serializable; -import java.util.*; -import java.util.stream.Collectors; import mage.cards.Card; import mage.constants.Zone; import mage.filter.FilterCard; import mage.game.Game; import mage.util.RandomUtil; +import java.io.Serializable; +import java.util.*; +import java.util.stream.Collectors; + /** * @author BetaSteward_at_googlemail.com */ @@ -186,7 +186,9 @@ public class Library implements Serializable { Map cards = new HashMap<>(); for (UUID cardId : library) { Card card = game.getCard(cardId); - cards.putIfAbsent(card.getName(), card); + if (card != null) { + cards.putIfAbsent(card.getName(), card); + } } return cards.values(); } @@ -234,4 +236,17 @@ public class Library implements Serializable { public void reset() { this.emptyDraw = false; } + + /** + * Tests only -- find card position in library + */ + public int getCardPosition(UUID cardId) { + UUID[] list = library.toArray(new UUID[0]); + for (int i = 0; i < list.length; i++) { + if (list[i].equals(cardId)) { + return i; + } + } + return -1; + } } diff --git a/Mage/src/main/java/mage/players/ManaPool.java b/Mage/src/main/java/mage/players/ManaPool.java index f95b01e136..ee51d6c703 100644 --- a/Mage/src/main/java/mage/players/ManaPool.java +++ b/Mage/src/main/java/mage/players/ManaPool.java @@ -94,21 +94,26 @@ public class ManaPool implements Serializable { * @return */ public boolean pay(ManaType manaType, Ability ability, Filter filter, Game game, Cost costToPay, Mana usedManaToPay) { - if (!isAutoPayment() && manaType != unlockedManaType) { + if (!isAutoPayment() + && manaType != unlockedManaType) { // if manual payment and the needed mana type was not unlocked, nothing will be paid return false; } - ManaType possibleAsThoughtPoolManaType = null; - if (isAutoPayment() && isAutoPaymentRestricted() && !wasManaAddedBeyondStock() && manaType != unlockedManaType) { + ManaType possibleAsThoughPoolManaType = null; + if (isAutoPayment() + && isAutoPaymentRestricted() + && !wasManaAddedBeyondStock() + && manaType != unlockedManaType) { // if automatic restricted payment and there is already mana in the pool // and the needed mana type was not unlocked, nothing will be paid if (unlockedManaType != null) { ManaPoolItem checkItem = new ManaPoolItem(); checkItem.add(unlockedManaType, 1); - possibleAsThoughtPoolManaType = game.getContinuousEffects().asThoughMana(manaType, checkItem, ability.getSourceId(), ability, ability.getControllerId(), game); + possibleAsThoughPoolManaType = game.getContinuousEffects().asThoughMana(manaType, checkItem, ability.getSourceId(), ability, ability.getControllerId(), game); } // Check if it's possible to use mana as thought for the unlocked manatype in the mana pool for this ability - if (possibleAsThoughtPoolManaType == null || possibleAsThoughtPoolManaType != unlockedManaType) { + if (possibleAsThoughPoolManaType == null + || possibleAsThoughPoolManaType != unlockedManaType) { return false; // if it's not possible return } } @@ -123,12 +128,17 @@ public class ManaPool implements Serializable { if (filter != null) { if (!filter.match(mana.getSourceObject(), game)) { // Prevent that cost reduction by convoke is filtered out - if (!(mana.getSourceObject() instanceof Spell) || ability.getSourceId().equals(mana.getSourceId())) { + if (!(mana.getSourceObject() instanceof Spell) + || ability.getSourceId().equals(mana.getSourceId())) { continue; } } } - if (possibleAsThoughtPoolManaType == null && manaType != unlockedManaType && isAutoPayment() && isAutoPaymentRestricted() && mana.count() == mana.getStock()) { + if (possibleAsThoughPoolManaType == null + && manaType != unlockedManaType + && isAutoPayment() + && isAutoPaymentRestricted() + && mana.count() == mana.getStock()) { // no mana added beyond the stock so don't auto pay this continue; } @@ -164,7 +174,8 @@ public class ManaPool implements Serializable { if (mana.isConditional() && mana.getConditionalMana().get(manaType) > 0 && mana.getConditionalMana().apply(ability, game, mana.getSourceId(), costToPay)) { - if (filter == null || filter.match(mana.getSourceObject(), game)) { + if (filter == null + || filter.match(mana.getSourceObject(), game)) { return mana.getConditionalMana().get(manaType); } } @@ -173,7 +184,8 @@ public class ManaPool implements Serializable { } public int getConditionalCount(Ability ability, Game game, FilterMana filter, Cost costToPay) { - if (ability == null || getConditionalMana().isEmpty()) { + if (ability == null + || getConditionalMana().isEmpty()) { return 0; } int count = 0; @@ -210,7 +222,8 @@ public class ManaPool implements Serializable { for (ManaType manaType : ManaType.values()) { if (!doNotEmptyManaTypes.contains(manaType)) { if (item.get(manaType) > 0) { - if (item.getDuration() != Duration.EndOfTurn || game.getPhase().getType() == TurnPhase.END) { + if (item.getDuration() != Duration.EndOfTurn + || game.getPhase().getType() == TurnPhase.END) { if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) { int amount = item.get(manaType); item.clear(manaType); @@ -223,7 +236,8 @@ public class ManaPool implements Serializable { } if (conditionalItem != null) { if (conditionalItem.get(manaType) > 0) { - if (item.getDuration() != Duration.EndOfTurn || game.getPhase().getType() == TurnPhase.END) { + if (item.getDuration() != Duration.EndOfTurn + || game.getPhase().getType() == TurnPhase.END) { if (game.replaceEvent(new GameEvent(GameEvent.EventType.EMPTY_MANA_POOL, playerId, null, playerId))) { int amount = conditionalItem.get(manaType); conditionalItem.clear(manaType); @@ -378,7 +392,8 @@ public class ManaPool implements Serializable { if (!game.replaceEvent(new ManaEvent(EventType.ADD_MANA, source.getId(), source.getSourceId(), playerId, mana))) { if (mana instanceof ConditionalMana) { ManaPoolItem item = new ManaPoolItem((ConditionalMana) mana, source.getSourceObject(game), - ((ConditionalMana) mana).getManaProducerOriginalId() != null ? ((ConditionalMana) mana).getManaProducerOriginalId() : source.getOriginalId()); + ((ConditionalMana) mana).getManaProducerOriginalId() != null + ? ((ConditionalMana) mana).getManaProducerOriginalId() : source.getOriginalId()); if (emptyOnTurnsEnd) { item.setDuration(Duration.EndOfTurn); } diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index a730164f73..6e5c31dc3b 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -85,6 +85,8 @@ public interface Player extends MageItem, Copyable { int gainLife(int amount, Game game, UUID sourceId); + int damage(int damage, UUID sourceId, Game game); + int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable); int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable, List appliedEffects); @@ -335,20 +337,31 @@ public interface Player extends MageItem, Copyable { boolean removeFromLibrary(Card card, Game game); - boolean searchLibrary(TargetCardInLibrary target, Game game); + boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game); - boolean searchLibrary(TargetCardInLibrary target, Game game, boolean triggerEvents); + boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, boolean triggerEvents); - boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId); + boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId); /** * @param target + * @param source * @param game * @param targetPlayerId player whose library will be searched * @param triggerEvents whether searching will trigger any game events * @return true if search was successful */ - boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents); + boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, boolean triggerEvents); + + /** + * Reveals all players' libraries. Useful for abilities like Jace, Architect of Thought's -8 + * that have effects that require information from all libraries. + * + * @param source + * @param game + * @return + */ + void lookAtAllLibraries(Ability source, Game game); boolean canPlayLand(); @@ -361,6 +374,7 @@ public interface Player extends MageItem, Copyable { * @param ignoreTiming if it's cast during the resolution of another spell * no sorcery or play land timing restriction are checked. For a land it has * to be the turn of the player playing that card. + * @param reference mage object that allows to play the card * @return */ boolean playCard(Card card, Game game, boolean noMana, boolean ignoreTiming, MageObjectReference reference); @@ -370,7 +384,7 @@ public interface Player extends MageItem, Copyable { * @param game * @param ignoreTiming false - it won't be checked if the stack is empty and * you are able to play a Sorcery. It's still checked, if you are able to - * play a land concerning the numner of lands you already played. + * play a land concerning the number of lands you already played. * @return */ boolean playLand(Card card, Game game, boolean ignoreTiming); @@ -383,9 +397,9 @@ public interface Player extends MageItem, Copyable { boolean hasProtectionFrom(MageObject source, Game game); - boolean flipCoin(Game game); + boolean flipCoin(Ability source, Game game, boolean winnable); - boolean flipCoin(Game game, ArrayList appliedEffects); + boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList appliedEffects); int rollDice(Game game, int numSides); @@ -640,9 +654,10 @@ public interface Player extends MageItem, Copyable { * * @param card * @param game + * @param abilitiesToActivate extra info about abilities that can be activated on NO option * @return player looked at the card */ - boolean lookAtFaceDownCard(Card card, Game game); + boolean lookAtFaceDownCard(Card card, Game game, int abilitiesToActivate); /** * Set seconds left to play the game. diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 2659dfd145..ee6ac479b7 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -1,9 +1,6 @@ package mage.players; -import java.io.Serializable; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.Map.Entry; +import com.google.common.collect.ImmutableMap; import mage.ConditionalMana; import mage.MageObject; import mage.MageObjectReference; @@ -46,11 +43,8 @@ import mage.filter.predicate.permanent.PermanentIdPredicate; import mage.game.*; import mage.game.combat.CombatGroup; import mage.game.command.CommandObject; -import mage.game.events.DamagePlayerEvent; -import mage.game.events.DamagedPlayerEvent; -import mage.game.events.GameEvent; +import mage.game.events.*; import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; import mage.game.match.MatchPlayer; import mage.game.permanent.Permanent; import mage.game.permanent.PermanentCard; @@ -72,6 +66,11 @@ import mage.util.GameLog; import mage.util.RandomUtil; import org.apache.log4j.Logger; +import java.io.Serializable; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.Map.Entry; + public abstract class PlayerImpl implements Player, Serializable { private static final Logger logger = Logger.getLogger(PlayerImpl.class); @@ -106,7 +105,7 @@ public abstract class PlayerImpl implements Player, Serializable { // priority control protected boolean passed; // player passed priority protected boolean passedTurn; // F4 - protected boolean passedTurnSkipStack; // F6 + protected boolean passedTurnSkipStack; // F6 // TODO: research protected boolean passedUntilEndOfTurn; // F5 protected boolean passedUntilNextMain; // F7 protected boolean passedUntilStackResolved; // F10 @@ -180,11 +179,9 @@ public abstract class PlayerImpl implements Player, Serializable { /** * During some steps we can't play anything */ - protected final Map silentPhaseSteps = new HashMap() { - { - put(PhaseStep.DECLARE_ATTACKERS, Step.StepPart.PRE); - } - }; + protected final Map silentPhaseSteps = ImmutableMap.builder(). + put(PhaseStep.DECLARE_ATTACKERS, Step.StepPart.PRE).build(); + public PlayerImpl(String name, RangeOfInfluence range) { this(UUID.randomUUID()); @@ -618,9 +615,7 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } } - if (hasProtectionFrom(source, game)) { - return false; - } + return !hasProtectionFrom(source, game); } return true; @@ -718,19 +713,23 @@ public abstract class PlayerImpl implements Player, Serializable { if (amount <= 0) { return discardedCards; } + + // all without dialogs if (this.getHand().size() == 1 || this.getHand().size() == amount) { - discardedCards.addAll(this.getHand()); - while (!this.getHand().isEmpty()) { - discard(this.getHand().get(this.getHand().iterator().next(), game), source, game); + List cardsToDiscard = new ArrayList<>(this.getHand()); + for (UUID id : cardsToDiscard) { + if (discard(this.getHand().get(id, game), source, game)) { + discardedCards.add(id); + } } return discardedCards; } + if (random) { for (int i = 0; i < amount; i++) { Card card = this.getHand().getRandom(game); - if (card != null) { + if (discard(card, source, game)) { discardedCards.add(card); - discard(card, source, game); } } } else { @@ -738,10 +737,8 @@ public abstract class PlayerImpl implements Player, Serializable { TargetDiscard target = new TargetDiscard(possibleAmount, possibleAmount, new FilterCard(CardUtil.numberToText(possibleAmount, "a") + " card" + (possibleAmount > 1 ? "s" : "")), playerId); choose(Outcome.Discard, target, source == null ? null : source.getSourceId(), game); for (UUID cardId : target.getTargets()) { - Card card = this.getHand().get(cardId, game); - if (card != null) { // can happen if user is removed (session expires) - discardedCards.add(card); - discard(card, source, game); + if (discard(this.getHand().get(cardId, game), source, game)) { + discardedCards.add(cardId); } } } @@ -883,30 +880,27 @@ public abstract class PlayerImpl implements Player, Serializable { if (!cardsToLibrary.isEmpty()) { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException if (!anyOrder) { - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - if (card != null) { - cards.remove(card); - moveObjectToLibrary(card.getId(), source == null ? null : source.getSourceId(), game, false, false); - } else { - return false;// probably cards were removed because player left the game - } + // random order + List ids = new ArrayList<>(cards); + Collections.shuffle(ids); + for (UUID id : ids) { + moveObjectToLibrary(id, source == null ? null : source.getSourceId(), game, false, false); } } else { - TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card to put on the bottom of your library (last one chosen will be bottommost)")); + // user defined order + TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card ORDER to put on the BOTTOM of your library (last one chosen will be bottommost)")); target.setRequired(true); - while (cards.size() > 1) { - this.choose(Outcome.Neutral, cards, target, game); - if (!canRespond()) { - return false; - } + while (cards.size() > 1 && this.canRespond() && this.choose(Outcome.Neutral, cards, target, game)) { UUID targetObjectId = target.getFirstTarget(); + if (targetObjectId == null) { + break; + } cards.remove(targetObjectId); moveObjectToLibrary(targetObjectId, source == null ? null : source.getSourceId(), game, false, false); target.clearChosen(); } - if (cards.size() == 1) { - moveObjectToLibrary(cards.iterator().next(), source == null ? null : source.getSourceId(), game, false, false); + for (UUID c : cards) { + moveObjectToLibrary(c, source == null ? null : source.getSourceId(), game, false, false); } } } @@ -948,30 +942,27 @@ public abstract class PlayerImpl implements Player, Serializable { Cards cards = new CardsImpl(cardsToLibrary); // prevent possible ConcurrentModificationException UUID sourceId = (source == null ? null : source.getSourceId()); if (!anyOrder) { - while (!cards.isEmpty()) { - Card card = cards.getRandom(game); - if (card != null) { - cards.remove(card.getId()); - moveObjectToLibrary(card.getId(), source == null ? null : source.getSourceId(), game, true, false); - } else { - return false; // probably cards were removed because player left the game - } + // random order + List ids = new ArrayList<>(cards); + Collections.shuffle(ids); + for (UUID id : ids) { + moveObjectToLibrary(id, source == null ? null : source.getSourceId(), game, true, false); } } else { - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put on the top of your library (last one chosen will be topmost)")); + // user defined order + TargetCard target = new TargetCard(Zone.ALL, new FilterCard("card ORDER to put on the TOP of your library (last one chosen will be topmost)")); target.setRequired(true); - while (cards.size() > 1) { - this.choose(Outcome.Neutral, cards, target, game); - if (!canRespond()) { - return false; - } + while (cards.size() > 1 && this.canRespond() && this.choose(Outcome.Neutral, cards, target, game)) { UUID targetObjectId = target.getFirstTarget(); + if (targetObjectId == null) { + break; + } cards.remove(targetObjectId); - moveObjectToLibrary(targetObjectId, sourceId, game, true, false); + moveObjectToLibrary(targetObjectId, source == null ? null : source.getSourceId(), game, true, false); target.clearChosen(); } - if (cards.size() == 1) { - moveObjectToLibrary(cards.iterator().next(), sourceId, game, true, false); + for (UUID c : cards) { + moveObjectToLibrary(c, source == null ? null : source.getSourceId(), game, true, false); } } } @@ -1041,15 +1032,15 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean cast(SpellAbility ability, Game game, boolean noMana, MageObjectReference permittingObject) { - if (game == null || ability == null) { + public boolean cast(SpellAbility originalAbility, Game game, boolean noMana, MageObjectReference permittingObject) { + if (game == null || originalAbility == null) { return false; } // Use ability copy to avoid problems with targets and costs on recast (issue https://github.com/magefree/mage/issues/5189). - ability = ability.copy(); - + SpellAbility ability = originalAbility.copy(); ability.setControllerId(getId()); + ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId())); if (ability.getSpellAbilityType() != SpellAbilityType.BASE) { ability = chooseSpellAbilityForCast(ability, game, noMana); if (ability == null) { @@ -1073,6 +1064,8 @@ public abstract class PlayerImpl implements Player, Serializable { logger.error("Got no spell from stack. ability: " + ability.getRule()); return false; } + // Update the zcc to the stack + ability.setSourceObjectZoneChangeCounter(game.getState().getZoneChangeCounter(ability.getSourceId())); // some effects set sourceId to cast without paying mana costs or other costs if (ability.getSourceId().equals(getCastSourceIdWithAlternateMana())) { Ability spellAbility = spell.getSpellAbility(); @@ -1119,6 +1112,9 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean playLand(Card card, Game game, boolean ignoreTiming) { // Check for alternate casting possibilities: e.g. land with Morph + if (card == null) { + return false; + } ActivatedAbility playLandAbility = null; boolean found = false; for (Ability ability : card.getAbilities()) { @@ -1143,8 +1139,14 @@ public abstract class PlayerImpl implements Player, Serializable { } //20091005 - 114.2a ActivationStatus activationStatus = playLandAbility.canActivate(this.playerId, game); - if (!ignoreTiming && !activationStatus.canActivate()) { - return false; + if (ignoreTiming) { + if (!canPlayLand()) { + return false; // ignore timing does not mean that more lands than normal can be played + } + } else { + if (!activationStatus.canActivate()) { + return false; + } } //20091005 - 305.1 @@ -1333,7 +1335,7 @@ public abstract class PlayerImpl implements Player, Serializable { switch (((SpellAbility) ability).getSpellAbilityType()) { case SPLIT_FUSED: if (zone == Zone.HAND) { - if (((SpellAbility) ability).canChooseTarget(game)) { + if (ability.canChooseTarget(game)) { useable.put(ability.getId(), (SpellAbility) ability); } } @@ -1398,21 +1400,37 @@ public abstract class PlayerImpl implements Player, Serializable { if (zone != Zone.HAND) { if (Zone.GRAVEYARD == zone && canPlayCardsFromGraveyard()) { for (ActivatedAbility ability : candidateAbilites.getPlayableAbilities(Zone.HAND)) { - if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { + if (canUse + || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { if (ability.canActivate(playerId, game).canActivate()) { output.put(ability.getId(), ability); } } } } - if (zone != Zone.BATTLEFIELD - && null != game.getContinuousEffects().asThough(object.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) { + if (zone != Zone.BATTLEFIELD) { for (Ability ability : candidateAbilites) { - if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { - ability.setControllerId(this.getId()); - if (ability instanceof ActivatedAbility && ability.getZone().match(Zone.HAND) - && ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) { - output.put(ability.getId(), (ActivatedAbility) ability); + if (game.getContinuousEffects().asThough(object.getId(), + AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, + null, + this.getId(), + game) + != null + // if anyone sees an issue with this code, please report it. Worked in my testing. + || game.getContinuousEffects().asThough(object.getId(), + AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, + ability, + this.getId(), + game) + != null) { + if (canUse + || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { + ability.setControllerId(this.getId()); + if (ability instanceof ActivatedAbility + && ability.getZone().match(Zone.HAND) + && ((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) { + output.put(ability.getId(), (ActivatedAbility) ability); + } } } } @@ -1447,37 +1465,39 @@ public abstract class PlayerImpl implements Player, Serializable { for (ActivatedAbility ability : otherAbilities) { if (canUse || ability.getAbilityType() == AbilityType.SPECIAL_ACTION) { Card card = game.getCard(ability.getSourceId()); - if (card.isSplitCard() && ability instanceof FlashbackAbility) { - FlashbackAbility flashbackAbility; - // Left Half - if (card.isInstant()) { - flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT); - } else { - flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY); - } - flashbackAbility.setSourceId(card.getId()); - flashbackAbility.setControllerId(card.getOwnerId()); - flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT); - flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName()); - if (flashbackAbility.canActivate(playerId, game).canActivate()) { - useable.put(flashbackAbility.getId(), flashbackAbility); - } - // Right Half - if (card.isInstant()) { - flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT); - } else { - flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY); - } - flashbackAbility.setSourceId(card.getId()); - flashbackAbility.setControllerId(card.getOwnerId()); - flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT); - flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName()); - if (flashbackAbility.canActivate(playerId, game).canActivate()) { - useable.put(flashbackAbility.getId(), flashbackAbility); - } + if (card != null) { + if (card.isSplitCard() && ability instanceof FlashbackAbility) { + FlashbackAbility flashbackAbility; + // Left Half + if (card.isInstant()) { + flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.INSTANT); + } else { + flashbackAbility = new FlashbackAbility(((SplitCard) card).getLeftHalfCard().getManaCost(), TimingRule.SORCERY); + } + flashbackAbility.setSourceId(card.getId()); + flashbackAbility.setControllerId(card.getOwnerId()); + flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_LEFT); + flashbackAbility.setAbilityName(((SplitCard) card).getLeftHalfCard().getName()); + if (flashbackAbility.canActivate(playerId, game).canActivate()) { + useable.put(flashbackAbility.getId(), flashbackAbility); + } + // Right Half + if (card.isInstant()) { + flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.INSTANT); + } else { + flashbackAbility = new FlashbackAbility(((SplitCard) card).getRightHalfCard().getManaCost(), TimingRule.SORCERY); + } + flashbackAbility.setSourceId(card.getId()); + flashbackAbility.setControllerId(card.getOwnerId()); + flashbackAbility.setSpellAbilityType(SpellAbilityType.SPLIT_RIGHT); + flashbackAbility.setAbilityName(((SplitCard) card).getRightHalfCard().getName()); + if (flashbackAbility.canActivate(playerId, game).canActivate()) { + useable.put(flashbackAbility.getId(), flashbackAbility); + } - } else { - useable.put(ability.getId(), ability); + } else { + useable.put(ability.getId(), ability); + } } } } @@ -1620,7 +1640,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, null, game); + untap &= effect.canBeUntapped(permanent, null, game, true); } if (untap) { canBeUntapped.add(permanent); @@ -1681,9 +1701,7 @@ public abstract class PlayerImpl implements Player, Serializable { leftForUntap = getPermanentsThatCanBeUntapped(game, canBeUntapped, handledEntry.getKey().getKey(), notMoreThanEffectsUsage); // remove already selected permanents for (Permanent permanent : selectedToUntap) { - if (leftForUntap.contains(permanent)) { - leftForUntap.remove(permanent); - } + leftForUntap.remove(permanent); } } else { @@ -1729,7 +1747,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (Permanent permanent : game.getBattlefield().getAllActivePermanents(playerId)) { boolean untap = true; for (RestrictionEffect effect : game.getContinuousEffects().getApplicableRestrictionEffects(permanent, game).keySet()) { - untap &= effect.canBeUntapped(permanent, null, game); + untap &= effect.canBeUntapped(permanent, null, game, true); } if (untap) { permanent.untap(game); @@ -1910,6 +1928,11 @@ public abstract class PlayerImpl implements Player, Serializable { return 0; } + @Override + public int damage(int damage, UUID sourceId, Game game) { + return doDamage(damage, sourceId, game, true, false, null); + } + @Override public int damage(int damage, UUID sourceId, Game game, boolean combatDamage, boolean preventable) { return doDamage(damage, sourceId, game, combatDamage, preventable, null); @@ -1947,7 +1970,7 @@ public abstract class PlayerImpl implements Player, Serializable { sourceControllerId = ((Card) source).getOwnerId(); } else if (source instanceof CommandObject) { sourceControllerId = ((CommandObject) source).getControllerId(); - sourceAbilities = ((CommandObject) source).getAbilities(); + sourceAbilities = source.getAbilities(); } } else { sourceAbilities = ((Permanent) source).getAbilities(game); @@ -2015,6 +2038,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public void removeCounters(String name, int amount, Ability source, Game game) { + int finalAmount = 0; for (int i = 0; i < amount; i++) { if (!counters.removeCounter(name, 1)) { break; @@ -2024,7 +2048,13 @@ public abstract class PlayerImpl implements Player, Serializable { event.setData(name); event.setAmount(1); game.fireEvent(event); + finalAmount++; } + GameEvent event = GameEvent.getEvent(GameEvent.EventType.COUNTERS_REMOVED, + getId(), (source == null ? null : source.getSourceId()), (source == null ? null : source.getControllerId())); + event.setData(name); + event.setAmount(finalAmount); + game.fireEvent(event); } protected boolean canDamage(MageObject source, Game game) { @@ -2364,7 +2394,9 @@ public abstract class PlayerImpl implements Player, Serializable { setStoredBookmark(game.bookmarkState()); // makes it possible to UNDO a declared attacker with costs from e.g. Propaganda } Permanent attacker = game.getPermanent(attackerId); - if (attacker != null && attacker.canAttack(defenderId, game) && attacker.isControlledBy(playerId)) { + if (attacker != null + && attacker.canAttack(defenderId, game) + && attacker.isControlledBy(playerId)) { if (!game.getCombat().declareAttacker(attackerId, defenderId, playerId, game)) { game.undo(playerId); } @@ -2392,22 +2424,22 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game) { - return searchLibrary(target, game, playerId, true); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game) { + return searchLibrary(target, source, game, playerId, true); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, boolean triggerEvents) { - return searchLibrary(target, game, playerId, triggerEvents); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, boolean triggerEvents) { + return searchLibrary(target, source, game, playerId, triggerEvents); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId) { - return searchLibrary(target, game, targetPlayerId, true); + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId) { + return searchLibrary(target, source, game, targetPlayerId, true); } @Override - public boolean searchLibrary(TargetCardInLibrary target, Game game, UUID targetPlayerId, boolean triggerEvents) { + public boolean searchLibrary(TargetCardInLibrary target, Ability source, Game game, UUID targetPlayerId, boolean triggerEvents) { //20091005 - 701.14c Library searchedLibrary = null; String searchInfo = null; @@ -2424,7 +2456,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (searchedLibrary == null) { return false; } - GameEvent event = GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY, targetPlayerId, playerId, playerId, Integer.MAX_VALUE); + GameEvent event = GameEvent.getEvent(GameEvent.EventType.SEARCH_LIBRARY, targetPlayerId, source.getSourceId(), playerId, Integer.MAX_VALUE); if (!game.replaceEvent(event)) { if (!game.isSimulation()) { game.informPlayers(searchInfo); @@ -2463,13 +2495,14 @@ public abstract class PlayerImpl implements Player, Serializable { for (UUID targetId : newTarget.getTargets()) { target.add(targetId, game); } - if (triggerEvents) { - game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, targetPlayerId, playerId)); - } + } else if (targetPlayerId.equals(playerId) && handleLibraryCastableCards(library, game, targetPlayerId)) { // for handling Panglacial Wurm newTarget.clearChosen(); continue; } + if (triggerEvents) { + game.fireEvent(GameEvent.getEvent(GameEvent.EventType.LIBRARY_SEARCHED, targetPlayerId, playerId)); + } break; } while (true); return true; @@ -2477,6 +2510,17 @@ public abstract class PlayerImpl implements Player, Serializable { return false; } + @Override + public void lookAtAllLibraries(Ability source, Game game) { + for (UUID playerId : game.getState().getPlayersInRange(this.getId(), game)) { + Player player = game.getPlayer(playerId); + String playerName = this.getName().equals(player.getName()) ? "Your " : player.getName() + "'s "; + playerName += "library"; + Cards cardsInLibrary = new CardsImpl(player.getLibrary().getTopCards(game, player.getLibrary().size())); + lookAtCards(playerName, cardsInLibrary, game); + } + } + private boolean handleLibraryCastableCards(Library library, Game game, UUID targetPlayerId) { // for handling Panglacial Wurm boolean alreadyChosenUse = false; @@ -2486,7 +2530,7 @@ public abstract class PlayerImpl implements Player, Serializable { for (Card card : library.getCards(game)) { for (Ability ability : card.getAbilities()) { if (ability.getClass() == WhileSearchingPlayFromLibraryAbility.class) { - libraryCastableCardTracker.put(card.getId(), card.getName() + " [" + card.getId().toString().substring(0, 3) + "]"); + libraryCastableCardTracker.put(card.getId(), card.getIdName()); } } } @@ -2531,27 +2575,60 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean flipCoin(Game game) { - return this.flipCoin(game, null); + public boolean flipCoin(Ability source, Game game, boolean winnable) { + return this.flipCoin(source, game, winnable, null); } /** + * @param source * @param game + * @param winnable * @param appliedEffects - * @return true if player won the toss + * @return if winnable, true if player won the toss, if not winnable, true + * for heads and false for tails */ @Override - public boolean flipCoin(Game game, ArrayList appliedEffects) { + public boolean flipCoin(Ability source, Game game, boolean winnable, ArrayList appliedEffects) { + boolean chosen = false; + if (winnable) { + chosen = this.chooseUse(Outcome.Benefit, "Heads or tails?", "", "Heads", "Tails", source, game); + game.informPlayers(getLogName() + " chose " + CardUtil.booleanToFlipName(chosen)); + } boolean result = RandomUtil.nextBoolean(); - if (!game.isSimulation()) { - game.informPlayers("[Flip a coin] " + getLogName() + (result ? " won (head)." : " lost (tail).")); + FlipCoinEvent event = new FlipCoinEvent(playerId, source.getSourceId(), result, chosen, winnable); + event.addAppliedEffects(appliedEffects); + game.replaceEvent(event); + game.informPlayers(getLogName() + " flipped " + CardUtil.booleanToFlipName(event.getResult())); + if (event.getFlipCount() > 1) { + boolean canChooseHeads = event.getResult(); + boolean canChooseTails = !event.getResult(); + for (int i = 1; i < event.getFlipCount(); i++) { + boolean tempFlip = RandomUtil.nextBoolean(); + canChooseHeads = canChooseHeads || tempFlip; + canChooseTails = canChooseTails || !tempFlip; + game.informPlayers(getLogName() + " flipped " + CardUtil.booleanToFlipName(tempFlip)); + } + if (canChooseHeads && canChooseTails) { + event.setResult(chooseUse(Outcome.Benefit, "Choose which flip to keep", + (event.isWinnable() ? "(You called " + event.getChosenName() + ")" : null), + "Heads", "Tails", source, game + )); + } else if (canChooseHeads) { + event.setResult(true); + } else { + event.setResult(false); + } + game.informPlayers(getLogName() + " chose to keep " + CardUtil.booleanToFlipName(event.getResult())); + } + if (event.isWinnable()) { + game.informPlayers(getLogName() + " " + (event.getResult() == event.getChosen() ? "won" : "lost") + " the flip"); } - GameEvent event = new GameEvent(GameEvent.EventType.FLIP_COIN, playerId, null, playerId, 0, result); event.setAppliedEffects(appliedEffects); - if (!game.replaceEvent(event)) { - game.fireEvent(new GameEvent(GameEvent.EventType.COIN_FLIPPED, playerId, null, playerId, 0, event.getFlag())); + game.fireEvent(event.getFlippedEvent()); + if (event.isWinnable()) { + return event.getResult() == event.getChosen(); } - return event.getFlag(); + return event.getResult(); } @Override @@ -2562,14 +2639,14 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numSides Number of sides the dice has + * @param numSides Number of sides the dice has * @return the number that the player rolled */ @Override public int rollDice(Game game, ArrayList appliedEffects, int numSides) { int result = RandomUtil.nextInt(numSides) + 1; if (!game.isSimulation()) { - game.informPlayers("[Roll a die] " + getLogName() + " rolled a " + result + " on a " + numSides + " sided dice"); + game.informPlayers("[Roll a die] " + getLogName() + " rolled a " + result + " on a " + numSides + " sided die"); } GameEvent event = new GameEvent(GameEvent.EventType.ROLL_DICE, playerId, null, playerId, result, true); event.setAppliedEffects(appliedEffects); @@ -2596,10 +2673,10 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param game * @param appliedEffects - * @param numberChaosSides The number of chaos sides the planar die - * currently has (normally 1 but can be 5) + * @param numberChaosSides The number of chaos sides the planar die + * currently has (normally 1 but can be 5) * @param numberPlanarSides The number of chaos sides the planar die - * currently has (normally 1) + * currently has (normally 1) * @return the outcome that the player rolled. Either ChaosRoll, PlanarRoll * or NilRoll */ @@ -2756,7 +2833,7 @@ public abstract class PlayerImpl implements Player, Serializable { /** * @param ability - * @param available if null, it won't be checked if enough mana is available + * @param available if null, it won't be checked if enough mana is available * @param sourceObject * @param game * @return @@ -2819,9 +2896,7 @@ public abstract class PlayerImpl implements Player, Serializable { } } } - if (canPlayCardByAlternateCost(card, available, ability, game)) { - return true; - } + return canPlayCardByAlternateCost(card, available, ability, game); } return false; } @@ -3032,7 +3107,7 @@ public abstract class PlayerImpl implements Player, Serializable { if (player != null) { if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) { Card card = player.getLibrary().getFromTop(game); - if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, card.getSpellAbility(), getId(), game)) { + if (card != null && null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, card.getSpellAbility(), getId(), game)) { for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) { if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) { playable.add(ability); @@ -3308,7 +3383,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean canPaySacrificeCost(Permanent permanent, UUID sourceId, - UUID controllerId, Game game + UUID controllerId, Game game ) { return sacrificeCostFilter == null || !sacrificeCostFilter.match(permanent, sourceId, controllerId, game); } @@ -3383,10 +3458,13 @@ public abstract class PlayerImpl implements Player, Serializable { } @Override - public boolean lookAtFaceDownCard(Card card, Game game - ) { + public boolean lookAtFaceDownCard(Card card, Game game, int abilitiesToActivate) { if (null != game.getContinuousEffects().asThough(card.getId(), AsThoughEffectType.LOOK_AT_FACE_DOWN, card.getSpellAbility(), this.getId(), game)) { - if (chooseUse(Outcome.Benefit, "Look at that card?", null, game)) { + // two modes: look at card or not to look and activate other abilities + String lookMessage = abilitiesToActivate > 0 ? "Look at that card (it's have " + abilitiesToActivate + " abilities to activate)?" : "Look at that card?"; + String lookYes = "Yes, look at card"; + String lookNo = abilitiesToActivate > 0 ? "No, activate ability" : "No"; + if (chooseUse(Outcome.Benefit, lookMessage, "", lookYes, lookNo, null, game)) { Cards cards = new CardsImpl(card); this.lookAtCards(getName() + " - " + sdf.format(System.currentTimeMillis()), cards, game); return true; @@ -3456,8 +3534,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Card card, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { Set cardList = new HashSet<>(); if (card != null) { @@ -3468,22 +3546,22 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCards(Cards cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards.getCards(game), toZone, source, game); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game + Ability source, Game game ) { return moveCards(cards, toZone, source, game, false, false, false, null); } @Override public boolean moveCards(Set cards, Zone toZone, - Ability source, Game game, - boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects + Ability source, Game game, + boolean tapped, boolean faceDown, boolean byOwner, List appliedEffects ) { if (cards.isEmpty()) { return true; @@ -3554,7 +3632,7 @@ public abstract class PlayerImpl implements Player, Serializable { case OUTSIDE: for (Card card : cards) { if (card instanceof Permanent) { - game.getBattlefield().removePermanent(((Permanent) card).getId()); + game.getBattlefield().removePermanent(card.getId()); ZoneChangeEvent event = new ZoneChangeEvent(card.getId(), (source == null ? null : source.getSourceId()), byOwner ? card.getOwnerId() : getId(), Zone.BATTLEFIELD, Zone.OUTSIDE, appliedEffects); game.fireEvent(event); @@ -3569,8 +3647,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Card card, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { Set cards = new HashSet<>(); cards.add(card); @@ -3579,8 +3657,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardsToExile(Set cards, Ability source, - Game game, boolean withName, UUID exileId, - String exileZoneName + Game game, boolean withName, UUID exileId, + String exileZoneName ) { if (cards.isEmpty()) { return true; @@ -3595,14 +3673,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game + Game game ) { return this.moveCardToHandWithInfo(card, sourceId, game, true); } @Override public boolean moveCardToHandWithInfo(Card card, UUID sourceId, - Game game, boolean withName + Game game, boolean withName ) { boolean result = false; Zone fromZone = game.getState().getZone(card.getId()); @@ -3627,7 +3705,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public Set moveCardsToGraveyardWithInfo(Set allCards, Ability source, - Game game, Zone fromZone + Game game, Zone fromZone ) { UUID sourceId = source == null ? null : source.getSourceId(); Set movedCards = new LinkedHashSet<>(); @@ -3635,7 +3713,7 @@ public abstract class PlayerImpl implements Player, Serializable { // identify cards from one owner Cards cards = new CardsImpl(); UUID ownerId = null; - for (Iterator it = allCards.iterator(); it.hasNext();) { + for (Iterator it = allCards.iterator(); it.hasNext(); ) { Card card = it.next(); if (cards.isEmpty()) { ownerId = card.getOwnerId(); @@ -3696,14 +3774,14 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToGraveyardWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone + Game game, Zone fromZone ) { if (card == null) { return false; } boolean result = false; // Zone fromZone = game.getState().getZone(card.getId()); - if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null ? fromZone == Zone.BATTLEFIELD : false)) { + if (card.moveToZone(Zone.GRAVEYARD, sourceId, game, fromZone != null && fromZone == Zone.BATTLEFIELD)) { if (!game.isSimulation()) { if (card instanceof PermanentCard && game.getCard(card.getId()) != null) { card = game.getCard(card.getId()); @@ -3725,8 +3803,8 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToLibraryWithInfo(Card card, UUID sourceId, - Game game, Zone fromZone, - boolean toTop, boolean withName + Game game, Zone fromZone, + boolean toTop, boolean withName ) { if (card == null) { return false; @@ -3760,7 +3838,7 @@ public abstract class PlayerImpl implements Player, Serializable { @Override public boolean moveCardToExileWithInfo(Card card, UUID exileId, String exileName, UUID sourceId, - Game game, Zone fromZone, boolean withName) { + Game game, Zone fromZone, boolean withName) { if (card == null) { return false; } @@ -3775,7 +3853,7 @@ public abstract class PlayerImpl implements Player, Serializable { } } else if (card instanceof Spell) { final Spell spell = (Spell) card; - if (spell.isCopiedSpell()) { + if (spell.isCopy()) { // Copied spell, only remove from stack game.getStack().remove(spell, game); } @@ -3896,13 +3974,8 @@ public abstract class PlayerImpl implements Player, Serializable { Cards cards = new CardsImpl(); cards.addAll(getLibrary().getTopCards(game, value)); if (!cards.isEmpty()) { - String text; - if (cards.size() == 1) { - text = "card if you want to put it on the bottom of your library (Scry)"; - } else { - text = "cards you want to put on the bottom of your library (Scry)"; - } - TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text)); + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, + new FilterCard("cards to PUT on the BOTTOM of your library (Scry)")); chooseTarget(Outcome.Benefit, cards, target, source, game); putCardsOnBottomOfLibrary(new CardsImpl(target.getTargets()), game, source, true); cards.removeAll(target.getTargets()); @@ -3922,13 +3995,8 @@ public abstract class PlayerImpl implements Player, Serializable { Cards cards = new CardsImpl(); cards.addAll(getLibrary().getTopCards(game, event.getAmount())); if (!cards.isEmpty()) { - String text; - if (cards.size() == 1) { - text = "card if you want to put it into your graveyard (Surveil)"; - } else { - text = "cards you want to put into your graveyard (Surveil)"; - } - TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, new FilterCard(text)); + TargetCard target = new TargetCard(0, cards.size(), Zone.LIBRARY, + new FilterCard("cards to PUT into your GRAVEYARD (Surveil)")); chooseTarget(Outcome.Benefit, cards, target, source, game); moveCards(new CardsImpl(target.getTargets()), Zone.GRAVEYARD, source, game); cards.removeAll(target.getTargets()); diff --git a/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java b/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java index 1db6d8cfa9..dd077671d8 100644 --- a/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java +++ b/Mage/src/main/java/mage/players/net/UserSkipPrioritySteps.java @@ -1,10 +1,8 @@ - package mage.players.net; import java.io.Serializable; /** - * * @author LevelX2 */ public class UserSkipPrioritySteps implements Serializable { @@ -12,10 +10,12 @@ public class UserSkipPrioritySteps implements Serializable { final SkipPrioritySteps yourTurn; final SkipPrioritySteps opponentTurn; - boolean stopOnDeclareAttackersDuringSkipAction = true; - boolean stopOnDeclareBlockerIfNoneAvailable = true; + boolean stopOnDeclareAttackers = true; + boolean stopOnDeclareBlockersWithZeroPermanents = false; + boolean stopOnDeclareBlockersWithAnyPermanents = true; boolean stopOnAllMainPhases = true; boolean stopOnAllEndPhases = true; + boolean stopOnStackNewObjects = true; public UserSkipPrioritySteps() { yourTurn = new SkipPrioritySteps(); @@ -30,20 +30,28 @@ public class UserSkipPrioritySteps implements Serializable { return opponentTurn; } - public boolean isStopOnDeclareBlockerIfNoneAvailable() { - return stopOnDeclareBlockerIfNoneAvailable; + public boolean isStopOnDeclareBlockersWithZeroPermanents() { + return stopOnDeclareBlockersWithZeroPermanents; } - public void setStopOnDeclareBlockerIfNoneAvailable(boolean stopOnDeclareBlockerIfNoneAvailable) { - this.stopOnDeclareBlockerIfNoneAvailable = stopOnDeclareBlockerIfNoneAvailable; + public void setStopOnDeclareBlockersWithZeroPermanents(boolean stopOnDeclareBlockersWithZeroPermanents) { + this.stopOnDeclareBlockersWithZeroPermanents = stopOnDeclareBlockersWithZeroPermanents; } - public boolean isStopOnDeclareAttackersDuringSkipAction() { - return stopOnDeclareAttackersDuringSkipAction; + public boolean isStopOnDeclareAttackers() { + return stopOnDeclareAttackers; } public void setStopOnDeclareAttackersDuringSkipActions(boolean stopOnDeclareAttackersDuringSkipActions) { - this.stopOnDeclareAttackersDuringSkipAction = stopOnDeclareAttackersDuringSkipActions; + this.stopOnDeclareAttackers = stopOnDeclareAttackersDuringSkipActions; + } + + public boolean isStopOnDeclareBlockersWithAnyPermanents() { + return stopOnDeclareBlockersWithAnyPermanents; + } + + public void setStopOnDeclareBlockersWithAnyPermanents(boolean stopOnDeclareBlockersWithAnyPermanents) { + this.stopOnDeclareBlockersWithAnyPermanents = stopOnDeclareBlockersWithAnyPermanents; } public boolean isStopOnAllMainPhases() { @@ -62,4 +70,11 @@ public class UserSkipPrioritySteps implements Serializable { this.stopOnAllEndPhases = stopOnAllEndPhases; } + public boolean isStopOnStackNewObjects() { + return stopOnStackNewObjects; + } + + public void setStopOnStackNewObjects(boolean stopOnStackNewObjects) { + this.stopOnStackNewObjects = stopOnStackNewObjects; + } } diff --git a/Mage/src/main/java/mage/target/Target.java b/Mage/src/main/java/mage/target/Target.java index f5818468dc..a9b7d45ec0 100644 --- a/Mage/src/main/java/mage/target/Target.java +++ b/Mage/src/main/java/mage/target/Target.java @@ -1,10 +1,5 @@ - package mage.target; -import java.io.Serializable; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.abilities.Ability; import mage.constants.Outcome; import mage.constants.Zone; @@ -12,8 +7,12 @@ import mage.filter.Filter; import mage.game.Game; import mage.players.Player; +import java.io.Serializable; +import java.util.List; +import java.util.Set; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public interface Target extends Serializable { @@ -30,7 +29,7 @@ public interface Target extends Serializable { * controls if it will be checked, if the target can be targeted from source * * @param notTarget true = do not check for protection, false = check for - * protection + * protection */ void setNotTarget(boolean notTarget); @@ -136,4 +135,5 @@ public interface Target extends Serializable { // used for cards like Spellskite void setTargetAmount(UUID targetId, int amount, Game game); + Target withChooseHint(String chooseHint); } diff --git a/Mage/src/main/java/mage/target/TargetImpl.java b/Mage/src/main/java/mage/target/TargetImpl.java index 110b67203c..8d7a0e061d 100644 --- a/Mage/src/main/java/mage/target/TargetImpl.java +++ b/Mage/src/main/java/mage/target/TargetImpl.java @@ -1,16 +1,5 @@ - package mage.target; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - import mage.MageObject; import mage.abilities.Ability; import mage.cards.Card; @@ -23,6 +12,8 @@ import mage.game.events.GameEvent.EventType; import mage.players.Player; import mage.util.RandomUtil; +import java.util.*; + /** * @author BetaSteward_at_googlemail.com */ @@ -45,6 +36,7 @@ public abstract class TargetImpl implements Target { protected UUID abilityController = null; // only used if target controller != ability controller protected int targetTag; // can be set if other target check is needed (AnotherTargetPredicate) + protected String chooseHint = null; // UI choose hints after target name @Override public abstract TargetImpl copy(); @@ -72,6 +64,7 @@ public abstract class TargetImpl implements Target { this.targetController = target.targetController; this.abilityController = target.abilityController; this.targetTag = target.targetTag; + this.chooseHint = target.chooseHint; } @Override @@ -101,12 +94,11 @@ public abstract class TargetImpl implements Target { @Override public String getMessage() { + // UI choose message String suffix = ""; -// if (targetController != null) { -// // Hint for the selecting player that the targets must be valid from the point of the ability controller -// // e.g. select opponent text may be misleading otherwise -// suffix = " (target controlling!)"; -// } + if (this.chooseHint != null) { + suffix = " (" + this.chooseHint + ")"; + } if (getMaxNumberOfTargets() != 1) { StringBuilder sb = new StringBuilder(); sb.append("Select ").append(targetName); @@ -277,7 +269,14 @@ public abstract class TargetImpl implements Target { @Override public boolean choose(Outcome outcome, UUID playerId, UUID sourceId, Game game) { Player player = game.getPlayer(playerId); + if (player == null) { + return false; + } + while (!isChosen() && !doneChosing()) { + if (!player.canRespond()) { + return chosen = targets.size() >= getNumberOfTargets(); + } chosen = targets.size() >= getNumberOfTargets(); if (!player.choose(outcome, this, sourceId, game)) { return chosen; @@ -289,19 +288,22 @@ public abstract class TargetImpl implements Target { @Override public boolean chooseTarget(Outcome outcome, UUID playerId, Ability source, Game game) { + Player player = game.getPlayer(playerId); + if (player == null) { + return false; + } + + List possibleTargets = new ArrayList<>(possibleTargets(source.getSourceId(), playerId, game)); while (!isChosen() && !doneChosing()) { + if (!player.canRespond()) { + return chosen = targets.size() >= getNumberOfTargets(); + } chosen = targets.size() >= getNumberOfTargets(); if (isRandom()) { - Set possibleTargets = possibleTargets(source.getSourceId(), playerId, game); if (!possibleTargets.isEmpty()) { - int i = 0; - int rnd = RandomUtil.nextInt(possibleTargets.size()); - Iterator it = possibleTargets.iterator(); - while (i < rnd) { - it.next(); - i++; - } - this.addTarget(((UUID) it.next()), source, game); + int index = RandomUtil.nextInt(possibleTargets.size()); + this.addTarget(possibleTargets.get(index), source, game); + possibleTargets.remove(index); } else { return chosen; } @@ -401,7 +403,7 @@ public abstract class TargetImpl implements Target { for (int K = minK; K <= maxK; K++) { // get the combination by index // e.g. 01 --> AB , 23 --> CD - int combination[] = new int[K]; + int[] combination = new int[K]; // position of current index // if (r = 1) r* @@ -544,4 +546,9 @@ public abstract class TargetImpl implements Target { rememberZoneChangeCounter(targetId, game); } + @Override + public Target withChooseHint(String chooseHint) { + this.chooseHint = chooseHint; + return this; + } } diff --git a/Mage/src/main/java/mage/target/TargetStackObject.java b/Mage/src/main/java/mage/target/TargetStackObject.java index a9eb6a3b4b..eeccdc2df7 100644 --- a/Mage/src/main/java/mage/target/TargetStackObject.java +++ b/Mage/src/main/java/mage/target/TargetStackObject.java @@ -1,10 +1,9 @@ - - package mage.target; -import mage.constants.Zone; import mage.abilities.Ability; +import mage.constants.Zone; import mage.filter.FilterStackObject; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.stack.StackObject; @@ -13,7 +12,6 @@ import java.util.Set; import java.util.UUID; /** - * * @author BetaSteward_at_googlemail.com */ public class TargetStackObject extends TargetObject { @@ -21,7 +19,7 @@ public class TargetStackObject extends TargetObject { protected final FilterStackObject filter; public TargetStackObject() { - this(1, 1, new FilterStackObject()); + this(1, 1, StaticFilters.FILTER_SPELL_OR_ABILITY); } public TargetStackObject(FilterStackObject filter) { @@ -59,7 +57,7 @@ public class TargetStackObject extends TargetObject { @Override public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { int count = 0; - for (StackObject stackObject: game.getStack()) { + for (StackObject stackObject : game.getStack()) { if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { @@ -78,7 +76,7 @@ public class TargetStackObject extends TargetObject { @Override public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { Set possibleTargets = new HashSet<>(); - for (StackObject stackObject: game.getStack()) { + for (StackObject stackObject : game.getStack()) { if (game.getState().getPlayersInRange(sourceControllerId, game).contains(stackObject.getControllerId()) && filter.match(stackObject, sourceId, sourceControllerId, game)) { possibleTargets.add(stackObject.getId()); } diff --git a/Mage/src/main/java/mage/target/Targets.java b/Mage/src/main/java/mage/target/Targets.java index a1645e12d4..64c67c104a 100644 --- a/Mage/src/main/java/mage/target/Targets.java +++ b/Mage/src/main/java/mage/target/Targets.java @@ -1,10 +1,11 @@ - package mage.target; import mage.abilities.Ability; import mage.constants.Outcome; import mage.game.Game; import mage.game.events.GameEvent; +import mage.target.targetpointer.*; +import org.apache.log4j.Logger; import java.util.ArrayList; import java.util.List; @@ -12,11 +13,12 @@ import java.util.UUID; import java.util.stream.Collectors; /** - * * @author BetaSteward_at_googlemail.com */ public class Targets extends ArrayList { + private static final Logger logger = Logger.getLogger(Targets.class); + public Targets() { } @@ -59,7 +61,7 @@ public class Targets extends ArrayList { return true; } - public boolean chooseTargets(Outcome outcome, UUID playerId, Ability source, boolean noMana, Game game) { + public boolean chooseTargets(Outcome outcome, UUID playerId, Ability source, boolean noMana, Game game, boolean canCancel) { if (this.size() > 0) { if (!canChoose(source.getSourceId(), playerId, game)) { return false; @@ -68,12 +70,23 @@ public class Targets extends ArrayList { while (!isChosen()) { Target target = this.getUnchosen().get(0); UUID targetController = playerId; - if (target.getTargetController() != null) { // some targets can have controller different than ability controller + + // some targets can have controller different than ability controller + if (target.getTargetController() != null) { targetController = target.getTargetController(); } - if (noMana) { // if cast without mana (e.g. by suspend you may not be able to cancel the casting if you are able to cast it + + // if cast without mana (e.g. by suspend you may not be able to cancel the casting if you are able to cast it + if (noMana) { target.setRequired(true); } + + // can be cancel by user + if (canCancel) { + target.setRequired(false); + } + + // make response checks if (!target.chooseTarget(outcome, targetController, source, game)) { return false; } @@ -101,7 +114,7 @@ public class Targets extends ArrayList { * Checks if there are enough targets that can be chosen. Should only be * used for Ability targets since this checks for protection, shroud etc. * - * @param sourceId - the target event source + * @param sourceId - the target event source * @param sourceControllerId - controller of the target event source * @param game * @return - true if enough valid targets exist @@ -130,6 +143,42 @@ public class Targets extends ArrayList { return null; } + public Target getEffectTarget(TargetPointer targetPointer) { + boolean proccessed = false; + + if (targetPointer instanceof FirstTargetPointer) { + proccessed = true; + if (this.size() > 0) { + return this.get(0); + } + } + + if (targetPointer instanceof SecondTargetPointer) { + proccessed = true; + if (this.size() > 1) { + return this.get(1); + } + } + + if (targetPointer instanceof ThirdTargetPointer) { + proccessed = true; + if (this.size() > 2) { + return this.get(2); + } + } + + if (targetPointer instanceof FixedTarget || targetPointer instanceof FixedTargets) { + // fixed target = direct ID, you can't find target type and description + proccessed = true; + } + + if (!proccessed) { + logger.error("Unknown target pointer " + (targetPointer != null ? targetPointer : "null"), new Throwable()); + } + + return null; + } + public Targets copy() { return new Targets(this); } diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java index 64bbbe3611..5e1ca2be78 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedAbility.java @@ -50,6 +50,7 @@ public class TargetActivatedAbility extends TargetObject { return stackObject != null && stackObject.getStackAbility() != null && stackObject.getStackAbility().getAbilityType() == AbilityType.ACTIVATED + && source != null && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); } diff --git a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java index a348ad4122..6552c4bba0 100644 --- a/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java +++ b/Mage/src/main/java/mage/target/common/TargetActivatedOrTriggeredAbility.java @@ -42,7 +42,7 @@ public class TargetActivatedOrTriggeredAbility extends TargetObject { } StackObject stackObject = game.getStack().getStackObject(id); - return isActivatedOrTriggeredAbility(stackObject) && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); + return isActivatedOrTriggeredAbility(stackObject) && source != null && filter.match(stackObject, source.getSourceId(), source.getControllerId(), game); } @Override diff --git a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java index 71ae125321..2e923b3fb6 100644 --- a/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java +++ b/Mage/src/main/java/mage/target/common/TargetCardInLibrary.java @@ -61,6 +61,10 @@ public class TargetCardInLibrary extends TargetCard { targetPlayer = player; } + if (player == null) { + return false; + } + List cards; if (librarySearchLimit == Integer.MAX_VALUE) { cards = targetPlayer.getLibrary().getCards(game); @@ -72,14 +76,17 @@ public class TargetCardInLibrary extends TargetCard { for (Card card : cards) { cardsId.add(card); } + while (!isChosen() && !doneChosing()) { + if (!player.canRespond()) { + return chosen = targets.size() >= minNumberOfTargets; + } chosen = targets.size() >= minNumberOfTargets; if (!player.chooseTarget(outcome, cardsId, this, null, game)) { return chosen; } chosen = targets.size() >= minNumberOfTargets; } - return chosen = true; } diff --git a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java index d5d490816d..f9c867c1e3 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java +++ b/Mage/src/main/java/mage/target/common/TargetCreatureOrPlaneswalker.java @@ -1,21 +1,29 @@ package mage.target.common; -import java.util.UUID; import mage.abilities.Ability; import mage.filter.common.FilterCreatureOrPlaneswalkerPermanent; import mage.game.Game; import mage.players.Player; import mage.target.TargetPermanent; +import java.util.UUID; + /** - * * @author LevelX2 */ public class TargetCreatureOrPlaneswalker extends TargetPermanent { public TargetCreatureOrPlaneswalker() { - this(1, 1, new FilterCreatureOrPlaneswalkerPermanent(), false); + this(1); + } + + public TargetCreatureOrPlaneswalker(int numTargets) { + this(numTargets, numTargets); + } + + public TargetCreatureOrPlaneswalker(int minNumTargets, int maxNumTargets) { + this(minNumTargets, maxNumTargets, new FilterCreatureOrPlaneswalkerPermanent(), false); } public TargetCreatureOrPlaneswalker(int minNumTargets, int maxNumTargets, FilterCreatureOrPlaneswalkerPermanent filter, boolean notTarget) { diff --git a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java index 396605907d..4bbc69cabc 100644 --- a/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java +++ b/Mage/src/main/java/mage/target/common/TargetCreaturePermanentWithDifferentTypes.java @@ -35,7 +35,8 @@ public class TargetCreaturePermanentWithDifferentTypes extends TargetCreaturePer for (Object object : getTargets()) { UUID targetId = (UUID) object; Permanent selectedCreature = game.getPermanent(targetId); - if (!creature.getId().equals(selectedCreature.getId())) { + if (selectedCreature != null + && !creature.getId().equals(selectedCreature.getId())) { if (creature.shareSubtypes(selectedCreature, game)) { return false; } diff --git a/Mage/src/main/java/mage/target/common/TargetDefender.java b/Mage/src/main/java/mage/target/common/TargetDefender.java index 3d48481d59..863c419b28 100644 --- a/Mage/src/main/java/mage/target/common/TargetDefender.java +++ b/Mage/src/main/java/mage/target/common/TargetDefender.java @@ -68,7 +68,8 @@ public class TargetDefender extends TargetImpl { } } for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, sourceControllerId, game)) { - if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) + if ((notTarget + || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, game)) { count++; if (count >= this.minNumberOfTargets) { @@ -84,7 +85,8 @@ public class TargetDefender extends TargetImpl { int count = 0; for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { + if (player != null + && filter.match(player, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -109,13 +111,15 @@ public class TargetDefender extends TargetImpl { for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); if (player != null - && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) + && (notTarget + || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, game)) { possibleTargets.add(playerId); } } for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_PLANESWALKER, sourceControllerId, game)) { - if ((notTarget || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) + if ((notTarget + || permanent.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(permanent, game)) { possibleTargets.add(permanent.getId()); } @@ -128,7 +132,8 @@ public class TargetDefender extends TargetImpl { Set possibleTargets = new HashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { + if (player != null + && filter.match(player, game)) { possibleTargets.add(playerId); } } @@ -162,7 +167,8 @@ public class TargetDefender extends TargetImpl { return filter.match(player, game); } Permanent permanent = game.getPermanent(id); - return permanent != null && filter.match(permanent, game); + return permanent != null + && filter.match(permanent, game); } @Override @@ -170,7 +176,8 @@ public class TargetDefender extends TargetImpl { Player player = game.getPlayer(id); MageObject targetSource = game.getObject(attackerId); if (player != null) { - return (notTarget || player.canBeTargetedBy(targetSource, (source == null ? null : source.getControllerId()), game)) + return (notTarget + || player.canBeTargetedBy(targetSource, (source == null ? null : source.getControllerId()), game)) && filter.match(player, game); } Permanent permanent = game.getPermanent(id); // planeswalker @@ -180,7 +187,8 @@ public class TargetDefender extends TargetImpl { if (source != null) { controllerId = source.getControllerId(); } - return (notTarget || permanent.canBeTargetedBy(targetSource, controllerId, game)) + return (notTarget + || permanent.canBeTargetedBy(targetSource, controllerId, game)) && filter.match(permanent, game); } return false; diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java index ac4156a25c..70dab46b02 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayer.java @@ -1,4 +1,3 @@ - package mage.target.common; import java.util.HashSet; @@ -99,7 +98,8 @@ public class TargetPermanentOrPlayer extends TargetImpl { } if (player != null) { if (!isNotTarget()) { - if (!player.canBeTargetedBy(targetSource, source.getControllerId(), game)) { + if (!player.canBeTargetedBy(targetSource, source.getControllerId(), game) + || !filter.match(player, source.getSourceId(), source.getControllerId(), game)) { return false; } } @@ -130,7 +130,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { MageObject targetSource = game.getObject(sourceId); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.match(player, game)) { + if (player != null && player.canBeTargetedBy(targetSource, sourceControllerId, game) && filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -163,7 +163,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { int count = 0; for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { + if (player != null && filter.getPlayerFilter().match(player, game)) { count++; if (count >= this.minNumberOfTargets) { return true; @@ -187,7 +187,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { MageObject targetSource = game.getObject(sourceId); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.match(player, game)) { + if (player != null && (notTarget || player.canBeTargetedBy(targetSource, sourceControllerId, game)) && filter.getPlayerFilter().match(player, sourceId, sourceControllerId, game)) { possibleTargets.add(playerId); } } @@ -204,7 +204,7 @@ public class TargetPermanentOrPlayer extends TargetImpl { Set possibleTargets = new HashSet<>(); for (UUID playerId : game.getState().getPlayersInRange(sourceControllerId, game)) { Player player = game.getPlayer(playerId); - if (player != null && filter.match(player, game)) { + if (player != null && filter.getPlayerFilter().match(player, game)) { possibleTargets.add(playerId); } } diff --git a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerWithCounter.java b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerWithCounter.java index 5fb97de434..d6a515991d 100644 --- a/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerWithCounter.java +++ b/Mage/src/main/java/mage/target/common/TargetPermanentOrPlayerWithCounter.java @@ -17,7 +17,7 @@ import mage.filter.predicate.permanent.CounterPredicate; */ public class TargetPermanentOrPlayerWithCounter extends TargetPermanentOrPlayer { - protected final FilterPermanentOrPlayerWithCounter filter; + protected final FilterPermanentOrPlayerWithCounter targetFilter; public TargetPermanentOrPlayerWithCounter() { this(1, 1); @@ -33,16 +33,16 @@ public class TargetPermanentOrPlayerWithCounter extends TargetPermanentOrPlayer public TargetPermanentOrPlayerWithCounter(int minNumTargets, int maxNumTargets, boolean notTarget) { super(minNumTargets, maxNumTargets, notTarget); - this.filter = new FilterPermanentOrPlayerWithCounter(); + this.targetFilter = new FilterPermanentOrPlayerWithCounter(); this.filterPermanent = new FilterPermanent(); this.filterPermanent.add(new CounterPredicate(null)); - this.targetName = filter.getMessage(); + this.targetName = targetFilter.getMessage(); } public TargetPermanentOrPlayerWithCounter(final TargetPermanentOrPlayerWithCounter target) { super(target); - this.filter = target.filter.copy(); - super.setFilter(this.filter); + this.targetFilter = target.targetFilter.copy(); + super.setFilter(this.targetFilter); } @Override diff --git a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java index c8a14e5c27..06a2eaf0e4 100644 --- a/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java +++ b/Mage/src/main/java/mage/target/targetpointer/FixedTarget.java @@ -1,15 +1,17 @@ package mage.target.targetpointer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.UUID; +import mage.MageObjectReference; import mage.abilities.Ability; import mage.cards.Card; import mage.constants.Zone; import mage.game.Game; import mage.game.permanent.Permanent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + public class FixedTarget implements TargetPointer { private final UUID targetId; @@ -21,6 +23,10 @@ public class FixedTarget implements TargetPointer { this.initialized = false; } + public FixedTarget(MageObjectReference mor) { + this(mor.getSourceId(), mor.getZoneChangeCounter()); + } + public FixedTarget(Card card, Game game) { this.targetId = card.getId(); this.zoneChangeCounter = card.getZoneChangeCounter(game); diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index ac9a02f558..94d2da8d54 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -1,9 +1,5 @@ - package mage.util; -import java.util.UUID; -import java.util.stream.Stream; - import mage.MageObject; import mage.Mana; import mage.abilities.Ability; @@ -12,11 +8,14 @@ import mage.abilities.SpellAbility; import mage.abilities.costs.VariableCost; import mage.abilities.costs.mana.*; import mage.cards.Card; +import mage.constants.EmptyNames; import mage.game.Game; import mage.game.permanent.Permanent; import mage.game.permanent.token.Token; import mage.util.functions.CopyTokenFunction; +import java.util.UUID; + /** * @author nantuko */ @@ -25,10 +24,10 @@ public final class CardUtil { private static final String SOURCE_EXILE_ZONE_TEXT = "SourceExileZone"; static final String[] numberStrings = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; + "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"}; static final String[] ordinalStrings = {"first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eightth", "ninth", - "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; + "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth", "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth", "twentieth"}; /** * Increase spell or ability cost to be paid. @@ -57,7 +56,7 @@ public final class CardUtil { * @param reduceCount */ public static void adjustCost(SpellAbility spellAbility, int reduceCount) { - CardUtil.adjustAbilityCost((Ability) spellAbility, reduceCount); + CardUtil.adjustAbilityCost(spellAbility, reduceCount); } public static ManaCosts increaseCost(ManaCosts manaCosts, int increaseCount) { @@ -129,8 +128,8 @@ public final class CardUtil { * * @param spellAbility * @param manaCostsToReduce costs to reduce - * @param convertToGeneric colored mana does reduce generic mana if no - * appropriate colored mana is in the costs included + * @param convertToGeneric colored mana does reduce generic mana if no + * appropriate colored mana is in the costs included */ public static void adjustCost(SpellAbility spellAbility, ManaCosts manaCostsToReduce, boolean convertToGeneric) { ManaCosts previousCost = spellAbility.getManaCostsToPay(); @@ -315,7 +314,7 @@ public final class CardUtil { * * @param number number to convert to text * @param forOne if the number is 1, this string will be returnedinstead of - * "one". + * "one". * @return */ public static String numberToText(int number, String forOne) { @@ -346,7 +345,7 @@ public final class CardUtil { if (number >= 1 && number < 21) { return ordinalStrings[number - 1]; } - return Integer.toString(number) + "th"; + return number + "th"; } public static String replaceSourceName(String message, String sourceName) { @@ -355,6 +354,13 @@ public final class CardUtil { return message; } + public static String booleanToFlipName(boolean flip) { + if (flip) { + return "Heads"; + } + return "Tails"; + } + public static boolean checkNumeric(String s) { return s.chars().allMatch(Character::isDigit); @@ -362,7 +368,7 @@ public final class CardUtil { /** * Parse card number as int (support base [123] and alternative numbers - * [123b]). + * [123b], [U123]). * * @param cardNumber origin card number * @return int @@ -373,17 +379,27 @@ public final class CardUtil { throw new IllegalArgumentException("Card number is empty."); } - if (Character.isDigit(cardNumber.charAt(cardNumber.length() - 1))) { - return Integer.parseInt(cardNumber); - } else { - return Integer.parseInt(cardNumber.substring(0, cardNumber.length() - 1)); + try { + if (!Character.isDigit(cardNumber.charAt(0))) { + // U123 + return Integer.parseInt(cardNumber.substring(1)); + } else if (!Character.isDigit(cardNumber.charAt(cardNumber.length() - 1))) { + // 123b + return Integer.parseInt(cardNumber.substring(0, cardNumber.length() - 1)); + } else { + // 123 + return Integer.parseInt(cardNumber); + } + } catch (NumberFormatException e) { + // wrong numbers like RA5 and etc + return -1; } } /** * Creates and saves a (card + zoneChangeCounter) specific exileId. * - * @param game the current game + * @param game the current game * @param source source ability * @return the specific UUID */ @@ -418,9 +434,9 @@ public final class CardUtil { * be specific to a permanent instance. So they won't match, if a permanent * was e.g. exiled and came back immediately. * - * @param text short value to describe the value + * @param text short value to describe the value * @param cardId id of the card - * @param game the game + * @param game the game * @return */ public static String getCardZoneString(String text, UUID cardId, Game game) { @@ -520,9 +536,38 @@ public final class CardUtil { title = textSuffix == null ? "" : textSuffix; } } else { - title = textSuffix == null ? "" : textSuffix;; + title = textSuffix == null ? "" : textSuffix; } return title; } + + /** + * Face down cards and their copy tokens don't have names and that's "empty" names is not equals + */ + public static boolean haveSameNames(String name1, String name2, Boolean ignoreMtgRuleForEmptyNames) { + if (ignoreMtgRuleForEmptyNames) { + // simple compare for tests and engine + return name1 != null && name2 != null && name1.equals(name2); + } else { + // mtg logic compare for game (empty names can't be same) + return !haveEmptyName(name1) && !haveEmptyName(name2) && name1.equals(name2); + } + } + + public static boolean haveSameNames(String name1, String name2) { + return haveSameNames(name1, name2, false); + } + + public static boolean haveSameNames(MageObject object1, MageObject object2) { + return object1 != null && object2 != null && haveSameNames(object1.getName(), object2.getName()); + } + + public static boolean haveEmptyName(String name) { + return name == null || name.isEmpty() || name.equals(EmptyNames.FACE_DOWN_CREATURE.toString()) || name.equals(EmptyNames.FACE_DOWN_TOKEN.toString()); + } + + public static boolean haveEmptyName(MageObject object) { + return object == null || haveEmptyName(object.getName()); + } } diff --git a/Mage/src/main/java/mage/util/ClassScanner.java b/Mage/src/main/java/mage/util/ClassScanner.java index 46609ea4ba..47972fe400 100644 --- a/Mage/src/main/java/mage/util/ClassScanner.java +++ b/Mage/src/main/java/mage/util/ClassScanner.java @@ -33,8 +33,8 @@ public final class ClassScanner { if(classLoader == null) classLoader = Thread.currentThread().getContextClassLoader(); assert classLoader != null; - HashMap dirs = new HashMap<>(); - TreeSet jars = new TreeSet<>(); + Map dirs = new HashMap<>(); + Set jars = new TreeSet<>(); for (String packageName : packages) { String path = packageName.replace('.', '/'); Enumeration resources = classLoader.getResources(path); @@ -51,8 +51,8 @@ public final class ClassScanner { } } - for (String filePath : dirs.keySet()) { - cards.addAll(findClasses(classLoader, new File(filePath), dirs.get(filePath), type)); + for (Map.Entry dir : dirs.entrySet()) { + cards.addAll(findClasses(classLoader, new File(dir.getKey()), dir.getValue(), type)); } for (String filePath : jars) { @@ -66,7 +66,7 @@ public final class ClassScanner { private static List findClasses(ClassLoader classLoader, File directory, String packageName, Class type) { List cards = new ArrayList<>(); - if (!directory.exists()) return cards; + if (directory == null || !directory.exists()) return cards; for (File file : directory.listFiles()) { if (file.getName().endsWith(".class")) { diff --git a/Mage/src/main/java/mage/util/DeckUtil.java b/Mage/src/main/java/mage/util/DeckUtil.java index aed0bda343..38da6de811 100644 --- a/Mage/src/main/java/mage/util/DeckUtil.java +++ b/Mage/src/main/java/mage/util/DeckUtil.java @@ -1,12 +1,19 @@ - package mage.util; +import org.apache.log4j.Logger; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + /** - * * @author LevelX2 */ public final class DeckUtil { + private static final Logger logger = Logger.getLogger(DeckUtil.class); + public static long fixedHash(String string) { long h = 1125899906842597L; // prime int len = string.length(); @@ -16,4 +23,23 @@ public final class DeckUtil { } return h; } + + public static String writeTextToTempFile(String text) { + return writeTextToTempFile("cbimportdeck", ".txt", text); + } + + public static String writeTextToTempFile(String filePrefix, String fileSuffix, String text) { + BufferedWriter bw = null; + try { + File temp = File.createTempFile(filePrefix, fileSuffix); + bw = new BufferedWriter(new FileWriter(temp)); + bw.write(text); + return temp.getPath(); + } catch (IOException e) { + logger.error("Can't write deck file to temp file", e); + } finally { + StreamUtils.closeQuietly(bw); + } + return null; + } } diff --git a/Mage/src/main/java/mage/util/GameLog.java b/Mage/src/main/java/mage/util/GameLog.java index a97c1d8988..93c2646088 100644 --- a/Mage/src/main/java/mage/util/GameLog.java +++ b/Mage/src/main/java/mage/util/GameLog.java @@ -1,11 +1,9 @@ - package mage.util; import mage.MageObject; import mage.ObjectColor; /** - * * @author LevelX2 */ public final class GameLog { @@ -40,11 +38,11 @@ public final class GameLog { } public static String getColoredObjectIdName(MageObject mageObject) { - return "" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]"; + return "" + mageObject.getIdName() + ""; } public static String getColoredObjectIdNameForTooltip(MageObject mageObject) { - return "" + mageObject.getName() + " [" + mageObject.getId().toString().substring(0, 3) + "]"; + return "" + mageObject.getIdName() + ""; } public static String getNeutralColoredText(String text) { diff --git a/Mage/src/main/java/mage/util/JarVersion.java b/Mage/src/main/java/mage/util/JarVersion.java new file mode 100644 index 0000000000..3089b441ab --- /dev/null +++ b/Mage/src/main/java/mage/util/JarVersion.java @@ -0,0 +1,60 @@ +package mage.util; + +import org.apache.log4j.Logger; + +import java.net.URL; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +/** + * @author JayDi85 + */ +public class JarVersion { + + private static final Logger logger = Logger.getLogger(JarVersion.class); + private static final String JAR_BUILD_TIME_FROM_CLASSES = "runtime"; + private static final String JAR_BUILD_TIME_ERROR = "n/a"; + + public static String getBuildTime(Class clazz) { + // build time info inserted by maven on jar build phase (see root pom.xml) + String resultFormat = "uuuu-MM-dd HH:mm"; + String className = clazz.getSimpleName() + ".class"; + String classPath = clazz.getResource(className).toString(); + + // https://stackoverflow.com/a/1273432/1276632 + String manifestPath; + if (classPath.startsWith("jar")) { + // jar source + manifestPath = classPath.substring(0, classPath.lastIndexOf('!') + 1) + "/META-INF/MANIFEST.MF"; + } else { + // dir source (e.g. IDE's debug) + // it's can be generated by runtime, but need extra code and performance: https://stackoverflow.com/questions/34674073/how-to-generate-manifest-mf-file-during-compile-phase + // manifestPath = classPath.substring(0, classPath.lastIndexOf("/" + className)) + "/META-INF/MANIFEST.MF"; + return JAR_BUILD_TIME_FROM_CLASSES; + } + + try { + Manifest manifest = new Manifest(new URL(manifestPath).openStream()); + Attributes attr = manifest.getMainAttributes(); + String buildTime = attr.getValue("Build-Time"); + // default maven format: yyyy-MM-dd'T'HH:mm:ss'Z' or see maven.build.timestamp.format in pom file + DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss'Z'").withZone(ZoneOffset.UTC); + TemporalAccessor ta = sourceFormatter.parse(buildTime); + DateTimeFormatter resultFormatter = DateTimeFormatter.ofPattern(resultFormat).withZone(ZoneOffset.UTC); + return resultFormatter.format(ta); + } catch (Throwable e) { + logger.error("Can't read build time in jar manifest for class " + clazz.getName() + " and path " + manifestPath, e); + return JAR_BUILD_TIME_ERROR; + } + } + + public static boolean isBuildTimeOk(String buildTime) { + return buildTime != null + && !buildTime.isEmpty() + && !buildTime.equals(JAR_BUILD_TIME_ERROR) + && !buildTime.equals(JAR_BUILD_TIME_FROM_CLASSES); + } +} diff --git a/Mage/src/main/java/mage/util/RandomUtil.java b/Mage/src/main/java/mage/util/RandomUtil.java index 2930798341..41006a786c 100644 --- a/Mage/src/main/java/mage/util/RandomUtil.java +++ b/Mage/src/main/java/mage/util/RandomUtil.java @@ -1,33 +1,38 @@ package mage.util; import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; /** * Created by IGOUDT on 5-9-2016. */ public final class RandomUtil { + private static Random random = new Random(); // thread safe with seed support + private RandomUtil() { } public static Random getRandom() { - return ThreadLocalRandom.current(); + return random; } public static int nextInt() { - return ThreadLocalRandom.current().nextInt(); + return random.nextInt(); } public static int nextInt(int max) { - return ThreadLocalRandom.current().nextInt(max); + return random.nextInt(max); } public static boolean nextBoolean() { - return ThreadLocalRandom.current().nextBoolean(); + return random.nextBoolean(); } public static double nextDouble() { - return ThreadLocalRandom.current().nextDouble(); + return random.nextDouble(); + } + + public static void setSeed(long newSeed) { + random.setSeed(newSeed); } } diff --git a/Mage/src/main/java/mage/util/SubTypeList.java b/Mage/src/main/java/mage/util/SubTypeList.java index 84b4fa7491..2dc37f16d5 100644 --- a/Mage/src/main/java/mage/util/SubTypeList.java +++ b/Mage/src/main/java/mage/util/SubTypeList.java @@ -20,20 +20,6 @@ public class SubTypeList extends ArrayList { Collections.addAll(this, subTypesList); } - @Deprecated - public boolean addAll(List subtypes) { - return addAll(subtypes.stream() - .map(SubType::byDescription) - .collect(Collectors.toList())); - } - - @Deprecated - public boolean removeAll(List subtypes) { - return removeAll(subtypes.stream() - .map(SubType::byDescription) - .collect(Collectors.toList())); - } - public boolean add(SubType... subTypes) { return Collections.addAll(this, subTypes); } @@ -42,18 +28,4 @@ public class SubTypeList extends ArrayList { return super.removeAll(Arrays.stream(subTypes) .collect(Collectors.toList())); } - - @Deprecated - public boolean add(String s) { - SubType subType = SubType.byDescription(s); - if (subType != null) { - return add(subType); - } - return false; - } - - @Deprecated - public boolean contains(String s) { - return contains(SubType.byDescription(s)); - } } diff --git a/Mage/src/main/java/mage/watchers/Watcher.java b/Mage/src/main/java/mage/watchers/Watcher.java index 07092b7c89..af3ceddd72 100644 --- a/Mage/src/main/java/mage/watchers/Watcher.java +++ b/Mage/src/main/java/mage/watchers/Watcher.java @@ -2,10 +2,13 @@ package mage.watchers; import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.UUID; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; +import org.apache.log4j.Logger; /** * @@ -15,14 +18,16 @@ import mage.game.events.GameEvent; */ public abstract class Watcher implements Serializable { - protected String basicKey; + private static final Logger logger = Logger.getLogger(Watcher.class); + protected UUID controllerId; protected UUID sourceId; protected boolean condition; protected final WatcherScope scope; - public Watcher(String basicKey, WatcherScope scope) { - this.basicKey = basicKey; + + + public Watcher(WatcherScope scope) { this.scope = scope; } @@ -31,7 +36,6 @@ public abstract class Watcher implements Serializable { this.controllerId = watcher.controllerId; this.sourceId = watcher.sourceId; this.scope = watcher.scope; - this.basicKey = watcher.basicKey; } public UUID getControllerId() { @@ -53,13 +57,14 @@ public abstract class Watcher implements Serializable { public String getKey() { switch (scope) { case GAME: - return basicKey; + return getBasicKey(); case PLAYER: - return controllerId + basicKey; + return controllerId + getBasicKey(); case CARD: - return sourceId + basicKey; + return sourceId + getBasicKey(); + default: + return getBasicKey(); } - return basicKey; } public boolean conditionMet() { @@ -70,8 +75,21 @@ public abstract class Watcher implements Serializable { condition = false; } + protected String getBasicKey(){ + return getClass().getSimpleName(); + } + public abstract void watch(GameEvent event, Game game); - public abstract Watcher copy(); + public T copy(){ + try { + Constructor constructor = this.getClass().getDeclaredConstructor(getClass()); + constructor.setAccessible(true); + return (T) constructor.newInstance(this); + } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { + logger.error("Can't copy watcher: " + e.getMessage(), e); + } + return null; + } } diff --git a/Mage/src/main/java/mage/watchers/Watchers.java b/Mage/src/main/java/mage/watchers/Watchers.java index af9bf034c8..7fba3a54de 100644 --- a/Mage/src/main/java/mage/watchers/Watchers.java +++ b/Mage/src/main/java/mage/watchers/Watchers.java @@ -1,22 +1,24 @@ - package mage.watchers; -import java.util.HashMap; -import java.util.UUID; import mage.game.Game; import mage.game.events.GameEvent; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; + +import java.util.HashMap; /** - * * @author BetaSteward_at_googlemail.com */ public class Watchers extends HashMap { + private static Logger logger = LogManager.getLogger(Watcher.class.getSimpleName()); + public Watchers() { } - public Watchers(final Watchers watchers) { - watchers.entrySet().forEach((entry) -> this.put(entry.getKey(), entry.getValue().copy())); + private Watchers(final Watchers watchers) { + watchers.forEach((key, value) -> this.put(key, value.copy())); } public Watchers copy() { @@ -37,7 +39,16 @@ public class Watchers extends HashMap { this.values().forEach(Watcher::reset); } - public Watcher get(String key, UUID id) { - return this.get(id + key); + public Watcher get(String key, String id) { + return get(id + key); + } + + @Override + public Watcher get(Object key) { + if (containsKey(key)) { + return super.get(key); + } + logger.error(key + " not found in watchers", new Throwable()); + return null; } } diff --git a/Mage/src/main/java/mage/watchers/common/AmountOfDamageAPlayerReceivedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/AmountOfDamageAPlayerReceivedThisTurnWatcher.java index 904adbb46e..c7e63fc85f 100644 --- a/Mage/src/main/java/mage/watchers/common/AmountOfDamageAPlayerReceivedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AmountOfDamageAPlayerReceivedThisTurnWatcher.java @@ -21,7 +21,7 @@ public class AmountOfDamageAPlayerReceivedThisTurnWatcher extends Watcher { private final Map amountOfDamageReceivedThisTurn = new HashMap<>(); public AmountOfDamageAPlayerReceivedThisTurnWatcher() { - super(AmountOfDamageAPlayerReceivedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AmountOfDamageAPlayerReceivedThisTurnWatcher(final AmountOfDamageAPlayerReceivedThisTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/AttackedLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/AttackedLastTurnWatcher.java index b8ca0dd44a..c6af696380 100644 --- a/Mage/src/main/java/mage/watchers/common/AttackedLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AttackedLastTurnWatcher.java @@ -24,7 +24,7 @@ public class AttackedLastTurnWatcher extends Watcher { public final Map> attackedThisTurnCreatures = new HashMap<>(); // dummy map for beginning of turn iteration purposes public AttackedLastTurnWatcher() { - super(AttackedLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AttackedLastTurnWatcher(final AttackedLastTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/AttackedOrBlockedThisCombatWatcher.java b/Mage/src/main/java/mage/watchers/common/AttackedOrBlockedThisCombatWatcher.java index f4e36b11e4..0af8f15aa7 100644 --- a/Mage/src/main/java/mage/watchers/common/AttackedOrBlockedThisCombatWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AttackedOrBlockedThisCombatWatcher.java @@ -19,29 +19,29 @@ import mage.watchers.Watcher; */ public class AttackedOrBlockedThisCombatWatcher extends Watcher { - public final Set attackedThisTurnCreatures = new HashSet<>(); - public final Set blockedThisTurnCreatures = new HashSet<>(); + private final Set attackedThisTurnCreatures = new HashSet<>(); + private final Set blockedThisTurnCreatures = new HashSet<>(); public AttackedOrBlockedThisCombatWatcher() { - super(AttackedOrBlockedThisCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AttackedOrBlockedThisCombatWatcher(final AttackedOrBlockedThisCombatWatcher watcher) { super(watcher); - this.attackedThisTurnCreatures.addAll(watcher.attackedThisTurnCreatures); - this.blockedThisTurnCreatures.addAll(watcher.blockedThisTurnCreatures); + this.getAttackedThisTurnCreatures().addAll(watcher.getAttackedThisTurnCreatures()); + this.getBlockedThisTurnCreatures().addAll(watcher.getBlockedThisTurnCreatures()); } @Override public void watch(GameEvent event, Game game) { if (event.getType() == GameEvent.EventType.BEGIN_COMBAT_STEP_PRE) { - this.attackedThisTurnCreatures.clear(); + this.getAttackedThisTurnCreatures().clear(); } if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { - this.attackedThisTurnCreatures.add(new MageObjectReference(event.getSourceId(), game)); + this.getAttackedThisTurnCreatures().add(new MageObjectReference(event.getSourceId(), game)); } if (event.getType() == GameEvent.EventType.BLOCKER_DECLARED) { - this.blockedThisTurnCreatures.add(new MageObjectReference(event.getSourceId(), game)); + this.getBlockedThisTurnCreatures().add(new MageObjectReference(event.getSourceId(), game)); } } diff --git a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java index 3254f72abe..adedcff2cc 100644 --- a/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/AttackedThisTurnWatcher.java @@ -1,26 +1,28 @@ package mage.watchers.common; +import mage.MageObjectReference; +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.watchers.Watcher; + import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import mage.MageObjectReference; -import mage.constants.WatcherScope; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.watchers.Watcher; /** * @author magenoxx_at_gmail.com */ public class AttackedThisTurnWatcher extends Watcher { - protected final Set attackedThisTurnCreatures = new HashSet<>(); - protected final Map attackedThisTurnCreaturesCounts = new HashMap<>(); + private final Set attackedThisTurnCreatures = new HashSet<>(); + private final Map attackedThisTurnCreaturesCounts = new HashMap<>(); public AttackedThisTurnWatcher() { - super(AttackedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public AttackedThisTurnWatcher(final AttackedThisTurnWatcher watcher) { @@ -47,6 +49,15 @@ public class AttackedThisTurnWatcher extends Watcher { return this.attackedThisTurnCreaturesCounts; } + public boolean checkIfAttacked(Permanent permanent, Game game) { + for (MageObjectReference mor : attackedThisTurnCreatures) { + if (mor.refersTo(permanent, game)) { + return true; + } + } + return false; + } + @Override public AttackedThisTurnWatcher copy() { return new AttackedThisTurnWatcher(this); diff --git a/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java b/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java index 1bfd8a2a1d..57506bf683 100644 --- a/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/BlockedAttackerWatcher.java @@ -3,6 +3,7 @@ package mage.watchers.common; import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; import mage.MageObjectReference; import mage.constants.WatcherScope; @@ -18,10 +19,10 @@ import mage.watchers.Watcher; */ public class BlockedAttackerWatcher extends Watcher { - public final HashMap> blockData = new HashMap<>(); + private final Map> blockData = new HashMap<>(); public BlockedAttackerWatcher() { - super(BlockedAttackerWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public BlockedAttackerWatcher(final BlockedAttackerWatcher watcher) { @@ -33,10 +34,10 @@ public class BlockedAttackerWatcher extends Watcher { } } - @Override - public BlockedAttackerWatcher copy() { - return new BlockedAttackerWatcher(this); - } +// @Override +// public BlockedAttackerWatcher copy() { +// return new BlockedAttackerWatcher(this); +// } @Override public void watch(GameEvent event, Game game) { diff --git a/Mage/src/main/java/mage/watchers/common/BlockedByOnlyOneCreatureThisCombatWatcher.java b/Mage/src/main/java/mage/watchers/common/BlockedByOnlyOneCreatureThisCombatWatcher.java index 8cb13352df..b058d6136e 100644 --- a/Mage/src/main/java/mage/watchers/common/BlockedByOnlyOneCreatureThisCombatWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/BlockedByOnlyOneCreatureThisCombatWatcher.java @@ -18,7 +18,7 @@ public class BlockedByOnlyOneCreatureThisCombatWatcher extends Watcher { private final Map blockedByOneCreature = new HashMap<>(); public BlockedByOnlyOneCreatureThisCombatWatcher() { - super(BlockedByOnlyOneCreatureThisCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public BlockedByOnlyOneCreatureThisCombatWatcher(final BlockedByOnlyOneCreatureThisCombatWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/BlockedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/BlockedThisTurnWatcher.java index 263f24b8bb..6d8b27ad05 100644 --- a/Mage/src/main/java/mage/watchers/common/BlockedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/BlockedThisTurnWatcher.java @@ -1,17 +1,17 @@ package mage.watchers.common; -import java.util.HashSet; -import java.util.Set; - import mage.MageObjectReference; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; + /** - * * @author Quercitron */ public class BlockedThisTurnWatcher extends Watcher { @@ -19,7 +19,7 @@ public class BlockedThisTurnWatcher extends Watcher { private final Set blockedThisTurnCreatures; public BlockedThisTurnWatcher() { - super(BlockedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); blockedThisTurnCreatures = new HashSet<>(); } @@ -44,6 +44,15 @@ public class BlockedThisTurnWatcher extends Watcher { return this.blockedThisTurnCreatures; } + public boolean checkIfBlocked(Permanent permanent, Game game) { + for (MageObjectReference mor : blockedThisTurnCreatures) { + if (mor.refersTo(permanent, game)) { + return true; + } + } + return false; + } + @Override public void reset() { super.reset(); diff --git a/Mage/src/main/java/mage/watchers/common/BloodthirstWatcher.java b/Mage/src/main/java/mage/watchers/common/BloodthirstWatcher.java index 784e44459a..b27a6a6247 100644 --- a/Mage/src/main/java/mage/watchers/common/BloodthirstWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/BloodthirstWatcher.java @@ -16,7 +16,7 @@ import java.util.UUID; */ public class BloodthirstWatcher extends Watcher { public BloodthirstWatcher(UUID controllerId) { - super(BloodthirstWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); this.controllerId = controllerId; } @@ -36,9 +36,4 @@ public class BloodthirstWatcher extends Watcher { } } } - - @Override - public BloodthirstWatcher copy() { - return new BloodthirstWatcher(this); - } } diff --git a/Mage/src/main/java/mage/watchers/common/CardsAmountDrawnThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/CardsAmountDrawnThisTurnWatcher.java index 5b4ed5ca22..71c1a70306 100644 --- a/Mage/src/main/java/mage/watchers/common/CardsAmountDrawnThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CardsAmountDrawnThisTurnWatcher.java @@ -22,7 +22,7 @@ public class CardsAmountDrawnThisTurnWatcher extends Watcher { private final Map amountOfCardsDrawnThisTurn = new HashMap<>(); public CardsAmountDrawnThisTurnWatcher() { - super(CardsAmountDrawnThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CardsAmountDrawnThisTurnWatcher(final CardsAmountDrawnThisTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CardsCycledOrDiscardedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/CardsCycledOrDiscardedThisTurnWatcher.java index a391fc9ec4..05f94ff6c8 100644 --- a/Mage/src/main/java/mage/watchers/common/CardsCycledOrDiscardedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CardsCycledOrDiscardedThisTurnWatcher.java @@ -27,7 +27,7 @@ public class CardsCycledOrDiscardedThisTurnWatcher extends Watcher { private final Map> numberOfCycledOrDiscardedCardsThisTurn = new HashMap<>(); public CardsCycledOrDiscardedThisTurnWatcher() { - super(CardsCycledOrDiscardedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CardsCycledOrDiscardedThisTurnWatcher(final CardsCycledOrDiscardedThisTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CardsDrawnDuringDrawStepWatcher.java b/Mage/src/main/java/mage/watchers/common/CardsDrawnDuringDrawStepWatcher.java index 477e24ae51..60cc296e91 100644 --- a/Mage/src/main/java/mage/watchers/common/CardsDrawnDuringDrawStepWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CardsDrawnDuringDrawStepWatcher.java @@ -24,7 +24,7 @@ public class CardsDrawnDuringDrawStepWatcher extends Watcher { private final Map amountOfCardsDrawnThisTurn = new HashMap<>(); public CardsDrawnDuringDrawStepWatcher() { - super(CardsDrawnDuringDrawStepWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CardsDrawnDuringDrawStepWatcher(final CardsDrawnDuringDrawStepWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java b/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java index bfd0fa5ff5..004019037d 100644 --- a/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CardsPutIntoGraveyardWatcher.java @@ -29,7 +29,7 @@ public class CardsPutIntoGraveyardWatcher extends Watcher { private final Set cardsPutToGraveyardFromBattlefield = new HashSet<>(); public CardsPutIntoGraveyardWatcher() { - super(CardsPutIntoGraveyardWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CardsPutIntoGraveyardWatcher(final CardsPutIntoGraveyardWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CastFromGraveyardWatcher.java b/Mage/src/main/java/mage/watchers/common/CastFromGraveyardWatcher.java index 9729f92d11..2950ef15b0 100644 --- a/Mage/src/main/java/mage/watchers/common/CastFromGraveyardWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastFromGraveyardWatcher.java @@ -20,7 +20,7 @@ public class CastFromGraveyardWatcher extends Watcher { private final Map> spellsCastFromGraveyard = new HashMap<>(); public CastFromGraveyardWatcher() { - super(CastFromGraveyardWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CastFromGraveyardWatcher(final CastFromGraveyardWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java b/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java index 6531c80dd4..58983d93bf 100644 --- a/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastFromHandWatcher.java @@ -18,7 +18,7 @@ public class CastFromHandWatcher extends Watcher { private Step step; public CastFromHandWatcher() { - super(CastFromHandWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CastFromHandWatcher(final CastFromHandWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CastSpellLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/CastSpellLastTurnWatcher.java index 0beaff987e..7f30b3b5ca 100644 --- a/Mage/src/main/java/mage/watchers/common/CastSpellLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastSpellLastTurnWatcher.java @@ -20,7 +20,7 @@ public class CastSpellLastTurnWatcher extends Watcher { private final List spellsCastThisTurnInOrder = new ArrayList<>(); public CastSpellLastTurnWatcher() { - super(CastSpellLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CastSpellLastTurnWatcher(final CastSpellLastTurnWatcher watcher) { @@ -81,10 +81,10 @@ public class CastSpellLastTurnWatcher extends Watcher { } return 0; } - - @Override - public CastSpellLastTurnWatcher copy() { - return new CastSpellLastTurnWatcher(this); - } +// +// @Override +// public CastSpellLastTurnWatcher copy() { +// return new CastSpellLastTurnWatcher(this); +// } } diff --git a/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java index 97a51a225d..f99ca683b4 100644 --- a/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CastSpellYourLastTurnWatcher.java @@ -19,7 +19,7 @@ public class CastSpellYourLastTurnWatcher extends Watcher { private UUID lastActivePlayer = null; public CastSpellYourLastTurnWatcher() { - super(CastSpellYourLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CastSpellYourLastTurnWatcher(final CastSpellYourLastTurnWatcher watcher) { @@ -60,9 +60,9 @@ public class CastSpellYourLastTurnWatcher extends Watcher { public Integer getAmountOfSpellsCastOnPlayersTurn(UUID playerId) { return amountOfSpellsCastOnPrevTurn.getOrDefault(playerId, 0); } - - @Override - public CastSpellYourLastTurnWatcher copy() { - return new CastSpellYourLastTurnWatcher(this); - } +// +// @Override +// public CastSpellYourLastTurnWatcher copy() { +// return new CastSpellYourLastTurnWatcher(this); +// } } diff --git a/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java b/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java index 8153aa9721..4d8fceaef5 100644 --- a/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ChooseBlockersRedundancyWatcher.java @@ -17,7 +17,7 @@ public class ChooseBlockersRedundancyWatcher extends Watcher { // workaround for public int copyCountApply = 0; public ChooseBlockersRedundancyWatcher() { - super(ChooseBlockersRedundancyWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ChooseBlockersRedundancyWatcher(final ChooseBlockersRedundancyWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java index 22f3fc3ba5..99e7996ac0 100644 --- a/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CommanderInfoWatcher.java @@ -24,11 +24,11 @@ import mage.watchers.Watcher; */ public class CommanderInfoWatcher extends Watcher { - public final Map damageToPlayer = new HashMap<>(); - public final boolean checkCommanderDamage; + private final Map damageToPlayer = new HashMap<>(); + private final boolean checkCommanderDamage; public CommanderInfoWatcher(UUID commander, boolean checkCommanderDamage) { - super(CommanderInfoWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); this.sourceId = commander; this.checkCommanderDamage = checkCommanderDamage; } diff --git a/Mage/src/main/java/mage/watchers/common/CreatureAttackedWhichPlayerWatcher.java b/Mage/src/main/java/mage/watchers/common/CreatureAttackedWhichPlayerWatcher.java index a36deed585..6ebaee8ee6 100644 --- a/Mage/src/main/java/mage/watchers/common/CreatureAttackedWhichPlayerWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CreatureAttackedWhichPlayerWatcher.java @@ -20,7 +20,7 @@ public class CreatureAttackedWhichPlayerWatcher extends Watcher { private final Map getPlayerAttackedThisTurnByCreature = new HashMap<>(); public CreatureAttackedWhichPlayerWatcher() { - super(CreatureAttackedWhichPlayerWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CreatureAttackedWhichPlayerWatcher(final CreatureAttackedWhichPlayerWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CreatureWasCastWatcher.java b/Mage/src/main/java/mage/watchers/common/CreatureWasCastWatcher.java index aecb265f34..11f1fbf5b9 100644 --- a/Mage/src/main/java/mage/watchers/common/CreatureWasCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CreatureWasCastWatcher.java @@ -22,7 +22,7 @@ public class CreatureWasCastWatcher extends Watcher { private final Set creaturesCasted = new HashSet<>(); public CreatureWasCastWatcher() { - super(CreatureWasCastWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CreatureWasCastWatcher(final CreatureWasCastWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/CreaturesDiedWatcher.java b/Mage/src/main/java/mage/watchers/common/CreaturesDiedWatcher.java index 5da28185c2..cf30c77490 100644 --- a/Mage/src/main/java/mage/watchers/common/CreaturesDiedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/CreaturesDiedWatcher.java @@ -2,6 +2,7 @@ package mage.watchers.common; import java.util.HashMap; +import java.util.Map; import java.util.UUID; import mage.constants.WatcherScope; import mage.game.Game; @@ -14,11 +15,11 @@ import mage.watchers.Watcher; */ public class CreaturesDiedWatcher extends Watcher { - private final HashMap amountOfCreaturesThatDiedByController = new HashMap<>(); - private final HashMap amountOfCreaturesThatDiedByOwner = new HashMap<>(); + private final Map amountOfCreaturesThatDiedByController = new HashMap<>(); + private final Map amountOfCreaturesThatDiedByOwner = new HashMap<>(); public CreaturesDiedWatcher() { - super(CreaturesDiedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public CreaturesDiedWatcher(final CreaturesDiedWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java b/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java index 3247f2ed1d..0f28c0a396 100644 --- a/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/DamageDoneWatcher.java @@ -21,28 +21,31 @@ import java.util.UUID; public class DamageDoneWatcher extends Watcher { // which object did how much damage during the turn - public final Map damagingObjects; + private final Map damagingObjects; + + public Map getDamagingObjects() { + return damagingObjects; + } + + public Map getDamagedObjects() { + return damagedObjects; + } // which object received how much damage during the turn - public final Map damagedObjects; + private final Map damagedObjects; public DamageDoneWatcher() { - super(DamageDoneWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.damagingObjects = new HashMap<>(); this.damagedObjects = new HashMap<>(); } - public DamageDoneWatcher(final DamageDoneWatcher watcher) { + private DamageDoneWatcher(final DamageDoneWatcher watcher) { super(watcher); this.damagingObjects = new HashMap<>(watcher.damagingObjects); this.damagedObjects = new HashMap<>(watcher.damagedObjects); } - @Override - public DamageDoneWatcher copy() { - return new DamageDoneWatcher(this); - } - @Override public void watch(GameEvent event, Game game) { switch (event.getType()) { diff --git a/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java b/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java index d45b1f4b4c..746d286f45 100644 --- a/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/DamagedByWatcher.java @@ -28,7 +28,7 @@ public class DamagedByWatcher extends Watcher { } public DamagedByWatcher(boolean watchPlaneswalkers) { - super(DamagedByWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); this.watchPlaneswalkers = watchPlaneswalkers; } diff --git a/Mage/src/main/java/mage/watchers/common/DragonOnTheBattlefieldWhileSpellWasCastWatcher.java b/Mage/src/main/java/mage/watchers/common/DragonOnTheBattlefieldWhileSpellWasCastWatcher.java index dd98b1f72c..46266a8218 100644 --- a/Mage/src/main/java/mage/watchers/common/DragonOnTheBattlefieldWhileSpellWasCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/DragonOnTheBattlefieldWhileSpellWasCastWatcher.java @@ -26,7 +26,7 @@ public class DragonOnTheBattlefieldWhileSpellWasCastWatcher extends Watcher { private final Set castWithDragonOnTheBattlefield = new HashSet<>(); public DragonOnTheBattlefieldWhileSpellWasCastWatcher() { - super(DragonOnTheBattlefieldWhileSpellWasCastWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public DragonOnTheBattlefieldWhileSpellWasCastWatcher(final DragonOnTheBattlefieldWhileSpellWasCastWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/FirstSpellCastThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/FirstSpellCastThisTurnWatcher.java index db98da2824..c60052f27d 100644 --- a/Mage/src/main/java/mage/watchers/common/FirstSpellCastThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/FirstSpellCastThisTurnWatcher.java @@ -19,7 +19,7 @@ public class FirstSpellCastThisTurnWatcher extends Watcher { private final Map playerFirstCastSpell = new HashMap<>(); public FirstSpellCastThisTurnWatcher() { - super(FirstSpellCastThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public FirstSpellCastThisTurnWatcher(final FirstSpellCastThisTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java b/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java index 8a90a6a2a5..26d8a0d393 100644 --- a/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/FirstTimeStepWatcher.java @@ -18,7 +18,7 @@ public class FirstTimeStepWatcher extends Watcher { private final EventType eventType; public FirstTimeStepWatcher(EventType eventType) { - super(eventType.toString() + FirstTimeStepWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); this.eventType = eventType; } @@ -38,4 +38,9 @@ public class FirstTimeStepWatcher extends Watcher { condition = true; } } + + @Override + public String getBasicKey(){ + return eventType.toString() + FirstTimeStepWatcher.class.getSimpleName(); + } } diff --git a/Mage/src/main/java/mage/watchers/common/GravestormWatcher.java b/Mage/src/main/java/mage/watchers/common/GravestormWatcher.java index 36a7d6f393..3b9afad51f 100644 --- a/Mage/src/main/java/mage/watchers/common/GravestormWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/GravestormWatcher.java @@ -19,7 +19,7 @@ public class GravestormWatcher extends Watcher { private int gravestormCount = 0; public GravestormWatcher() { - super(GravestormWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public GravestormWatcher(final GravestormWatcher watcher) { @@ -31,7 +31,7 @@ public class GravestormWatcher extends Watcher { public void watch(GameEvent event, Game game) { if (event.getType() == EventType.ZONE_CHANGE) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getFromZone() == Zone.BATTLEFIELD && zEvent.getToZone() == Zone.GRAVEYARD) { + if (zEvent.isDiesEvent()) { gravestormCount++; } } diff --git a/Mage/src/main/java/mage/watchers/common/LandfallWatcher.java b/Mage/src/main/java/mage/watchers/common/LandfallWatcher.java index dacc4a52cc..ce1827b8c3 100644 --- a/Mage/src/main/java/mage/watchers/common/LandfallWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/LandfallWatcher.java @@ -15,14 +15,14 @@ import mage.watchers.Watcher; */ public class LandfallWatcher extends Watcher { - final Set playerPlayedLand = new HashSet<>(); // player that had a land enter the battlefield - final Set landEnteredBattlefield = new HashSet<>(); // land played + private final Set playerPlayedLand = new HashSet<>(); // player that had a land enter the battlefield + private final Set landEnteredBattlefield = new HashSet<>(); // land played public LandfallWatcher() { - super(LandfallWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public LandfallWatcher(final LandfallWatcher watcher) { + private LandfallWatcher(final LandfallWatcher watcher) { super(watcher); playerPlayedLand.addAll(watcher.playerPlayedLand); landEnteredBattlefield.addAll(watcher.landEnteredBattlefield); diff --git a/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java b/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java index 473b319763..d35a740342 100644 --- a/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/LifeLossOtherFromCombatWatcher.java @@ -19,7 +19,7 @@ public class LifeLossOtherFromCombatWatcher extends Watcher { private final Set players = new HashSet<>(); public LifeLossOtherFromCombatWatcher() { - super(LifeLossOtherFromCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public LifeLossOtherFromCombatWatcher(final LifeLossOtherFromCombatWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/ManaSpentToCastWatcher.java b/Mage/src/main/java/mage/watchers/common/ManaSpentToCastWatcher.java index 615790dc02..127574ca08 100644 --- a/Mage/src/main/java/mage/watchers/common/ManaSpentToCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ManaSpentToCastWatcher.java @@ -17,10 +17,10 @@ import mage.watchers.Watcher; */ public class ManaSpentToCastWatcher extends Watcher { - Mana payment = null; + private Mana payment = null; public ManaSpentToCastWatcher() { - super(ManaSpentToCastWatcher.class.getSimpleName(), WatcherScope.CARD); + super(WatcherScope.CARD); } public ManaSpentToCastWatcher(final ManaSpentToCastWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/MiracleWatcher.java b/Mage/src/main/java/mage/watchers/common/MiracleWatcher.java index 697ec9ab9c..325b958d59 100644 --- a/Mage/src/main/java/mage/watchers/common/MiracleWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/MiracleWatcher.java @@ -29,7 +29,7 @@ public class MiracleWatcher extends Watcher { private final Map amountOfCardsDrawnThisTurn = new HashMap<>(); public MiracleWatcher() { - super(MiracleWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MiracleWatcher(final MiracleWatcher watcher) { @@ -65,8 +65,7 @@ public class MiracleWatcher extends Watcher { if (ability instanceof MiracleAbility) { Player controller = game.getPlayer(ability.getControllerId()); if (controller != null) { - Cards cards = new CardsImpl(); - cards.add(card); + Cards cards = new CardsImpl(card); controller.lookAtCards("Miracle", cards, game); if (controller.chooseUse(Outcome.Benefit, "Reveal " + card.getLogName() + " to be able to use Miracle?", ability, game)) { controller.revealCards("Miracle", cards, game); diff --git a/Mage/src/main/java/mage/watchers/common/MorbidWatcher.java b/Mage/src/main/java/mage/watchers/common/MorbidWatcher.java index 8f29d2eda0..349c6ce533 100644 --- a/Mage/src/main/java/mage/watchers/common/MorbidWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/MorbidWatcher.java @@ -14,7 +14,7 @@ import mage.watchers.Watcher; public class MorbidWatcher extends Watcher { public MorbidWatcher() { - super(MorbidWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public MorbidWatcher(final MorbidWatcher watcher) { @@ -33,9 +33,9 @@ public class MorbidWatcher extends Watcher { } } - @Override - public MorbidWatcher copy() { - return new MorbidWatcher(this); - } +// @Override +// public MorbidWatcher copy() { +// return new MorbidWatcher(this); +// } } diff --git a/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java index db149374d7..fa14361fd5 100644 --- a/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/NumberOfTimesPermanentTargetedATurnWatcher.java @@ -20,7 +20,7 @@ public class NumberOfTimesPermanentTargetedATurnWatcher extends Watcher { private final Map permanentsTargeted = new HashMap<>(); public NumberOfTimesPermanentTargetedATurnWatcher() { - super(NumberOfTimesPermanentTargetedATurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public NumberOfTimesPermanentTargetedATurnWatcher(final NumberOfTimesPermanentTargetedATurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldWatcher.java b/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldWatcher.java index 870daa230f..b4bc3df198 100644 --- a/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldWatcher.java @@ -5,10 +5,8 @@ */ package mage.watchers.common; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; +import java.util.*; + import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; @@ -21,11 +19,11 @@ import mage.watchers.Watcher; */ public class PermanentsEnteredBattlefieldWatcher extends Watcher { - private final HashMap> enteringBattlefield = new HashMap<>(); - private final HashMap> enteringBattlefieldLastTurn = new HashMap<>(); + private final Map> enteringBattlefield = new HashMap<>(); + private final Map> enteringBattlefieldLastTurn = new HashMap<>(); public PermanentsEnteredBattlefieldWatcher() { - super(PermanentsEnteredBattlefieldWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PermanentsEnteredBattlefieldWatcher(final PermanentsEnteredBattlefieldWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldYourLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldYourLastTurnWatcher.java index 331602e3f1..2c52ef3ed8 100644 --- a/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldYourLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PermanentsEnteredBattlefieldYourLastTurnWatcher.java @@ -11,10 +11,7 @@ import mage.game.events.GameEvent; import mage.game.permanent.Permanent; import mage.watchers.Watcher; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; +import java.util.*; /** * @@ -22,12 +19,12 @@ import java.util.UUID; */ public class PermanentsEnteredBattlefieldYourLastTurnWatcher extends Watcher { - private final HashMap> enteringBattlefield = new HashMap<>(); - private final HashMap> enteringBattlefieldLastTurn = new HashMap<>(); + private final Map> enteringBattlefield = new HashMap<>(); + private final Map> enteringBattlefieldLastTurn = new HashMap<>(); private UUID lastActivePlayer = null; public PermanentsEnteredBattlefieldYourLastTurnWatcher() { - super(PermanentsEnteredBattlefieldYourLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PermanentsEnteredBattlefieldYourLastTurnWatcher(final PermanentsEnteredBattlefieldYourLastTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java b/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java index 9e8119c4db..9db7329017 100644 --- a/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PermanentsSacrificedWatcher.java @@ -5,10 +5,8 @@ */ package mage.watchers.common; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; +import java.util.*; + import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; @@ -21,10 +19,10 @@ import mage.watchers.Watcher; */ public class PermanentsSacrificedWatcher extends Watcher { - private final HashMap> sacrificedPermanents = new HashMap<>(); + private final Map> sacrificedPermanents = new HashMap<>(); public PermanentsSacrificedWatcher() { - super(PermanentsSacrificedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PermanentsSacrificedWatcher(final PermanentsSacrificedWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java b/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java index 58c37e601d..21ab1cc6a1 100644 --- a/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlanarRollWatcher.java @@ -21,7 +21,7 @@ public class PlanarRollWatcher extends Watcher { private final Map numberTimesPlanarDieRolled = new HashMap<>(); public PlanarRollWatcher() { - super(PlanarRollWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlanarRollWatcher(final PlanarRollWatcher watcher) { @@ -56,8 +56,4 @@ public class PlanarRollWatcher extends Watcher { numberTimesPlanarDieRolled.clear(); } - @Override - public PlanarRollWatcher copy() { - return new PlanarRollWatcher(this); - } } diff --git a/Mage/src/main/java/mage/watchers/common/PlayLandWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayLandWatcher.java index 78686fe9ae..bc6769e219 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayLandWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayLandWatcher.java @@ -14,11 +14,11 @@ import mage.watchers.Watcher; */ public class PlayLandWatcher extends Watcher { - final Set playerPlayedLand = new HashSet<>(); // player that played land - final Set landPlayed = new HashSet<>(); // land played + private final Set playerPlayedLand = new HashSet<>(); // player that played land + private final Set landPlayed = new HashSet<>(); // land played public PlayLandWatcher() { - super(PlayLandWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayLandWatcher(final PlayLandWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java index c38dc937ed..57e3702587 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerAttackedStepWatcher.java @@ -18,7 +18,7 @@ public class PlayerAttackedStepWatcher extends Watcher { private final Map playerAttacked = new HashMap<>(); public PlayerAttackedStepWatcher() { - super(PlayerAttackedStepWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerAttackedStepWatcher(final PlayerAttackedStepWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java index b9514120f1..be67da9b4f 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerAttackedWatcher.java @@ -21,7 +21,7 @@ public class PlayerAttackedWatcher extends Watcher { private final Map playerAttacked = new HashMap<>(); public PlayerAttackedWatcher() { - super(PlayerAttackedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerAttackedWatcher(final PlayerAttackedWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayerCastCreatureWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerCastCreatureWatcher.java index f9cd63037d..420a019923 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerCastCreatureWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerCastCreatureWatcher.java @@ -1,25 +1,25 @@ package mage.watchers.common; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.constants.WatcherScope; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.stack.Spell; import mage.watchers.Watcher; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + /** - * * @author LevelX2 */ public class PlayerCastCreatureWatcher extends Watcher { - final Set playerIds = new HashSet<>(); + private final Set playerIds = new HashSet<>(); public PlayerCastCreatureWatcher() { - super(PlayerCastCreatureWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerCastCreatureWatcher(final PlayerCastCreatureWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayerDamagedBySourceWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerDamagedBySourceWatcher.java index b0ea417c8f..d3e26cfa74 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerDamagedBySourceWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerDamagedBySourceWatcher.java @@ -21,7 +21,7 @@ public class PlayerDamagedBySourceWatcher extends Watcher { private final Set damageSourceIds = new HashSet<>(); public PlayerDamagedBySourceWatcher(UUID playerId) { - super(PlayerDamagedBySourceWatcher.class.getSimpleName(), WatcherScope.PLAYER); + super(WatcherScope.PLAYER); setControllerId(playerId); } @@ -30,10 +30,6 @@ public class PlayerDamagedBySourceWatcher extends Watcher { this.damageSourceIds.addAll(watcher.damageSourceIds); } - @Override - public PlayerDamagedBySourceWatcher copy() { - return new PlayerDamagedBySourceWatcher(this); - } @Override public void watch(GameEvent event, Game game) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java index fe9ceb02c0..e067a5fb90 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerGainedLifeWatcher.java @@ -21,10 +21,10 @@ public class PlayerGainedLifeWatcher extends Watcher { private final Map amountOfLifeGainedThisTurn = new HashMap<>(); public PlayerGainedLifeWatcher() { - super(PlayerGainedLifeWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public PlayerGainedLifeWatcher(final PlayerGainedLifeWatcher watcher) { + private PlayerGainedLifeWatcher(final PlayerGainedLifeWatcher watcher) { super(watcher); for (Entry entry : watcher.amountOfLifeGainedThisTurn.entrySet()) { amountOfLifeGainedThisTurn.put(entry.getKey(), entry.getValue()); @@ -45,7 +45,7 @@ public class PlayerGainedLifeWatcher extends Watcher { } } - public int getLiveGained(UUID playerId) { + public int getLifeGained(UUID playerId) { return amountOfLifeGainedThisTurn.getOrDefault(playerId, 0); } diff --git a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeNonCombatWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeNonCombatWatcher.java index 2c7300286c..d6a28c4d39 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeNonCombatWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeNonCombatWatcher.java @@ -25,7 +25,7 @@ public class PlayerLostLifeNonCombatWatcher extends Watcher { private final Map amountOfLifeLostLastTurn = new HashMap<>(); public PlayerLostLifeNonCombatWatcher() { - super(PlayerLostLifeNonCombatWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerLostLifeNonCombatWatcher(final PlayerLostLifeNonCombatWatcher watcher) { @@ -77,8 +77,8 @@ public class PlayerLostLifeNonCombatWatcher extends Watcher { amountOfLifeLostThisTurn.clear(); } - @Override - public PlayerLostLifeNonCombatWatcher copy() { - return new PlayerLostLifeNonCombatWatcher(this); - } +// @Override +// public PlayerLostLifeNonCombatWatcher copy() { +// return new PlayerLostLifeNonCombatWatcher(this); +// } } diff --git a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java index bcc4182fd9..b90a4e4457 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayerLostLifeWatcher.java @@ -23,7 +23,7 @@ public class PlayerLostLifeWatcher extends Watcher { private final Map amountOfLifeLostLastTurn = new HashMap<>(); public PlayerLostLifeWatcher() { - super(PlayerLostLifeWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayerLostLifeWatcher(final PlayerLostLifeWatcher watcher) { @@ -49,7 +49,7 @@ public class PlayerLostLifeWatcher extends Watcher { } } - public int getLiveLost(UUID playerId) { + public int getLifeLost(UUID playerId) { return amountOfLifeLostThisTurn.getOrDefault(playerId, 0); } @@ -64,7 +64,7 @@ public class PlayerLostLifeWatcher extends Watcher { return amount; } - public int getLiveLostLastTurn(UUID playerId) { + public int getLifeLostLastTurn(UUID playerId) { return amountOfLifeLostLastTurn.getOrDefault(playerId, 0); } @@ -75,8 +75,8 @@ public class PlayerLostLifeWatcher extends Watcher { amountOfLifeLostThisTurn.clear(); } - @Override - public PlayerLostLifeWatcher copy() { - return new PlayerLostLifeWatcher(this); - } +// @Override +// public PlayerLostLifeWatcher copy() { +// return new PlayerLostLifeWatcher(this); +// } } diff --git a/Mage/src/main/java/mage/watchers/common/PlayersAttackedLastTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayersAttackedLastTurnWatcher.java index 4ee5fb7898..2416759fb6 100644 --- a/Mage/src/main/java/mage/watchers/common/PlayersAttackedLastTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/PlayersAttackedLastTurnWatcher.java @@ -20,7 +20,7 @@ public class PlayersAttackedLastTurnWatcher extends Watcher { private final Map playersAttackedInLastTurn = new HashMap<>(); public PlayersAttackedLastTurnWatcher() { - super(PlayersAttackedLastTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public PlayersAttackedLastTurnWatcher(final PlayersAttackedLastTurnWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/PlayersAttackedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/PlayersAttackedThisTurnWatcher.java new file mode 100644 index 0000000000..b10eb74ab6 --- /dev/null +++ b/Mage/src/main/java/mage/watchers/common/PlayersAttackedThisTurnWatcher.java @@ -0,0 +1,90 @@ +package mage.watchers.common; + +import mage.constants.WatcherScope; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.players.PlayerList; +import mage.watchers.Watcher; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * @author JayDi85 + */ +public class PlayersAttackedThisTurnWatcher extends Watcher { + + // how many players or opponents each player attacked this turn + private final Map playersAttackedThisTurn = new HashMap<>(); + private final Map opponentsAttackedThisTurn = new HashMap<>(); + + public PlayersAttackedThisTurnWatcher() { + super(WatcherScope.GAME); + } + + public PlayersAttackedThisTurnWatcher(final PlayersAttackedThisTurnWatcher watcher) { + super(watcher); + + for (Map.Entry entry : watcher.playersAttackedThisTurn.entrySet()) { + this.playersAttackedThisTurn.putIfAbsent(entry.getKey(), entry.getValue()); + } + + for (Map.Entry entry : watcher.opponentsAttackedThisTurn.entrySet()) { + this.opponentsAttackedThisTurn.putIfAbsent(entry.getKey(), entry.getValue()); + } + } + + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.BEGINNING_PHASE_PRE) { + playersAttackedThisTurn.clear(); + opponentsAttackedThisTurn.clear(); + } + + if (event.getType() == GameEvent.EventType.ATTACKER_DECLARED) { + + // players + PlayerList playersAttacked = playersAttackedThisTurn.get(event.getPlayerId()); + if (playersAttacked == null) { + playersAttacked = new PlayerList(); + } + UUID playerDefender = game.getCombat().getDefendingPlayerId(event.getSourceId(), game); + if (playerDefender != null + && !playersAttacked.contains(playerDefender)) { + playersAttacked.add(playerDefender); + } + playersAttackedThisTurn.putIfAbsent(event.getPlayerId(), playersAttacked); + + // opponents + PlayerList opponentsAttacked = opponentsAttackedThisTurn.get(event.getPlayerId()); + if (opponentsAttacked == null) { + opponentsAttacked = new PlayerList(); + } + UUID opponentDefender = game.getCombat().getDefendingPlayerId(event.getSourceId(), game); + if (opponentDefender != null + && game.getOpponents(event.getPlayerId()).contains(opponentDefender) + && !opponentsAttacked.contains(opponentDefender)) { + opponentsAttacked.add(opponentDefender); + } + opponentsAttackedThisTurn.putIfAbsent(event.getPlayerId(), opponentsAttacked); + } + } + + public int getAttackedPlayersCount(UUID playerID) { + PlayerList defendersList = playersAttackedThisTurn.getOrDefault(playerID, null); + if (defendersList != null) { + return defendersList.size(); + } + return 0; + } + + public int getAttackedOpponentsCount(UUID playerID) { + PlayerList defendersList = opponentsAttackedThisTurn.getOrDefault(playerID, null); + if (defendersList != null) { + return defendersList.size(); + } + return 0; + } +} diff --git a/Mage/src/main/java/mage/watchers/common/ProwlWatcher.java b/Mage/src/main/java/mage/watchers/common/ProwlWatcher.java index b06c4d00b5..3357383265 100644 --- a/Mage/src/main/java/mage/watchers/common/ProwlWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ProwlWatcher.java @@ -26,10 +26,10 @@ public class ProwlWatcher extends Watcher { private final Set allSubtypes = new HashSet<>(); public ProwlWatcher() { - super(ProwlWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } - public ProwlWatcher(final ProwlWatcher watcher) { + private ProwlWatcher(final ProwlWatcher watcher) { super(watcher); for (Entry> entry : watcher.damagingSubtypes.entrySet()) { damagingSubtypes.put(entry.getKey(), entry.getValue()); diff --git a/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java b/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java index 74f34fb3aa..65084d84cd 100644 --- a/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/RevoltWatcher.java @@ -22,7 +22,7 @@ public class RevoltWatcher extends Watcher { private final Set revoltActivePlayerIds = new HashSet<>(0); public RevoltWatcher() { - super(RevoltWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public RevoltWatcher(final RevoltWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/SourceDidDamageWatcher.java b/Mage/src/main/java/mage/watchers/common/SourceDidDamageWatcher.java index b082d7def3..e790aee96b 100644 --- a/Mage/src/main/java/mage/watchers/common/SourceDidDamageWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SourceDidDamageWatcher.java @@ -19,7 +19,7 @@ public class SourceDidDamageWatcher extends Watcher { public final Set damageSources = new HashSet<>(); public SourceDidDamageWatcher() { - super(SourceDidDamageWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SourceDidDamageWatcher(final SourceDidDamageWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java index c40f0e0f07..64fe3db2d6 100644 --- a/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/SpellsCastWatcher.java @@ -5,10 +5,8 @@ */ package mage.watchers.common; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; +import java.util.*; + import mage.MageObject; import mage.constants.WatcherScope; import mage.constants.Zone; @@ -25,11 +23,11 @@ import mage.watchers.Watcher; */ public class SpellsCastWatcher extends Watcher { - private final HashMap> spellsCast = new HashMap<>(); + private final Map> spellsCast = new HashMap<>(); private int nonCreatureSpells; public SpellsCastWatcher() { - super(SpellsCastWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public SpellsCastWatcher(final SpellsCastWatcher watcher) { diff --git a/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java b/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java index 65e44a07af..c142833210 100644 --- a/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/WasBlockedThisTurnWatcher.java @@ -19,11 +19,11 @@ public class WasBlockedThisTurnWatcher extends Watcher { private final Set wasBlockedThisTurnCreatures; public WasBlockedThisTurnWatcher() { - super(WasBlockedThisTurnWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); wasBlockedThisTurnCreatures = new HashSet<>(); } - public WasBlockedThisTurnWatcher(final WasBlockedThisTurnWatcher watcher) { + private WasBlockedThisTurnWatcher(final WasBlockedThisTurnWatcher watcher) { super(watcher); wasBlockedThisTurnCreatures = new HashSet<>(watcher.wasBlockedThisTurnCreatures); } diff --git a/Mage/src/main/java/mage/watchers/common/ZuberasDiedWatcher.java b/Mage/src/main/java/mage/watchers/common/ZuberasDiedWatcher.java index d176bdd186..61c555cffe 100644 --- a/Mage/src/main/java/mage/watchers/common/ZuberasDiedWatcher.java +++ b/Mage/src/main/java/mage/watchers/common/ZuberasDiedWatcher.java @@ -14,10 +14,14 @@ import mage.watchers.Watcher; */ public class ZuberasDiedWatcher extends Watcher { - public int zuberasDiedThisTurn = 0; + public int getZuberasDiedThisTurn() { + return zuberasDiedThisTurn; + } + + private int zuberasDiedThisTurn = 0; public ZuberasDiedWatcher() { - super(ZuberasDiedWatcher.class.getSimpleName(), WatcherScope.GAME); + super(WatcherScope.GAME); } public ZuberasDiedWatcher(final ZuberasDiedWatcher watcher) { diff --git a/Mage/src/main/resources/ratings/aer.csv b/Mage/src/main/resources/ratings/aer.csv new file mode 100644 index 0000000000..8801646b1a --- /dev/null +++ b/Mage/src/main/resources/ratings/aer.csv @@ -0,0 +1,184 @@ +Ajani Unyielding:40114 +Herald of Anguish:39905 +Rishkar, Peema Renegade:39137 +Aethersphere Harvester:38827 +Heart of Kiran:37403 +Yahenni’s Expertise:37199 +Tezzeret the Schemer:34694 +Solemn Recruit:34338 +Untethered Express:33419 +Battle at the Bridge:33072 +Yahenni, Undying Partisan:32377 +Fatal Push:32126 +Sram’s Expertise:32076 +Walking Ballista:31052 +Baral’s Expertise:30879 +Freejam Regent:30870 +Glint-Sleeve Siphoner:30022 +Ridgescale Tusker:30018 +Quicksmith Spy:29214 +Scrapper Champion:29176 +Aethertide Whale:28976 +Daring Demolition:28538 +Gifted Aetherborn:28163 +Quicksmith Rebel:27792 +Hungry Flames:27737 +Thopter Arrest:27574 +Exquisite Archangel:27415 +Kari Zev, Skyship Raider:27188 +Aetherwind Basker:26371 +Treasure Keeper:26283 +Greenbelt Rampager:26185 +Vengeful Rebel:25902 +Aethergeode Miner:25711 +Rishkar’s Expertise:25327 +Lightning Runner:25297 +Shock:25129 +Caught in the Brights:24815 +Lifecrafter’s Bestiary:24466 +Midnight Entourage:23732 +Sram, Senior Edificer:23386 +Metallic Mimic:23383 +Maulfist Revolutionary:23093 +Greenwheel Liberator:21817 +Chandra’s Revolution:21713 +Maverick Thopterist:21685 +Airdrop Aeronauts:21061 +Narnam Renegade:20406 +Winding Constrictor:20174 +Scrap Trawler:20001 +Monstrous Onslaught:19528 +Wind-Kin Raiders:19507 +Deadeye Harpooner:19305 +Skyship Plunderer:18967 +Aether Poisoner:18617 +Cruel Finality:18352 +Release the Gremlins:18286 +Aether Chaser:17813 +Rogue Refiner:17646 +Reckless Racer:17299 +Dawnfeather Eagle:17238 +Felidar Guardian:17122 +Prey Upon:16986 +Spire Patrol:16942 +Druid of the Cowl:16941 +Aetherstream Leopard:16826 +Reverse Engineer:15858 +Daredevil Dragster:15795 +Shielded Aether Thief:15596 +Scrounging Bandar:14827 +Lifecraft Cavalry:14821 +Pacification Array:14672 +Renegade Rallier:14442 +Trophy Mage:14084 +Enraged Giant:13989 +Foundry Hornet:13907 +Call for Unity:13832 +Renegade Wheelsmith:13717 +Peacewalker Colossus:13604 +Sweatworks Brawler:13229 +Aether Swooper:13171 +Outland Boar:13074 +Restoration Specialist:12713 +Perilous Predicament:12702 +Aeronaut Admiral:12409 +Tezzeret’s Touch:12281 +Oath of Ajani:11663 +Bastion Inventor:11485 +Weldfast Engineer:11309 +Countless Gears Renegade:11144 +Mechanized Production:10887 +Hinterland Drake:10667 +Consulate Crackdown:10549 +Renegade Map:10115 +Peema Aether-Seer:9906 +Unbridled Growth:9661 +Lifecraft Awakening:9620 +Baral, Chief of Compliance:9382 +Merchant’s Dockhand:9033 +Barricade Breaker:8635 +Lifecrafter’s Gift:8248 +Hidden Herbalists:8012 +Mobile Garrison:7976 +Aether Herder:7964 +Disallow:7550 +Kari Zev’s Expertise:7472 +Cogwork Assembler:7463 +Heroic Intervention:6922 +Hidden Stockpile:6732 +Illusionist’s Stratagem:6678 +Leave in the Dust:6675 +Ghirapur Osprey:6597 +Decommission:6354 +Ice Over:6297 +Night Market Aeronaut:6198 +Gremlin Infestation:6195 +Spire of Industry:6181 +Audacious Infiltrator:6084 +Sly Requisitioner:5718 +Alley Strangler:5595 +Silkweaver Elite:5574 +Aid from the Cowl:5463 +Highspire Infusion:5402 +Frontline Rebel:5350 +Invigorated Rampage:5268 +Defiant Salvager:5211 +Watchful Automaton:5147 +Siege Modification:5142 +Inspiring Statuary:4932 +Embraal Gear-Smasher:4847 +Deft Dismissal:4727 +Shipwreck Moray:4645 +Metallic Rebuke:4618 +Dispersal Technician:4389 +Resourceful Return:4325 +Efficient Construction:4108 +Welder Automaton:4076 +Aether Inspector:3989 +Ravenous Intruder:3963 +Ironclad Revolutionary:3930 +Implement of Ferocity:3720 +Alley Evasion:3712 +Hope of Ghirapur:3699 +Aerial Modification:3671 +Gonti’s Aether Heart:3295 +Foundry Assembler:3292 +Fen Hauler:3265 +Natural Obsolescence:3262 +Destructive Tampering:3239 +Implement of Examination:3217 +Irontread Crusher:3097 +Filigree Crawler:3020 +Servo Schematic:3006 +Verdant Automaton:2979 +Reservoir Walker:2918 +Whir of Invention:2916 +Paradox Engine:2714 +Salvage Scuttler:2677 +Augmenting Automaton:2636 +Fourth Bridge Prowler:2448 +Conviction:2411 +Lathnu Sailback:2352 +Planar Bridge:2348 +Night Market Guard:2244 +Bastion Enforcer:2236 +Precise Strike:2179 +Universal Solvent:2128 +Implement of Malice:2089 +Crackdown Construct:1926 +Dark Intimations:1876 +Pia’s Revolution:1850 +Renegade’s Getaway:1472 +Aegis Automaton:1355 +Consulate Dreadnought:1255 +Indomitable Creativity:1206 +Negate:1016 +Consulate Turret:1014 +Implement of Combustion:806 +Take into Custody:678 +Implement of Improvement:624 +Wrangle:543 +Ornithopter:177 +Gonti’s Machinations:167 +Prizefighter Construct:123 +Secret Salvage:77 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/akh.csv b/Mage/src/main/resources/ratings/akh.csv new file mode 100644 index 0000000000..168d2671cc --- /dev/null +++ b/Mage/src/main/resources/ratings/akh.csv @@ -0,0 +1,249 @@ +Angel of Sanctions:1638 +Glorybringer:1590 +Oketra the True:1512 +Rhonas the Indomitable:1456 +Gideon of the Trials:1445 +Hazoret the Fervent:1404 +Liliana, Death’s Majesty:1370 +Archfiend of Ifnir:1346 +Cast Out:1331 +Curator of Mysteries:1329 +Regal Caracal:1324 +Glyph Keeper:1312 +Cut /// Ribbons:1310 +Dusk /// Dawn:1266 +Vizier of Many Faces:1252 +Never /// Return:1251 +Vizier of the Menagerie:1243 +Heart-Piercer Manticore:1220 +Liliana’s Mastery:1216 +Trial of Zeal:1195 +Samut, Voice of Dissent:1190 +Nissa, Steward of Elements:1174 +Magma Spray:1157 +Honored Hydra:1132 +Sweltering Suns:1126 +Glory-Bound Initiate:1125 +Lord of the Accursed:1119 +Ahn-Crop Crasher:1115 +Insult /// Injury:1113 +Champion of Rhonas:1096 +Plague Belcher:1095 +Angler Drake:1091 +Cartouche of Strength:1089 +Electrify:1083 +Combat Celebrant:1079 +Compulsory Rest:1073 +Crocodile of the Crossing:1061 +Gust Walker:1058 +Scaled Behemoth:1055 +Decimator Beetle:1050 +Bone Picker:1048 +Drake Haven:1042 +Mouth /// Feed:1039 +Channeler Initiate:1038 +Deem Worthy:1031 +Bontu the Glorified:1022 +Trial of Solidarity:1018 +Final Reward:1013 +Stir the Sands:1010 +Hapatra, Vizier of Poisons:1009 +Start /// Finish:1005 +Trial of Strength:1002 +Emberhorn Minotaur:999 +Prepare /// Fight:998 +Baleful Ammit:997 +Cartouche of Knowledge:989 +Cruel Reality:989 +Sandwurm Convergence:973 +Prowling Serpopard:965 +Trial of Ambition:962 +Devoted Crop-Mate:959 +Oketra’s Attendant:955 +Commit /// Memory:952 +Neheb, the Worthy:952 +Aven Wind Guide:944 +Bloodrage Brawler:944 +Fan Bearer:936 +Dread Wanderer:930 +Temmet, Vizier of Naktamun:924 +Oketra’s Monument:921 +Edifice of Authority:919 +Cartouche of Ambition:918 +Wayward Servant:905 +Lay Claim:903 +Splendid Agony:896 +Tah-Crop Elite:894 +Kefnet the Mindful:884 +Gravedigger:871 +Harsh Mentor:864 +Soulstinger:863 +Exemplar of Strength:862 +Cartouche of Zeal:861 +Defiant Greatmaw:846 +Enigma Drake:846 +Cartouche of Solidarity:840 +Labyrinth Guardian:836 +Vizier of Deferment:835 +Naga Vitalist:834 +Pull from Tomorrow:832 +Rags /// Riches:832 +Khenra Charioteer:829 +Hooded Brawler:828 +Horror of the Broken Lands:815 +Trueheart Duelist:815 +Honored Crop-Captain:813 +Bitterblade Warrior:812 +Shefet Monitor:808 +Heaven /// Earth:807 +Seraph of the Suns:805 +Nef-Crop Entangler:803 +Greater Sandwurm:802 +Ruthless Sniper:799 +Cursed Minotaur:798 +Rhet-Crop Spearmaster:796 +Soul-Scar Mage:796 +Trial of Knowledge:787 +Trueheart Twins:785 +Battlefield Scavenger:784 +Aven Initiate:782 +Wasteland Scorpion:778 +Impeccable Timing:774 +Essence Scatter:773 +Open into Wonder:769 +Unwavering Initiate:767 +Warfire Javelineer:765 +Manticore of the Gauntlet:762 +Binding Mummy:760 +Approach of the Second Sun:758 +Ahn-Crop Champion:757 +Synchronized Strike:756 +Winged Shepherd:747 +Ornery Kudu:742 +Cryptic Serpent:741 +Shimmerscale Drake:739 +Hieroglyphic Illumination:737 +Censor:733 +Illusory Wrappings:731 +Watchful Naga:731 +Vizier of Tumbling Sands:724 +Minotaur Sureshot:720 +Rhonas’s Monument:719 +Galestrike:718 +Merciless Javelineer:718 +Bounty of the Luxa:712 +Aven Mindcensor:708 +Naga Oracle:705 +Thresher Lizard:692 +Quarry Hauler:689 +Irrigated Farmland:688 +Pathmaker Initiate:681 +Shadowstorm Vizier:678 +Grim Strider:676 +Flameblade Adept:674 +Sheltered Thicket:672 +Destined /// Lead:668 +Wander in Death:668 +Weaver of Currents:663 +Blighted Bat:651 +Nest of Scarabs:648 +Oracle’s Vault:646 +Canyon Slough:643 +Evolving Wilds:640 +Colossapede:638 +Sacred Cat:637 +Doomed Dissenter:635 +Fetid Pools:628 +Festering Mummy:616 +Onward /// Victory:615 +Throne of the God-Pharaoh:613 +Anointed Procession:608 +Gift of Paradise:602 +Anointer Priest:599 +Consuming Fervor:595 +Limits of Solidarity:594 +Spring /// Mind:593 +Desert Cerodon:592 +Sparring Mummy:592 +River Serpent:584 +Seeker of Insight:582 +Shed Weakness:582 +Gideon’s Intervention:580 +Slither Blade:580 +Tah-Crop Skirmisher:580 +Initiate’s Companion:570 +Pitiless Vizier:567 +Scattered Groves:563 +Supernatural Stamina:563 +Vizier of Remedies:563 +Hekma Sentinels:562 +Bloodlust Inciter:559 +Pouncing Cheetah:559 +Winds of Rebuke:550 +Cancel:540 +Painful Lesson:536 +Mighty Leap:535 +Pyramid of the Pantheon:535 +Reduce /// Rubble:533 +Brute Strength:530 +Floodwaters:530 +Faith of the Devoted:529 +Manglehorn:529 +Miasmic Mummy:522 +Fling:519 +Oashra Cultivator:512 +In Oketra’s Name:510 +Forsake the Worldly:506 +Supply Caravan:505 +Time to Reflect:505 +Decision Paralysis:504 +Giant Spider:504 +Hapatra’s Mark:500 +Nimble-Blade Khenra:499 +Harvest Season:497 +Failure /// Comply:496 +Zenith Seeker:494 +Those Who Serve:491 +Bontu’s Monument:488 +As Foretold:487 +Tormenting Voice:487 +Hazoret’s Monument:485 +New Perspectives:484 +Pursue Glory:478 +Unburden:476 +Djeru’s Resolve:469 +Spidery Grasp:468 +Kefnet’s Monument:466 +Lay Bare the Heart:464 +Scribe of the Mindful:463 +Honed Khopesh:450 +Stinging Shot:443 +Trespasser’s Curse:431 +Blazing Volley:430 +Watchers of the Dead:415 +Sixth Sense:413 +Dune Beetle:386 +Cradle of the Accursed:382 +Glorious End:380 +Sacred Excavation:379 +Grasping Dunes:372 +Shadow of the Grave:370 +Cascading Cataracts:357 +Hyena Pack:356 +Benefaction of Rhonas:354 +Dissenter’s Deliverance:353 +Painted Bluffs:348 +Renewed Faith:337 +Hazoret’s Favor:305 +Violent Impact:284 +Haze of Pollen:277 +Scarab Feast:268 +Compelling Argument:265 +Embalmer’s Tools:260 +Luxa River Shrine:213 +By Force:201 +Ancient Crab:198 +Sunscorched Desert:186 +Dispossess:109 +Protection of the Hekma:108 +Gate to the Afterlife 95 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/dom.csv b/Mage/src/main/resources/ratings/dom.csv new file mode 100644 index 0000000000..b14997dc93 --- /dev/null +++ b/Mage/src/main/resources/ratings/dom.csv @@ -0,0 +1,249 @@ +Lyra Dawnbringer:2375 +Karn, Scion of Urza:2372 +Shalai, Voice of Plenty:2234 +Teferi, Hero of Dominaria:2215 +Verix Bladewing:2207 +Aryel, Knight of Windgrace:2166 +Multani, Yavimaya’s Avatar:2150 +History of Benalia:2123 +Siege-Gang Commander:2091 +In Bolas’s Clutches:2047 +Josu Vess, Lich Knight:2044 +Cast Down:2025 +Demonlord Belzenlok:2016 +Eviscerate:2010 +Serra Angel:2000 +Slimefoot, the Stowaway:1995 +Seal Away:1985 +Tatyova, Benthic Druid:1981 +Zahid, Djinn of the Lamp:1971 +Darigaaz Reincarnated:1959 +Weatherlight:1952 +Phyrexian Scriptures:1951 +Forebear’s Blade:1928 +Adeliz, the Cinder Wind:1919 +The Eldest Reborn:1919 +Teshar, Ancestor’s Apostle:1913 +Territorial Allosaurus:1896 +Danitha Capashen, Paragon:1895 +Muldrotha, the Gravetide:1881 +Fight with Fire:1879 +Shivan Fire:1879 +Helm of the Host:1876 +Knight of Grace:1863 +Vicious Offering:1859 +Pegasus Courser:1856 +Icy Manipulator:1849 +Benalish Marshal:1837 +Untamed Kavu:1836 +Goblin Chainwhirler:1834 +Raff Capashen, Ship’s Mage:1834 +Blessed Light:1833 +Rite of Belzenlok:1827 +Naru Meha, Master Wizard:1824 +Grand Warlord Radha:1817 +Two-Headed Giant:1817 +Llanowar Elves:1815 +Shanna, Sisay’s Legacy:1814 +Steel Leaf Champion:1811 +Song of Freyalise:1807 +Settle the Score:1804 +Time of Ice:1804 +Grunn, the Lonely King:1793 +Knight of Malice:1786 +Arvad the Cursed:1783 +Jhoira, Weatherlight Captain:1780 +Saproling Migration:1780 +Wizard’s Lightning:1779 +Tempest Djinn:1777 +Urgoros, the Empty One:1773 +Cloudreader Sphinx:1769 +Baloth Gorger:1768 +Skittering Surveyor:1765 +Baird, Steward of Argive:1762 +Blackblade Reforged:1760 +Hallar, the Firefletcher:1760 +On Serra’s Wings:1753 +Evra, Halcyon Witness:1748 +Traxos, Scourge of Kroog:1746 +Blink of an Eye:1742 +Triumph of Gerrard:1725 +Deep Freeze:1723 +Kazarov, Sengir Pureblood:1718 +Tiana, Ship’s Caretaker:1712 +Merfolk Trickster:1709 +Squee, the Immortal:1708 +Valduk, Keeper of the Flame:1708 +Kwende, Pride of Femeref:1707 +Whisper, Blood Liturgist:1707 +Academy Drake:1705 +Jaya Ballard:1704 +Gideon’s Reproach:1703 +Warcry Phoenix:1703 +Sporecrown Thallid:1698 +Yavimaya Sapherd:1692 +Rona, Disciple of Gix:1686 +Wizard’s Retort:1684 +Elfhame Druid:1683 +Fiery Intervention:1682 +Torgaar, Famine Incarnate:1682 +Yawgmoth’s Vile Offering:1677 +Deathbloom Thallid:1665 +Fungal Infection:1662 +Daring Archaeologist:1658 +Cold-Water Snapper:1656 +Thorn Elemental:1656 +Call the Cavalry:1649 +Sylvan Awakening:1648 +Jaya’s Immolating Inferno:1646 +Verdant Force:1642 +Fungal Plots:1636 +Spore Swarm:1635 +Divination:1629 +Syncopate:1626 +Marwyn, the Nurturer:1625 +Sergeant-at-Arms:1625 +Garna, the Bloodflame:1624 +Ghitu Chronicler:1622 +Tetsuko Umezawa, Fugitive:1612 +Dread Shade:1602 +Stronghold Confessor:1601 +Academy Journeymage:1599 +Chainer’s Torment:1593 +Thallid Omnivore:1592 +Thallid Soothsayer:1592 +Jousting Lance:1587 +Firefist Adept:1581 +Goblin Barrage:1580 +Naban, Dean of Iteration:1579 +Caligo Skin-Witch:1577 +Karn’s Temporal Sundering:1577 +Keldon Overseer:1574 +Dauntless Bodyguard:1572 +Opt:1572 +Ghitu Journeymage:1570 +The Mending of Dominaria:1568 +The Mirari Conjecture:1568 +Wild Onslaught:1567 +Haphazard Bombardment:1566 +Skizzik:1565 +Mammoth Spider:1558 +Serra Disciple:1558 +Clifftop Retreat:1557 +Aven Sentry:1556 +Mishra’s Self-Replicator:1552 +Ancient Animus:1550 +D’Avenant Trapper:1550 +Gilded Lotus:1549 +Jhoira’s Familiar:1548 +Champion of the Flame:1547 +Ghitu Lavarunner:1547 +Woodland Cemetery:1543 +Keldon Raider:1541 +Grow from the Ashes:1536 +Radiating Lightning:1536 +Sanctum Spirit:1533 +Windgrace Acolyte:1532 +Urza’s Ruinous Blast:1531 +Sulfur Falls:1527 +The Antiquities War:1522 +Adamant Will:1519 +Goblin Warchief:1518 +Adventurous Impulse:1516 +Mesa Unicorn:1512 +Bloodtallow Candle:1510 +Hinterland Harbor:1509 +Lingering Phantom:1506 +Short Sword:1499 +Llanowar Scout:1495 +Juggernaut:1493 +Frenzied Rage:1490 +Slinn Voda, the Rising Deep:1489 +Dub:1484 +Cabal Paladin:1482 +Gift of Growth:1482 +Dark Bargain:1481 +Benalish Honor Guard:1480 +Isolated Chapel:1473 +Kamahl’s Druidic Vow:1472 +Memorial to Glory:1469 +Sentinel of the Pearl Trident:1466 +Krosan Druid:1465 +Guardians of Koilos:1457 +Llanowar Envoy:1455 +Pardic Wanderer:1450 +Soul Salvage:1449 +The Flame of Keld:1448 +Arcane Flight:1445 +Divest:1444 +Feral Abomination:1441 +Artificer’s Assistant:1439 +Memorial to Unity:1439 +Yargle, Glutton of Urborg:1436 +Sparring Construct:1431 +Mox Amber:1429 +Weight of Memory:1426 +Precognition Field:1424 +The First Eruption:1420 +Invoke the Divine:1414 +Unwind:1413 +Primordial Wurm:1409 +Bloodstone Goblin:1408 +Vodalian Arcanist:1401 +Cabal Stronghold:1400 +Urza’s Tome:1393 +Lich’s Mastery:1390 +Primevals’ Glorious Rebirth:1390 +Run Amok:1390 +Gaea’s Protector:1382 +Pierce the Sky:1382 +Relic Runner:1381 +Jodah, Archmage Eternal:1378 +Excavation Elephant:1377 +Knight of New Benalia:1377 +Aesthir Glider:1376 +Befuddle:1375 +Homarid Explorer:1372 +Memorial to Folly:1371 +Howling Golem:1369 +Voltaic Servant:1369 +Nature’s Spiral:1368 +Sorcerer’s Wand:1366 +Corrosive Ooze:1360 +Broken Bond:1357 +Curator’s Ward:1355 +Tolarian Scholar:1354 +Memorial to Genius:1349 +Rampaging Cyclops:1347 +Warlord’s Fury:1328 +Fervent Strike:1321 +Demonic Vigor:1320 +Keldon Warcaller:1319 +Arbor Armament:1314 +Final Parting:1313 +Diligent Excavator:1312 +Navigator’s Compass:1308 +Charge:1307 +Amaranthine Wall:1305 +Cabal Evangel:1305 +Fire Elemental:1304 +Shield of the Realm:1304 +Oath of Teferi:1300 +Tragic Poet:1283 +Blessing of Belzenlok:1272 +Board the Weatherlight:1258 +Thran Temporal Gateway:1256 +Drudge Sentinel:1248 +Orcish Vandal:1247 +Skirk Prospector:1246 +Zhalfirin Void:1239 +Sage of Lat-Nam:1232 +Rescue:1225 +Gaea’s Blessing:1218 +Healing Grace:1200 +Rat Colony:1191 +Powerstone Shard:1162 +Seismic Shift:1152 +Damping Sphere:1133 +Fall of the Thran:1104 +Memorial to War:1089 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/grn.csv b/Mage/src/main/resources/ratings/grn.csv new file mode 100644 index 0000000000..b8ec123486 --- /dev/null +++ b/Mage/src/main/resources/ratings/grn.csv @@ -0,0 +1,259 @@ +Doom Whisperer:2332 +Aurelia, Exemplar of Justice:2258 +Vraska, Golgari Queen:2211 +Ral, Izzet Viceroy:2196 +Dream Eater:2180 +Thief of Sanity:2164 +Assassin's Trophy:2153 +Trostani Discordant:2141 +Beast Whisperer:2102 +Nullhide Ferox:2102 +Legion Warboss:2100 +March of the Multitudes:2094 +Conclave Tribunal:2092 +Niv-Mizzet, Parun:2088 +Light of the Legion:2073 +Price of Fame:2036 +Etrata, the Silencer:2019 +Venerated Loxodon:2017 +Justice Strike:2016 +Tajic, Legion's Edge:2005 +Underrealm Lich:1985 +Pelt Collector:1984 +Izoni, Thousand-Eyed:1977 +Find // Finality:1976 +Lazav, the Multifarious:1973 +Nightveil Sprite:1968 +Midnight Reaper:1964 +Lava Coil:1963 +Watcher in the Mist:1961 +Response // Resurgence:1958 +Knight of Autumn:1950 +Dimir Spybug:1948 +Integrity // Intervention:1945 +Nightveil Predator:1943 +Emmara, Soul of the Accord:1942 +Luminous Bonds:1932 +Artful Takedown:1923 +Ritual of Soot:1914 +Blood Operative:1903 +Conclave Cavalier:1902 +Truefire Captain:1902 +Runaway Steam-Kin:1901 +Murmuring Mystic:1899 +Arclight Phoenix:1894 +Risk Factor:1893 +Boros Challenger:1887 +Dead Weight:1887 +Bounty of Might:1886 +Connive // Concoct:1886 +Status // Statue:1885 +Deadly Visit:1878 +Deafening Clarion:1878 +Roc Charger:1864 +Kraul Harpooner:1839 +Citywatch Sphinx:1837 +Assure // Assemble:1836 +Expansion // Explosion:1836 +Capture Sphere:1834 +Thoughtbound Phantasm:1832 +Crackling Drake:1830 +Dawn of Hope:1827 +Disinformation Campaign:1826 +House Guildmage:1824 +Quasiduplicate:1816 +Sunhome Stalwart:1815 +Skyknight Legionnaire:1805 +Darkblade Agent:1788 +Plaguecrafter:1786 +Goblin Cratermaker:1773 +Affectionate Indrik:1772 +Whisper Agent:1771 +Notion Rain:1761 +Ledev Champion:1757 +Charnel Troll:1751 +Thought Erasure:1750 +Golgari Findbroker:1749 +Chemister's Insight:1743 +Goblin Banneret:1737 +Swiftblade Vindicator:1736 +Command the Storm:1728 +Camaraderie:1726 +Wee Dragonauts:1723 +District Guide:1722 +Hypothesizzle:1715 +League Guildmage:1712 +Direct Current:1711 +Experimental Frenzy:1711 +Discovery // Dispersal:1708 +Rampaging Monument:1705 +Rosemane Centaur:1698 +Inescapable Blaze:1693 +Watery Grave:1687 +Legion Guildmage:1680 +Chamber Sentry:1674 +Inspiring Unicorn:1671 +Ionize:1669 +Flower // Flourish:1663 +Divine Visitation:1656 +Dimir Informant:1653 +Healer's Hawk:1651 +Conclave Guildmage:1648 +Sinister Sabotage:1647 +Parhelion Patrol:1640 +Ochran Assassin:1639 +Goblin Electromancer:1634 +Glowspore Shaman:1631 +Siege Wurm:1629 +Wojek Bodyguard:1629 +Hellkite Whelp:1626 +Hired Poisoner:1625 +Unexplained Disappearance:1625 +Overgrown Tomb:1624 +Prey Upon:1624 +Pitiless Gorgon:1622 +Flight of Equenauts:1621 +Hatchery Spider:1621 +Temple Garden:1621 +Beacon Bolt:1620 +Citywide Bust:1615 +Bounty Agent:1613 +Piston-Fist Cyclops:1605 +Steam Vents:1600 +Erratic Cyclops:1582 +Swarm Guildmage:1582 +Sacred Foundry:1581 +Mission Briefing:1580 +Muse Drake:1574 +Arboretum Elemental:1572 +Worldsoul Colossus:1572 +Skyline Scout:1569 +Smelt-Ward Minotaur:1568 +Burglar Rat:1561 +Whispering Snitch:1560 +Fresh-Faced Recruit:1555 +Necrotic Wound:1554 +Electrostatic Field:1541 +Disdainful Stroke:1534 +Gruesome Menagerie:1534 +Sprouting Renewal:1534 +Sonic Assault:1533 +Sure Strike:1527 +Severed Strands:1522 +Beamsplitter Mage:1521 +Chromatic Lantern:1516 +Ledev Guardian:1510 +Radical Idea:1502 +Pilfering Imp:1500 +Vernadi Shieldmate:1497 +Ornery Goblin:1495 +Gatekeeper Gargoyle:1489 +Barging Sergeant:1484 +Blade Instructor:1483 +Rhizome Lurcher:1481 +Invert // Invent:1477 +Ironshell Beetle:1477 +Generous Stray:1474 +Demotion:1469 +Might of the Masses:1468 +Molderhulk:1467 +Selective Snare:1466 +Hammer Dropper:1463 +Swathcutter Giant:1462 +Firemind's Research:1460 +Devkarin Dissident:1459 +Mnemonic Betrayal:1459 +Vigorspore Wurm:1459 +Haazda Marshal:1457 +Lotleth Giant:1455 +Righteous Blow:1451 +Fire Urchin:1446 +Gird for Battle:1441 +Kraul Swarm:1437 +Veiled Shade:1437 +Centaur Peacemaker:1434 +Golgari Raiders:1434 +Passwall Adept:1434 +Sworn Companions:1434 +Erstwhile Trooper:1432 +Hunted Witness:1431 +Kraul Foragers:1431 +Collar the Culprit:1427 +Mausoleum Secrets:1424 +Take Heart:1424 +Dazzling Lights:1419 +Rubblebelt Boar:1418 +Sumala Woodshaper:1418 +Intrusive Packbeast:1416 +Loxodon Restorer:1415 +Omnispell Adept:1415 +Spinal Centipede:1415 +Glaive of the Guildpact:1414 +Vivid Revival:1410 +Douser of Lights:1409 +Devious Cover-Up:1404 +Chance for Glory:1402 +Child of Night:1402 +Enhanced Surveillance:1399 +Hitchclaw Recluse:1398 +Mephitic Vapors:1395 +Circuitous Route:1389 +Cosmotronic Wave:1389 +Leapfrog:1379 +Goblin Locksmith:1377 +Guildmages' Forum:1370 +Guild Summit:1368 +Bartizan Bats:1367 +Undercity Uprising:1363 +Thousand-Year Storm:1355 +Drowned Secrets:1349 +Boros Guildgate :1345 +Grappling Sundew:1344 +Boros Guildgate :1343 +Tenth District Guard:1342 +Izzet Guildgate :1338 +Crushing Canopy:1335 +Portcullis Vine:1333 +Undercity Necrolisk:1332 +Dimir Guildgate :1331 +Barrier of Bones:1327 +Wild Ceratok:1327 +Izzet Guildgate :1326 +Gravitic Punch:1320 +Silent Dart:1310 +Wary Okapi:1309 +Pack's Favor:1307 +Garrison Sergeant:1303 +Vedalken Mesmerist:1303 +Golgari Guildgate :1295 +Golgari Guildgate :1286 +Dimir Guildgate :1280 +Maniacal Rage:1280 +Selesnya Guildgate :1280 +Urban Utopia:1278 +Wall of Mist:1273 +Maximize Altitude:1268 +Join Shields:1267 +Selesnya Guildgate :1266 +Book Devourer:1263 +Wishcoin Crab:1262 +Narcomoeba:1257 +Crush Contraband:1248 +Gateway Plaza:1248 +Fearless Halberdier:1246 +Torch Courier:1242 +Candlelight Vigil:1241 +Moodmark Painter:1230 +Creeping Chill:1218 +Izzet Locket:1217 +Dimir Locket:1202 +Maximize Velocity:1200 +Unmoored Ego:1184 +Never Happened:1175 +Golgari Locket:1173 +Selesnya Locket:1154 +Boros Locket:1128 +Street Riot:1110 +Vicious Rumors:1101 +Pause for Reflection:1089 +Wand of Vertebrae:1073 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/hou.csv b/Mage/src/main/resources/ratings/hou.csv new file mode 100644 index 0000000000..5687f1f849 --- /dev/null +++ b/Mage/src/main/resources/ratings/hou.csv @@ -0,0 +1,184 @@ +The Scarab God:2272 +Angel of Condemnation:2079 +The Locust God:2077 +The Scorpion God:2048 +Pride Sovereign:2046 +Crested Sunmare:1996 +Nicol Bolas, God-Pharaoh:1965 +Majestic Myriarch:1915 +Neheb, the Eternal:1906 +Hour of Devastation:1901 +Adorned Pouncer:1889 +Ammit Eternal:1881 +Samut, the Tested:1874 +Razaketh, the Foulblooded:1856 +Grind // Dust:1855 +Resilient Khenra:1832 +Sand Strangler:1822 +Ramunap Hydra:1818 +Abrade:1816 +Desert’s Hold:1813 +Champion of Wits:1810 +Bontu’s Last Reckoning:1807 +Nimble Obstructionist:1796 +Chaos Maw:1788 +Sifter Wurm:1783 +Unesh, Criosphinx Sovereign:1776 +Hour of Glory:1771 +River Hoopoe:1769 +Ominous Sphinx:1754 +Torment of Hailfire:1754 +Open Fire:1751 +Torment of Venom:1743 +Dreamstealer:1740 +Struggle // Survive:1737 +Burning-Fist Minotaur:1734 +Ambuscade:1732 +God-Pharaoh’s Gift:1731 +Accursed Horde:1729 +Doomfall:1727 +Earthshaker Khenra:1716 +Aerial Guide:1711 +Khenra Scrapper:1709 +Oketra’s Avenger:1691 +Bloodwater Entity:1689 +Rhonas’s Last Stand:1686 +Angel of the God-Pharaoh:1685 +Tenacious Hunter:1685 +Hour of Promise:1684 +Eternal of Harsh Truths:1680 +Fervent Paincaster:1677 +Lethal Sting:1673 +Vizier of the Anointed:1673 +Wildfire Eternal:1671 +Puncturing Blow:1668 +Sandblast:1668 +Sunscourge Champion:1661 +Spellweaver Eternal:1656 +Vizier of the True:1656 +Banewhip Punisher:1652 +Kefnet’s Last Word:1652 +Merciless Eternal:1648 +Vile Manifestation:1647 +Bitterbow Sharpshooters:1646 +Driven // Despair:1643 +Supreme Will:1638 +Hour of Revelation:1637 +Torment of Scarabs:1637 +Oasis Ritualist:1636 +Farm // Market:1628 +Unraveling Mummy:1628 +Obelisk Spider:1617 +Mirage Mirror:1615 +Manticore Eternal:1613 +Resolute Survivors:1610 +Ruin Rat:1610 +Overwhelming Splendor:1608 +Unconventional Tactics:1608 +Hour of Eternity:1606 +Devotee of Strength:1605 +Sinuous Striker:1604 +Sunset Pyramid:1602 +Riddleform:1600 +Solitary Camel:1600 +Harrier Naga:1598 +Steward of Solidarity:1597 +Sidewinder Naga:1595 +Dauntless Aven:1591 +Feral Prowler:1591 +Thorned Moloch:1586 +Striped Riverwinder:1584 +Frontline Devastator:1580 +Appeal // Authority:1578 +Aven of Enduring Hope:1577 +Mummy Paramount:1571 +Uncage the Menagerie:1570 +Consign // Oblivion:1564 +Hollow One:1561 +Aven Reedstalker:1560 +Rhonas’s Stalwart:1559 +Unsummon:1557 +Desert of the Glorified:1556 +Manalith:1555 +Hope Tender:1551 +Granitic Titan:1550 +Ifnir Deadlands:1550 +Blur of Blades:1547 +Marauding Boneslasher:1547 +Shefet Dunes:1547 +Claim // Fame:1545 +Magmaroth:1545 +Beneath the Sands:1543 +Ramunap Excavator:1542 +Desert of the Mindful:1541 +Khenra Eternal:1541 +Reason // Believe:1541 +Rampaging Hippo:1540 +Unquenchable Thirst:1539 +Razaketh’s Rite:1537 +Saving Grace:1532 +Steadfast Sentinel:1531 +Wall of Forgotten Pharaohs:1531 +Imminent Doom:1530 +Defiant Khenra:1526 +Cunning Survivor:1525 +Ramunap Ruins:1525 +Hashep Oasis:1524 +Overcome:1523 +Abandoned Sarcophagus:1514 +Carrion Screecher:1514 +Firebrand Archer:1510 +Frilled Sandwalla:1507 +Hazoret’s Undying Fury:1505 +Inferno Jet:1499 +Crypt of the Eternals:1496 +Gift of Strength:1495 +Kindled Fury:1493 +Ipnu Rivulet:1492 +Act of Heroism:1491 +Without Weakness:1489 +Desert of the Indomitable:1487 +Fraying Sanity:1485 +Hostile Desert:1484 +Traveler’s Amulet:1482 +God-Pharaoh’s Faithful:1477 +Desert of the Fervent:1476 +Apocalypse Demon:1474 +Wretched Camel:1472 +Dagger of the Worthy:1468 +Refuse // Cooperate:1468 +Quarry Beetle:1464 +Countervailing Winds:1460 +Gilded Cerodon:1455 +Djeru, With Eyes Open:1450 +Strategic Planning:1450 +Tragic Lesson:1449 +Scrounger of Souls:1447 +Dune Diviner:1438 +Desert of the True:1436 +Chandra’s Defeat:1433 +Proven Combatant:1430 +Survivors’ Encampment:1427 +Djeru’s Renunciation:1425 +Disposal Mummy:1422 +Imaginary Threats:1418 +Moaning Wall:1416 +Dutiful Servants:1403 +Oketra’s Last Mercy:1403 +Crash Through:1400 +Lurching Rotbeast:1397 +Swarm Intelligence:1397 +Life Goes On:1395 +Grisly Survivor:1388 +Dunes of the Dead:1381 +Jace’s Defeat:1369 +Endless Sands:1367 +Seer of the Last Tomorrow:1360 +Graven Abomination:1352 +Gideon’s Defeat:1346 +Liliana’s Defeat:1345 +Leave // Chance:1324 +Solemnity:1265 +Scavenger Grounds:1256 +Crook of Condemnation:1228 +Nissa’s Defeat:1185 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/ima.csv b/Mage/src/main/resources/ratings/ima.csv new file mode 100644 index 0000000000..d9afedab23 --- /dev/null +++ b/Mage/src/main/resources/ratings/ima.csv @@ -0,0 +1,249 @@ +Consecrated Sphinx:2182 +Ancestral Vision:2144 +Archangel of Thune:2141 +Elesh Norn, Grand Cenobite:2135 +Mana Drain:2124 +Urabrask the Hidden:2107 +Sheoldred, Whispering One:2106 +Swords to Plowshares:2106 +Primeval Titan:2103 +Ob Nixilis, the Fallen:2081 +Doom Blade:2064 +Rampaging Baloths:2056 +Thundermaw Hellkite:2053 +Restoration Angel:2044 +Keiga, the Tide Star:2042 +Avacyn, Angel of Hope:2029 +Kiki-Jiki, Mirror Breaker:2024 +Kokusho, the Evening Star:2020 +Cryptic Command:2012 +Supreme Verdict:2002 +Genesis Hydra:2001 +Fireball:2000 +Emeria Angel:1992 +Austere Command:1969 +Blood Baron of Vizkopa:1968 +Lotus Cobra:1955 +Sphinx of Uthuun:1927 +Yosei, the Morning Star:1924 +Rift Bolt:1912 +Scourge of Valkas:1909 +Bogardan Hellkite:1907 +Ryusei, the Falling Star:1907 +Spiritmonger:1900 +Vorinclex, Voice of Hunger:1897 +Indulgent Tormentor:1888 +Heroes’ Bane:1885 +Jugan, the Rising Star:1877 +Simic Sky Swallower:1874 +Serra Angel:1873 +Grisly Spectacle:1865 +Rune-Scarred Demon:1864 +Channel:1861 +Hypersonic Dragon:1856 +Lightning Helix:1856 +Teferi, Mage of Zhalfir:1854 +Knight of the Reliquary:1848 +Thran Dynamo:1848 +Thoughtseize:1839 +Anger of the Gods:1836 +Savageborn Hydra:1829 +Charmbreaker Devils:1828 +Staggershock:1824 +Malfegor:1812 +Palladium Myr:1808 +Draconic Roar:1796 +Ulcerate:1795 +Heat Ray:1794 +Mahamoti Djinn:1793 +Hoarding Dragon:1786 +Corpsejack Menace:1783 +Abyssal Persecutor:1774 +Firemane Angel:1771 +Curse of Predation:1766 +Electrolyze:1754 +Reave Soul:1754 +Oblivion Stone:1744 +Overgrown Battlement:1738 +Claustrophobia:1736 +Obstinate Baloth:1732 +Blizzard Specter:1724 +Pillar of Flame:1724 +Wall of Roots:1723 +Undercity Troll:1721 +Cephalid Broker:1717 +Abzan Battle Priest:1716 +Abzan Falconer:1698 +Mind Stone:1697 +Illusory Ambusher:1691 +Fog Bank:1690 +Mana Leak:1689 +Genesis Wave:1686 +Condescend:1685 +Rosheen Meanderer:1682 +Aether Vial:1681 +Wing Shards:1680 +Bladewing the Risen:1677 +Vizkopa Guildmage:1671 +Aetherize:1669 +Bloodghast:1667 +Horizon Canopy:1662 +Noxious Dragon:1661 +Seeker of the Way:1657 +Azorius Charm:1650 +Topan Freeblade:1650 +Ajani’s Pridemate:1649 +Guttersnipe:1648 +Orzhov Basilica:1648 +Necropotence:1645 +Prodigal Pyromancer:1641 +Monastery Swiftspear:1639 +Phantom Monster:1637 +Search for Tomorrow:1637 +Phyrexian Rager:1630 +Frost Lynx:1624 +Carven Caryatid:1621 +Hunt the Weak:1621 +Izzet Boilerworks:1620 +Blinding Mage:1616 +Amass the Components:1610 +Iona’s Judgment:1605 +Repeal:1602 +Serra Ascendant:1601 +Star Compass:1600 +Kiln Fiend:1597 +Simic Growth Chamber:1596 +Auriok Champion:1592 +Illusory Angel:1588 +Day of the Dragons:1587 +Jungle Barrier:1586 +Rakdos Carnarium:1586 +Dimir Aqueduct:1575 +Golgari Rot Farm:1572 +Jin-Gitaxias, Core Augur:1570 +Bladewing’s Thrall:1562 +Mnemonic Wall:1562 +Ainok Bond-Kin:1561 +Crowned Ceratok:1556 +Jhessian Thief:1555 +Boros Garrison:1551 +Selesnya Sanctuary:1551 +Grove of the Burnwillows:1547 +Chronicler of Heroes:1546 +Glimpse the Unthinkable:1543 +Manakin:1537 +Riverwheel Aerialists:1531 +Guardian Idol:1525 +Assault Formation:1520 +Graven Cairns:1520 +Mer-Ek Nightblade:1519 +Stalwart Aven:1518 +Netcaster Spider:1516 +Angelic Accord:1514 +Doomed Traveler:1514 +Thrill-Kill Assassin:1514 +Distortion Strike:1511 +Azorius Chancery:1509 +Skywise Teachings:1503 +Borderland Marauder:1497 +Sustainer of the Realm:1495 +Furnace Whelp:1494 +Sultai Flayer:1493 +Ivy Elemental:1490 +Darksteel Axe:1487 +Gruul Turf:1486 +Path of Bravery:1485 +Wight of Precinct Six:1480 +Dissolve:1477 +Doorkeeper:1476 +Evolving Wilds:1472 +Keldon Halberdier:1468 +Foul-Tongue Invocation:1465 +Durkwood Baloth:1462 +Nantuko Shaman:1462 +Vent Sentinel:1461 +Scion of Ugin:1460 +Splatter Thug:1459 +Mishra’s Bauble:1458 +Child of Night:1454 +Ojutai’s Breath:1454 +Night of Souls’ Betrayal:1449 +Greater Basilisk:1448 +Butcher’s Glee:1446 +Surreal Memoir:1443 +Magus of the Moon:1438 +Battle-Rattle Shaman:1435 +Guard Duty:1429 +Sandstone Oracle:1426 +Enlarge:1425 +Jace’s Phantasm:1425 +Pristine Talisman:1424 +Duskdale Wurm:1423 +Elusive Spellfist:1423 +Dragon Egg:1421 +Flusterstorm:1421 +Kolaghan Monument:1415 +Balustrade Spy:1410 +Dragon Bell Monk:1407 +Student of Ojutai:1407 +Dragon Tempest:1406 +Angel of Mercy:1405 +Dragonloft Idol:1395 +Sanguine Bond:1394 +Dead Reveler:1393 +Wrench Mind:1393 +Diminish:1392 +Wildsize:1392 +Windfall:1392 +Guided Strike:1391 +Survival Cache:1391 +Lord of the Pit:1390 +Nimbus Maze:1390 +Rakdos Drake:1384 +Phantom Tiger:1381 +River of Tears:1381 +Moonglove Extract:1380 +Timberland Guide:1378 +Trepanation Blade:1378 +Burrenton Forge-Tender:1376 +Virulent Swipe:1376 +Hunting Pack:1367 +Fury Charm:1364 +Infantry Veteran:1360 +Coordinated Assault:1356 +Jaddi Offshoot:1353 +Inspiring Call:1350 +Shriekgeist:1349 +Thought Scour:1345 +Pentarch Ward:1344 +Bogbrew Witch:1343 +Tavern Swindler:1342 +Prey’s Vengeance:1341 +Serum Powder:1340 +Rotfeaster Maggot:1338 +Emerge Unscathed:1322 +Lead the Stampede:1322 +Bala Ged Scorpion:1321 +Dragonlord’s Servant:1321 +Great Teacher’s Decree:1313 +Eternal Thirst:1312 +Hammerhand:1302 +Haunting Hymn:1301 +Festering Newt:1287 +Tormenting Voice:1286 +Earth Elemental:1278 +Benevolent Ancestor:1264 +Trumpet Blast:1253 +Bewilder:1252 +Mark of Mutiny:1245 +Crucible of Fire:1242 +Bubbling Cauldron:1241 +Duress:1236 +Lure:1228 +Mindcrank:1225 +Radiant Fountain:1224 +Disenchant:1215 +Runed Servitor:1213 +Aerial Predation:1196 +Shimmering Grotto:1163 +Nature’s Claim:1137 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/kld.csv b/Mage/src/main/resources/ratings/kld.csv new file mode 100644 index 0000000000..b477e4f360 --- /dev/null +++ b/Mage/src/main/resources/ratings/kld.csv @@ -0,0 +1,274 @@ +Sword of Feast and Famine:100 +Chandra, Torch of Defiance:99 +Skysovereign, Consul Flagship:98 +Noxious Gearhulk:97 +Sword of Fire and Ice:96 +Angel of Invention:95 +Verdurous Gearhulk:94 +Demon of Dark Schemes:94 +Sol Ring:93 +Cataclysmic Gearhulk:92 +Torrential Gearhulk:92 +Nissa, Vital Force:91 +Hangarback Walker:90 +Gonti, Lord of Luxury:90 +Steel Overseer:89 +Skyship Stalker:89 +Pia Nalaar:88 +Sword of Light and Shadow:88 +Smuggler's Copter:87 +Confiscation Coup:87 +Combustible Gearhulk:86 +Oviya Pashiri, Sage Lifecrafte:86 +Mana Crypt:86 +Solemn Simulacrum:85 +Mana Vault:85 +Harnessed Lightning:84 +Aetherstorm Roc:84 +Cultivator's Caravan:84 +Fairgrounds Warden:83 +Rashmi, Eternities Crafter:83 +Dovin Baan:83 +Aerial Responder:82 +Saheeli's Artistry:82 +Bristling Hydra:82 +Master Trinketeer:81 +Welding Sparks:81 +Cultivator of Blades:81 +Aethersquall Ancient:80 +Longtusk Cub:80 +Unlicensed Disintegration:80 +Snare Thopter:79 +Fleetwheel Cruiser:79 +Depala, Pilot Exemplar:79 +Multiform Wonder:79 +Cloudblazer:78 +Filigree Familiar:78 +Gauntlet of Power:78 +Skywhaler's Shot:78 +Renegade Freighter:77 +Fumigate:77 +Chromatic Lantern:77 +Champion's Helm:77 +Revoke Privileges:76 +Peema Outrider:76 +Arborback Stomper:76 +Architect of the Untamed:76 +Tidy Conclusion:75 +Servant of the Conduit:75 +Aetherborn Marauder:75 +Essence Extraction:75 +Saheeli Rai:74 +Chief of the Foundry:74 +Syndicate Trafficker:74 +Lathnu Hellion:74 +Bomat Bazaar Barge:73 +Visionary Augmenter:73 +Foundry Inspector:73 +Wispweaver Angel:73 +Gearshift Ace:73 +Mox Opal:72 +Key to the City:72 +Furious Reprisal:72 +Captured by the Consulate:72 +Scrapheap Scrounger:71 +Aethertorch Renegade:71 +Die Young:71 +Whirler Virtuoso:71 +Animation Module:71 +Æther Vial:70 +Marionette Master:70 +Nature's Way:70 +Chandra's Pyrohelix:70 +Long-Finned Skywhale:70 +Aether Meltdown:69 +Restoration Gearsmith:69 +Empyreal Voyager:69 +Ovalchase Daredevil:69 +Thriving Rhino:69 +Hunt the Weak:68 +Veteran Motorist:68 +Voltaic Brawler:68 +Lightning Greaves:68 +Dynavolt Tower:68 +Scroll Rack:67 +Padeem, Consul of Innovation:67 +Shrewd Negotiation:67 +Propeller Pioneer:67 +Kambal, Consul of Allocation:67 +Malfunction:66 +Brazen Scourge:66 +Chrome Mox:66 +Ballista Charger:66 +Sculpting Steel:66 +Glint-Sleeve Artisan:66 +Gearseeker Serpent:65 +Glint-Nest Crane:65 +Armorcraft Judge:65 +Thriving Grubs:65 +Sky Skiff:65 +Speedway Fanatic:64 +Riparian Tiger:64 +Underhanded Designs:64 +Kujar Seedsculptor:64 +Maulfist Doorbuster:64 +Subtle Strike:64 +Mind's Eye:63 +Impeccable Timing:63 +Spontaneous Artist:63 +Foundry Screecher:63 +Elegant Edgecrafters:63 +Weaponcraft Enthusiast:62 +Contraband Kingpin:62 +Consul's Shieldguard:62 +Glimmer of Genius:62 +Eliminate the Competition:62 +Metalwork Colossus:62 +Aetherworks Marvel:61 +Aviary Mechanic:61 +Aether Hub:61 +Fateful Showdown:61 +Prophetic Prism:61 +Experimental Aviator:60 +Metallurgic Summonings:60 +Aether Theorist:60 +Rings of Brighthearth:60 +Toolcraft Exemplar:60 +Attune with Aether:60 +Thriving Ibex:59 +Narnam Cobra:59 +Quicksmith Genius:59 +Fabrication Module:59 +Lotus Petal:59 +Thriving Rats:58 +Insidious Will:58 +Embraal Bruiser:58 +Maulfist Squad:58 +Dhund Operative:58 +Cloudstone Curio:58 +Salivating Gremlins:57 +Janjeet Sentry:57 +Static Orb:57 +Era of Innovation:57 +Fairgrounds Trumpeter:57 +Wind Drake:56 +Lawless Broker:56 +Ovalchase Dragster:56 +Fragmentize:56 +Blossoming Defense:56 +Built to Last:56 +Territorial Gorger:55 +Skyswirl Harrier:55 +Rush of Vitality:55 +Wild Wanderer:55 +Deadlock Trap:55 +Spireside Infiltrator:54 +Durable Handicraft:54 +Prakhata Pillar-Bug:54 +Dukhara Peafowl:54 +Sage of Shaila's Claim:54 +Incendiary Sabotage:54 +Weldfast Monitor:53 +Trusty Companion:53 +Iron League Steed:53 +Spark of Creativity:53 +Self-Assembler:53 +Make Obsolete:52 +Select for Inspection:52 +Live Fast:52 +Ambitious Aetherborn:52 +Thriving Turtle:52 +Nimble Innovator:51 +Eager Construct:51 +Servo Exhibition:51 +Appetite for the Unnatural:51 +Midnight Oil:51 +Eddytrail Hawk:50 +Æther Tradewinds:50 +Reckless Fireweaver:50 +Weldfast Wingsmith:50 +Ghirapur Guide:50 +Electrostatic Pummeler:49 +Painter's Servant:49 +Bastion Mastodon:49 +Highspire Artisan:49 +Cathartic Reunion:49 +Wayward Giant:48 +Acrobatic Maneuver:48 +Crucible of Worlds:48 +Built to Smash:48 +Prakhata Club Security:47 +Vedalken Blademaster:47 +Panharmonicon:47 +Decoction Module:47 +Inventor's Apprentice:47 +Fretwork Colony:46 +Hightide Hermit:46 +Spirebluff Canal:46 +Botanical Sanctum:46 +Blooming Marsh:45 +Whirlermaker:45 +Concealed Courtyard:45 +Wildest Dreams:45 +Tezzeret's Ambition:44 +Ninth Bridge Patrol:44 +Metalspinner's Puzzleknot:44 +Inspiring Vantage:44 +Ruinous Gremlin:43 +Inventors' Fair:43 +Herald of the Fair:43 +Hazardous Conditions:43 +Glassblower's Puzzleknot:42 +Hijack:42 +Engineered Might:42 +Bomat Courier:42 +Night Market Lookout:41 +Inventor's Goggles:41 +Cowl Prowler:41 +Dukhara Scavenger:41 +Ornamental Courage:40 +Fortuitous Find:40 +Demolition Stomper:40 +Cogworker's Puzzleknot:39 +Creeping Mold:39 +Aradara Express:39 +Minister of Inquiries:38 +Harsh Scrutiny:38 +Accomplished Automaton:38 +Woodweaver's Puzzleknot:37 +Failed Inspection:37 +Diabolic Tutor:37 +Consulate Skygate:36 +Refurbish:36 +Disappearing Act:36 +Pressure Point:35 +Authority of the Consuls:35 +Workshop Assistant:34 +Inspired Charge:34 +Take Down:34 +Renegade Tactics:33 +Larger Than Life:33 +Revolutionary Rebuff:32 +Ceremonious Rejection:32 +Torch Gauntlet:31 +Fireforger's Puzzleknot:31 +Morbid Curiosity:30 +Ghirapur Orrery:30 +Paradoxical Outcome:29 +Curio Vendor:28 +Aetherflux Reservoir:28 +Start Your Engines:27 +Terror of the Fairgrounds:26 +Demolish:26 +Wily Bandar:25 +Consulate Surveillance:24 +Giant Spectacle:23 +Mind Rot:22 +Lost Legacy:21 +Commencement of Festivities:20 +Sequestered Stash:18 +Madcap Experiment:16 +Tasseled Dromedary:14 +Dramatic Reversal:11 +Perpetual Timepiece:6 +Dubious Challenge:0 \ No newline at end of file diff --git a/Mage.Server.Plugins/Mage.Player.AI/src/main/resources/m13.csv b/Mage/src/main/resources/ratings/m13.csv similarity index 100% rename from Mage.Server.Plugins/Mage.Player.AI/src/main/resources/m13.csv rename to Mage/src/main/resources/ratings/m13.csv diff --git a/Mage/src/main/resources/ratings/m19.csv b/Mage/src/main/resources/ratings/m19.csv new file mode 100644 index 0000000000..82164b0866 --- /dev/null +++ b/Mage/src/main/resources/ratings/m19.csv @@ -0,0 +1,260 @@ +Resplendent Angel:2323 +Tezzeret, Artifice Master:2297 +Ajani, Adversary of Tyrants:2268 +Vivien Reid:2257 +Nicol Bolas, the Ravager:2210 +Bone Dragon:2163 +Demanding Dragon:2122 +Murder:2118 +Banefire:2116 +Lathliss, Dragon Queen:2111 +Djinn of Wishes:2092 +Isareth the Awakener:2083 +Demon of Catastrophes:2078 +Leonin Warleader:2036 +Hieromancer's Cage:2031 +Lightning Strike:2030 +Goreclaw, Terror of Qal Sisma:1990 +Angel of the Dawn:1965 +Vine Mare:1962 +Cleansing Nova:1957 +Luminous Bonds:1957 +Hungering Hydra:1956 +Pelakka Wurm:1948 +Palladia-Mors, the Ruiner:1940 +Thorn Lieutenant:1931 +Rabid Bite:1929 +Dismissive Pyromancer:1919 +Lena, Selfless Champion:1914 +Herald of Faith:1911 +Sigiled Sword of Valeron:1906 +Vaevictis Asmadi, the Dire:1898 +Lich's Caress:1895 +Graveyard Marshal:1885 +Pegasus Courser:1878 +Chromium, the Mutable:1875 +Volcanic Dragon:1869 +Mentor of the Meek:1866 +Vampire Sovereign:1860 +Valiant Knight:1855 +Poison-Tip Archer:1851 +Spit Flame:1851 +Windreader Sphinx:1846 +Death Baron:1844 +Skyrider Patrol:1844 +Shock:1841 +Regal Bloodlord:1840 +Ajani's Pridemate:1836 +Psychic Symbiont:1833 +Liliana, Untouched by Death:1825 +Exclusion Mage:1824 +Star-Crowned Stag:1823 +Sleep:1817 +Heroic Reinforcements:1805 +Patient Rebuilding:1804 +Druid of the Cowl:1790 +Horizon Scholar:1784 +Skymarch Bloodletter:1777 +Sarkhan, Fireblood:1776 +Runic Armasaur:1774 +Prodigious Growth:1773 +Take Vengeance:1772 +Aven Wind Mage:1770 +Dryad Greenseeker:1761 +Electrify:1751 +Sarkhan's Unsealing:1743 +Plague Mare:1739 +Gallant Cavalry:1736 +Mystic Archaeologist:1724 +Draconic Disciple:1723 +Essence Scatter:1723 +Vigilant Baloth:1719 +Skeleton Archer:1717 +Arcades, the Strategist:1715 +Militia Bugler:1715 +Departed Deckhand:1713 +Fell Specter:1708 +Strangling Spores:1703 +Bristling Boar:1699 +Snapping Drake:1693 +Enigma Drake:1692 +Knightly Valor:1692 +Gravedigger:1690 +Sai, Master Thopterist:1688 +Aviation Pioneer:1685 +Skyscanner:1683 +Shield Mare:1680 +Meteor Golem:1674 +Sparktongue Dragon:1673 +Brawl-Bash Ogre:1667 +Remorseful Cleric:1666 +Sift:1663 +Fiery Finish:1654 +Transmogrifying Wand:1653 +Aerial Engineer:1649 +Cavalry Drillmaster:1648 +Ghastbark Twins:1645 +Reclamation Sage:1640 +Ajani's Last Stand:1637 +Metamorphic Alteration:1634 +Mirror Image:1633 +Omenspeaker:1633 +Vivien's Invocation:1633 +Dark-Dweller Oracle:1630 +Boggart Brute:1628 +Dwindle:1625 +Goblin Trashmaster:1625 +Make a Stand:1624 +Liliana's Contract:1623 +Giant Spider:1622 +Open the Graves:1621 +Colossal Dreadmaw:1616 +Divination:1615 +Goblin Instigator:1614 +Supreme Phantom:1613 +Chaos Wand:1605 +Rhox Oracle:1603 +Elvish Rejuvenator:1602 +Skilled Animator:1600 +Leonin Vanguard:1597 +Declare Dominance:1596 +Reassembling Skeleton:1595 +Daggerback Basilisk:1591 +Bone to Ash:1585 +Rise from the Grave:1585 +Gift of Paradise:1582 +Titanic Growth:1582 +Arcane Encyclopedia:1581 +Switcheroo:1581 +Doomed Dissenter:1579 +Gigantosaurus:1579 +Siegebreaker Giant:1577 +Child of Night:1575 +Surge Mare:1575 +Cancel:1561 +Volley Veteran:1560 +Epicure of Blood:1559 +Vampire Neonate:1555 +Guttersnipe:1554 +Aethershield Artificer:1553 +Rogue's Gloves:1553 +Macabre Waltz:1550 +Hired Blade:1548 +Salvager of Secrets:1545 +Diamond Mare:1543 +Blood Divination:1542 +Nightmare's Thirst:1542 +Gargoyle Sentinel:1539 +Act of Treason:1538 +Lightning Mare:1534 +Abnormal Endurance:1531 +Inspired Charge:1531 +Gearsmith Guardian:1527 +Dragon Egg:1521 +Anticipate:1519 +Viashino Pyromancer:1519 +Rustwing Falcon:1514 +Two-Headed Zombie:1513 +Blanchwood Armor:1511 +Hostile Minotaur:1510 +Druid of Horns:1508 +Marauder's Axe:1508 +Diregraf Ghoul:1507 +Havoc Devils:1506 +Satyr Enchanter:1505 +Centaur Courser:1502 +Plummet:1497 +Disperse:1494 +Sure Strike:1494 +Inferno Hellion:1491 +Novice Knight:1491 +Oakenform:1483 +Knight of the Tusk:1482 +Fountain of Renewal:1477 +Ravenous Harpy:1474 +Knight's Pledge:1469 +Thornhide Wolves:1463 +Dragon's Hoard:1461 +Daybreak Chaplain:1459 +Ghirapur Guide:1457 +Greenwood Sentinel:1456 +Recollect:1455 +Goblin Motivator:1452 +Talons of Wildwood:1449 +Colossal Majesty:1447 +Gearsmith Prodigy:1441 +Scholar of Stars:1439 +Ajani's Welcome:1433 +Mighty Leap:1432 +Naturalize:1431 +Trusty Packbeast:1431 +Dwarven Priest:1426 +Uncomfortable Chill:1423 +Oreskos Swiftclaw:1422 +Psychic Corrosion:1421 +Loxodon Line Breaker:1419 +Aether Tunnel:1404 +Frilled Sea Serpent:1403 +Infernal Scarring:1403 +Phylactery Lich:1398 +Mind Rot:1396 +Explosive Apparatus:1395 +Amulet of Safekeeping:1390 +Duress:1390 +Magistrate's Scepter:1388 +Suspicious Bookcase:1388 +Invoke the Divine:1385 +Manalith:1384 +Onakke Ogre:1384 +Tormenting Voice:1384 +One with the Machine:1378 +Meandering River:1374 +Lava Axe:1369 +Stone Quarry:1369 +Thud:1368 +Field Creeper:1367 +Rupture Spire:1366 +Elvish Clancaller:1365 +Wall of Mist:1363 +Suncleanser:1357 +Highland Game:1352 +Walking Corpse:1352 +Fire Elemental:1351 +Tectonic Rift:1348 +Totally Lost:1348 +Woodland Stream:1346 +Trumpet Blast:1339 +Millstone:1329 +Crash Through:1327 +Bogstomper:1326 +Aegis of the Heavens:1323 +Forsaken Sanctuary:1323 +Apex of Power:1307 +Tranquil Expanse:1304 +Cinder Barrens:1296 +Infernal Reckoning:1294 +Revitalize:1293 +Wall of Vines:1292 +Detection Tower:1283 +Timber Gorge:1282 +Submerged Boneyard:1277 +Mistcaller:1273 +Ghostform:1272 +Catalyst Elemental:1268 +Omniscience:1267 +Tolarian Scholar:1267 +Stitcher's Supplier:1263 +Desecrated Tomb:1258 +Scapeshift:1251 +Sovereign's Bite:1250 +Highland Lake:1245 +Infectious Horror:1241 +Doublecast:1240 +Fraying Omnipotence:1220 +Crucible of Worlds:1209 +Root Snare:1201 +Smelt:1199 +Reliquary Tower:1197 +Foul Orchard:1190 +Isolate:1139 +Alpine Moon:1068 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/mm3.csv b/Mage/src/main/resources/ratings/mm3.csv new file mode 100644 index 0000000000..3d175cd059 --- /dev/null +++ b/Mage/src/main/resources/ratings/mm3.csv @@ -0,0 +1,249 @@ +Jace, the Mind Sculptor:2196 +Master of the Wild Hunt:2148 +Lightning Bolt:2107 +Swords to Plowshares:2060 +Vendilion Clique:2058 +Ravenous Chupacabra:2057 +Courser of Kruphix:1981 +Reef Worm:1962 +Vindicate:1961 +Pillory of the Sleepless:1926 +Akroma, Angel of Fury:1923 +Gisela, Blade of Goldnight:1918 +Akroma, Angel of Wrath:1913 +Animar, Soul of Elements:1902 +Murder:1900 +Ruric Thar, the Unbowed:1896 +Protean Hulk:1894 +Pacifism:1888 +Akroma’s Vengeance:1885 +Murder of Crows:1885 +Phyrexian Obliterator:1882 +Rancor:1864 +Vesuvan Shapeshifter:1858 +Niv-Mizzet, the Firemind:1854 +Shadowmage Infiltrator:1854 +Fiend Hunter:1844 +Pernicious Deed:1841 +Thalia, Guardian of Thraben:1829 +Living Death:1827 +Man-o’-War:1827 +Elvish Piper:1825 +Imperial Recruiter:1810 +Sundering Titan:1806 +Decree of Justice:1803 +Prossh, Skyraider of Kher:1803 +Cloudblazer:1798 +Laquatus’s Champion:1795 +Darien, King of Kjeldor:1787 +Grenzo, Dungeon Warden:1787 +Pyroclasm:1787 +Brion Stoutarm:1786 +Utopia Sprawl:1785 +Counterspell:1772 +Coalition Relic:1765 +Disfigure:1755 +Kongming, “Sleeping Dragon”:1752 +Spikeshot Goblin:1752 +Blightning:1750 +Arbor Elf:1748 +Bident of Thassa:1743 +Hell’s Caretaker:1739 +Cultivate:1728 +Kindle:1726 +Luminarch Ascension:1719 +Fallen Angel:1718 +Krosan Tusker:1718 +Promise of Bunrei:1713 +Squadron Hawk:1712 +Mystic Snake:1711 +Horseshoe Crab:1707 +Ensnaring Bridge:1706 +Lorescale Coatl:1702 +Nicol Bolas:1702 +Boros Charm:1701 +Treasure Keeper:1701 +Undead Gladiator:1699 +Baloth Null:1698 +Chandra’s Outrage:1691 +Notion Thief:1691 +Merfolk Looter:1689 +Willbender:1689 +Azusa, Lost but Seeking:1686 +Quicksilver Dagger:1686 +Armageddon:1683 +Dusk Legion Zealot:1678 +Zombify:1678 +Urbis Protector:1676 +Rishadan Port:1673 +Blue Sun’s Zenith:1672 +Mesmeric Fiend:1669 +Chalice of the Void:1668 +Zulaport Cutthroat:1662 +Epic Confrontation:1658 +Exclude:1658 +Eidolon of the Great Revel:1655 +Nyx-Fleece Ram:1653 +Diabolic Edict:1651 +Brainstorm:1648 +Magus of the Wheel:1648 +Zada, Hedron Grinder:1645 +Court Hussar:1638 +Sift:1638 +Iwamori of the Open Fist:1637 +Twisted Abomination:1633 +Izzet Chemister:1632 +Ire Shaman:1629 +Kavu Predator:1628 +Street Wraith:1628 +Dauntless Cathar:1625 +Cloudshift:1622 +Mystic of the Hidden Way:1622 +Summoner’s Pact:1622 +Ball Lightning:1621 +Skeletonize:1620 +Ruthless Ripper:1614 +Hordeling Outburst:1609 +Path of Peace:1609 +Loyal Sentry:1607 +Eladamri’s Call:1606 +Mishra’s Factory:1604 +Ash Barrens:1602 +Griffin Protector:1591 +Myriad Landscape:1588 +Hanna, Ship’s Navigator:1586 +Flash:1585 +Prophetic Prism:1585 +Unearth:1584 +Enthralling Victor:1583 +Freed from the Real:1581 +Fathom Seer:1578 +Sai of the Shinobi:1578 +Ancient Craving:1577 +Bloodhunter Bat:1577 +Invigorate:1576 +Watchwolf:1575 +Mogg Flunkies:1571 +Vessel of Nascency:1571 +Whitemane Lion:1571 +Swiftfoot Boots:1570 +Plague Wind:1569 +Perilous Myr:1568 +Karona’s Zealot:1567 +Geist of the Moors:1563 +Jalira, Master Polymorphist:1563 +Cascade Bluffs:1560 +Elvish Aberration:1560 +Kavu Climber:1555 +Thresher Lizard:1555 +Horror of the Broken Lands:1551 +Ainok Survivalist:1549 +Genju of the Falls:1549 +Frenzied Goblin:1547 +Pyre Hound:1545 +Stangg:1544 +Twilight Mire:1544 +Broodhatch Nantuko:1542 +Kor Firewalker:1542 +Ratcatcher:1542 +Presence of Gond:1541 +Noble Templar:1539 +Brine Elemental:1537 +Death’s-Head Buzzard:1537 +Fierce Empath:1537 +Timberpack Wolf:1537 +Skirk Commando:1536 +Ghost Ship:1535 +Ember Weaver:1533 +Pact of Negation:1531 +Shoreline Ranger:1531 +Woolly Loxodon:1526 +Curiosity:1525 +Gods Willing:1523 +Deadly Designs:1521 +Phyrexian Ghoul:1519 +Giant Growth:1518 +Fortune Thief:1517 +Genju of the Spires:1517 +Angelic Page:1516 +Nettle Sentinel:1516 +Wildheart Invoker:1514 +Ambassador Oak:1513 +Nezumi Cutthroat:1511 +Knight of the Skyward Eye:1510 +Dark Ritual:1509 +Supernatural Stamina:1509 +Flooded Grove:1503 +Ordeal of Heliod:1503 +Fetid Heath:1500 +Accumulated Knowledge:1498 +Balduvian Horde:1497 +Vampire Lacerator:1491 +Chartooth Cougar:1487 +Lunarch Mantle:1487 +Pendelhaven:1487 +Doomsday:1486 +Colossal Dreadmaw:1485 +Krosan Colossus:1483 +Retraction Helix:1473 +Arcane Denial:1472 +Quicksand:1472 +Fencing Ace:1470 +Goblin War Drums:1467 +Self-Assembler:1463 +Rugged Prairie:1461 +Caustic Tar:1459 +Erg Raiders:1458 +Simian Spirit Guide:1458 +Regrowth:1454 +Mikokoro, Center of the Sea:1450 +Returned Phalanx:1449 +Cursecatcher:1445 +Tree of Redemption:1445 +Soulbright Flamekin:1444 +Primal Clay:1443 +Uncaged Fury:1443 +Will-o’-the-Wisp:1443 +Browbeat:1434 +Heavy Arbalest:1430 +Echoing Courage:1429 +Blood Moon:1425 +Choking Tethers:1424 +Stampede Driver:1422 +Crimson Mage:1421 +Relentless Rats:1421 +Living Wish:1420 +Totally Lost:1418 +Humble Defector:1417 +Ihsan’s Shade:1417 +Zoetic Cavern:1412 +Act of Treason:1405 +Savannah Lions:1404 +Coralhelm Guide:1398 +Trumpet Blast:1397 +Twisted Image:1397 +Dragon’s Eye Savants:1392 +Blue Elemental Blast:1385 +Ancient Stirrings:1377 +Phantasmal Bear:1374 +Rest in Peace:1373 +Dirge of Dread:1372 +Red Elemental Blast:1361 +Triskaidekaphobia:1361 +Cinder Storm:1352 +Auramancer:1346 +Haunted Fengraf:1343 +Strionic Resonator:1342 +Act of Heroism:1341 +Borrowing 100,000 Arrows:1338 +Jackal Pup:1337 +Valor in Akros:1337 +Nihil Spellbomb:1316 +Assembly-Worker:1301 +Pillage:1300 +Disenchant:1271 +Renewed Faith:1250 +Plummet:1238 +Congregate:1218 +Lull:1212 +Conflux:1208 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/rix.csv b/Mage/src/main/resources/ratings/rix.csv new file mode 100644 index 0000000000..4d56154087 --- /dev/null +++ b/Mage/src/main/resources/ratings/rix.csv @@ -0,0 +1,191 @@ +Rekindling Phoenix:2418 +Tetzimoc, Primal Death:2401 +Ravenous Chupacabra:2290 +Twilight Prophet:2282 +Etali, Primal Storm:2192 +Angrath, the Flame-Chained:2180 +The Immortal Sun:2168 +Profane Procession:2155 +Jadelight Ranger:2143 +Ghalta, Primal Hunger:2131 +Tendershoot Dryad:2121 +Bishop of Binding:2103 +Kumena, Tyrant of Orazca:2098 +Dire Fleet Poisoner:2094 +Trapjaw Tyrant:2087 +Bombard:2052 +Moment of Craving:2039 +Huatli, Radiant Champion:2029 +Hadana’s Climb:2019 +Reaver Ambush:2001 +Warkite Marauder:2001 +Champion of Dusk:2000 +Baffling End:1990 +Luminous Bonds:1970 +Impale:1966 +Golden Demise:1946 +Journey to Eternity:1941 +Crested Herdcaller:1936 +Azor, the Lawbringer:1914 +Thrashing Brontodon:1908 +Raging Regisaur:1902 +Zacama, Primal Calamity:1901 +Legion Lieutenant:1898 +Deeproot Elite:1893 +Sadistic Skymarcher:1893 +Needletooth Raptor:1889 +Elenda, the Dusk Rose:1888 +Dire Fleet Daredevil:1883 +Merfolk Mistbinder:1881 +Hunt the Weak:1839 +Forerunner of the Legion:1828 +Zetalpa, Primal Dawn:1820 +Golden Guardian:1819 +Radiant Destiny:1816 +Vona’s Hunger:1798 +Polyraptor:1793 +Tilonalli’s Summoner:1792 +Swift Warden:1774 +Slaughter the Strong:1767 +Protean Raider:1764 +Waterknot:1762 +Seafloor Oracle:1761 +Forerunner of the Empire:1760 +Divine Verdict:1759 +Reckless Rage:1758 +Dusk Legion Zealot:1755 +Squire’s Devotion:1754 +Temple Altisaur:1753 +Forerunner of the Heralds:1749 +Deadeye Brawler:1748 +Nezahal, Primal Tide:1742 +Captain’s Hook:1722 +Curious Obsession:1720 +Charging Tuskodon:1717 +Azor’s Gateway:1706 +Dire Fleet Neckbreaker:1703 +Wayward Swordtooth:1699 +Resplendent Griffin:1698 +Jungle Creeper:1693 +Siegehorn Ceratops:1690 +Kitesail Corsair:1689 +Martyr of Dusk:1689 +Exultant Skymarcher:1686 +Sailor of Means:1683 +Silvergill Adept:1680 +Atzocan Seer:1675 +Jungleborn Pioneer:1674 +Path of Discovery:1669 +Skymarcher Aspirant:1667 +Siren Reaver:1661 +Paladin of Atonement:1655 +Forerunner of the Coalition:1652 +Mutiny:1648 +Storm Fleet Sprinter:1638 +Relentless Raptor:1634 +Everdawn Champion:1625 +Goblin Trailblazer:1622 +Storm Fleet Swashbuckler:1606 +Spire Winder:1600 +Strength of the Pack:1594 +Secrets of the Golden City:1593 +Mausoleum Harpy:1586 +Slippery Scoundrel:1585 +Colossal Dreadmaw:1584 +Knight of the Stampede:1584 +Dusk Charger:1579 +Expel from Orazca:1578 +Oathsworn Vampire:1578 +Overgrown Armasaur:1576 +Daring Buccaneer:1562 +Deadeye Rig-Hauler:1557 +Sun-Crested Pterodon:1557 +Soul of the Rapids:1549 +Cherished Hatchling:1547 +Crashing Tide:1538 +Recover:1538 +Arch of Orazca:1537 +Majestic Heliopterus:1531 +Sanguine Glorifier:1525 +Form of the Dinosaur:1523 +Pride of Conquerors:1523 +Famished Paladin:1516 +Moment of Triumph:1515 +Silverclad Ferocidons:1511 +Frilled Deathspitter:1509 +Kumena’s Awakening:1505 +Snubhorn Sentry:1504 +Voracious Vampire:1504 +Fathom Fleet Boarder:1501 +Buccaneer’s Bravado:1492 +Thunderherd Migration:1487 +Legion Conquistador:1483 +See Red:1481 +Riverwise Augur:1478 +Cacophodon:1477 +Tomb Robber:1475 +Giltgrove Stalker:1472 +Swaggering Corsair:1472 +Evolving Wilds:1463 +Dinosaur Hunter:1461 +World Shaper:1452 +Path of Mettle:1447 +Hardy Veteran:1446 +Mist-Cloaked Herald:1443 +Fanatical Firebrand:1442 +Jadecraft Artisan:1440 +Stampeding Horncrest:1439 +Admiral’s Order:1436 +Timestream Navigator:1433 +Brazen Freebooter:1427 +Imperial Ceratops:1415 +Aggressive Urge:1413 +Traveler’s Amulet:1412 +Grasping Scoundrel:1403 +Jade Bearer:1384 +Aquatic Incursion:1375 +Shake the Foundations:1374 +Vampire Revenant:1368 +Orazca Raptor:1363 +Sun Sentinel:1362 +Hornswoggle:1350 +Mastermind’s Acquisition:1344 +Raptor Companion:1340 +Sea Legs:1332 +Sun-Collared Raptor:1322 +Tilonalli’s Crown:1318 +Gleaming Barrier:1307 +Enter the Unknown:1301 +Storm the Vault:1297 +Crafty Cutpurse:1291 +Pitiless Plunderer:1288 +Forsaken Sanctuary:1281 +Pirate’s Pillage:1274 +Arterial Flow:1255 +Woodland Stream:1246 +Orazca Frillback:1244 +Dead Man’s Chest:1233 +River Darter:1233 +Naturalize:1224 +Cleansing Ray:1203 +Highland Lake:1199 +Strider Harness:1198 +Negate:1195 +Stone Quarry:1192 +Dark Inquiry:1187 +Release to the Wind:1165 +Plummet:1160 +Foul Orchard:1146 +Orazca Relic:1123 +Flood of Recollection:1121 +Canal Monitor:1094 +Blazing Hope:1069 +Brass’s Bounty:1064 +Sworn Guardian:1060 +Blood Sun:1059 +Gruesome Fate:1036 +Awakened Amalgam:1017 +Induced Amnesia:1003 +Silent Gravestone:968 +Sphinx’s Decree:961 +Shatter:907 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/rna.csv b/Mage/src/main/resources/ratings/rna.csv new file mode 100644 index 0000000000..620b2081c3 --- /dev/null +++ b/Mage/src/main/resources/ratings/rna.csv @@ -0,0 +1,254 @@ +Biogenic Ooze:1000 +Angel of Grace:986 +Rakdos, the Showstopper:974 +Skarrgan Hellkite:964 +Spawn of Mayhem:954 +Seraph of the Scales:945 +Hydroid Krasis:937 +Domri, Chaos Bringer:929 +Ethereal Absolution:922 +Lawmage's Binding:915 +Electrodominance:908 +Sphinx of Foresight:902 +Ravager Wurm:896 +Bedevil:891 +Mesmerizing Benthid:885 +Zegana, Utopian Speaker:880 +Thrash // Threat:875 +Deputy of Detention:870 +Mortify:865 +Judith, the Scourge Diva:861 +Gruul Spellbreaker:856 +Pestilent Spirit:852 +Dovin, Grand Arbiter:848 +Warrant // Warden:843 +Skewer the Critics:839 +Sunder Shaman:836 +Sharktocrab:832 +Biomancer's Familiar:828 +Prime Speaker Vannifar:824 +Kaya's Wrath:821 +Incubation Druid:817 +Theater of Horrors:814 +Frilled Mystic:810 +Get the Point:807 +Nikya of the Old Ways:804 +Combine Guildmage:801 +Rix Maadi Reveler:797 +Growth-Chamber Guardian:794 +Ministrant of Obligation:791 +Frenzied Arynx:788 +Teysa Karlov:785 +Bedeck // Bedazzle:782 +Precognitive Perception:779 +Final Payment:776 +Rhythm of the Wild:774 +Captive Audience:771 +End-Raze Forerunners:768 +Lumbering Battlement:765 +Rakdos Firewheeler:763 +Senate Guildmage:760 +Trollbred Guardian:757 +Galloping Lizrog:755 +Grotesque Demise:752 +Skatewing Spy:749 +Azorius Skyguard:747 +Sphinx of New Prahv:744 +Cry of the Carnarium:742 +Dagger Caster:739 +Immolation Shaman:737 +Orzhov Enforcer:735 +Consecrate // Consume:732 +Aeromunculus:730 +Windstorm Drake:727 +Clear the Stage:725 +Depose // Deploy:723 +Revival // Revenge:720 +Mass Manipulation:718 +Senate Griffin:716 +Biogenic Upgrade:713 +Savage Smash:711 +Unbreakable Formation:709 +Applied Biomancy:707 +Pitiless Pontiff:705 +Hero of Precinct One:702 +Summary Judgment:700 +Gyre Engineer:698 +Benthic Biomancer:696 +Cult Guildmage:694 +Zhur-Taa Goblin:691 +Spirit of the Spires:689 +Collision // Colossus:687 +Pteramander:685 +Flames of the Raze-Boar:683 +Carnival // Carnage:681 +Grasping Thrull:679 +Hackrobat:677 +Clan Guildmage:675 +Imperious Oligarch:673 +Scorchmark:670 +Syndicate Guildmage:668 +Gatebreaker Ram:666 +Rampaging Rendhorn:664 +Forbidding Spirit:662 +Tithe Taker:660 +Fireblade Artist:658 +Azorius Knight-Arbiter:656 +Simic Ascendancy:654 +Guardian Project:652 +Enraged Ceratok:650 +Bolrac-Clan Crusher:648 +Consign to the Pit:646 +Repudiate // Replicate:644 +Gruul Beastmaster:642 +Gutterbones:640 +Spire Mangler:638 +Titanic Brawl:636 +Dovin's Acuity:634 +Incubation // Incongruity:633 +Sky Tether:631 +Basilica Bell-Haunt:629 +Amplifire:627 +Essence Capture:625 +Arrester's Admonition:623 +Chillbringer:621 +Clamor Shaman:619 +Syndicate Messenger:617 +Rubblebelt Runner:615 +Faerie Duelist:613 +Burning-Tree Vandal:611 +Sauroform Hybrid:609 +Undercity's Embrace:607 +Sphinx of the Guildpact:605 +Growth Spiral:603 +Orzhov Racketeers:602 +Dead Revels:600 +Vindictive Vampire:598 +Priest of Forgotten Gods:596 +Silhana Wayfinder:594 +Rumbling Ruin:592 +Skitter Eel:590 +Wrecking Beast:588 +Gateway Sneak:586 +Sage's Row Savant:584 +Gate Colossus:582 +Swirling Torrent:580 +Light Up the Stage:578 +Senate Courier:576 +Sentinel's Mark:574 +Ghor-Clan Wrecker:572 +Angelic Exaltation:571 +Blade Juggler:569 +Bring to Trial:567 +Code of Constraint:565 +Eyes Everywhere:563 +Gravel-Hide Goblin:561 +Absorb:559 +Sphinx's Insight:557 +Bladebrand:555 +Hallowed Fountain:553 +Verity Circle:551 +Archway Angel:549 +Breeding Pool:547 +Twilight Panther:545 +Resolute Watchdog:543 +Gates Ablaze:541 +Rakdos Roustabout:539 +Rubblebelt Recluse:537 +Mammoth Spider:535 +Knight of the Last Breath:533 +Territorial Boar:531 +Glass of the Guildpact:529 +Undercity Scavenger:527 +Blood Crypt:525 +Macabre Mockery:522 +Steeple Creeper:520 +Impassioned Orator:518 +Arrester's Zeal:516 +Kaya, Orzhov Usurper:514 +Rubble Slinger:512 +Emergency Powers:510 +Plague Wight:508 +Noxious Groodion:506 +Civic Stalwart:503 +Vizkopa Vampire:501 +Rally to Battle:499 +Gift of Strength:497 +Stomping Ground:495 +High Alert:492 +Cindervines:490 +Goblin Gathering:488 +Storm Strike:486 +Shimmer of Possibility:483 +Bloodmist Infiltrator:481 +Smelt-Ward Ignus:479 +Footlight Fiend:477 +Godless Shrine:474 +Rakdos Trumpeter:472 +Slimebind:469 +Debtors' Transport:467 +Spear Spewer:465 +Stony Strength:462 +Mirror March:460 +Carrion Imp:457 +Tome of the Guildpact:455 +Open the Gates:452 +Concordia Pegasus:450 +Ill-Gotten Inheritance:447 +Quench:445 +Sylvan Brushstrider:442 +Tenth District Veteran:439 +Lavinia, Azorius Renegade:437 +Drill Bit:434 +Watchful Giant:431 +Scuttlegator:428 +Regenesis:426 +Humongulus:423 +Spikewheel Acrobat:420 +Axebane Beast:417 +Haazda Officer:414 +Prying Eyes:411 +Knight of Sorrows:408 +Plaza of Harmony:405 +Rafter Demon:402 +Saruli Caretaker:399 +Awaken the Erstwhile:396 +Thought Collapse:392 +Wilderness Reclamation:389 +Act of Treason:386 +Smothering Tithe:382 +Tin Street Dodger:379 +Catacomb Crocodile:375 +Sagittars' Volley:371 +Cavalcade of Calamity:368 +Azorius Guildgate:364 +Orzhov Guildgate:360 +Bankrupt in Blood:356 +Persistent Petitioners:352 +Gateway Plaza:348 +Simic Guildgate:343 +Thirsting Shade:339 +Justiciar's Portal:334 +Font of Agonies:329 +Tower Defense:325 +Wall of Lost Thoughts:320 +Rakdos Guildgate:314 +Feral Maaka:309 +Burn Bright:303 +Gruul Guildgate:297 +Expose to Daylight:291 +Gruul Locket:285 +Azorius Locket:278 +Prowling Caracal:271 +Simic Locket:263 +Coral Commando:255 +Screaming Shield:246 +Junktroller:236 +Scrabbling Claws:226 +Orzhov Locket:214 +Rampage of the Clans:201 +Deface:186 +Clear the Mind:168 +Rakdos Locket:145 +Rubble Reading:115 +Root Snare:66 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/setsWithRatings.csv b/Mage/src/main/resources/ratings/setsWithRatings.csv new file mode 100644 index 0000000000..172ed6537e --- /dev/null +++ b/Mage/src/main/resources/ratings/setsWithRatings.csv @@ -0,0 +1,19 @@ +# this file specifies which sets have set files. +# each line must be exactly the 3 letter expansion code. this corresponds to a csv resource file in the same directory +# The .csv files have a strict format: +# each line must be: +# cardname : integer rating +# each set's ratings are post-processed to have a normalized score [1..100], so the files don't need to have the same rating system. +# I created the first few files with draftaholicsanonymous but you can use any integer rating system you want +grn +m19 +dom +rix +xln +hou +akh +aer +kld +mm3 +ima +m13 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/uma.csv b/Mage/src/main/resources/ratings/uma.csv new file mode 100644 index 0000000000..35b7309598 --- /dev/null +++ b/Mage/src/main/resources/ratings/uma.csv @@ -0,0 +1,254 @@ +Bitterblossom:1000 +Mana Vault:986 +Liliana of the Veil:974 +Karn Liberated:964 +Mikaeus, the Unhallowed:954 +Sublime Archangel:945 +Sigarda, Host of Herons:937 +Noble Hierarch:929 +Shriekmaw:922 +Snapcaster Mage:915 +Glen Elendra Archmage:908 +Balefire Dragon:902 +Vengevine:896 +Demonic Tutor:891 +Maelstrom Pulse:885 +Celestial Colonnade:880 +Tasigur, the Golden Fang:875 +Reveillark:870 +Lord of Extinction:865 +Eternal Witness:861 +Tarmogoyf:856 +Woodfall Primus:852 +Eldrazi Conscription:848 +Kitchen Finks:843 +Temporal Manipulation:839 +Fiend Hunter:836 +Dig Through Time:832 +Talrand, Sky Summoner:828 +Chainer's Edict:824 +Faith's Fetters:821 +Creeping Tar Pit:817 +Fire // Ice:814 +Raging Ravine:810 +Reanimate:807 +Platinum Emperion:804 +Moan of the Unhallowed:801 +Fauna Shaman:797 +Sovereigns of Lost Alara:794 +Ancient Tomb:791 +Spider Spawning:788 +Kozilek, Butcher of Truth:785 +Urban Evolution:782 +Young Pyromancer:779 +Angel of Despair:776 +Last Gasp:774 +Rolling Temblor:771 +All Is Dust:768 +Devoted Druid:765 +Fiery Temper:763 +Murderous Redcap:760 +Leovold, Emissary of Trest:757 +Wall of Reverence:755 +Golgari Grave-Troll:752 +Unburial Rites:749 +Mahamoti Djinn:747 +Ulamog, the Infinite Gyre:744 +Stirring Wildwood:742 +Swift Reckoning:739 +Pattern of Rebirth:737 +Dimir Guildmage:735 +Warleader's Helix:732 +Thermo-Alchemist:730 +Penumbra Wurm:727 +Unholy Hunger:725 +Through the Breach:723 +Gurmag Angler:720 +Emancipation Angel:718 +Sleight of Hand:716 +Wild Mongrel:713 +Boar Umbra:711 +Reckless Wurm:709 +Kodama's Reach:707 +Magmaw:705 +Phalanx Leader:702 +Vengeful Rebirth:700 +Emrakul, the Aeons Torn:698 +Daybreak Coronet:696 +Treasure Cruise:694 +Rise from the Tides:691 +Firewing Phoenix:689 +Travel Preparations:687 +Satyr Wayfinder:685 +Engineered Explosives:683 +Entomb:681 +Hero of Iroas:679 +Reya Dawnbringer:677 +Soul's Fire:675 +Become Immense:673 +Containment Priest:670 +Archaeomancer:668 +Slum Reaper:666 +Forbidden Alchemy:664 +Stingerfling Spider:662 +Anger:660 +Artisan of Kozilek:658 +Garna, the Bloodflame:656 +Lavaclaw Reaches:654 +Think Twice:652 +Vexing Devil:650 +Shirei, Shizo's Caretaker:648 +Magus of the Bazaar:646 +Snake Umbra:644 +Ulamog's Crusher:642 +Aethersnipe:640 +Iridescent Drake:638 +Hero of Leina Tower:636 +Mad Prophet:634 +Blast of Genius:633 +Brazen Scourge:631 +Stitched Drake:629 +Faithless Looting:627 +Squee, Goblin Nabob:625 +Ghoulsteed:623 +Resurrection:621 +Life from the Loam:619 +Safehold Elite:617 +Canker Abomination:615 +Flight of Fancy:613 +Frantic Search:611 +Rune Snag:609 +Sigil of the New Dawn:607 +Circular Logic:605 +Hooting Mandrills:603 +Just the Wind:602 +Gaddock Teeg:600 +Wickerbough Elder:598 +Seismic Assault:596 +Deranged Assistant:594 +Marang River Prowler:592 +Rally the Peasants:590 +Wingsteed Rider:588 +Walker of the Grove:586 +Gods Willing:584 +Basking Rootwalla:582 +Scuzzback Marauders:580 +Slippery Bogle:578 +Spider Umbra:576 +Boneyard Wurm:574 +Skywing Aven:572 +Death Denied:571 +Sparkspitter:569 +Staunch-Hearted Warrior:567 +Goryo's Vengeance:565 +Icatian Crier:563 +Golgari Thug:561 +Lotus-Eye Mystics:559 +Conflagrate:557 +Seize the Day:555 +Miraculous Recovery:553 +Molten Birth:551 +Fulminator Mage:549 +Prismatic Lens:547 +Karakas:545 +Dreamscape Artist:543 +Eel Umbra:541 +Skyspear Cavalry:539 +Cathodion:537 +Prey Upon:535 +Grave Scrabbler:533 +Brawn:531 +Wild Hunger:529 +Apprentice Necromancer:527 +Heliod's Pilgrim:525 +Olivia's Dragoon:522 +Phyrexian Tower:520 +Generator Servant:518 +Cavern of Souls:516 +Ghoulcaller's Accomplice:514 +Plumeveil:512 +Pulse of Murasa:510 +Foil:508 +Dark Depths:506 +Hissing Iguanar:503 +Visions of Beyond:501 +Mystic Retrieval:499 +Golgari Charm:497 +Desolate Lighthouse:495 +Disrupting Shoal:492 +Mammoth Umbra:490 +Double Cleave:488 +Verdant Eidolon:486 +Living Lore:483 +Reviving Vapors:481 +Whirlwind Adept:479 +Hyena Umbra:477 +Tethmos High Priest:474 +Countersquall:472 +Terramorphic Expanse:469 +Crow of Dark Tidings:467 +Miming Slime:465 +Ancestor's Chosen:462 +Spirit Cairn:460 +Unstable Mutation:457 +Urborg, Tomb of Yawgmoth:455 +Twins of Maurer Estate:452 +Malevolent Whispers:450 +Shed Weakness:447 +Shielding Plax:445 +Golgari Brownscale:442 +Buried Alive:439 +Arena Athlete:437 +Dawn Charm:434 +Ronom Unicorn:431 +Fecundity:428 +Gamble:426 +Akroan Crusader:423 +Bloodflow Connoisseur:420 +Myr Servitor:417 +Fume Spitter:414 +Sultai Skullkeeper:411 +Rakdos Shred-Freak:408 +Undying Rage:405 +Raid Bombardment:402 +Turn to Mist:399 +Lava Spike:396 +Wandering Champion:392 +Desperate Ritual:389 +Martyr of Sands:386 +Spoils of the Vault:382 +Phyrexian Altar:379 +Conviction:375 +Thespian's Stage:371 +Angelic Renewal:368 +Furnace Celebration:364 +Laboratory Maniac:360 +Reckless Charge:356 +Stitcher's Apprentice:352 +Grave Strength:348 +Runed Halo:343 +Dark Dabbling:339 +Crushing Canopy:334 +Flagstones of Trokair:329 +Rogue's Passage:325 +Mark of the Vampire:320 +Vessel of Endless Rest:314 +Beckon Apparition:309 +Offalsnout:303 +Songs of the Damned:297 +Appetite for Brains:291 +Mage-Ring Network:285 +Nightbird's Clutches:278 +Bridge from Below:271 +Patchwork Gnomes:263 +Ingot Chewer:255 +Sanitarium Skeleton:246 +Mistveil Plains:236 +Repel the Darkness:226 +Back to Basics:214 +Dakmor Salvage:201 +Groundskeeper:186 +Defy Gravity:168 +Nourishing Shoal:145 +Stream of Consciousness:115 +Heap Doll:66 \ No newline at end of file diff --git a/Mage/src/main/resources/ratings/xln.csv b/Mage/src/main/resources/ratings/xln.csv new file mode 100644 index 0000000000..3e92060d88 --- /dev/null +++ b/Mage/src/main/resources/ratings/xln.csv @@ -0,0 +1,259 @@ +Vraska, Relic Seeker:2381 +Hostage Taker:2336 +Carnage Tyrant:2332 +Regisaur Alpha:2276 +Ripjaw Raptor:2228 +Captivating Crew:2225 +Vraska’s Contempt:2214 +Vona, Butcher of Magan:2192 +Huatli, Warrior Poet:2173 +Repeating Barrage:2144 +Charging Monstrosaur:2133 +Lightning Strike:2122 +Walk the Plank:2096 +Ixalan’s Binding:2083 +Burning Sun’s Avatar:2068 +Mavren Fein, Dusk Apostle:2061 +Settle the Wreckage:2057 +Waker of the Wilds:2033 +Kinjalli’s Sunwing:2032 +Sanctum Seeker:2003 +Rampaging Ferocidon:2000 +Legion’s Landing:1999 +Territorial Hammerskull:1990 +Dreamcaller Siren:1983 +Bishop of Rebirth:1975 +Vanquish the Weak:1969 +River’s Rebuke:1967 +Fathom Fleet Captain:1950 +Imperial Aerosaur:1939 +Drover of the Mighty:1932 +Deathgorge Scavenger:1917 +Snapping Sailback:1916 +Shapers of Nature:1913 +Entrancing Melody:1911 +Contract Killing:1910 +Adanto Vanguard:1901 +Air Elemental:1901 +Dire Fleet Ravager:1889 +Merfolk Branchwalker:1889 +Jace, Cunning Castaway:1881 +Savage Stomp:1878 +Kitesail Freebooter:1877 +Raging Swordtooth:1858 +Ruin Raider:1856 +Vance’s Blasting Cannons:1854 +Unfriendly Fire:1844 +Captain Lannery Storm:1843 +Pious Interdiction:1842 +Firecannon Blast:1837 +Ranging Raptors:1835 +Treasure Map:1832 +Sky Terror:1824 +Vanquisher’s Banner:1823 +Watertrap Weaver:1811 +Pirate’s Cutlass:1806 +Emperor’s Vanguard:1805 +Storm Fleet Aerialist:1805 +Tempest Caller:1798 +Daring Saboteur:1795 +Search for Azcanta:1794 +Rowdy Crew:1793 +Seekers’ Squire:1777 +Skulduggery:1773 +Glorifier of Dusk:1757 +Siren Lookout:1757 +One With the Wind:1754 +Admiral Beckett Brass:1752 +Bishop of the Bloodstained:1752 +Wanted Scoundrels:1750 +Pounce:1748 +Jade Guardian:1740 +Vineshaper Mystic:1740 +Skymarch Bloodletter:1739 +Gishath, Sun’s Avatar:1733 +Call to the Feast:1730 +Paladin of the Bloodstained:1729 +Emissary of Sunrise:1725 +Otepec Huntmaster:1719 +Thundering Spineback:1710 +Tishana’s Wayfinder:1707 +Fiery Cannonade:1697 +Verdant Sun’s Avatar:1692 +Dark Nourishment:1682 +Deadeye Tracker:1679 +Siren Stormtamer:1679 +Chart a Course:1674 +Dire Fleet Captain:1673 +Inspiring Cleric:1671 +Bishop’s Soldier:1669 +Deathless Ancient:1669 +Deeproot Warrior:1669 +Tilonalli’s Knight:1669 +Deadeye Plunderers:1664 +Conqueror’s Galleon:1657 +Bright Reprisal:1654 +Shining Aerosaur:1654 +Raptor Hatchling:1653 +Wakening Sun’s Avatar:1651 +Fell Flagship:1649 +Herald of Secret Streams:1645 +Headstrong Brute:1643 +Fathom Fleet Firebrand:1641 +Colossal Dreadmaw:1637 +Vicious Conquistador:1636 +Bloodcrazed Paladin:1635 +Bellowing Aegisaur:1629 +Tishana, Voice of Thunder:1628 +Kopala, Warden of Waves:1626 +New Horizons:1624 +Deadeye Tormentor:1621 +Marauding Looter:1621 +Kumena’s Speaker:1619 +Vampire’s Zeal:1618 +Duskborne Skymarcher:1616 +Ixalli’s Diviner:1616 +Ravenous Daggertooth:1615 +Angrath’s Marauders:1613 +Perilous Voyage:1613 +Slash of Talons:1613 +Shaper Apprentice:1612 +Wildgrowth Walker:1609 +Storm Fleet Spy:1607 +Sailor of Means:1605 +Bonded Horncrest:1600 +Grazing Whiptail:1597 +Thaumatic Compass:1596 +Thrash of Raptors:1594 +Legion’s Judgment:1591 +Queen’s Commission:1590 +Deeproot Champion:1587 +Steadfast Armasaur:1581 +River Heralds’ Boon:1579 +Rigging Runner:1575 +Goring Ceratops:1572 +Skittering Heartstopper:1572 +Storm Fleet Arsonist:1571 +Dire Fleet Hoarder:1569 +Commune with Dinosaurs:1566 +Atzocan Archer:1562 +River Sneak:1562 +Skyblade of the Legion:1560 +Run Aground:1558 +Anointed Deacon:1557 +Pterodon Knight:1557 +Mark of the Vampire:1555 +Fathom Fleet Cutthroat:1552 +Prosperous Pirates:1549 +Shipwreck Looter:1546 +Arguel’s Blood Fast:1536 +Wind Strider:1535 +Legion Conquistador:1533 +Depths of Desire:1531 +Ruthless Knave:1531 +Sunbird’s Invocation:1531 +Growing Rites of Itlimoc:1525 +Lookout’s Dispersal:1525 +Lightning-Rig Crew:1517 +Sure Strike:1517 +Boneyard Parley:1515 +Dusk Legion Dreadnought:1515 +Priest of the Wakening Sun:1514 +Brazen Buccaneers:1513 +Star of Extinction:1513 +Raptor Companion:1511 +Rallying Roar:1505 +Heartless Pillage:1501 +Sleek Schooner:1500 +Fleet Swallower:1498 +Ixalli’s Keeper:1497 +Dive Down:1496 +Sheltering Light:1492 +Sun-Crowned Hunters:1483 +Cobbled Wings:1474 +Dire Fleet Interloper:1473 +Lurking Chupacabra:1465 +Storm Fleet Pyromancer:1463 +Dowsing Dagger:1456 +Shadowed Caravel:1455 +Spike-Tailed Ceratops:1455 +Kinjalli’s Caller:1454 +Deeproot Waters:1452 +Rootbound Crag:1451 +Verdant Rebirth:1451 +Storm Sculptor:1448 +Frenzied Raptor:1446 +Opt:1440 +Jungle Delver:1438 +Sword-Point Diplomacy:1438 +Nest Robber:1436 +Tilonalli’s Skinshifter:1434 +Siren’s Ruse:1433 +Crushing Canopy:1431 +Dinosaur Stampede:1429 +Overflowing Insight:1425 +Swashbuckling:1418 +Crash the Ramparts:1413 +Sunpetal Grove:1412 +Favorable Winds:1406 +Shapers’ Sanctuary:1406 +Queen’s Bay Soldier:1405 +Deadeye Quartermaster:1401 +Queen’s Agent:1397 +Dual Shot:1396 +Pirate’s Prize:1394 +March of the Drowned:1387 +Blossom Dryad:1385 +Drowned Catacomb:1383 +Tocatli Honor Guard:1373 +Dragonskull Summit:1372 +Raiders’ Wake:1371 +Spell Swindle:1368 +Sunrise Seeker:1361 +Desperate Castaways:1342 +Prying Blade:1338 +Sorcerous Spyglass:1334 +Blight Keeper:1330 +Costly Plunder:1310 +Primal Amulet:1306 +Unclaimed Territory:1306 +Fire Shrine Keeper:1301 +Imperial Lancer:1297 +Belligerent Brontodon:1296 +Emergent Growth:1293 +Wily Goblin:1293 +Cancel:1287 +Duress:1286 +Old-Growth Dryads:1282 +Navigator’s Ruin:1273 +Glacial Fortress:1262 +Trove of Temptation:1259 +Pillar of Origins:1252 +Hijack:1236 +Rile:1234 +Revel in Riches:1232 +Headwater Sentries:1225 +Grim Captain’s Call:1214 +Elaborate Firecannon:1209 +Looming Altisaur:1206 +Encampment Keeper:1199 +Slice in Twain:1198 +Spell Pierce:1186 +Makeshift Munitions:1183 +Rummaging Goblin:1182 +Axis of Mortality:1179 +Unknown Shores:1173 +Shore Keeper:1172 +Ancient Brontodon:1165 +Sanguine Sacrament:1162 +Arcane Adaptation:1151 +Ashes of the Abhorrent:1135 +Ritual of Rejuvenation:1102 +Field of Ruin:1097 +Hierophant’s Chalice:1077 +Gilded Sentinel:1035 +Blinding Fog:1033 +Demystify:1023 +Sentinel Totem:998 +Demolish:994 +Spreading Rot:935 \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/exporter/MtgOnlineDeckExporterTest.java b/Mage/src/test/java/mage/cards/decks/exporter/MtgOnlineDeckExporterTest.java new file mode 100644 index 0000000000..7deb0cb70e --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/exporter/MtgOnlineDeckExporterTest.java @@ -0,0 +1,35 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class MtgOnlineDeckExporterTest { + + @Test + public void writeDeck() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeckCardLists deck = new DeckCardLists(); + deck.getCards().add(new DeckCardInfo("Forest", "1", "RNA", 2)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 3)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 5)); // must combine + deck.getCards().add(new DeckCardInfo("Mountain", "3", "RNA", 1)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 2)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 5)); // must combine + deck.getSideboard().add(new DeckCardInfo("Mountain", "2", "RNA", 3)); + DeckExporter exporter = new MtgOnlineDeckExporter(); + exporter.writeDeck(baos, deck); + assertEquals("2 Forest" + System.lineSeparator() + + "8 Plains" + System.lineSeparator() + + "1 Mountain" + System.lineSeparator() + + System.lineSeparator() + + "7 Island" + System.lineSeparator() + + "3 Mountain" + System.lineSeparator(), + baos.toString()); + } +} \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/exporter/XmageDeckExporterTest.java b/Mage/src/test/java/mage/cards/decks/exporter/XmageDeckExporterTest.java new file mode 100644 index 0000000000..f905f63a0e --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/exporter/XmageDeckExporterTest.java @@ -0,0 +1,35 @@ +package mage.cards.decks.exporter; + +import mage.cards.decks.DeckCardInfo; +import mage.cards.decks.DeckCardLists; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.assertEquals; + +public class XmageDeckExporterTest { + + @Test + public void writeDeck() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DeckCardLists deck = new DeckCardLists(); + deck.getCards().add(new DeckCardInfo("Forest", "1", "RNA", 2)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 3)); + deck.getCards().add(new DeckCardInfo("Plains", "2", "RNA", 5)); // must combine + deck.getCards().add(new DeckCardInfo("Mountain", "3", "RNA", 1)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 2)); + deck.getSideboard().add(new DeckCardInfo("Island", "1", "RNA", 5)); // must combine + deck.getSideboard().add(new DeckCardInfo("Mountain", "2", "RNA", 3)); + DeckExporter exporter = new XmageDeckExporter(); + exporter.writeDeck(baos, deck); + assertEquals("2 [RNA:1] Forest" + System.lineSeparator() + + "8 [RNA:2] Plains" + System.lineSeparator() + + "1 [RNA:3] Mountain" + System.lineSeparator() + + "SB: 7 [RNA:1] Island" + System.lineSeparator() + + "SB: 3 [RNA:2] Mountain" + System.lineSeparator(), + baos.toString()); + } + +} \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/importer/CodDeckImportTest.java b/Mage/src/test/java/mage/cards/decks/importer/CodDeckImportTest.java new file mode 100644 index 0000000000..9dd94dfdb8 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/CodDeckImportTest.java @@ -0,0 +1,40 @@ +package mage.cards.decks.importer; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import mage.cards.decks.DeckCardLists; + +public class CodDeckImportTest { + + private static final FakeCardLookup LOOKUP = new FakeCardLookup(false) + .addCard("Forest") + .addCard("Razorverge Thicket") + .addCard("Avacyn's Pilgrim") + .addCard("War Priest of Thune"); + + @Test + public void testImport() { + CodDeckImporter importer = new CodDeckImporter() { + @Override + public CardLookup getCardLookup() { + return LOOKUP; + } + }; + StringBuilder errors = new StringBuilder(); + DeckCardLists deck = importer.importDeck( + "src/test/java/mage/cards/decks/importer/samples/testdeck.cod", errors); + assertEquals("Deck Name", deck.getName()); + + TestDeckChecker.checker() + .addMain("Forest", 12) + .addMain("Razorverge Thicket", 100) + .addMain("Avacyn's Pilgrim", 1) + .addSide("War Priest of Thune", 3) + .verify(deck, 113, 3); + + assertEquals("Could not find card: '@#$NOT A REAL CARD NAME@#$'\n", errors.toString()); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/DecDeckImportTest.java b/Mage/src/test/java/mage/cards/decks/importer/DecDeckImportTest.java new file mode 100644 index 0000000000..65803c884b --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/DecDeckImportTest.java @@ -0,0 +1,52 @@ +package mage.cards.decks.importer; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import mage.cards.decks.DeckCardLists; + +public class DecDeckImportTest { + + private static final FakeCardLookup LOOKUP = new FakeCardLookup(); + + @Test + public void testImport() { + StringBuilder errors = new StringBuilder(); + DecDeckImporter importer = new DecDeckImporter() { + @Override + public CardLookup getCardLookup() { + return LOOKUP; + } + }; + DeckCardLists deck = importer.importDeck( + "src/test/java/mage/cards/decks/importer/samples/testdeck.dec", errors); + + TestDeckChecker.checker() + .addMain("Masticore", 4) + .addMain("Metalworker", 4) + .addMain("Phyrexian Colossus", 1) + .addMain("Crumbling Sanctuary", 1) + .addMain("Grim Monolith", 4) + .addMain("Mishra's Helix", 1) + .addMain("Phyrexian Processor", 4) + .addMain("Tangle Wire", 4) + .addMain("Thran Dynamo", 4) + .addMain("Voltaic Key", 4) + .addMain("Tinker", 4) + .addMain("Brainstorm", 4) + .addMain("Crystal Vein", 4) + .addMain("Island", 9) + .addMain("Rishadan Port", 4) + .addMain("Saprazzan Skerry", 4) + .addSide("Annul", 4) + .addSide("Chill", 4) + .addSide("Miscalculation", 4) + .addSide("Mishra's Helix", 1) + .addSide("Rising Waters", 2) + .verify(deck, 60, 15); + + assertEquals("", errors.toString()); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/DraftLogImporterTest.java b/Mage/src/test/java/mage/cards/decks/importer/DraftLogImporterTest.java new file mode 100644 index 0000000000..7c64308dd4 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/DraftLogImporterTest.java @@ -0,0 +1,75 @@ +package mage.cards.decks.importer; + +import mage.cards.decks.DeckCardLists; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DraftLogImporterTest { + + private static final FakeCardLookup LOOKUP = new FakeCardLookup(); + + @Test + public void testImport() { + StringBuilder errors = new StringBuilder(); + DraftLogImporter importer = new DraftLogImporter() { + @Override + public CardLookup getCardLookup() { + return LOOKUP; + } + }; + DeckCardLists deck = importer.importDeck( + "src/test/java/mage/cards/decks/importer/samples/testdeck.draft", errors); + + TestDeckChecker.checker() + .addMain("Raging Ravine", 1) + .addMain("Fiery Temper", 1) + .addMain("Wild Mongrel", 1) + .addMain("Wild Mongrel", 1) + .addMain("Shielding Plax", 1) + .addMain("Wild Mongrel", 1) + .addMain("Basking Rootwalla", 1) + .addMain("Wild Mongrel", 1) + .addMain("Arena Athlete", 1) + .addMain("Undying Rage", 1) + .addMain("Molten Birth", 1) + .addMain("Shed Weakness", 1) + .addMain("Pulse of Murasa", 1) + .addMain("Just the Wind", 1) + .addMain("Stitcher's Apprentice", 1) + .addMain("Life from the Loam", 1) + .addMain("Satyr Wayfinder", 1) + .addMain("Mad Prophet", 1) + .addMain("Wild Mongrel", 1) + .addMain("Wickerbough Elder", 1) + .addMain("Basking Rootwalla", 1) + .addMain("Satyr Wayfinder", 1) + .addMain("Brawn", 1) + .addMain("Myr Servitor", 1) + .addMain("Terramorphic Expanse", 1) + .addMain("Foil", 1) + .addMain("Flight of Fancy", 1) + .addMain("Mark of the Vampire", 1) + .addMain("Repel the Darkness", 1) + .addMain("Golgari Charm", 1) + .addMain("Raid Bombardment", 1) + .addMain("Reckless Wurm", 1) + .addMain("Satyr Wayfinder", 1) + .addMain("Kodama's Reach", 1) + .addMain("Last Gasp", 1) + .addMain("Wild Mongrel", 1) + .addMain("Myr Servitor", 1) + .addMain("Raid Bombardment", 1) + .addMain("Treasure Cruise", 1) + .addMain("Bloodflow Connoisseur", 1) + .addMain("Treasure Cruise", 1) + .addMain("Hyena Umbra", 1) + .addMain("Kodama's Reach", 1) + .addMain("Just the Wind", 1) + .addMain("Flight of Fancy", 1) + .verify(deck, 45, 0); + + assertEquals("", errors.toString()); + } + +} \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/importer/FakeCardLookup.java b/Mage/src/test/java/mage/cards/decks/importer/FakeCardLookup.java new file mode 100644 index 0000000000..105f070785 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/FakeCardLookup.java @@ -0,0 +1,54 @@ +package mage.cards.decks.importer; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; + +public class FakeCardLookup extends CardLookup { + + private final Map lookup = new HashMap<>(); + private final boolean alwaysMatches; + + public FakeCardLookup() { + this(true); + } + + public FakeCardLookup(boolean alwaysMatches) { + this.alwaysMatches = alwaysMatches; + } + + public FakeCardLookup addCard(String cardName) { + lookup.put(cardName, new CardInfo() {{ + name = cardName; + }}); + return this; + } + + public Optional lookupCardInfo(String cardName) { + CardInfo card = lookup.get(cardName); + if (card != null) { + return Optional.of(card); + } + + if (alwaysMatches) { + return Optional.of(new CardInfo() {{ + name = cardName; + }}); + } + + return Optional.empty(); + } + + @Override + public List lookupCardInfo(CardCriteria criteria) { + return lookupCardInfo(criteria.getName()) + .map(Collections::singletonList) + .orElse(Collections.emptyList()); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/MwsDeckImportTest.java b/Mage/src/test/java/mage/cards/decks/importer/MwsDeckImportTest.java new file mode 100644 index 0000000000..cf364d8108 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/MwsDeckImportTest.java @@ -0,0 +1,57 @@ +package mage.cards.decks.importer; + +import static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.List; + +import org.junit.Test; + +import mage.cards.decks.DeckCardLists; +import mage.cards.repository.CardCriteria; +import mage.cards.repository.CardInfo; + +public class MwsDeckImportTest { + + private static final FakeCardLookup LOOKUP = new FakeCardLookup(); + + @Test + public void testImport() { + MWSDeckImporter importer = new MWSDeckImporter() { + @Override + public CardLookup getCardLookup() { + return LOOKUP; + } + }; + StringBuilder errors = new StringBuilder(); + DeckCardLists deck = importer.importDeck( + "src/test/java/mage/cards/decks/importer/samples/testdeck.mwDeck", errors); + + TestDeckChecker.checker() + .addMain("Mutavault", 4) + .addMain("Plains", 18) + .addMain("Daring Skyjek", 2) + .addMain("Azorius Arrester", 4) + .addMain("Banisher Priest", 4) + .addMain("Boros Elite", 4) + .addMain("Dryad Militant", 4) + .addMain("Imposing Sovereign", 4) + .addMain("Precinct Captain", 4) + .addMain("Soldier of the Pantheon", 4) + .addMain("Spear of Heliod", 3) + .addMain("Rootborn Defenses", 1) + .addMain("Brave the Elements", 4) + + .addSide("Wear/Tear", 1) + .addSide("Glare of Heresy", 2) + .addSide("Fiendslayer Paladin", 3) + .addSide("Riot Control", 3) + .addSide("Ajani, Caller of the Pride", 3) + .addSide("Rootborn Defenses", 3) + + .verify(deck, 60, 15); + + assertEquals("", errors.toString()); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/O8dDeckImportTest.java b/Mage/src/test/java/mage/cards/decks/importer/O8dDeckImportTest.java new file mode 100644 index 0000000000..4eade3abd7 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/O8dDeckImportTest.java @@ -0,0 +1,33 @@ +package mage.cards.decks.importer; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import mage.cards.decks.DeckCardLists; + +public class O8dDeckImportTest { + + private static final FakeCardLookup LOOKUP = new FakeCardLookup(); + + @Test + public void testImport() { + O8dDeckImporter importer = new O8dDeckImporter() { + @Override + public CardLookup getCardLookup() { + return LOOKUP; + } + }; + StringBuilder errors = new StringBuilder(); + DeckCardLists deck = importer.importDeck( + "src/test/java/mage/cards/decks/importer/samples/testdeck.o8d", errors); + + TestDeckChecker.checker() + .addMain("Forest", 1) + .addSide("Island", 2) + .verify(deck, 1, 2); + + assertEquals("", errors.toString()); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/TestDeckChecker.java b/Mage/src/test/java/mage/cards/decks/importer/TestDeckChecker.java new file mode 100644 index 0000000000..e4f2543239 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/TestDeckChecker.java @@ -0,0 +1,54 @@ +package mage.cards.decks.importer; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.junit.Assert; + +import mage.cards.decks.DeckCardLists; + +public class TestDeckChecker { + + private final List main = new ArrayList<>(); + private final List side = new ArrayList<>(); + + public TestDeckChecker addMain(String name) { + return addMain(name, 1); + } + + public TestDeckChecker addMain(String name, int quantity) { + main.addAll(Collections.nCopies(quantity, name)); + return this; + } + + public TestDeckChecker addSide(String name) { + return addSide(name, 1); + } + + public TestDeckChecker addSide(String name, int quantity) { + side.addAll(Collections.nCopies(quantity, name)); + return this; + } + + public void verify(DeckCardLists deck, int nMain, int nSide) { + assertEquals(nMain, main.size()); + assertEquals(nSide, side.size()); + assertEquals(nMain, deck.getCards().size()); + assertEquals(nSide, deck.getSideboard().size()); + + for (int i = 0; i < main.size(); i++) { + String expected = main.get(i); + String actual = deck.getCards().get(i).getCardName(); + assertEquals(String.format("Expected: '%s' Actual: '%s' at index: %s", + expected, actual, i), expected, actual); + } + } + + public static TestDeckChecker checker() { + return new TestDeckChecker(); + } + +} diff --git a/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.cod b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.cod new file mode 100644 index 0000000000..c90d63f676 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.cod @@ -0,0 +1,14 @@ + + + Deck Name + Some comments in here. + + + + + + + + + + \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.dec b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.dec new file mode 100644 index 0000000000..80abb81381 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.dec @@ -0,0 +1,28 @@ +// Name: Mono-Blue Tinker from MTGSalvation.com via mtgtrice mtg-decks +// Creatures + 4 Masticore + 4 Metalworker + 1 Phyrexian Colossus +// Artifacts + 1 Crumbling Sanctuary + 4 Grim Monolith + 1 Mishra's Helix + 4 Phyrexian Processor + 4 Tangle Wire + 4 Thran Dynamo + 4 Voltaic Key +// Sorceries + 4 Tinker +// Instants + 4 Brainstorm +// Lands + 4 Crystal Vein + 9 Island + 4 Rishadan Port + 4 Saprazzan Skerry +// Sideboard +SB: 4 Annul +SB: 4 Chill +SB: 4 Miscalculation +SB: 1 Mishra's Helix +SB: 2 Rising Waters \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.draft b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.draft new file mode 100644 index 0000000000..95aaf72cae --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.draft @@ -0,0 +1,466 @@ +Event #: 8a74113b-27e5-4a29-85be-4b83f622af00 +Time: 4/11/2019 8:55:15 AM +Players: + Computer Player 4 + Computer Player 2 + Computer Player 6 + hitchyflav + Computer Player 5 + Computer Player 3 + +------ UMA ------ + +Pack 1 pick 1: + Deranged Assistant + Nightbird's Clutches + Groundskeeper + Sanitarium Skeleton + Skywing Aven + Foil + Tethmos High Priest + Kodama's Reach + Pulse of Murasa + Basking Rootwalla + Ulamog's Crusher + Vengeful Rebirth + Laboratory Maniac + Boneyard Wurm +--> Raging Ravine + +Pack 1 pick 2: + Deranged Assistant + Olivia's Dragoon + Sultai Skullkeeper +--> Fiery Temper + Wild Mongrel + Dimir Guildmage + Turn to Mist + Ingot Chewer + Just the Wind + Mad Prophet + Rakdos Shred-Freak + Firewing Phoenix + Vengeful Rebirth + Fecundity + +Pack 1 pick 3: + Death Denied + Stitcher's Apprentice + Archaeomancer + Arena Athlete + Lotus-Eye Mystics +--> Wild Mongrel + Spider Umbra + Martyr of Sands + Mad Prophet + Ghoulcaller's Accomplice + Safehold Elite + Malevolent Whispers + Devoted Druid + +Pack 1 pick 4: + Stitcher's Apprentice +--> Wild Mongrel + Ronom Unicorn + Death Denied + Flight of Fancy + Undying Rage + Grave Scrabbler + Wandering Champion + Angelic Renewal + Patchwork Gnomes + Wingsteed Rider + Mage-Ring Network + +Pack 1 pick 5: + Defy Gravity + Grave Scrabbler + Fume Spitter +--> Shielding Plax + Ghoulcaller's Accomplice + Rakdos Shred-Freak + Sparkspitter + Resurrection + Molten Birth + Slum Reaper + Grave Strength + +Pack 1 pick 6: + Terramorphic Expanse +--> Wild Mongrel + Shed Weakness + Tethmos High Priest + Angelic Renewal + Slum Reaper + Foil + Rune Snag + Wickerbough Elder + Frantic Search + +Pack 1 pick 7: + Deranged Assistant + Nightbird's Clutches + Groundskeeper + Skywing Aven + Foil + Kodama's Reach + Pulse of Murasa +--> Basking Rootwalla + Vengeful Rebirth + +Pack 1 pick 8: + Deranged Assistant + Olivia's Dragoon + Sultai Skullkeeper +--> Wild Mongrel + Dimir Guildmage + Turn to Mist + Just the Wind + Rakdos Shred-Freak + +Pack 1 pick 9: + Death Denied + Stitcher's Apprentice + Archaeomancer +--> Arena Athlete + Spider Umbra + Martyr of Sands + Ghoulcaller's Accomplice + +Pack 1 pick 10: + Stitcher's Apprentice + Ronom Unicorn + Flight of Fancy +--> Undying Rage + Wandering Champion + Angelic Renewal + +Pack 1 pick 11: + Defy Gravity + Fume Spitter + Ghoulcaller's Accomplice +--> Molten Birth + Slum Reaper + +Pack 1 pick 12: +--> Shed Weakness + Angelic Renewal + Rune Snag + Frantic Search + +Pack 1 pick 13: + Foil + Kodama's Reach +--> Pulse of Murasa + +Pack 1 pick 14: + Sultai Skullkeeper +--> Just the Wind + +Pack 1 pick 15: +--> Stitcher's Apprentice + +------ UMA ------ + +Pack 2 pick 1: + Reckless Wurm + Dark Dabbling + Lotus-Eye Mystics + Heliod's Pilgrim + Satyr Wayfinder + Moan of the Unhallowed + Akroan Crusader + Fire // Ice + Grave Scrabbler + Mark of the Vampire + Safehold Elite + Blast of Genius + Spirit Cairn + Shriekmaw +--> Life from the Loam + +Pack 2 pick 2: +--> Satyr Wayfinder + Shed Weakness + Rakdos Shred-Freak + Defy Gravity + Crow of Dark Tidings + Frantic Search + Walker of the Grove + Prey Upon + Repel the Darkness + Eel Umbra + Brawn + Stingerfling Spider + Forbidden Alchemy + Celestial Colonnade + +Pack 2 pick 3: + Deranged Assistant + Beckon Apparition + Bloodflow Connoisseur + Faith's Fetters +--> Mad Prophet + Myr Servitor + Shed Weakness + Dimir Guildmage + Ingot Chewer + Icatian Crier + Plumeveil + Golgari Charm + Visions of Beyond + +Pack 2 pick 4: + Defy Gravity + Conviction + Terramorphic Expanse +--> Wild Mongrel + Moan of the Unhallowed + Gurmag Angler + Vessel of Endless Rest + Hissing Iguanar + Mark of the Vampire + Martyr of Sands + Circular Logic + Rise from the Tides + +Pack 2 pick 5: + Slum Reaper + Icatian Crier +--> Wickerbough Elder + Mad Prophet + Defy Gravity + Gurmag Angler + Archaeomancer + Foil + Eel Umbra + Vessel of Endless Rest + Rally the Peasants + +Pack 2 pick 6: + Wandering Champion +--> Basking Rootwalla + Frantic Search + Angelic Renewal + Cathodion + Olivia's Dragoon + Flight of Fancy + Skyspear Cavalry + Thermo-Alchemist + Fume Spitter + +Pack 2 pick 7: + Dark Dabbling + Lotus-Eye Mystics + Heliod's Pilgrim +--> Satyr Wayfinder + Moan of the Unhallowed + Akroan Crusader + Grave Scrabbler + Mark of the Vampire + Blast of Genius + +Pack 2 pick 8: + Shed Weakness + Defy Gravity + Crow of Dark Tidings + Frantic Search + Walker of the Grove + Repel the Darkness + Eel Umbra +--> Brawn + +Pack 2 pick 9: + Deranged Assistant + Beckon Apparition + Bloodflow Connoisseur +--> Myr Servitor + Shed Weakness + Icatian Crier + Golgari Charm + +Pack 2 pick 10: + Defy Gravity + Conviction +--> Terramorphic Expanse + Moan of the Unhallowed + Mark of the Vampire + Circular Logic + +Pack 2 pick 11: + Icatian Crier + Defy Gravity +--> Foil + Eel Umbra + Vessel of Endless Rest + +Pack 2 pick 12: + Wandering Champion + Angelic Renewal +--> Flight of Fancy + Fume Spitter + +Pack 2 pick 13: + Dark Dabbling + Moan of the Unhallowed +--> Mark of the Vampire + +Pack 2 pick 14: +--> Repel the Darkness + Eel Umbra + +Pack 2 pick 15: +--> Golgari Charm + +------ UMA ------ + +Pack 3 pick 1: + Myr Servitor + Dimir Guildmage +--> Raid Bombardment + Kodama's Reach + Arena Athlete + Martyr of Sands + Shed Weakness + Skywing Aven + Wickerbough Elder + Hooting Mandrills + Sparkspitter + Desperate Ritual + Grave Strength + Dawn Charm + Reya Dawnbringer + +Pack 3 pick 2: + Pulse of Murasa + Crow of Dark Tidings + Raid Bombardment +--> Reckless Wurm + Hyena Umbra + Just the Wind + Verdant Eidolon + Groundskeeper + Double Cleave + Repel the Darkness + Stitcher's Apprentice + Sleight of Hand + Living Lore + Artisan of Kozilek + +Pack 3 pick 3: + Moan of the Unhallowed + Thermo-Alchemist + Stitcher's Apprentice + Bloodflow Connoisseur + Sparkspitter + Mark of the Vampire + Treasure Cruise + Flight of Fancy + Unholy Hunger + Staunch-Hearted Warrior +--> Satyr Wayfinder + Spirit Cairn + Blast of Genius + +Pack 3 pick 4: + Bloodflow Connoisseur + Grave Scrabbler + Hyena Umbra + Slum Reaper +--> Kodama's Reach + Sparkspitter + Sanitarium Skeleton + Stitched Drake + Pulse of Murasa + Mammoth Umbra + Olivia's Dragoon + Vengeful Rebirth + +Pack 3 pick 5: + Beckon Apparition + Turn to Mist + Spider Umbra + Bloodflow Connoisseur +--> Last Gasp + Terramorphic Expanse + Treasure Cruise + Miming Slime + Emancipation Angel + Warleader's Helix + Snapcaster Mage + +Pack 3 pick 6: + Ingot Chewer + Defy Gravity + Mammoth Umbra +--> Wild Mongrel + Reckless Charge + Fume Spitter + Skywing Aven + Hyena Umbra + Twins of Maurer Estate + Urban Evolution + +Pack 3 pick 7: +--> Myr Servitor + Kodama's Reach + Arena Athlete + Martyr of Sands + Shed Weakness + Skywing Aven + Wickerbough Elder + Sparkspitter + Dawn Charm + +Pack 3 pick 8: + Pulse of Murasa +--> Raid Bombardment + Hyena Umbra + Just the Wind + Repel the Darkness + Stitcher's Apprentice + Sleight of Hand + Living Lore + +Pack 3 pick 9: + Moan of the Unhallowed + Thermo-Alchemist + Stitcher's Apprentice + Sparkspitter + Mark of the Vampire +--> Treasure Cruise + Flight of Fancy + +Pack 3 pick 10: +--> Bloodflow Connoisseur + Hyena Umbra + Sanitarium Skeleton + Stitched Drake + Mammoth Umbra + Olivia's Dragoon + +Pack 3 pick 11: + Spider Umbra + Terramorphic Expanse +--> Treasure Cruise + Miming Slime + Warleader's Helix + +Pack 3 pick 12: + Defy Gravity + Skywing Aven +--> Hyena Umbra + Urban Evolution + +Pack 3 pick 13: +--> Kodama's Reach + Martyr of Sands + Shed Weakness + +Pack 3 pick 14: + Hyena Umbra +--> Just the Wind + +Pack 3 pick 15: +--> Flight of Fancy + diff --git a/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.mwDeck b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.mwDeck new file mode 100644 index 0000000000..527f58f60d --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.mwDeck @@ -0,0 +1,23 @@ +// Deck file for Magic Workstation (http://www.magicworkstation.com) +// NAME : WW Human +// CREATOR : meltiin (magic-ville.com) +// FORMAT : Standard + 4 [M14] Mutavault + 18 [UNH] Plains + 2 [GTC] Daring Skyjek + 4 [RTR] Azorius Arrester + 4 [M14] Banisher Priest + 4 [GTC] Boros Elite + 4 [RTR] Dryad Militant + 4 [M14] Imposing Sovereign + 4 [RTR] Precinct Captain + 4 [THS] Soldier of the Pantheon + 3 [THS] Spear of Heliod + 1 [RTR] Rootborn Defenses + 4 [M14] Brave the Elements +SB: 1 [DGM] Wear/Tear +SB: 2 [THS] Glare of Heresy +SB: 3 [M14] Fiendslayer Paladin +SB: 3 [DGM] Riot Control +SB: 3 [M14] Ajani, Caller of the Pride +SB: 3 [RTR] Rootborn Defenses \ No newline at end of file diff --git a/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.o8d b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.o8d new file mode 100644 index 0000000000..556671d0f4 --- /dev/null +++ b/Mage/src/test/java/mage/cards/decks/importer/samples/testdeck.o8d @@ -0,0 +1,8 @@ + +

    + Forest +
    +
    + Island +
    + diff --git a/Utils/cardClass.tmpl b/Utils/cardClass.tmpl index cfad53cb34..9d165a4cd2 100644 --- a/Utils/cardClass.tmpl +++ b/Utils/cardClass.tmpl @@ -3,7 +3,7 @@ package mage.cards.[=$cardNameFirstLetter=]; import java.util.UUID;[= if ($power || $power eq 0) { if ($planeswalker eq 'true') { - $OUT .= "\nimport mage.abilities.common.PlaneswalkerEntersWithLoyalityCountersAbility;" + $OUT .= "\nimport mage.abilities.common.PlaneswalkerEntersWithLoyaltyCountersAbility;" }else { $OUT .= "\nimport mage.MageInt;" } @@ -30,7 +30,7 @@ public final class [=$className=] extends CardImpl { [=$subType=][=$colors=][= if ($power || $power eq 0) { if ($planeswalker eq 'true') { - $OUT .= "\n this.addAbility(new PlanswalkerEntersWithLoyalityCountersAbility($power));"; + $OUT .= "\n this.addAbility(new PlaneswalkerEntersWithLoyaltyCountersAbility($power));"; } else { $OUT .= "\n this.power = new MageInt($power);"; $OUT .= "\n this.toughness = new MageInt($toughness);"; @@ -39,7 +39,7 @@ if ($power || $power eq 0) { =][=$abilities=] } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/cardExtendedClass.tmpl b/Utils/cardExtendedClass.tmpl index 79d978519b..5ea23f3f71 100644 --- a/Utils/cardExtendedClass.tmpl +++ b/Utils/cardExtendedClass.tmpl @@ -14,7 +14,7 @@ public final class [=$className=] extends mage.sets.[=$baseSet=].[=$className=] this.expansionSetCode = "[=$expansionSetCode=]";[=$rarityExtended=] } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/cardExtendedLandClass.tmpl b/Utils/cardExtendedLandClass.tmpl index 00b9cac234..0d73918d6f 100644 --- a/Utils/cardExtendedLandClass.tmpl +++ b/Utils/cardExtendedLandClass.tmpl @@ -13,7 +13,7 @@ public final class [=$className=][=$landNr=] extends mage.cards.basiclands.[=$cl this.expansionSetCode = "[=$expansionSetCode=]"; } - public [=$className=][=$landNr=](final [=$className=][=$landNr=] card) { + private [=$className=][=$landNr=](final [=$className=][=$landNr=] card) { super(card); } diff --git a/Utils/cardSplitClass.tmpl b/Utils/cardSplitClass.tmpl index b836f087a8..c9d9200ba4 100644 --- a/Utils/cardSplitClass.tmpl +++ b/Utils/cardSplitClass.tmpl @@ -24,7 +24,7 @@ public final class [=$className=] extends SplitCard { } - public [=$className=](final [=$className=] card) { + private [=$className=](final [=$className=] card) { super(card); } diff --git a/Utils/find_new_cards.pl b/Utils/find_new_cards.pl index db6a7db5f3..79d50ff958 100644 --- a/Utils/find_new_cards.pl +++ b/Utils/find_new_cards.pl @@ -5,7 +5,7 @@ use strict; my $addedCards; -my $GIT_CMD = "C:\\Program Files (x86)\\Git\\bin\\git.exe"; +my $GIT_CMD = "git.exe"; my $text = `\"$GIT_CMD\" tag`; print "Assuming the tag command is on: \"$GIT_CMD\" tag\n"; diff --git a/Utils/gen-card.pl b/Utils/gen-card.pl index 44abc4a54c..3c2e34b1c2 100755 --- a/Utils/gen-card.pl +++ b/Utils/gen-card.pl @@ -32,7 +32,7 @@ sub fixCost { my $author; if (-e $authorFile) { - open (DATA, $authorFile); + open (DATA, $authorFile) || die "can't open $authorFile : $!"; $author = ; chomp $author; close(DATA); @@ -40,14 +40,14 @@ if (-e $authorFile) { $author = 'anonymous'; } -open (DATA, $dataFile) || die "can't open $dataFile"; +open (DATA, $dataFile) || die "can't open $dataFile : $!"; while(my $line = ) { my @data = split('\\|', $line); $cards{$data[0]}{$data[1]} = \@data; } close(DATA); -open (DATA, $setsFile) || die "can't open $setsFile"; +open (DATA, $setsFile) || die "can't open $setsFile : $!"; while(my $line = ) { my @data = split('\\|', $line); $sets{$data[0]}= $data[1]; @@ -55,14 +55,14 @@ while(my $line = ) { } close(DATA); -open (DATA, $knownSetsFile) || die "can't open $knownSetsFile"; +open (DATA, $knownSetsFile) || die "can't open $knownSetsFile : $!"; while(my $line = ) { my @data = split('\\|', $line); $knownSets{$data[0]}= $data[1]; } close(DATA); -open (DATA, $keywordsFile) || die "can't open $keywordsFile"; +open (DATA, $keywordsFile) || die "can't open $keywordsFile : $!"; while(my $line = ) { my @data = split('\\|', $line); $keywords{toCamelCase($data[0])}= $data[1]; diff --git a/Utils/gen-list-unimplemented-cards-for-set.pl b/Utils/gen-list-unimplemented-cards-for-set.pl index 98a8da096e..3d8d2849a3 100755 --- a/Utils/gen-list-unimplemented-cards-for-set.pl +++ b/Utils/gen-list-unimplemented-cards-for-set.pl @@ -89,6 +89,7 @@ sub toCamelCase { # TODO: check for basic lands with ending 1,2,3,4,5 ... my %cardNames; my $toPrint = ''; +my $setAbbr = $sets{$setName}; foreach my $card (sort cardSort @setCards) { my $className = toCamelCase(@{$card}[0]); @@ -102,7 +103,7 @@ foreach my $card (sort cardSort @setCards) { } my $cardName = @{$card}[0]; $cardName =~ s/ /+/g; - $toPrint .= "@{$card}[2]|[@{$card}[0]](https://magiccards.info/query?q=!$cardName)"; + $toPrint .= "@{$card}[2]|[@{$card}[0]](https://scryfall.com/search?q=!\"$cardName\" e:$setAbbr)"; } } @@ -127,7 +128,7 @@ foreach $cn (sort keys (%cardNames)) } my $cn2 = $cn; $cn2 =~ s/ /+/g; - print ISSUE_TRACKER "- $x_or_not [$cn](https://magiccards.info/query?q=!$cn2)\n"; + print ISSUE_TRACKER "- $x_or_not [$cn](https://scryfall.com/search?q=!\"$cn2\" e:$setAbbr)\n"; } close ISSUE_TRACKER; -print ("Tracking Issue text for a new Github issue (similar to https://github.com/magefree/mage/issues/2215): " . lc($sets{$setName}) ."_issue_tracker.txt\n"); +print ("Tracking Issue text for a new Github issue (similar to https://github.com/magefree/mage/issues/2215): " . lc($setAbbr) ."_issue_tracker.txt\n"); diff --git a/Utils/keywords.txt b/Utils/keywords.txt index b965d6b3ae..f32a5b3028 100644 --- a/Utils/keywords.txt +++ b/Utils/keywords.txt @@ -1,4 +1,5 @@ Afflict|number| +Afterlife|number| Annihilator|number| Ascend|new| Assist|new| @@ -75,12 +76,14 @@ Prowess|new| Reach|instance| Rebound|new| Renown|number| +Riot|new| Scavenge|cost| Shadow|instance| Shroud|instance| Soulbond|instance| Soulshift|number| Skulk|new| +Spectacle|card, cost| Storm|new| Sunburst|new| Swampcycling|cost| diff --git a/Utils/known-sets.txt b/Utils/known-sets.txt index 8930efa547..c62da74fcd 100644 --- a/Utils/known-sets.txt +++ b/Utils/known-sets.txt @@ -137,6 +137,7 @@ Mercadian Masques|MercadianMasques| Mirage|Mirage| Mirrodin|Mirrodin| Mirrodin Besieged|MirrodinBesieged| +Modern Horizons|ModernHorizons| Modern Masters|ModernMasters| Modern Masters 2015|ModernMasters2015| Modern Masters 2017|ModernMasters2017| @@ -160,6 +161,7 @@ Premium Deck Series: Fire and Lightning|PremiumDeckSeriesFireAndLightning| Premium Deck Series: Slivers|PremiumDeckSeriesSlivers| Prerelease Events|PrereleaseEvents| Prophecy|Prophecy| +Ravnica Allegiance|RavnicaAllegiance| Ravnica: City of Guilds|RavnicaCityOfGuilds| Return to Ravnica|ReturnToRavnica| Revised Edition|RevisedEdition| @@ -195,6 +197,7 @@ Urza's Legacy|UrzasLegacy| Urza's Saga|UrzasSaga| Vintage Masters|VintageMasters| Visions|Visions| +War of the Spark|WarOfTheSpark| Weatherlight|Weatherlight| Welcome Deck 2016|WelcomeDeck2016| Welcome Deck 2017|WelcomeDeck2017| diff --git a/Utils/mtg-cards-data.txt b/Utils/mtg-cards-data.txt index 4859b6ceed..334185d784 100644 --- a/Utils/mtg-cards-data.txt +++ b/Utils/mtg-cards-data.txt @@ -32666,7 +32666,7 @@ Mountain|Duel Decks: Mind vs. Might|62|L||Basic Land - Mountain|||{T}: Add {R}.| Forest|Duel Decks: Mind vs. Might|63|L||Basic Land - Forest|||{T}: Add {G}.| Forest|Duel Decks: Mind vs. Might|64|L||Basic Land - Forest|||{T}: Add {G}.| Forest|Duel Decks: Mind vs. Might|65|L||Basic Land - Forest|||{T}: Add {G}.| -Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3||+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to any target, where X is the number of Gremlins you control.| +Chandra, Gremlin Wrangler|Heroes of the Realm|1|M|{2}{R}{R}|Legendary Planeswalker - Chandra|3|+1: Create a 2/2 red Gremlin creature token.$-2:Chandra, Gremlin Wrangler deals X damage to any target, where X is the number of Gremlins you control.| Dungeon Master|Heroes of the Realm|1|M|{2}{W}{U}|Legendary Planeswalker - Dungeon Master|||+1: Target opponent creates a 1/1 black Skeleton creature token with “When this creature dies, each opponent loses 2 life.”$+1: Roll a d20. If you roll a 1, skip your next turn. If you roll a 12 or higher, draw a card.$-6: You get an adventuring party. (Your party is a 3/3 red Fighter with first strike, a 1/1 white Cleric with lifelink, a 2/2 black Rogue with hexproof, and a 1/1 blue Wizard with flying.)| Nira, Hellkite Duelist|Heroes of the Realm|3|M|{W}{U}{B}{R}{G}|Legendary Creature — Dragon|6|6|Flash$Flying, trample, haste$When Nira, Hellkite Duelist enters the battlefield, the next time you would lose the game this turn, instead draw three cards and your life total becomes 5.| Baffling End|Rivals of Ixalan|1|U|{1}{W}|Enchantment|||When Baffling End enters the battlefield, exile target creature an opponent controls with converted mana cost 3 or less.$When Baffling End leaves the battlefield, target opponent create a 3/3 green Dinosaur creature token with trample.| @@ -34575,4 +34575,544 @@ Vraska, Regal Gorgon|Guilds of Ravnica|269|M|{5}{B}{G}|Legendary Planeswalker - Kraul Raider|Guilds of Ravnica|270|C|{2}{B}|Creature - Insect Warrior|2|3|Menace| Attendant of Vraska|Guilds of Ravnica|271|U|{1}{B}{G}|Creature - Zombie Soldier|3|3|When Attendant of Vraska dies, if you control a Vraska planeswalker, you gain life equal to Attendant of Vraska's power.| Vraska's Stoneglare|Guilds of Ravnica|272|R|{4}{B}{G}|Sorcery|||Destroy target creature. You gain life equal to its toughness. You may search your library and/or graveyard for a card named Vraska, Regal Gorgon, reveal it, and put it into your hand. If you search your library this way, shuffle it.| -Impervious Greatwurm|Guilds of Ravnica|273|M|{7}{G}{G}{G}|Creature - Wurm|16|16|Convoke$Indestructible| \ No newline at end of file +Impervious Greatwurm|Guilds of Ravnica|273|M|{7}{G}{G}{G}|Creature - Wurm|16|16|Convoke$Indestructible| +Angel of Grace|Ravnica Allegiance|1|M|{3}{W}{W}|Creature - Angel|5|4|Flash$Flying$When Angel of Grace enters the battlefield, until end of turn, damage that would reduce your life total to less than 1 reduces it to 1 instead.${4}{W}{W}, Exile Angel of Grace from your graveyard: Your life total becomes 10.| +Angelic Exaltation|Ravnica Allegiance|2|U|{3}{W}|Enchantment|||Whenever a creature you control attacks alone, it gets +X/+X until end of turn, where X is the number of creatures you control.| +Archway Angel|Ravnica Allegiance|3|U|{5}{W}|Creature - Angel|3|4|Flying$When Archway Angel enters the battlefield, you gain 2 life for each Gate you control.| +Arrester's Zeal|Ravnica Allegiance|4|C|{W}|Instant|||Target creature gets +2/+2 until end of turn.$Addendum — If you cast this spell during your main phase, that creature gains flying until end of turn.| +Bring to Trial|Ravnica Allegiance|5|C|{2}{W}|Sorcery|||Exile target creature with power 4 or greater.| +Civic Stalwart|Ravnica Allegiance|6|C|{3}{W}|Creature - Elephant Soldier|3|3|When Civic Stalwart enters the battlefield, creatures you control get +1/+1 until end of turn.| +Concordia Pegasus|Ravnica Allegiance|7|C|{1}{W}|Creature - Pegasus|1|3|Flying| +Expose to Daylight|Ravnica Allegiance|8|C|{2}{W}|Instant|||Destroy target artifact or enchantment. Scry 1.| +Forbidding Spirit|Ravnica Allegiance|9|U|{1}{W}{W}|Creature - Spirit Cleric|3|3|When Forbidding Spirit enters the battlefield, until your next turn, creatures can't attack you or a planeswalker you control unless their controller pays {2} for each of those creatures.| +Haazda Officer|Ravnica Allegiance|10|C|{2}{W}|Creature - Human Soldier|3|2|When Haazda Officer enters the battlefield, target creature you control gets +1/+1 until end of turn.| +Hero of Precinct One|Ravnica Allegiance|11|R|{1}{W}|Creature - Human Warrior|2|2|Whenever you cast a multicolored spell, create a 1/1 white Human creature token.| +Impassioned Orator|Ravnica Allegiance|12|C|{1}{W}|Creature - Human Cleric|2|2|Whenever another creature enters the battlefield under your control, you gain 1 life.| +Justiciar's Portal|Ravnica Allegiance|13|C|{1}{W}|Instant|||Exile target creature you control, then return that card to the battlefield under its owner's control. It gains first strike until end of turn.| +Knight of Sorrows|Ravnica Allegiance|14|C|{4}{W}|Creature - Human Knight|3|3|Knight of Sorrows can block an additional creature each combat.$Afterlife 1| +Lumbering Battlement|Ravnica Allegiance|15|R|{4}{W}|Creature - Beast|4|5|Vigilance$When Lumbering Battlement enters the battlefield, exile any number of other nontoken creatures you control until it leaves the battlefield.$Lumbering Battlement gets +2/+2 for each card exiled with it.| +Ministrant of Obligation|Ravnica Allegiance|16|U|{2}{W}|Creature - Human Cleric|2|1|Afterlife 2| +Prowling Caracal|Ravnica Allegiance|17|C|{1}{W}|Creature - Cat|3|1|| +Rally to Battle|Ravnica Allegiance|18|U|{3}{W}|Instant|||Creatures you control get +1/+3 until end of turn. Untap them.| +Resolute Watchdog|Ravnica Allegiance|19|U|{W}|Creature - Hound|1|3|Defender${1}, Sacrifice Resolute Watchdog: Target creature you control gains indestructible until end of turn.| +Sentinel's Mark|Ravnica Allegiance|20|U|{1}{W}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets +1/+2 and has vigilance.$Addendum — When Sentinel's Mark enters the battlefield, if you cast it during your main phase, enchanted creature gains lifelink until end of turn.| +Sky Tether|Ravnica Allegiance|21|U|{W}|Enchantment - Aura|||Enchant creature$Enchanted creature has defender and loses flying.| +Smothering Tithe|Ravnica Allegiance|22|R|{3}{W}|Enchantment|||Whenever an opponent draws a card, that player may pay {2}. If the player doesn't, you create a colorless Treasure artifact token with "{T}, Sacrifice this artifact: Add one mana of any color."| +Spirit of the Spires|Ravnica Allegiance|23|U|{3}{W}|Creature - Spirit|2|4|Flying$Other creatures you control with flying get +0/+1.| +Summary Judgment|Ravnica Allegiance|24|C|{1}{W}|Instant|||Summary Judgment deals 3 damage to target tapped creature.$Addendum — If you cast this spell during your main phase, it deals 5 damage to that creature instead.| +Syndicate Messenger|Ravnica Allegiance|25|C|{3}{W}|Creature - Bird|2|3|Flying$Afterlife 1| +Tenth District Veteran|Ravnica Allegiance|26|C|{2}{W}|Creature - Human Soldier|2|3|Vigilance$Whenever Tenth District Veteran attacks, untap another target creature you control.| +Tithe Taker|Ravnica Allegiance|27|R|{1}{W}|Creature - Human Soldier|2|1|During your turn, spells your opponents cast cost {1} more to cast and abilities your opponents activate cost {1} more to activate unless they're mana abilities.$Afterlife 1| +Twilight Panther|Ravnica Allegiance|28|C|{W}|Creature - Cat Spirit|1|2|{B}: Twilight Panther gains deathtouch until end of turn.| +Unbreakable Formation|Ravnica Allegiance|29|R|{2}{W}|Instant|||Creatures you control gain indestructible until end of turn.$Addendum — If you cast this spell during your main phase, put a +1/+1 counter on each of those creatures, and they also gain vigilance until end of turn.| +Watchful Giant|Ravnica Allegiance|30|C|{5}{W}|Creature - Giant Soldier|3|6|When Watchful Giant enters the battlefield, create a 1/1 white Human creature token.| +Arrester's Admonition|Ravnica Allegiance|31|C|{2}{U}|Instant|||Return target creature to its owner's hand.$Addendum — If you cast this spell during your main phase, draw a card.| +Benthic Biomancer|Ravnica Allegiance|32|R|{U}|Creature - Merfolk Wizard Mutant|1|1|{1}{U}: Adapt 1.$Whenever one or more +1/+1 counters are put on Benthic Biomancer, draw a card, then discard a card.| +Chillbringer|Ravnica Allegiance|33|C|{4}{U}|Creature - Elemental|3|3|Flying$When Chillbringer enters the battlefield, tap target creature an opponent controls. It doesn't untap during its controller's next untap step.| +Clear the Mind|Ravnica Allegiance|34|C|{2}{U}|Sorcery|||Target player shuffles their graveyard into their library.$Draw a card.| +Code of Constraint|Ravnica Allegiance|35|U|{2}{U}|Instant|||Target creature gets -4/-0 until end of turn.$Draw a card.$Addendum — If you cast this spell during your main phase, tap that creature and it doesn't untap during its controller's next untap step.| +Coral Commando|Ravnica Allegiance|36|C|{2}{U}|Creature - Merfolk Warrior|3|2|| +Essence Capture|Ravnica Allegiance|37|U|{U}{U}|Instant|||Counter target creature spell. Put a +1/+1 counter on up to one target creature you control.| +Eyes Everywhere|Ravnica Allegiance|38|U|{2}{U}|Enchantment|||At the beginning of your upkeep, scry 1.${5}{U}: Exchange control of Eyes Everywhere and target nonland permanent. Activate this ability only any time you could cast a sorcery.| +Faerie Duelist|Ravnica Allegiance|39|C|{1}{U}|Creature - Faerie Rogue|1|2|Flash$Flying$When Faerie Duelist enters the battlefield, target creature an opponent controls gets -2/-0 until end of turn.| +Gateway Sneak|Ravnica Allegiance|40|U|{2}{U}|Creature - Vedalken Rogue|1|3|Whenever a Gate enters the battlefield under your control, Gateway Sneak can't be blocked this turn.$Whenever Gateway Sneak deals combat damage to a player, draw a card.| +Humongulus|Ravnica Allegiance|41|C|{4}{U}|Creature - Homunculus|2|5|Hexproof| +Mass Manipulation|Ravnica Allegiance|42|R|{X}{X}{U}{U}{U}{U}|Sorcery|||Gain control of X target creatures and/or planeswalkers.| +Mesmerizing Benthid|Ravnica Allegiance|43|M|{3}{U}{U}|Creature - Octopus|4|5|When Mesmerizing Benthid enters the battlefield, create two 0/2 blue Illusion creature tokens with "Whenever this creature blocks a creature, that creature doesn't untap during its controller's next untap step."$Mesmerizing Benthid has hexproof as long as you control an Illusion.| +Persistent Petitioners|Ravnica Allegiance|44|C|{1}{U}|Creature - Human Advisor|1|3|{1}, {T}: Target player puts the top card of their library into their graveyard.$Tap four untapped Advisors you control: Target player puts the top twelve cards of their library into their graveyard.$A deck can have any number of cards named Persistent Petitioners.| +Precognitive Perception|Ravnica Allegiance|45|R|{3}{U}{U}|Instant|||Draw three cards.$Addendum — If you cast this spell during your main phase, instead scry 3, then draw three cards.| +Prying Eyes|Ravnica Allegiance|46|C|{4}{U}{U}|Instant|||Draw four cards, then discard two cards.| +Pteramander|Ravnica Allegiance|47|U|{U}|Creature - Salamander Drake|1|1|Flying${7}{U}: Adapt 4. This ability costs {1} less to activate for each instant and sorcery card in your graveyard.| +Quench|Ravnica Allegiance|48|C|{1}{U}|Instant|||Counter target spell unless its controller pays {2}.| +Sage's Row Savant|Ravnica Allegiance|49|C|{1}{U}|Creature - Vedalken Wizard|2|1|When Sage's Row Savant enters the battlefield, scry 2.| +Senate Courier|Ravnica Allegiance|50|C|{2}{U}|Creature - Bird|1|4|Flying${1}{W}: Senate Courier gains vigilance until end of turn.| +Shimmer of Possibility|Ravnica Allegiance|51|C|{1}{U}|Sorcery|||Look at the top four cards of your library. Put one of them into your hand and the rest on the bottom of your library in a random order.| +Skatewing Spy|Ravnica Allegiance|52|U|{3}{U}|Creature - Vedalken Rogue Mutant|2|3|{5}{U}: Adapt 2.$Each creature you control with a +1/+1 counter on it has flying.| +Skitter Eel|Ravnica Allegiance|53|C|{3}{U}|Creature - Fish Crab|3|3|{2}{U}: Adapt 2.| +Slimebind|Ravnica Allegiance|54|C|{1}{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature gets -4/-0.| +Sphinx of Foresight|Ravnica Allegiance|55|R|{2}{U}{U}|Creature - Sphinx|4|4|You may reveal this card from your opening hand. If you do, scry 3 at the beginning of your first upkeep.$Flying$At the beginning of your upkeep, scry 1.| +Swirling Torrent|Ravnica Allegiance|56|U|{5}{U}|Sorcery|||Choose one or both —$• Put target creature on top of its owner's library.$• Return target creature to its owner's hand.| +Thought Collapse|Ravnica Allegiance|57|C|{1}{U}{U}|Instant|||Counter target spell. Its controller puts the top three cards of their library into their graveyard.| +Verity Circle|Ravnica Allegiance|58|R|{2}{U}|Enchantment|||Whenever a creature an opponent controls becomes tapped, if it isn't being declared as an attacker, you may draw a card.${4}{U}: Tap target creature without flying.| +Wall of Lost Thoughts|Ravnica Allegiance|59|U|{1}{U}|Creature - Wall|0|4|Defender$When Wall of Lost Thoughts enters the battlefield, target player puts the top four cards of their library into their graveyard.| +Windstorm Drake|Ravnica Allegiance|60|U|{4}{U}|Creature - Drake|3|3|Flying$Other creatures you control with flying get +1/+0.| +Awaken the Erstwhile|Ravnica Allegiance|61|R|{3}{B}{B}|Sorcery|||Each player discards all the cards in their hand, then creates that many 2/2 black Zombie creature tokens.| +Bankrupt in Blood|Ravnica Allegiance|62|U|{1}{B}|Sorcery|||As an additional cost to cast this spell, sacrifice two creatures.$Draw three cards.| +Blade Juggler|Ravnica Allegiance|63|C|{4}{B}|Creature - Human Rogue|3|2|Spectacle {2}{B}$When Blade Juggler enters the battlefield, it deals 1 damage to you and you draw a card.| +Bladebrand|Ravnica Allegiance|64|C|{1}{B}|Instant|||Target creature gains deathtouch until end of turn.$Draw a card.| +Bloodmist Infiltrator|Ravnica Allegiance|65|U|{2}{B}|Creature - Vampire|3|1|Whenever Bloodmist Infiltrator attacks, you may sacrifice another creature. If you do, Bloodmist Infiltrator can't be blocked this turn.| +Carrion Imp|Ravnica Allegiance|66|C|{3}{B}|Creature - Imp|2|3|Flying$When Carrion Imp enters the battlefield, you may exile target creature card from a graveyard. If you do, you gain 2 life.| +Catacomb Crocodile|Ravnica Allegiance|67|C|{4}{B}|Creature - Crocodile|3|7|| +Clear the Stage|Ravnica Allegiance|68|U|{4}{B}|Instant|||Target creature gets -3/-3 until end of turn. If you control a creature with power 4 or greater, you may return up to one target creature card from your graveyard to your hand.| +Consign to the Pit|Ravnica Allegiance|69|C|{5}{B}|Sorcery|||Destroy target creature. Consign to the Pit deals 2 damage to that creature's controller.| +Cry of the Carnarium|Ravnica Allegiance|70|U|{1}{B}{B}|Sorcery|||All creatures get -2/-2 until end of turn. Exile all creature cards in all graveyards that were put there from the battlefield this turn. If a creature would die this turn, exile it instead.| +Dead Revels|Ravnica Allegiance|71|C|{3}{B}|Sorcery|||Spectacle {1}{B}$Return up to two target creature cards from your graveyard to your hand.| +Debtors' Transport|Ravnica Allegiance|72|C|{5}{B}|Creature - Thrull|5|3|Afterlife 2| +Drill Bit|Ravnica Allegiance|73|U|{2}{B}|Sorcery|||Spectacle {B}$Target player reveals their hand. You choose a nonland card from it. That player discards that card.| +Font of Agonies|Ravnica Allegiance|74|R|{B}|Enchantment|||Whenever you pay life, put that many blood counters on Font of Agonies.${1}{B}, Remove four blood counters from Font of Agonies: Destroy target creature.| +Grotesque Demise|Ravnica Allegiance|75|C|{2}{B}|Instant|||Exile target creature with power 3 or less.| +Gutterbones|Ravnica Allegiance|76|R|{B}|Creature - Skeleton Warrior|2|1|Gutterbones enters the battlefield tapped.${1}{B}: Return Gutterbones from your graveyard to your hand. Activate this ability only during your turn and only if an opponent lost life this turn.| +Ill-Gotten Inheritance|Ravnica Allegiance|77|C|{3}{B}|Enchantment|||At the beginning of your upkeep, Ill-Gotten Inheritance deals 1 damage to each opponent and you gain 1 life.${5}{B}, Sacrifice Ill-Gotten Inheritance: It deals 4 damage to target opponent and you gain 4 life.| +Noxious Groodion|Ravnica Allegiance|78|C|{2}{B}|Creature - Beast|2|2|Deathtouch| +Orzhov Enforcer|Ravnica Allegiance|79|U|{1}{B}|Creature - Human Rogue|1|2|Deathtouch$Afterlife 1| +Orzhov Racketeers|Ravnica Allegiance|80|U|{4}{B}|Creature - Human Rogue|3|2|Whenever Orzhov Racketeers deals combat damage to a player, that player discards a card.$Afterlife 2| +Pestilent Spirit|Ravnica Allegiance|81|R|{2}{B}|Creature - Spirit|3|2|Menace, deathtouch$Instant and sorcery spells you control have deathtouch.| +Plague Wight|Ravnica Allegiance|82|C|{1}{B}|Creature - Zombie|2|1|Whenever Plague Wight becomes blocked, each creature blocking it gets -1/-1 until end of turn.| +Priest of Forgotten Gods|Ravnica Allegiance|83|R|{1}{B}|Creature - Human Cleric|1|2|{T}, Sacrifice two other creatures: Any number of target players each lose 2 life and sacrifice a creature. You add {B}{B} and draw a card.| +Rakdos Trumpeter|Ravnica Allegiance|84|C|{1}{B}|Creature - Human Shaman|1|3|Menace${3}{R}: Rakdos Trumpeter gets +2/+0 until end of turn.| +Spawn of Mayhem|Ravnica Allegiance|85|M|{2}{B}{B}|Creature - Demon|4|4|Spectacle {1}{B}{B}$Flying, trample$At the beginning of your upkeep, Spawn of Mayhem deals 1 damage to each player. Then if you have 10 or less life, put a +1/+1 counter on Spawn of Mayhem.| +Spire Mangler|Ravnica Allegiance|86|U|{2}{B}|Creature - Insect|2|1|Flash$Flying$When Spire Mangler enters the battlefield, target creature with flying you control gets +2/+0 until end of turn.| +Thirsting Shade|Ravnica Allegiance|87|C|{B}|Creature - Shade|1|1|Lifelink${2}{B}: Thirsting Shade gets +1/+1 until end of turn.| +Undercity Scavenger|Ravnica Allegiance|88|C|{3}{B}|Creature - Ogre Warrior|3|3|When Undercity Scavenger enters the battlefield, you may sacrifice another creature. If you do, put two +1/+1 counters on Undercity Scavenger, then scry 2.| +Undercity's Embrace|Ravnica Allegiance|89|C|{2}{B}|Instant|||Target opponent sacrifices a creature. If you control a creature with power 4 or greater, you gain 4 life.| +Vindictive Vampire|Ravnica Allegiance|90|U|{3}{B}|Creature - Vampire|2|3|Whenever another creature you control dies, Vindictive Vampire deals 1 damage to each opponent and you gain 1 life.| +Act of Treason|Ravnica Allegiance|91|C|{2}{R}|Sorcery|||Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn.| +Amplifire|Ravnica Allegiance|92|R|{2}{R}{R}|Creature - Elemental|1|1|At the beginning of your upkeep, reveal cards from the top of your library until you reveal a creature card. Until your next turn, Amplifire's base power becomes twice that card's power and its base toughness becomes twice that card's toughness. Put the revealed cards on the bottom of your library in a random order.| +Burn Bright|Ravnica Allegiance|93|C|{2}{R}|Instant|||Creatures you control get +2/+0 until end of turn.| +Burning-Tree Vandal|Ravnica Allegiance|94|C|{2}{R}|Creature - Human Rogue|2|1|Riot$Whenever Burning-Tree Vandal attacks, you may discard a card. If you do, draw a card.| +Cavalcade of Calamity|Ravnica Allegiance|95|U|{1}{R}|Enchantment|||Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking.| +Clamor Shaman|Ravnica Allegiance|96|U|{2}{R}|Creature - Goblin Shaman|1|1|Riot$Whenever Clamor Shaman attacks, target creature an opponent controls can't block this turn.| +Dagger Caster|Ravnica Allegiance|97|U|{3}{R}|Creature - Viashino Rogue|2|3|When Dagger Caster enters the battlefield, it deals 1 damage to each opponent and 1 damage to each creature your opponents control.| +Deface|Ravnica Allegiance|98|C|{R}|Sorcery|||Choose one —$• Destroy target artifact.$• Destroy target creature with defender.| +Electrodominance|Ravnica Allegiance|99|R|{X}{R}{R}|Instant|||Electrodominance deals X damage to any target. You may cast a card with converted mana cost X or less from your hand without paying its mana cost.| +Feral Maaka|Ravnica Allegiance|100|C|{1}{R}|Creature - Cat|2|2|| +Flames of the Raze-Boar|Ravnica Allegiance|101|U|{5}{R}|Instant|||Flames of the Raze-Boar deals 4 damage to target creature an opponent controls. Then Flames of the Raze-Boar deals 2 damage to each other creature that player controls if you control a creature with power 4 or greater.| +Gates Ablaze|Ravnica Allegiance|102|U|{2}{R}|Sorcery|||Gates Ablaze deals X damage to each creature, where X is the number of Gates you control.| +Ghor-Clan Wrecker|Ravnica Allegiance|103|C|{3}{R}|Creature - Human Warrior|2|2|Riot$Menace| +Goblin Gathering|Ravnica Allegiance|104|C|{2}{R}|Sorcery|||Create a number of 1/1 red Goblin creature tokens equal to two plus the number of cards named Goblin Gathering in your graveyard.| +Gravel-Hide Goblin|Ravnica Allegiance|105|C|{1}{R}|Creature - Goblin Shaman|2|1|{3}{G}: Gravel-Hide Goblin gets +2/+2 until end of turn.| +Immolation Shaman|Ravnica Allegiance|106|R|{1}{R}|Creature - Viashino Shaman|1|3|Whenever an opponent activates an ability of an artifact, creature, or land that isn't a mana ability, Immolation Shaman deals 1 damage to that player.${3}{R}{R}: Immolation Shaman gets +3/+3 and gains menace until end of turn.| +Light Up the Stage|Ravnica Allegiance|107|U|{2}{R}|Sorcery|||Spectacle {R}$Exile the top two cards of your library. Until the end of your next turn, you may play those cards.| +Mirror March|Ravnica Allegiance|108|R|{5}{R}|Enchantment|||Whenever a nontoken creature enters the battlefield under your control, flip a coin until you lose a flip. For each flip you won, create a token that's a copy of that creature. Those tokens gain haste. Exile them at the beginning of the next end step.| +Rix Maadi Reveler|Ravnica Allegiance|109|R|{1}{R}|Creature - Human Shaman|2|2|Spectacle {2}{B}{R}$When Rix Maadi Reveler enters the battlefield, discard a card, then draw a card. If Rix Maadi Reveler's spectacle cost was paid, instead discard your hand, then draw three cards.| +Rubble Reading|Ravnica Allegiance|110|C|{3}{R}|Sorcery|||Destroy target land. Scry 2.| +Rubblebelt Recluse|Ravnica Allegiance|111|C|{4}{R}|Creature - Ogre Berserker|6|5|Rubblebelt Recluse attacks each combat if able.| +Rumbling Ruin|Ravnica Allegiance|112|U|{5}{R}|Creature - Elemental|6|6|When Rumbling Ruin enters the battlefield, count the number of +1/+1 counters on creatures you control. Creatures your opponents control with power less than or equal to that number can't block this turn.| +Scorchmark|Ravnica Allegiance|113|C|{1}{R}|Instant|||Scorchmark deals 2 damage to target creature. If that creature would die this turn, exile it instead.| +Skarrgan Hellkite|Ravnica Allegiance|114|M|{3}{R}{R}|Creature - Dragon|4|4|Riot$Flying${3}{R}: Skarrgan Hellkite deals 2 damage divided as you choose among one or two targets. Activate this ability only if Skarrgan Hellkite has a +1/+1 counter on it.| +Skewer the Critics|Ravnica Allegiance|115|C|{2}{R}|Sorcery|||Spectacle {R}$Skewer the Critics deals 3 damage to any target.| +Smelt-Ward Ignus|Ravnica Allegiance|116|U|{1}{R}|Creature - Elemental|2|1|{2}{R}, Sacrifice Smelt-Ward Ignus: Gain control of target creature with power 3 or less until end of turn. Untap that creature. It gains haste until end of turn. Activate this ability only any time you could cast a sorcery.| +Spear Spewer|Ravnica Allegiance|117|C|{R}|Creature - Goblin Warrior|0|2|Defender${T}: Spear Spewer deals 1 damage to each player.| +Spikewheel Acrobat|Ravnica Allegiance|118|C|{3}{R}|Creature - Human Rogue|5|2|Spectacle {2}{R}| +Storm Strike|Ravnica Allegiance|119|C|{R}|Instant|||Target creature gets +1/+0 and gains first strike until end of turn. Scry 1.| +Tin Street Dodger|Ravnica Allegiance|120|U|{R}|Creature - Goblin Rogue|1|1|Haste${R}: Tin Street Dodger can't be blocked this turn except by creatures with defender.| +Axebane Beast|Ravnica Allegiance|121|C|{3}{G}|Creature - Beast|3|4|| +Biogenic Ooze|Ravnica Allegiance|122|M|{3}{G}{G}|Creature - Ooze|2|2|When Biogenic Ooze enters the battlefield, create a 2/2 green Ooze creature token.$At the beginning of your end step, put a +1/+1 counter on each Ooze you control.${1}{G}{G}{G}: Create a 2/2 green Ooze creature token.| +Biogenic Upgrade|Ravnica Allegiance|123|U|{4}{G}{G}|Sorcery|||Distribute three +1/+1 counters among one, two, or three target creatures, then double the number of +1/+1 counters on each of those creatures.| +End-Raze Forerunners|Ravnica Allegiance|124|R|{5}{G}{G}{G}|Creature - Boar|7|7|Vigilance, trample, haste$When End-Raze Forerunners enters the battlefield, other creatures you control get +2/+2 and gain vigilance and trample until end of turn.| +Enraged Ceratok|Ravnica Allegiance|125|U|{2}{G}{G}|Creature - Rhino|4|4|Enraged Ceratok can't be blocked by creatures with power 2 or less.| +Gatebreaker Ram|Ravnica Allegiance|126|U|{2}{G}|Creature - Sheep|2|2|Gatebreaker Ram gets +1/+1 for each Gate you control.$As long as you control two or more Gates, Gatebreaker Ram has vigilance and trample.| +Gift of Strength|Ravnica Allegiance|127|C|{1}{G}|Instant|||Target creature gets +3/+3 and gains reach until end of turn.| +Growth-Chamber Guardian|Ravnica Allegiance|128|R|{1}{G}|Creature - Elf Crab Warrior|2|2|{2}{G}: Adapt 2.$Whenever one or more +1/+1 counters are put on Growth-Chamber Guardian, you may search your library for a card named Growth-Chamber Guardian, reveal it, put it into your hand, then shuffle your library.| +Gruul Beastmaster|Ravnica Allegiance|129|U|{3}{G}|Creature - Human Shaman|2|2|Riot$Whenever Gruul Beastmaster attacks, another target creature you control gets +X/+0 until end of turn, where X is Gruul Beastmaster's power.| +Guardian Project|Ravnica Allegiance|130|R|{3}{G}|Enchantment|||Whenever a nontoken creature enters the battlefield under your control, if that creature does not have the same name as another creature you control or a creature card in your graveyard, draw a card.| +Incubation Druid|Ravnica Allegiance|131|R|{1}{G}|Creature - Elf Druid|0|2|{T}: Add one mana of any type that a land you control could produce. If Incubation Druid has a +1/+1 counter on it, add three mana of that type instead.${3}{G}{G}: Adapt 3.| +Mammoth Spider|Ravnica Allegiance|132|C|{4}{G}|Creature - Spider|3|5|Reach| +Open the Gates|Ravnica Allegiance|133|C|{G}|Sorcery|||Search your library for a basic land card or a Gate card, reveal it, put it into your hand, then shuffle your library.| +Rampage of the Clans|Ravnica Allegiance|134|R|{3}{G}|Instant|||Destroy all artifacts and enchantments. For each permanent destroyed this way, its controller creates a 3/3 green Centaur creature token.| +Rampaging Rendhorn|Ravnica Allegiance|135|C|{4}{G}|Creature - Beast|4|4|Riot| +Regenesis|Ravnica Allegiance|136|U|{3}{G}{G}|Instant|||Return up to two target permanent cards from your graveyard to your hand.| +Root Snare|Ravnica Allegiance|137|C|{1}{G}|Instant|||Prevent all combat damage that would be dealt this turn.| +Sagittars' Volley|Ravnica Allegiance|138|C|{2}{G}|Instant|||Destroy target creature with flying. Sagittars' Volley deals 1 damage to each creature with flying your opponents control.| +Saruli Caretaker|Ravnica Allegiance|139|C|{G}|Creature - Dryad|0|3|Defender${T}, Tap an untapped creature you control: Add one mana of any color.| +Sauroform Hybrid|Ravnica Allegiance|140|C|{1}{G}|Creature - Human Lizard Warrior|2|2|{4}{G}{G}: Adapt 4.| +Silhana Wayfinder|Ravnica Allegiance|141|U|{1}{G}|Creature - Elf Scout|2|1|When Silhana Wayfinder enters the battlefield, look at the top four cards of your library. You may reveal a creature or land card from among them and put it on top of your library. Put the rest on the bottom of your library in a random order.| +Steeple Creeper|Ravnica Allegiance|142|C|{2}{G}|Creature - Frog Snake|4|2|{3}{U}: Steeple Creeper gains flying until end of turn.| +Stony Strength|Ravnica Allegiance|143|C|{G}|Instant|||Put a +1/+1 counter on target creature you control. Untap that creature.| +Sylvan Brushstrider|Ravnica Allegiance|144|C|{2}{G}|Creature - Beast|3|2|When Sylvan Brushstrider enters the battlefield, you gain 2 life.| +Territorial Boar|Ravnica Allegiance|145|C|{1}{G}|Creature - Boar|2|2|Whenever a creature with power 4 or greater enters the battlefield under your control, Territorial Boar gets +1/+1 and gains vigilance until end of turn.| +Titanic Brawl|Ravnica Allegiance|146|C|{1}{G}|Instant|||This spell costs {1} less to cast if it targets a creature you control with a +1/+1 counter on it.$Target creature you control fights target creature you don't control.| +Tower Defense|Ravnica Allegiance|147|U|{1}{G}|Instant|||Creatures you control get +0/+5 and gain reach until end of turn.| +Trollbred Guardian|Ravnica Allegiance|148|U|{4}{G}|Creature - Troll Frog Warrior|5|5|{2}{G}: Adapt 2.$Each creature you control with a +1/+1 counter on it has trample.| +Wilderness Reclamation|Ravnica Allegiance|149|U|{3}{G}|Enchantment|||At the beginning of your end step, untap all lands you control.| +Wrecking Beast|Ravnica Allegiance|150|C|{5}{G}{G}|Creature - Beast|6|6|Riot$Trample| +Absorb|Ravnica Allegiance|151|R|{W}{U}{U}|Instant|||Counter target spell. You gain 3 life.| +Aeromunculus|Ravnica Allegiance|152|C|{1}{G}{U}|Creature - Homunculus Mutant|2|3|Flying${2}{G}{U}: Adapt 1.| +Applied Biomancy|Ravnica Allegiance|153|C|{G}{U}|Instant|||Choose one or both —$• Target creature gets +1/+1 until end of turn.$• Return target creature to its owner's hand.| +Azorius Knight-Arbiter|Ravnica Allegiance|154|C|{3}{W}{U}|Creature - Human Knight|2|5|Vigilance$Azorius Knight-Arbiter can't be blocked.| +Azorius Skyguard|Ravnica Allegiance|155|U|{4}{W}{U}|Creature - Human Knight|3|3|Flying, first strike$Creatures your opponents control get -1/-0.| +Basilica Bell-Haunt|Ravnica Allegiance|156|U|{W}{W}{B}{B}|Creature - Spirit|3|4|When Basilica Bell-Haunt enters the battlefield, each opponent discards a card and you gain 3 life.| +Bedevil|Ravnica Allegiance|157|R|{B}{B}{R}|Instant|||Destroy target artifact, creature, or planeswalker.| +Biomancer's Familiar|Ravnica Allegiance|158|R|{G}{U}|Creature - Mutant|2|2|Activated abilities of creatures you control cost {2} less to activate. This effect can't reduce the amount of mana an ability costs to activate to less than one mana.${T}: The next time target creature adapts this turn, it adapts as though it had no +1/+1 counters on it.| +Bolrac-Clan Crusher|Ravnica Allegiance|159|U|{3}{R}{G}|Creature - Ogre Warrior|4|4|{T}, Remove a +1/+1 counter from a creature you control: Bolrac-Clan Crusher deals 2 damage to any target.| +Captive Audience|Ravnica Allegiance|160|M|{5}{B}{R}|Enchantment|||Captive Audience enters the battlefield under the control of an opponent of your choice.$At the beginning of your upkeep, choose one that hasn't been chosen —$• Your life total becomes 4.$• Discard your hand.$• Each opponent creates five 2/2 black Zombie creature tokens.| +Cindervines|Ravnica Allegiance|161|R|{R}{G}|Enchantment|||Whenever an opponent casts a noncreature spell, Cindervines deals 1 damage to that player.${1}, Sacrifice Cindervines: Destroy target artifact or enchantment. Cindervines deals 2 damage to that permanent's controller.| +Clan Guildmage|Ravnica Allegiance|162|U|{R}{G}|Creature - Human Shaman|2|2|{1}{R}, {T}: Target creature can't block this turn.${2}{G}, {T}: Target land you control becomes a 4/4 Elemental creature with haste until end of turn. It's still a land.| +Combine Guildmage|Ravnica Allegiance|163|U|{G}{U}|Creature - Merfolk Wizard|2|2|{1}{G}, {T}: This turn, each creature you control enters the battlefield with an additional +1/+1 counter on it.${1}{U}, {T}: Move a +1/+1 counter from target creature you control onto another target creature you control.| +Cult Guildmage|Ravnica Allegiance|164|U|{B}{R}|Creature - Human Shaman|2|2|{3}{B}, {T}: Target player discards a card. Activate this ability only any time you could cast a sorcery.${R}, {T}: Cult Guildmage deals 1 damage to target opponent or planeswalker.| +Deputy of Detention|Ravnica Allegiance|165|R|{1}{W}{U}|Creature - Vedalken Wizard|1|3|When Deputy of Detention enters the battlefield, exile target nonland permanent an opponent controls and all other nonland permanents that player controls with the same name as that permanent until Deputy of Detention leaves the battlefield.| +Domri, Chaos Bringer|Ravnica Allegiance|166|M|{2}{R}{G}|Legendary Planeswalker - Domri|5|+1: Add {R} or {G}. If that mana is spent on a creature spell, it gains riot.$−3: Look at the top four cards of your library. You may reveal up to two creature cards from among them and put them into your hand. Put the rest on the bottom of your library in a random order.$−8: You get an emblem with "At the beginning of each end step, create a 4/4 red and green Beast creature token with trample."| +Dovin, Grand Arbiter|Ravnica Allegiance|167|M|{1}{W}{U}|Legendary Planeswalker - Dovin|3|+1: Until end of turn, whenever a creature you control deals combat damage to a player, put a loyalty counter on Dovin, Grand Arbiter.$-1: Create a 1/1 colorless Thopter artifact creature token with flying. You gain 1 life.$-7: Look at the top ten cards of your library. Put three of them into your hand and the rest on the bottom of your library in a random order.| +Dovin's Acuity|Ravnica Allegiance|168|U|{1}{W}{U}|Enchantment|||When Dovin's Acuity enters the battlefield, you gain 2 life and draw a card.$Whenever you cast an instant spell during your main phase, you may return Dovin's Acuity to its owner's hand.| +Emergency Powers|Ravnica Allegiance|169|M|{5}{W}{U}|Instant|||Each player shuffles their hand and graveyard into their library, then draws seven cards. Exile Emergency Powers.$Addendum — If you cast this spell during your main phase, you may put a permanent card with converted mana cost 7 or less from your hand onto the battlefield.| +Ethereal Absolution|Ravnica Allegiance|170|R|{4}{W}{B}|Enchantment|||Creatures you control get +1/+1.$Creatures your opponents control get -1/-1.${2}{W}{B}: Exile target card from an opponent's graveyard. If it was a creature card, you create a 1/1 white and black Spirit creature token with flying.| +Final Payment|Ravnica Allegiance|171|C|{W}{B}|Instant|||As an additional cost to cast this spell, pay 5 life or sacrifice a creature or enchantment.$Destroy target creature.| +Fireblade Artist|Ravnica Allegiance|172|U|{B}{R}|Creature - Human Shaman|2|2|Haste$At the beginning of your upkeep, you may sacrifice a creature. When you do, Fireblade Artist deals 2 damage to target opponent or planeswalker.| +Frenzied Arynx|Ravnica Allegiance|173|C|{2}{R}{G}|Creature - Cat Beast|3|3|Riot$Trample${4}{R}{G}: Frenzied Arynx gets +3/+0 until end of turn.| +Frilled Mystic|Ravnica Allegiance|174|U|{G}{G}{U}{U}|Creature - Elf Lizard Wizard|3|2|Flash$When Frilled Mystic enters the battlefield, you may counter target spell.| +Galloping Lizrog|Ravnica Allegiance|175|U|{3}{G}{U}|Creature - Frog Lizard|3|3|Trample$When Galloping Lizrog enters the battlefield, you may remove any number of +1/+1 counters from among creatures you control. If you do, put twice that many +1/+1 counters on Galloping Lizrog.| +Get the Point|Ravnica Allegiance|176|C|{3}{B}{R}|Instant|||Destroy target creature. Scry 1.| +Grasping Thrull|Ravnica Allegiance|177|C|{3}{W}{B}|Creature - Thrull|3|3|Flying$When Grasping Thrull enters the battlefield, it deals 2 damage to each opponent and you gain 2 life.| +Growth Spiral|Ravnica Allegiance|178|C|{G}{U}|Instant|||Draw a card. You may put a land card from your hand onto the battlefield.| +Gruul Spellbreaker|Ravnica Allegiance|179|R|{1}{R}{G}|Creature - Ogre Warrior|3|3|Riot$Trample$As long as it's your turn, you and Gruul Spellbreaker have hexproof.| +Gyre Engineer|Ravnica Allegiance|180|U|{1}{G}{U}|Creature - Vedalken Wizard|1|1|{T}: Add {G}{U}.| +Hackrobat|Ravnica Allegiance|181|U|{1}{B}{R}|Creature - Human Rogue|2|3|Spectacle {B}{R}${B}: Hackrobat gains deathtouch until end of turn.${R}: Hackrobat gets +2/-2 until end of turn.| +High Alert|Ravnica Allegiance|182|U|{1}{W}{U}|Enchantment|||Each creature you control assigns combat damage equal to its toughness rather than its power.$Creatures you control can attack as though they didn't have defender.${2}{W}{U}: Untap target creature.| +Hydroid Krasis|Ravnica Allegiance|183|M|{X}{G}{U}|Creature - Jellyfish Hydra Beast|0|0|When you cast this spell, you gain half X life and draw half X cards. Round down each time.$Flying, trample$Hydroid Krasis enters the battlefield with X +1/+1 counters on it.| +Imperious Oligarch|Ravnica Allegiance|184|C|{W}{B}|Creature - Human Cleric|2|1|Vigilance$Afterlife 1| +Judith, the Scourge Diva|Ravnica Allegiance|185|R|{1}{B}{R}|Legendary Creature - Human Shaman|2|2|Other creatures you control get +1/+0.$Whenever a nontoken creature you control dies, Judith, the Scourge Diva deals 1 damage to any target.| +Kaya, Orzhov Usurper|Ravnica Allegiance|186|M|{1}{W}{B}|Legendary Planeswalker - Kaya|3|+1: Exile up to two target cards from a single graveyard. You gain 2 life if at least one creature card was exiled this way.$-1: Exile target nonland permanent with converted mana cost 1 or less.$-5: Kaya, Orzhov Usurper deals damage to target player equal to the number of cards that player owns in exile and you gain that much life.| +Kaya's Wrath|Ravnica Allegiance|187|R|{W}{W}{B}{B}|Sorcery|||Destroy all creatures. You gain life equal to the number of creatures you controlled that were destroyed this way.| +Knight of the Last Breath|Ravnica Allegiance|188|U|{5}{W}{B}|Creature - Giant Knight|4|4|{3}, Sacrifice another nontoken creature: Create a 1/1 white and black Spirit creature token with flying.$Afterlife 3| +Lavinia, Azorius Renegade|Ravnica Allegiance|189|R|{W}{U}|Legendary Creature - Human Soldier|2|2|Each opponent can't cast noncreature spells with converted mana cost greater than the number of lands that player controls.$Whenever an opponent casts a spell, if no mana was spent to cast it, counter that spell.| +Lawmage's Binding|Ravnica Allegiance|190|C|{1}{W}{U}|Enchantment - Aura|||Flash$Enchant creature$Enchanted creature can't attack or block, and its activated abilities can't be activated.| +Macabre Mockery|Ravnica Allegiance|191|U|{2}{B}{R}|Instant|||Put target creature card from an opponent's graveyard onto the battlefield under your control. It gets +2/+0 and gains haste until end of turn. Sacrifice it at the beginning of the next end step.| +Mortify|Ravnica Allegiance|192|U|{1}{W}{B}|Instant|||Destroy target creature or enchantment.| +Nikya of the Old Ways|Ravnica Allegiance|193|R|{3}{R}{G}|Legendary Creature - Centaur Druid|5|5|You can't cast noncreature spells.$Whenever you tap a land for mana, add one mana of any type that land produced.| +Pitiless Pontiff|Ravnica Allegiance|194|U|{W}{B}|Creature - Vampire Cleric|2|2|{1}, Sacrifice another creature: Pitiless Pontiff gains deathtouch and indestructible until end of turn.| +Prime Speaker Vannifar|Ravnica Allegiance|195|M|{2}{G}{U}|Legendary Creature - Elf Ooze Wizard|2|4|{T}, Sacrifice another creature: Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card onto the battlefield, then shuffle your library. Activate this ability only any time you could cast a sorcery.| +Rafter Demon|Ravnica Allegiance|196|C|{2}{B}{R}|Creature - Demon|4|2|Spectacle {3}{B}{R}$When Rafter Demon enters the battlefield, if its spectacle cost was paid, each opponent discards a card.| +Rakdos Firewheeler|Ravnica Allegiance|197|U|{B}{B}{R}{R}|Creature - Human Rogue|4|3|When Rakdos Firewheeler enters the battlefield, it deals 2 damage to target opponent and 2 damage to up to one target creature or planeswalker.| +Rakdos Roustabout|Ravnica Allegiance|198|C|{1}{B}{R}|Creature - Ogre Warrior|3|2|Whenever Rakdos Roustabout becomes blocked, it deals 1 damage to the player or planeswalker it's attacking.| +Rakdos, the Showstopper|Ravnica Allegiance|199|M|{4}{B}{R}|Legendary Creature - Demon|6|6|Flying, trample$When Rakdos, the Showstopper enters the battlefield, flip a coin for each creature that isn't a Demon, Devil, or Imp. Destroy each creature whose coin comes up tails.| +Ravager Wurm|Ravnica Allegiance|200|M|{3}{R}{G}{G}|Creature - Wurm|4|5|Riot$When Ravager Wurm enters the battlefield, choose up to one —$• Ravager Wurm fights target creature you don't control.$• Destroy target land with an activated ability that isn't a mana ability.| +Rhythm of the Wild|Ravnica Allegiance|201|U|{1}{R}{G}|Enchantment|||Creature spells you control can't be countered.$Nontoken creatures you control have riot.| +Rubblebelt Runner|Ravnica Allegiance|202|C|{1}{R}{G}|Creature - Viashino Warrior|3|3|Rubblebelt Runner can't be blocked by creature tokens.| +Savage Smash|Ravnica Allegiance|203|C|{1}{R}{G}|Sorcery|||Target creature you control gets +2/+2 until end of turn. It fights target creature you don't control.| +Senate Guildmage|Ravnica Allegiance|204|U|{W}{U}|Creature - Human Wizard|2|2|{W}, {T}: You gain 2 life.${U}, {T}: Draw a card, then discard a card.| +Seraph of the Scales|Ravnica Allegiance|205|M|{2}{W}{B}|Creature - Angel|4|3|Flying${W}: Seraph of the Scales gains vigilance until end of turn.${B}: Seraph of the Scales gains deathtouch until end of turn.$Afterlife 2| +Sharktocrab|Ravnica Allegiance|206|U|{2}{G}{U}|Creature - Fish Octopus Crab|4|4|{2}{G}{U}: Adapt 1.$Whenever one or more +1/+1 counter are put on Sharktocrab, tap target creature an opponent controls. That creature doesn't untap during its controller's next untap step.| +Simic Ascendancy|Ravnica Allegiance|207|R|{G}{U}|Enchantment|||{1}{G}{U}: Put a +1/+1 counter on target creature you control.$Whenever one or more +1/+1 counters are put on a creature you control, put that many growth counters on Simic Ascendancy.$At the beginning of your upkeep, if Simic Ascendancy has twenty or more growth counters on it, you win the game.| +Sphinx of New Prahv|Ravnica Allegiance|208|U|{W}{W}{U}{U}|Creature - Sphinx|4|3|Flying, vigilance$Spells your opponents cast that target Sphinx of New Prahv cost {2} more to cast.| +Sphinx's Insight|Ravnica Allegiance|209|C|{2}{W}{U}|Instant|||Draw two cards.$Addendum — If you cast this spell during your main phase, you gain 2 life.| +Sunder Shaman|Ravnica Allegiance|210|U|{R}{R}{G}{G}|Creature - Giant Shaman|5|5|Sunder Shaman can't be blocked by more than one creature.$Whenever Sunder Shaman deals combat damage to a player, destroy target artifact or enchantment that player controls.| +Syndicate Guildmage|Ravnica Allegiance|211|U|{W}{B}|Creature - Human Cleric|2|2|{1}{W}, {T}: Tap target creature with power 4 or greater.${4}{B}, {T}: Syndicate Guildmage deals 2 damage to target opponent or planeswalker.| +Teysa Karlov|Ravnica Allegiance|212|R|{2}{W}{B}|Legendary Creature - Human Advisor|2|4|If a creature dying causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time.$Creature tokens you control have vigilance and lifelink.| +Theater of Horrors|Ravnica Allegiance|213|R|{1}{B}{R}|Enchantment|||At the beginning of your upkeep, exile the top card of your library.$During your turn, if an opponent lost life this turn, you may play cards exiled with Theater of Horrors.${3}{R}: Theater of Horrors deals 1 damage to target opponent or planeswalker.| +Zegana, Utopian Speaker|Ravnica Allegiance|214|R|{2}{G}{U}|Legendary Creature - Merfolk Wizard|4|4|When Zegana, Utopian Speaker enters the battlefield, if you control another creature with a +1/+1 counter on it, draw a card.${4}{G}{U}: Adapt 4.$Each creature you control with a +1/+1 counter on it has trample.| +Zhur-Taa Goblin|Ravnica Allegiance|215|U|{R}{G}|Creature - Goblin Berserker|2|2|Riot| +Footlight Fiend|Ravnica Allegiance|216|C|{B/R}|Creature - Devil|1|1|When Footlight Fiend dies, it deals 1 damage to any target.| +Rubble Slinger|Ravnica Allegiance|217|C|{2}{R/G}|Creature - Human Warrior|2|3|Reach| +Scuttlegator|Ravnica Allegiance|218|C|{4}{G/U}{G/U}|Creature - Crab Turtle Crocodile|6|6|Defender${6}{G/U}{G/U}: Adapt 3.$As long as Scuttlegator has a +1/+1 counter on it, it can attack as though it didn't have defender.| +Senate Griffin|Ravnica Allegiance|219|C|{2}{W/U}{W/U}|Creature - Griffin|3|2|Flying$When Senate Griffin enters the battlefield, scry 1.| +Vizkopa Vampire|Ravnica Allegiance|220|C|{2}{W/B}|Creature - Vampire|3|1|Lifelink| +Bedazzle|Ravnica Allegiance|221|R|{4}{B}{R}|Instant|||Destroy target nonbasic land. Bedazzle deals 2 damage to target opponent or planeswalker.| +Bedeck|Ravnica Allegiance|221|R|{B/R}{B/R}|Instant|||Target creature gets +3/-3 until end of turn.| +Carnage|Ravnica Allegiance|222|U|{2}{B}{R}|Sorcery|||Carnage deals 3 damage to target opponent. That player discards two cards.| +Carnival|Ravnica Allegiance|222|U|{B/R}|Instant|||Carnival deals 1 damage to target creature or planeswalker and 1 damage to that permanent's controller.| +Collision|Ravnica Allegiance|223|U|{1}{R/G}|Instant|||Collision deals 6 damage to target creature with flying.| +Colossus|Ravnica Allegiance|223|U|{R}{G}|Instant|||Target creature gets +4/+2 and gains trample until end of turn.| +Consecrate|Ravnica Allegiance|224|U|{1}{W/B}|Instant|||Exile target card from a graveyard.$Draw a card.| +Consume|Ravnica Allegiance|224|U|{2}{W}{B}|Sorcery|||Target player sacrifices a creature with the greatest power among creatures they control. You gain life equal to its power.| +Deploy|Ravnica Allegiance|225|U|{2}{W}{U}|Instant|||Create two 1/1 colorless Thopter artifact creature tokens with flying, then you gain 1 life for each creature you control.| +Depose|Ravnica Allegiance|225|U|{1}{W/U}|Instant|||Tap target creature.$Draw a card.| +Incongruity|Ravnica Allegiance|226|U|{1}{G}{U}|Instant|||Exile target creature. That creature's controller creates a 3/3 green Frog Lizard creature token.| +Incubation|Ravnica Allegiance|226|U|{G/U}|Sorcery|||Look at the top five cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Replicate|Ravnica Allegiance|227|R|{1}{G}{U}|Sorcery|||Create a token that's a copy of target creature you control.| +Repudiate|Ravnica Allegiance|227|R|{G/U}{G/U}|Instant|||Counter target activated or triggered ability.| +Revenge|Ravnica Allegiance|228|R|{4}{W}{B}|Sorcery|||Double your life total. Target opponent loses half their life, rounded up.| +Revival|Ravnica Allegiance|228|R|{W/B}{W/B}|Sorcery|||Return target creature card with converted mana cost 3 or less from your graveyard to the battlefield.| +Thrash|Ravnica Allegiance|229|R|{R/G}{R/G}|Instant|||Target creature you control deals damage equal to its power to target creature or planeswalker you don't control.| +Threat|Ravnica Allegiance|229|R|{2}{R}{G}|Sorcery|||Create a 4/4 red and green Beast creature token with trample.| +Warden|Ravnica Allegiance|230|R|{3}{W}{U}|Sorcery|||Create a 4/4 white and blue Sphinx creature token with flying and vigilance.| +Warrant|Ravnica Allegiance|230|R|{W/U}{W/U}|Instant|||Put target attacking or blocking creature on top of its owner's library.| +Azorius Locket|Ravnica Allegiance|231|C|{3}|Artifact|||{T}: Add {W} or {U}.${W/U}{W/U}{W/U}{W/U}, {T}, Sacrifice Azorius Locket: Draw two cards.| +Gate Colossus|Ravnica Allegiance|232|U|{8}|Artifact Creature - Construct|8|8|This spell costs {1} less to cast for each Gate you control.$Gate Colossus can't be blocked by creatures with power 2 or less.$Whenever a Gate enters the battlefield under your control, you may put Gate Colossus from your graveyard on top of your library.| +Glass of the Guildpact|Ravnica Allegiance|233|R|{2}|Artifact|||Multicolored creatures you control get +1/+1.| +Gruul Locket|Ravnica Allegiance|234|C|{3}|Artifact|||{T}: Add {R} or {G}.${R/G}{R/G}{R/G}{R/G}, {T}, Sacrifice Gruul Locket: Draw two cards.| +Junktroller|Ravnica Allegiance|235|U|{4}|Artifact Creature - Golem|0|6|Defender${T}: Put target card from a graveyard on the bottom of its owner's library.| +Orzhov Locket|Ravnica Allegiance|236|C|{3}|Artifact|||{T}: Add {W} or {B}.${W/B}{W/B}{W/B}{W/B}, {T}, Sacrifice Orzhov Locket: Draw two cards.| +Rakdos Locket|Ravnica Allegiance|237|C|{3}|Artifact|||{T}: Add {B} or {R}.${B/R}{B/R}{B/R}{B/R}, {T}, Sacrifice Rakdos Locket: Draw two cards.| +Scrabbling Claws|Ravnica Allegiance|238|U|{1}|Artifact|||{T}: Target player exiles a card from their graveyard.${1}, Sacrifice Scrabbling Claws: Exile target card from a graveyard. Draw a card.| +Screaming Shield|Ravnica Allegiance|239|U|{1}|Artifact - Equipment|||Equipped creature gets +0/+3 and has "{2}, {T}: Target player puts the top three cards of their library into their graveyard."$Equip {3}| +Simic Locket|Ravnica Allegiance|240|C|{3}|Artifact|||{T}: Add {G} or {U}.${G/U}{G/U}{G/U}{G/U}, {T}, Sacrifice Simic Locket: Draw two cards.| +Sphinx of the Guildpact|Ravnica Allegiance|241|U|{7}|Artifact Creature - Sphinx|5|5|Sphinx of the Guildpact is all colors.$Flying$Hexproof from monocolored| +Tome of the Guildpact|Ravnica Allegiance|242|R|{5}|Artifact|||Whenever you cast a multicolored spell, draw a card.${T}: Add one mana of any color.| +Azorius Guildgate|Ravnica Allegiance|243|C||Land - Gate|||Azorius Guildgate enters the battlefield tapped.${T}: Add {W} or {U}.| +Blood Crypt|Ravnica Allegiance|245|R||Land - Swamp Mountain|||({T}: Add {B} or {R}.)$As Blood Crypt enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| +Breeding Pool|Ravnica Allegiance|246|R||Land - Forest Island|||({T}: Add {G} or {U}.)$As Breeding Pool enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| +Gateway Plaza|Ravnica Allegiance|247|C||Land - Gate|||Gateway Plaza enters the battlefield tapped.$When Gateway Plaza enters the battlefield, sacrifice it unless you pay {1}.${T}: Add one mana of any color.| +Godless Shrine|Ravnica Allegiance|248|R||Land - Plains Swamp|||({T}: Add {W} or {B}.)$As Godless Shrine enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| +Gruul Guildgate|Ravnica Allegiance|249|C||Land - Gate|||Gruul Guildgate enters the battlefield tapped.${T}: Add {R} or {G}.| +Hallowed Fountain|Ravnica Allegiance|251|R||Land - Plains Island|||({T}: Add {W} or {U}.)$As Hallowed Fountain enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| +Orzhov Guildgate|Ravnica Allegiance|252|C||Land - Gate|||Orzhov Guildgate enters the battlefield tapped.${T}: Add {W} or {B}.| +Plaza of Harmony|Ravnica Allegiance|254|R||Land|||When Plaza of Harmony enters the battlefield, if you control two or more Gates, you gain 3 life.${T}: Add {C}.${T}: Add one mana of any type a Gate you control could produce.| +Rakdos Guildgate|Ravnica Allegiance|255|C||Land - Gate|||Rakdos Guildgate enters the battlefield tapped.${T}: Add {B} or {R}.| +Simic Guildgate|Ravnica Allegiance|257|C||Land - Gate|||Simic Guildgate enters the battlefield tapped.${T}: Add {G} or {U}.| +Stomping Ground|Ravnica Allegiance|259|R||Land - Mountain Forest|||({T}: Add {R} or {G}.)$As Stomping Ground enters the battlefield, you may pay 2 life. If you don't, it enters the battlefield tapped.| +Dovin, Architect of Law|Ravnica Allegiance|265|M|{4}{W}{U}|Legendary Planeswalker - Dovin|5|+1: You gain 2 life and draw a card.$-1: Tap target creature. It doesn't untap during its controller's next untap step.$-9: Tap all permanents target opponent controls. That player skips their next untap step.| +Elite Arrester|Ravnica Allegiance|266|C|{W}|Creature - Human Soldier|0|3|{1}{U}, {T}: Tap target creature.| +Dovin's Dismissal|Ravnica Allegiance|267|R|{2}{W}{U}|Instant|||Put up to one target tapped creature on top of its owner's library. You may search your library and/or graveyard for a card named Dovin, Architect of Law, reveal it, and put it into your hand. If you search your library this way, shuffle it.| +Dovin's Automaton|Ravnica Allegiance|268|U|{4}|Artifact Creature - Homunculus|3|3|As long as you control a Dovin planeswalker, Dovin's Automaton gets +2/+2 and has vigilance.| +Domri, City Smasher|Ravnica Allegiance|269|M|{4}{R}{G}|Legendary Planeswalker - Domri|4|+2: Creatures you control get +1/+1 and gain haste until end of turn.$-3: Domri, City Smasher deals 3 damage to any target.$-8: Put three +1/+1 counters on each creature you control. Those creatures gain trample until end of turn.| +Ragefire|Ravnica Allegiance|270|C|{1}{R}|Sorcery|||Ragefire deals 3 damage to target creature.| +Charging War Boar|Ravnica Allegiance|271|U|{1}{R}{G}|Creature - Boar|3|1|Haste$As long as you control a Domri planeswalker, Charging War Boar gets +1/+1 and has trample.| +Domri's Nodorog|Ravnica Allegiance|272|R|{3}{R}{G}|Creature - Beast|5|2|Trample$When Domri's Nodorog enters the battlefield, you may search your library and/or graveyard for a card named Domri, City Smasher, reveal it, and put it into your hand. If you search your library this way, shuffle it.| +The Haunt of Hightower|Ravnica Allegiance|273|M|{4}{B}{B}|Legendary Creature - Vampire|3|3|Flying, lifelink$Whenever The Haunt of Hightower attacks, defending player discards a card.$Whenever a card is put into an opponent's graveyard from anywhere, put a +1/+1 counter on The Haunt of Hightower.| +Serra the Benevolent|Modern Horizons|26|M|{2}{W}{W}|Legendary Planeswalker - Serra|4|+2: Creatures you control with flying get +1/+1 until end of turn.$-3: Create a 4/4 white Angel creature token with flying and vigilance.$-6: You get an emblem with "If you control a creature, damage that would reduce your life total to less than 1 reduces it to 1 instead."| +Cabal Therapist|Modern Horizons|80|R|{B}|Creature - Horror|1|1|Menace$At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.| +Karn, the Great Creator|War of the Spark|1|R|{4}|Legendary Planeswalker - Karn|5|Activated abilities of artifacts your opponents control can't be activated.$+1: Until your next turn, up to one target noncreature artifact becomes an artifact creature with power and toughness each equal to its converted mana cost.$-2: You may choose an artifact card you own from outside the game or in exile, reveal that card, and put it into your hand.| +Ugin, the Ineffable|War of the Spark|2|R|{6}|Legendary Planeswalker - Ugin|4|Colorless spells you cast cost {2} less to cast.$+1: Exile the top card of your library face down and look at it. Create a 2/2 colorless Spirit creature token. When that token leaves the battlefield, put the exiled card into your hand.$-3: Destroy target permanent that's one or more colors.| +Ugin's Conjurant|War of the Spark|3|U|{X}|Creature - Spirit Monk|0|0|Ugin's Conjurant enters the battlefield with X +1/+1 counters on it.$If damage would be dealt to Ugin's Conjurant while it has a +1/+1 counter on it, prevent that damage and remove that many +1/+1 counters from Ugin's Conjurant.| +Ajani's Pridemate|War of the Spark|4|U|{1}{W}|Creature - Cat Soldier|2|2|Whenever you gain life, put a +1/+1 counter on Ajani's Pridemate.| +Battlefield Promotion|War of the Spark|5|C|{1}{W}|Instant|||Put a +1/+1 counter on target creature. That creature gains first strike until end of turn. You gain 2 life.| +Bond of Discipline|War of the Spark|6|U|{4}{W}|Sorcery|||Tap all creatures your opponents control. Creatures you control gain lifelink until end of turn.| +Bulwark Giant|War of the Spark|7|C|{5}{W}|Creature - Giant Soldier|3|6|When Bulwark Giant enters the battlefield, you gain 5 life.| +Charmed Stray|War of the Spark|8|C|{W}|Creature - Cat|1|1|Lifelink$Whenever Charmed Stray enters the battlefield, put a +1/+1 counter on each other creature you control named Charmed Stray.| +Defiant Strike|War of the Spark|9|C|{W}|Instant|||Target creature gets +1/+0 until end of turn.$Draw a card.| +Divine Arrow|War of the Spark|10|C|{1}{W}|Instant|||Divine Arrow deals 4 damage to target attacking or blocking creature.| +Enforcer Griffin|War of the Spark|11|C|{4}{W}|Creature - Griffin|3|4|Flying| +Finale of Glory|War of the Spark|12|M|{X}{W}{W}|Sorcery|||Create X 2/2 white Soldier creature tokens with vigilance. If X is 10 or more, also create X 4/4 white Angel creature tokens with flying and vigilance.| +Gideon Blackblade|War of the Spark|13|M|{1}{W}{W}|Legendary Planeswalker - Gideon|4|As long as it's your turn, Gideon Blackblade is a 4/4 Human Soldier creature with indestructible that's still a planeswalker.$Prevent all damage that would be dealt to Gideon Blackblade during your turn.$+1: Up to one other target creature you control gains your choice of vigilance, lifelink, or indestructible until end of turn.$-6: Exile target nonland permanent.| +Gideon's Sacrifice|War of the Spark|14|C|{W}|Instant|||Choose a creature or planeswalker you control. All damage that would be dealt this turn to you and permanents you control is dealt to the chosen permanent instead.| +Gideon's Triumph|War of the Spark|15|U|{1}{W}|Instant|||Target opponent sacrifices a creature that attacked or blocked this turn. If you control a Gideon planeswalker, that player sacrifices two of those creatures instead.| +God-Eternal Oketra|War of the Spark|16|M|{3}{W}{W}|Legendary Creature - Zombie God|3|6|Double strike$Whenever you cast a creature spell, create a 4/4 black Zombie Warrior creature token with vigilance.$When God-Eternal Oketra dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.| +Grateful Apparition|War of the Spark|17|U|{1}{W}|Creature - Spirit|1|1|Flying$Whenever Grateful Apparition deals combat damage to a player or planeswalker, proliferate.| +Ignite the Beacon|War of the Spark|18|R|{4}{W}|Instant|||Search your library for up to two planeswalker cards, reveal them, put them into your hand, then shuffle your library.| +Ironclad Krovod|War of the Spark|19|C|{3}{W}|Creature - Beast|2|5|| +Law-Rune Enforcer|War of the Spark|20|C|{W}|Creature - Human Soldier|1|2|{1}, {T}: Tap target creature with converted mana cost 2 or greater.| +Loxodon Sergeant|War of the Spark|21|C|{3}{W}|Creature - Elephant Soldier|3|3|Vigilance$When Loxodon Sergeant enters the battlefield, other creatures you control gain vigilance until end of turn.| +Makeshift Battalion|War of the Spark|22|C|{2}{W}|Creature - Human Soldier|3|2|Whenever Makeshift Battalion and at least two other creatures attack, put a +1/+1 counter on Makeshift Battalion.| +Martyr for the Cause|War of the Spark|23|C|{1}{W}|Creature - Human Soldier|2|2|When Martyr for the Cause dies, proliferate.| +Parhelion II|War of the Spark|24|R|{6}{W}{W}|Legendary Artifact - Vehicle|5|5|Flying, first strike, vigilance$Whenever Parhelion II attacks, create two 4/4 white Angel creature tokens with flying and vigilance that are attacking.$Crew 4| +Pouncing Lynx|War of the Spark|25|C|{1}{W}|Creature - Cat|2|1|As long as it's your turn, Pouncing Lynx has first strike.| +Prison Realm|War of the Spark|26|U|{2}{W}|Enchantment|||When Prison Realm enters the battlefield, exile target creature or planeswalker an opponent controls until Prison Realm leaves the battlefield.$When Prison Realm enters the battlefield, scry 1.| +Rally of Wings|War of the Spark|27|U|{1}{W}|Instant|||Untap all creatures you control. Creatures you control with flying get +2/+2 until end of turn.| +Ravnica at War|War of the Spark|28|R|{3}{W}|Sorcery|||Exile all multicolored permanents.| +Rising Populace|War of the Spark|29|C|{2}{W}|Creature - Human|2|2|Whenever another creature or planeswalker you control dies, put a +1/+1 counter on Rising Populace.| +Single Combat|War of the Spark|30|R|{3}{W}{W}|Sorcery|||Each player chooses a creature or planeswalker they control, then sacrifices the rest. Players can't cast creature or planeswalker spells until the end of your next turn.| +Sunblade Angel|War of the Spark|31|U|{5}{W}|Creature - Angel|3|3|Flying, first strike, vigilance, lifelink| +Teyo, the Shieldmage|War of the Spark|32|U|{2}{W}|Legendary Planeswalker - Teyo|5|You have hexproof.$-2: Create a 0/3 white Wall creature token with defender.| +Teyo's Lightshield|War of the Spark|33|C|{2}{W}|Creature - Illusion|0|3|When Teyo's Lightshield enters the battlefield, put a +1/+1 counter on target creature you control.| +Tomik, Distinguished Advokist|War of the Spark|34|R|{W}{W}|Legendary Creature - Human Advisor|2|3|Flying$Lands on the battlefield and land cards in graveyards can't be the targets of spells or abilities your opponents control.$Your opponents can't play land cards from graveyards.| +Topple the Statue|War of the Spark|35|C|{2}{W}|Instant|||Tap target permanent. If it's an artifact, destroy it.$Draw a card.| +Trusted Pegasus|War of the Spark|36|C|{2}{W}|Creature - Pegasus|2|2|Flying$Whenever Trusted Pegasus attacks, target attacking creature without flying gains flying until end of turn.| +The Wanderer|War of the Spark|37|U|{3}{W}|Legendary Planeswalker|5|Prevent all noncombat damage that would be dealt to you and other permanents you control.$-2: Exile target creature with power 4 or greater.| +Wanderer's Strike|War of the Spark|38|C|{4}{W}|Sorcery|||Exile target creature, then proliferate.| +War Screecher|War of the Spark|39|C|{1}{W}|Creature - Bird|1|3|Flying${5}{W}, {T}: Other creatures you control get +1/+1 until end of turn.| +Ashiok's Skulker|War of the Spark|40|C|{4}{U}|Creature - Nightmare|3|5|{3}{U}: Ashiok's Skulker can't be blocked this turn.| +Augur of Bolas|War of the Spark|41|U|{1}{U}|Creature - Merfolk Wizard|1|3|When Augur of Bolas enters the battlefield, look at the top three cards of your library. You may reveal an instant or sorcery card from among them and put it into your hand. Put the rest on the bottom of your library in any order.| +Aven Eternal|War of the Spark|42|C|{2}{U}|Creature - Zombie Bird Warrior|2|2|Flying$When Aven Eternal enters the battlefield, amass 1.| +Bond of Insight|War of the Spark|43|U|{3}{U}|Sorcery|||Each player puts the top four cards of their library into their graveyard. Return up to two instant and/or sorcery cards from your graveyard to your hand. Exile Bond of Insight.| +Callous Dismissal|War of the Spark|44|C|{1}{U}|Sorcery|||Return target nonland permanent to its owner's hand.$Amass 1.| +Commence the Endgame|War of the Spark|45|R|{4}{U}{U}|Instant|||This spell can't be countered.$Draw two cards, then amass X, where X is the number of cards in your hand.| +Contentious Plan|War of the Spark|46|C|{1}{U}|Sorcery|||Proliferate.$Draw a card.| +Crush Dissent|War of the Spark|47|C|{3}{U}|Instant|||Counter target spell unless its controller pays {2}.$Amass 2.| +Erratic Visionary|War of the Spark|48|C|{1}{U}|Creature - Human Wizard|1|3|{1}{U}, {T}: Draw a card, then discard a card.| +Eternal Skylord|War of the Spark|49|U|{4}{U}|Creature - Zombie Wizard|3|3|When Eternal Skylord enters the battlefield, amass 2.$Zombie tokens you control have flying.| +Fblthp, the Lost|War of the Spark|50|R|{1}{U}|Legendary Creature - Homunculus|1|1|When Fblthp, the Lost enters the battlefield, draw a card. If it entered from your library or was cast from your library, draw two cards instead.$When Fblthp becomes the target of a spell, shuffle Fblthp into its owner's library.| +Finale of Revelation|War of the Spark|51|M|{X}{U}{U}|Sorcery|||Draw X cards. If X is 10 or more, instead shuffle your graveyard into your library, draw X cards, untap up to five lands, and you have no maximum hand size for the rest of the game.$Exile Finale of Revelation.| +Flux Channeler|War of the Spark|52|U|{2}{U}|Creature - Human Wizard|2|2|Whenever you cast a noncreature spell, proliferate.| +God-Eternal Kefnet|War of the Spark|53|M|{2}{U}{U}|Legendary Creature - Zombie God|4|5|Flying$You may reveal the first card you draw each turn as you draw it. Whenever you reveal an instant or sorcery card this way, copy that card and you may cast the copy. That copy costs {2} less to cast.$When God-Eternal Kefnet dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.| +Jace, Wielder of Mysteries|War of the Spark|54|R|{1}{U}{U}{U}|Legendary Planeswalker - Jace|4|If you would draw a card while your library has no cards in it, you win the game instead.$+1: Target player puts the top two cards of their library into their graveyard. Draw a card.$-8: Draw seven cards. Then if your library has no cards in it, you win the game.| +Jace's Triumph|War of the Spark|55|U|{2}{U}|Sorcery|||Draw two cards. If you control a Jace planeswalker, draw three cards instead.| +Kasmina, Enigmatic Mentor|War of the Spark|56|U|{3}{U}|Legendary Planeswalker - Kasmina|5|Spells your opponents cast that target a creature or planeswalker you control cost {2} more to cast.$-2: Create a 2/2 blue Wizard creature token. Draw a card, then discard a card.| +Kasmina's Transmutation|War of the Spark|57|C|{1}{U}|Enchantment - Aura|||Enchant creature$Enchanted creature loses all abilities and has base power and toughness 1/1.| +Kiora's Dambreaker|War of the Spark|58|C|{5}{U}|Creature - Leviathan|5|6|When Kiora's Dambreaker enters the battlefield, proliferate.| +Lazotep Plating|War of the Spark|59|U|{1}{U}|Instant|||Amass 1.$You and permanents you control gain hexproof until end of turn.| +Naga Eternal|War of the Spark|60|C|{2}{U}|Creature - Zombie Naga|3|2|| +Narset, Parter of Veils|War of the Spark|61|U|{1}{U}{U}|Legendary Planeswalker - Narset|5|Each opponent can't draw more than one card each turn.$-2: Look at the top four cards of your library. You may reveal a noncreature, nonland card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.| +Narset's Reversal|War of the Spark|62|R|{U}{U}|Instant|||Copy target instant or sorcery spell, then return it to its owner's hand. You may choose new targets for the copy.| +No Escape|War of the Spark|63|C|{2}{U}|Instant|||Counter target creature or planeswalker spell. If that spell is countered this way, exile it instead of putting it into its owner's graveyard.$Scry 1.| +Relentless Advance|War of the Spark|64|C|{3}{U}|Sorcery|||Amass 3.| +Rescuer Sphinx|War of the Spark|65|U|{2}{U}{U}|Creature - Sphinx|3|2|Flying$As Rescuer Sphinx enters the battlefield, you may return a nonland permanent you control to its owner's hand. If you do, Rescuer Sphinx enters the battlefield with a +1/+1 counter on it.| +Silent Submersible|War of the Spark|66|R|{U}{U}|Artifact - Vehicle|2|3|Whenever Silent Submersible deals combat damage to a player or planeswalker, draw a card.$Crew 2| +Sky Theater Strix|War of the Spark|67|C|{1}{U}|Creature - Bird|1|2|Flying$Whenever you cast a noncreature spell, Sky Theater Strix gets +1/+0 until end of turn.| +Spark Double|War of the Spark|68|R|{3}{U}|Creature - Illusion|0|0|You may have Spark Double enter the battlefield as a copy of a creature or planeswalker you control, except it enters with an additional +1/+1 counter on it if it's a creature, it enters with an additional loyalty counter on it if it's a planeswalker, and it isn't legendary if that permanent is legendary.| +Spellkeeper Weird|War of the Spark|69|C|{2}{U}|Creature - Weird|1|4|{2}, {T}, Sacrifice Spellkeeper Weird: Return target instant or sorcery card from your graveyard to your hand.| +Stealth Mission|War of the Spark|70|C|{2}{U}|Sorcery|||Put two +1/+1 counters on target creature you control. That creature can't be blocked this turn.| +Tamiyo's Epiphany|War of the Spark|71|C|{3}{U}|Sorcery|||Scry 4, then draw two cards.| +Teferi's Time Twist|War of the Spark|72|C|{1}{U}|Instant|||Exile target permanent you control. Return that card to the battlefield under its owner's control at the beginning of the next end step. If it enters the battlefield as a creature, it enters with an additional +1/+1 counter on it.| +Thunder Drake|War of the Spark|73|C|{3}{U}|Creature - Elemental Drake|2|3|Flying$Whenever you cast you cast your second spell each turn, put a +1/+1 counter on Thunder Drake.| +Totally Lost|War of the Spark|74|C|{4}{U}|Instant|||Put target nonland permanent on top of its owner's library.| +Wall of Runes|War of the Spark|75|C|{U}|Creature - Wall|0|4|Defender$When Wall of Runes enters the battlefield, scry 1.| +Aid the Fallen|War of the Spark|76|C|{1}{B}|Sorcery|||Choose one or both—$• Return target creature card from your graveyard to your hand.$• Return target planeswalker card from your graveyard to your hand.| +Banehound|War of the Spark|77|C|{B}|Creature - Nightmare Hound|1|1|Lifelink, haste| +Bleeding Edge|War of the Spark|78|U|{1}{B}{B}|Sorcery|||Up to one target creature gets -2/-2 until end of turn. Amass 2.| +Bolas's Citadel|War of the Spark|79|R|{3}{B}{B}{B}|Legendary Artifact|||You may look at the top card of your library any time.$You may play the top card of your library. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost.${T}, Sacrifice ten nonland permanents: Each opponent loses 10 life.| +Bond of Revival|War of the Spark|80|U|{4}{B}|Sorcery|||Return target creature card from your graveyard to the battlefield. It gains haste until your next turn.| +Charity Extractor|War of the Spark|81|C|{3}{B}|Creature - Human Knight|1|5|Lifelink| +Command the Dreadhorde|War of the Spark|82|R|{4}{B}{B}|Sorcery|||Choose any number of target creature and/or planeswalker cards in graveyards. Command the Dreadhorde deals damage to you equal to the total converted mana cost of those cards. Put them onto the battlefield under your control.| +Davriel, Rogue Shadowmage|War of the Spark|83|U|{2}{B}|Legendary Planeswalker - Davriel|3|At the beginning of each opponent's upkeep, if that player has one or fewer cards in hand, Davriel, Rogue Shadowmage deals 2 damage to them.$-1: Target player discards a card.| +Davriel's Shadowfugue|War of the Spark|84|C|{3}{B}|Sorcery|||Target player discards two cards and loses 2 life.| +Deliver Unto Evil|War of the Spark|85|R|{2}{B}|Sorcery|||Choose up to four target cards in your graveyard. If you control a Bolas planeswalker, return those cards to your hand. Otherwise, an opponent chooses two of them. Leave the chosen cards in your graveyard and put the rest into your hand.$Exile Deliver Unto Evil.| +Dreadhorde Invasion|War of the Spark|86|R|{1}{B}|Enchantment|||At the beginning of your upkeep, you lose 1 life and amass 1.$Whenever a Zombie token you control with power 6 or greater attacks, it gains lifelink until end of turn.| +Dreadmalkin|War of the Spark|87|U|{B}|Creature - Zombie Cat|1|1|Menace${2}{B}, Sacrifice another creature or planeswalker: Put two +1/+1 counters on Dreadmalkin.| +Duskmantle Operative|War of the Spark|88|C|{1}{B}|Creature - Human Rogue|2|2|Duskmantle Operative can't be blocked by creatures with power 4 or greater.| +The Elderspell|War of the Spark|89|R|{B}{B}|Sorcery|||Destroy any number of target planeswalkers. Choose a planeswalker you control. Put two loyalty counters on it for each planeswalker destroyed this way.| +Eternal Taskmaster|War of the Spark|90|U|{1}{B}|Creature - Zombie|2|3|Eternal Taskmaster enters the battlefield tapped.$Whenever Eternal Taskmaster attacks, you may pay {2}{B}. If you do, return target creature card from your graveyard to your hand.| +Finale of Eternity|War of the Spark|91|M|{X}{B}{B}|Sorcery|||Destroy up to three target creatures with toughness X or less. If X is 10 or more, return all creature cards from your graveyard to the battlefield.| +God-Eternal Bontu|War of the Spark|92|M|{3}{B}{B}|Legendary Creature - Zombie God|5|6|Menace$When God-Eternal Bontu enters the battlefield, sacrifice any number of other permanents, then draw that many cards.$When God-Eternal Bontu dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.| +Herald of the Dreadhorde|War of the Spark|93|C|{3}{B}|Creature - Zombie Warrior|3|2|When Herald of the Dreadhorde dies, amass 2.| +Kaya's Ghostform|War of the Spark|94|C|{B}|Enchantment - Aura|||Enchant creature or planeswalker you control$When enchanted permanent dies or is put into exile, return that card to the battlefield under your control.| +Lazotep Behemoth|War of the Spark|95|C|{4}{B}|Creature - Zombie Hippo|5|4|| +Lazotep Reaver|War of the Spark|96|C|{1}{B}|Creature - Zombie Beast|1|2|When Lazotep Reaver enters the battlefield, amass 1.| +Liliana, Dreadhorde General|War of the Spark|97|M|{4}{B}{B}|Legendary Planeswalker - Liliana|6|Whenever a creature you control dies, draw a card.$+1: Create a 2/2 black Zombie creature token.$-4: Each player sacrifices two creatures.$-9: Each opponent chooses a permanent they control of each permanent type and sacrifices the rest.| +Liliana's Triumph|War of the Spark|98|U|{1}{B}|Instant|||Each opponent sacrifices a creature. If you control a Liliana planeswalker, each opponent also discards a card.| +Massacre Girl|War of the Spark|99|R|{3}{B}{B}|Legendary Creature - Human Assassin|4|4|Menace$When Massacre Girl enters the battlefield, each other creature gets -1/-1 until end of turn. Whenever a creature dies this turn, each creature other than Massacre Girl gets -1/-1 until end of turn.| +Ob Nixilis, the Hate-Twisted|War of the Spark|100|U|{3}{B}{B}|Legendary Planeswalker - Nixilis|5|Whenever an opponent draws a card, Ob Nixilis, the Hate-Twisted deals 1 damage to that player.$-2: Destroy target creature. Its controller draws two cards.| +Ob Nixilis's Cruelty|War of the Spark|101|C|{2}{B}|Instant|||Target creature gets -5/-5 until end of turn. If that creature would die this turn, exile it instead.| +Price of Betrayal|War of the Spark|102|U|{B}|Sorcery|||Remove up to five counters from target artifact, creature, planeswalker, or opponent.| +Shriekdiver|War of the Spark|103|C|{2}{B}|Creature - Zombie Bird Warrior|2|1|Flying${1}: Shriekdiver gains haste until end of turn.| +Sorin's Thirst|War of the Spark|104|C|{B}{B}|Instant|||Sorin's Thirst deals 2 damage to target creature and you gain 2 life.| +Spark Harvest|War of the Spark|105|C|{B}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature or pay {3}{B}.$Destroy target creature or planeswalker.| +Spark Reaper|War of the Spark|106|C|{2}{B}|Creature - Zombie|2|3|{3}, Sacrifice a creature or planeswalker: You gain 1 life and draw a card.| +Tithebearer Giant|War of the Spark|107|C|{5}{B}|Creature - Giant Warrior|4|5|When Tithebearer Giant enters the battlefield, you draw a card and you lose 1 life.| +Toll of the Invasion|War of the Spark|108|C|{2}{B}|Sorcery|||Target opponent reveals their hand. You choose a nonland card from it. That player discards that card.$Amass 1.| +Unlikely Aid|War of the Spark|109|C|{1}{B}|Instant|||Target creature gets +2/+0 and gains indestructible until end of turn.| +Vampire Opportunist|War of the Spark|110|C|{1}{B}|Creature - Vampire|2|1|{6}{B}: Each opponent loses 2 life and you gain 2 life.| +Vizier of the Scorpion|War of the Spark|111|U|{2}{B}|Creature - Zombie Wizard|1|1|When Vizier of the Scorpion enters the battlefield, amass 1.$Zombie tokens you control have deathtouch.| +Vraska's Finisher|War of the Spark|112|C|{2}{B}|Creature - Gorgon Assassin|3|2|When Vraska's Finisher enters the battlefield, destroy target creature or planeswalker an opponent controls that was dealt damage this turn.| +Ahn-Crop Invader|War of the Spark|113|C|{2}{R}|Creature - Zombie Minotaur Warrior|2|2|As long as it's your turn, Ahn-Crop Invader has first strike.${1}, Sacrifice another creature: Ahn-Crop Invader gets +2/+0 until end of turn.| +Blindblast|War of the Spark|114|C|{2}{R}|Instant|||Blindblast deals 1 damage to target creature. That creature can't block this turn.$Draw a card.| +Bolt Bend|War of the Spark|115|U|{3}{R}|Instant|||This spell costs {3} less to cast if you control a creature with power 4 or greater.$Change the target of target spell or ability with a single target.| +Bond of Passion|War of the Spark|116|U|{4}{R}{R}|Sorcery|||Gain control of target creature until end of turn. Untap that creature. It gains haste until end of turn. Bond of Passion deals 2 damage to any other target.| +Burning Prophet|War of the Spark|117|C|{1}{R}|Creature - Human Wizard|1|3|Whenever you cast a noncreature spell, Burning Prophet gets +1/+0 until end of turn, then scry 1.| +Chainwhip Cyclops|War of the Spark|118|C|{4}{R}|Creature - Cyclops Warrior|4|4|{3}{R}: Target creature can't block this turn.| +Chandra, Fire Artisan|War of the Spark|119|R|{2}{R}{R}|Legendary Planeswalker - Chandra|4|Whenever one or more loyalty counters are removed from Chandra, Fire Artisan, she deals that much damage to target opponent or planeswalker.$+1: Exile the top card of your library. You may play it this turn.$-7: Exile the top seven cards of your library. You may play them this turn.| +Chandra's Pyrohelix|War of the Spark|120|C|{1}{R}|Instant|||Chandra's Pyrohelix deals 2 damage divided as you choose among one or two targets.| +Chandra's Triumph|War of the Spark|121|U|{1}{R}|Instant|||Chandra's Triumph deals 3 damage to target creature or planeswalker an opponent controls. Chandra's Triumph deals 5 damage to that permanent instead if you control a Chandra planeswalker.| +Cyclops Electromancer|War of the Spark|122|U|{4}{R}|Creature - Cyclops Wizard|4|2|When Cyclops Electromancer enters the battlefield, it deals X damage to target creature an opponent controls, where X is the number of instant and sorcery cards in your graveyard.| +Demolish|War of the Spark|123|C|{3}{R}|Sorcery|||Destroy target artifact or land.| +Devouring Hellion|War of the Spark|124|U|{2}{R}|Creature - Hellion|2|2|As Devouring Hellion enters the battlefield, you may sacrifice any number of creatures and/or planeswalkers. If you do, it enters with twice that many +1/+1 counters on it.| +Dreadhorde Arcanist|War of the Spark|125|R|{1}{R}|Creature - Zombie Wizard|1|3|Trample$Whenever Dreadhorde Arcanist attacks, you may cast target instant or sorcery card with converted mana cost less than or equal to Dreadhorde Arcanist's power from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead.| +Dreadhorde Twins|War of the Spark|126|U|{3}{R}|Creature - Zombie Jackal Warrior|2|2|When Dreadhorde Twins enters the battlefield, amass 2.$Zombie tokens you control have trample.| +Finale of Promise|War of the Spark|127|M|{X}{R}{R}|Sorcery|||You may cast up to one target instant card and/or sorcery card from your graveyard each with converted mana cost X or less without paying their mana costs. If a card cast this way would be put into your graveyard this turn, exile it instead. If X is 10 or more, copy each of those spells twice. You may choose new targets for the copies.| +Goblin Assailant|War of the Spark|128|C|{1}{R}|Creature - Goblin Warrior|2|2|| +Goblin Assault Team|War of the Spark|129|C|{3}{R}|Creature - Goblin Warrior|4|1|Haste$When Goblin Assault Team dies, put a +1/+1 counter on target creature you control.| +Grim Initiate|War of the Spark|130|C|{R}|Creature - Zombie Warrior|1|1|First strike$When Grim Initiate dies, amass 1.| +Heartfire|War of the Spark|131|C|{1}{R}|Instant|||As an additional cost to cast this spell, sacrifice a creature or planeswalker.$Heartfire deals 4 damage to any target.| +Honor the God-Pharaoh|War of the Spark|132|C|{2}{R}|Sorcery|||As an additional cost to cast this spell, discard a card.$Draw two cards. Amass 1.| +Ilharg, the Raze-Boar|War of the Spark|133|M|{3}{R}{R}|Legendary Creature - Boar God|6|6|Trample$Whenever Ilharg, the Raze-Boar attacks, you may put a creature card from your hand onto the battlefield tapped and attacking. Return that creature to your hand at the beginning of the next end step.$When Ilharg, the Raze-Boar dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.| +Invading Manticore|War of the Spark|134|C|{5}{R}|Creature - Zombie Manticore|4|5|When Invading Manticore enters the battlefield, amass 2.| +Jaya, Venerated Firemage|War of the Spark|135|U|{4}{R}|Legendary Planeswalker - Jaya|5|If another red source you control would deal damage to a permanent or player, it deals that much damage plus 1 to that permanent or player instead.$-2: Jaya, Venerated Firemage deals 2 damage to any target.| +Jaya's Greeting|War of the Spark|136|C|{1}{R}|Instant|||Jaya's Greeting deals 3 damage to target creature. Scry 1.| +Krenko, Tin Street Kingpin|War of the Spark|137|R|{2}{R}|Legendary Creature - Goblin|1|2|Whenever Krenko, Tin Street Kingpin attacks, put a +1/+1 counter on it, then create a number of 1/1 red Goblin creature tokens equal to Krenko's power.| +Mizzium Tank|War of the Spark|138|R|{1}{R}{R}|Artifact - Vehicle|3|2|Trample$Whenever you cast a noncreature spell, Mizzium Tank becomes an artifact creature and gets +1/+1 until end of turn.$Crew 1| +Nahiri's Stoneblades|War of the Spark|139|C|{1}{R}|Instant|||Up to two target creatures each get +2/+0 until end of turn.| +Neheb, Dreadhorde Champion|War of the Spark|140|R|{2}{R}{R}|Legendary Creature - Zombie Minotaur Warrior|5|4|Trample$Whenever Neheb, Dreadhorde Champion deals combat damage to a player or planeswalker, you may discard any number of cards. If you do, draw that many cards and add that much {R}. Until end of turn, you don't lose this mana as steps and phases end.| +Raging Kronch|War of the Spark|141|C|{2}{R}|Creature - Beast|4|3|Raging Kronch can't attack alone.| +Samut's Sprint|War of the Spark|142|C|{R}|Instant|||Target creature gets +2/+1 and gains haste until end of turn. Scry 1.| +Sarkhan the Masterless|War of the Spark|143|R|{3}{R}{R}|Legendary Planeswalker - Sarkhan|5|Whenever a creature attacks you or a planeswalker you control, each Dragon you control deals 1 damage to that creature.$+1: Until end of turn, each planeswalker you control becomes a 4/4 red Dragon creature and gains flying.$-3: Create a 4/4 red Dragon creature token with flying.| +Sarkhan's Catharsis|War of the Spark|144|C|{4}{R}|Instant|||Sarkhan's Catharsis deals 5 damage to target player or planeswalker.| +Spellgorger Weird|War of the Spark|145|C|{2}{R}|Creature - Weird|2|2|Whenever you cast a noncreature spell, put a +1/+1 counter on Spellgorger Weird.| +Tibalt, Rakish Instigator|War of the Spark|146|U|{2}{R}|Legendary Planeswalker - Tibalt|5|Your opponents can't gain life.$-2: Create a 1/1 red Devil creature token with "Whenever this creature dies, it deals 1 damage to any target."| +Tibalt's Rager|War of the Spark|147|U|{1}{R}|Creature - Devil|1|2|When Tibalt's Rager dies, it deals 1 damage to any target.${1}{R}: Tibalt's Rager gets +2/+0 until end of turn.| +Turret Ogre|War of the Spark|148|C|{3}{R}|Creature - Ogre Warrior|4|3|Reach$When Turret Ogre enters the battlefield, if you control another creature with power 4 or greater, Turret Ogre deals 2 damage to each opponent.| +Arboreal Grazer|War of the Spark|149|C|{G}|Creature - Beast|0|3|Reach$When Arboreal Grazer enters the battlefield, you may put a land card from your hand onto the battlefield tapped.| +Arlinn, Voice of the Pack|War of the Spark|150|U|{4}{G}{G}|Legendary Planeswalker - Arlinn|7|Each creature you control that's a Wolf or Werewolf enters the battlefield with an additional +1/+1 counter on it.$-2: Create a 2/2 green Wolf creature token.| +Arlinn's Wolf|War of the Spark|151|C|{2}{G}|Creature - Wolf|3|2|Arlinn's Wolf can't be blocked by creatures with power 2 or less.| +Awakening of Vitu-Ghazi|War of the Spark|152|R|{3}{G}{G}|Instant|||Put nine +1/+1 counters on target land you control. It becomes a legendary 0/0 Elemental creature with haste named Vitu-Ghazi. It's still a land.| +Band Together|War of the Spark|153|C|{2}{G}|Instant|||Up to two target creatures you control each deal damage equal to their power to another target creature.| +Bloom Hulk|War of the Spark|154|C|{3}{G}|Creature - Plant Elemental|4|4|When Bloom Hulk enters the battlefield, proliferate.| +Bond of Flourishing|War of the Spark|155|U|{1}{G}|Sorcery|||Look at the top three card of your library. You may reveal a permanent card from among them and put it into your hand. Put the rest on the bottom of your library in any order. You gain 3 life.| +Centaur Nurturer|War of the Spark|156|C|{3}{G}|Creature - Centaur Druid|2|4|When Centaur Nurturer enters the battlefield, you gain 3 life.${T}: Add one mana of any color.| +Challenger Troll|War of the Spark|157|U|{4}{G}|Creature - Troll|6|5|Each creature you control with power 4 or greater can't be blocked by more than one creature.| +Courage in Crisis|War of the Spark|158|C|{2}{G}|Sorcery|||Put a +1/+1 counter on target creature, then proliferate.| +Evolution Sage|War of the Spark|159|U|{2}{G}|Creature - Elf Druid|3|2|Whenever a land enters the battlefield under your control, proliferate.| +Finale of Devastation|War of the Spark|160|M|{X}{G}{G}|Sorcery|||Search your library and/or graveyard for a creature card with converted mana cost X or less and put it onto the battlefield. If you search your library this way, shuffle it. If X is 10 or more, creatures you control get +X/+X and gain haste until end of turn.| +Forced Landing|War of the Spark|161|C|{1}{G}|Instant|||Put target creature with flying on the bottom of its owner's library.| +Giant Growth|War of the Spark|162|C|{G}|Instant|||Target creature gets +3/+3 until end of turn.| +God-Eternal Rhonas|War of the Spark|163|M|{3}{G}{G}|Legendary Creature - Zombie God|5|5|Deathtouch$When God-Eternal Rhonas enters the battlefield, double the power of each other creature you control until end of turn. Those creatures gain vigilance until end of turn.$When God-Eternal Rhonas dies or is put into exile from the battlefield, you may put it into its owner's library third from the top.| +Jiang Yanggu, Wildcrafter|War of the Spark|164|U|{2}{G}|Legendary Planeswalker - Yanggu|3|Each creature you control with a +1/+1 counter on it has "{T}: Add one mana of any color."$-1: Put a +1/+1 counter on target creature.| +Kraul Stinger|War of the Spark|165|C|{2}{G}|Creature - Insect Assassin|2|2|Deathtouch| +Kronch Wrangler|War of the Spark|166|C|{1}{G}|Creature - Human Warrior|2|1|Trample$Whenever a creature with power 4 or greater enters the battlefield under your control, put a +1/+1 counter on Kronch Wrangler.| +Mowu, Loyal Companion|War of the Spark|167|U|{3}{G}|Legendary Creature - Hound|3|3|Trample, vigilance$If one or more +1/+1 counters would be put on Mowu, Loyal Companion, that many plus one +1/+1 counters are put on it instead.| +New Horizons|War of the Spark|168|C|{2}{G}|Enchantment - Aura|||Enchant land$When New Horizons enters the battlefield, put a +1/+1 counter on target creature you control.$Enchanted land has "{T}: Add two mana of any one color."| +Nissa, Who Shakes the World|War of the Spark|169|R|{3}{G}{G}|Legendary Planeswalker - Nissa|5|Whenever you tap a Forest for mana, add an additional {G}.$+1: Put three +1/+1 counters on up to one target noncreature land you control. Untap it. It becomes a 0/0 Elemental creature with vigilance and haste that's still a land.$-8: You get an emblem with "Lands you control have indestructible." Search your library for any number of Forest cards, put them onto the battlefield tapped, then shuffle your library.| +Nissa's Triumph|War of the Spark|170|U|{G}{G}|Sorcery|||Search your library for up to two basic Forest cards. If you control a Nissa planeswalker, instead search your library for up to three land cards. Reveal those cards, put them into your hand, then shuffle your library.| +Paradise Druid|War of the Spark|171|U|{1}{G}|Creature - Elf Druid|2|1|Paradise Druid has hexproof as long as it's untapped.${T}: Add one mana of any color.| +Planewide Celebration|War of the Spark|172|R|{5}{G}{G}|Sorcery|||Choose four. You may choose the same mode more than once.$• Create a 2/2 Citizen creature token that's all colors.$• Return target permanent card from your graveyard to your hand.$• Proliferate.$• You gain 4 life.| +Pollenbright Druid|War of the Spark|173|C|{1}{G}|Creature - Elf Druid|1|1|When Pollenbright Druid enters the battlefield, choose one —$• Put a +1/+1 counter on target creature.$• Proliferate.| +Primordial Wurm|War of the Spark|174|C|{4}{G}{G}|Creature - Wurm|7|6|| +Return to Nature|War of the Spark|175|C|{1}{G}|Instant|||Choose one —$• Destroy target artifact.$• Destroy target enchantment.$• Exile target card from a graveyard.| +Snarespinner|War of the Spark|176|C|{1}{G}|Creature - Spider|1|3|Reach$Whenever Snarespinner blocks a creature with flying, Snarespinner gets +2/+0 until end of turn.| +Steady Aim|War of the Spark|177|C|{1}{G}|Instant|||Untap target creature. It gets +1/+4 and gains reach until end of turn.| +Storm the Citadel|War of the Spark|178|U|{4}{G}|Sorcery|||Until end of turn, creatures you control get +2/+2 and gain "Whenever this creature deals combat damage to a player or planeswalker, destroy target artifact or enchantment defending player controls."| +Thundering Ceratok|War of the Spark|179|C|{4}{G}|Creature - Rhino|4|5|Trample$When Thundering Ceratok enters the battlefield, other creatures you control gain trample until end of turn.| +Vivien, Champion of the Wilds|War of the Spark|180|R|{2}{G}|Legendary Planeswalker - Vivien|4|You may cast creature spells as though they had flash.$+1: Until your next turn, up to one target creature gains vigilance and reach.$-2: Look at the top three cards of your library. Exile one face down and put the rest on the bottom of your library in any order. For as long as it remains exiled, you may look at that card and you may cast it if it's a creature card.| +Vivien's Arkbow|War of the Spark|181|R|{1}{G}|Legendary Artifact|||{X}, {T}, Discard a card: Look at the top X cards of your library. You may put a creature card with converted mana cost X or less from among them onto the battlefield. Put the rest on the bottom of your library in a random order.| +Vivien's Grizzly|War of the Spark|182|C|{2}{G}|Creature - Bear Spirit|2|3|{3}{G}: Look at the top card of your library. If it's a creature or planeswalker card, you may reveal it and put it into your hand. If you don't put the card into your hand, put it on the bottom of your library.| +Wardscale Crocodile|War of the Spark|183|C|{4}{G}|Creature - Crocodile|5|3|Hexproof| +Ajani, the Greathearted|War of the Spark|184|R|{2}{G}{W}|Legendary Planeswalker - Ajani|5|Creatures you control have vigilance.$+1: You gain 3 life.$-2: Put a +1/+1 counter on each creature you control and a loyalty counter on each other planeswalker you control.| +Angrath's Rampage|War of the Spark|185|U|{B}{R}|Sorcery|||Choose one —$• Target player sacrifices an artifact.$• Target player sacrifices a creature.$• Target player sacrifices a planeswalker.| +Bioessence Hydra|War of the Spark|186|R|{3}{G}{U}|Creature - Hydra Mutant|4|4|Trample$Bioessence Hydra enters the battlefield with a +1/+1 counter on it for each loyalty counter on planeswalkers you control.$Whenever one or more loyalty counters are put on planeswalkers you control, put that many +1/+1 counters on Bioessence Hydra.| +Casualties of War|War of the Spark|187|R|{2}{B}{B}{G}{G}|Sorcery|||Choose one or more —$• Destroy target artifact.$• Destroy target creature.$• Destroy target enchantment.$• Destroy target land.$• Destroy target planeswalker.| +Cruel Celebrant|War of the Spark|188|U|{W}{B}|Creature - Vampire|1|2|Whenever Cruel Celebrant or another creature or planeswalker you control dies, each opponent loses 1 life and you gain 1 life.| +Deathsprout|War of the Spark|189|U|{1}{B}{B}{G}|Instant|||Destroy target creature. Search your library for a basic land card, put it onto the battlefield tapped, then shuffle your library.| +Despark|War of the Spark|190|U|{W}{B}|Instant|||Exile target permanent with converted mana cost 4 or greater.| +Domri, Anarch of Bolas|War of the Spark|191|R|{1}{R}{G}|Legendary Planeswalker - Domri|3|Creatures you control get +1/+0.$+1: Add {R} or {G}. Creature spells you cast this turn can't be countered.$-2: Target creature you control fights target creature you don't control.| +Domri's Ambush|War of the Spark|192|U|{R}{G}|Sorcery|||Put a +1/+1 counter on target creature you control. Then that creature deals damage equal to its power to target creature or planeswalker you don't control.| +Dovin's Veto|War of the Spark|193|U|{W}{U}|Instant|||This spell can't be countered.$Counter target noncreature spell.| +Dreadhorde Butcher|War of the Spark|194|R|{B}{R}|Creature - Zombie Warrior|1|1|Haste$Whenever Dreadhorde Butcher deals combat damage to a player or planeswalker, put a +1/+1 counter on Dreadhorde Butcher.$When Dreadhorde Butcher dies, it deals damage equal to its power to any target.| +Elite Guardmage|War of the Spark|195|U|{2}{W}{U}|Creature - Human Wizard|2|3|Flying$When Elite Guardmage enters the battlefield, you gain 3 life and draw a card.| +Enter the God-Eternals|War of the Spark|196|R|{2}{U}{U}{B}|Sorcery|||Enter the God-Eternals deals 4 damage to target creature and you gain life equal to the damage dealt this way. Target player puts the top four cards of their library into their graveyard. Amass 4.| +Feather, the Redeemed|War of the Spark|197|R|{R}{W}{W}|Legendary Creature - Angel|3|4|Flying$Whenever you cast an instant or sorcery spell that targets a creature you control, exile that card instead of putting it into your graveyard as it resolves. If you do, return it to your hand at the beginning of the next end step.| +Gleaming Overseer|War of the Spark|198|U|{1}{U}{B}|Creature - Zombie Wizard|1|4|When Gleaming Overseer enters the battlefield, amass 1.$Zombie tokens you control have hexproof and menace.| +Heartwarming Redemption|War of the Spark|199|U|{2}{R}{W}|Instant|||Discard all the cards in your hand, then draw that many cards plus one. You gain life equal to the number of cards in your hand.| +Huatli's Raptor|War of the Spark|200|U|{G}{W}|Creature - Dinosaur|2|3|Vigilance$When Huatli's Raptor enters the battlefield, proliferate.| +Invade the City|War of the Spark|201|U|{1}{U}{R}|Sorcery|||Amass X, where X is the number of instant and sorcery cards in your graveyard.| +Leyline Prowler|War of the Spark|202|U|{1}{B}{G}|Creature - Nightmare Beast|2|3|Deathtouch, lifelink${T}: Add one mana of any color.| +Living Twister|War of the Spark|203|R|{R}{R}{G}|Creature - Elemental|2|5|{1}{R}, Discard a land card: Living Twister deals 2 damage to any target.${G}: Return a tapped land you control to its owner's hand.| +Mayhem Devil|War of the Spark|204|U|{1}{B}{R}|Creature - Devil|3|3|Whenever a player sacrifices a permanent, Mayhem Devil deals 1 damage to any target.| +Merfolk Skydiver|War of the Spark|205|U|{G}{U}|Creature - Merfolk Mutant|1|1|Flying$When Merfolk Skydiver enters the battlefield, put a +1/+1 counter on target creature you control.${3}{G}{U}: Proliferate.| +Neoform|War of the Spark|206|U|{G}{U}|Sorcery|||As an additional cost to cast this spell, sacrifice a creature.$Search your library for a creature card with converted mana cost equal to 1 plus the sacrificed creature's converted mana cost, put that card onto the battlefield with an additional +1/+1 counter on it, then shuffle your library.| +Nicol Bolas, Dragon-God|War of the Spark|207|M|{U}{B}{B}{B}{R}|Legendary Planeswalker - Bolas|4|Nicol Bolas, Dragon-God has all loyalty abilities of all other planeswalkers on the battlefield.$+1: You draw a card. Each opponent exiles a card from their hand or a permanent they control.$-3: Destroy target creature or planeswalker.$-8: Each opponent who doesn't control a legendary creature or planeswalker loses the game.| +Niv-Mizzet Reborn|War of the Spark|208|M|{W}{U}{B}{R}{G}|Legendary Creature - Dragon Avatar|6|6|Flying$When Niv-Mizzet Reborn enters the battlefield, reveal the top ten cards of your library. For each color pair, choose a card that's exactly those colors from among them. Put the chosen cards into your hand and the rest on the bottom of your library in a random order.| +Oath of Kaya|War of the Spark|209|R|{1}{W}{B}|Legendary Enchantment|||When Oath of Kaya enters the battlefield, it deals 3 damage to any target and you gain 3 life.$Whenever an opponent attacks a planeswalker you control with one or more creatures, Oath of Kaya deals 2 damage to that player and you gain 2 life.| +Pledge of Unity|War of the Spark|210|U|{1}{G}{W}|Instant|||Put a +1/+1 counter on each creature you control. You gain 1 life for each creature you control.| +Ral, Storm Conduit|War of the Spark|211|R|{2}{U}{R}|Legendary Planeswalker - Ral|4|Whenever you cast or copy an instant or sorcery spell, Ral, Storm Conduit deals 1 damage to target opponent or planeswalker.$+2: Scry 1.$-2: When you cast your next instant or sorcery spell this turn, copy that spell. You may choose new targets for the copy.| +Ral's Outburst|War of the Spark|212|U|{2}{U}{R}|Instant|||Ral's Outburst deals 3 damage to any target. Look at the top two cards of your library. Put one of them into your hand and the other into your graveyard.| +Roalesk, Apex Hybrid|War of the Spark|213|M|{2}{G}{G}{U}|Legendary Creature - Human Mutant|4|5|Flying, trample$When Roalesk, Apex Hybrid enters the battlefield, put two +1/+1 counters on another target creature you control.$When Roalesk dies, proliferate, then proliferate again.| +Role Reversal|War of the Spark|214|R|{U}{U}{R}|Sorcery|||Exchange control of two target permanents that share a permanent type.| +Rubblebelt Rioters|War of the Spark|215|U|{1}{R}{G}|Creature - Human Berserker|0|4|Haste$Whenever Rubblebelt Rioters attacks, it gets +X/+0 until end of turn, where X is the greatest power among creatures you control.| +Solar Blaze|War of the Spark|216|R|{2}{R}{W}|Sorcery|||Each creature deals damage to itself equal to its power.| +Sorin, Vengeful Bloodlord|War of the Spark|217|R|{2}{W}{B}|Legendary Planeswalker - Sorin|4|As long as it's your turn, creatures and planeswalkers you control have lifelink.$+2: Sorin, Vengeful Bloodlord deals 1 damage to target player or planeswalker.$-X: Return target creature card with converted mana cost X from your graveyard to the battlefield. That creature is a Vampire in addition to its other types.| +Soul Diviner|War of the Spark|218|R|{U}{B}|Creature - Zombie Wizard|2|3|{T}, Remove a counter from an artifact, creature, land, or planeswalker you control: Draw a card.| +Storrev, Devkarin Lich|War of the Spark|219|R|{1}{B}{B}{G}|Legendary Creature - Zombie Elf Wizard|5|4|Trample$Whenever Storrev, Devkarin Lich deals combat damage to a player or planeswalker, return to your hand target creature or planeswalker card in your graveyard that wasn't put there this combat.| +Tamiyo, Collector of Tales|War of the Spark|220|R|{2}{G}{U}|Legendary Planeswalker - Tamiyo|5|Spells and abilities your opponents control can't cause you to discard cards or sacrifice permanents.$+1: Choose a nonland card name, then reveal the top four cards of your library. Put all cards with the chosen name from among them into your hand and the rest into your graveyard.$-3: Return target card from your graveyard to your hand.| +Teferi, Time Raveler|War of the Spark|221|R|{1}{W}{U}|Legendary Planeswalker - Teferi|4|Each opponent can cast spells only any time they could cast a sorcery.$+1: Until your next turn, you may cast sorcery spells as though they had flash.$-3: Return up to one target artifact, creature, or enchantment to its owner's hand. Draw a card.| +Tenth District Legionnaire|War of the Spark|222|U|{R}{W}|Creature - Human Soldier|2|2|Haste$Whenever you cast a spell that targets Tenth District Legionnaire, put a +1/+1 counter on Tenth District Legionnaire, then scry 1.| +Time Wipe|War of the Spark|223|R|{2}{W}{W}{U}|Sorcery|||Return a creature you control to its owner's hand, then destroy all creatures.| +Tolsimir, Friend to Wolves|War of the Spark|224|R|{2}{G}{G}{W}|Legendary Creature - Elf Scout|3|3|When Tolsimir, Friend to Wolves enters the battlefield, create Voja, Friend to Elves, a legendary 3/3 green and white Wolf creature token.$Whenever a Wolf enters the battlefield under your control, you gain 3 life and that creature fights up to one target creature an opponent controls.| +Tyrant's Scorn|War of the Spark|225|U|{U}{B}|Instant|||Choose one —$• Destroy target creature with converted mana cost 3 or less.$• Return target creature to its owner's hand.| +Widespread Brutality|War of the Spark|226|R|{1}{B}{R}{R}|Sorcery|||Amass 2, then the Army you amassed deals damage equal to its power to each non-Army creature.| +Angrath, Captain of Chaos|War of the Spark|227|U|{2}{B/R}{B/R}|Legendary Planeswalker - Angrath|5|Creatures you control have menace.$-2: Amass 2.| +Ashiok, Dream Render|War of the Spark|228|U|{1}{U/B}{U/B}|Legendary Planeswalker - Ashiok|5|Spells and abilities your opponents control can't cause their controller to search their library.$-1: Target player puts the top four cards of their library into their graveyard. Then exile each opponent's graveyard.| +Dovin, Hand of Control|War of the Spark|229|U|{2}{W/U}|Legendary Planeswalker - Dovin|5|Artifact, instant, and sorcery spells your opponents cast cost {1} more to cast.$-1: Until your next turn, prevent all damage that would be dealt to and dealt by target permanent an opponent controls.| +Huatli, the Sun's Heart|War of the Spark|230|U|{2}{G/W}|Legendary Planeswalker - Huatli|7|Each creature you control assigns combat damage equal to its toughness rather than its power.$-3: You gain life equal to the greatest toughness among creatures you control.| +Kaya, Bane of the Dead|War of the Spark|231|U|{3}{W/B}{W/B}{W/B}|Legendary Planeswalker - Kaya|7|Your opponents and permanents your opponents control with hexproof can be the target of spells and abilities you control as though they didn't have hexproof.$-3: Exile target creature.| +Kiora, Behemoth Beckoner|War of the Spark|232|U|{2}{G/U}|Legendary Planeswalker - Kiora|7|Whenever a creature with power 4 or greater enters the battlefield under your control, draw a card.$-1: Untap target permanent.| +Nahiri, Storm of Stone|War of the Spark|233|U|{2}{R/W}{R/W}|Legendary Planeswalker - Nahiri|6|As long as it's your turn, creatures you control have first strike and equip abilities you activate cost {1} less to activate.$-X: Nahiri, Storm of Stone deals X damage to target tapped creature.| +Saheeli, Sublime Artificer|War of the Spark|234|U|{1}{U/R}{U/R}|Legendary Planeswalker - Saheeli|5|Whenever you cast a noncreature spell, create a 1/1 colorless Servo artifact creature token.$-2: Target artifact you control becomes a copy of another target artifact or creature you control until end of turn, except it's an artifact in addition to its other types.| +Samut, Tyrant Smasher|War of the Spark|235|U|{2}{R/G}{R/G}|Legendary Planeswalker - Samut|5|Creatures you control have haste.$-1: Target creature gets +2/+1 and gains haste until end of turn. Scry 1.| +Vraska, Swarm's Eminence|War of the Spark|236|U|{2}{B/G}{B/G}|Legendary Planeswalker - Vraska|5|Whenever a creature you control with deathtouch deals damage to a player or planeswalker, put a +1/+1 counter on that creature.$-2: Create a 1/1 black Assassin creature token with deathtouch and "Whenever this creature deals damage to a planeswalker, destroy that planeswalker."| +Firemind Vessel|War of the Spark|237|U|{4}|Artifact|||Firemind Vessel enters the battlefield tapped.${T}: Add two mana of different colors.| +God-Pharaoh's Statue|War of the Spark|238|U|{6}|Legendary Artifact|||Spells your opponents cast cost {2} more to cast.$At the beginning of your end step, each opponent loses 1 life.| +Guild Globe|War of the Spark|239|C|{2}|Artifact|||When Guild Globe enters the battlefield, draw a card.${2}, {T}, Sacrifice Guild Globe: Add two mana of different colors.| +Iron Bully|War of the Spark|240|C|{3}|Artifact Creature - Golem|1|1|Menace$When Iron Bully enters the battlefield, put a +1/+1 counter on target creature.| +Mana Geode|War of the Spark|241|C|{3}|Artifact|||When Mana Geode enters the battlefield, scry 1.${T}: Add one mana of any color.| +Prismite|War of the Spark|242|C|{2}|Artifact Creature - Golem|2|1|{2}: Add one mana of any color.| +Saheeli's Silverwing|War of the Spark|243|C|{4}|Artifact Creature - Drake|2|3|Flying$When Saheeli's Silverwing enters the battlefield, look at the top card of target opponent's library.| +Blast Zone|War of the Spark|244|R||Land|||Blast Zone enters the battlefield with a charge counter on it.${T}: Add {C}.${X}{X}, {T}: Put X charge counters on Blast Zone.${3}, {T}, Sacrifice Blast Zone: Destroy each nonland permanent with converted mana cost equal to the number of charge counters on Blast Zone.| +Emergence Zone|War of the Spark|245|U||Land|||{T}: Add {C}.${1}, {T}, Sacrifice Emergence Zone: You may cast spells this turn as though they had flash.| +Gateway Plaza|War of the Spark|246|C||Land - Gate|||Gateway Plaza enters the battlefield tapped.$When Gateway Plaza enters the battlefield, sacrifice it unless you pay {1}.${T}: Add one mana of any color.| +Interplanar Beacon|War of the Spark|247|U||Land|||Whenever you cast a planeswalker spell, you gain 1 life.${T}: Add {C}.${1}, {T}: Add two mana of different colors. Spend this mana only to cast planeswalker spells.| +Karn's Bastion|War of the Spark|248|R||Land|||{T}: Add {C}.${4}, {T}: Proliferate.| +Mobilized District|War of the Spark|249|R||Land|||{T}: Add {C}.${4}: Mobilized District becomes a 3/3 Citizen creature with vigilance until end of turn. It's still a land. This ability costs {1} less to activate for each legendary creature and planeswalker you control.| +Plains|War of the Spark|252|C||Basic Land - Plains|||({T}: Add {W}.)| +Island|War of the Spark|254|C||Basic Land - Island|||({T}: Add {U}.)| +Swamp|War of the Spark|258|C||Basic Land - Swamp|||({T}: Add {B}.)| +Mountain|War of the Spark|261|C||Basic Land - Mountain|||({T}: Add {R}.)| +Forest|War of the Spark|264|C||Basic Land - Forest|||({T}: Add {G}.)| +Gideon, the Oathsworn|War of the Spark|265|M|{4}{W}{W}|Legendary Planeswalker - Gideon|4|Whenever you attack with two or more non-Gideon creatures, put a +1/+1 counter on each of those creatures.$+2: Until end of turn, Gideon, the Oathsworn becomes a 5/5 white Soldier creature that's still a planeswalker. Prevent all damage that would be dealt to him this turn.$-9: Exile Gideon, the Oathsworn and each creature your opponents control.| +Desperate Lunge|War of the Spark|266|C|{1}{W}|Instant|||Target creature gets +2/+2 and gains flying until end of turn. You gain 2 life.| +Gideon's Battle Cry|War of the Spark|267|R|{2}{W}{W}|Sorcery|||Put a +1/+1 counter on each creature you control. You may search your library and/or graveyard for a card named Gideon, the Oathsworn, reveal it, and put it into your hand. If you search your library this way, shuffle it.| +Gideon's Company|War of the Spark|268|U|{3}{W}|Creature - Human Soldier|3|3|Whenever you gain life, put two +1/+1 counters on Gideon's Company.${3}{W}: Put a loyalty counter on target Gideon planeswalker.| +Orzhov Guildgate|War of the Spark|269|C||Land - Gate|||Orzhov Guildgate enters the battlefield tapped.${T}: Add {W} or {B}.| +Jace, Arcane Strategist|War of the Spark|270|M|{4}{U}{U}|Legendary Planeswalker - Jace|4|Whenever you draw your second card each turn, put a +1/+1 counter on target creature you control.$+1: Draw a card.$-7: Creatures you control can't be blocked this turn.| +Guildpact Informant|War of the Spark|271|C|{2}{U}|Creature - Faerie Rogue|1|1|Flying$Whenever Guildpact Informant deals combat damage to a player or planeswalker, proliferate.| +Jace's Projection|War of the Spark|272|U|{2}{U}{U}|Creature - Wizard Illusion|2|2|Whenever you draw a card, put a +1/+1 counter on Jace's Projection.${3}{U}: Put a loyalty counter on target Jace planeswalker.| +Jace's Ruse|War of the Spark|273|R|{3}{U}{U}|Sorcery|||Return up to two target creatures to their owner's hand. You may search your library and/or graveyard for a card named Jace, Arcane Strategist, reveal it, and put it into your hand. If you search your library this way, shuffle it.| +Simic Guildgate|War of the Spark|274|C||Land - Gate|||Simic Guildgate enters the battlefield tapped.${T}: Add {G} or {U}.| +Tezzeret, Master of the Bridge|War of the Spark|275|M|{4}{U}{B}|Legendary Planeswalker - Tezzeret|5|Creature and planeswalker spells you cast have affinity for artifacts.$+2: Tezzeret, Master of the Bridge deals X damage to each opponent, where X is the number of artifacts you control. You gain X life.$-3: Return target artifact card from your graveyard to your hand.$-8: Exile the top ten cards of your library. Put all artifact cards from among them onto the battlefield.| \ No newline at end of file diff --git a/Utils/mtg-sets-data.txt b/Utils/mtg-sets-data.txt index 797a5ba772..23aab08326 100644 --- a/Utils/mtg-sets-data.txt +++ b/Utils/mtg-sets-data.txt @@ -139,6 +139,7 @@ Masters Edition|MED| Game Day|MGDC| Mirage|MIR| Launch Party|MLP| +Modern Horizons|MH1| Modern Masters 2015|MM2| Modern Masters 2017|MM3| Modern Masters|MMA| @@ -165,6 +166,7 @@ Planeshift|PLS| Portal|POR| Prerelease Events|PTC| Portal Three Kingdoms|PTK| +Ravnica Allegiance|RNA| Ravnica: City of Guilds|RAV| Rivals of Ixalan|RIX| Rise of the Eldrazi|ROE| @@ -208,6 +210,7 @@ Vanguard Set 4|VG4| MTGO Vanguard|VGO| Visions|VIS| Vintage Masters|VMA| +War of the Spark|WAR| Welcome Deck 2016|W16| Welcome Deck 2017|W17| World Magic Cup Qualifier|WMCQ| diff --git a/mageadmin.log b/mageadmin.log deleted file mode 100644 index 90f899eed0..0000000000 --- a/mageadmin.log +++ /dev/null @@ -1,1478 +0,0 @@ -DEBUG 2017-05-12 00:41:30,044 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,049 Logging level: null =>[main] MageTestPlayerBase.init -FATAL 2017-05-12 00:41:30,841 ConfigSettings error =>[main] ConfigSettings. -javax.xml.bind.UnmarshalException - - with linked exception: -[java.io.FileNotFoundException: C:\dev\mage\config\config.xml (The system cannot find the path specified)] - at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:220) - at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189) - at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157) - at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162) - at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171) - at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189) - at mage.server.util.ConfigSettings.(ConfigSettings.java:53) - at mage.server.util.ConfigSettings.(ConfigSettings.java:44) - at org.mage.test.serverside.base.MageTestPlayerBase.init(MageTestPlayerBase.java:99) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) - at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) - at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) - at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) - at org.junit.runners.ParentRunner.run(ParentRunner.java:363) - at org.junit.runners.Suite.runChild(Suite.java:128) - at org.junit.runners.Suite.runChild(Suite.java:27) - at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) - at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) - at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) - at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) - at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) - at org.junit.runners.ParentRunner.run(ParentRunner.java:363) - at org.junit.runner.JUnitCore.run(JUnitCore.java:137) - at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) - at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:51) - at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:237) - at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) - at java.lang.reflect.Method.invoke(Method.java:498) - at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147) -Caused by: java.io.FileNotFoundException: C:\dev\mage\config\config.xml (The system cannot find the path specified) - at java.io.FileInputStream.open0(Native Method) - at java.io.FileInputStream.open(FileInputStream.java:195) - at java.io.FileInputStream.(FileInputStream.java:138) - at java.io.FileInputStream.(FileInputStream.java:93) - at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:90) - at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:188) - at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:623) - at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:148) - at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:805) - at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) - at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) - at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) - at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643) - at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:217) - ... 35 more -DEBUG 2017-05-12 00:41:30,850 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,850 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,852 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,853 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,854 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,854 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,855 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,855 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,857 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,857 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,859 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,859 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,861 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,862 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,864 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,865 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,867 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,867 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,868 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,869 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,870 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,870 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,871 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,872 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,873 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,873 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,874 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,875 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,876 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,876 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,878 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,878 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,880 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,880 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,882 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,882 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,883 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,884 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,885 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,885 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,891 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,892 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,893 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,893 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,894 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,895 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,896 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,896 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,898 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,898 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,899 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,899 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,900 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,901 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,902 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,902 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,903 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,903 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,904 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,904 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,905 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,905 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,906 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,907 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,908 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,908 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,909 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,909 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,910 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,910 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,911 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,913 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,913 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,914 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,915 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,915 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,916 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,917 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,918 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,918 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,919 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,920 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,920 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,921 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,923 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,923 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,924 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,924 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,928 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,928 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,929 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,930 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,933 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,933 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,934 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,935 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,936 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,936 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,937 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,938 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,939 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,939 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,941 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,941 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,943 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,943 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,945 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,945 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,946 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,947 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,948 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,948 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,949 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,949 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,950 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,950 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,952 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,952 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,953 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,953 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,954 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,954 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,955 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,955 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,956 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,956 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,957 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,957 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,958 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,958 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,958 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,959 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,960 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,961 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,962 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,962 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,964 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,964 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,965 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,965 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,966 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,966 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,966 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,966 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,967 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,967 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,968 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,968 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,969 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,969 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,971 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,971 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,972 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,972 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,973 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,973 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,974 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,974 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,975 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,975 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,976 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,976 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,977 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,977 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,978 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,978 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,979 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,979 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,982 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,982 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,983 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,984 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,985 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,985 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,986 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,987 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,988 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,988 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,989 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,990 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,991 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,991 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,992 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,993 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,994 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,994 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,995 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,995 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,997 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,997 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,998 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,998 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:30,999 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,000 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,001 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,001 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,008 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,008 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,009 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,010 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,013 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,014 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,014 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,015 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,016 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,017 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,019 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,019 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,020 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,020 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,020 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,021 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,021 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,021 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,022 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,022 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,023 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,023 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,024 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,024 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,025 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,025 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,025 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,025 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,026 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,026 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,027 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,027 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,027 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,028 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,028 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,028 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,029 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,029 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,030 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,030 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,031 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,031 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,032 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,032 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,033 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,033 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,033 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,034 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,034 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,034 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,035 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,035 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,036 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,036 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,036 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,037 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,038 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,038 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,039 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,039 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,040 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,040 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,041 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,041 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,042 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,042 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,043 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,043 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,043 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,043 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,044 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,044 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,045 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,045 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,046 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,046 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,047 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,047 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,048 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,048 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,049 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,049 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,050 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,050 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,050 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,050 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,051 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,051 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,052 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,052 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,052 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,053 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,053 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,053 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,054 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,054 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,055 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,055 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,056 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,056 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,057 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,057 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,057 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,058 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,058 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,058 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,059 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,059 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,059 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,059 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,060 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,060 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,061 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,061 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,061 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,062 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,062 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,063 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,063 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,063 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,064 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,064 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,065 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,065 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,066 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,066 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,067 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,067 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,068 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,068 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,069 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,069 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,070 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,070 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,071 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,071 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,072 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,072 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,073 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,073 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,074 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,074 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,075 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,075 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,076 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,076 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,077 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,077 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,078 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,078 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,078 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,078 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,079 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,079 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,080 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,080 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,081 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,081 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,081 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,081 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,082 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,082 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,083 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,083 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,083 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,084 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,084 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,084 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,086 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,086 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,087 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,087 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,088 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,088 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,089 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,089 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,089 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,090 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,090 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,090 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,091 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,092 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,093 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,093 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,096 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,099 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,100 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,101 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,102 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,102 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,103 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,103 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,105 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,105 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,105 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,106 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,107 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,107 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,108 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,108 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,108 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,109 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,110 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,110 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,111 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,111 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,114 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,114 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,115 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,115 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,116 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,116 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,117 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,117 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,118 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,118 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,119 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,119 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,120 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,120 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,122 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,122 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,127 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,127 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,128 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,128 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,130 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,130 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,131 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,131 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,164 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,165 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,165 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,166 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,166 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,166 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,167 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,167 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,167 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,167 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,168 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,168 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,168 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,168 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,169 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,169 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,170 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,170 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,171 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,171 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,171 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,171 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,172 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,172 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,173 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,173 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,173 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,173 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,174 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,174 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,175 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,175 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,176 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,177 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,178 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,178 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,179 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,179 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,180 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,180 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,182 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,182 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,183 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,183 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,187 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,187 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,188 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,188 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,204 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,204 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,205 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,205 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,220 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,220 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,221 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,221 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,229 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,229 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,230 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,230 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,242 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,242 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,243 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,243 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,243 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,243 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,244 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,244 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,245 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,245 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,246 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,246 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,247 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,247 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,248 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,248 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,248 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,249 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,249 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,249 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,250 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,250 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,251 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,251 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,252 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,252 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,253 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,253 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,253 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,254 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,254 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,254 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,255 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,255 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,255 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,255 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,260 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,260 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,261 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,261 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,262 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,263 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,263 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,263 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,264 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,264 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,264 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,265 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,265 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,266 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,266 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,266 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,267 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,267 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,268 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,268 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,269 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,269 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,270 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,270 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,271 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,271 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,272 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,272 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,273 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,273 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,274 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,274 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,275 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,275 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,275 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,275 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,276 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,276 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,277 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,277 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,278 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,278 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,279 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,279 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,280 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,280 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,281 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,281 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,282 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,282 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,283 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,283 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,284 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,284 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,284 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,284 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,285 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,285 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,290 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,290 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,291 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,291 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,292 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,292 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,293 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,293 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,293 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,293 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,295 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,295 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,295 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,295 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,296 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,297 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,297 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,297 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,298 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,298 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,301 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,302 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,302 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,302 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,303 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,303 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,303 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,304 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,304 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,305 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,305 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,305 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,306 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,306 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,306 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,306 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,307 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,308 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,308 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,308 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,309 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,310 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,310 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,310 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,311 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,311 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,312 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,312 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,313 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,313 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,314 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,314 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,315 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,315 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,315 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,315 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,316 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,317 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,318 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,318 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,319 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,319 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,319 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,319 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,320 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,321 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,321 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,321 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,322 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,322 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,323 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,323 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,324 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,324 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,324 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,325 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,328 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,328 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,329 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,329 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,330 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,330 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,330 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,330 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,331 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,331 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,331 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,332 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,332 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,333 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,333 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,333 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,334 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,334 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,335 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,335 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,335 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,335 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,336 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,336 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,337 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,337 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,338 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,338 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,339 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,339 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,339 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,339 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,340 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,340 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,341 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,341 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,342 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,342 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,343 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,343 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,344 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,344 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,345 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,345 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,345 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,345 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,346 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,347 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,348 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,348 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,348 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,348 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,349 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,349 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,350 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,350 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,351 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,351 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,351 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,351 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,352 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,352 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,353 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,353 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,354 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,354 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,355 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,355 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,355 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,355 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,357 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,357 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,358 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,359 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,359 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,359 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,360 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,360 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,361 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,361 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,362 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,362 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,363 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,363 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,364 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,364 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,365 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,365 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,366 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,366 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,367 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,367 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,368 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,369 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,369 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,369 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,371 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,372 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,373 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,373 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,376 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,376 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,377 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,377 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,379 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,380 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,382 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,383 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,391 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,392 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,403 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,403 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,405 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,405 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,406 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,406 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,407 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,408 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,408 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,408 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,409 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,409 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,412 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,412 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,417 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,441 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,442 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,442 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,450 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,450 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,451 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,466 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,467 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,467 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,691 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,691 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,692 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,692 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,693 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,693 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,694 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,694 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,752 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,752 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,752 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,753 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,753 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,754 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,754 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,754 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,755 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,755 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,756 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,756 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,766 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,766 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,766 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,767 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,774 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,774 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,775 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,775 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,780 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,780 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,780 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,780 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,781 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,781 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,782 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,782 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,784 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,784 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,785 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,785 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,786 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,786 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,787 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,787 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,793 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,793 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,793 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,793 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,797 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,797 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,799 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,801 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,802 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:31,803 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,051 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,051 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,052 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,052 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,069 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,069 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,070 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,070 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,082 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,082 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,083 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,083 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,087 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,087 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,088 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,089 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,094 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,094 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,095 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,095 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,105 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,144 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,145 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,145 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,149 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,149 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,150 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,150 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,150 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,150 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,151 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,151 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,151 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,152 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,152 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,152 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,153 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,153 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,154 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,154 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,155 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,155 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,156 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,156 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,156 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,156 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,157 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,157 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,159 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,159 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,159 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,160 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,161 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,161 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,162 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,162 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,166 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,167 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,167 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,167 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,169 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,169 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,170 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,170 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,171 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,171 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,172 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,172 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,173 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,173 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,174 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,175 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,176 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,177 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,189 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,190 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,191 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,191 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,233 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,233 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,234 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,234 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,235 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,235 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,236 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,236 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,237 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,237 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,237 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,237 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,239 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,240 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,240 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,240 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,244 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,244 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,245 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,245 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,246 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,246 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,247 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,247 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,252 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,253 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,253 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,253 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,254 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,254 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,254 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,255 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,256 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,256 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,256 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,256 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,257 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,257 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,258 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,258 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,258 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,259 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,259 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,259 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,260 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,260 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,261 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,261 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,262 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,262 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,263 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,263 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,264 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,265 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,265 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,265 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,266 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,266 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,267 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,267 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,268 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,268 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,271 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,271 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,272 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,272 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,273 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,273 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,275 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,275 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,276 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,276 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,281 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,281 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,282 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,282 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,282 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,283 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,283 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,283 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,285 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,285 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,285 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,286 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,287 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,287 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,288 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,288 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,289 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,289 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,299 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,300 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,300 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,301 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,307 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,307 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,308 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,308 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,314 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,314 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,315 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,315 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,316 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,316 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,317 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,317 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,318 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,318 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,319 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,319 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,320 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,320 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,325 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,325 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,326 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,326 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,327 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,327 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,328 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,328 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,328 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,329 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,330 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,330 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,330 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,330 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,332 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,332 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,332 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,332 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,333 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,333 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,334 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,334 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,335 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,335 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,336 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,336 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,337 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,337 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,338 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,338 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,339 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,339 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,340 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,340 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,341 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,341 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,342 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,342 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,343 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,343 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,344 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,344 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,344 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,344 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,345 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,345 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,346 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,346 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,347 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,348 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,349 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,349 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,350 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,350 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,350 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,350 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,351 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,351 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,352 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,352 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,353 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,353 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,354 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,354 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,354 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,355 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,356 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,356 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,357 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,357 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,358 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,358 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,358 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,359 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,359 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,359 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,360 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,360 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,360 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,360 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,361 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,361 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,362 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,362 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,362 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,363 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,363 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,363 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,364 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,364 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,364 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,364 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,365 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,365 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,366 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,366 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,367 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,367 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,368 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,368 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,369 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,369 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,370 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,370 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,371 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,371 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,372 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,372 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,374 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,374 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,383 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,383 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,384 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,384 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,384 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,384 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,385 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,385 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,386 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,386 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,387 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,387 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,388 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,388 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,388 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,389 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,389 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,389 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,390 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,390 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,391 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,391 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,392 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,392 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,393 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,393 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,395 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,395 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,396 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,397 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,398 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,398 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,399 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,399 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,400 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,401 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,401 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,401 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,402 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,402 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,403 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,403 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,405 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,405 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,406 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,406 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,406 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,407 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,407 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,407 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,408 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,408 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,409 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,409 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,410 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,410 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,411 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,411 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,433 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,433 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,434 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,434 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,435 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,435 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,436 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,436 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,437 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,437 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,438 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,438 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,439 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,439 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,440 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,440 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,441 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,441 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,442 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,442 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,443 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,443 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,444 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,444 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,445 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,445 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,446 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,446 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,447 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,447 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,447 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,447 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,449 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,450 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,450 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,451 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,454 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,454 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,455 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,455 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,456 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,456 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,457 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,458 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,458 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,458 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,459 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,460 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,460 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,460 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,461 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,461 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,462 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,462 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,463 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,463 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,463 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,464 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,464 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,465 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,465 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,465 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,466 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,467 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,479 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,479 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,499 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,500 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,500 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,501 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,506 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,507 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,507 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,507 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,508 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,508 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,509 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,509 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,510 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,510 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,511 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,511 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,512 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,512 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,512 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,512 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,513 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,513 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,513 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,514 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,515 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,515 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,516 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,516 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,517 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,517 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,518 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,518 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,519 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,519 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,520 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,520 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,520 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,520 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,521 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,521 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,522 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,522 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,528 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,528 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,529 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,530 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,541 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,541 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,541 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,541 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,542 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,542 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,543 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,544 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,546 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,546 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,547 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,547 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,547 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,547 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,548 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,548 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,548 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,549 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:32,665 created dao for class class mage.cards.repository.DatabaseVersion with reflection =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:32,666 creating table 'version' =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:32,986 opened connection to jdbc:h2:file:./db/cards.h2;AUTO_SERVER=TRUE got #1201466784 =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:32,988 executed create table statement changed 0 rows: CREATE TABLE IF NOT EXISTS `version` (`entity` VARCHAR(255) , `version` BIGINT ) =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:32,997 built statement SELECT * FROM `version` WHERE (`entity` = ? AND `version` = 51 ) =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,006 prepared statement 'SELECT * FROM `version` WHERE (`entity` = ? AND `version` = 51 ) ' with 1 args =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,016 starting iterator @1943634922 for 'SELECT * FROM `version` WHERE (`entity` = ? AND `version` = 51 ) ' =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,016 closed iterator @1943634922 after 0 rows =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,017 query of 'SELECT * FROM `version` WHERE (`entity` = ? AND `version` = 51 ) ' returned 0 results =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,021 insert data with statement 'INSERT INTO `version` (`entity` ,`version` ) VALUES (?,?)' and 2 args, changed 1 rows =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,026 created dao for class class mage.cards.repository.CardInfo with reflection =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,027 dropping table 'card' =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,027 dropping index 'className_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,027 dropping index 'name_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,027 dropping index 'setCode_cardNumber_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,032 ignoring drop error 'org.h2.jdbc.JdbcSQLException: Index "CLASSNAME_INDEX" not found; SQL statement: -DROP INDEX `className_index` [42112-187]' for statement: DROP INDEX `className_index` =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,033 ignoring drop error 'org.h2.jdbc.JdbcSQLException: Index "NAME_INDEX" not found; SQL statement: -DROP INDEX `name_index` [42112-187]' for statement: DROP INDEX `name_index` =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,034 ignoring drop error 'org.h2.jdbc.JdbcSQLException: Index "SETCODE_CARDNUMBER_INDEX" not found; SQL statement: -DROP INDEX `setCode_cardNumber_index` [42112-187]' for statement: DROP INDEX `setCode_cardNumber_index` =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,035 ignoring drop error 'org.h2.jdbc.JdbcSQLException: Table "CARD" not found; SQL statement: -DROP TABLE `card` [42102-187]' for statement: DROP TABLE `card` =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,035 creating table 'card' =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,036 creating index 'className_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,036 creating index 'name_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,036 creating index 'setCode_cardNumber_index' for table 'card =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,038 executed create table statement changed 0 rows: CREATE TABLE IF NOT EXISTS `card` (`name` VARCHAR(255) , `cardNumber` VARCHAR(255) , `setCode` VARCHAR(255) , `className` VARCHAR(255) , `power` VARCHAR(255) , `toughness` VARCHAR(255) , `startingLoyalty` VARCHAR(255) , `convertedManaCost` INTEGER , `rarity` VARCHAR(100) , `types` VARCHAR(255) , `subtypes` VARCHAR(255) , `supertypes` VARCHAR(255) , `manaCosts` VARCHAR(255) , `rules` VARCHAR(700) , `black` TINYINT(1) , `blue` TINYINT(1) , `green` TINYINT(1) , `red` TINYINT(1) , `white` TINYINT(1) , `frameColor` VARCHAR(255) , `frameStyle` VARCHAR(255) , `variousArt` TINYINT(1) , `splitCard` TINYINT(1) , `splitCardFuse` TINYINT(1) , `splitCardAftermath` TINYINT(1) , `splitCardHalf` TINYINT(1) , `flipCard` TINYINT(1) , `doubleFaced` TINYINT(1) , `nightCard` TINYINT(1) , `flipCardName` VARCHAR(255) , `secondSideName` VARCHAR(255) ) =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,043 executed create table statement changed 0 rows: CREATE INDEX IF NOT EXISTS `className_index` ON `card` ( `className` ) =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,044 executed create table statement changed 0 rows: CREATE INDEX IF NOT EXISTS `name_index` ON `card` ( `name`, `nightCard` ) =>[main] Slf4jLoggingLog.log -INFO 2017-05-12 00:41:33,045 executed create table statement changed 0 rows: CREATE INDEX IF NOT EXISTS `setCode_cardNumber_index` ON `card` ( `cardNumber`, `setCode` ) =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,046 executing raw query for: select * from card where lower(name) = 'plains' =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,049 starting iterator @26757919 for 'select * from card where lower(name) = 'plains'' =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,049 closed iterator @26757919 after 0 rows =>[main] Slf4jLoggingLog.log -DEBUG 2017-05-12 00:41:33,051 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,052 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,054 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,055 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,058 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,060 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,061 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,061 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,062 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,062 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,062 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,063 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,065 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,065 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,066 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,066 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,067 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,067 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,067 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,068 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,069 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,070 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,070 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,071 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,071 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,071 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,072 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,072 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,073 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,074 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,074 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,074 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,075 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,076 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,076 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,077 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,078 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,078 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,078 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,079 Logging level: null =>[main] MageTestPlayerBase.init -INFO 2017-05-12 00:41:33,672 Starting MAGE tests =>[main] MageTestBase.init -INFO 2017-05-12 00:41:33,672 Logging level: null =>[main] MageTestBase.init -DEBUG 2017-05-12 00:41:33,674 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,674 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,675 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,675 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,675 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,675 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,676 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,676 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,739 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,739 Logging level: null =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,740 Starting MAGE tests =>[main] MageTestPlayerBase.init -DEBUG 2017-05-12 00:41:33,740 Logging level: null =>[main] MageTestPlayerBase.init diff --git a/pom.xml b/pom.xml index 39d6abf21b..97942f168f 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.mage mage-root - 1.4.31 + 1.4.35 pom Mage Root Mage Root POM @@ -29,6 +29,7 @@ + maven-resources-plugin 2.7 @@ -36,6 +37,8 @@ UTF-8 + + maven-jar-plugin 2.5 @@ -43,6 +46,7 @@ MageTeam + ${maven.build.timestamp} @@ -60,7 +64,6 @@ Mage.Server.Console Mage.Tests Mage.Updater - Mage.Stats Mage.Verify @@ -84,8 +87,9 @@ - 1.4.31 + 1.4.35 UTF-8 + yyyy-MM-dd'T'HH:mm:ss'Z' @@ -93,7 +97,7 @@ junit junit - 4.12 + 4.13-beta-2 log4j @@ -103,7 +107,12 @@ org.slf4j slf4j-log4j12 - 1.7.19 + 1.8.0-beta2 + + + com.google.guava + guava + 20.0 diff --git a/readme.md b/readme.md index 4c25a0bdad..043c124dbd 100644 --- a/readme.md +++ b/readme.md @@ -12,6 +12,9 @@ XMage community: * [Reddit XMage group](https://www.reddit.com/r/XMage/); * [Reddit XMage discord channel](https://discord.gg/Pqf42yn). +Servers status: +* http://xmageservers.online/ + ## Features * Deck editor (load and save decks) diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000000..9b5b43fcd3 --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,2 @@ +sonar.projectName=XMage +sonar.projectVersion=1.4.332V0